moonbridge
diff moonbridge.c @ 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 |
line diff
1.1 --- a/moonbridge.c Sun Apr 12 00:33:08 2015 +0200 1.2 +++ b/moonbridge.c Tue Apr 14 00:26:38 2015 +0200 1.3 @@ -33,6 +33,8 @@ 1.4 #include <sys/socket.h> 1.5 #include <sys/un.h> 1.6 #include <netinet/in.h> 1.7 +#include <netdb.h> 1.8 +#include <arpa/inet.h> 1.9 #include <poll.h> 1.10 #include <signal.h> 1.11 #include <sys/wait.h> 1.12 @@ -123,8 +125,7 @@ 1.13 /* Enum for 'proto' field of struct moonbr_listener */ 1.14 #define MOONBR_PROTO_INTERVAL 1 1.15 #define MOONBR_PROTO_LOCAL 2 1.16 -#define MOONBR_PROTO_TCP6 3 1.17 -#define MOONBR_PROTO_TCP4 4 1.18 +#define MOONBR_PROTO_TCP 3 1.19 1.20 /* Data structure for a pool's listener that can accept incoming connections */ 1.21 struct moonbr_listener { 1.22 @@ -140,11 +141,19 @@ 1.23 struct timeval wakeup; /* point in time of next invocation */ 1.24 } interval; 1.25 struct { 1.26 - char *path; /* full path name (i.e. filename with path) of UNIX domain socket */ 1.27 - } local; 1.28 + union { 1.29 + struct sockaddr addr_abstract; 1.30 + struct sockaddr_un addr_un; 1.31 + struct sockaddr_in addr_in; 1.32 + struct sockaddr_in6 addr_in6; 1.33 + } addr; 1.34 + socklen_t addrlen; 1.35 + } socket; 1.36 + } type_specific; 1.37 + union { 1.38 struct { 1.39 + char ip[INET6_ADDRSTRLEN]; /* IP to listen on */ 1.40 int port; /* port number to listen on (in host endianess) */ 1.41 - int localhost_only; /* nonzero = listen on localhost only */ 1.42 } tcp; 1.43 } proto_specific; 1.44 int listenfd; /* -1 = none */ 1.45 @@ -409,8 +418,8 @@ 1.46 for (i=0; i<pool->listener_count; i++) { 1.47 struct moonbr_listener *listener = &pool->listener[i]; 1.48 if (listener->proto == MOONBR_PROTO_LOCAL) { 1.49 - moonbr_log(LOG_INFO, "Unlinking local socket \"%s\"", listener->proto_specific.local.path); 1.50 - if (unlink(listener->proto_specific.local.path)) { 1.51 + moonbr_log(LOG_INFO, "Unlinking local socket \"%s\"", listener->type_specific.socket.addr.addr_un.sun_path); 1.52 + if (unlink(listener->type_specific.socket.addr.addr_un.sun_path)) { 1.53 moonbr_log(LOG_ERR, "Error while unlinking local socket: %s", strerror(errno)); 1.54 } 1.55 } 1.56 @@ -488,15 +497,9 @@ 1.57 struct moonbr_listener *listener = &pool->listener[i]; 1.58 if ( 1.59 listener->proto == MOONBR_PROTO_INTERVAL && 1.60 - listener->proto_specific.interval.name 1.61 + listener->type_specific.interval.name 1.62 ) { 1.63 - free(listener->proto_specific.interval.name); 1.64 - } 1.65 - if ( 1.66 - listener->proto == MOONBR_PROTO_LOCAL && 1.67 - listener->proto_specific.local.path 1.68 - ) { 1.69 - free(listener->proto_specific.local.path); 1.70 + free(listener->type_specific.interval.name); 1.71 } 1.72 } 1.73 free(pool); 1.74 @@ -512,122 +515,53 @@ 1.75 switch (listener->proto) { 1.76 case MOONBR_PROTO_INTERVAL: 1.77 /* nothing to do here: starting intervals is performed in moonbr_run() function */ 1.78 - if (!listener->proto_specific.interval.name) { 1.79 + if (!listener->type_specific.interval.name) { 1.80 moonbr_log(LOG_INFO, "Adding unnamed interval listener"); 1.81 } else { 1.82 - moonbr_log(LOG_INFO, "Adding interval listener \"%s\"", listener->proto_specific.interval.name); 1.83 + moonbr_log(LOG_INFO, "Adding interval listener \"%s\"", listener->type_specific.interval.name); 1.84 } 1.85 break; 1.86 case MOONBR_PROTO_LOCAL: 1.87 - moonbr_log(LOG_INFO, "Adding local socket listener for path \"%s\"", listener->proto_specific.local.path); 1.88 + moonbr_log(LOG_INFO, "Adding local socket listener for path \"%s\"", listener->type_specific.socket.addr.addr_un.sun_path); 1.89 + listener->listenfd = socket(PF_LOCAL, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); 1.90 + if (listener->listenfd == -1) goto moonbr_start_pool_error; 1.91 + if (!unlink(listener->type_specific.socket.addr.addr_un.sun_path)) { 1.92 + moonbr_log(LOG_WARNING, "Unlinked named socket \"%s\" prior to listening", listener->type_specific.socket.addr.addr_un.sun_path); 1.93 + } else { 1.94 + if (errno != ENOENT) { 1.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)); 1.96 + } 1.97 + } 1.98 + if ( 1.99 + bind(listener->listenfd, &listener->type_specific.socket.addr.addr_abstract, listener->type_specific.socket.addrlen) 1.100 + ) goto moonbr_start_pool_error; 1.101 + if (listen(listener->listenfd, MOONBR_LISTEN_BACKLOG)) goto moonbr_start_pool_error; 1.102 + break; 1.103 + case MOONBR_PROTO_TCP: 1.104 + moonbr_log(LOG_INFO, "Adding TCP listener on interface \"%s\", port %i", listener->proto_specific.tcp.ip, listener->proto_specific.tcp.port); 1.105 + listener->listenfd = socket(listener->type_specific.socket.addr.addr_abstract.sa_family, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); 1.106 + if (listener->listenfd == -1) goto moonbr_start_pool_error; 1.107 { 1.108 - struct sockaddr_un servaddr = { .sun_family = AF_UNIX }; 1.109 - const int path_maxlen = sizeof(struct sockaddr_un) - ( 1.110 - (void *)servaddr.sun_path - (void *)&servaddr 1.111 - ); 1.112 - if ( 1.113 - snprintf( 1.114 - servaddr.sun_path, 1.115 - path_maxlen, 1.116 - "%s", 1.117 - listener->proto_specific.local.path 1.118 - ) >= path_maxlen 1.119 - ) { 1.120 - errno = ENAMETOOLONG; 1.121 - }; 1.122 - listener->listenfd = socket(PF_LOCAL, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); 1.123 - if (listener->listenfd == -1) goto moonbr_start_pool_error; 1.124 - if (!unlink(listener->proto_specific.local.path)) { 1.125 - moonbr_log(LOG_WARNING, "Unlinked named socket \"%s\" prior to listening", listener->proto_specific.local.path); 1.126 - } else { 1.127 - if (errno != ENOENT) { 1.128 - moonbr_log(LOG_ERR, "Could not unlink named socket \"%s\" prior to listening: %s", listener->proto_specific.local.path, strerror(errno)); 1.129 - } 1.130 - } 1.131 - if ( 1.132 - bind(listener->listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) 1.133 - ) goto moonbr_start_pool_error; 1.134 - if (listen(listener->listenfd, MOONBR_LISTEN_BACKLOG)) goto moonbr_start_pool_error; 1.135 - } 1.136 - break; 1.137 - case MOONBR_PROTO_TCP6: 1.138 - if (listener->proto_specific.tcp.localhost_only) { 1.139 - moonbr_log(LOG_INFO, "Adding localhost TCP/IPv6 listener on port %i", listener->proto_specific.tcp.port); 1.140 - } else { 1.141 - moonbr_log(LOG_INFO, "Adding public TCP/IPv6 listener on port %i", listener->proto_specific.tcp.port); 1.142 + /* avoid "Address already in use" error when restarting service */ 1.143 + static const int reuseval = 1; 1.144 + if (setsockopt( 1.145 + listener->listenfd, SOL_SOCKET, SO_REUSEADDR, &reuseval, sizeof(reuseval) 1.146 + )) goto moonbr_start_pool_error; 1.147 } 1.148 { 1.149 - struct sockaddr_in6 servaddr = { 1.150 - .sin6_family = AF_INET6, 1.151 - .sin6_port = htons(listener->proto_specific.tcp.port) 1.152 + /* default to send TCP RST when process terminates unexpectedly */ 1.153 + static const struct linger lingerval = { 1.154 + .l_onoff = 1, 1.155 + .l_linger = 0 1.156 }; 1.157 - listener->listenfd = socket(PF_INET6, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); 1.158 - if (listener->listenfd == -1) goto moonbr_start_pool_error; 1.159 - { 1.160 - /* avoid "Address already in use" error when restarting service */ 1.161 - static const int reuseval = 1; 1.162 - if (setsockopt( 1.163 - listener->listenfd, SOL_SOCKET, SO_REUSEADDR, &reuseval, sizeof(reuseval) 1.164 - )) goto moonbr_start_pool_error; 1.165 - } 1.166 - { 1.167 - /* default to send TCP RST when process terminates unexpectedly */ 1.168 - static const struct linger lingerval = { 1.169 - .l_onoff = 1, 1.170 - .l_linger = 0 1.171 - }; 1.172 - if (setsockopt( 1.173 - listener->listenfd, SOL_SOCKET, SO_LINGER, &lingerval, sizeof(lingerval) 1.174 - )) goto moonbr_start_pool_error; 1.175 - } 1.176 - if (listener->proto_specific.tcp.localhost_only) { 1.177 - servaddr.sin6_addr.s6_addr[15] = 1; 1.178 - } 1.179 - if ( 1.180 - bind(listener->listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) 1.181 - ) goto moonbr_start_pool_error; 1.182 - if (listen(listener->listenfd, MOONBR_LISTEN_BACKLOG)) goto moonbr_start_pool_error; 1.183 + if (setsockopt( 1.184 + listener->listenfd, SOL_SOCKET, SO_LINGER, &lingerval, sizeof(lingerval) 1.185 + )) goto moonbr_start_pool_error; 1.186 } 1.187 - break; 1.188 - case MOONBR_PROTO_TCP4: 1.189 - if (listener->proto_specific.tcp.localhost_only) { 1.190 - moonbr_log(LOG_INFO, "Adding localhost TCP/IPv4 listener on port %i", listener->proto_specific.tcp.port); 1.191 - } else { 1.192 - moonbr_log(LOG_INFO, "Adding public TCP/IPv4 listener on port %i", listener->proto_specific.tcp.port); 1.193 - } 1.194 - { 1.195 - struct sockaddr_in servaddr = { 1.196 - .sin_family = AF_INET, 1.197 - .sin_port = htons(listener->proto_specific.tcp.port) 1.198 - }; 1.199 - listener->listenfd = socket(PF_INET, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); 1.200 - if (listener->listenfd == -1) goto moonbr_start_pool_error; 1.201 - { 1.202 - /* avoid "Address already in use" error when restarting service */ 1.203 - static const int reuseval = 1; 1.204 - if (setsockopt( 1.205 - listener->listenfd, SOL_SOCKET, SO_REUSEADDR, &reuseval, sizeof(reuseval) 1.206 - )) goto moonbr_start_pool_error; 1.207 - } 1.208 - { 1.209 - /* default to send TCP RST when process terminates unexpectedly */ 1.210 - static const struct linger lingerval = { 1.211 - .l_onoff = 1, 1.212 - .l_linger = 0 1.213 - }; 1.214 - if (setsockopt( 1.215 - listener->listenfd, SOL_SOCKET, SO_LINGER, &lingerval, sizeof(lingerval) 1.216 - )) goto moonbr_start_pool_error; 1.217 - } 1.218 - if (listener->proto_specific.tcp.localhost_only) { 1.219 - ((uint8_t *)&servaddr.sin_addr.s_addr)[0] = 127; 1.220 - ((uint8_t *)&servaddr.sin_addr.s_addr)[3] = 1; 1.221 - } 1.222 - if ( 1.223 - bind(listener->listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) 1.224 - ) goto moonbr_start_pool_error; 1.225 - if (listen(listener->listenfd, MOONBR_LISTEN_BACKLOG)) goto moonbr_start_pool_error; 1.226 - } 1.227 + if ( 1.228 + bind(listener->listenfd, &listener->type_specific.socket.addr.addr_abstract, listener->type_specific.socket.addrlen) 1.229 + ) goto moonbr_start_pool_error; 1.230 + if (listen(listener->listenfd, MOONBR_LISTEN_BACKLOG)) goto moonbr_start_pool_error; 1.231 break; 1.232 default: 1.233 moonbr_log(LOG_CRIT, "Internal error (should not happen): Unexpected value in listener.proto field"); 1.234 @@ -847,8 +781,8 @@ 1.235 if (fd < 0) { 1.236 lua_newtable(L); 1.237 lua_pushstring(L, 1.238 - listener->proto_specific.interval.name ? 1.239 - listener->proto_specific.interval.name : "" 1.240 + listener->type_specific.interval.name ? 1.241 + listener->type_specific.interval.name : "" 1.242 ); 1.243 lua_setfield(L, -2, "interval"); 1.244 } else { 1.245 @@ -1462,32 +1396,23 @@ 1.246 static void moonbr_connect(struct moonbr_pool *pool) { 1.247 struct moonbr_listener *listener = moonbr_pop_connected_listener(pool); 1.248 struct moonbr_worker *worker; 1.249 - switch (listener->proto) { 1.250 - case MOONBR_PROTO_INTERVAL: 1.251 + if (listener->proto == MOONBR_PROTO_INTERVAL) { 1.252 worker = moonbr_pop_idle_worker(pool); 1.253 if (moonbr_stat) { 1.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); 1.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); 1.256 } 1.257 worker->restart_interval_listener = listener; 1.258 moonbr_send_control_message(worker, MOONBR_COMMAND_CONNECT, -1, listener); 1.259 /* do not push listener to queue of idle listeners yet */ 1.260 - break; 1.261 - case MOONBR_PROTO_LOCAL: 1.262 + } else { 1.263 + int peerfd; 1.264 do { 1.265 - int peerfd; 1.266 - struct sockaddr_un peeraddr; 1.267 - socklen_t peeraddr_len = sizeof(struct sockaddr_un); 1.268 - peerfd = accept4( 1.269 - listener->listenfd, 1.270 - (struct sockaddr *)&peeraddr, 1.271 - &peeraddr_len, 1.272 - SOCK_CLOEXEC 1.273 - ); 1.274 + peerfd = accept4(listener->listenfd, NULL, NULL, SOCK_CLOEXEC); 1.275 if (peerfd == -1) { 1.276 if (errno == EWOULDBLOCK) { 1.277 break; 1.278 } else if (errno == ECONNABORTED) { 1.279 - moonbr_log(LOG_WARNING, "Connection aborted before accepting it (proto=\"local\", path=\"%s\")", listener->proto_specific.local.path); 1.280 + moonbr_log(LOG_WARNING, "Connection aborted before accepting it"); 1.281 break; 1.282 } else if (errno != EINTR) { 1.283 moonbr_log(LOG_ERR, "Could not accept socket connection: %s", strerror(errno)); 1.284 @@ -1496,7 +1421,7 @@ 1.285 } else { 1.286 worker = moonbr_pop_idle_worker(pool); 1.287 if (moonbr_stat) { 1.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); 1.289 + moonbr_log(LOG_INFO, "Dispatching connection for pool #%i to PID %i", listener->pool->poolnum, (int)worker->pid); 1.290 } 1.291 moonbr_send_control_message(worker, MOONBR_COMMAND_CONNECT, peerfd, listener); 1.292 if (close(peerfd) && errno != EINTR) { 1.293 @@ -1506,80 +1431,6 @@ 1.294 } 1.295 } while (pool->first_idle_worker); 1.296 moonbr_add_idle_listener(listener); 1.297 - break; 1.298 - case MOONBR_PROTO_TCP6: 1.299 - do { 1.300 - int peerfd; 1.301 - struct sockaddr_in6 peeraddr; 1.302 - socklen_t peeraddr_len = sizeof(struct sockaddr_in6); 1.303 - peerfd = accept4( 1.304 - listener->listenfd, 1.305 - (struct sockaddr *)&peeraddr, 1.306 - &peeraddr_len, 1.307 - SOCK_CLOEXEC 1.308 - ); 1.309 - if (peerfd == -1) { 1.310 - if (errno == EWOULDBLOCK) { 1.311 - break; 1.312 - } else if (errno == ECONNABORTED) { 1.313 - moonbr_log(LOG_WARNING, "Connection aborted before accepting it (proto=\"tcp6\", port=%i)", listener->proto_specific.tcp.port); 1.314 - break; 1.315 - } else if (errno != EINTR) { 1.316 - moonbr_log(LOG_ERR, "Could not accept socket connection: %s", strerror(errno)); 1.317 - moonbr_terminate_error(); 1.318 - } 1.319 - } else { 1.320 - worker = moonbr_pop_idle_worker(pool); 1.321 - if (moonbr_stat) { 1.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); 1.323 - } 1.324 - moonbr_send_control_message(worker, MOONBR_COMMAND_CONNECT, peerfd, listener); 1.325 - if (close(peerfd) && errno != EINTR) { 1.326 - moonbr_log(LOG_ERR, "Could not close incoming socket connection in parent process: %s", strerror(errno)); 1.327 - moonbr_terminate_error(); 1.328 - } 1.329 - } 1.330 - } while (pool->first_idle_worker); 1.331 - moonbr_add_idle_listener(listener); 1.332 - break; 1.333 - case MOONBR_PROTO_TCP4: 1.334 - do { 1.335 - int peerfd; 1.336 - struct sockaddr_in peeraddr; 1.337 - socklen_t peeraddr_len = sizeof(struct sockaddr_in); 1.338 - peerfd = accept4( 1.339 - listener->listenfd, 1.340 - (struct sockaddr *)&peeraddr, 1.341 - &peeraddr_len, 1.342 - SOCK_CLOEXEC 1.343 - ); 1.344 - if (peerfd == -1) { 1.345 - if (errno == EWOULDBLOCK) { 1.346 - break; 1.347 - } else if (errno == ECONNABORTED) { 1.348 - moonbr_log(LOG_WARNING, "Connection aborted before accepting it (proto=\"tcp4\", port=%i)", listener->proto_specific.tcp.port); 1.349 - break; 1.350 - } else if (errno != EINTR) { 1.351 - moonbr_log(LOG_ERR, "Could not accept socket connection: %s", strerror(errno)); 1.352 - moonbr_terminate_error(); 1.353 - } 1.354 - } else { 1.355 - worker = moonbr_pop_idle_worker(pool); 1.356 - if (moonbr_stat) { 1.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); 1.358 - } 1.359 - moonbr_send_control_message(worker, MOONBR_COMMAND_CONNECT, peerfd, listener); 1.360 - if (close(peerfd) && errno != EINTR) { 1.361 - moonbr_log(LOG_ERR, "Could not close incoming socket connection in parent process: %s", strerror(errno)); 1.362 - moonbr_terminate_error(); 1.363 - } 1.364 - } 1.365 - } while (pool->first_idle_worker); 1.366 - moonbr_add_idle_listener(listener); 1.367 - break; 1.368 - default: 1.369 - moonbr_log(LOG_ERR, "Internal error (should not happen): Unexpected value in listener.proto field"); 1.370 - moonbr_terminate_error(); 1.371 } 1.372 } 1.373 1.374 @@ -1598,8 +1449,8 @@ 1.375 if (listener->proto == MOONBR_PROTO_INTERVAL) { 1.376 timeradd( 1.377 &now, 1.378 - &listener->proto_specific.interval.delay, 1.379 - &listener->proto_specific.interval.wakeup 1.380 + &listener->type_specific.interval.delay, 1.381 + &listener->type_specific.interval.wakeup 1.382 ); 1.383 } 1.384 } 1.385 @@ -1615,20 +1466,20 @@ 1.386 if (listener) { 1.387 moonbr_add_idle_listener(listener); 1.388 worker->restart_interval_listener = NULL; 1.389 - if (listener->proto_specific.interval.strict) { 1.390 + if (listener->type_specific.interval.strict) { 1.391 timeradd( 1.392 - &listener->proto_specific.interval.wakeup, 1.393 - &listener->proto_specific.interval.delay, 1.394 - &listener->proto_specific.interval.wakeup 1.395 + &listener->type_specific.interval.wakeup, 1.396 + &listener->type_specific.interval.delay, 1.397 + &listener->type_specific.interval.wakeup 1.398 ); 1.399 - if (timercmp(&listener->proto_specific.interval.wakeup, now, <)) { 1.400 - listener->proto_specific.interval.wakeup = *now; 1.401 + if (timercmp(&listener->type_specific.interval.wakeup, now, <)) { 1.402 + listener->type_specific.interval.wakeup = *now; 1.403 } 1.404 } else { 1.405 timeradd( 1.406 now, 1.407 - &listener->proto_specific.interval.delay, 1.408 - &listener->proto_specific.interval.wakeup 1.409 + &listener->type_specific.interval.delay, 1.410 + &listener->type_specific.interval.wakeup 1.411 ); 1.412 } 1.413 } 1.414 @@ -1687,7 +1538,7 @@ 1.415 moonbr_add_connected_listener(listener); 1.416 } 1.417 } else if (listener->proto == MOONBR_PROTO_INTERVAL) { 1.418 - if (!timercmp(&listener->proto_specific.interval.wakeup, &now, >)) { 1.419 + if (!timercmp(&listener->type_specific.interval.wakeup, &now, >)) { 1.420 moonbr_remove_idle_listener(listener); 1.421 moonbr_add_connected_listener(listener); 1.422 } 1.423 @@ -1799,7 +1650,7 @@ 1.424 /* calculate wakeup time for interval listeners */ 1.425 for (listener=pool->first_idle_listener; listener; listener=listener->next_listener) { 1.426 if (listener->proto == MOONBR_PROTO_INTERVAL) { 1.427 - moonbr_calc_wait(&wait, &listener->proto_specific.interval.wakeup); 1.428 + moonbr_calc_wait(&wait, &listener->type_specific.interval.wakeup); 1.429 } 1.430 } 1.431 /* calculate wakeup time for idle workers (only first idle worker is significant) */ 1.432 @@ -2063,7 +1914,7 @@ 1.433 { 1.434 const char *name = lua_tostring(L, -1); 1.435 if (name) { 1.436 - if (asprintf(&listener->proto_specific.interval.name, "%s", name) < 0) { 1.437 + if (asprintf(&listener->type_specific.interval.name, "%s", name) < 0) { 1.438 moonbr_log(LOG_CRIT, "Memory allocation_error"); 1.439 moonbr_terminate_error(); 1.440 } 1.441 @@ -2071,68 +1922,116 @@ 1.442 } 1.443 lua_getfield(L, 3, "delay"); 1.444 if ( 1.445 - !moonbr_lua_totimeval(L, -1, &listener->proto_specific.interval.delay) || 1.446 - !timerisset(&listener->proto_specific.interval.delay) 1.447 + !moonbr_lua_totimeval(L, -1, &listener->type_specific.interval.delay) || 1.448 + !timerisset(&listener->type_specific.interval.delay) 1.449 ) { 1.450 luaL_error(L, "No valid interval delay specified; use listen{{proto=\"interval\", delay=...}, ...}"); 1.451 } 1.452 lua_getfield(L, 3, "strict"); 1.453 if (!lua_isnil(L, -1)) { 1.454 if (lua_isboolean(L, -1)) { 1.455 - if (lua_toboolean(L, -1)) listener->proto_specific.interval.strict = 1; 1.456 + if (lua_toboolean(L, -1)) listener->type_specific.interval.strict = 1; 1.457 } else { 1.458 luaL_error(L, "Option \"strict\" must be a boolean if set; use listen{{proto=\"interval\", strict=true, ...}, ...}"); 1.459 } 1.460 } 1.461 } else if (proto && !strcmp(proto, "local")) { 1.462 + const char *path; 1.463 + const int path_maxlen = ( 1.464 + sizeof(listener->type_specific.socket.addr.addr_un) - 1.465 + ((void *)listener->type_specific.socket.addr.addr_un.sun_path - (void *)&listener->type_specific.socket.addr.addr_un) 1.466 + ) - 1; /* one byte for termination */ 1.467 listener->proto = MOONBR_PROTO_LOCAL; 1.468 lua_getfield(L, 3, "path"); 1.469 - { 1.470 - const char *path = lua_tostring(L, -1); 1.471 - if (!path) { 1.472 - luaL_error(L, "No valid path specified for local socket; use listen{{proto=\"local\", path=...}, ...}"); 1.473 - } 1.474 - if (asprintf(&listener->proto_specific.local.path, "%s", path) < 0) { 1.475 - moonbr_log(LOG_CRIT, "Memory allocation_error"); 1.476 - moonbr_terminate_error(); 1.477 + path = lua_tostring(L, -1); 1.478 + if (!path) { 1.479 + luaL_error(L, "No valid path specified for local socket; use listen{{proto=\"local\", path=...}, ...}"); 1.480 + } 1.481 + if (strlen(path) > path_maxlen) { 1.482 + luaL_error(L, "Path name for local socket exceeded maximum length of %i characters", path_maxlen); 1.483 + } 1.484 + strcpy(listener->type_specific.socket.addr.addr_un.sun_path, path); 1.485 + } else if (proto && !strcmp(proto, "tcp")) { 1.486 + const char *host, *port; 1.487 + struct addrinfo hints = { 0, }; 1.488 + struct addrinfo *res, *addrinfo; 1.489 + int errcode; 1.490 + const char *ip; 1.491 + lua_getfield(L, 3, "host"); 1.492 + host = lua_isnil(L, -1) ? "::" : lua_tostring(L, -1); 1.493 + if (!host) { 1.494 + luaL_error(L, "No host specified; use listen{{proto=\"tcp\", host=...}, ...}"); 1.495 + } 1.496 + lua_getfield(L, 3, "port"); 1.497 + port = lua_tostring(L, -1); 1.498 + if (!port) { 1.499 + luaL_error(L, "No port specified; use listen{{proto=\"tcp\", host=...}, ...}"); 1.500 + } 1.501 + hints.ai_family = AF_UNSPEC; 1.502 + hints.ai_socktype = SOCK_STREAM; 1.503 + hints.ai_protocol = IPPROTO_TCP; 1.504 + hints.ai_flags = AI_ADDRCONFIG | AI_PASSIVE; 1.505 + errcode = getaddrinfo(host, port, &hints, &res); 1.506 + if (errcode) { 1.507 + freeaddrinfo(res); 1.508 + if (errcode == EAI_SYSTEM) { 1.509 + char errmsg[MOONBR_MAXSTRERRORLEN]; 1.510 + strerror_r(errno, errmsg, MOONBR_MAXSTRERRORLEN); /* use thread-safe call in case child created threads */ 1.511 + luaL_error(L, "Could not resolve host: %s: %s", gai_strerror(errcode), errmsg); 1.512 + } else { 1.513 + luaL_error(L, "Could not resolve host: %s", gai_strerror(errcode)); 1.514 } 1.515 } 1.516 - } else if (proto && !strcmp(proto, "tcp6")) { 1.517 - listener->proto = MOONBR_PROTO_TCP6; 1.518 - lua_getfield(L, 3, "port"); 1.519 - listener->proto_specific.tcp.port = lua_tointeger(L, -1); 1.520 - if ( 1.521 - listener->proto_specific.tcp.port < 1 || 1.522 - listener->proto_specific.tcp.port > 65535 1.523 - ) { 1.524 - luaL_error(L, "No valid port number specified; use listen{{proto=\"tcp6\", port=...}, ...}"); 1.525 + for (addrinfo=res; addrinfo; addrinfo=addrinfo->ai_next) { 1.526 + if (addrinfo->ai_family == AF_INET6) goto moonbr_listen_init_pool_found; 1.527 + } 1.528 + for (addrinfo=res; addrinfo; addrinfo=addrinfo->ai_next) { 1.529 + if (addrinfo->ai_family == AF_INET) goto moonbr_listen_init_pool_found; 1.530 } 1.531 - lua_getfield(L, 3, "localhost"); 1.532 - if (!lua_isnil(L, -1)) { 1.533 - if (lua_isboolean(L, -1)) { 1.534 - if (lua_toboolean(L, -1)) listener->proto_specific.tcp.localhost_only = 1; 1.535 - } else { 1.536 - luaL_error(L, "Option \"localhost\" must be a boolean if set; use listen{{proto=\"tcp6\", localhost=true, ...}, ...}"); 1.537 - } 1.538 + addrinfo = res; 1.539 + moonbr_listen_init_pool_found: 1.540 + if (addrinfo->ai_addrlen > sizeof(listener->type_specific.socket.addr)) { 1.541 + moonbr_log(LOG_CRIT, "Size of ai_addrlen is unexpectedly big (should not happen)"); 1.542 + moonbr_terminate_error(); 1.543 } 1.544 - } else if (proto && !strcmp(proto, "tcp4")) { 1.545 - listener->proto = MOONBR_PROTO_TCP4; 1.546 - lua_getfield(L, 3, "port"); 1.547 - listener->proto_specific.tcp.port = lua_tointeger(L, -1); 1.548 - if ( 1.549 - listener->proto_specific.tcp.port < 1 || 1.550 - listener->proto_specific.tcp.port > 65535 1.551 - ) { 1.552 - luaL_error(L, "No valid port number specified; use listen{{proto=\"tcp4\", port=...}, ...}"); 1.553 + memcpy(&listener->type_specific.socket.addr, addrinfo->ai_addr, addrinfo->ai_addrlen); 1.554 + listener->type_specific.socket.addrlen = addrinfo->ai_addrlen; 1.555 + switch (addrinfo->ai_family) { 1.556 + case AF_INET6: 1.557 + ip = inet_ntop( 1.558 + addrinfo->ai_family, 1.559 + &((struct sockaddr_in6 *)addrinfo->ai_addr)->sin6_addr, 1.560 + listener->proto_specific.tcp.ip, 1.561 + INET6_ADDRSTRLEN 1.562 + ); 1.563 + if (!ip) { 1.564 + moonbr_log(LOG_CRIT, "System error in inet_ntop call: %s", strerror(errno)); 1.565 + moonbr_terminate_error(); 1.566 + } 1.567 + listener->proto_specific.tcp.port = ntohs(((struct sockaddr_in6 *)addrinfo->ai_addr)->sin6_port); 1.568 + break; 1.569 + case AF_INET: 1.570 + ip = inet_ntop( 1.571 + addrinfo->ai_family, 1.572 + &((struct sockaddr_in *)addrinfo->ai_addr)->sin_addr, 1.573 + listener->proto_specific.tcp.ip, 1.574 + INET6_ADDRSTRLEN 1.575 + ); 1.576 + if (!ip) { 1.577 + moonbr_log(LOG_CRIT, "System error in inet_ntop call: %s", strerror(errno)); 1.578 + moonbr_terminate_error(); 1.579 + } 1.580 + listener->proto_specific.tcp.port = ntohs(((struct sockaddr_in *)addrinfo->ai_addr)->sin_port); 1.581 + break; 1.582 + default: 1.583 + strcpy(listener->proto_specific.tcp.ip, "unknown"); 1.584 + listener->proto_specific.tcp.port = 0; 1.585 } 1.586 - lua_getfield(L, 3, "localhost"); 1.587 - if (!lua_isnil(L, -1)) { 1.588 - if (lua_isboolean(L, -1)) { 1.589 - if (lua_toboolean(L, -1)) listener->proto_specific.tcp.localhost_only = 1; 1.590 - } else { 1.591 - luaL_error(L, "Option \"localhost\" must be a boolean if set; use listen{{proto=\"tcp4\", localhost=true, ...}, ...}"); 1.592 - } 1.593 - } 1.594 + listener->proto = MOONBR_PROTO_TCP; 1.595 + } else if (proto) { 1.596 + luaL_error(L, "Unknown protocol \"%s\"", proto); 1.597 + } else { 1.598 + luaL_error(L, "No valid protocol specified; use listen{{proto=..., ...}, ...}"); 1.599 } 1.600 } 1.601 lua_settop(L, 2); 1.602 @@ -2200,38 +2099,19 @@ 1.603 int i; 1.604 i = moonbr_start_pool(pool); 1.605 if (i >= 0) { 1.606 - struct moonbr_listener *listener = &pool->listener[i]; 1.607 - switch (listener->proto) { 1.608 - case MOONBR_PROTO_INTERVAL: 1.609 - lua_pushfstring(L, "Could not initialize listener #%d (proto=\"interval\"): %s", i+1, strerror(errno)); 1.610 - break; 1.611 - case MOONBR_PROTO_LOCAL: 1.612 - lua_pushfstring(L, "Could not initialize listener #%d (proto=\"local\", path=\"%s\"): %s", i+1, listener->proto_specific.local.path, strerror(errno)); 1.613 - break; 1.614 - case MOONBR_PROTO_TCP6: 1.615 - lua_pushfstring(L, "Could not initialize listener #%d (proto=\"tcp6\", port=%d): %s", i+1, listener->proto_specific.tcp.port, strerror(errno)); 1.616 - break; 1.617 - case MOONBR_PROTO_TCP4: 1.618 - lua_pushfstring(L, "Could not initialize listener #%d (proto=\"tcp4\", port=%d): %s", i+1, listener->proto_specific.tcp.port, strerror(errno)); 1.619 - break; 1.620 - default: 1.621 - moonbr_log(LOG_ERR, "Internal error (should not happen): Unexpected value in listener.proto field"); 1.622 - moonbr_terminate_error(); 1.623 - } 1.624 - goto moonbr_listen_error; 1.625 + lua_pushfstring(L, "Could not initialize listener #%d: %s", i+1, strerror(errno)); 1.626 + moonbr_listen_error: 1.627 + moonbr_destroy_pool(pool); 1.628 + lua_pushnil(L); 1.629 + lua_rawsetp(L, LUA_REGISTRYINDEX, moonbr_luakey_prepare_func(pool)); 1.630 + lua_pushnil(L); 1.631 + lua_rawsetp(L, LUA_REGISTRYINDEX, moonbr_luakey_connect_func(pool)); 1.632 + lua_pushnil(L); 1.633 + lua_rawsetp(L, LUA_REGISTRYINDEX, moonbr_luakey_finish_func(pool)); 1.634 + lua_error(L); 1.635 } 1.636 } 1.637 return 0; 1.638 - moonbr_listen_error: 1.639 - moonbr_destroy_pool(pool); 1.640 - lua_pushnil(L); 1.641 - lua_rawsetp(L, LUA_REGISTRYINDEX, moonbr_luakey_prepare_func(pool)); 1.642 - lua_pushnil(L); 1.643 - lua_rawsetp(L, LUA_REGISTRYINDEX, moonbr_luakey_connect_func(pool)); 1.644 - lua_pushnil(L); 1.645 - lua_rawsetp(L, LUA_REGISTRYINDEX, moonbr_luakey_finish_func(pool)); 1.646 - lua_error(L); 1.647 - return 0; /* avoid compiler warning */ 1.648 } 1.649 1.650