diff --git a/README-test-server b/README-test-server index 1091c539c..dd4a93210 100644 --- a/README-test-server +++ b/README-test-server @@ -177,6 +177,29 @@ Incrementing numbers should appear in the browser display. By default the test server logs to both stderr and syslog. + +Running test server as a Daemon +------------------------------- + +You can use the -D option on the test server to have it fork into the +background and return immediately. In this daemonized mode all stderr is +disabled and logging goes only to syslog, eg, /var/log/messages or similar. + +The server maintains a lockfile at /tmp/.lwsts-lock that contains the pid +of the master process, and deletes this file when the master process +terminates. + +To stop the daemon, do + + kill `cat /tmp/.lwsts-lock` + +If it finds a stale lock (the pid mentioned in the file does not exist +any more) it will delete the lock and create a new one during startup. + +If the lock is valid, the daemon will exit with a note on stderr that +it was already running.s + + Using SSL on the server side ---------------------------- diff --git a/lib/daemonize.c b/lib/daemonize.c index 4add03dd5..9738fbd20 100644 --- a/lib/daemonize.c +++ b/lib/daemonize.c @@ -21,7 +21,7 @@ #include #include -static int pid_daemon; +int pid_daemon; static char lock_path[PATH_MAX]; static void @@ -64,6 +64,14 @@ child_handler(int signum) } } +static void lws_daemon_closing(int sigact) +{ + if (getpid() == pid_daemon) + unlink(lock_path); + + kill(getpid(), SIGKILL); +} + /* * You just need to call this from your main(), when it * returns you are all set "in the background" decoupled @@ -76,11 +84,31 @@ int lws_daemonize(const char *_lock_path) { pid_t sid, parent; + int fd; + char buf[10]; + int n, ret; + struct sigaction act; /* already a daemon */ if (getppid() == 1) return (1); + fd = open(_lock_path, O_RDONLY); + if (fd > 0) { + n = read(fd, buf, sizeof buf); + close(fd); + if (n) { + n = atoi(buf); + ret = kill(n, 0); + if (ret >= 0) { + fprintf(stderr, "Daemon already running from pid %d, aborting\n", n); + exit(1); + } + fprintf(stderr, "Removing stale lock file %s from dead pid %d\n", _lock_path, n); + unlink(lock_path); + } + } + strncpy(lock_path, _lock_path, sizeof lock_path); lock_path[sizeof(lock_path) - 1] = '\0'; @@ -114,6 +142,7 @@ lws_daemonize(const char *_lock_path) /* At this point we are executing as the child process */ parent = getppid(); + pid_daemon = getpid(); /* Cancel certain signals */ signal(SIGCHLD, SIG_DFL); /* A child process dies */ @@ -161,6 +190,13 @@ lws_daemonize(const char *_lock_path) /* Tell the parent process that we are A-okay */ kill(parent, SIGUSR1); + act.sa_handler = lws_daemon_closing; + sigemptyset(&act.sa_mask); + act.sa_flags = 0; + act.sa_restorer = NULL; + + sigaction(SIGTERM, &act, NULL); + /* return to continue what is now "the daemon" */ return (0); diff --git a/lib/libwebsockets.c b/lib/libwebsockets.c index 1b62f9270..6ae44c4c6 100644 --- a/lib/libwebsockets.c +++ b/lib/libwebsockets.c @@ -703,6 +703,10 @@ libwebsocket_service_fd(struct libwebsocket_context *context, if (context->last_timeout_check_s != tv.tv_sec) { context->last_timeout_check_s = tv.tv_sec; + /* if our parent went down, don't linger around */ + if (context->started_with_parent && kill(context->started_with_parent, 0) < 0) + kill(getpid(), SIGTERM); + /* global timeout check once per second */ for (n = 0; n < context->fds_count; n++) { @@ -1443,12 +1447,17 @@ libwebsocket_create_context(int port, const char *interf, } #endif - context = (struct libwebsocket_context *) malloc(sizeof(struct libwebsocket_context)); if (!context) { lwsl_err("No memory for websocket context\n"); return NULL; } +#ifndef NO_DAEMONIZE + extern int pid_daemon; + context->started_with_parent = pid_daemon; + lwsl_notice(" Started with daemon pid %d\n", pid_daemon); +#endif + context->protocols = protocols; context->listen_port = port; context->http_proxy_port = 0; @@ -1975,10 +1984,14 @@ libwebsockets_fork_service_loop(struct libwebsocket_context *context) * solaris, could remember ppid right after fork and wait for it to change. */ - if (getppid() == 1) - break; + /* if our parent went down, don't linger around */ + if (context->started_with_parent && kill(context->started_with_parent, 0) < 0) + kill(getpid(), SIGTERM); + + if (getppid() == 1) + break; //#endif - } + } return 1; diff --git a/lib/private-libwebsockets.h b/lib/private-libwebsockets.h index ce3094947..8f69cff19 100644 --- a/lib/private-libwebsockets.h +++ b/lib/private-libwebsockets.h @@ -257,6 +257,8 @@ struct libwebsocket_context { unsigned int options; unsigned long last_timeout_check_s; + int started_with_parent; + int fd_random; int listen_service_modulo; int listen_service_count; diff --git a/test-server/test-server.c b/test-server/test-server.c index 7ac0a9b11..dc5a9cd3f 100644 --- a/test-server/test-server.c +++ b/test-server/test-server.c @@ -43,7 +43,6 @@ int count_pollfds; #endif /* EXTERNAL_POLL */ -//#define LWS_NO_FORK /* * This demo server shows how to use libwebsockets for one or more @@ -562,6 +561,7 @@ int main(int argc, char **argv) } } +#ifndef NO_DAEMONIZE /* * normally lock path would be /var/lock/lwsts or similar, to * simplify getting started without having to take care about @@ -571,7 +571,7 @@ int main(int argc, char **argv) fprintf(stderr, "Failed to daemonize\n"); return 1; } - +#endif /* we will only try to log things according to our debug_level */ setlogmask(LOG_UPTO (LOG_DEBUG)); openlog("lwsts", syslog_options, LOG_DAEMON); @@ -685,6 +685,8 @@ int main(int argc, char **argv) lwsl_err("Unable to fork service loop %d\n", n); return 1; } + if (n) + exit(0); while (1) {