diff --git a/src/HttpServer.cc b/src/HttpServer.cc index bc9e5fda..27c1167b 100644 --- a/src/HttpServer.cc +++ b/src/HttpServer.cc @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -1412,6 +1413,7 @@ int start_listen(struct ev_loop *loop, Sessions *sessions, addrinfo hints; int r; bool ok = false; + const char *addr = nullptr; auto acceptor = std::make_shared(sessions, config); auto service = util::utos(config->port); @@ -1424,12 +1426,17 @@ int start_listen(struct ev_loop *loop, Sessions *sessions, hints.ai_flags |= AI_ADDRCONFIG; #endif // AI_ADDRCONFIG + if (!config->address.empty()) { + addr = config->address.c_str(); + } + addrinfo *res, *rp; - r = getaddrinfo(nullptr, service.c_str(), &hints, &res); + r = getaddrinfo(addr, service.c_str(), &hints, &res); if (r != 0) { std::cerr << "getaddrinfo() failed: " << gai_strerror(r) << std::endl; return -1; } + for (rp = res; rp; rp = rp->ai_next) { int fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); if (fd == -1) { @@ -1455,8 +1462,9 @@ int start_listen(struct ev_loop *loop, Sessions *sessions, new ListenEventHandler(sessions, fd, acceptor); if (config->verbose) { - std::cout << (rp->ai_family == AF_INET ? "IPv4" : "IPv6") - << ": listen on port " << config->port << std::endl; + std::string s = util::numeric_name(rp->ai_addr, rp->ai_addrlen); + std::cout << (rp->ai_family == AF_INET ? "IPv4" : "IPv6") << ": listen " + << s << ":" << config->port << std::endl; } ok = true; continue; diff --git a/src/HttpServer.h b/src/HttpServer.h index 54b7abaf..3723afd1 100644 --- a/src/HttpServer.h +++ b/src/HttpServer.h @@ -55,6 +55,7 @@ struct Config { std::string private_key_file; std::string cert_file; std::string dh_param_file; + std::string address; ev_tstamp stream_read_timeout; ev_tstamp stream_write_timeout; nghttp2_option *session_option; diff --git a/src/nghttp.cc b/src/nghttp.cc index 8e6151f4..cff6a84e 100644 --- a/src/nghttp.cc +++ b/src/nghttp.cc @@ -109,20 +109,6 @@ std::string strip_fragment(const char *raw_uri) { } } // namespace -namespace { -// Returns numeric address string of |addr|. If getnameinfo() is -// failed, "unknown" is returned. -std::string numeric_name(addrinfo *addr) { - std::array host; - auto rv = getnameinfo(addr->ai_addr, addr->ai_addrlen, host.data(), - host.size(), nullptr, 0, NI_NUMERICHOST); - if (rv != 0) { - return "unknown"; - } - return host.data(); -} -} // namespace - Request::Request(const std::string &uri, const http_parser_url &u, const nghttp2_data_provider *data_prd, int64_t data_length, const nghttp2_priority_spec &pri_spec, @@ -686,13 +672,15 @@ int HttpClient::noop() { return 0; } void HttpClient::on_connect_fail() { if (state == ClientState::IDLE) { std::cerr << "[ERROR] Could not connect to the address " - << numeric_name(cur_addr) << std::endl; + << util::numeric_name(cur_addr->ai_addr, cur_addr->ai_addrlen) + << std::endl; } auto cur_state = state; disconnect(); if (cur_state == ClientState::IDLE) { if (initiate_connection() == 0) { - std::cerr << "Trying next address " << numeric_name(cur_addr) + std::cerr << "Trying next address " + << util::numeric_name(cur_addr->ai_addr, cur_addr->ai_addrlen) << std::endl; } } diff --git a/src/nghttpd.cc b/src/nghttpd.cc index 258017df..80488233 100644 --- a/src/nghttpd.cc +++ b/src/nghttpd.cc @@ -97,6 +97,9 @@ void print_help(std::ostream &out) { Set path to server's certificate. Required unless --no-tls is specified. Options: + -a --address + The address to bind to. If not specified the default IP + address determined by getaddrinfo is used. -D, --daemon Run in a background. If -D is used, the current working directory is changed to '/'. Therefore if this option @@ -151,6 +154,7 @@ int main(int argc, char **argv) { while (1) { static int flag = 0; static option long_options[] = { + {"address", required_argument, nullptr, 'a'}, {"daemon", no_argument, nullptr, 'D'}, {"htdocs", required_argument, nullptr, 'd'}, {"help", no_argument, nullptr, 'h'}, @@ -168,13 +172,16 @@ int main(int argc, char **argv) { {"early-response", no_argument, &flag, 5}, {nullptr, 0, nullptr, 0}}; int option_index = 0; - int c = - getopt_long(argc, argv, "DVb:c:d:ehn:p:v", long_options, &option_index); + int c = getopt_long(argc, argv, "DVb:c:d:ehn:p:va:", long_options, + &option_index); char *end; if (c == -1) { break; } switch (c) { + case 'a': + config.address = optarg; + break; case 'D': config.daemon = true; break; diff --git a/src/util.cc b/src/util.cc index 039438a7..9d785a40 100644 --- a/src/util.cc +++ b/src/util.cc @@ -658,6 +658,16 @@ bool numeric_host(const char *hostname) { return true; } +std::string numeric_name(const struct sockaddr *sa, socklen_t salen) { + std::array host; + auto rv = getnameinfo(sa, salen, host.data(), host.size(), nullptr, 0, + NI_NUMERICHOST); + if (rv != 0) { + return "unknown"; + } + return host.data(); +} + int reopen_log_file(const char *path) { #if defined(__ANDROID__) || defined(ANDROID) int fd; diff --git a/src/util.h b/src/util.h index 5bddbd55..ca8155ab 100644 --- a/src/util.h +++ b/src/util.h @@ -29,6 +29,7 @@ #include #include +#include #include #include @@ -470,6 +471,10 @@ void write_uri_field(std::ostream &o, const char *uri, const http_parser_url &u, bool numeric_host(const char *hostname); +// Returns numeric address string of |addr|. If getnameinfo() is +// failed, "unknown" is returned. +std::string numeric_name(const struct sockaddr *sa, socklen_t salen); + // Opens |path| with O_APPEND enabled. If file does not exist, it is // created first. This function returns file descriptor referring the // opened file if it succeeds, or -1.