moonbridge
view moonbridge.c @ 300:fba670e4beec
Code formatting
| author | jbe | 
|---|---|
| date | Sun Jun 18 01:33:40 2017 +0200 (2017-06-18) | 
| parents | c78bb327ef6a | 
| children | b2282fb8553b | 
 line source
     2 /*** Version ***/
     3 #define MOONBR_VERSION_STRING "1.0.1"
     6 /*** Compile-time configuration ***/
     8 #define MOONBR_LUA_PANIC_BUG_WORKAROUND 1
    11 /*** C preprocessor macros for portability support ***/
    13 #ifndef __has_include
    14 #define __has_include(x) 0
    15 #endif
    18 /*** Include directives for used system libraries ***/
    20 #include <stdlib.h>
    21 #include <stdint.h>
    22 #include <string.h>
    23 #include <errno.h>
    24 #include <unistd.h>
    25 #include <signal.h>
    26 #include <sys/wait.h>
    27 #include <sys/resource.h>
    28 #include <poll.h>
    29 #include <time.h>
    30 #include <sys/time.h>
    31 #include <sys/socket.h>
    32 #include <sys/un.h>
    33 #include <netinet/in.h>
    34 #include <netdb.h>
    35 #include <arpa/inet.h>
    36 #include <getopt.h>
    37 #include <sys/file.h>
    38 #include <syslog.h>
    39 #if defined(__FreeBSD__) || __has_include(<libutil.h>)
    40 #include <libutil.h>
    41 #endif
    42 #if defined(__linux__) || __has_include(<bsd/libutil.h>)
    43 #include <bsd/libutil.h>
    44 #endif
    45 #if defined(__linux__) || __has_include(<bsd/unistd.h>)
    46 #include <bsd/unistd.h>
    47 #endif
    50 /*** Fallback definitions for missing constants on some platforms ***/
    52 /* INFTIM is used as timeout parameter for poll() */
    53 #ifndef INFTIM
    54 #define INFTIM -1
    55 #endif
    58 /*** Include directives for Lua ***/
    60 #include <lua.h>
    61 #include <lauxlib.h>
    62 #include <lualib.h>
    65 /*** Include directive for moonbridge_io library ***/
    67 #include "moonbridge_io.h"
    70 /*** Constants ***/
    72 /* Backlog option for listen() call */
    73 #define MOONBR_LISTEN_BACKLOG 1024
    75 /* Maximum length of a timestamp used for strftime() */
    76 #define MOONBR_LOG_MAXTIMELEN 40
    78 /* Maximum length of a log message */
    79 #define MOONBR_LOG_MAXMSGLEN 4095
    81 /* Exitcodes passed to exit() call */
    82 #define MOONBR_EXITCODE_GRACEFUL 0
    83 #define MOONBR_EXITCODE_CMDLINEERROR 1
    84 #define MOONBR_EXITCODE_ALREADYRUNNING 2
    85 #define MOONBR_EXITCODE_STARTUPERROR 3
    86 #define MOONBR_EXITCODE_RUNTIMEERROR 4
    88 /* Maximum length of a line sent to stderr by child processes */
    89 #define MOONBR_MAXERRORLINELEN 1024
    91 /* Maximum length of an error string returned by strerror() */
    92 #define MOONBR_MAXSTRERRORLEN 80
    94 /* Error message for noncompliant strerror_r() implementation on GNU systems */
    95 #define MOONBR_STRERROR_R_MSG "Error detail unavailable due to noncompliant strerror_r() implementation"
    97 /* Status bytes exchanged between master and child processes */
    98 #define MOONBR_STATUS_IDLE 'I'
    99 #define MOONBR_COMMAND_CONNECT 'C'
   100 #define MOONBR_COMMAND_TERMINATE 'T'
   101 #define MOONBR_STATUS_GOODBYE 'B'
   103 /* Constant file descriptors */
   104 #define MOONBR_FD_STDERR 2
   105 #define MOONBR_FD_CONTROL 3
   106 #define MOONBR_FD_END 4
   108 /* Return values of moonbr_try_destroy_worker() */
   109 #define MOONBR_DESTROY_NONE 0
   110 #define MOONBR_DESTROY_PREPARE 1
   111 #define MOONBR_DESTROY_IDLE_OR_ASSIGNED 2
   114 /*** Types ***/
   116 /* Enum for 'moonbr_pstate' */
   117 #define MOONBR_PSTATE_STARTUP 0
   118 #define MOONBR_PSTATE_RUNNING 1
   119 #define MOONBR_PSTATE_FORKED  2
   121 /* Enum for 'proto' field of struct moonbr_listener */
   122 #define MOONBR_PROTO_INTERVAL 1
   123 #define MOONBR_PROTO_LOCAL 2
   124 #define MOONBR_PROTO_TCP 3
   126 /* Data structure for a pool's listener that can accept incoming connections */
   127 struct moonbr_listener {
   128   struct moonbr_pool *pool;
   129   struct moonbr_listener *prev_listener;  /* previous idle or(!) connected listener */
   130   struct moonbr_listener *next_listener;  /* next idle or(!) connected listener */
   131   int proto;
   132   union {
   133     struct {
   134       char *name;  /* name of interval passed to 'connect' function as 'interval' field in table */
   135       int main;    /* nonzero = termination of 'connect' function causes shutdown */
   136       int strict;  /* nonzero = runtime of 'connect' function does not delay interval */
   137       struct timeval delay;   /* interval between invocations of 'connect' function */
   138       struct timeval wakeup;  /* point in time of next invocation */
   139     } interval;
   140     struct {
   141       union {
   142         struct sockaddr addr_abstract;
   143         struct sockaddr_un addr_un;
   144         struct sockaddr_in addr_in;
   145         struct sockaddr_in6 addr_in6;
   146       } addr;
   147       socklen_t addrlen;
   148     } socket;
   149   } type_specific;
   150   union {
   151     struct {
   152       char ip[INET6_ADDRSTRLEN];  /* IP to listen on */
   153       int port;  /* port number to listen on (in host endianess) */
   154     } tcp;
   155   } proto_specific;
   156   int listenfd;  /* -1 = none */
   157   int pollidx;   /* -1 = none */
   158 };
   160 /* Data structure for a child process that is handling incoming connections */
   161 struct moonbr_worker {
   162   struct moonbr_pool *pool;
   163   struct moonbr_worker *prev_worker;
   164   struct moonbr_worker *next_worker;
   165   struct moonbr_worker *prev_idle_worker;
   166   struct moonbr_worker *next_idle_worker;
   167   int main;       /* nonzero = terminate Moonbridge when this worker dies */
   168   int idle;       /* nonzero = waiting for command from parent process */
   169   int assigned;   /* nonzero = currently handling a connection */
   170   pid_t pid;
   171   int controlfd;  /* socket to send/receive control message to/from child process */
   172   int errorfd;    /* socket to receive error output from child process' stderr */
   173   char *errorlinebuf;  /* optional buffer for collecting stderr data from child process */
   174   int errorlinelen;    /* number of bytes stored in 'errorlinebuf' */
   175   int errorlineovf;    /* nonzero = line length overflow */
   176   struct timeval idle_expiration;  /* point in time until child process may stay in idle state */
   177   struct moonbr_listener *restart_interval_listener;  /* set while interval listener is assigned */
   178 };
   180 /* Data structure for a pool of workers and listeners */
   181 struct moonbr_pool {
   182   int poolnum;  /* number of pool for log output */
   183   struct moonbr_pool *next_pool;  /* next entry in linked list starting with 'moonbr_first_pool' */
   184   struct moonbr_worker *first_worker;       /* first worker of pool */
   185   struct moonbr_worker *last_worker;        /* last worker of pool */
   186   struct moonbr_worker *first_idle_worker;  /* first idle worker of pool */
   187   struct moonbr_worker *last_idle_worker;   /* last idle worker of pool */
   188   int idle_worker_count;
   189   int unassigned_worker_count;
   190   int total_worker_count;
   191   int worker_count_stat;  /* only needed for statistics */
   192   int pre_fork;  /* desired minimum number of unassigned workers */
   193   int min_fork;  /* desired minimum number of workers in total */
   194   int max_fork;  /* maximum number of workers */
   195   struct timeval fork_delay;   /* delay after each fork() until a fork may happen again */
   196   struct timeval fork_wakeup;  /* point in time when a fork may happen again (unless a worker terminates before) */
   197   struct timeval fork_error_delay;   /* delay between fork()s when an error during fork or preparation occurred */
   198   struct timeval fork_error_wakeup;  /* point in time when fork may happen again if an error in preparation occurred */
   199   int use_fork_error_wakeup;         /* nonzero = error in preparation occured; gets reset on next fork */
   200   struct timeval exit_delay;    /* delay for terminating excessive workers (unassigned_worker_count > pre_fork) */
   201   struct timeval exit_wakeup;   /* point in time when terminating an excessive worker */
   202   struct timeval idle_timeout;  /* delay before an idle worker is terminated */
   203   size_t memory_limit;  /* maximum bytes of memory that the Lua machine may allocate */
   204   int listener_count;  /* total number of listeners of pool (and size of 'listener' array at end of this struct) */
   205   struct moonbr_listener *first_idle_listener;       /* first listener that is idle (i.e. has no waiting connection) */
   206   struct moonbr_listener *last_idle_listener;        /* last  listener that is idle (i.e. has no waiting connection) */
   207   struct moonbr_listener *first_connected_listener;  /* first listener that has a pending connection */
   208   struct moonbr_listener *last_connected_listener;   /* last  listener that has a pending connection */
   209   struct moonbr_listener listener[1];  /* static array of variable(!) size to contain 'listener' structures */
   210 };
   212 /* Enum for 'channel' field of struct moonbr_poll_worker */
   213 #define MOONBR_POLL_WORKER_CONTROLCHANNEL 1
   214 #define MOONBR_POLL_WORKER_ERRORCHANNEL 2
   216 /* Structure to refer from 'moonbr_poll_worker_fds' entry to worker structure */
   217 struct moonbr_poll_worker {
   218   struct moonbr_worker *worker;
   219   int channel;  /* field indicating whether file descriptor is 'controlfd' or 'errorfd' */
   220 };
   222 /* Variable indicating that clean shutdown was requested */
   223 static int moonbr_shutdown_in_progress = 0;
   226 /*** Macros for Lua registry ***/
   228 /* Lightuserdata keys for Lua registry to store 'prepare', 'connect', and 'finish' functions */
   229 #define moonbr_luakey_prepare_func(pool) ((void *)(intptr_t)(pool) + 0)
   230 #define moonbr_luakey_connect_func(pool) ((void *)(intptr_t)(pool) + 1)
   231 #define moonbr_luakey_finish_func(pool)  ((void *)(intptr_t)(pool) + 2)
   234 /*** Global variables ***/
   236 /* State of process execution */
   237 static int moonbr_pstate = MOONBR_PSTATE_STARTUP;
   239 /* Process ID of the main process */
   240 static pid_t moonbr_masterpid;
   242 /* Condition variables set by the signal handler */
   243 static volatile sig_atomic_t moonbr_cond_poll = 0;
   244 static volatile sig_atomic_t moonbr_cond_terminate = 0;
   245 static volatile sig_atomic_t moonbr_cond_interrupt = 0;
   246 static volatile sig_atomic_t moonbr_cond_child = 0;
   248 /* Socket pair to denote signal delivery when signal handler was called just before poll() */
   249 static int moonbr_poll_signalfds[2];
   250 #define moonbr_poll_signalfd_read moonbr_poll_signalfds[0]
   251 #define moonbr_poll_signalfd_write moonbr_poll_signalfds[1]
   253 /* Global variables for pidfile and logging */
   254 static struct pidfh *moonbr_pidfh = NULL;
   255 static FILE *moonbr_logfile = NULL;
   256 static int moonbr_use_syslog = 0;
   258 /* First and last entry of linked list of all created pools during initialization */
   259 static struct moonbr_pool *moonbr_first_pool = NULL;
   260 static struct moonbr_pool *moonbr_last_pool = NULL;
   262 /* Total count of pools */
   263 static int moonbr_pool_count = 0;
   265 /* Set to a nonzero value if dynamic part of 'moonbr_poll_fds' ('moonbr_poll_worker_fds') needs an update */
   266 static int moonbr_poll_refresh_needed = 0;
   268 /* Array passed to poll(), consisting of static part and dynamic part ('moonbr_poll_worker_fds') */
   269 static struct pollfd *moonbr_poll_fds = NULL;  /* the array */
   270 static int moonbr_poll_fds_bufsize = 0;        /* memory allocated for this number of elements */
   271 static int moonbr_poll_fds_count = 0;          /* total number of elements */
   272 static int moonbr_poll_fds_static_count;       /* number of elements in static part */
   274 /* Dynamic part of 'moonbr_poll_fds' array */
   275 #define moonbr_poll_worker_fds (moonbr_poll_fds+moonbr_poll_fds_static_count)
   277 /* Additional information for dynamic part of 'moonbr_poll_fds' array */
   278 struct moonbr_poll_worker *moonbr_poll_workers;  /* the array */
   279 static int moonbr_poll_workers_bufsize = 0;     /* memory allocated for this number of elements */
   280 static int moonbr_poll_worker_count = 0;        /* number of elements in array */
   282 /* Variable set to nonzero value to disallow further calls of 'listen' function */
   283 static int moonbr_booted = 0;
   285 /* Verbosity settings */
   286 static int moonbr_debug = 0;
   287 static int moonbr_stat = 0;
   289 /* Memory consumption by Lua machine */
   290 static size_t moonbr_memory_usage = 0;
   291 static size_t moonbr_memory_limit = 0;
   294 /*** Functions for signal handling ***/
   296 /* Signal handler for master and child processes */
   297 static void moonbr_signal(int sig) {
   298   int errno2 = errno;  /* backup errno variable */
   299   if (getpid() == moonbr_masterpid) {
   300     /* master process */
   301     switch (sig) {
   302     case SIGHUP:
   303     case SIGINT:
   304       /* fast shutdown requested */
   305       moonbr_cond_interrupt = 1;
   306       break;
   307     case SIGTERM:
   308       /* clean shutdown requested */
   309       moonbr_cond_terminate = 1;
   310       break;
   311     case SIGCHLD:
   312       /* child process terminated */
   313       moonbr_cond_child = 1;
   314       break;
   315     }
   316     if (moonbr_cond_poll) {
   317       /* avoid race condition if signal handler is invoked right before poll() */
   318       char buf[1] = {0};
   319       write(moonbr_poll_signalfd_write, buf, 1);
   320     }
   321   } else {
   322     /* child process forwards certain signals to parent process */
   323     switch (sig) {
   324     case SIGHUP:
   325     case SIGINT:
   326       kill(moonbr_masterpid, sig);
   327     }
   328   }
   329   errno = errno2;  /* restore errno from backup */
   330 }
   332 /* Initialize signal handling */
   333 static void moonbr_signal_init(){
   334   moonbr_masterpid = getpid();
   335   signal(SIGHUP, moonbr_signal);
   336   signal(SIGINT, moonbr_signal);
   337   signal(SIGTERM, moonbr_signal);
   338   signal(SIGCHLD, moonbr_signal);
   339 }
   342 /*** Functions for logging in master process ***/
   344 /* Logs a pre-formatted message with given syslog() priority */
   345 static void moonbr_log_msg(int priority, const char *msg) {
   346   if (moonbr_logfile) {
   347     /* logging to logfile desired (timestamp is prepended in that case) */
   348     time_t now_time = 0;
   349     struct tm now_tmstruct;
   350     char timestr[MOONBR_LOG_MAXTIMELEN+1];
   351     time(&now_time);
   352     localtime_r(&now_time, &now_tmstruct);
   353     if (!strftime(
   354       timestr, MOONBR_LOG_MAXTIMELEN+1, "%Y-%m-%d %H:%M:%S %Z: ", &now_tmstruct
   355     )) timestr[0] = 0;
   356     fprintf(moonbr_logfile, "%s%s\n", timestr, msg);
   357   }
   358   if (moonbr_use_syslog) {
   359     /* logging through syslog desired */
   360     syslog(priority, "%s", msg);
   361   }
   362 }
   364 /* Formats a message via vsnprintf() and logs it with given syslog() priority */
   365 static void moonbr_log(int priority, const char *message, ...) {
   366   char msgbuf[MOONBR_LOG_MAXMSGLEN+1];  /* buffer of static size to store formatted message */
   367   int msglen;  /* length of full message (may exceed MOONBR_LOG_MAXMSGLEN) */
   368   {
   369     /* pass variable arguments to vsnprintf() to format message */
   370     va_list ap;
   371     va_start(ap, message);
   372     msglen = vsnprintf(msgbuf, MOONBR_LOG_MAXMSGLEN+1, message, ap);
   373     va_end(ap);
   374   }
   375   {
   376     /* split and log message line by line */
   377     char *line = msgbuf;
   378     while (1) {
   379       char *endptr = strchr(line, '\n');
   380       if (endptr) {
   381         /* terminate string where newline character is found */
   382         *endptr = 0;
   383       } else if (line != msgbuf && msglen > MOONBR_LOG_MAXMSGLEN) {
   384         /* break if line is incomplete and not the first line */
   385         break;
   386       }
   387       moonbr_log_msg(priority, line);
   388       if (!endptr) break;  /* break if end of formatted message is reached */
   389       line = endptr+1;     /* otherwise continue with remaining message */
   390     }
   391   }
   392   if (msglen > MOONBR_LOG_MAXMSGLEN) {
   393     /* print warning if message was truncated */
   394     moonbr_log_msg(priority, "Previous log message has been truncated due to excessive length");
   395   }
   396 }
   399 /*** Termination function ***/
   401 /* Kill all child processes, remove PID file (if existent), and exit master process with given exitcode */
   402 static void moonbr_terminate(int exitcode) {
   403   {
   404     struct moonbr_pool *pool;
   405     for (pool=moonbr_first_pool; pool; pool=pool->next_pool) {
   406       {
   407         struct moonbr_worker *worker;
   408         for (worker=pool->first_worker; worker; worker=worker->next_worker) {
   409           moonbr_log(LOG_INFO, "Sending SIGKILL to child with PID %i", (int)worker->pid);
   410           if (kill(worker->pid, SIGKILL)) {
   411             moonbr_log(LOG_ERR, "Error while killing child process: %s", strerror(errno));
   412           }
   413         }
   414       }
   415       {
   416         int i;
   417         for (i=0; i<pool->listener_count; i++) {
   418           struct moonbr_listener *listener = &pool->listener[i];
   419           if (listener->proto == MOONBR_PROTO_LOCAL) {
   420             moonbr_log(LOG_INFO, "Unlinking local socket \"%s\"", listener->type_specific.socket.addr.addr_un.sun_path);
   421             if (unlink(listener->type_specific.socket.addr.addr_un.sun_path)) {
   422               moonbr_log(LOG_ERR, "Error while unlinking local socket: %s", strerror(errno));
   423             }
   424           }
   425         }
   426       }
   427     }
   428   }
   429   moonbr_log(exitcode ? LOG_ERR : LOG_NOTICE, "Terminating with exit code %i", exitcode);
   430   if (moonbr_pidfh && pidfile_remove(moonbr_pidfh)) {
   431     moonbr_log(LOG_ERR, "Error while removing PID file: %s", strerror(errno));
   432   }
   433   exit(exitcode);
   434 }
   436 /* Terminate with either MOONBR_EXITCODE_STARTUPERROR or MOONBR_EXITCODE_RUNTIMEERROR */
   437 #define moonbr_terminate_error() \
   438   moonbr_terminate( \
   439     moonbr_pstate == MOONBR_PSTATE_STARTUP ? \
   440     MOONBR_EXITCODE_STARTUPERROR : \
   441     MOONBR_EXITCODE_RUNTIMEERROR \
   442   )
   445 /*** Helper functions ***/
   447 /* Fills a 'struct timeval' structure with the current time (using CLOCK_MONOTONIC) */
   448 static void moonbr_now(struct timeval *now) {
   449   struct timespec ts = {0, };
   450   if (clock_gettime(CLOCK_MONOTONIC, &ts)) {
   451     moonbr_log(LOG_CRIT, "Error in clock_gettime() call: %s", strerror(errno));
   452     moonbr_terminate_error();
   453   }
   454   *now = (struct timeval){ .tv_sec = ts.tv_sec, .tv_usec = ts.tv_nsec / 1000 };
   455 }
   457 /* Formats a 'struct timeval' value (not thread-safe) */
   458 static char *moonbr_format_timeval(struct timeval *t) {
   459   static char buf[32];
   460   snprintf(buf, 32, "%ji.%06ji seconds", (intmax_t)t->tv_sec, (intmax_t)t->tv_usec);
   461   return buf;
   462 }
   465 /*** Functions for pool creation and startup ***/
   467 /* Creates a 'struct moonbr_pool' structure with a given number of listeners */
   468 static struct moonbr_pool *moonbr_create_pool(int listener_count) {
   469   struct moonbr_pool *pool;
   470   pool = calloc(1,
   471     sizeof(struct moonbr_pool) +  /* size of 'struct moonbr_pool' with one listener */
   472     (listener_count-1) * sizeof(struct moonbr_listener)  /* size of extra listeners */
   473   );
   474   if (!pool) {
   475     moonbr_log(LOG_CRIT, "Memory allocation error");
   476     moonbr_terminate_error();
   477   }
   478   pool->listener_count = listener_count;
   479   {
   480     /* initialization of listeners */
   481     int i;
   482     for (i=0; i<listener_count; i++) {
   483       struct moonbr_listener *listener = &pool->listener[i];
   484       listener->pool = pool;
   485       listener->listenfd = -1;
   486       listener->pollidx = -1;
   487     }
   488   }
   489   return pool;
   490 }
   492 /* Destroys a 'struct moonbr_pool' structure before it has been started */
   493 static void moonbr_destroy_pool(struct moonbr_pool *pool) {
   494   int i;
   495   for (i=0; i<pool->listener_count; i++) {
   496     struct moonbr_listener *listener = &pool->listener[i];
   497     if (
   498       listener->proto == MOONBR_PROTO_INTERVAL &&
   499       listener->type_specific.interval.name
   500     ) {
   501       free(listener->type_specific.interval.name);
   502     }
   503   }
   504   free(pool);
   505 }
   507 /* Starts a all listeners in a pool */
   508 static int moonbr_start_pool(struct moonbr_pool *pool) {
   509   moonbr_log(LOG_INFO, "Creating pool", pool->poolnum);
   510   {
   511     int i;
   512     for (i=0; i<pool->listener_count; i++) {
   513       struct moonbr_listener *listener = &pool->listener[i];
   514       switch (listener->proto) {
   515       case MOONBR_PROTO_INTERVAL:
   516         if (listener->type_specific.interval.main) {
   517           /* nothing to do here: starting main thread is performed in moonbr_run() function */
   518           if (!listener->type_specific.interval.name) {
   519             moonbr_log(LOG_INFO, "Adding unnamed main thread");
   520           } else {
   521             moonbr_log(LOG_INFO, "Adding main thread \"%s\"", listener->type_specific.interval.name);
   522           }
   523         } else {
   524           /* nothing to do here: starting intervals is performed in moonbr_run() function */
   525           if (!listener->type_specific.interval.name) {
   526             moonbr_log(LOG_INFO, "Adding unnamed interval listener");
   527           } else {
   528             moonbr_log(LOG_INFO, "Adding interval listener \"%s\"", listener->type_specific.interval.name);
   529           }
   530         }
   531         break;
   532       case MOONBR_PROTO_LOCAL:
   533         moonbr_log(LOG_INFO, "Adding local socket listener for path \"%s\"", listener->type_specific.socket.addr.addr_un.sun_path);
   534         listener->listenfd = socket(PF_LOCAL, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
   535         if (listener->listenfd == -1) goto moonbr_start_pool_error;
   536         if (!unlink(listener->type_specific.socket.addr.addr_un.sun_path)) {
   537           moonbr_log(LOG_WARNING, "Unlinked named socket \"%s\" prior to listening", listener->type_specific.socket.addr.addr_un.sun_path);
   538         } else {
   539           if (errno != ENOENT) {
   540             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));
   541           }
   542         }
   543         if (
   544           bind(listener->listenfd, &listener->type_specific.socket.addr.addr_abstract, listener->type_specific.socket.addrlen)
   545         ) goto moonbr_start_pool_error;
   546         if (listen(listener->listenfd, MOONBR_LISTEN_BACKLOG)) goto moonbr_start_pool_error;
   547         break;
   548       case MOONBR_PROTO_TCP:
   549         moonbr_log(LOG_INFO, "Adding TCP listener on interface \"%s\", port %i", listener->proto_specific.tcp.ip, listener->proto_specific.tcp.port);
   550         listener->listenfd = socket(listener->type_specific.socket.addr.addr_abstract.sa_family, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);  /* NOTE: not correctly using PF_* but AF_* constants here */
   551         if (listener->listenfd == -1) goto moonbr_start_pool_error;
   552         {
   553           /* avoid "Address already in use" error when restarting service */
   554           static const int reuseval = 1;
   555           if (setsockopt(
   556             listener->listenfd, SOL_SOCKET, SO_REUSEADDR, &reuseval, sizeof(reuseval)
   557           )) goto moonbr_start_pool_error;
   558         }
   559         {
   560           /* default to send TCP RST when process terminates unexpectedly */
   561           static const struct linger lingerval = {
   562             .l_onoff = 1,
   563             .l_linger = 0
   564           };
   565           if (setsockopt(
   566             listener->listenfd, SOL_SOCKET, SO_LINGER, &lingerval, sizeof(lingerval)
   567           )) goto moonbr_start_pool_error;
   568         }
   569         if (
   570           bind(listener->listenfd, &listener->type_specific.socket.addr.addr_abstract, listener->type_specific.socket.addrlen)
   571         ) goto moonbr_start_pool_error;
   572         if (listen(listener->listenfd, MOONBR_LISTEN_BACKLOG)) goto moonbr_start_pool_error;
   573         break;
   574       default:
   575         moonbr_log(LOG_CRIT, "Internal error (should not happen): Unexpected value in listener.proto field");
   576         moonbr_terminate_error();
   577       }
   578     }
   579     goto moonbr_start_pool_ok;
   580     moonbr_start_pool_error:
   581     {
   582       int j = i;
   583       int errno2 = errno;
   584       for (; i>=0; i--) {
   585         struct moonbr_listener *listener = &pool->listener[i];
   586         if (listener->listenfd != -1) close(listener->listenfd);
   587       }
   588       errno = errno2;
   589       return j;
   590     }
   591   }
   592   moonbr_start_pool_ok:
   593   pool->poolnum = ++moonbr_pool_count;
   594   moonbr_log(LOG_INFO, "Pool #%i created", pool->poolnum);
   595   if (moonbr_last_pool) moonbr_last_pool->next_pool = pool;
   596   else moonbr_first_pool = pool;
   597   moonbr_last_pool = pool;
   598   return -1;
   599 }
   602 /*** Function to send data and a file descriptor to child process */
   604 /* Sends control message of one bye plus optional file descriptor plus optional pointer to child process */
   605 static void moonbr_send_control_message(struct moonbr_worker *worker, char status, int fd, void *ptr) {
   606   {
   607     struct iovec iovector = { .iov_base = &status, .iov_len = 1 };      /* carrying status byte */
   608     char control_message_buffer[CMSG_SPACE(sizeof(int))] = {0, };       /* used to transfer file descriptor */
   609     struct msghdr message = { .msg_iov = &iovector, .msg_iovlen = 1 };  /* data structure passed to sendmsg() call */
   610     if (moonbr_debug) {
   611       if (fd == -1) {
   612         moonbr_log(LOG_DEBUG, "Sending control message \"%c\" to child process in pool #%i (PID %i)", (int)status, worker->pool->poolnum, (int)worker->pid);
   613       } else {
   614         moonbr_log(LOG_DEBUG, "Sending control message \"%c\" with file descriptor #%i to child process in pool #%i (PID %i)", (int)status, fd, worker->pool->poolnum, (int)worker->pid);
   615       }
   616     }
   617     if (fd != -1) {
   618       /* attach control message with file descriptor */
   619       message.msg_control = control_message_buffer;
   620       message.msg_controllen = CMSG_SPACE(sizeof(int));
   621       {
   622         struct cmsghdr *control_message = CMSG_FIRSTHDR(&message);
   623         control_message->cmsg_level = SOL_SOCKET;
   624         control_message->cmsg_type = SCM_RIGHTS;
   625         control_message->cmsg_len = CMSG_LEN(sizeof(int));
   626         memcpy(CMSG_DATA(control_message), &fd, sizeof(int));
   627       }
   628     }
   629     while (sendmsg(worker->controlfd, &message, MSG_NOSIGNAL) < 0) {
   630       if (errno == EPIPE) {
   631         moonbr_log(LOG_ERR, "Error while communicating with idle child process in pool #%i (PID %i): %s", worker->pool->poolnum, (int)worker->pid, strerror(errno));
   632         return;  /* do not close socket; socket is closed when reading from it */
   633       }
   634       if (errno != EINTR) {
   635         moonbr_log(LOG_CRIT, "Unexpected error while communicating with idle child process in pool #%i (PID %i): %s", worker->pool->poolnum, (int)worker->pid, strerror(errno));
   636         moonbr_terminate_error();
   637       }
   638     }
   639   }
   640   if (ptr) {
   641     char buf[sizeof(void *)];
   642     char *pos = buf;
   643     int len = sizeof(void *);
   644     ssize_t written;
   645     if (moonbr_debug) {
   646       moonbr_log(LOG_DEBUG, "Sending memory pointer to child process in pool #%i (PID %i)", (int)status, worker->pool->poolnum, (int)worker->pid);
   647     }
   648     memcpy(buf, &ptr, sizeof(void *));
   649     while (len) {
   650       written = send(worker->controlfd, pos, len, MSG_NOSIGNAL);
   651       if (written > 0) {
   652         pos += written;
   653         len -= written;
   654       } else if (errno == EPIPE) {
   655         moonbr_log(LOG_ERR, "Error while communicating with idle child process in pool #%i (PID %i): %s", worker->pool->poolnum, (int)worker->pid, strerror(errno));
   656         return;  /* do not close socket; socket is closed when reading from it */
   657       } else if (errno != EINTR) {
   658         moonbr_log(LOG_CRIT, "Unexpected error while communicating with idle child process in pool #%i (PID %i): %s", worker->pool->poolnum, (int)worker->pid, strerror(errno));
   659         moonbr_terminate_error();
   660       }
   661     }
   662   }
   663 }
   666 /*** Functions running in child process ***/
   668 /* Logs an error in child process */
   669 static void moonbr_child_log(const char *message) {
   670   fprintf(stderr, "%s\n", message);
   671 }
   673 /* Logs a fatal error in child process and terminates process with error status */
   674 static void moonbr_child_log_fatal(const char *message) {
   675   moonbr_child_log(message);
   676   exit(1);
   677 }
   679 /* Logs an error in child process while appending error string for global errno variable */
   680 static void moonbr_child_log_errno(const char *message) {
   681   char errmsg[MOONBR_MAXSTRERRORLEN] = MOONBR_STRERROR_R_MSG;
   682   strerror_r(errno, errmsg, MOONBR_MAXSTRERRORLEN);  /* use thread-safe call in case child created threads */
   683   fprintf(stderr, "%s: %s\n", message, errmsg);
   684 }
   686 /* Logs a fatal error in child process while appending error string for errno and terminating process */
   687 static void moonbr_child_log_errno_fatal(const char *message) {
   688   moonbr_child_log_errno(message);
   689   exit(1);
   690 }
   692 /* Receives a control message consisting of one character plus an optional file descriptor from parent process */
   693 static void moonbr_child_receive_control_message(int socketfd, char *status, int *fd) {
   694   struct iovec iovector = { .iov_base = status, .iov_len = 1 };  /* reference to status byte variable */
   695   char control_message_buffer[CMSG_SPACE(sizeof(int))] = {0, };  /* used to receive file descriptor */
   696   struct msghdr message = {  /* data structure passed to recvmsg() call */
   697     .msg_iov = &iovector,
   698     .msg_iovlen = 1,
   699     .msg_control = control_message_buffer,
   700     .msg_controllen = CMSG_SPACE(sizeof(int))
   701   };
   702   {
   703     int received;
   704     while ((received = recvmsg(socketfd, &message, MSG_CMSG_CLOEXEC)) < 0) {
   705       if (errno != EINTR) {
   706         moonbr_child_log_errno_fatal("Error while trying to receive connection socket from parent process");
   707       }
   708     }
   709     if (!received) {
   710       moonbr_child_log_fatal("Unexpected EOF while trying to receive connection socket from parent process");
   711     }
   712   }
   713   {
   714     struct cmsghdr *control_message = CMSG_FIRSTHDR(&message);
   715     if (control_message) {
   716       if (control_message->cmsg_level != SOL_SOCKET) {
   717         moonbr_child_log_fatal("Received control message with cmsg_level not equal to SOL_SOCKET");
   718       }
   719       if (control_message->cmsg_type != SCM_RIGHTS) {
   720         moonbr_child_log_fatal("Received control message with cmsg_type not equal to SCM_RIGHTS");
   721       }
   722       memcpy(fd, CMSG_DATA(control_message), sizeof(int));
   723     } else {
   724       *fd = -1;
   725     }
   726   }
   727 }
   729 /* Receives a pointer from parent process */
   730 static void *moonbr_child_receive_pointer(int socketfd) {
   731   char buf[sizeof(void *)];
   732   char *pos = buf;
   733   int len = sizeof(void *);
   734   ssize_t bytes_read;
   735   while (len) {
   736     bytes_read = recv(socketfd, pos, len, 0);
   737     if (bytes_read > 0) {
   738       pos += bytes_read;
   739       len -= bytes_read;
   740     } else if (!bytes_read) {
   741       moonbr_child_log_fatal("Unexpected EOF while trying to receive memory pointer from parent process");
   742     } else if (errno != EINTR) {
   743       moonbr_child_log_errno_fatal("Error while trying to receive memory pointer from parent process");
   744     }
   745   }
   746   {
   747     void *ptr;  /* avoid breaking strict-aliasing rules */
   748     memcpy(&ptr, buf, sizeof(void *));
   749     return ptr;
   750   }
   751 }
   753 /* Main function of child process to be called after fork() and file descriptor rearrangement */
   754 void moonbr_child_run(struct moonbr_pool *pool, lua_State *L) {
   755   char controlmsg;
   756   int fd;
   757   struct itimerval notimer = { { 0, }, { 0, } };
   758   lua_rawgetp(L, LUA_REGISTRYINDEX, moonbr_luakey_prepare_func(pool));
   759   if (lua_isnil(L, -1)) lua_pop(L, 1);
   760   else if (lua_pcall(L, 0, 0, 1)) {
   761     fprintf(stderr, "Error in \"prepare\" function: %s\n", lua_tostring(L, -1));
   762     exit(1);
   763   }
   764   moonbr_io_catch_sigterm(L);  // NOTE: should not fail
   765   while (1) {
   766     struct moonbr_listener *listener;
   767     if (setitimer(ITIMER_REAL, ¬imer, NULL)) {
   768       moonbr_child_log_errno_fatal("Could not reset ITIMER_REAL via setitimer()");
   769     }
   770     controlmsg = MOONBR_STATUS_IDLE;
   771     if (write(MOONBR_FD_CONTROL, &controlmsg, 1) <= 0) {
   772       moonbr_child_log_errno_fatal("Error while sending ready message to parent process");
   773     }
   774     moonbr_child_receive_control_message(MOONBR_FD_CONTROL, &controlmsg, &fd);
   775     if (!(
   776       (controlmsg == MOONBR_COMMAND_TERMINATE && fd == -1) ||
   777       (controlmsg == MOONBR_COMMAND_CONNECT)
   778     )) {
   779       moonbr_child_log_fatal("Received illegal control message from parent process");
   780     }
   781     if (controlmsg == MOONBR_COMMAND_TERMINATE) break;
   782     moonbr_io_sigterm_flag = 0;  /* ignore any prior SIGTERM (can't be handled in blocking recv anyway) */
   783     listener = moonbr_child_receive_pointer(MOONBR_FD_CONTROL);
   784     if (
   785       listener->proto != MOONBR_PROTO_LOCAL &&
   786       listener->proto != MOONBR_PROTO_TCP &&
   787       fd >= 0
   788     ) {
   789       moonbr_child_log_fatal("Received unexpected file descriptor from parent process");
   790     } else if (
   791       listener->proto != MOONBR_PROTO_INTERVAL && fd < 0
   792     ) {
   793       moonbr_child_log_fatal("Missing file descriptor from parent process");
   794     }
   795     if (fd >= 0) moonbr_io_pushhandle(L, fd);
   796     lua_rawgetp(L, LUA_REGISTRYINDEX, moonbr_luakey_connect_func(pool));
   797     if (fd < 0) {
   798       lua_newtable(L);
   799       if (listener->proto == MOONBR_PROTO_INTERVAL) {
   800         lua_pushstring(L,
   801           listener->type_specific.interval.name ?
   802           listener->type_specific.interval.name : ""
   803         );
   804         if (listener->type_specific.interval.main) {
   805           lua_setfield(L, -2, "main");
   806         } else {
   807           lua_setfield(L, -2, "interval");
   808         }
   809       }
   810     } else {
   811       lua_pushvalue(L, -2);
   812     }
   813     if (lua_pcall(L, 1, 1, 1)) {
   814       fprintf(stderr, "Error in \"connect\" function: %s\n", lua_tostring(L, -1));
   815       exit(1);
   816     }
   817     if (fd >= 0) moonbr_io_closehandle(L, -2, 0);  /* attemt clean close */
   818     if (
   819       moonbr_io_sigterm_flag ||
   820       lua_type(L, -1) != LUA_TBOOLEAN || !lua_toboolean(L, -1)
   821     ) break;
   822 #ifdef MOONBR_LUA_PANIC_BUG_WORKAROUND
   823     lua_settop(L, 2);
   824 #else
   825     lua_settop(L, 1);
   826 #endif
   827   }
   828   controlmsg = MOONBR_STATUS_GOODBYE;
   829   if (write(MOONBR_FD_CONTROL, &controlmsg, 1) <= 0) {
   830     moonbr_child_log_errno_fatal("Error while sending goodbye message to parent process");
   831   }
   832   if (close(MOONBR_FD_CONTROL) && errno != EINTR) {
   833     moonbr_child_log_errno("Error while closing control socket");
   834   }
   835   lua_rawgetp(L, LUA_REGISTRYINDEX, moonbr_luakey_finish_func(pool));
   836   if (lua_isnil(L, -1)) lua_pop(L, 1);
   837   else if (lua_pcall(L, 0, 0, 1)) {
   838     fprintf(stderr, "Error in \"finish\" function: %s\n", lua_tostring(L, -1));
   839     exit(1);
   840   }
   841   lua_close(L);
   842   exit(0);
   843 }
   846 /*** Functions to spawn child process ***/
   848 /* Helper function to send an error message to a file descriptor (not needing a file stream) */
   849 static void moonbr_child_emergency_print(int fd, char *message) {
   850   size_t len = strlen(message);
   851   ssize_t written;
   852   while (len) {
   853     written = write(fd, message, len);
   854     if (written > 0) {
   855       message += written;
   856       len -= written;
   857     } else {
   858       if (written != -1 || errno != EINTR) break;
   859     }
   860   }
   861 }
   863 /* Helper function to send an error message plus a text for errno to a file descriptor and terminate the process */
   864 static void moonbr_child_emergency_error(int fd, char *message) {
   865   int errno2 = errno;
   866   moonbr_child_emergency_print(fd, message);
   867   moonbr_child_emergency_print(fd, ": ");
   868   moonbr_child_emergency_print(fd, strerror(errno2));
   869   moonbr_child_emergency_print(fd, "\n");
   870   exit(1);
   871 }
   873 /* Creates a child process and (in case of success) registers it in the 'struct moonbr_pool' structure */
   874 static int moonbr_create_worker(struct moonbr_pool *pool, lua_State *L) {
   875   struct moonbr_worker *worker;
   876   worker = calloc(1, sizeof(struct moonbr_worker));
   877   if (!worker) {
   878     moonbr_log(LOG_CRIT, "Memory allocation error");
   879     return -1;
   880   }
   881   worker->pool = pool;
   882   {
   883     int controlfds[2];
   884     int errorfds[2];
   885     if (socketpair(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0, controlfds)) {
   886       moonbr_log(LOG_ERR, "Could not create control socket pair for communcation with child process: %s", strerror(errno));
   887       free(worker);
   888       return -1;
   889     }
   890     if (socketpair(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0, errorfds)) {
   891       moonbr_log(LOG_ERR, "Could not create socket pair to redirect stderr of child process: %s", strerror(errno));
   892       close(controlfds[0]);
   893       close(controlfds[1]);
   894       free(worker);
   895       return -1;
   896     }
   897     if (moonbr_logfile && fflush(moonbr_logfile)) {
   898       moonbr_log(LOG_CRIT, "Could not flush log file prior to forking: %s", strerror(errno));
   899       moonbr_terminate_error();
   900     }
   901     worker->pid = fork();
   902     if (worker->pid == -1) {
   903       moonbr_log(LOG_ERR, "Could not fork: %s", strerror(errno));
   904       close(controlfds[0]);
   905       close(controlfds[1]);
   906       close(errorfds[0]);
   907       close(errorfds[1]);
   908       free(worker);
   909       return -1;
   910     } else if (!worker->pid) {
   911       moonbr_pstate = MOONBR_PSTATE_FORKED;
   912 #ifdef MOONBR_LUA_PANIC_BUG_WORKAROUND
   913       lua_pushliteral(L, "Failed to pass error message due to bug in Lua panic handler (hint: not enough memory?)");
   914 #endif
   915       moonbr_memory_limit = pool->memory_limit;
   916       if (moonbr_pidfh && pidfile_close(moonbr_pidfh)) {
   917         moonbr_child_emergency_error(errorfds[1], "Could not close PID file in forked child process");
   918       }
   919       if (moonbr_logfile && moonbr_logfile != stderr && fclose(moonbr_logfile)) {
   920         moonbr_child_emergency_error(errorfds[1], "Could not close log file in forked child process");
   921       }
   922       if (dup2(errorfds[1], MOONBR_FD_STDERR) == -1) {
   923         moonbr_child_emergency_error(errorfds[1], "Could not duplicate socket to stderr file descriptor");
   924       }
   925       if (dup2(controlfds[1], MOONBR_FD_CONTROL) == -1) {
   926         moonbr_child_emergency_error(errorfds[1], "Could not duplicate control socket");
   927       }
   928       closefrom(MOONBR_FD_END);
   929       moonbr_child_run(pool, L);
   930     }
   931     if (moonbr_stat) {
   932       moonbr_log(LOG_INFO, "Created new worker in pool #%i with PID %i", worker->pool->poolnum, (int)worker->pid);
   933     }
   934     worker->controlfd = controlfds[0];
   935     worker->errorfd = errorfds[0];
   936     if (close(controlfds[1]) && errno != EINTR) {
   937       moonbr_log(LOG_CRIT, "Could not close opposite end of control file descriptor after forking");
   938       moonbr_terminate_error();
   939     }
   940     if (close(errorfds[1]) && errno != EINTR) {
   941       moonbr_log(LOG_CRIT, "Could not close opposite end of control file descriptor after forking");
   942       moonbr_terminate_error();
   943     }
   944   }
   945   worker->prev_worker = pool->last_worker;
   946   if (worker->prev_worker) worker->prev_worker->next_worker = worker;
   947   else pool->first_worker = worker;
   948   pool->last_worker = worker;
   949   pool->unassigned_worker_count++;
   950   pool->total_worker_count++;
   951   pool->worker_count_stat = 1;
   952   moonbr_poll_refresh_needed = 1;
   953   return 0;  /* return zero only in case of success */
   954 }
   957 /*** Functions for queues of 'struct moonbr_listener' ***/
   959 /* Appends a 'struct moonbr_listener' to the queue of idle listeners and registers it for poll() */
   960 static void moonbr_add_idle_listener(struct moonbr_listener *listener) {
   961   listener->prev_listener = listener->pool->last_idle_listener;
   962   if (listener->prev_listener) listener->prev_listener->next_listener = listener;
   963   else listener->pool->first_idle_listener = listener;
   964   listener->pool->last_idle_listener = listener;
   965   if (listener->pollidx != -1) moonbr_poll_fds[listener->pollidx].events |= POLLIN;
   966 }
   968 /* Removes a 'struct moonbr_listener' from the queue of idle listeners and unregisters it from poll() */
   969 static void moonbr_remove_idle_listener(struct moonbr_listener *listener) {
   970   if (listener->prev_listener) listener->prev_listener->next_listener = listener->next_listener;
   971   else listener->pool->first_idle_listener = listener->next_listener;
   972   if (listener->next_listener) listener->next_listener->prev_listener = listener->prev_listener;
   973   else listener->pool->last_idle_listener = listener->prev_listener;
   974   listener->prev_listener = NULL;
   975   listener->next_listener = NULL;
   976   if (listener->pollidx != -1) moonbr_poll_fds[listener->pollidx].events &= ~POLLIN;
   977 }
   979 /* Adds a listener to the queue of connected listeners (i.e. waiting to have their incoming connection accepted) */
   980 static void moonbr_add_connected_listener(struct moonbr_listener *listener) {
   981   listener->prev_listener = listener->pool->last_connected_listener;
   982   if (listener->prev_listener) listener->prev_listener->next_listener = listener;
   983   else listener->pool->first_connected_listener = listener;
   984   listener->pool->last_connected_listener = listener;
   985 }
   987 /* Removes and returns the first connected listener in the queue */
   988 static struct moonbr_listener *moonbr_pop_connected_listener(struct moonbr_pool *pool) {
   989   struct moonbr_listener *listener = pool->first_connected_listener;
   990   listener->pool->first_connected_listener = listener->next_listener;
   991   if (listener->pool->first_connected_listener) listener->pool->first_connected_listener->prev_listener = NULL;
   992   else listener->pool->last_connected_listener = NULL;
   993   listener->next_listener = NULL;
   994   return listener;
   995 }
   998 /*** Functions to handle polling ***/
  1000 /* Returns an index to a new initialized entry in moonbr_poll_fds[] */
  1001 int moonbr_poll_fds_nextindex() {
  1002   if (moonbr_poll_fds_count >= moonbr_poll_fds_bufsize) {
  1003     if (moonbr_poll_fds_bufsize) moonbr_poll_fds_bufsize *= 2;
  1004     else moonbr_poll_fds_bufsize = 1;
  1005     moonbr_poll_fds = realloc(
  1006       moonbr_poll_fds, moonbr_poll_fds_bufsize * sizeof(struct pollfd)
  1007     );
  1008     if (!moonbr_poll_fds) {
  1009       moonbr_log(LOG_CRIT, "Memory allocation error");
  1010       moonbr_terminate_error();
  1011     }
  1012   }
  1013   moonbr_poll_fds[moonbr_poll_fds_count] = (struct pollfd){0, };
  1014   return moonbr_poll_fds_count++;
  1015 }
  1017 /* Returns an index to a new initialized entry in moonbr_poll_workers[] */
  1018 int moonbr_poll_workers_nextindex() {
  1019   if (moonbr_poll_worker_count >= moonbr_poll_workers_bufsize) {
  1020     if (moonbr_poll_workers_bufsize) moonbr_poll_workers_bufsize *= 2;
  1021     else moonbr_poll_workers_bufsize = 1;
  1022     moonbr_poll_workers = realloc(
  1023       moonbr_poll_workers, moonbr_poll_workers_bufsize * sizeof(struct moonbr_poll_worker)
  1024     );
  1025     if (!moonbr_poll_workers) {
  1026       moonbr_log(LOG_CRIT, "Memory allocation error");
  1027       moonbr_terminate_error();
  1028     }
  1029   }
  1030   moonbr_poll_workers[moonbr_poll_worker_count] = (struct moonbr_poll_worker){0, };
  1031   return moonbr_poll_worker_count++;
  1032 }
  1034 /* Queues all listeners as idle, and initializes static part of moonbr_poll_fds[], which is passed to poll() */
  1035 static void moonbr_poll_init() {
  1036   if (socketpair(
  1037     PF_LOCAL,
  1038     SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
  1039     0,
  1040     moonbr_poll_signalfds
  1041   )) {
  1042     moonbr_log(LOG_CRIT, "Could not create socket pair for signal delivery during polling: %s", strerror(errno));
  1043     moonbr_terminate_error();
  1044   }
  1045   {
  1046     int j = moonbr_poll_fds_nextindex();
  1047     struct pollfd *pollfd = &moonbr_poll_fds[j];
  1048     pollfd->fd = moonbr_poll_signalfd_read;
  1049     pollfd->events = POLLIN;
  1050   }
  1051   {
  1052     struct moonbr_pool *pool;
  1053     for (pool=moonbr_first_pool; pool; pool=pool->next_pool) {
  1054       int i;
  1055       for (i=0; i<pool->listener_count; i++) {
  1056         struct moonbr_listener *listener = &pool->listener[i];
  1057         if (listener->listenfd != -1) {
  1058           int j = moonbr_poll_fds_nextindex();
  1059           listener->pollidx = j;
  1060           moonbr_poll_fds[j].fd = listener->listenfd;
  1061         }
  1062         moonbr_add_idle_listener(listener);
  1063       }
  1064     }
  1065   }
  1066   moonbr_poll_fds_static_count = moonbr_poll_fds_count;  /* remember size of static part of array */
  1067 }
  1069 /* Disables polling of all listeners (required for clean shutdown) */
  1070 static void moonbr_poll_shutdown() {
  1071   int i;
  1072   for (i=1; i<moonbr_poll_fds_static_count; i++) {
  1073     moonbr_poll_fds[i].fd = -1;
  1074   }
  1075 }
  1077 /* (Re)builds dynamic part of moonbr_poll_fds[] array, and (re)builds moonbr_poll_workers[] array */
  1078 static void moonbr_poll_refresh() {
  1079   moonbr_poll_refresh_needed = 0;
  1080   moonbr_poll_fds_count = moonbr_poll_fds_static_count;
  1081   moonbr_poll_worker_count = 0;
  1082   {
  1083     struct moonbr_pool *pool;
  1084     for (pool=moonbr_first_pool; pool; pool=pool->next_pool) {
  1085       struct moonbr_worker *worker;
  1086       for (worker=pool->first_worker; worker; worker=worker->next_worker) {
  1087         if (worker->controlfd != -1) {
  1088           int j = moonbr_poll_fds_nextindex();
  1089           int k = moonbr_poll_workers_nextindex();
  1090           struct pollfd *pollfd = &moonbr_poll_fds[j];
  1091           struct moonbr_poll_worker *poll_worker = &moonbr_poll_workers[k];
  1092           pollfd->fd = worker->controlfd;
  1093           pollfd->events = POLLIN;
  1094           poll_worker->channel = MOONBR_POLL_WORKER_CONTROLCHANNEL;
  1095           poll_worker->worker = worker;
  1096         }
  1097         if (worker->errorfd != -1) {
  1098           int j = moonbr_poll_fds_nextindex();
  1099           int k = moonbr_poll_workers_nextindex();
  1100           struct pollfd *pollfd = &moonbr_poll_fds[j];
  1101           struct moonbr_poll_worker *poll_worker = &moonbr_poll_workers[k];
  1102           pollfd->fd = worker->errorfd;
  1103           pollfd->events = POLLIN;
  1104           poll_worker->channel = MOONBR_POLL_WORKER_ERRORCHANNEL;
  1105           poll_worker->worker = worker;
  1106         }
  1107       }
  1108     }
  1109   }
  1110 }
  1112 /* resets socket and 'revents' field of moonbr_poll_fds[] for signal delivery just before poll() is called */
  1113 static void moonbr_poll_reset_signal() {
  1114   ssize_t readcount;
  1115   char buf[1];
  1116   moonbr_poll_fds[0].revents = 0;
  1117   while ((readcount = read(moonbr_poll_signalfd_read, buf, 1)) < 0) {
  1118     if (errno == EAGAIN) break;
  1119     if (errno != EINTR) {
  1120       moonbr_log(LOG_CRIT, "Error while reading from signal delivery socket: %s", strerror(errno));
  1121       moonbr_terminate_error();
  1122     }
  1123   }
  1124   if (!readcount) {
  1125     moonbr_log(LOG_CRIT, "Unexpected EOF when reading from signal delivery socket: %s", strerror(errno));
  1126     moonbr_terminate_error();
  1127   }
  1128 }
  1131 /*** Shutdown initiation ***/
  1133 /* Sets global variable 'moonbr_shutdown_in_progress', closes listeners, and demands worker termination */
  1134 static void moonbr_initiate_shutdown() {
  1135   struct moonbr_pool *pool;
  1136   int i;
  1137   struct moonbr_worker *worker;
  1138   if (moonbr_shutdown_in_progress) {
  1139     moonbr_log(LOG_NOTICE, "Shutdown already in progress");
  1140     return;
  1141   }
  1142   moonbr_shutdown_in_progress = 1;
  1143   moonbr_log(LOG_NOTICE, "Initiate shutdown");
  1144   for (pool = moonbr_first_pool; pool; pool = pool->next_pool) {
  1145     for (i=0; i<pool->listener_count; i++) {
  1146       struct moonbr_listener *listener = &pool->listener[i];
  1147       if (listener->listenfd != -1) {
  1148         if (close(listener->listenfd) && errno != EINTR) {
  1149           moonbr_log(LOG_CRIT, "Could not close listening socket: %s", strerror(errno));
  1150           moonbr_terminate_error();
  1151         }
  1152       }
  1153     }
  1154     for (worker=pool->first_worker; worker; worker=worker->next_worker) {
  1155       if (moonbr_debug) {
  1156         moonbr_log(LOG_DEBUG, "Sending SIGTERM to child with PID %i", (int)worker->pid);
  1157       }
  1158       if (kill(worker->pid, SIGTERM)) {
  1159         moonbr_log(LOG_ERR, "Error while terminating child process: %s", strerror(errno));
  1160       }
  1161     }
  1162   }
  1163   moonbr_poll_shutdown();  /* avoids loops due to error condition when polling closed listeners */
  1164 }
  1167 /*** Functions to handle previously created 'struct moonbr_worker' structures ***/
  1169 #define moonbr_try_destroy_worker_stat(str, field) \
  1170   moonbr_log(LOG_INFO, "Resource usage in pool #%i for PID %i: " str " %li", worker->pool->poolnum, (int)worker->pid, (long)childusage.field);
  1172 /* Destroys a worker structure if socket connections have been closed and child process has terminated */
  1173 static int moonbr_try_destroy_worker(struct moonbr_worker *worker) {
  1174   if (worker->controlfd != -1 || worker->errorfd != -1) return MOONBR_DESTROY_NONE;
  1175   {
  1176     int childstatus;
  1177     struct rusage childusage;
  1178     {
  1179       pid_t waitedpid;
  1180       while (
  1181         (waitedpid = wait4(worker->pid, &childstatus, WNOHANG, &childusage)) == -1
  1182       ) {
  1183         if (errno != EINTR) {
  1184           moonbr_log(LOG_CRIT, "Error in wait4() call: %s", strerror(errno));
  1185           moonbr_terminate_error();
  1186         }
  1187       }
  1188       if (!waitedpid) return 0;  /* return 0 if worker couldn't be destroyed */
  1189       if (waitedpid != worker->pid) {
  1190         moonbr_log(LOG_CRIT, "Wrong PID returned by wait4() call");
  1191         moonbr_terminate_error();
  1192       }
  1193     }
  1194     if (WIFEXITED(childstatus)) {
  1195       if (WEXITSTATUS(childstatus) || moonbr_stat) {
  1196         moonbr_log(
  1197           WEXITSTATUS(childstatus) ? LOG_WARNING : LOG_INFO,
  1198           "Child process in pool #%i with PID %i returned with exit code %i", worker->pool->poolnum, (int)worker->pid, WEXITSTATUS(childstatus)
  1199         );
  1200       }
  1201     } else if (WIFSIGNALED(childstatus)) {
  1202       if (WCOREDUMP(childstatus)) {
  1203         moonbr_log(LOG_ERR, "Child process in pool #%i with PID %i died from signal %i (core dump was created)", worker->pool->poolnum, (int)worker->pid, WTERMSIG(childstatus));
  1204       } else if (WTERMSIG(childstatus) == SIGALRM) {
  1205         moonbr_log(LOG_WARNING, "Child process in pool #%i with PID %i exited prematurely due to timeout", worker->pool->poolnum, (int)worker->pid);
  1206       } else {
  1207         moonbr_log(LOG_ERR, "Child process in pool #%i with PID %i died from signal %i", worker->pool->poolnum, (int)worker->pid, WTERMSIG(childstatus));
  1208       }
  1209     } else {
  1210       moonbr_log(LOG_CRIT, "Illegal exit status from child process in pool #%i with PID %i", worker->pool->poolnum, (int)worker->pid);
  1211       moonbr_terminate_error();
  1212     }
  1213     if (moonbr_stat) {
  1214       moonbr_log(LOG_INFO, "Resource usage in pool #%i for PID %i: user time %s", worker->pool->poolnum, (int)worker->pid, moonbr_format_timeval(&childusage.ru_utime));
  1215       moonbr_log(LOG_INFO, "Resource usage in pool #%i for PID %i: system time %s", worker->pool->poolnum, (int)worker->pid, moonbr_format_timeval(&childusage.ru_stime));
  1216       moonbr_try_destroy_worker_stat("max resident set size", ru_maxrss);
  1217       moonbr_try_destroy_worker_stat("integral shared memory size", ru_ixrss);
  1218       moonbr_try_destroy_worker_stat("integral unshared data", ru_idrss);
  1219       moonbr_try_destroy_worker_stat("integral unshared stack", ru_isrss);
  1220       moonbr_try_destroy_worker_stat("page replaims", ru_minflt);
  1221       moonbr_try_destroy_worker_stat("page faults", ru_majflt);
  1222       moonbr_try_destroy_worker_stat("swaps", ru_nswap);
  1223       moonbr_try_destroy_worker_stat("block input operations", ru_inblock);
  1224       moonbr_try_destroy_worker_stat("block output operations", ru_oublock);
  1225       moonbr_try_destroy_worker_stat("messages sent", ru_msgsnd);
  1226       moonbr_try_destroy_worker_stat("messages received", ru_msgrcv);
  1227       moonbr_try_destroy_worker_stat("signals received", ru_nsignals);
  1228       moonbr_try_destroy_worker_stat("voluntary context switches", ru_nvcsw);
  1229       moonbr_try_destroy_worker_stat("involuntary context switches", ru_nivcsw);
  1230     }
  1231   }
  1232   {
  1233     int retval = (
  1234       (worker->idle || worker->assigned) ?
  1235       MOONBR_DESTROY_IDLE_OR_ASSIGNED :
  1236       MOONBR_DESTROY_PREPARE
  1237     );
  1238     if (worker->main) moonbr_initiate_shutdown();
  1239     if (worker->prev_worker) worker->prev_worker->next_worker = worker->next_worker;
  1240     else worker->pool->first_worker = worker->next_worker;
  1241     if (worker->next_worker) worker->next_worker->prev_worker = worker->prev_worker;
  1242     else worker->pool->last_worker = worker->prev_worker;
  1243     if (worker->idle) {
  1244       if (worker->prev_idle_worker) worker->prev_idle_worker->next_idle_worker = worker->next_idle_worker;
  1245       else worker->pool->first_idle_worker = worker->next_idle_worker;
  1246       if (worker->next_idle_worker) worker->next_idle_worker->prev_idle_worker = worker->prev_idle_worker;
  1247       else worker->pool->last_idle_worker  = worker->prev_idle_worker;
  1248       worker->pool->idle_worker_count--;
  1249     }
  1250     if (!worker->assigned) worker->pool->unassigned_worker_count--;
  1251     worker->pool->total_worker_count--;
  1252     worker->pool->worker_count_stat = 1;
  1253     if (worker->errorlinebuf) free(worker->errorlinebuf);
  1254     free(worker);
  1255     return retval;
  1256   }
  1257 }
  1259 /* Marks a worker as idle and stores it in a queue, optionally setting 'idle_expiration' value */
  1260 static void moonbr_add_idle_worker(struct moonbr_worker *worker) {
  1261   worker->prev_idle_worker = worker->pool->last_idle_worker;
  1262   if (worker->prev_idle_worker) worker->prev_idle_worker->next_idle_worker = worker;
  1263   else worker->pool->first_idle_worker = worker;
  1264   worker->pool->last_idle_worker = worker;
  1265   worker->idle = 1;
  1266   worker->pool->idle_worker_count++;
  1267   if (worker->assigned) {
  1268     worker->assigned = 0;
  1269     worker->pool->unassigned_worker_count++;
  1270   }
  1271   worker->pool->worker_count_stat = 1;
  1272   if (timerisset(&worker->pool->idle_timeout)) {
  1273     struct timeval now;
  1274     moonbr_now(&now);
  1275     timeradd(&now, &worker->pool->idle_timeout, &worker->idle_expiration);
  1276   }
  1277 }
  1279 /* Pops a worker from the queue of idle workers (idle queue must not be empty) */
  1280 static struct moonbr_worker *moonbr_pop_idle_worker(struct moonbr_pool *pool) {
  1281   struct moonbr_worker *worker;
  1282   worker = pool->first_idle_worker;
  1283   pool->first_idle_worker = worker->next_idle_worker;
  1284   if (pool->first_idle_worker) pool->first_idle_worker->prev_idle_worker = NULL;
  1285   else pool->last_idle_worker = NULL;
  1286   worker->next_idle_worker = NULL;
  1287   worker->idle = 0;
  1288   worker->pool->idle_worker_count--;
  1289   worker->assigned = 1;
  1290   worker->pool->unassigned_worker_count--;
  1291   worker->pool->worker_count_stat = 1;
  1292   return worker;
  1293 }
  1296 /*** Functions to communicate with child processes ***/
  1298 /* Tells child process to terminate */
  1299 static void moonbr_terminate_idle_worker(struct moonbr_worker *worker) {
  1300   moonbr_send_control_message(worker, MOONBR_COMMAND_TERMINATE, -1, NULL);
  1301 }
  1303 /* Handles status messages from child process */
  1304 static void moonbr_read_controlchannel(struct moonbr_worker *worker) {
  1305   char controlmsg;
  1306   {
  1307     ssize_t bytes_read;
  1308     while ((bytes_read = read(worker->controlfd, &controlmsg, 1)) <= 0) {
  1309       if (bytes_read == 0 || errno == ECONNRESET) {
  1310         moonbr_log(LOG_WARNING, "Child process in pool #%i with PID %i unexpectedly closed control socket", worker->pool->poolnum, (int)worker->pid);
  1311         if (close(worker->controlfd) && errno != EINTR) {
  1312           moonbr_log(LOG_CRIT, "Error while closing control socket to child process in pool #%i with PID %i: %s", worker->pool->poolnum, (int)worker->pid, strerror(errno));
  1313           moonbr_terminate_error();
  1314         }
  1315         worker->controlfd = -1;
  1316         moonbr_poll_refresh_needed = 1;
  1317         return;
  1318       }
  1319       if (errno != EINTR) {
  1320         moonbr_log(LOG_CRIT, "Unexpected error while reading control socket from child process in pool #%i with PID %i: %s", worker->pool->poolnum, (int)worker->pid, strerror(errno));
  1321         moonbr_terminate_error();
  1322       }
  1323     }
  1324   }
  1325   if (worker->idle) {
  1326     moonbr_log(LOG_CRIT, "Unexpected data from supposedly idle child process in pool #%i with PID %i", worker->pool->poolnum, (int)worker->pid);
  1327     moonbr_terminate_error();
  1328   }
  1329   if (moonbr_debug) {
  1330     moonbr_log(LOG_DEBUG, "Received control message from child in pool #%i with PID %i: \"%c\"", worker->pool->poolnum, (int)worker->pid, (int)controlmsg);
  1331   }
  1332   switch (controlmsg) {
  1333   case MOONBR_STATUS_IDLE:
  1334     if (moonbr_stat) {
  1335       moonbr_log(LOG_INFO, "Child process in pool #%i with PID %i reports as idle", worker->pool->poolnum, (int)worker->pid);
  1336     }
  1337     moonbr_add_idle_worker(worker);
  1338     break;
  1339   case MOONBR_STATUS_GOODBYE:
  1340     if (moonbr_stat) {
  1341       moonbr_log(LOG_INFO, "Child process in pool #%i with PID %i announced termination", worker->pool->poolnum, (int)worker->pid);
  1342     }
  1343     if (close(worker->controlfd) && errno != EINTR) {
  1344       moonbr_log(LOG_CRIT, "Error while closing control socket to child process in pool #%i with PID %i: %s", worker->pool->poolnum, (int)worker->pid, strerror(errno));
  1345       moonbr_terminate_error();
  1346     }
  1347     worker->controlfd = -1;
  1348     moonbr_poll_refresh_needed = 1;
  1349     break;
  1350   default:
  1351     moonbr_log(LOG_CRIT, "Received illegal data (\"%c\") while reading control socket from child process in pool #%i with PID %i", (int)controlmsg, worker->pool->poolnum, (int)worker->pid);
  1352     moonbr_terminate_error();
  1353   }
  1354 }
  1356 /* Handles stderr stream from child process */
  1357 static void moonbr_read_errorchannel(struct moonbr_worker *worker) {
  1358   char staticbuf[MOONBR_MAXERRORLINELEN+1];
  1359   char *buf = worker->errorlinebuf;
  1360   if (!buf) buf = staticbuf;
  1361   {
  1362     ssize_t bytes_read;
  1363     while (
  1364       (bytes_read = read(
  1365         worker->errorfd,
  1366         buf + worker->errorlinelen,
  1367         MOONBR_MAXERRORLINELEN+1 - worker->errorlinelen
  1368       )) <= 0
  1369     ) {
  1370       if (bytes_read == 0 || errno == ECONNRESET) {
  1371         if (moonbr_debug) {
  1372           moonbr_log(LOG_DEBUG, "Child process in pool #%i with PID %i closed stderr socket", worker->pool->poolnum, (int)worker->pid);
  1373         }
  1374         if (close(worker->errorfd) && errno != EINTR) {
  1375           moonbr_log(LOG_CRIT, "Error while closing stderr socket to child process in pool #%i with PID %i: %s", worker->pool->poolnum, (int)worker->pid, strerror(errno));
  1376           moonbr_terminate_error();
  1377         }
  1378         worker->errorfd = -1;
  1379         moonbr_poll_refresh_needed = 1;
  1380         break;
  1381       }
  1382       if (errno != EINTR) {
  1383         moonbr_log(LOG_CRIT, "Unexpected error while reading stderr from child process in pool #%i with PID %i: %s", worker->pool->poolnum, (int)worker->pid, strerror(errno));
  1384         moonbr_terminate_error();
  1385       }
  1386     }
  1387     worker->errorlinelen += bytes_read;
  1388   }
  1389   {
  1390     int i;
  1391     for (i=0; i<worker->errorlinelen; i++) {
  1392       if (buf[i] == '\n') buf[i] = 0;
  1393       if (!buf[i]) {
  1394         if (worker->errorlineovf) {
  1395           worker->errorlineovf = 0;
  1396         } else {
  1397           moonbr_log(LOG_WARNING, "[Pool #%i, PID %i] %s", worker->pool->poolnum, (int)worker->pid, buf);
  1398         }
  1399         worker->errorlinelen -= i+1;
  1400         memmove(buf, buf+i+1, worker->errorlinelen);
  1401         i = -1;
  1402       }
  1403     }
  1404     if (i > MOONBR_MAXERRORLINELEN) {
  1405       buf[MOONBR_MAXERRORLINELEN] = 0;
  1406       if (!worker->errorlineovf) {
  1407         moonbr_log(LOG_WARNING, "[Pool #%i, PID %i](line has been truncated) %s", worker->pool->poolnum, (int)worker->pid, buf);
  1408       }
  1409       worker->errorlinelen = 0;
  1410       worker->errorlineovf = 1;
  1411     }
  1412   }
  1413   if (!worker->errorlinebuf && worker->errorlinelen) {  /* allocate buffer on heap only if necessary */
  1414     worker->errorlinebuf = malloc((MOONBR_MAXERRORLINELEN+1) * sizeof(char));
  1415     if (!worker->errorlinebuf) {
  1416       moonbr_log(LOG_CRIT, "Memory allocation error");
  1417       moonbr_terminate_error();
  1418     }
  1419     memcpy(worker->errorlinebuf, staticbuf, worker->errorlinelen);
  1420   }
  1421 }
  1424 /*** Handler for incoming connections ***/
  1426 /* Accepts one or more incoming connections on listener socket and passes it to worker(s) popped from idle queue */
  1427 static void moonbr_connect(struct moonbr_pool *pool) {
  1428   struct moonbr_listener *listener = moonbr_pop_connected_listener(pool);
  1429   struct moonbr_worker *worker;
  1430   if (listener->proto == MOONBR_PROTO_INTERVAL) {
  1431     worker = moonbr_pop_idle_worker(pool);
  1432     if (listener->type_specific.interval.main) {
  1433       if (moonbr_stat) {
  1434         moonbr_log(LOG_INFO, "Dispatching main thread \"%s\" of pool #%i to PID %i", listener->type_specific.interval.name, listener->pool->poolnum, (int)worker->pid);
  1435       }
  1436       worker->main = 1;
  1437     } else {
  1438       if (moonbr_stat) {
  1439         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);
  1440       }
  1441       worker->restart_interval_listener = listener;
  1442     }
  1443     moonbr_send_control_message(worker, MOONBR_COMMAND_CONNECT, -1, listener);
  1444     /* do not push listener to queue of idle listeners (yet) */
  1445   } else {
  1446     int peerfd;
  1447     do {
  1448 #if defined(__linux__) && !defined(_GNU_SOURCE)
  1449       peerfd = accept(listener->listenfd, NULL, NULL);
  1450       if (peerfd != -1) {
  1451         if (fcntl(peerfd, F_SETFD, FD_CLOEXEC) == -1) {
  1452           moonbr_log(LOG_ERR, "Error in fcntl() call: %s", strerror(errno));
  1453           moonbr_terminate_error();
  1454         }
  1455       }
  1456 #else
  1457       peerfd = accept4(listener->listenfd, NULL, NULL, SOCK_CLOEXEC);
  1458 #endif
  1459       if (peerfd == -1) {
  1460         if (errno == EWOULDBLOCK) {
  1461           break;
  1462         } else if (errno == ECONNABORTED) {
  1463           moonbr_log(LOG_WARNING, "Connection aborted before accepting it");
  1464           break;
  1465         } else if (errno != EINTR) {
  1466           moonbr_log(LOG_ERR, "Could not accept socket connection: %s", strerror(errno));
  1467           moonbr_terminate_error();
  1468         }
  1469       } else {
  1470         worker = moonbr_pop_idle_worker(pool);
  1471         if (moonbr_stat) {
  1472           moonbr_log(LOG_INFO, "Dispatching connection for pool #%i to PID %i", listener->pool->poolnum, (int)worker->pid);
  1473         }
  1474         moonbr_send_control_message(worker, MOONBR_COMMAND_CONNECT, peerfd, listener);
  1475         if (close(peerfd) && errno != EINTR) {
  1476           moonbr_log(LOG_ERR, "Could not close incoming socket connection in parent process: %s", strerror(errno));
  1477           moonbr_terminate_error();
  1478         }
  1479       }
  1480     } while (pool->first_idle_worker);
  1481     moonbr_add_idle_listener(listener);
  1482   }
  1483 }
  1486 /*** Functions to initialize and restart interval timers ***/
  1488 /* Initializes all interval timers */
  1489 static void moonbr_interval_initialize() {
  1490   struct timeval now;
  1491   struct moonbr_pool *pool;
  1492   moonbr_now(&now);
  1493   for (pool=moonbr_first_pool; pool; pool=pool->next_pool) {
  1494     int i;
  1495     for (i=0; i<pool->listener_count; i++) {
  1496       struct moonbr_listener *listener = &pool->listener[i];
  1497       if (listener->proto == MOONBR_PROTO_INTERVAL) {
  1498         timeradd(
  1499           &now,
  1500           &listener->type_specific.interval.delay,
  1501           &listener->type_specific.interval.wakeup
  1502         );
  1503       }
  1504     }
  1505   }
  1506 }
  1508 /* If necessary, restarts interval timers and queues interval listener as idle after a worker changed status */
  1509 static void moonbr_interval_restart(
  1510   struct moonbr_worker *worker,
  1511   struct timeval *now           /* passed to synchronize with moonbr_run() function */
  1512 ) {
  1513   struct moonbr_listener *listener = worker->restart_interval_listener;
  1514   if (listener) {
  1515     moonbr_add_idle_listener(listener);
  1516     worker->restart_interval_listener = NULL;
  1517     if (listener->type_specific.interval.strict) {
  1518       timeradd(
  1519         &listener->type_specific.interval.wakeup,
  1520         &listener->type_specific.interval.delay,
  1521         &listener->type_specific.interval.wakeup
  1522       );
  1523       if (timercmp(&listener->type_specific.interval.wakeup, now, <)) {
  1524         listener->type_specific.interval.wakeup = *now;
  1525       }
  1526     } else {
  1527       timeradd(
  1528         now,
  1529         &listener->type_specific.interval.delay,
  1530         &listener->type_specific.interval.wakeup
  1531       );
  1532     }
  1533   }
  1534 }
  1537 /*** Main loop and helper functions ***/
  1539 /* Stores the earliest required wakeup time in 'wait' variable */
  1540 static void moonbr_calc_wait(struct timeval *wait, struct timeval *wakeup) {
  1541   if (!timerisset(wait) || timercmp(wakeup, wait, <)) *wait = *wakeup;
  1542 }
  1544 /* Main loop of Moonbridge system (including initialization of signal handlers and polling structures) */
  1545 static void moonbr_run(lua_State *L) {
  1546   struct timeval now;
  1547   struct moonbr_pool *pool;
  1548   struct moonbr_worker *worker;
  1549   struct moonbr_worker *next_worker;  /* needed when worker is removed during iteration of workers */
  1550   struct moonbr_listener *listener;
  1551   struct moonbr_listener *next_listener;  /* needed when listener is removed during iteration of listeners */
  1552   int i;
  1553   moonbr_poll_init();    /* must be executed before moonbr_signal_init() */
  1554   moonbr_signal_init();
  1555   moonbr_interval_initialize();
  1556   moonbr_pstate = MOONBR_PSTATE_RUNNING;
  1557   while (1) {
  1558     struct timeval wait = {0, };  /* point in time when premature wakeup of poll() is required */
  1559     if (moonbr_cond_interrupt) {
  1560       moonbr_log(LOG_WARNING, "Fast shutdown requested");
  1561       moonbr_terminate(MOONBR_EXITCODE_GRACEFUL);
  1562     }
  1563     if (moonbr_cond_terminate) {
  1564       moonbr_initiate_shutdown();
  1565       moonbr_cond_terminate = 0;
  1566     }
  1567     moonbr_cond_child = 0;  /* must not be reset between moonbr_try_destroy_worker() and poll() */
  1568     moonbr_now(&now);
  1569     for (pool=moonbr_first_pool; pool; pool=pool->next_pool) {
  1570       int terminated_worker_count = 0;  /* allows shortcut for new worker creation */
  1571       /* terminate idle workers when expired */
  1572       if (timerisset(&pool->idle_timeout)) {
  1573         while ((worker = pool->first_idle_worker) != NULL) {
  1574           if (timercmp(&worker->idle_expiration, &now, >)) break;
  1575           moonbr_pop_idle_worker(pool);
  1576           moonbr_terminate_idle_worker(worker);
  1577         }
  1578       }
  1579       /* mark listeners as connected when incoming connection is pending */
  1580       for (listener=pool->first_idle_listener; listener; listener=next_listener) {
  1581         next_listener = listener->next_listener;  /* extra variable necessary due to changing list */
  1582         if (listener->pollidx != -1) {
  1583           if (moonbr_poll_fds[listener->pollidx].revents) {
  1584             moonbr_poll_fds[listener->pollidx].revents = 0;
  1585             moonbr_remove_idle_listener(listener);
  1586             moonbr_add_connected_listener(listener);
  1587           }
  1588         } else if (
  1589           listener->proto != MOONBR_PROTO_INTERVAL ||
  1590           !timercmp(&listener->type_specific.interval.wakeup, &now, >)
  1591         ) {
  1592           moonbr_remove_idle_listener(listener);
  1593           moonbr_add_connected_listener(listener);
  1594         }
  1595       }
  1596       /* process input from child processes */
  1597       for (i=0; i<moonbr_poll_worker_count; i++) {
  1598         if (moonbr_poll_worker_fds[i].revents) {
  1599           moonbr_poll_worker_fds[i].revents = 0;
  1600           struct moonbr_poll_worker *poll_worker = &moonbr_poll_workers[i];
  1601           switch (poll_worker->channel) {
  1602           case MOONBR_POLL_WORKER_CONTROLCHANNEL:
  1603             moonbr_read_controlchannel(poll_worker->worker);
  1604             moonbr_interval_restart(poll_worker->worker, &now);
  1605             break;
  1606           case MOONBR_POLL_WORKER_ERRORCHANNEL:
  1607             moonbr_read_errorchannel(poll_worker->worker);
  1608             break;
  1609           }
  1610         }
  1611       }
  1612       /* collect dead child processes */
  1613       for (worker=pool->first_worker; worker; worker=next_worker) {
  1614         next_worker = worker->next_worker;  /* extra variable necessary due to changing list */
  1615         switch (moonbr_try_destroy_worker(worker)) {
  1616         case MOONBR_DESTROY_PREPARE:
  1617           pool->use_fork_error_wakeup = 1;
  1618           break;
  1619         case MOONBR_DESTROY_IDLE_OR_ASSIGNED:
  1620           terminated_worker_count++;
  1621           break;
  1622         }
  1623       }
  1624       if (!moonbr_shutdown_in_progress) {
  1625         /* connect listeners with idle workers */
  1626         while (pool->first_connected_listener && pool->first_idle_worker) {
  1627           moonbr_connect(pool);
  1628         }
  1629         /* create new worker processes */
  1630         while (
  1631           pool->total_worker_count < pool->max_fork && (
  1632             pool->unassigned_worker_count < pool->pre_fork ||
  1633             pool->total_worker_count < pool->min_fork
  1634           )
  1635         ) {
  1636           if (pool->use_fork_error_wakeup) {
  1637             if (timercmp(&pool->fork_error_wakeup, &now, >)) {
  1638             moonbr_calc_wait(&wait, &pool->fork_error_wakeup);
  1639             break;
  1640             }
  1641           } else {
  1642             if (terminated_worker_count) {
  1643               terminated_worker_count--;
  1644             } else if (timercmp(&pool->fork_wakeup, &now, >)) {
  1645               moonbr_calc_wait(&wait, &pool->fork_wakeup);
  1646               break;
  1647             }
  1648           }
  1649           if (moonbr_create_worker(pool, L)) {
  1650             /* on error, enforce error delay */
  1651             timeradd(&now, &pool->fork_error_delay, &pool->fork_error_wakeup);
  1652             pool->use_fork_error_wakeup = 1;
  1653             moonbr_calc_wait(&wait, &pool->fork_error_wakeup);
  1654             break;
  1655           } else {
  1656             /* normal fork delay on success */
  1657             timeradd(&now, &pool->fork_delay, &pool->fork_wakeup);
  1658             timeradd(&now, &pool->fork_error_delay, &pool->fork_error_wakeup);
  1659             pool->use_fork_error_wakeup = 0;  /* gets set later if error occures during preparation */
  1660           }
  1661         }
  1662         /* terminate excessive worker processes */
  1663         while (
  1664           pool->total_worker_count > pool->min_fork &&
  1665           pool->idle_worker_count > pool->pre_fork
  1666         ) {
  1667           if (timerisset(&pool->exit_wakeup)) {
  1668             if (timercmp(&pool->exit_wakeup, &now, >)) {
  1669               moonbr_calc_wait(&wait, &pool->exit_wakeup);
  1670               break;
  1671             }
  1672             moonbr_terminate_idle_worker(moonbr_pop_idle_worker(pool));
  1673             timeradd(&now, &pool->exit_delay, &pool->exit_wakeup);
  1674           } else {
  1675             timeradd(&now, &pool->exit_delay, &pool->exit_wakeup);
  1676             break;
  1677           }
  1678         }
  1679         if (!(
  1680           pool->total_worker_count > pool->min_fork &&
  1681           pool->idle_worker_count > pool->pre_fork
  1682         )) {
  1683           timerclear(&pool->exit_wakeup);  /* timer gets restarted later when there are excessive workers */
  1684         }
  1685       }
  1686       /* optionally output worker count stats */
  1687       if (moonbr_stat && pool->worker_count_stat) {
  1688         pool->worker_count_stat = 0;
  1689         moonbr_log(
  1690           LOG_INFO,
  1691           "Worker count for pool #%i: %i idle, %i assigned, %i total",
  1692           pool->poolnum, pool->idle_worker_count,
  1693           pool->total_worker_count - pool->unassigned_worker_count,
  1694           pool->total_worker_count);
  1695       }
  1696       /* calculate wakeup time for interval listeners */
  1697       for (listener=pool->first_idle_listener; listener; listener=listener->next_listener) {
  1698         if (listener->proto == MOONBR_PROTO_INTERVAL) {
  1699           moonbr_calc_wait(&wait, &listener->type_specific.interval.wakeup);
  1700         }
  1701       }
  1702       /* calculate wakeup time for idle workers (only first idle worker is significant) */
  1703       if (timerisset(&pool->idle_timeout) && pool->first_idle_worker) {
  1704         moonbr_calc_wait(&wait, &pool->first_idle_worker->idle_expiration);
  1705       }
  1706     }
  1707     /* terminate idle workers in case of shutdown and check if shutdown is complete */
  1708     if (moonbr_shutdown_in_progress) {
  1709       int remaining = 0;
  1710       for (pool=moonbr_first_pool; pool; pool=pool->next_pool) {
  1711         while (pool->idle_worker_count) {
  1712           moonbr_terminate_idle_worker(moonbr_pop_idle_worker(pool));
  1713         }
  1714         if (pool->first_worker) remaining = 1;
  1715       }
  1716       if (!remaining) {
  1717         moonbr_log(LOG_INFO, "All worker threads have terminated");
  1718         moonbr_terminate(MOONBR_EXITCODE_GRACEFUL);
  1719       }
  1720     }
  1721     if (moonbr_poll_refresh_needed) moonbr_poll_refresh();
  1722     moonbr_cond_poll = 1;
  1723     if (!moonbr_cond_child && !moonbr_cond_terminate && !moonbr_cond_interrupt) {
  1724       int timeout;
  1725       if (timerisset(&wait)) {
  1726         if (timercmp(&wait, &now, <)) {
  1727           moonbr_log(LOG_CRIT, "Internal error (should not happen): Future is in the past");
  1728           moonbr_terminate_error();
  1729         }
  1730         timersub(&wait, &now, &wait);
  1731         timeout = wait.tv_sec * 1000 + wait.tv_usec / 1000;
  1732       } else {
  1733         timeout = INFTIM;
  1734       }
  1735       if (moonbr_debug) {
  1736         moonbr_log(LOG_DEBUG, "Waiting for I/O");
  1737       }
  1738       poll(moonbr_poll_fds, moonbr_poll_fds_count, timeout);
  1739     } else {
  1740       if (moonbr_debug) {
  1741         moonbr_log(LOG_DEBUG, "Do not wait for I/O");
  1742       }
  1743     }
  1744     moonbr_cond_poll = 0;
  1745     moonbr_poll_reset_signal();
  1746   }
  1747 }
  1750 /*** Lua interface ***/
  1752 static int moonbr_lua_panic(lua_State *L) {
  1753   const char *errmsg;
  1754   errmsg = lua_tostring(L, -1);
  1755   if (!errmsg) {
  1756     if (lua_isnoneornil(L, -1)) errmsg = "(error message is nil)";
  1757     else errmsg = "(error message is not a string)";
  1758   }
  1759   if (moonbr_pstate == MOONBR_PSTATE_FORKED) {
  1760     fprintf(stderr, "Uncaught Lua error: %s\n", errmsg);
  1761     exit(1);
  1762   } else {
  1763     moonbr_log(LOG_CRIT, "Uncaught Lua error: %s", errmsg);
  1764     moonbr_terminate_error();
  1765   }
  1766   return 0;
  1767 }
  1769 static int moonbr_addtraceback(lua_State *L) {
  1770   luaL_traceback(L, L, luaL_tolstring(L, 1, NULL), 1);
  1771   return 1;
  1772 }
  1774 /* Memory allocator that allows limiting memory consumption */
  1775 static void *moonbr_alloc (void *ud, void *ptr, size_t osize, size_t nsize) {
  1776   (void)ud;  /* not used */
  1777   if (nsize == 0) {
  1778     if (ptr) {
  1779       moonbr_memory_usage -= osize;
  1780       free(ptr);
  1781     }
  1782     return NULL;
  1783   } else if (ptr) {
  1784     if (
  1785       moonbr_memory_limit &&
  1786       nsize > osize &&
  1787       moonbr_memory_usage + (nsize - osize) > moonbr_memory_limit
  1788     ) {
  1789       return NULL;
  1790     } else {
  1791       ptr = realloc(ptr, nsize);
  1792       if (ptr) moonbr_memory_usage += nsize - osize;
  1793     }
  1794   } else {
  1795     if (
  1796       moonbr_memory_limit &&
  1797       moonbr_memory_usage + nsize > moonbr_memory_limit
  1798     ) {
  1799       return NULL;
  1800     } else {
  1801       ptr = realloc(ptr, nsize);
  1802       if (ptr) moonbr_memory_usage += nsize;
  1803     }
  1804   }
  1805   return ptr;
  1806 }
  1808 static int moonbr_lua_tonatural(lua_State *L, int idx) {
  1809   int isnum;
  1810   lua_Number n;
  1811   n = lua_tonumberx(L, idx, &isnum);
  1812   if (isnum && n>=0 && n<INT_MAX && (lua_Number)(int)n == n) return n;
  1813   else return -1;
  1814 }
  1816 static int moonbr_lua_totimeval(lua_State *L, int idx, struct timeval *value) {
  1817   int isnum;
  1818   lua_Number n;
  1819   n = lua_tonumberx(L, idx, &isnum);
  1820   if (isnum && n>=0 && n<=100000000) {
  1821     value->tv_sec = n;
  1822     value->tv_usec = 1e6 * (n - value->tv_sec);
  1823     return 1;
  1824   } else {
  1825     return 0;
  1826   }
  1827 }
  1829 static int moonbr_timeout(lua_State *L) {
  1830   struct itimerval oldval;
  1831   if (lua_isnoneornil(L, 1) && lua_isnoneornil(L, 2)) {
  1832     getitimer(ITIMER_REAL, &oldval);
  1833   } else {
  1834     struct itimerval newval = {};
  1835     timerclear(&newval.it_interval);
  1836     timerclear(&newval.it_value);
  1837     if (lua_toboolean(L, 1)) {
  1838       luaL_argcheck(
  1839         L, moonbr_lua_totimeval(L, 1, &newval.it_value), 1,
  1840         "interval in seconds expected"
  1841       );
  1842     }
  1843     if (lua_isnoneornil(L, 2)) {
  1844       if (setitimer(ITIMER_REAL, &newval, &oldval)) {
  1845         moonbr_log(LOG_CRIT, "Could not set ITIMER_REAL via setitimer()");
  1846         moonbr_terminate_error();
  1847       }
  1848     } else {
  1849       getitimer(ITIMER_REAL, &oldval);
  1850       if (!timerisset(&oldval.it_value)) {
  1851         if (setitimer(ITIMER_REAL, &newval, NULL)) {
  1852           moonbr_log(LOG_CRIT, "Could not set ITIMER_REAL via setitimer()");
  1853           moonbr_terminate_error();
  1854         }
  1855         lua_call(L, lua_gettop(L) - 2, LUA_MULTRET);
  1856         timerclear(&newval.it_value);
  1857         if (setitimer(ITIMER_REAL, &newval, NULL)) {
  1858           moonbr_log(LOG_CRIT, "Could not set ITIMER_REAL via setitimer()");
  1859           moonbr_terminate_error();
  1860         }
  1861       } else if (timercmp(&newval.it_value, &oldval.it_value, <)) {
  1862         struct itimerval remval;
  1863         if (setitimer(ITIMER_REAL, &newval, NULL)) {
  1864           moonbr_log(LOG_CRIT, "Could not set ITIMER_REAL via setitimer()");
  1865           moonbr_terminate_error();
  1866         }
  1867         lua_call(L, lua_gettop(L) - 2, LUA_MULTRET);
  1868         getitimer(ITIMER_REAL, &remval);
  1869         timersub(&oldval.it_value, &newval.it_value, &newval.it_value);
  1870         timeradd(&newval.it_value, &remval.it_value, &newval.it_value);
  1871         if (setitimer(ITIMER_REAL, &newval, NULL)) {
  1872           moonbr_log(LOG_CRIT, "Could not set ITIMER_REAL via setitimer()");
  1873           moonbr_terminate_error();
  1874         }
  1875       } else {
  1876         lua_call(L, lua_gettop(L) - 2, LUA_MULTRET);
  1877       }
  1878       return lua_gettop(L) - 1;
  1879     }
  1880   }
  1881   lua_pushnumber(L, oldval.it_value.tv_sec + 1e-6 * oldval.it_value.tv_usec);
  1882   return 1;
  1883 }
  1885 #define moonbr_listen_init_pool_forkoption(luaname, cname, defval) do { \
  1886   lua_getfield(L, 2, luaname); \
  1887   pool->cname = lua_isnil(L, -1) ? (defval) : moonbr_lua_tonatural(L, -1); \
  1888 } while(0)
  1890 #define moonbr_listen_init_pool_timeoption(luaname, cname, defval, defvalu) ( \
  1891   lua_getfield(L, 2, luaname), \
  1892   lua_isnil(L, -1) ? ( \
  1893     pool->cname.tv_sec = (defval), pool->cname.tv_usec = (defvalu), \
  1894     1 \
  1895   ) : ( \
  1896     (lua_isboolean(L, -1) && !lua_toboolean(L, -1)) ? ( \
  1897       pool->cname.tv_sec = 0, pool->cname.tv_usec = 0, \
  1898       1 \
  1899     ) : ( \
  1900       moonbr_lua_totimeval(L, -1, &pool->cname) \
  1901     ) \
  1902   ) \
  1903 )
  1905 static int moonbr_listen_init_pool(lua_State *L) {
  1906   struct moonbr_pool *pool;
  1907   const char *proto;
  1908   int is_main;
  1909   int i;
  1910   int dynamic = 0;  /* nonzero = listeners exist which require dynamic worker creation */
  1911   pool = lua_touserdata(L, 1);
  1912   for (i=0; i<pool->listener_count; i++) {
  1913     struct moonbr_listener *listener = &pool->listener[i];
  1914     lua_settop(L, 2);
  1915 #if LUA_VERSION_NUM >= 503
  1916     lua_geti(L, 2, i+1);
  1917 #else
  1918     lua_pushinteger(L, i+1);
  1919     lua_gettable(L, 2);
  1920 #endif
  1921     lua_getfield(L, 3, "proto");
  1922     proto = lua_tostring(L, -1);
  1923     is_main = !strcmp(proto, "main");
  1924     if (proto && (is_main || !strcmp(proto, "interval"))) {
  1925       listener->proto = MOONBR_PROTO_INTERVAL;
  1926       lua_getfield(L, 3, "name");
  1927       {
  1928         const char *name = lua_tostring(L, -1);
  1929         if (name) {
  1930           char *name_dup = strdup(name);
  1931           if (!name_dup) {
  1932             moonbr_log(LOG_CRIT, "Memory allocation_error");
  1933             moonbr_terminate_error();
  1934           }
  1935           listener->type_specific.interval.name = name_dup;
  1936         }
  1937       }
  1938       if (is_main) {
  1939         listener->type_specific.interval.main = 1;
  1940       } else {
  1941         listener->type_specific.interval.main = 0;
  1942         dynamic = 1;
  1943         lua_getfield(L, 3, "delay");
  1944         if (
  1945           !moonbr_lua_totimeval(L, -1, &listener->type_specific.interval.delay) ||
  1946           !timerisset(&listener->type_specific.interval.delay)
  1947         ) {
  1948           luaL_error(L, "No valid interval delay specified; use listen{{proto=\"interval\", delay=...}, ...}");
  1949         }
  1950         lua_getfield(L, 3, "strict");
  1951         if (!lua_isnil(L, -1)) {
  1952           if (lua_isboolean(L, -1)) {
  1953             if (lua_toboolean(L, -1)) listener->type_specific.interval.strict = 1;
  1954           } else {
  1955             luaL_error(L, "Option \"strict\" must be a boolean if set; use listen{{proto=\"interval\", strict=true, ...}, ...}");
  1956           }
  1957         }
  1958       }
  1959     } else if (proto && !strcmp(proto, "local")) {
  1960       const char *path;
  1961       const int path_maxlen = (
  1962         sizeof(listener->type_specific.socket.addr.addr_un) -
  1963         ((void *)listener->type_specific.socket.addr.addr_un.sun_path - (void *)&listener->type_specific.socket.addr.addr_un)
  1964       ) - 1;  /* one byte for termination */
  1965       dynamic = 1;
  1966       listener->proto = MOONBR_PROTO_LOCAL;
  1967       lua_getfield(L, 3, "path");
  1968       path = lua_tostring(L, -1);
  1969       if (!path) {
  1970         luaL_error(L, "No valid path specified for local socket; use listen{{proto=\"local\", path=...}, ...}");
  1971       }
  1972       if (strlen(path) > path_maxlen) {
  1973         luaL_error(L, "Path name for local socket exceeded maximum length of %i characters", path_maxlen);
  1974       }
  1975       strcpy(listener->type_specific.socket.addr.addr_un.sun_path, path);
  1976     } else if (proto && !strcmp(proto, "tcp")) {
  1977       const char *host, *port;
  1978       struct addrinfo hints = { 0, };
  1979       struct addrinfo *res, *addrinfo;
  1980       int errcode;
  1981       const char *ip;
  1982       dynamic = 1;
  1983       lua_getfield(L, 3, "host");
  1984       host = lua_isnil(L, -1) ? "::" : lua_tostring(L, -1);
  1985       if (!host) {
  1986         luaL_error(L, "No host specified; use listen{{proto=\"tcp\", host=...}, ...}");
  1987       }
  1988       lua_getfield(L, 3, "port");
  1989       port = lua_tostring(L, -1);
  1990       if (!port) {
  1991         luaL_error(L, "No port specified; use listen{{proto=\"tcp\", host=...}, ...}");
  1992       }
  1993       hints.ai_family = AF_UNSPEC;
  1994       hints.ai_socktype = SOCK_STREAM;
  1995       hints.ai_protocol = IPPROTO_TCP;
  1996       hints.ai_flags = AI_ADDRCONFIG | AI_PASSIVE;
  1997       errcode = getaddrinfo(host, port, &hints, &res);
  1998       if (errcode) {
  1999         freeaddrinfo(res);
  2000         if (errcode == EAI_SYSTEM) {
  2001           char errmsg[MOONBR_MAXSTRERRORLEN] = MOONBR_STRERROR_R_MSG;
  2002           strerror_r(errno, errmsg, MOONBR_MAXSTRERRORLEN);  /* use thread-safe call in case child created threads */
  2003           luaL_error(L, "Could not resolve host: %s: %s", gai_strerror(errcode), errmsg);
  2004         } else {
  2005           luaL_error(L, "Could not resolve host: %s", gai_strerror(errcode));
  2006         }
  2007       }
  2008       for (addrinfo=res; addrinfo; addrinfo=addrinfo->ai_next) {
  2009         if (addrinfo->ai_family == AF_INET6) goto moonbr_listen_init_pool_found;
  2010       }
  2011       for (addrinfo=res; addrinfo; addrinfo=addrinfo->ai_next) {
  2012         if (addrinfo->ai_family == AF_INET) goto moonbr_listen_init_pool_found;
  2013       }
  2014       addrinfo = res;
  2015       moonbr_listen_init_pool_found:
  2016       if (addrinfo->ai_addrlen > sizeof(listener->type_specific.socket.addr)) {
  2017         moonbr_log(LOG_CRIT, "Size of ai_addrlen is unexpectedly big (should not happen)");
  2018         moonbr_terminate_error();
  2019       }
  2020       memcpy(&listener->type_specific.socket.addr, addrinfo->ai_addr, addrinfo->ai_addrlen);
  2021       listener->type_specific.socket.addrlen = addrinfo->ai_addrlen;
  2022       switch (addrinfo->ai_family) {
  2023       case AF_INET6:
  2024         ip = inet_ntop(
  2025           addrinfo->ai_family,
  2026           &((struct sockaddr_in6 *)addrinfo->ai_addr)->sin6_addr,
  2027           listener->proto_specific.tcp.ip,
  2028           INET6_ADDRSTRLEN
  2029         );
  2030         if (!ip) {
  2031           moonbr_log(LOG_CRIT, "System error in inet_ntop call: %s", strerror(errno));
  2032           moonbr_terminate_error();
  2033         }
  2034         listener->proto_specific.tcp.port = ntohs(((struct sockaddr_in6 *)addrinfo->ai_addr)->sin6_port);
  2035         break;
  2036       case AF_INET:
  2037         ip = inet_ntop(
  2038           addrinfo->ai_family,
  2039           &((struct sockaddr_in *)addrinfo->ai_addr)->sin_addr,
  2040           listener->proto_specific.tcp.ip,
  2041           INET6_ADDRSTRLEN
  2042         );
  2043         if (!ip) {
  2044           moonbr_log(LOG_CRIT, "System error in inet_ntop call: %s", strerror(errno));
  2045           moonbr_terminate_error();
  2046         }
  2047         listener->proto_specific.tcp.port = ntohs(((struct sockaddr_in *)addrinfo->ai_addr)->sin_port);
  2048         break;
  2049       default:
  2050         strcpy(listener->proto_specific.tcp.ip, "unknown");
  2051         listener->proto_specific.tcp.port = 0;
  2052       }
  2053       listener->proto = MOONBR_PROTO_TCP;
  2054     } else if (proto) {
  2055       luaL_error(L, "Unknown protocol \"%s\"", proto);
  2056     } else {
  2057       luaL_error(L, "No valid protocol specified; use listen{{proto=..., ...}, ...}");
  2058     }
  2059   }
  2060   lua_settop(L, 2);
  2061   if (dynamic) {
  2062     moonbr_listen_init_pool_forkoption("pre_fork", pre_fork, 1);
  2063     moonbr_listen_init_pool_forkoption("min_fork", min_fork, pool->pre_fork > 2 ? pool->pre_fork : 2);
  2064     moonbr_listen_init_pool_forkoption("max_fork", max_fork, pool->min_fork > 16 ? pool->min_fork : 16);
  2065     if (!moonbr_listen_init_pool_timeoption("fork_delay", fork_delay, 0, 250000)) {
  2066       luaL_error(L, "Option \"fork_delay\" is expected to be a non-negative number");
  2067     }
  2068     if (!moonbr_listen_init_pool_timeoption("fork_error_delay", fork_error_delay, 2, 0)) {
  2069       luaL_error(L, "Option \"fork_error_delay\" is expected to be a non-negative number");
  2070     }
  2071     if (!moonbr_listen_init_pool_timeoption("exit_delay", exit_delay, 60, 0)) {
  2072       luaL_error(L, "Option \"exit_delay\" is expected to be a non-negative number");
  2073     }
  2074     if (timercmp(&pool->fork_error_delay, &pool->fork_delay, <)) {
  2075       pool->fork_error_delay = pool->fork_delay;
  2076     }
  2077     if (!moonbr_listen_init_pool_timeoption("idle_timeout", idle_timeout, 0, 0)) {
  2078       luaL_error(L, "Option \"idle_timeout\" is expected to be a non-negative number");
  2079     }
  2080   } else {
  2081     pool->pre_fork = 0;
  2082     pool->min_fork = pool->listener_count;
  2083     pool->max_fork = pool->listener_count;
  2084   }
  2085   lua_getfield(L, 2, "memory_limit");
  2086   if (!lua_isnil(L, -1)) {
  2087     int isnum;
  2088     lua_Number n;
  2089     n = lua_tonumberx(L, -1, &isnum);
  2090     if (n < 0 || !isnum) {
  2091       luaL_error(L, "Option \"memory_limit\" is expected to be a non-negative number");
  2092     }
  2093     pool->memory_limit = n;
  2094   }
  2095   lua_settop(L, 2);
  2096   lua_getfield(L, 2, "prepare");
  2097   if (!lua_isnil(L, -1) && !lua_isfunction(L, -1)) {
  2098     luaL_error(L, "Option \"prepare\" must be nil or a function");
  2099   }
  2100   lua_rawsetp(L, LUA_REGISTRYINDEX, moonbr_luakey_prepare_func(pool));
  2101   lua_getfield(L, 2, "connect");
  2102   if (!lua_isfunction(L, -1)) {
  2103     luaL_error(L, "Option \"connect\" must be a function; use listen{{...}, {...}, connect=function(socket) ... end, ...}");
  2104   }
  2105   lua_rawsetp(L, LUA_REGISTRYINDEX, moonbr_luakey_connect_func(pool));
  2106   lua_getfield(L, 2, "finish");
  2107   if (!lua_isnil(L, -1) && !lua_isfunction(L, -1)) {
  2108     luaL_error(L, "Option \"finish\" must be nil or a function");
  2109   }
  2110   lua_rawsetp(L, LUA_REGISTRYINDEX, moonbr_luakey_finish_func(pool));
  2111   return 0;
  2112 }
  2114 static int moonbr_listen(lua_State *L) {
  2115   struct moonbr_pool *pool;
  2116   lua_Integer listener_count;
  2117   if (moonbr_booted) luaL_error(L, "Moonbridge bootup is already complete");
  2118   luaL_checktype(L, 1, LUA_TTABLE);
  2119   listener_count = luaL_len(L, 1);
  2120   if (!listener_count) luaL_error(L, "No listen ports specified; use listen{{proto=..., port=...},...}");
  2121   if (listener_count > 100) luaL_error(L, "Too many listeners");
  2122   pool = moonbr_create_pool(listener_count);
  2123   lua_pushcfunction(L, moonbr_listen_init_pool);
  2124   lua_pushlightuserdata(L, pool);
  2125   lua_pushvalue(L, 1);
  2126   if (lua_pcall(L, 2, 0, 0)) goto moonbr_listen_error;
  2127   {
  2128     int i;
  2129     i = moonbr_start_pool(pool);
  2130     if (i >= 0) {
  2131       lua_pushfstring(L, "Could not initialize listener #%d: %s", i+1, strerror(errno));
  2132       moonbr_listen_error:
  2133       moonbr_destroy_pool(pool);
  2134       lua_pushnil(L);
  2135       lua_rawsetp(L, LUA_REGISTRYINDEX, moonbr_luakey_prepare_func(pool));
  2136       lua_pushnil(L);
  2137       lua_rawsetp(L, LUA_REGISTRYINDEX, moonbr_luakey_connect_func(pool));
  2138       lua_pushnil(L);
  2139       lua_rawsetp(L, LUA_REGISTRYINDEX, moonbr_luakey_finish_func(pool));
  2140       lua_error(L);
  2141     }
  2142   }
  2143   return 0;
  2144 }
  2147 /*** Function to modify Lua's library path and/or cpath ***/
  2149 #if defined(MOONBR_LUA_PATH) || defined(MOONBR_LUA_CPATH)
  2150 static void moonbr_modify_path(lua_State *L, char *key, char *value) {
  2151   int stackbase;
  2152   stackbase = lua_gettop(L);
  2153   lua_getglobal(L, "package");
  2154   lua_getfield(L, stackbase+1, key);
  2155   {
  2156     const char *current_str;
  2157     size_t current_strlen;
  2158     luaL_Buffer buf;
  2159     current_str = lua_tolstring(L, stackbase+2, ¤t_strlen);
  2160     luaL_buffinit(L, &buf);
  2161     if (current_str) {
  2162       lua_pushvalue(L, stackbase+2);
  2163       luaL_addvalue(&buf);
  2164       if (current_strlen && current_str[current_strlen-1] != ';') {
  2165         luaL_addchar(&buf, ';');
  2166       }
  2167     }
  2168     luaL_addstring(&buf, value);
  2169     luaL_pushresult(&buf);
  2170   }
  2171   lua_setfield(L, stackbase+1, key);
  2172   lua_settop(L, stackbase);
  2173 }
  2174 #endif
  2177 /*** Main function and command line invokation ***/
  2179 static void moonbr_usage(int err, const char *cmd) {
  2180   FILE *out;
  2181   out = err ? stderr : stdout;
  2182   if (!cmd) cmd = "moonbridge";
  2183   fprintf(out, "Get this help message: %s {-h|--help}\n", cmd);
  2184   fprintf(out, "Usage: %s \\\n", cmd);
  2185   fprintf(out, "           [-b|--background] \\\n");
  2186   fprintf(out, "           [-d|--debug] \\\n");
  2187   fprintf(out, "           [-f|--logfacility {DAEMON|USER|0|1|...|7}] \\\n");
  2188   fprintf(out, "           [-i|--logident <syslog ident> \\\n");
  2189   fprintf(out, "           [-l|--logfile <logfile>] \\\n");
  2190   fprintf(out, "           [-p|--pidfile <pidfile>] \\\n");
  2191   fprintf(out, "           [-s|--stats] \\\n");
  2192   fprintf(out, "           -- <Lua script> [<cmdline options for Lua script>]\n");
  2193   exit(err);
  2194 }
  2196 #define moonbr_usage_error() moonbr_usage(MOONBR_EXITCODE_CMDLINEERROR, argc ? argv[0] : NULL)
  2198 int main(int argc, char **argv) {
  2199   {
  2200     int daemonize = 0;
  2201     int log_facility = LOG_USER;
  2202     const char *log_ident = "moonbridge";
  2203     const char *log_filename = NULL;
  2204     const char *pid_filename = NULL;
  2205     int option;
  2206     struct option longopts[] = {
  2207       { "background",  no_argument,       NULL, 'b' },
  2208       { "debug",       no_argument,       NULL, 'd' },
  2209       { "logfacility", required_argument, NULL, 'f' },
  2210       { "help",        no_argument,       NULL, 'h' },
  2211       { "logident",    required_argument, NULL, 'i' },
  2212       { "logfile",     required_argument, NULL, 'l' },
  2213       { "pidfile",     required_argument, NULL, 'p' },
  2214       { "stats",       no_argument,       NULL, 's' },
  2215       { NULL,          0,                 NULL, 0   }
  2216     };
  2217     while ((option = getopt_long(argc, argv, "bdf:hi:l:p:s", longopts, NULL)) != -1) {
  2218       switch (option) {
  2219       case 'b':
  2220         daemonize = 1;
  2221         break;
  2222       case 'd':
  2223         moonbr_debug = 1;
  2224         moonbr_stat = 1;
  2225         break;
  2226       case 'f':
  2227         if (!strcmp(optarg, "DAEMON")) {
  2228           log_facility = LOG_DAEMON;
  2229         } else if (!strcmp(optarg, "USER")) {
  2230           log_facility = LOG_USER;
  2231         } else if (!strcmp(optarg, "0")) {
  2232           log_facility = LOG_LOCAL0;
  2233         } else if (!strcmp(optarg, "1")) {
  2234           log_facility = LOG_LOCAL1;
  2235         } else if (!strcmp(optarg, "2")) {
  2236           log_facility = LOG_LOCAL2;
  2237         } else if (!strcmp(optarg, "3")) {
  2238           log_facility = LOG_LOCAL3;
  2239         } else if (!strcmp(optarg, "4")) {
  2240           log_facility = LOG_LOCAL4;
  2241         } else if (!strcmp(optarg, "5")) {
  2242           log_facility = LOG_LOCAL5;
  2243         } else if (!strcmp(optarg, "6")) {
  2244           log_facility = LOG_LOCAL6;
  2245         } else if (!strcmp(optarg, "7")) {
  2246           log_facility = LOG_LOCAL7;
  2247         } else {
  2248           moonbr_usage_error();
  2249         }
  2250         moonbr_use_syslog = 1;
  2251         break;
  2252       case 'h':
  2253         moonbr_usage(MOONBR_EXITCODE_GRACEFUL, argv[0]);
  2254         break;
  2255       case 'i':
  2256         log_ident = optarg;
  2257         moonbr_use_syslog = 1;
  2258         break;
  2259       case 'l':
  2260         log_filename = optarg;
  2261         break;
  2262       case 'p':
  2263         pid_filename = optarg;
  2264         break;
  2265       case 's':
  2266         moonbr_stat = 1;
  2267         break;
  2268       default:
  2269         moonbr_usage_error();
  2270       }
  2271     }
  2272     if (argc - optind < 1) moonbr_usage_error();
  2273     if (pid_filename) {
  2274       pid_t otherpid;
  2275       while ((moonbr_pidfh = pidfile_open(pid_filename, 0644, &otherpid)) == NULL) {
  2276         if (errno == EEXIST) {
  2277           if (otherpid == -1) {
  2278             fprintf(stderr, "PID file \"%s\" is already locked\n", pid_filename);
  2279           } else {
  2280             fprintf(stderr, "PID file \"%s\" is already locked by process with PID: %i\n", pid_filename, (int)otherpid);
  2281           }
  2282           exit(MOONBR_EXITCODE_ALREADYRUNNING);
  2283         } else if (errno != EINTR) {
  2284           fprintf(stderr, "Could not write PID file \"%s\": %s\n", pid_filename, strerror(errno));
  2285           exit(MOONBR_EXITCODE_STARTUPERROR);
  2286         }
  2287       }
  2288     }
  2289     if (log_filename) {
  2290       int logfd;
  2291       while (
  2292         ( logfd = flopen(
  2293             log_filename,
  2294             O_WRONLY|O_NONBLOCK|O_CREAT|O_APPEND|O_CLOEXEC,
  2295             0640
  2296           )
  2297         ) < 0
  2298       ) {
  2299         if (errno == EWOULDBLOCK) {
  2300           fprintf(stderr, "Logfile \"%s\" is locked\n", log_filename);
  2301           exit(MOONBR_EXITCODE_ALREADYRUNNING);
  2302         } else if (errno != EINTR) {
  2303           fprintf(stderr, "Could not open logfile \"%s\": %s\n", log_filename, strerror(errno));
  2304           exit(MOONBR_EXITCODE_STARTUPERROR);
  2305         }
  2306       }
  2307       moonbr_logfile = fdopen(logfd, "a");
  2308       if (!moonbr_logfile) {
  2309         fprintf(stderr, "Could not open write stream to logfile \"%s\": %s\n", log_filename, strerror(errno));
  2310         exit(MOONBR_EXITCODE_STARTUPERROR);
  2311       }
  2312     }
  2313     if (daemonize == 0 && !moonbr_logfile) moonbr_logfile = stderr;
  2314     if (moonbr_logfile) setlinebuf(moonbr_logfile);
  2315     else moonbr_use_syslog = 1;
  2316     if (moonbr_use_syslog) openlog(log_ident, LOG_NDELAY | LOG_PID, log_facility);
  2317     if (daemonize) {
  2318       if (daemon(1, 0)) {
  2319         moonbr_log(LOG_ERR, "Could not daemonize moonbridge process");
  2320         moonbr_terminate_error();
  2321       }
  2322     }
  2323   }
  2324   moonbr_log(LOG_NOTICE, "Starting moonbridge server");
  2325   if (moonbr_pidfh && pidfile_write(moonbr_pidfh)) {
  2326     moonbr_log(LOG_ERR, "Could not write pidfile (after locking)");
  2327   }
  2328   {
  2329     lua_State *L;
  2330     L = lua_newstate(moonbr_alloc, NULL);
  2331     if (!L) {
  2332       moonbr_log(LOG_CRIT, "Could not initialize Lua state");
  2333       moonbr_terminate_error();
  2334     }
  2335     lua_atpanic(L, moonbr_lua_panic);
  2336     lua_pushliteral(L, MOONBR_VERSION_STRING);
  2337     lua_setglobal(L, "_MOONBRIDGE_VERSION");
  2338     luaL_openlibs(L);
  2339     luaL_requiref(L, "moonbridge_io", luaopen_moonbridge_io, 1);
  2340     lua_pop(L, 1);
  2341 #ifdef MOONBR_LUA_PATH
  2342     moonbr_modify_path(L, "path", MOONBR_LUA_PATH);
  2343 #endif
  2344 #ifdef MOONBR_LUA_CPATH
  2345     moonbr_modify_path(L, "cpath", MOONBR_LUA_CPATH);
  2346 #endif
  2347     lua_pushcfunction(L, moonbr_timeout);
  2348     lua_setglobal(L, "timeout");
  2349     lua_pushcfunction(L, moonbr_listen);
  2350     lua_setglobal(L, "listen");
  2351     lua_pushcfunction(L, moonbr_addtraceback);  /* on stack position 1 */
  2352     moonbr_log(LOG_INFO, "Loading \"%s\"", argv[optind]);
  2353     if (luaL_loadfile(L, argv[optind])) {
  2354       moonbr_log(LOG_ERR, "Error while loading \"%s\": %s", argv[optind], lua_tostring(L, -1));
  2355       moonbr_terminate_error();
  2356     }
  2357     { int i; for (i=optind+1; i<argc; i++) lua_pushstring(L, argv[i]); }
  2358     if (lua_pcall(L, argc-(optind+1), 0, 1)) {
  2359       moonbr_log(LOG_ERR, "Error while executing \"%s\": %s", argv[optind], lua_tostring(L, -1));
  2360       moonbr_terminate_error();
  2361     }
  2362     if (!moonbr_first_pool) {
  2363       moonbr_log(LOG_WARNING, "No listener initialized.");
  2364       moonbr_terminate_error();
  2365     }
  2366     lua_getglobal(L, "listen");
  2367     lua_pushcfunction(L, moonbr_listen);
  2368     if (lua_compare(L, -2, -1, LUA_OPEQ)) {
  2369       lua_pushnil(L);
  2370       lua_setglobal(L, "listen");
  2371     }
  2372     lua_settop(L, 1);
  2373     lua_gc(L, LUA_GCCOLLECT, 0);  /* collect garbage before forking later */
  2374     moonbr_run(L);
  2375   }
  2376   return 0;
  2377 }
