Listen both on IPv6 and IPv4 if possible

This commit is contained in:
Tatsuhiro Tsujikawa 2012-06-06 22:43:35 +09:00
parent 28ed887463
commit 8da4938031
1 changed files with 63 additions and 16 deletions

View File

@ -29,6 +29,8 @@
#include <sys/socket.h> #include <sys/socket.h>
#include <netdb.h> #include <netdb.h>
#include <signal.h> #include <signal.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <cstdlib> #include <cstdlib>
@ -72,10 +74,19 @@ int cache_downstream_host_address()
LOG(FATAL) << "Unable to get downstream address: " << gai_strerror(rv); LOG(FATAL) << "Unable to get downstream address: " << gai_strerror(rv);
DIE(); DIE();
} }
char host[NI_MAXHOST];
rv = getnameinfo(res->ai_addr, res->ai_addrlen, host, sizeof(host),
0, 0, NI_NUMERICHOST);
if(rv == 0) {
LOG(INFO) << "Using first returned address for downstream " LOG(INFO) << "Using first returned address for downstream "
<< get_config()->downstream_host << host
<< ", port " << ", port "
<< get_config()->downstream_port; << get_config()->downstream_port;
} else {
LOG(FATAL) << gai_strerror(rv);
DIE();
}
memcpy(&mod_config()->downstream_addr, res->ai_addr, res->ai_addrlen); memcpy(&mod_config()->downstream_addr, res->ai_addr, res->ai_addrlen);
mod_config()->downstream_addrlen = res->ai_addrlen; mod_config()->downstream_addrlen = res->ai_addrlen;
freeaddrinfo(res); freeaddrinfo(res);
@ -91,7 +102,7 @@ void evlistener_errorcb(evconnlistener *listener, void *ptr)
} // namespace } // namespace
namespace { namespace {
evconnlistener* create_evlistener(ListenHandler *handler) evconnlistener* create_evlistener(ListenHandler *handler, int family)
{ {
// TODO Listen both IPv4 and IPv6 // TODO Listen both IPv4 and IPv6
addrinfo hints; addrinfo hints;
@ -100,12 +111,13 @@ evconnlistener* create_evlistener(ListenHandler *handler)
char service[10]; char service[10];
snprintf(service, sizeof(service), "%u", get_config()->port); snprintf(service, sizeof(service), "%u", get_config()->port);
memset(&hints, 0, sizeof(addrinfo)); memset(&hints, 0, sizeof(addrinfo));
hints.ai_family = AF_UNSPEC; hints.ai_family = family;
hints.ai_socktype = SOCK_STREAM; hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE; hints.ai_flags = AI_PASSIVE;
#ifdef AI_ADDRCONFIG #ifdef AI_ADDRCONFIG
hints.ai_flags |= AI_ADDRCONFIG; hints.ai_flags |= AI_ADDRCONFIG;
#endif // AI_ADDRCONFIG #endif // AI_ADDRCONFIG
addrinfo *res, *rp; addrinfo *res, *rp;
r = getaddrinfo(get_config()->host, service, &hints, &res); r = getaddrinfo(get_config()->host, service, &hints, &res);
if(r != 0) { if(r != 0) {
@ -124,23 +136,46 @@ evconnlistener* create_evlistener(ListenHandler *handler)
continue; continue;
} }
evutil_make_socket_nonblocking(fd); evutil_make_socket_nonblocking(fd);
#ifdef IPV6_V6ONLY
if(family == AF_INET6) {
if(setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &val,
static_cast<socklen_t>(sizeof(val))) == -1) {
close(fd);
continue;
}
}
#endif // IPV6_V6ONLY
if(bind(fd, rp->ai_addr, rp->ai_addrlen) == 0) { if(bind(fd, rp->ai_addr, rp->ai_addrlen) == 0) {
break; break;
} }
close(fd); close(fd);
} }
if(rp) {
char host[NI_MAXHOST];
r = getnameinfo(rp->ai_addr, rp->ai_addrlen, host, sizeof(host),
0, 0, NI_NUMERICHOST);
if(r == 0) {
LOG(INFO) << "Listening on " << host << ", port " << get_config()->port;
} else {
LOG(FATAL) << gai_strerror(r);
DIE();
}
}
freeaddrinfo(res); freeaddrinfo(res);
if(rp == 0) { if(rp == 0) {
LOG(ERROR) << "No valid address returned for host " << get_config()->host if(ENABLE_LOG) {
<< ", port " << get_config()->port; LOG(INFO) << "Listening " << (family == AF_INET ? "IPv4" : "IPv6")
<< " socket failed";
}
return 0; return 0;
} }
evconnlistener *evlistener = evconnlistener_new evconnlistener *evlistener = evconnlistener_new
(handler->get_evbase(), (handler->get_evbase(),
ssl_acceptcb, ssl_acceptcb,
handler, handler,
LEV_OPT_REUSEABLE | LEV_OPT_CLOSE_ON_FREE, LEV_OPT_REUSEABLE | LEV_OPT_CLOSE_ON_FREE,
1024, 512,
fd); fd);
evconnlistener_set_error_cb(evlistener, evlistener_errorcb); evconnlistener_set_error_cb(evlistener, evlistener_errorcb);
return evlistener; return evlistener;
@ -151,20 +186,32 @@ namespace {
int event_loop() int event_loop()
{ {
event_base *evbase = event_base_new(); event_base *evbase = event_base_new();
ListenHandler *listener_handler = new ListenHandler(evbase); ListenHandler *listener_handler = new ListenHandler(evbase);
evconnlistener *evlistener6, *evlistener4;
evlistener6 = create_evlistener(listener_handler, AF_INET6);
evlistener4 = create_evlistener(listener_handler, AF_INET);
if(!evlistener6 && !evlistener4) {
LOG(FATAL) << "Failed to listen on address "
<< get_config()->host << ", port " << get_config()->port;
DIE();
}
if(get_config()->num_worker > 1) { if(get_config()->num_worker > 1) {
listener_handler->create_worker_thread(get_config()->num_worker); listener_handler->create_worker_thread(get_config()->num_worker);
} }
evconnlistener *evlistener = create_evlistener(listener_handler);
if(evlistener == NULL) {
return -1;
}
if(ENABLE_LOG) { if(ENABLE_LOG) {
LOG(INFO) << "Entering event loop"; LOG(INFO) << "Entering event loop";
} }
event_base_loop(evbase, 0); event_base_loop(evbase, 0);
if(evlistener4) {
evconnlistener_free(evlistener); evconnlistener_free(evlistener4);
}
if(evlistener6) {
evconnlistener_free(evlistener6);
}
return 0; return 0;
} }
} // namespace } // namespace
@ -180,7 +227,7 @@ int main(int argc, char **argv)
SSL_load_error_strings(); SSL_load_error_strings();
SSL_library_init(); SSL_library_init();
Log::set_severity_level(WARNING); Log::set_severity_level(INFO);
create_config(); create_config();
mod_config()->server_name = "shrpx spdylay/"SPDYLAY_VERSION; mod_config()->server_name = "shrpx spdylay/"SPDYLAY_VERSION;