Browse Source

[core] systemd socket activation support

personal/stbuehler/fix-fdevent
Glenn Strauss 3 years ago
parent
commit
ce7b47c015
  1. 3
      src/base.h
  2. 2
      src/configfile.c
  3. 97
      src/network.c
  4. 7
      src/server.c

3
src/base.h

@ -347,6 +347,7 @@ typedef struct {
buffer *syslog_facility;
unsigned short compat_module_load;
unsigned short systemd_socket_activation;
} server_config;
typedef struct server_socket {
@ -459,6 +460,8 @@ struct server {
uid_t uid;
gid_t gid;
pid_t pid;
server_socket_array srv_sockets_inherited;
};

2
src/configfile.c

@ -277,6 +277,7 @@ static int config_insert(server *srv) {
{ "server.syslog-facility", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 80 */
{ "server.socket-perms", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 81 */
{ "server.http-parseopts", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_SERVER }, /* 82 */
{ "server.systemd-socket-activation", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 83 */
{ NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
};
@ -321,6 +322,7 @@ static int config_insert(server *srv) {
cv[80].destination = srv->srvconf.syslog_facility;
http_parseopts = array_init();
cv[82].destination = http_parseopts;
cv[83].destination = &(srv->srvconf.systemd_socket_activation);
srv->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));

97
src/network.c

@ -219,6 +219,17 @@ static int network_server_init(server *srv, buffer *host_token, size_t sidx, int
return 0;
}
if (srv->srvconf.systemd_socket_activation) {
for (size_t i = 0; i < srv->srv_sockets_inherited.used; ++i) {
if (0 != memcmp(&srv->srv_sockets_inherited.ptr[i]->addr, &srv_socket->addr, addr_len)) continue;
if ((unsigned short)~0u == srv->srv_sockets_inherited.ptr[i]->sidx) {
srv->srv_sockets_inherited.ptr[i]->sidx = sidx;
}
stdin_fd = srv->srv_sockets_inherited.ptr[i]->fd;
break;
}
}
if (-1 != stdin_fd) {
srv_socket->fd = stdin_fd;
if (-1 == fdevent_fcntl_set_nb_cloexec(srv->ev, stdin_fd)) {
@ -367,12 +378,65 @@ int network_close(server *srv) {
srv->srv_sockets.used = 0;
srv->srv_sockets.size = 0;
for (i = 0; i < srv->srv_sockets_inherited.used; i++) {
server_socket *srv_socket = srv->srv_sockets_inherited.ptr[i];
if (srv_socket->fd != -1 && srv_socket->sidx != (unsigned short)~0u) {
close(srv_socket->fd);
}
buffer_free(srv_socket->srv_token);
free(srv_socket);
}
free(srv->srv_sockets_inherited.ptr);
srv->srv_sockets_inherited.ptr = NULL;
srv->srv_sockets_inherited.used = 0;
srv->srv_sockets_inherited.size = 0;
return 0;
}
int network_init(server *srv, int stdin_fd) {
size_t i;
static int network_socket_activation_nfds(server *srv, int nfds) {
buffer *host = buffer_init();
socklen_t addr_len;
sock_addr addr;
int rc = 0;
nfds += 3; /* #define SD_LISTEN_FDS_START 3 */
for (int fd = 3; fd < nfds; ++fd) {
addr_len = sizeof(sock_addr);
if (-1 == (rc = getsockname(fd, (struct sockaddr *)&addr, &addr_len))) {
log_error_write(srv, __FILE__, __LINE__, "ss",
"socket activation getsockname()", strerror(errno));
break;
}
network_host_normalize_addr_str(host, &addr);
rc = network_server_init(srv, host, 0, fd);
if (0 != rc) break;
srv->srv_sockets.ptr[srv->srv_sockets.used-1]->sidx = (unsigned short)~0u;
}
buffer_free(host);
memcpy(&srv->srv_sockets_inherited, &srv->srv_sockets, sizeof(server_socket_array));
memset(&srv->srv_sockets, 0, sizeof(server_socket_array));
return rc;
}
static int network_socket_activation_from_env(server *srv) {
char *listen_pid = getenv("LISTEN_PID");
char *listen_fds = getenv("LISTEN_FDS");
pid_t lpid = listen_pid ? (pid_t)strtoul(listen_pid,NULL,10) : 0;
int nfds = listen_fds ? atoi(listen_fds) : 0;
int rc = (lpid == getpid() && nfds > 0)
? network_socket_activation_nfds(srv, nfds)
: 0;
unsetenv("LISTEN_PID");
unsetenv("LISTEN_FDS");
unsetenv("LISTEN_FDNAMES");
/*(upon graceful restart, unsetenv will result in no-op above)*/
return rc;
}
int network_init(server *srv, int stdin_fd) {
#ifdef __WIN32
WSADATA wsaData;
WORD wVersionRequested = MAKEWORD(2, 2);
@ -384,7 +448,19 @@ int network_init(server *srv, int stdin_fd) {
if (0 != network_write_init(srv)) return -1;
{
if (srv->srvconf.systemd_socket_activation) {
for (size_t i = 0; i < srv->srv_sockets_inherited.used; ++i) {
srv->srv_sockets_inherited.ptr[i]->sidx = (unsigned short)~0u;
}
if (0 != network_socket_activation_from_env(srv)) return -1;
if (0 == srv->srv_sockets_inherited.used) {
srv->srvconf.systemd_socket_activation = 0;
}
}
/* process srv->srvconf.bindhost
* (skip if systemd socket activation is enabled and bindhost is empty; do not additionally listen on "*") */
if (!srv->srvconf.systemd_socket_activation || !buffer_string_is_empty(srv->srvconf.bindhost)) {
int rc;
buffer *b = buffer_init();
buffer_copy_buffer(b, srv->srvconf.bindhost);
@ -401,7 +477,7 @@ int network_init(server *srv, int stdin_fd) {
}
/* check for $SERVER["socket"] */
for (i = 1; i < srv->config_context->used; i++) {
for (size_t i = 1; i < srv->config_context->used; ++i) {
data_config *dc = (data_config *)srv->config_context->data[i];
/* not our stage */
@ -422,6 +498,19 @@ int network_init(server *srv, int stdin_fd) {
if (0 != network_server_init(srv, dc->string, i, -1)) return -1;
}
if (srv->srvconf.systemd_socket_activation) {
/* activate any inherited sockets not explicitly listed in config file */
server_socket *srv_socket;
for (size_t i = 0; i < srv->srv_sockets_inherited.used; ++i) {
if ((unsigned short)~0u != srv->srv_sockets_inherited.ptr[i]->sidx) continue;
srv->srv_sockets_inherited.ptr[i]->sidx = 0;
srv_socket = calloc(1, sizeof(server_socket));
force_assert(NULL != srv_socket);
memcpy(srv_socket, srv->srv_sockets_inherited.ptr[i], sizeof(server_socket));
network_srv_sockets_append(srv, srv_socket);
}
}
return 0;
}

7
src/server.c

@ -87,6 +87,7 @@
static int oneshot_fd = 0;
static volatile int pid_fd = -2;
static server_socket_array graceful_sockets;
static server_socket_array inherited_sockets;
static volatile sig_atomic_t graceful_restart = 0;
static volatile sig_atomic_t graceful_shutdown = 0;
static volatile sig_atomic_t srv_shutdown = 0;
@ -301,6 +302,7 @@ static server *server_init(void) {
srv->srvconf.loadavg[1] = 0.0;
srv->srvconf.loadavg[2] = 0.0;
srv->srvconf.compat_module_load = 1;
srv->srvconf.systemd_socket_activation = 0;
/* use syslog */
srv->errorlog_fd = STDERR_FILENO;
@ -856,11 +858,15 @@ static int log_error_close(server *srv) {
static void server_sockets_save (server *srv) { /* graceful_restart */
memcpy(&graceful_sockets, &srv->srv_sockets, sizeof(server_socket_array));
memset(&srv->srv_sockets, 0, sizeof(server_socket_array));
memcpy(&inherited_sockets, &srv->srv_sockets_inherited, sizeof(server_socket_array));
memset(&srv->srv_sockets_inherited, 0, sizeof(server_socket_array));
}
static void server_sockets_restore (server *srv) { /* graceful_restart */
memcpy(&srv->srv_sockets, &graceful_sockets, sizeof(server_socket_array));
memset(&graceful_sockets, 0, sizeof(server_socket_array));
memcpy(&srv->srv_sockets_inherited, &inherited_sockets, sizeof(server_socket_array));
memset(&inherited_sockets, 0, sizeof(server_socket_array));
}
static int server_sockets_set_nb_cloexec (server *srv) {
@ -1003,6 +1009,7 @@ static int server_main (server * const srv, int argc, char **argv) {
/*graceful_restart = 0;*//*(reset below to avoid further daemonizing)*/
/*(intentionally preserved)*/
/*memset(graceful_sockets, 0, sizeof(graceful_sockets));*/
/*memset(inherited_sockets, 0, sizeof(inherited_sockets));*/
/*pid_fd = -1;*/
srv->srvconf.port = 0;

Loading…
Cancel
Save