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.

This commit is contained in:
Brian Card 2015-01-24 15:26:49 -05:00
parent 682db00ba9
commit 516a2f0efc
3 changed files with 60 additions and 21 deletions

View File

@ -31,6 +31,7 @@
#include <fcntl.h> #include <fcntl.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <netinet/tcp.h> #include <netinet/tcp.h>
#include <arpa/inet.h>
#include <cassert> #include <cassert>
#include <set> #include <set>
@ -1459,12 +1460,34 @@ int verify_callback(int preverify_ok, X509_STORE_CTX *ctx) {
} }
} // namespace } // 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 { namespace {
int start_listen(struct ev_loop *loop, Sessions *sessions, int start_listen(struct ev_loop *loop, Sessions *sessions,
const Config *config) { const Config *config) {
addrinfo hints; addrinfo hints;
int r; int r;
bool ok = false; bool ok = false;
const char *addr = nullptr;
auto acceptor = std::make_shared<AcceptHandler>(sessions, config); auto acceptor = std::make_shared<AcceptHandler>(sessions, config);
auto service = util::utos(config->port); auto service = util::utos(config->port);
@ -1477,12 +1500,17 @@ int start_listen(struct ev_loop *loop, Sessions *sessions,
hints.ai_flags |= AI_ADDRCONFIG; hints.ai_flags |= AI_ADDRCONFIG;
#endif // AI_ADDRCONFIG #endif // AI_ADDRCONFIG
if (!config->address.empty()) {
addr = config->address.c_str();
}
addrinfo *res, *rp; addrinfo *res, *rp;
r = getaddrinfo(nullptr, service.c_str(), &hints, &res); r = getaddrinfo(addr, service.c_str(), &hints, &res);
if (r != 0) { if (r != 0) {
std::cerr << "getaddrinfo() failed: " << gai_strerror(r) << std::endl; std::cerr << "getaddrinfo() failed: " << gai_strerror(r) << std::endl;
return -1; return -1;
} }
for (rp = res; rp; rp = rp->ai_next) { for (rp = res; rp; rp = rp->ai_next) {
int fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); int fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
if (fd == -1) { if (fd == -1) {
@ -1508,8 +1536,10 @@ int start_listen(struct ev_loop *loop, Sessions *sessions,
new ListenEventHandler(sessions, fd, acceptor); new ListenEventHandler(sessions, fd, acceptor);
if (config->verbose) { if (config->verbose) {
std::cout << (rp->ai_family == AF_INET ? "IPv4" : "IPv6") char s[INET6_ADDRSTRLEN];
<< ": listen on port " << config->port << std::endl; 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; ok = true;
continue; continue;

View File

@ -55,6 +55,7 @@ struct Config {
std::string private_key_file; std::string private_key_file;
std::string cert_file; std::string cert_file;
std::string dh_param_file; std::string dh_param_file;
std::string address;
ev_tstamp stream_read_timeout; ev_tstamp stream_read_timeout;
ev_tstamp stream_write_timeout; ev_tstamp stream_write_timeout;
nghttp2_option *session_option; nghttp2_option *session_option;

View File

@ -97,6 +97,9 @@ void print_help(std::ostream &out) {
<CERT> Set path to server's certificate. Required unless <CERT> Set path to server's certificate. Required unless
--no-tls is specified. --no-tls is specified.
Options: Options:
-a --address
The address to bind to. If not specified the default IP
address determined by getaddrinfo is used.
-D, --daemon -D, --daemon
Run in a background. If -D is used, the current working Run in a background. If -D is used, the current working
directory is changed to '/'. Therefore if this option directory is changed to '/'. Therefore if this option
@ -151,6 +154,7 @@ int main(int argc, char **argv) {
while (1) { while (1) {
static int flag = 0; static int flag = 0;
static option long_options[] = { static option long_options[] = {
{ "address", required_argument, nullptr, 'a' },
{ "daemon", no_argument, nullptr, 'D' }, { "daemon", no_argument, nullptr, 'D' },
{ "htdocs", required_argument, nullptr, 'd' }, { "htdocs", required_argument, nullptr, 'd' },
{ "help", no_argument, nullptr, 'h' }, { "help", no_argument, nullptr, 'h' },
@ -166,15 +170,19 @@ int main(int argc, char **argv) {
{ "version", no_argument, &flag, 3 }, { "version", no_argument, &flag, 3 },
{ "dh-param-file", required_argument, &flag, 4 }, { "dh-param-file", required_argument, &flag, 4 },
{ "early-response", no_argument, &flag, 5 }, { "early-response", no_argument, &flag, 5 },
{nullptr, 0, nullptr, 0}}; { nullptr, 0, nullptr, 0 }
};
int option_index = 0; int option_index = 0;
int c = int c = getopt_long(argc, argv, "DVb:c:d:ehn:p:va:", long_options,
getopt_long(argc, argv, "DVb:c:d:ehn:p:v", long_options, &option_index); &option_index);
char *end; char *end;
if (c == -1) { if (c == -1) {
break; break;
} }
switch (c) { switch (c) {
case 'a':
config.address = optarg;
break;
case 'D': case 'D':
config.daemon = true; config.daemon = true;
break; break;