From 89f4574e0b1553c8e5dcbfc275e829a759b697f6 Mon Sep 17 00:00:00 2001 From: Guus Sliepen Date: Mon, 26 Mar 2012 14:46:09 +0100 Subject: [PATCH] Add support for systemd style socket activation. If the LISTEN_FDS environment variable is set and tinc is run in the foreground, tinc will use filedescriptors 3 to 3 + LISTEN_FDS for its listening TCP sockets. For now, tinc will create matching listening UDP sockets itself. There is no dependency on systemd or on libsystemd-daemon. --- src/net_setup.c | 133 +++++++++++++++++++++++++++++++----------------- src/tincd.c | 6 +++ 2 files changed, 93 insertions(+), 46 deletions(-) diff --git a/src/net_setup.c b/src/net_setup.c index 4b90737f..d3940e72 100644 --- a/src/net_setup.c +++ b/src/net_setup.c @@ -581,71 +581,112 @@ static bool setup_myself(void) { /* Open sockets */ - listen_sockets = 0; - cfg = lookup_config(config_tree, "BindToAddress"); + if(!do_detach && getenv("LISTEN_FDS")) { + sockaddr_t sa; + socklen_t salen; - do { - get_config_string(cfg, &address); - if(cfg) - cfg = lookup_config_next(config_tree, cfg); + listen_sockets = atoi(getenv("LISTEN_FDS")); +#ifdef HAVE_UNSETENV + unsetenv("LISTEN_FDS"); +#endif - char *port = myport; + if(listen_sockets > MAXSOCKETS) { + logger(LOG_ERR, "Too many listening sockets"); + return false; + } - if(address) { - char *space = strchr(address, ' '); - if(space) { - *space++ = 0; - port = space; + for(i = 0; i < listen_sockets; i++) { + salen = sizeof sa; + if(getsockname(i + 3, &sa.sa, &salen) < 0) { + logger(LOG_ERR, "Could not get address of listen fd %d: %s", i + 3, sockstrerror(errno)); + return false; } - if(!strcmp(address, "*")) - *address = 0; - } + listen_socket[i].tcp = i + 3; + +#ifdef FD_CLOEXEC + fcntl(i + 3, F_SETFD, FD_CLOEXEC); +#endif - hint.ai_family = addressfamily; - hint.ai_socktype = SOCK_STREAM; - hint.ai_protocol = IPPROTO_TCP; - hint.ai_flags = AI_PASSIVE; + listen_socket[i].udp = setup_vpn_in_socket(&sa); + if(listen_socket[i].udp < 0) + return false; - err = getaddrinfo(address && *address ? address : NULL, port, &hint, &ai); - free(address); + ifdebug(CONNECTIONS) { + hostname = sockaddr2hostname(&sa); + logger(LOG_NOTICE, "Listening on %s", hostname); + free(hostname); + } - if(err || !ai) { - logger(LOG_ERR, "System call `%s' failed: %s", "getaddrinfo", - gai_strerror(err)); - return false; + memcpy(&listen_socket[i].sa, &sa, salen); } + } else { + listen_sockets = 0; + cfg = lookup_config(config_tree, "BindToAddress"); + + do { + get_config_string(cfg, &address); + if(cfg) + cfg = lookup_config_next(config_tree, cfg); + + char *port = myport; + + if(address) { + char *space = strchr(address, ' '); + if(space) { + *space++ = 0; + port = space; + } + + if(!strcmp(address, "*")) + *address = 0; + } + + hint.ai_family = addressfamily; + hint.ai_socktype = SOCK_STREAM; + hint.ai_protocol = IPPROTO_TCP; + hint.ai_flags = AI_PASSIVE; - for(aip = ai; aip; aip = aip->ai_next) { - if(listen_sockets >= MAXSOCKETS) { - logger(LOG_ERR, "Too many listening sockets"); + err = getaddrinfo(address && *address ? address : NULL, port, &hint, &ai); + free(address); + + if(err || !ai) { + logger(LOG_ERR, "System call `%s' failed: %s", "getaddrinfo", + gai_strerror(err)); return false; } - listen_socket[listen_sockets].tcp = - setup_listen_socket((sockaddr_t *) aip->ai_addr); + for(aip = ai; aip; aip = aip->ai_next) { + if(listen_sockets >= MAXSOCKETS) { + logger(LOG_ERR, "Too many listening sockets"); + return false; + } - if(listen_socket[listen_sockets].tcp < 0) - continue; + listen_socket[listen_sockets].tcp = + setup_listen_socket((sockaddr_t *) aip->ai_addr); - listen_socket[listen_sockets].udp = - setup_vpn_in_socket((sockaddr_t *) aip->ai_addr); + if(listen_socket[listen_sockets].tcp < 0) + continue; - if(listen_socket[listen_sockets].udp < 0) - continue; + listen_socket[listen_sockets].udp = + setup_vpn_in_socket((sockaddr_t *) aip->ai_addr); - ifdebug(CONNECTIONS) { - hostname = sockaddr2hostname((sockaddr_t *) aip->ai_addr); - logger(LOG_NOTICE, "Listening on %s", hostname); - free(hostname); - } + if(listen_socket[listen_sockets].udp < 0) + continue; - memcpy(&listen_socket[listen_sockets].sa, aip->ai_addr, aip->ai_addrlen); - listen_sockets++; - } + ifdebug(CONNECTIONS) { + hostname = sockaddr2hostname((sockaddr_t *) aip->ai_addr); + logger(LOG_NOTICE, "Listening on %s", hostname); + free(hostname); + } - freeaddrinfo(ai); - } while(cfg); + memcpy(&listen_socket[listen_sockets].sa, aip->ai_addr, aip->ai_addrlen); + listen_sockets++; + } + + freeaddrinfo(ai); + } while(cfg); + } if(listen_sockets) logger(LOG_NOTICE, "Ready"); diff --git a/src/tincd.c b/src/tincd.c index 443301e0..148e13e4 100644 --- a/src/tincd.c +++ b/src/tincd.c @@ -539,6 +539,12 @@ int main(int argc, char **argv) { g_argv = argv; + if(getenv("LISTEN_PID") && atoi(getenv("LISTEN_PID")) == getpid()) + do_detach = false; +#ifdef HAVE_UNSETENV + unsetenv("LISTEN_PID"); +#endif + init_configuration(&config_tree); /* Slllluuuuuuurrrrp! */ -- 2.20.1