# HG changeset patch # User jbe # Date 1428963998 -7200 # Node ID d9cc81641175906c6f3d71abf59b07bebda52288 # Parent 61a2f55b353878124cde9ff82e23117b1ca2ab9e Code cleanup; Allow binding to specific interfaces diff -r 61a2f55b3538 -r d9cc81641175 example_application.lua --- a/example_application.lua Sun Apr 12 00:33:08 2015 +0200 +++ b/example_application.lua Tue Apr 14 00:26:38 2015 +0200 @@ -154,10 +154,10 @@ listen{ -- listen to a tcp version 4 socket - { proto = "tcp4", port = 8080, localhost = false }, + --{ proto = "tcp", host = "0.0.0.0", port = 8080 }, -- listen to a tcp version 6 socket - --{ proto = "tcp6", port = 8080, localhost = false }, + { proto = "tcp", host = "::", port = 8080}, -- listen to a unix domain socket --{ proto = "local", path = 'socket' }, diff -r 61a2f55b3538 -r d9cc81641175 helloworld.lua --- a/helloworld.lua Sun Apr 12 00:33:08 2015 +0200 +++ b/helloworld.lua Tue Apr 14 00:26:38 2015 +0200 @@ -6,8 +6,8 @@ local http = require "moonbridge_http" listen{ - { proto = "tcp4", port = 8080, localhost = true }, - { proto = "tcp6", port = 8080, localhost = true }, + { proto = "tcp", host = "127.0.0.1", port = 8080 }, -- IPv4 + { proto = "tcp", host = "::1", port = 8080 }, -- IPv6 connect = http.generate_handler( function(request) local function error_response(status) diff -r 61a2f55b3538 -r d9cc81641175 moonbridge.c --- a/moonbridge.c Sun Apr 12 00:33:08 2015 +0200 +++ b/moonbridge.c Tue Apr 14 00:26:38 2015 +0200 @@ -33,6 +33,8 @@ #include #include #include +#include +#include #include #include #include @@ -123,8 +125,7 @@ /* Enum for 'proto' field of struct moonbr_listener */ #define MOONBR_PROTO_INTERVAL 1 #define MOONBR_PROTO_LOCAL 2 -#define MOONBR_PROTO_TCP6 3 -#define MOONBR_PROTO_TCP4 4 +#define MOONBR_PROTO_TCP 3 /* Data structure for a pool's listener that can accept incoming connections */ struct moonbr_listener { @@ -140,11 +141,19 @@ struct timeval wakeup; /* point in time of next invocation */ } interval; struct { - char *path; /* full path name (i.e. filename with path) of UNIX domain socket */ - } local; + union { + struct sockaddr addr_abstract; + struct sockaddr_un addr_un; + struct sockaddr_in addr_in; + struct sockaddr_in6 addr_in6; + } addr; + socklen_t addrlen; + } socket; + } type_specific; + union { struct { + char ip[INET6_ADDRSTRLEN]; /* IP to listen on */ int port; /* port number to listen on (in host endianess) */ - int localhost_only; /* nonzero = listen on localhost only */ } tcp; } proto_specific; int listenfd; /* -1 = none */ @@ -409,8 +418,8 @@ for (i=0; ilistener_count; i++) { struct moonbr_listener *listener = &pool->listener[i]; if (listener->proto == MOONBR_PROTO_LOCAL) { - moonbr_log(LOG_INFO, "Unlinking local socket \"%s\"", listener->proto_specific.local.path); - if (unlink(listener->proto_specific.local.path)) { + moonbr_log(LOG_INFO, "Unlinking local socket \"%s\"", listener->type_specific.socket.addr.addr_un.sun_path); + if (unlink(listener->type_specific.socket.addr.addr_un.sun_path)) { moonbr_log(LOG_ERR, "Error while unlinking local socket: %s", strerror(errno)); } } @@ -488,15 +497,9 @@ struct moonbr_listener *listener = &pool->listener[i]; if ( listener->proto == MOONBR_PROTO_INTERVAL && - listener->proto_specific.interval.name + listener->type_specific.interval.name ) { - free(listener->proto_specific.interval.name); - } - if ( - listener->proto == MOONBR_PROTO_LOCAL && - listener->proto_specific.local.path - ) { - free(listener->proto_specific.local.path); + free(listener->type_specific.interval.name); } } free(pool); @@ -512,122 +515,53 @@ switch (listener->proto) { case MOONBR_PROTO_INTERVAL: /* nothing to do here: starting intervals is performed in moonbr_run() function */ - if (!listener->proto_specific.interval.name) { + if (!listener->type_specific.interval.name) { moonbr_log(LOG_INFO, "Adding unnamed interval listener"); } else { - moonbr_log(LOG_INFO, "Adding interval listener \"%s\"", listener->proto_specific.interval.name); + moonbr_log(LOG_INFO, "Adding interval listener \"%s\"", listener->type_specific.interval.name); } break; case MOONBR_PROTO_LOCAL: - moonbr_log(LOG_INFO, "Adding local socket listener for path \"%s\"", listener->proto_specific.local.path); + moonbr_log(LOG_INFO, "Adding local socket listener for path \"%s\"", listener->type_specific.socket.addr.addr_un.sun_path); + listener->listenfd = socket(PF_LOCAL, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); + if (listener->listenfd == -1) goto moonbr_start_pool_error; + if (!unlink(listener->type_specific.socket.addr.addr_un.sun_path)) { + moonbr_log(LOG_WARNING, "Unlinked named socket \"%s\" prior to listening", listener->type_specific.socket.addr.addr_un.sun_path); + } else { + if (errno != ENOENT) { + moonbr_log(LOG_ERR, "Could not unlink named socket \"%s\" prior to listening: %s", listener->type_specific.socket.addr.addr_un.sun_path, strerror(errno)); + } + } + if ( + bind(listener->listenfd, &listener->type_specific.socket.addr.addr_abstract, listener->type_specific.socket.addrlen) + ) goto moonbr_start_pool_error; + if (listen(listener->listenfd, MOONBR_LISTEN_BACKLOG)) goto moonbr_start_pool_error; + break; + case MOONBR_PROTO_TCP: + moonbr_log(LOG_INFO, "Adding TCP listener on interface \"%s\", port %i", listener->proto_specific.tcp.ip, listener->proto_specific.tcp.port); + listener->listenfd = socket(listener->type_specific.socket.addr.addr_abstract.sa_family, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); + if (listener->listenfd == -1) goto moonbr_start_pool_error; { - struct sockaddr_un servaddr = { .sun_family = AF_UNIX }; - const int path_maxlen = sizeof(struct sockaddr_un) - ( - (void *)servaddr.sun_path - (void *)&servaddr - ); - if ( - snprintf( - servaddr.sun_path, - path_maxlen, - "%s", - listener->proto_specific.local.path - ) >= path_maxlen - ) { - errno = ENAMETOOLONG; - }; - listener->listenfd = socket(PF_LOCAL, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); - if (listener->listenfd == -1) goto moonbr_start_pool_error; - if (!unlink(listener->proto_specific.local.path)) { - moonbr_log(LOG_WARNING, "Unlinked named socket \"%s\" prior to listening", listener->proto_specific.local.path); - } else { - if (errno != ENOENT) { - moonbr_log(LOG_ERR, "Could not unlink named socket \"%s\" prior to listening: %s", listener->proto_specific.local.path, strerror(errno)); - } - } - if ( - bind(listener->listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) - ) goto moonbr_start_pool_error; - if (listen(listener->listenfd, MOONBR_LISTEN_BACKLOG)) goto moonbr_start_pool_error; - } - break; - case MOONBR_PROTO_TCP6: - if (listener->proto_specific.tcp.localhost_only) { - moonbr_log(LOG_INFO, "Adding localhost TCP/IPv6 listener on port %i", listener->proto_specific.tcp.port); - } else { - moonbr_log(LOG_INFO, "Adding public TCP/IPv6 listener on port %i", listener->proto_specific.tcp.port); + /* avoid "Address already in use" error when restarting service */ + static const int reuseval = 1; + if (setsockopt( + listener->listenfd, SOL_SOCKET, SO_REUSEADDR, &reuseval, sizeof(reuseval) + )) goto moonbr_start_pool_error; } { - struct sockaddr_in6 servaddr = { - .sin6_family = AF_INET6, - .sin6_port = htons(listener->proto_specific.tcp.port) + /* default to send TCP RST when process terminates unexpectedly */ + static const struct linger lingerval = { + .l_onoff = 1, + .l_linger = 0 }; - listener->listenfd = socket(PF_INET6, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); - if (listener->listenfd == -1) goto moonbr_start_pool_error; - { - /* avoid "Address already in use" error when restarting service */ - static const int reuseval = 1; - if (setsockopt( - listener->listenfd, SOL_SOCKET, SO_REUSEADDR, &reuseval, sizeof(reuseval) - )) goto moonbr_start_pool_error; - } - { - /* default to send TCP RST when process terminates unexpectedly */ - static const struct linger lingerval = { - .l_onoff = 1, - .l_linger = 0 - }; - if (setsockopt( - listener->listenfd, SOL_SOCKET, SO_LINGER, &lingerval, sizeof(lingerval) - )) goto moonbr_start_pool_error; - } - if (listener->proto_specific.tcp.localhost_only) { - servaddr.sin6_addr.s6_addr[15] = 1; - } - if ( - bind(listener->listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) - ) goto moonbr_start_pool_error; - if (listen(listener->listenfd, MOONBR_LISTEN_BACKLOG)) goto moonbr_start_pool_error; + if (setsockopt( + listener->listenfd, SOL_SOCKET, SO_LINGER, &lingerval, sizeof(lingerval) + )) goto moonbr_start_pool_error; } - break; - case MOONBR_PROTO_TCP4: - if (listener->proto_specific.tcp.localhost_only) { - moonbr_log(LOG_INFO, "Adding localhost TCP/IPv4 listener on port %i", listener->proto_specific.tcp.port); - } else { - moonbr_log(LOG_INFO, "Adding public TCP/IPv4 listener on port %i", listener->proto_specific.tcp.port); - } - { - struct sockaddr_in servaddr = { - .sin_family = AF_INET, - .sin_port = htons(listener->proto_specific.tcp.port) - }; - listener->listenfd = socket(PF_INET, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); - if (listener->listenfd == -1) goto moonbr_start_pool_error; - { - /* avoid "Address already in use" error when restarting service */ - static const int reuseval = 1; - if (setsockopt( - listener->listenfd, SOL_SOCKET, SO_REUSEADDR, &reuseval, sizeof(reuseval) - )) goto moonbr_start_pool_error; - } - { - /* default to send TCP RST when process terminates unexpectedly */ - static const struct linger lingerval = { - .l_onoff = 1, - .l_linger = 0 - }; - if (setsockopt( - listener->listenfd, SOL_SOCKET, SO_LINGER, &lingerval, sizeof(lingerval) - )) goto moonbr_start_pool_error; - } - if (listener->proto_specific.tcp.localhost_only) { - ((uint8_t *)&servaddr.sin_addr.s_addr)[0] = 127; - ((uint8_t *)&servaddr.sin_addr.s_addr)[3] = 1; - } - if ( - bind(listener->listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) - ) goto moonbr_start_pool_error; - if (listen(listener->listenfd, MOONBR_LISTEN_BACKLOG)) goto moonbr_start_pool_error; - } + if ( + bind(listener->listenfd, &listener->type_specific.socket.addr.addr_abstract, listener->type_specific.socket.addrlen) + ) goto moonbr_start_pool_error; + if (listen(listener->listenfd, MOONBR_LISTEN_BACKLOG)) goto moonbr_start_pool_error; break; default: moonbr_log(LOG_CRIT, "Internal error (should not happen): Unexpected value in listener.proto field"); @@ -847,8 +781,8 @@ if (fd < 0) { lua_newtable(L); lua_pushstring(L, - listener->proto_specific.interval.name ? - listener->proto_specific.interval.name : "" + listener->type_specific.interval.name ? + listener->type_specific.interval.name : "" ); lua_setfield(L, -2, "interval"); } else { @@ -1462,32 +1396,23 @@ static void moonbr_connect(struct moonbr_pool *pool) { struct moonbr_listener *listener = moonbr_pop_connected_listener(pool); struct moonbr_worker *worker; - switch (listener->proto) { - case MOONBR_PROTO_INTERVAL: + if (listener->proto == MOONBR_PROTO_INTERVAL) { worker = moonbr_pop_idle_worker(pool); if (moonbr_stat) { - moonbr_log(LOG_INFO, "Dispatching interval timer \"%s\" of pool #%i to PID %i", listener->proto_specific.interval.name, listener->pool->poolnum, (int)worker->pid); + moonbr_log(LOG_INFO, "Dispatching interval timer \"%s\" of pool #%i to PID %i", listener->type_specific.interval.name, listener->pool->poolnum, (int)worker->pid); } worker->restart_interval_listener = listener; moonbr_send_control_message(worker, MOONBR_COMMAND_CONNECT, -1, listener); /* do not push listener to queue of idle listeners yet */ - break; - case MOONBR_PROTO_LOCAL: + } else { + int peerfd; do { - int peerfd; - struct sockaddr_un peeraddr; - socklen_t peeraddr_len = sizeof(struct sockaddr_un); - peerfd = accept4( - listener->listenfd, - (struct sockaddr *)&peeraddr, - &peeraddr_len, - SOCK_CLOEXEC - ); + peerfd = accept4(listener->listenfd, NULL, NULL, SOCK_CLOEXEC); if (peerfd == -1) { if (errno == EWOULDBLOCK) { break; } else if (errno == ECONNABORTED) { - moonbr_log(LOG_WARNING, "Connection aborted before accepting it (proto=\"local\", path=\"%s\")", listener->proto_specific.local.path); + moonbr_log(LOG_WARNING, "Connection aborted before accepting it"); break; } else if (errno != EINTR) { moonbr_log(LOG_ERR, "Could not accept socket connection: %s", strerror(errno)); @@ -1496,7 +1421,7 @@ } else { worker = moonbr_pop_idle_worker(pool); if (moonbr_stat) { - moonbr_log(LOG_INFO, "Dispatching local socket connection on path \"%s\" for pool #%i to PID %i", listener->proto_specific.local.path, listener->pool->poolnum, (int)worker->pid); + moonbr_log(LOG_INFO, "Dispatching connection for pool #%i to PID %i", listener->pool->poolnum, (int)worker->pid); } moonbr_send_control_message(worker, MOONBR_COMMAND_CONNECT, peerfd, listener); if (close(peerfd) && errno != EINTR) { @@ -1506,80 +1431,6 @@ } } while (pool->first_idle_worker); moonbr_add_idle_listener(listener); - break; - case MOONBR_PROTO_TCP6: - do { - int peerfd; - struct sockaddr_in6 peeraddr; - socklen_t peeraddr_len = sizeof(struct sockaddr_in6); - peerfd = accept4( - listener->listenfd, - (struct sockaddr *)&peeraddr, - &peeraddr_len, - SOCK_CLOEXEC - ); - if (peerfd == -1) { - if (errno == EWOULDBLOCK) { - break; - } else if (errno == ECONNABORTED) { - moonbr_log(LOG_WARNING, "Connection aborted before accepting it (proto=\"tcp6\", port=%i)", listener->proto_specific.tcp.port); - break; - } else if (errno != EINTR) { - moonbr_log(LOG_ERR, "Could not accept socket connection: %s", strerror(errno)); - moonbr_terminate_error(); - } - } else { - worker = moonbr_pop_idle_worker(pool); - if (moonbr_stat) { - moonbr_log(LOG_INFO, "Dispatching TCP/IPv6 connection for pool #%i on port %i to PID %i", listener->pool->poolnum, listener->proto_specific.tcp.port, (int)worker->pid); - } - moonbr_send_control_message(worker, MOONBR_COMMAND_CONNECT, peerfd, listener); - if (close(peerfd) && errno != EINTR) { - moonbr_log(LOG_ERR, "Could not close incoming socket connection in parent process: %s", strerror(errno)); - moonbr_terminate_error(); - } - } - } while (pool->first_idle_worker); - moonbr_add_idle_listener(listener); - break; - case MOONBR_PROTO_TCP4: - do { - int peerfd; - struct sockaddr_in peeraddr; - socklen_t peeraddr_len = sizeof(struct sockaddr_in); - peerfd = accept4( - listener->listenfd, - (struct sockaddr *)&peeraddr, - &peeraddr_len, - SOCK_CLOEXEC - ); - if (peerfd == -1) { - if (errno == EWOULDBLOCK) { - break; - } else if (errno == ECONNABORTED) { - moonbr_log(LOG_WARNING, "Connection aborted before accepting it (proto=\"tcp4\", port=%i)", listener->proto_specific.tcp.port); - break; - } else if (errno != EINTR) { - moonbr_log(LOG_ERR, "Could not accept socket connection: %s", strerror(errno)); - moonbr_terminate_error(); - } - } else { - worker = moonbr_pop_idle_worker(pool); - if (moonbr_stat) { - moonbr_log(LOG_INFO, "Dispatching TCP/IPv4 connection for pool #%i on port %i to PID %i", listener->pool->poolnum, listener->proto_specific.tcp.port, (int)worker->pid); - } - moonbr_send_control_message(worker, MOONBR_COMMAND_CONNECT, peerfd, listener); - if (close(peerfd) && errno != EINTR) { - moonbr_log(LOG_ERR, "Could not close incoming socket connection in parent process: %s", strerror(errno)); - moonbr_terminate_error(); - } - } - } while (pool->first_idle_worker); - moonbr_add_idle_listener(listener); - break; - default: - moonbr_log(LOG_ERR, "Internal error (should not happen): Unexpected value in listener.proto field"); - moonbr_terminate_error(); } } @@ -1598,8 +1449,8 @@ if (listener->proto == MOONBR_PROTO_INTERVAL) { timeradd( &now, - &listener->proto_specific.interval.delay, - &listener->proto_specific.interval.wakeup + &listener->type_specific.interval.delay, + &listener->type_specific.interval.wakeup ); } } @@ -1615,20 +1466,20 @@ if (listener) { moonbr_add_idle_listener(listener); worker->restart_interval_listener = NULL; - if (listener->proto_specific.interval.strict) { + if (listener->type_specific.interval.strict) { timeradd( - &listener->proto_specific.interval.wakeup, - &listener->proto_specific.interval.delay, - &listener->proto_specific.interval.wakeup + &listener->type_specific.interval.wakeup, + &listener->type_specific.interval.delay, + &listener->type_specific.interval.wakeup ); - if (timercmp(&listener->proto_specific.interval.wakeup, now, <)) { - listener->proto_specific.interval.wakeup = *now; + if (timercmp(&listener->type_specific.interval.wakeup, now, <)) { + listener->type_specific.interval.wakeup = *now; } } else { timeradd( now, - &listener->proto_specific.interval.delay, - &listener->proto_specific.interval.wakeup + &listener->type_specific.interval.delay, + &listener->type_specific.interval.wakeup ); } } @@ -1687,7 +1538,7 @@ moonbr_add_connected_listener(listener); } } else if (listener->proto == MOONBR_PROTO_INTERVAL) { - if (!timercmp(&listener->proto_specific.interval.wakeup, &now, >)) { + if (!timercmp(&listener->type_specific.interval.wakeup, &now, >)) { moonbr_remove_idle_listener(listener); moonbr_add_connected_listener(listener); } @@ -1799,7 +1650,7 @@ /* calculate wakeup time for interval listeners */ for (listener=pool->first_idle_listener; listener; listener=listener->next_listener) { if (listener->proto == MOONBR_PROTO_INTERVAL) { - moonbr_calc_wait(&wait, &listener->proto_specific.interval.wakeup); + moonbr_calc_wait(&wait, &listener->type_specific.interval.wakeup); } } /* calculate wakeup time for idle workers (only first idle worker is significant) */ @@ -2063,7 +1914,7 @@ { const char *name = lua_tostring(L, -1); if (name) { - if (asprintf(&listener->proto_specific.interval.name, "%s", name) < 0) { + if (asprintf(&listener->type_specific.interval.name, "%s", name) < 0) { moonbr_log(LOG_CRIT, "Memory allocation_error"); moonbr_terminate_error(); } @@ -2071,68 +1922,116 @@ } lua_getfield(L, 3, "delay"); if ( - !moonbr_lua_totimeval(L, -1, &listener->proto_specific.interval.delay) || - !timerisset(&listener->proto_specific.interval.delay) + !moonbr_lua_totimeval(L, -1, &listener->type_specific.interval.delay) || + !timerisset(&listener->type_specific.interval.delay) ) { luaL_error(L, "No valid interval delay specified; use listen{{proto=\"interval\", delay=...}, ...}"); } lua_getfield(L, 3, "strict"); if (!lua_isnil(L, -1)) { if (lua_isboolean(L, -1)) { - if (lua_toboolean(L, -1)) listener->proto_specific.interval.strict = 1; + if (lua_toboolean(L, -1)) listener->type_specific.interval.strict = 1; } else { luaL_error(L, "Option \"strict\" must be a boolean if set; use listen{{proto=\"interval\", strict=true, ...}, ...}"); } } } else if (proto && !strcmp(proto, "local")) { + const char *path; + const int path_maxlen = ( + sizeof(listener->type_specific.socket.addr.addr_un) - + ((void *)listener->type_specific.socket.addr.addr_un.sun_path - (void *)&listener->type_specific.socket.addr.addr_un) + ) - 1; /* one byte for termination */ listener->proto = MOONBR_PROTO_LOCAL; lua_getfield(L, 3, "path"); - { - const char *path = lua_tostring(L, -1); - if (!path) { - luaL_error(L, "No valid path specified for local socket; use listen{{proto=\"local\", path=...}, ...}"); - } - if (asprintf(&listener->proto_specific.local.path, "%s", path) < 0) { - moonbr_log(LOG_CRIT, "Memory allocation_error"); - moonbr_terminate_error(); + path = lua_tostring(L, -1); + if (!path) { + luaL_error(L, "No valid path specified for local socket; use listen{{proto=\"local\", path=...}, ...}"); + } + if (strlen(path) > path_maxlen) { + luaL_error(L, "Path name for local socket exceeded maximum length of %i characters", path_maxlen); + } + strcpy(listener->type_specific.socket.addr.addr_un.sun_path, path); + } else if (proto && !strcmp(proto, "tcp")) { + const char *host, *port; + struct addrinfo hints = { 0, }; + struct addrinfo *res, *addrinfo; + int errcode; + const char *ip; + lua_getfield(L, 3, "host"); + host = lua_isnil(L, -1) ? "::" : lua_tostring(L, -1); + if (!host) { + luaL_error(L, "No host specified; use listen{{proto=\"tcp\", host=...}, ...}"); + } + lua_getfield(L, 3, "port"); + port = lua_tostring(L, -1); + if (!port) { + luaL_error(L, "No port specified; use listen{{proto=\"tcp\", host=...}, ...}"); + } + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + hints.ai_flags = AI_ADDRCONFIG | AI_PASSIVE; + errcode = getaddrinfo(host, port, &hints, &res); + if (errcode) { + freeaddrinfo(res); + if (errcode == EAI_SYSTEM) { + char errmsg[MOONBR_MAXSTRERRORLEN]; + strerror_r(errno, errmsg, MOONBR_MAXSTRERRORLEN); /* use thread-safe call in case child created threads */ + luaL_error(L, "Could not resolve host: %s: %s", gai_strerror(errcode), errmsg); + } else { + luaL_error(L, "Could not resolve host: %s", gai_strerror(errcode)); } } - } else if (proto && !strcmp(proto, "tcp6")) { - listener->proto = MOONBR_PROTO_TCP6; - lua_getfield(L, 3, "port"); - listener->proto_specific.tcp.port = lua_tointeger(L, -1); - if ( - listener->proto_specific.tcp.port < 1 || - listener->proto_specific.tcp.port > 65535 - ) { - luaL_error(L, "No valid port number specified; use listen{{proto=\"tcp6\", port=...}, ...}"); + for (addrinfo=res; addrinfo; addrinfo=addrinfo->ai_next) { + if (addrinfo->ai_family == AF_INET6) goto moonbr_listen_init_pool_found; + } + for (addrinfo=res; addrinfo; addrinfo=addrinfo->ai_next) { + if (addrinfo->ai_family == AF_INET) goto moonbr_listen_init_pool_found; } - lua_getfield(L, 3, "localhost"); - if (!lua_isnil(L, -1)) { - if (lua_isboolean(L, -1)) { - if (lua_toboolean(L, -1)) listener->proto_specific.tcp.localhost_only = 1; - } else { - luaL_error(L, "Option \"localhost\" must be a boolean if set; use listen{{proto=\"tcp6\", localhost=true, ...}, ...}"); - } + addrinfo = res; + moonbr_listen_init_pool_found: + if (addrinfo->ai_addrlen > sizeof(listener->type_specific.socket.addr)) { + moonbr_log(LOG_CRIT, "Size of ai_addrlen is unexpectedly big (should not happen)"); + moonbr_terminate_error(); } - } else if (proto && !strcmp(proto, "tcp4")) { - listener->proto = MOONBR_PROTO_TCP4; - lua_getfield(L, 3, "port"); - listener->proto_specific.tcp.port = lua_tointeger(L, -1); - if ( - listener->proto_specific.tcp.port < 1 || - listener->proto_specific.tcp.port > 65535 - ) { - luaL_error(L, "No valid port number specified; use listen{{proto=\"tcp4\", port=...}, ...}"); + memcpy(&listener->type_specific.socket.addr, addrinfo->ai_addr, addrinfo->ai_addrlen); + listener->type_specific.socket.addrlen = addrinfo->ai_addrlen; + switch (addrinfo->ai_family) { + case AF_INET6: + ip = inet_ntop( + addrinfo->ai_family, + &((struct sockaddr_in6 *)addrinfo->ai_addr)->sin6_addr, + listener->proto_specific.tcp.ip, + INET6_ADDRSTRLEN + ); + if (!ip) { + moonbr_log(LOG_CRIT, "System error in inet_ntop call: %s", strerror(errno)); + moonbr_terminate_error(); + } + listener->proto_specific.tcp.port = ntohs(((struct sockaddr_in6 *)addrinfo->ai_addr)->sin6_port); + break; + case AF_INET: + ip = inet_ntop( + addrinfo->ai_family, + &((struct sockaddr_in *)addrinfo->ai_addr)->sin_addr, + listener->proto_specific.tcp.ip, + INET6_ADDRSTRLEN + ); + if (!ip) { + moonbr_log(LOG_CRIT, "System error in inet_ntop call: %s", strerror(errno)); + moonbr_terminate_error(); + } + listener->proto_specific.tcp.port = ntohs(((struct sockaddr_in *)addrinfo->ai_addr)->sin_port); + break; + default: + strcpy(listener->proto_specific.tcp.ip, "unknown"); + listener->proto_specific.tcp.port = 0; } - lua_getfield(L, 3, "localhost"); - if (!lua_isnil(L, -1)) { - if (lua_isboolean(L, -1)) { - if (lua_toboolean(L, -1)) listener->proto_specific.tcp.localhost_only = 1; - } else { - luaL_error(L, "Option \"localhost\" must be a boolean if set; use listen{{proto=\"tcp4\", localhost=true, ...}, ...}"); - } - } + listener->proto = MOONBR_PROTO_TCP; + } else if (proto) { + luaL_error(L, "Unknown protocol \"%s\"", proto); + } else { + luaL_error(L, "No valid protocol specified; use listen{{proto=..., ...}, ...}"); } } lua_settop(L, 2); @@ -2200,38 +2099,19 @@ int i; i = moonbr_start_pool(pool); if (i >= 0) { - struct moonbr_listener *listener = &pool->listener[i]; - switch (listener->proto) { - case MOONBR_PROTO_INTERVAL: - lua_pushfstring(L, "Could not initialize listener #%d (proto=\"interval\"): %s", i+1, strerror(errno)); - break; - case MOONBR_PROTO_LOCAL: - lua_pushfstring(L, "Could not initialize listener #%d (proto=\"local\", path=\"%s\"): %s", i+1, listener->proto_specific.local.path, strerror(errno)); - break; - case MOONBR_PROTO_TCP6: - lua_pushfstring(L, "Could not initialize listener #%d (proto=\"tcp6\", port=%d): %s", i+1, listener->proto_specific.tcp.port, strerror(errno)); - break; - case MOONBR_PROTO_TCP4: - lua_pushfstring(L, "Could not initialize listener #%d (proto=\"tcp4\", port=%d): %s", i+1, listener->proto_specific.tcp.port, strerror(errno)); - break; - default: - moonbr_log(LOG_ERR, "Internal error (should not happen): Unexpected value in listener.proto field"); - moonbr_terminate_error(); - } - goto moonbr_listen_error; + lua_pushfstring(L, "Could not initialize listener #%d: %s", i+1, strerror(errno)); + moonbr_listen_error: + moonbr_destroy_pool(pool); + lua_pushnil(L); + lua_rawsetp(L, LUA_REGISTRYINDEX, moonbr_luakey_prepare_func(pool)); + lua_pushnil(L); + lua_rawsetp(L, LUA_REGISTRYINDEX, moonbr_luakey_connect_func(pool)); + lua_pushnil(L); + lua_rawsetp(L, LUA_REGISTRYINDEX, moonbr_luakey_finish_func(pool)); + lua_error(L); } } return 0; - moonbr_listen_error: - moonbr_destroy_pool(pool); - lua_pushnil(L); - lua_rawsetp(L, LUA_REGISTRYINDEX, moonbr_luakey_prepare_func(pool)); - lua_pushnil(L); - lua_rawsetp(L, LUA_REGISTRYINDEX, moonbr_luakey_connect_func(pool)); - lua_pushnil(L); - lua_rawsetp(L, LUA_REGISTRYINDEX, moonbr_luakey_finish_func(pool)); - lua_error(L); - return 0; /* avoid compiler warning */ }