From 516a2f0efc5d56189ba57afb9663b7392e4c3830 Mon Sep 17 00:00:00 2001 From: Brian Card Date: Sat, 24 Jan 2015 15:26:49 -0500 Subject: [PATCH] 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;