From 516a2f0efc5d56189ba57afb9663b7392e4c3830 Mon Sep 17 00:00:00 2001 From: Brian Card Date: Sat, 24 Jan 2015 15:26:49 -0500 Subject: [PATCH 1/5] Adding an address parameter that allows nghttpd to bind to a non-default address. Both IPv4 and IPv6 addresses are supported. In addition with verbose mode enable the address that the webserver binds to is now printed in addition to the port. --- src/HttpServer.cc | 36 +++++++++++++++++++++++++++++++++--- src/HttpServer.h | 1 + src/nghttpd.cc | 44 ++++++++++++++++++++++++++------------------ 3 files changed, 60 insertions(+), 21 deletions(-) diff --git a/src/HttpServer.cc b/src/HttpServer.cc index 6ffdbc86..ca8ee39d 100644 --- a/src/HttpServer.cc +++ b/src/HttpServer.cc @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -1459,12 +1460,34 @@ int verify_callback(int preverify_ok, X509_STORE_CTX *ctx) { } } // namespace +namespace { +// finds a readable address and adds stores it in the given string +char *get_ip_str(const struct sockaddr *sa, char *s, size_t maxlen) { + switch (sa->sa_family) { + case AF_INET: + inet_ntop(AF_INET, &(((struct sockaddr_in *)sa)->sin_addr), s, maxlen); + break; + + case AF_INET6: + inet_ntop(AF_INET6, &(((struct sockaddr_in6 *)sa)->sin6_addr), s, maxlen); + break; + + default: + strncpy(s, "Unknown AF", maxlen); + return NULL; + } + + return s; +} +} // namespace + namespace { int start_listen(struct ev_loop *loop, Sessions *sessions, const Config *config) { addrinfo hints; int r; bool ok = false; + const char *addr = nullptr; auto acceptor = std::make_shared(sessions, config); auto service = util::utos(config->port); @@ -1477,12 +1500,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) { @@ -1508,8 +1536,10 @@ 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; + char s[INET6_ADDRSTRLEN]; + get_ip_str((struct sockaddr *)rp->ai_addr, s, sizeof s); + 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 02802a9c..71f3b6f1 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/nghttpd.cc b/src/nghttpd.cc index a8c17a03..e9a7ead7 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,30 +154,35 @@ int main(int argc, char **argv) { while (1) { static int flag = 0; static option long_options[] = { - {"daemon", no_argument, nullptr, 'D'}, - {"htdocs", required_argument, nullptr, 'd'}, - {"help", no_argument, nullptr, 'h'}, - {"verbose", no_argument, nullptr, 'v'}, - {"verify-client", no_argument, nullptr, 'V'}, - {"header-table-size", required_argument, nullptr, 'c'}, - {"push", required_argument, nullptr, 'p'}, - {"padding", required_argument, nullptr, 'b'}, - {"workers", required_argument, nullptr, 'n'}, - {"error-gzip", no_argument, nullptr, 'e'}, - {"no-tls", no_argument, &flag, 1}, - {"color", no_argument, &flag, 2}, - {"version", no_argument, &flag, 3}, - {"dh-param-file", required_argument, &flag, 4}, - {"early-response", no_argument, &flag, 5}, - {nullptr, 0, nullptr, 0}}; + { "address", required_argument, nullptr, 'a' }, + { "daemon", no_argument, nullptr, 'D' }, + { "htdocs", required_argument, nullptr, 'd' }, + { "help", no_argument, nullptr, 'h' }, + { "verbose", no_argument, nullptr, 'v' }, + { "verify-client", no_argument, nullptr, 'V' }, + { "header-table-size", required_argument, nullptr, 'c' }, + { "push", required_argument, nullptr, 'p' }, + { "padding", required_argument, nullptr, 'b' }, + { "workers", required_argument, nullptr, 'n' }, + { "error-gzip", no_argument, nullptr, 'e' }, + { "no-tls", no_argument, &flag, 1 }, + { "color", no_argument, &flag, 2 }, + { "version", no_argument, &flag, 3 }, + { "dh-param-file", required_argument, &flag, 4 }, + { "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; From d10bce3dc89611be70d249a03afea65f095f813b Mon Sep 17 00:00:00 2001 From: Brian Card Date: Mon, 23 Feb 2015 07:13:03 -0500 Subject: [PATCH 2/5] fixing formatiing --- src/nghttpd.cc | 39 +++++++++++++++++++-------------------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/src/nghttpd.cc b/src/nghttpd.cc index e9a7ead7..9566cfa3 100644 --- a/src/nghttpd.cc +++ b/src/nghttpd.cc @@ -154,27 +154,26 @@ 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' }, - { "verbose", no_argument, nullptr, 'v' }, - { "verify-client", no_argument, nullptr, 'V' }, - { "header-table-size", required_argument, nullptr, 'c' }, - { "push", required_argument, nullptr, 'p' }, - { "padding", required_argument, nullptr, 'b' }, - { "workers", required_argument, nullptr, 'n' }, - { "error-gzip", no_argument, nullptr, 'e' }, - { "no-tls", no_argument, &flag, 1 }, - { "color", no_argument, &flag, 2 }, - { "version", no_argument, &flag, 3 }, - { "dh-param-file", required_argument, &flag, 4 }, - { "early-response", no_argument, &flag, 5 }, - { nullptr, 0, nullptr, 0 } - }; + {"address", required_argument, nullptr, 'a'}, + {"daemon", no_argument, nullptr, 'D'}, + {"htdocs", required_argument, nullptr, 'd'}, + {"help", no_argument, nullptr, 'h'}, + {"verbose", no_argument, nullptr, 'v'}, + {"verify-client", no_argument, nullptr, 'V'}, + {"header-table-size", required_argument, nullptr, 'c'}, + {"push", required_argument, nullptr, 'p'}, + {"padding", required_argument, nullptr, 'b'}, + {"workers", required_argument, nullptr, 'n'}, + {"error-gzip", no_argument, nullptr, 'e'}, + {"no-tls", no_argument, &flag, 1}, + {"color", no_argument, &flag, 2}, + {"version", no_argument, &flag, 3}, + {"dh-param-file", required_argument, &flag, 4}, + {"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:va:", 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; From 933b9636e52624ea97ff15eedb7592640ee05100 Mon Sep 17 00:00:00 2001 From: Brian Card Date: Mon, 23 Feb 2015 07:15:54 -0500 Subject: [PATCH 3/5] removing additional space after option variable --- src/nghttpd.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nghttpd.cc b/src/nghttpd.cc index 9566cfa3..3b6d8e61 100644 --- a/src/nghttpd.cc +++ b/src/nghttpd.cc @@ -172,7 +172,7 @@ int main(int argc, char **argv) { {"early-response", no_argument, &flag, 5}, {nullptr, 0, nullptr, 0}}; int option_index = 0; - int c = + int c = getopt_long(argc, argv, "DVb:c:d:ehn:p:va:", long_options, &option_index); char *end; if (c == -1) { From b773d63b921afa77d87efc4e7c0489f78bed54b5 Mon Sep 17 00:00:00 2001 From: Brian Card Date: Tue, 24 Feb 2015 09:50:18 -0500 Subject: [PATCH 4/5] Moving nghttp's numeric_name function to util.cc and using this to generate the address name in HttpServer.cc --- src/HttpServer.cc | 3 +-- src/nghttp.cc | 18 ++---------------- src/util.cc | 12 ++++++++++++ src/util.h | 3 +++ 4 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/HttpServer.cc b/src/HttpServer.cc index ca8ee39d..1c986410 100644 --- a/src/HttpServer.cc +++ b/src/HttpServer.cc @@ -1536,8 +1536,7 @@ int start_listen(struct ev_loop *loop, Sessions *sessions, new ListenEventHandler(sessions, fd, acceptor); if (config->verbose) { - char s[INET6_ADDRSTRLEN]; - get_ip_str((struct sockaddr *)rp->ai_addr, s, sizeof s); + std::string s = util::numeric_name(rp); std::cout << (rp->ai_family == AF_INET ? "IPv4" : "IPv6") << ": listen " << s << ":" << config->port << std::endl; } diff --git a/src/nghttp.cc b/src/nghttp.cc index 1bc0392d..ccff2567 100644 --- a/src/nghttp.cc +++ b/src/nghttp.cc @@ -107,20 +107,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) { - char host[NI_MAXHOST]; - auto rv = getnameinfo(addr->ai_addr, addr->ai_addrlen, host, sizeof(host), - nullptr, 0, NI_NUMERICHOST); - if (rv != 0) { - return "unknown"; - } - return host; -} -} // 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, @@ -688,13 +674,13 @@ int HttpClient::noop() { return 0; } void HttpClient::on_connect_fail() { if (state == STATE_IDLE) { std::cerr << "[ERROR] Could not connect to the address " - << numeric_name(cur_addr) << std::endl; + << util::numeric_name(cur_addr) << std::endl; } auto cur_state = state; disconnect(); if (cur_state == STATE_IDLE) { if (initiate_connection() == 0) { - std::cerr << "Trying next address " << numeric_name(cur_addr) + std::cerr << "Trying next address " << util::numeric_name(cur_addr) << std::endl; } } diff --git a/src/util.cc b/src/util.cc index eafe13b9..8dea595b 100644 --- a/src/util.cc +++ b/src/util.cc @@ -686,6 +686,18 @@ bool numeric_host(const char *hostname) { return true; } +// Returns numeric address string of |addr|. If getnameinfo() is +// failed, "unknown" is returned. +std::string numeric_name(addrinfo *addr) { + char host[NI_MAXHOST]; + auto rv = getnameinfo(addr->ai_addr, addr->ai_addrlen, host, sizeof(host), + nullptr, 0, NI_NUMERICHOST); + if (rv != 0) { + return "unknown"; + } + return host; +} + 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 8f63fe37..f4246d40 100644 --- a/src/util.h +++ b/src/util.h @@ -29,6 +29,7 @@ #include #include +#include #include #include @@ -417,6 +418,8 @@ void write_uri_field(std::ostream &o, const char *uri, const http_parser_url &u, bool numeric_host(const char *hostname); +std::string numeric_name(addrinfo *addr); + // 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. From 1bdf664f4d87bb8a2c2633beab94912ff4357cc1 Mon Sep 17 00:00:00 2001 From: Brian Card Date: Thu, 26 Feb 2015 08:59:25 -0500 Subject: [PATCH 5/5] Changing signature of numeric_name from numeric_name(addrinfo *addr) to numeric_name(const struct sockaddr *sa, socklen_t salen) to remove dependency on addrinfo struct. --- src/HttpServer.cc | 2 +- src/nghttp.cc | 4 ++-- src/util.cc | 4 ++-- src/util.h | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/HttpServer.cc b/src/HttpServer.cc index 1c986410..ce649be8 100644 --- a/src/HttpServer.cc +++ b/src/HttpServer.cc @@ -1536,7 +1536,7 @@ int start_listen(struct ev_loop *loop, Sessions *sessions, new ListenEventHandler(sessions, fd, acceptor); if (config->verbose) { - std::string s = util::numeric_name(rp); + 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; } diff --git a/src/nghttp.cc b/src/nghttp.cc index ccff2567..24a8dd7f 100644 --- a/src/nghttp.cc +++ b/src/nghttp.cc @@ -674,13 +674,13 @@ int HttpClient::noop() { return 0; } void HttpClient::on_connect_fail() { if (state == STATE_IDLE) { std::cerr << "[ERROR] Could not connect to the address " - << util::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 == STATE_IDLE) { if (initiate_connection() == 0) { - std::cerr << "Trying next address " << util::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/util.cc b/src/util.cc index 8dea595b..9ae07965 100644 --- a/src/util.cc +++ b/src/util.cc @@ -688,9 +688,9 @@ bool numeric_host(const char *hostname) { // Returns numeric address string of |addr|. If getnameinfo() is // failed, "unknown" is returned. -std::string numeric_name(addrinfo *addr) { +std::string numeric_name(const struct sockaddr *sa, socklen_t salen) { char host[NI_MAXHOST]; - auto rv = getnameinfo(addr->ai_addr, addr->ai_addrlen, host, sizeof(host), + auto rv = getnameinfo(sa, salen, host, sizeof(host), nullptr, 0, NI_NUMERICHOST); if (rv != 0) { return "unknown"; diff --git a/src/util.h b/src/util.h index f4246d40..b111dca2 100644 --- a/src/util.h +++ b/src/util.h @@ -418,7 +418,7 @@ void write_uri_field(std::ostream &o, const char *uri, const http_parser_url &u, bool numeric_host(const char *hostname); -std::string numeric_name(addrinfo *addr); +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