summaryrefslogtreecommitdiff
path: root/src/network.c
diff options
context:
space:
mode:
authorGlenn Strauss <gstrauss@gluelogic.com>2020-09-25 10:59:28 -0400
committerGlenn Strauss <gstrauss@gluelogic.com>2020-10-11 12:19:27 -0400
commit352d5d776d4ce090c06fc43bf17f98b127f98a7f (patch)
tree45378d8c3349f3b450ac2265f25d422ada1fd700 /src/network.c
parentf779d354a2581dcaca19b76cbebfb5f917fef0a3 (diff)
downloadlighttpd-git-352d5d776d4ce090c06fc43bf17f98b127f98a7f.tar.gz
[core] graceful and immediate restart option
graceful and (nearly) immediate lighttpd restart option For *some* configurations, it *may* be safe to background the current lighttpd server (or workers) to continue processing active requests and, in parallel, to start up a new lighttpd server with a new configuration. For other configurations, doing so might not be safe! Therefore, this option must be explicitly configured to enable: server.feature-flags += ("server.graceful-restart-bg" => "enable") server.systemd-socket-activation = "enable" Along with enabling server.feature-flags "server.graceful-restart-bg", enabling server.systemd-socket-activation allows transfer of open listening sockets to the new lighttpd server instance, and occurs without closing the listening sockets and without destroying the kernel listen backlog queue on the socket. Safe configurations may include lighttpd.conf which connect to standalone backend daemons, e.g. proxying to other servers, including PHP-FPM backends. Unsafe configurations include lighttpd.conf which use "bin-path" option in *.server configs, instructing lighttpd to execute the backends. Using the graceful-and-immediate-restart option is likely *unsafe* if the backend daemon expects only one instance of itself to run at a time. Current implementation of graceful and immediate restart option keeps the backgrounded lighttpd in the same process group, so that subsequent SIGINT or SIGTERM will shut down both the new and the backgrounded servers. (An alternative option (commented out in the code) is to background and detach from the new lighttpd process.) Regardless, existing subprocesses, such as CGI, remain in original process group. As a result, the new lighttpd server may receive SIGCHLD for unknown processes inherited from the old server, which the new lighttpd server will reap and discard. The original lighttpd server, now a child, will be unable to detect exit or reap and report status on those pre-existing subprocesses. Graceful restart is triggered in lighttpd by sending lighttpd SIGUSR1. If lighttpd is configured with workers, then SIGINT (not SIGUSR1) is sent to the process group, including other processes started by lighttpd, e.g. CGI. To work well with graceful restart, CGI scripts and other processes should trap SIGINT (and SIGUSR1 for good measure). Long-running scripts may want to checkpoint and close, e.g. a CGI script implementing a long-running websocket connection.
Diffstat (limited to 'src/network.c')
-rw-r--r--src/network.c41
1 files changed, 41 insertions, 0 deletions
diff --git a/src/network.c b/src/network.c
index a1e41489..4b39aa7c 100644
--- a/src/network.c
+++ b/src/network.c
@@ -452,6 +452,47 @@ int network_close(server *srv) {
return 0;
}
+void network_socket_activation_to_env (server * const srv) {
+ /* set up listening sockets for systemd socket activation
+ * and ensure FD_CLOEXEC flag is not set on listen fds */
+ int fd = 3; /* #define SD_LISTEN_FDS_START 3 */
+ for (uint32_t n = 0, i; n < srv->srv_sockets.used; ++n) {
+ server_socket *srv_socket = srv->srv_sockets.ptr[n];
+ if (srv_socket->fd < fd) continue;
+ if (srv_socket->fd == fd) {
+ fdevent_clrfd_cloexec(fd);
+ ++fd;
+ continue;
+ }
+ /* (expecting ordered list, but check if fd is later in list)*/
+ for (i = n+1; i < srv->srv_sockets.used; ++i) {
+ if (fd == srv->srv_sockets.ptr[i]->fd)
+ break;
+ }
+ if (i < srv->srv_sockets.used) {
+ fdevent_clrfd_cloexec(fd);
+ ++fd;
+ --n; /* loop to reprocess this entry */
+ continue;
+ }
+
+ /* dup2() removes FD_CLOEXEC on newfd */
+ if (fd != dup2(srv_socket->fd, fd)) continue;
+ ++fd;
+ /* old fd will be closed upon execv() due to its FD_CLOEXEC flag
+ * (if not already closed by another dup2() over it) */
+ }
+ fd -= 3; /* now num fds; #define SD_LISTEN_FDS_START 3 */
+ if (0 == fd) return; /*(no active sockets?)*/
+ buffer * const tb = srv->tmp_buf;
+ buffer_clear(tb);
+ buffer_append_int(tb, fd);
+ setenv("LISTEN_FDS", tb->ptr, 1);
+ buffer_clear(tb);
+ buffer_append_int(tb, srv->pid); /* getpid() */
+ setenv("LISTEN_PID", tb->ptr, 1);
+}
+
static int network_socket_activation_nfds(server *srv, network_socket_config *s, int nfds) {
buffer *host = buffer_init();
socklen_t addr_len;