moonbridge
changeset 125:d9cc81641175
Code cleanup; Allow binding to specific interfaces
author | jbe |
---|---|
date | Tue Apr 14 00:26:38 2015 +0200 (2015-04-14) |
parents | 61a2f55b3538 |
children | e0ab9fd00cb1 |
files | example_application.lua helloworld.lua moonbridge.c |
line diff
1.1 --- a/example_application.lua Sun Apr 12 00:33:08 2015 +0200 1.2 +++ b/example_application.lua Tue Apr 14 00:26:38 2015 +0200 1.3 @@ -154,10 +154,10 @@ 1.4 1.5 listen{ 1.6 -- listen to a tcp version 4 socket 1.7 - { proto = "tcp4", port = 8080, localhost = false }, 1.8 + --{ proto = "tcp", host = "0.0.0.0", port = 8080 }, 1.9 1.10 -- listen to a tcp version 6 socket 1.11 - --{ proto = "tcp6", port = 8080, localhost = false }, 1.12 + { proto = "tcp", host = "::", port = 8080}, 1.13 1.14 -- listen to a unix domain socket 1.15 --{ proto = "local", path = 'socket' },
2.1 --- a/helloworld.lua Sun Apr 12 00:33:08 2015 +0200 2.2 +++ b/helloworld.lua Tue Apr 14 00:26:38 2015 +0200 2.3 @@ -6,8 +6,8 @@ 2.4 local http = require "moonbridge_http" 2.5 2.6 listen{ 2.7 - { proto = "tcp4", port = 8080, localhost = true }, 2.8 - { proto = "tcp6", port = 8080, localhost = true }, 2.9 + { proto = "tcp", host = "127.0.0.1", port = 8080 }, -- IPv4 2.10 + { proto = "tcp", host = "::1", port = 8080 }, -- IPv6 2.11 connect = http.generate_handler( 2.12 function(request) 2.13 local function error_response(status)
3.1 --- a/moonbridge.c Sun Apr 12 00:33:08 2015 +0200 3.2 +++ b/moonbridge.c Tue Apr 14 00:26:38 2015 +0200 3.3 @@ -33,6 +33,8 @@ 3.4 #include <sys/socket.h> 3.5 #include <sys/un.h> 3.6 #include <netinet/in.h> 3.7 +#include <netdb.h> 3.8 +#include <arpa/inet.h> 3.9 #include <poll.h> 3.10 #include <signal.h> 3.11 #include <sys/wait.h> 3.12 @@ -123,8 +125,7 @@ 3.13 /* Enum for 'proto' field of struct moonbr_listener */ 3.14 #define MOONBR_PROTO_INTERVAL 1 3.15 #define MOONBR_PROTO_LOCAL 2 3.16 -#define MOONBR_PROTO_TCP6 3 3.17 -#define MOONBR_PROTO_TCP4 4 3.18 +#define MOONBR_PROTO_TCP 3 3.19 3.20 /* Data structure for a pool's listener that can accept incoming connections */ 3.21 struct moonbr_listener { 3.22 @@ -140,11 +141,19 @@ 3.23 struct timeval wakeup; /* point in time of next invocation */ 3.24 } interval; 3.25 struct { 3.26 - char *path; /* full path name (i.e. filename with path) of UNIX domain socket */ 3.27 - } local; 3.28 + union { 3.29 + struct sockaddr addr_abstract; 3.30 + struct sockaddr_un addr_un; 3.31 + struct sockaddr_in addr_in; 3.32 + struct sockaddr_in6 addr_in6; 3.33 + } addr; 3.34 + socklen_t addrlen; 3.35 + } socket; 3.36 + } type_specific; 3.37 + union { 3.38 struct { 3.39 + char ip[INET6_ADDRSTRLEN]; /* IP to listen on */ 3.40 int port; /* port number to listen on (in host endianess) */ 3.41 - int localhost_only; /* nonzero = listen on localhost only */ 3.42 } tcp; 3.43 } proto_specific; 3.44 int listenfd; /* -1 = none */ 3.45 @@ -409,8 +418,8 @@ 3.46 for (i=0; i<pool->listener_count; i++) { 3.47 struct moonbr_listener *listener = &pool->listener[i]; 3.48 if (listener->proto == MOONBR_PROTO_LOCAL) { 3.49 - moonbr_log(LOG_INFO, "Unlinking local socket \"%s\"", listener->proto_specific.local.path); 3.50 - if (unlink(listener->proto_specific.local.path)) { 3.51 + moonbr_log(LOG_INFO, "Unlinking local socket \"%s\"", listener->type_specific.socket.addr.addr_un.sun_path); 3.52 + if (unlink(listener->type_specific.socket.addr.addr_un.sun_path)) { 3.53 moonbr_log(LOG_ERR, "Error while unlinking local socket: %s", strerror(errno)); 3.54 } 3.55 } 3.56 @@ -488,15 +497,9 @@ 3.57 struct moonbr_listener *listener = &pool->listener[i]; 3.58 if ( 3.59 listener->proto == MOONBR_PROTO_INTERVAL && 3.60 - listener->proto_specific.interval.name 3.61 + listener->type_specific.interval.name 3.62 ) { 3.63 - free(listener->proto_specific.interval.name); 3.64 - } 3.65 - if ( 3.66 - listener->proto == MOONBR_PROTO_LOCAL && 3.67 - listener->proto_specific.local.path 3.68 - ) { 3.69 - free(listener->proto_specific.local.path); 3.70 + free(listener->type_specific.interval.name); 3.71 } 3.72 } 3.73 free(pool); 3.74 @@ -512,122 +515,53 @@ 3.75 switch (listener->proto) { 3.76 case MOONBR_PROTO_INTERVAL: 3.77 /* nothing to do here: starting intervals is performed in moonbr_run() function */ 3.78 - if (!listener->proto_specific.interval.name) { 3.79 + if (!listener->type_specific.interval.name) { 3.80 moonbr_log(LOG_INFO, "Adding unnamed interval listener"); 3.81 } else { 3.82 - moonbr_log(LOG_INFO, "Adding interval listener \"%s\"", listener->proto_specific.interval.name); 3.83 + moonbr_log(LOG_INFO, "Adding interval listener \"%s\"", listener->type_specific.interval.name); 3.84 } 3.85 break; 3.86 case MOONBR_PROTO_LOCAL: 3.87 - moonbr_log(LOG_INFO, "Adding local socket listener for path \"%s\"", listener->proto_specific.local.path); 3.88 + moonbr_log(LOG_INFO, "Adding local socket listener for path \"%s\"", listener->type_specific.socket.addr.addr_un.sun_path); 3.89 + listener->listenfd = socket(PF_LOCAL, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); 3.90 + if (listener->listenfd == -1) goto moonbr_start_pool_error; 3.91 + if (!unlink(listener->type_specific.socket.addr.addr_un.sun_path)) { 3.92 + moonbr_log(LOG_WARNING, "Unlinked named socket \"%s\" prior to listening", listener->type_specific.socket.addr.addr_un.sun_path); 3.93 + } else { 3.94 + if (errno != ENOENT) { 3.95 + 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)); 3.96 + } 3.97 + } 3.98 + if ( 3.99 + bind(listener->listenfd, &listener->type_specific.socket.addr.addr_abstract, listener->type_specific.socket.addrlen) 3.100 + ) goto moonbr_start_pool_error; 3.101 + if (listen(listener->listenfd, MOONBR_LISTEN_BACKLOG)) goto moonbr_start_pool_error; 3.102 + break; 3.103 + case MOONBR_PROTO_TCP: 3.104 + moonbr_log(LOG_INFO, "Adding TCP listener on interface \"%s\", port %i", listener->proto_specific.tcp.ip, listener->proto_specific.tcp.port); 3.105 + listener->listenfd = socket(listener->type_specific.socket.addr.addr_abstract.sa_family, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); 3.106 + if (listener->listenfd == -1) goto moonbr_start_pool_error; 3.107 { 3.108 - struct sockaddr_un servaddr = { .sun_family = AF_UNIX }; 3.109 - const int path_maxlen = sizeof(struct sockaddr_un) - ( 3.110 - (void *)servaddr.sun_path - (void *)&servaddr 3.111 - ); 3.112 - if ( 3.113 - snprintf( 3.114 - servaddr.sun_path, 3.115 - path_maxlen, 3.116 - "%s", 3.117 - listener->proto_specific.local.path 3.118 - ) >= path_maxlen 3.119 - ) { 3.120 - errno = ENAMETOOLONG; 3.121 - }; 3.122 - listener->listenfd = socket(PF_LOCAL, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); 3.123 - if (listener->listenfd == -1) goto moonbr_start_pool_error; 3.124 - if (!unlink(listener->proto_specific.local.path)) { 3.125 - moonbr_log(LOG_WARNING, "Unlinked named socket \"%s\" prior to listening", listener->proto_specific.local.path); 3.126 - } else { 3.127 - if (errno != ENOENT) { 3.128 - moonbr_log(LOG_ERR, "Could not unlink named socket \"%s\" prior to listening: %s", listener->proto_specific.local.path, strerror(errno)); 3.129 - } 3.130 - } 3.131 - if ( 3.132 - bind(listener->listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) 3.133 - ) goto moonbr_start_pool_error; 3.134 - if (listen(listener->listenfd, MOONBR_LISTEN_BACKLOG)) goto moonbr_start_pool_error; 3.135 - } 3.136 - break; 3.137 - case MOONBR_PROTO_TCP6: 3.138 - if (listener->proto_specific.tcp.localhost_only) { 3.139 - moonbr_log(LOG_INFO, "Adding localhost TCP/IPv6 listener on port %i", listener->proto_specific.tcp.port); 3.140 - } else { 3.141 - moonbr_log(LOG_INFO, "Adding public TCP/IPv6 listener on port %i", listener->proto_specific.tcp.port); 3.142 + /* avoid "Address already in use" error when restarting service */ 3.143 + static const int reuseval = 1; 3.144 + if (setsockopt( 3.145 + listener->listenfd, SOL_SOCKET, SO_REUSEADDR, &reuseval, sizeof(reuseval) 3.146 + )) goto moonbr_start_pool_error; 3.147 } 3.148 { 3.149 - struct sockaddr_in6 servaddr = { 3.150 - .sin6_family = AF_INET6, 3.151 - .sin6_port = htons(listener->proto_specific.tcp.port) 3.152 + /* default to send TCP RST when process terminates unexpectedly */ 3.153 + static const struct linger lingerval = { 3.154 + .l_onoff = 1, 3.155 + .l_linger = 0 3.156 }; 3.157 - listener->listenfd = socket(PF_INET6, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); 3.158 - if (listener->listenfd == -1) goto moonbr_start_pool_error; 3.159 - { 3.160 - /* avoid "Address already in use" error when restarting service */ 3.161 - static const int reuseval = 1; 3.162 - if (setsockopt( 3.163 - listener->listenfd, SOL_SOCKET, SO_REUSEADDR, &reuseval, sizeof(reuseval) 3.164 - )) goto moonbr_start_pool_error; 3.165 - } 3.166 - { 3.167 - /* default to send TCP RST when process terminates unexpectedly */ 3.168 - static const struct linger lingerval = { 3.169 - .l_onoff = 1, 3.170 - .l_linger = 0 3.171 - }; 3.172 - if (setsockopt( 3.173 - listener->listenfd, SOL_SOCKET, SO_LINGER, &lingerval, sizeof(lingerval) 3.174 - )) goto moonbr_start_pool_error; 3.175 - } 3.176 - if (listener->proto_specific.tcp.localhost_only) { 3.177 - servaddr.sin6_addr.s6_addr[15] = 1; 3.178 - } 3.179 - if ( 3.180 - bind(listener->listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) 3.181 - ) goto moonbr_start_pool_error; 3.182 - if (listen(listener->listenfd, MOONBR_LISTEN_BACKLOG)) goto moonbr_start_pool_error; 3.183 + if (setsockopt( 3.184 + listener->listenfd, SOL_SOCKET, SO_LINGER, &lingerval, sizeof(lingerval) 3.185 + )) goto moonbr_start_pool_error; 3.186 } 3.187 - break; 3.188 - case MOONBR_PROTO_TCP4: 3.189 - if (listener->proto_specific.tcp.localhost_only) { 3.190 - moonbr_log(LOG_INFO, "Adding localhost TCP/IPv4 listener on port %i", listener->proto_specific.tcp.port); 3.191 - } else { 3.192 - moonbr_log(LOG_INFO, "Adding public TCP/IPv4 listener on port %i", listener->proto_specific.tcp.port); 3.193 - } 3.194 - { 3.195 - struct sockaddr_in servaddr = { 3.196 - .sin_family = AF_INET, 3.197 - .sin_port = htons(listener->proto_specific.tcp.port) 3.198 - }; 3.199 - listener->listenfd = socket(PF_INET, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); 3.200 - if (listener->listenfd == -1) goto moonbr_start_pool_error; 3.201 - { 3.202 - /* avoid "Address already in use" error when restarting service */ 3.203 - static const int reuseval = 1; 3.204 - if (setsockopt( 3.205 - listener->listenfd, SOL_SOCKET, SO_REUSEADDR, &reuseval, sizeof(reuseval) 3.206 - )) goto moonbr_start_pool_error; 3.207 - } 3.208 - { 3.209 - /* default to send TCP RST when process terminates unexpectedly */ 3.210 - static const struct linger lingerval = { 3.211 - .l_onoff = 1, 3.212 - .l_linger = 0 3.213 - }; 3.214 - if (setsockopt( 3.215 - listener->listenfd, SOL_SOCKET, SO_LINGER, &lingerval, sizeof(lingerval) 3.216 - )) goto moonbr_start_pool_error; 3.217 - } 3.218 - if (listener->proto_specific.tcp.localhost_only) { 3.219 - ((uint8_t *)&servaddr.sin_addr.s_addr)[0] = 127; 3.220 - ((uint8_t *)&servaddr.sin_addr.s_addr)[3] = 1; 3.221 - } 3.222 - if ( 3.223 - bind(listener->listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) 3.224 - ) goto moonbr_start_pool_error; 3.225 - if (listen(listener->listenfd, MOONBR_LISTEN_BACKLOG)) goto moonbr_start_pool_error; 3.226 - } 3.227 + if ( 3.228 + bind(listener->listenfd, &listener->type_specific.socket.addr.addr_abstract, listener->type_specific.socket.addrlen) 3.229 + ) goto moonbr_start_pool_error; 3.230 + if (listen(listener->listenfd, MOONBR_LISTEN_BACKLOG)) goto moonbr_start_pool_error; 3.231 break; 3.232 default: 3.233 moonbr_log(LOG_CRIT, "Internal error (should not happen): Unexpected value in listener.proto field"); 3.234 @@ -847,8 +781,8 @@ 3.235 if (fd < 0) { 3.236 lua_newtable(L); 3.237 lua_pushstring(L, 3.238 - listener->proto_specific.interval.name ? 3.239 - listener->proto_specific.interval.name : "" 3.240 + listener->type_specific.interval.name ? 3.241 + listener->type_specific.interval.name : "" 3.242 ); 3.243 lua_setfield(L, -2, "interval"); 3.244 } else { 3.245 @@ -1462,32 +1396,23 @@ 3.246 static void moonbr_connect(struct moonbr_pool *pool) { 3.247 struct moonbr_listener *listener = moonbr_pop_connected_listener(pool); 3.248 struct moonbr_worker *worker; 3.249 - switch (listener->proto) { 3.250 - case MOONBR_PROTO_INTERVAL: 3.251 + if (listener->proto == MOONBR_PROTO_INTERVAL) { 3.252 worker = moonbr_pop_idle_worker(pool); 3.253 if (moonbr_stat) { 3.254 - 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); 3.255 + 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); 3.256 } 3.257 worker->restart_interval_listener = listener; 3.258 moonbr_send_control_message(worker, MOONBR_COMMAND_CONNECT, -1, listener); 3.259 /* do not push listener to queue of idle listeners yet */ 3.260 - break; 3.261 - case MOONBR_PROTO_LOCAL: 3.262 + } else { 3.263 + int peerfd; 3.264 do { 3.265 - int peerfd; 3.266 - struct sockaddr_un peeraddr; 3.267 - socklen_t peeraddr_len = sizeof(struct sockaddr_un); 3.268 - peerfd = accept4( 3.269 - listener->listenfd, 3.270 - (struct sockaddr *)&peeraddr, 3.271 - &peeraddr_len, 3.272 - SOCK_CLOEXEC 3.273 - ); 3.274 + peerfd = accept4(listener->listenfd, NULL, NULL, SOCK_CLOEXEC); 3.275 if (peerfd == -1) { 3.276 if (errno == EWOULDBLOCK) { 3.277 break; 3.278 } else if (errno == ECONNABORTED) { 3.279 - moonbr_log(LOG_WARNING, "Connection aborted before accepting it (proto=\"local\", path=\"%s\")", listener->proto_specific.local.path); 3.280 + moonbr_log(LOG_WARNING, "Connection aborted before accepting it"); 3.281 break; 3.282 } else if (errno != EINTR) { 3.283 moonbr_log(LOG_ERR, "Could not accept socket connection: %s", strerror(errno)); 3.284 @@ -1496,7 +1421,7 @@ 3.285 } else { 3.286 worker = moonbr_pop_idle_worker(pool); 3.287 if (moonbr_stat) { 3.288 - 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); 3.289 + moonbr_log(LOG_INFO, "Dispatching connection for pool #%i to PID %i", listener->pool->poolnum, (int)worker->pid); 3.290 } 3.291 moonbr_send_control_message(worker, MOONBR_COMMAND_CONNECT, peerfd, listener); 3.292 if (close(peerfd) && errno != EINTR) { 3.293 @@ -1506,80 +1431,6 @@ 3.294 } 3.295 } while (pool->first_idle_worker); 3.296 moonbr_add_idle_listener(listener); 3.297 - break; 3.298 - case MOONBR_PROTO_TCP6: 3.299 - do { 3.300 - int peerfd; 3.301 - struct sockaddr_in6 peeraddr; 3.302 - socklen_t peeraddr_len = sizeof(struct sockaddr_in6); 3.303 - peerfd = accept4( 3.304 - listener->listenfd, 3.305 - (struct sockaddr *)&peeraddr, 3.306 - &peeraddr_len, 3.307 - SOCK_CLOEXEC 3.308 - ); 3.309 - if (peerfd == -1) { 3.310 - if (errno == EWOULDBLOCK) { 3.311 - break; 3.312 - } else if (errno == ECONNABORTED) { 3.313 - moonbr_log(LOG_WARNING, "Connection aborted before accepting it (proto=\"tcp6\", port=%i)", listener->proto_specific.tcp.port); 3.314 - break; 3.315 - } else if (errno != EINTR) { 3.316 - moonbr_log(LOG_ERR, "Could not accept socket connection: %s", strerror(errno)); 3.317 - moonbr_terminate_error(); 3.318 - } 3.319 - } else { 3.320 - worker = moonbr_pop_idle_worker(pool); 3.321 - if (moonbr_stat) { 3.322 - 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); 3.323 - } 3.324 - moonbr_send_control_message(worker, MOONBR_COMMAND_CONNECT, peerfd, listener); 3.325 - if (close(peerfd) && errno != EINTR) { 3.326 - moonbr_log(LOG_ERR, "Could not close incoming socket connection in parent process: %s", strerror(errno)); 3.327 - moonbr_terminate_error(); 3.328 - } 3.329 - } 3.330 - } while (pool->first_idle_worker); 3.331 - moonbr_add_idle_listener(listener); 3.332 - break; 3.333 - case MOONBR_PROTO_TCP4: 3.334 - do { 3.335 - int peerfd; 3.336 - struct sockaddr_in peeraddr; 3.337 - socklen_t peeraddr_len = sizeof(struct sockaddr_in); 3.338 - peerfd = accept4( 3.339 - listener->listenfd, 3.340 - (struct sockaddr *)&peeraddr, 3.341 - &peeraddr_len, 3.342 - SOCK_CLOEXEC 3.343 - ); 3.344 - if (peerfd == -1) { 3.345 - if (errno == EWOULDBLOCK) { 3.346 - break; 3.347 - } else if (errno == ECONNABORTED) { 3.348 - moonbr_log(LOG_WARNING, "Connection aborted before accepting it (proto=\"tcp4\", port=%i)", listener->proto_specific.tcp.port); 3.349 - break; 3.350 - } else if (errno != EINTR) { 3.351 - moonbr_log(LOG_ERR, "Could not accept socket connection: %s", strerror(errno)); 3.352 - moonbr_terminate_error(); 3.353 - } 3.354 - } else { 3.355 - worker = moonbr_pop_idle_worker(pool); 3.356 - if (moonbr_stat) { 3.357 - 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); 3.358 - } 3.359 - moonbr_send_control_message(worker, MOONBR_COMMAND_CONNECT, peerfd, listener); 3.360 - if (close(peerfd) && errno != EINTR) { 3.361 - moonbr_log(LOG_ERR, "Could not close incoming socket connection in parent process: %s", strerror(errno)); 3.362 - moonbr_terminate_error(); 3.363 - } 3.364 - } 3.365 - } while (pool->first_idle_worker); 3.366 - moonbr_add_idle_listener(listener); 3.367 - break; 3.368 - default: 3.369 - moonbr_log(LOG_ERR, "Internal error (should not happen): Unexpected value in listener.proto field"); 3.370 - moonbr_terminate_error(); 3.371 } 3.372 } 3.373 3.374 @@ -1598,8 +1449,8 @@ 3.375 if (listener->proto == MOONBR_PROTO_INTERVAL) { 3.376 timeradd( 3.377 &now, 3.378 - &listener->proto_specific.interval.delay, 3.379 - &listener->proto_specific.interval.wakeup 3.380 + &listener->type_specific.interval.delay, 3.381 + &listener->type_specific.interval.wakeup 3.382 ); 3.383 } 3.384 } 3.385 @@ -1615,20 +1466,20 @@ 3.386 if (listener) { 3.387 moonbr_add_idle_listener(listener); 3.388 worker->restart_interval_listener = NULL; 3.389 - if (listener->proto_specific.interval.strict) { 3.390 + if (listener->type_specific.interval.strict) { 3.391 timeradd( 3.392 - &listener->proto_specific.interval.wakeup, 3.393 - &listener->proto_specific.interval.delay, 3.394 - &listener->proto_specific.interval.wakeup 3.395 + &listener->type_specific.interval.wakeup, 3.396 + &listener->type_specific.interval.delay, 3.397 + &listener->type_specific.interval.wakeup 3.398 ); 3.399 - if (timercmp(&listener->proto_specific.interval.wakeup, now, <)) { 3.400 - listener->proto_specific.interval.wakeup = *now; 3.401 + if (timercmp(&listener->type_specific.interval.wakeup, now, <)) { 3.402 + listener->type_specific.interval.wakeup = *now; 3.403 } 3.404 } else { 3.405 timeradd( 3.406 now, 3.407 - &listener->proto_specific.interval.delay, 3.408 - &listener->proto_specific.interval.wakeup 3.409 + &listener->type_specific.interval.delay, 3.410 + &listener->type_specific.interval.wakeup 3.411 ); 3.412 } 3.413 } 3.414 @@ -1687,7 +1538,7 @@ 3.415 moonbr_add_connected_listener(listener); 3.416 } 3.417 } else if (listener->proto == MOONBR_PROTO_INTERVAL) { 3.418 - if (!timercmp(&listener->proto_specific.interval.wakeup, &now, >)) { 3.419 + if (!timercmp(&listener->type_specific.interval.wakeup, &now, >)) { 3.420 moonbr_remove_idle_listener(listener); 3.421 moonbr_add_connected_listener(listener); 3.422 } 3.423 @@ -1799,7 +1650,7 @@ 3.424 /* calculate wakeup time for interval listeners */ 3.425 for (listener=pool->first_idle_listener; listener; listener=listener->next_listener) { 3.426 if (listener->proto == MOONBR_PROTO_INTERVAL) { 3.427 - moonbr_calc_wait(&wait, &listener->proto_specific.interval.wakeup); 3.428 + moonbr_calc_wait(&wait, &listener->type_specific.interval.wakeup); 3.429 } 3.430 } 3.431 /* calculate wakeup time for idle workers (only first idle worker is significant) */ 3.432 @@ -2063,7 +1914,7 @@ 3.433 { 3.434 const char *name = lua_tostring(L, -1); 3.435 if (name) { 3.436 - if (asprintf(&listener->proto_specific.interval.name, "%s", name) < 0) { 3.437 + if (asprintf(&listener->type_specific.interval.name, "%s", name) < 0) { 3.438 moonbr_log(LOG_CRIT, "Memory allocation_error"); 3.439 moonbr_terminate_error(); 3.440 } 3.441 @@ -2071,68 +1922,116 @@ 3.442 } 3.443 lua_getfield(L, 3, "delay"); 3.444 if ( 3.445 - !moonbr_lua_totimeval(L, -1, &listener->proto_specific.interval.delay) || 3.446 - !timerisset(&listener->proto_specific.interval.delay) 3.447 + !moonbr_lua_totimeval(L, -1, &listener->type_specific.interval.delay) || 3.448 + !timerisset(&listener->type_specific.interval.delay) 3.449 ) { 3.450 luaL_error(L, "No valid interval delay specified; use listen{{proto=\"interval\", delay=...}, ...}"); 3.451 } 3.452 lua_getfield(L, 3, "strict"); 3.453 if (!lua_isnil(L, -1)) { 3.454 if (lua_isboolean(L, -1)) { 3.455 - if (lua_toboolean(L, -1)) listener->proto_specific.interval.strict = 1; 3.456 + if (lua_toboolean(L, -1)) listener->type_specific.interval.strict = 1; 3.457 } else { 3.458 luaL_error(L, "Option \"strict\" must be a boolean if set; use listen{{proto=\"interval\", strict=true, ...}, ...}"); 3.459 } 3.460 } 3.461 } else if (proto && !strcmp(proto, "local")) { 3.462 + const char *path; 3.463 + const int path_maxlen = ( 3.464 + sizeof(listener->type_specific.socket.addr.addr_un) - 3.465 + ((void *)listener->type_specific.socket.addr.addr_un.sun_path - (void *)&listener->type_specific.socket.addr.addr_un) 3.466 + ) - 1; /* one byte for termination */ 3.467 listener->proto = MOONBR_PROTO_LOCAL; 3.468 lua_getfield(L, 3, "path"); 3.469 - { 3.470 - const char *path = lua_tostring(L, -1); 3.471 - if (!path) { 3.472 - luaL_error(L, "No valid path specified for local socket; use listen{{proto=\"local\", path=...}, ...}"); 3.473 - } 3.474 - if (asprintf(&listener->proto_specific.local.path, "%s", path) < 0) { 3.475 - moonbr_log(LOG_CRIT, "Memory allocation_error"); 3.476 - moonbr_terminate_error(); 3.477 + path = lua_tostring(L, -1); 3.478 + if (!path) { 3.479 + luaL_error(L, "No valid path specified for local socket; use listen{{proto=\"local\", path=...}, ...}"); 3.480 + } 3.481 + if (strlen(path) > path_maxlen) { 3.482 + luaL_error(L, "Path name for local socket exceeded maximum length of %i characters", path_maxlen); 3.483 + } 3.484 + strcpy(listener->type_specific.socket.addr.addr_un.sun_path, path); 3.485 + } else if (proto && !strcmp(proto, "tcp")) { 3.486 + const char *host, *port; 3.487 + struct addrinfo hints = { 0, }; 3.488 + struct addrinfo *res, *addrinfo; 3.489 + int errcode; 3.490 + const char *ip; 3.491 + lua_getfield(L, 3, "host"); 3.492 + host = lua_isnil(L, -1) ? "::" : lua_tostring(L, -1); 3.493 + if (!host) { 3.494 + luaL_error(L, "No host specified; use listen{{proto=\"tcp\", host=...}, ...}"); 3.495 + } 3.496 + lua_getfield(L, 3, "port"); 3.497 + port = lua_tostring(L, -1); 3.498 + if (!port) { 3.499 + luaL_error(L, "No port specified; use listen{{proto=\"tcp\", host=...}, ...}"); 3.500 + } 3.501 + hints.ai_family = AF_UNSPEC; 3.502 + hints.ai_socktype = SOCK_STREAM; 3.503 + hints.ai_protocol = IPPROTO_TCP; 3.504 + hints.ai_flags = AI_ADDRCONFIG | AI_PASSIVE; 3.505 + errcode = getaddrinfo(host, port, &hints, &res); 3.506 + if (errcode) { 3.507 + freeaddrinfo(res); 3.508 + if (errcode == EAI_SYSTEM) { 3.509 + char errmsg[MOONBR_MAXSTRERRORLEN]; 3.510 + strerror_r(errno, errmsg, MOONBR_MAXSTRERRORLEN); /* use thread-safe call in case child created threads */ 3.511 + luaL_error(L, "Could not resolve host: %s: %s", gai_strerror(errcode), errmsg); 3.512 + } else { 3.513 + luaL_error(L, "Could not resolve host: %s", gai_strerror(errcode)); 3.514 } 3.515 } 3.516 - } else if (proto && !strcmp(proto, "tcp6")) { 3.517 - listener->proto = MOONBR_PROTO_TCP6; 3.518 - lua_getfield(L, 3, "port"); 3.519 - listener->proto_specific.tcp.port = lua_tointeger(L, -1); 3.520 - if ( 3.521 - listener->proto_specific.tcp.port < 1 || 3.522 - listener->proto_specific.tcp.port > 65535 3.523 - ) { 3.524 - luaL_error(L, "No valid port number specified; use listen{{proto=\"tcp6\", port=...}, ...}"); 3.525 + for (addrinfo=res; addrinfo; addrinfo=addrinfo->ai_next) { 3.526 + if (addrinfo->ai_family == AF_INET6) goto moonbr_listen_init_pool_found; 3.527 + } 3.528 + for (addrinfo=res; addrinfo; addrinfo=addrinfo->ai_next) { 3.529 + if (addrinfo->ai_family == AF_INET) goto moonbr_listen_init_pool_found; 3.530 } 3.531 - lua_getfield(L, 3, "localhost"); 3.532 - if (!lua_isnil(L, -1)) { 3.533 - if (lua_isboolean(L, -1)) { 3.534 - if (lua_toboolean(L, -1)) listener->proto_specific.tcp.localhost_only = 1; 3.535 - } else { 3.536 - luaL_error(L, "Option \"localhost\" must be a boolean if set; use listen{{proto=\"tcp6\", localhost=true, ...}, ...}"); 3.537 - } 3.538 + addrinfo = res; 3.539 + moonbr_listen_init_pool_found: 3.540 + if (addrinfo->ai_addrlen > sizeof(listener->type_specific.socket.addr)) { 3.541 + moonbr_log(LOG_CRIT, "Size of ai_addrlen is unexpectedly big (should not happen)"); 3.542 + moonbr_terminate_error(); 3.543 } 3.544 - } else if (proto && !strcmp(proto, "tcp4")) { 3.545 - listener->proto = MOONBR_PROTO_TCP4; 3.546 - lua_getfield(L, 3, "port"); 3.547 - listener->proto_specific.tcp.port = lua_tointeger(L, -1); 3.548 - if ( 3.549 - listener->proto_specific.tcp.port < 1 || 3.550 - listener->proto_specific.tcp.port > 65535 3.551 - ) { 3.552 - luaL_error(L, "No valid port number specified; use listen{{proto=\"tcp4\", port=...}, ...}"); 3.553 + memcpy(&listener->type_specific.socket.addr, addrinfo->ai_addr, addrinfo->ai_addrlen); 3.554 + listener->type_specific.socket.addrlen = addrinfo->ai_addrlen; 3.555 + switch (addrinfo->ai_family) { 3.556 + case AF_INET6: 3.557 + ip = inet_ntop( 3.558 + addrinfo->ai_family, 3.559 + &((struct sockaddr_in6 *)addrinfo->ai_addr)->sin6_addr, 3.560 + listener->proto_specific.tcp.ip, 3.561 + INET6_ADDRSTRLEN 3.562 + ); 3.563 + if (!ip) { 3.564 + moonbr_log(LOG_CRIT, "System error in inet_ntop call: %s", strerror(errno)); 3.565 + moonbr_terminate_error(); 3.566 + } 3.567 + listener->proto_specific.tcp.port = ntohs(((struct sockaddr_in6 *)addrinfo->ai_addr)->sin6_port); 3.568 + break; 3.569 + case AF_INET: 3.570 + ip = inet_ntop( 3.571 + addrinfo->ai_family, 3.572 + &((struct sockaddr_in *)addrinfo->ai_addr)->sin_addr, 3.573 + listener->proto_specific.tcp.ip, 3.574 + INET6_ADDRSTRLEN 3.575 + ); 3.576 + if (!ip) { 3.577 + moonbr_log(LOG_CRIT, "System error in inet_ntop call: %s", strerror(errno)); 3.578 + moonbr_terminate_error(); 3.579 + } 3.580 + listener->proto_specific.tcp.port = ntohs(((struct sockaddr_in *)addrinfo->ai_addr)->sin_port); 3.581 + break; 3.582 + default: 3.583 + strcpy(listener->proto_specific.tcp.ip, "unknown"); 3.584 + listener->proto_specific.tcp.port = 0; 3.585 } 3.586 - lua_getfield(L, 3, "localhost"); 3.587 - if (!lua_isnil(L, -1)) { 3.588 - if (lua_isboolean(L, -1)) { 3.589 - if (lua_toboolean(L, -1)) listener->proto_specific.tcp.localhost_only = 1; 3.590 - } else { 3.591 - luaL_error(L, "Option \"localhost\" must be a boolean if set; use listen{{proto=\"tcp4\", localhost=true, ...}, ...}"); 3.592 - } 3.593 - } 3.594 + listener->proto = MOONBR_PROTO_TCP; 3.595 + } else if (proto) { 3.596 + luaL_error(L, "Unknown protocol \"%s\"", proto); 3.597 + } else { 3.598 + luaL_error(L, "No valid protocol specified; use listen{{proto=..., ...}, ...}"); 3.599 } 3.600 } 3.601 lua_settop(L, 2); 3.602 @@ -2200,38 +2099,19 @@ 3.603 int i; 3.604 i = moonbr_start_pool(pool); 3.605 if (i >= 0) { 3.606 - struct moonbr_listener *listener = &pool->listener[i]; 3.607 - switch (listener->proto) { 3.608 - case MOONBR_PROTO_INTERVAL: 3.609 - lua_pushfstring(L, "Could not initialize listener #%d (proto=\"interval\"): %s", i+1, strerror(errno)); 3.610 - break; 3.611 - case MOONBR_PROTO_LOCAL: 3.612 - lua_pushfstring(L, "Could not initialize listener #%d (proto=\"local\", path=\"%s\"): %s", i+1, listener->proto_specific.local.path, strerror(errno)); 3.613 - break; 3.614 - case MOONBR_PROTO_TCP6: 3.615 - lua_pushfstring(L, "Could not initialize listener #%d (proto=\"tcp6\", port=%d): %s", i+1, listener->proto_specific.tcp.port, strerror(errno)); 3.616 - break; 3.617 - case MOONBR_PROTO_TCP4: 3.618 - lua_pushfstring(L, "Could not initialize listener #%d (proto=\"tcp4\", port=%d): %s", i+1, listener->proto_specific.tcp.port, strerror(errno)); 3.619 - break; 3.620 - default: 3.621 - moonbr_log(LOG_ERR, "Internal error (should not happen): Unexpected value in listener.proto field"); 3.622 - moonbr_terminate_error(); 3.623 - } 3.624 - goto moonbr_listen_error; 3.625 + lua_pushfstring(L, "Could not initialize listener #%d: %s", i+1, strerror(errno)); 3.626 + moonbr_listen_error: 3.627 + moonbr_destroy_pool(pool); 3.628 + lua_pushnil(L); 3.629 + lua_rawsetp(L, LUA_REGISTRYINDEX, moonbr_luakey_prepare_func(pool)); 3.630 + lua_pushnil(L); 3.631 + lua_rawsetp(L, LUA_REGISTRYINDEX, moonbr_luakey_connect_func(pool)); 3.632 + lua_pushnil(L); 3.633 + lua_rawsetp(L, LUA_REGISTRYINDEX, moonbr_luakey_finish_func(pool)); 3.634 + lua_error(L); 3.635 } 3.636 } 3.637 return 0; 3.638 - moonbr_listen_error: 3.639 - moonbr_destroy_pool(pool); 3.640 - lua_pushnil(L); 3.641 - lua_rawsetp(L, LUA_REGISTRYINDEX, moonbr_luakey_prepare_func(pool)); 3.642 - lua_pushnil(L); 3.643 - lua_rawsetp(L, LUA_REGISTRYINDEX, moonbr_luakey_connect_func(pool)); 3.644 - lua_pushnil(L); 3.645 - lua_rawsetp(L, LUA_REGISTRYINDEX, moonbr_luakey_finish_func(pool)); 3.646 - lua_error(L); 3.647 - return 0; /* avoid compiler warning */ 3.648 } 3.649 3.650