moonbridge
view moonbridge.c @ 237:1fd00eed96ee
Work on optional libtls integration for moonbridge_io (tls_config stub)
| author | jbe | 
|---|---|
| date | Sat Aug 20 21:54:15 2016 +0200 (2016-08-20) | 
| parents | 6d5f241588a0 | 
| children | 30a04a6a45db | 
 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_MAIN 1
   123 #define MOONBR_PROTO_INTERVAL 2
   124 #define MOONBR_PROTO_LOCAL 3
   125 #define MOONBR_PROTO_TCP 4
   127 /* Data structure for a pool's listener that can accept incoming connections */
   128 struct moonbr_listener {
   129   struct moonbr_pool *pool;
   130   struct moonbr_listener *prev_listener;  /* previous idle or(!) connected listener */
   131   struct moonbr_listener *next_listener;  /* next idle or(!) connected listener */
   132   int proto;
   133   union {
   134     struct {
   135       char *name;  /* name of interval passed to 'connect' function as 'interval' field in table */
   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   if (getpid() == moonbr_masterpid) {
   299     /* master process */
   300     switch (sig) {
   301     case SIGHUP:
   302     case SIGINT:
   303       /* fast shutdown requested */
   304       moonbr_cond_interrupt = 1;
   305       break;
   306     case SIGTERM:
   307       /* clean shutdown requested */
   308       moonbr_cond_terminate = 1;
   309       break;
   310     case SIGCHLD:
   311       /* child process terminated */
   312       moonbr_cond_child = 1;
   313       break;
   314     }
   315     if (moonbr_cond_poll) {
   316       /* avoid race condition if signal handler is invoked right before poll() */
   317       char buf[1] = {0};
   318       write(moonbr_poll_signalfd_write, buf, 1);
   319     }
   320   } else {
   321     /* child process forwards certain signals to parent process */
   322     switch (sig) {
   323     case SIGHUP:
   324     case SIGINT:
   325     case SIGTERM:
   326       kill(moonbr_masterpid, sig);
   327     }
   328   }
   329 }
   331 /* Initialize signal handling */
   332 static void moonbr_signal_init(){
   333   moonbr_masterpid = getpid();
   334   signal(SIGHUP, moonbr_signal);
   335   signal(SIGINT, moonbr_signal);
   336   signal(SIGTERM, moonbr_signal);
   337   signal(SIGCHLD, moonbr_signal);
   338   /* signal(SIGUSR1, moonbr_signal); */  /* might be used to terminate children gracefully */
   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_MAIN:
   516         /* nothing to do here: starting main thread is performed in moonbr_run() function */
   517         moonbr_log(LOG_INFO, "Adding main thread");
   518         break;
   519       case MOONBR_PROTO_INTERVAL:
   520         /* nothing to do here: starting intervals is performed in moonbr_run() function */
   521         if (!listener->type_specific.interval.name) {
   522           moonbr_log(LOG_INFO, "Adding unnamed interval listener");
   523         } else {
   524           moonbr_log(LOG_INFO, "Adding interval listener \"%s\"", listener->type_specific.interval.name);
   525         }
   526         break;
   527       case MOONBR_PROTO_LOCAL:
   528         moonbr_log(LOG_INFO, "Adding local socket listener for path \"%s\"", listener->type_specific.socket.addr.addr_un.sun_path);
   529         listener->listenfd = socket(PF_LOCAL, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
   530         if (listener->listenfd == -1) goto moonbr_start_pool_error;
   531         if (!unlink(listener->type_specific.socket.addr.addr_un.sun_path)) {
   532           moonbr_log(LOG_WARNING, "Unlinked named socket \"%s\" prior to listening", listener->type_specific.socket.addr.addr_un.sun_path);
   533         } else {
   534           if (errno != ENOENT) {
   535             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));
   536           }
   537         }
   538         if (
   539           bind(listener->listenfd, &listener->type_specific.socket.addr.addr_abstract, listener->type_specific.socket.addrlen)
   540         ) goto moonbr_start_pool_error;
   541         if (listen(listener->listenfd, MOONBR_LISTEN_BACKLOG)) goto moonbr_start_pool_error;
   542         break;
   543       case MOONBR_PROTO_TCP:
   544         moonbr_log(LOG_INFO, "Adding TCP listener on interface \"%s\", port %i", listener->proto_specific.tcp.ip, listener->proto_specific.tcp.port);
   545         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 */
   546         if (listener->listenfd == -1) goto moonbr_start_pool_error;
   547         {
   548           /* avoid "Address already in use" error when restarting service */
   549           static const int reuseval = 1;
   550           if (setsockopt(
   551             listener->listenfd, SOL_SOCKET, SO_REUSEADDR, &reuseval, sizeof(reuseval)
   552           )) goto moonbr_start_pool_error;
   553         }
   554         {
   555           /* default to send TCP RST when process terminates unexpectedly */
   556           static const struct linger lingerval = {
   557             .l_onoff = 1,
   558             .l_linger = 0
   559           };
   560           if (setsockopt(
   561             listener->listenfd, SOL_SOCKET, SO_LINGER, &lingerval, sizeof(lingerval)
   562           )) goto moonbr_start_pool_error;
   563         }
   564         if (
   565           bind(listener->listenfd, &listener->type_specific.socket.addr.addr_abstract, listener->type_specific.socket.addrlen)
   566         ) goto moonbr_start_pool_error;
   567         if (listen(listener->listenfd, MOONBR_LISTEN_BACKLOG)) goto moonbr_start_pool_error;
   568         break;
   569       default:
   570         moonbr_log(LOG_CRIT, "Internal error (should not happen): Unexpected value in listener.proto field");
   571         moonbr_terminate_error();
   572       }
   573     }
   574     goto moonbr_start_pool_ok;
   575     moonbr_start_pool_error:
   576     {
   577       int j = i;
   578       int errno2 = errno;
   579       for (; i>=0; i--) {
   580         struct moonbr_listener *listener = &pool->listener[i];
   581         if (listener->listenfd != -1) close(listener->listenfd);
   582       }
   583       errno = errno2;
   584       return j;
   585     }
   586   }
   587   moonbr_start_pool_ok:
   588   pool->poolnum = ++moonbr_pool_count;
   589   moonbr_log(LOG_INFO, "Pool #%i created", pool->poolnum);
   590   if (moonbr_last_pool) moonbr_last_pool->next_pool = pool;
   591   else moonbr_first_pool = pool;
   592   moonbr_last_pool = pool;
   593   return -1;
   594 }
   597 /*** Function to send data and a file descriptor to child process */
   599 /* Sends control message of one bye plus optional file descriptor plus optional pointer to child process */
   600 static void moonbr_send_control_message(struct moonbr_worker *worker, char status, int fd, void *ptr) {
   601   {
   602     struct iovec iovector = { .iov_base = &status, .iov_len = 1 };      /* carrying status byte */
   603     char control_message_buffer[CMSG_SPACE(sizeof(int))] = {0, };       /* used to transfer file descriptor */
   604     struct msghdr message = { .msg_iov = &iovector, .msg_iovlen = 1 };  /* data structure passed to sendmsg() call */
   605     if (moonbr_debug) {
   606       if (fd == -1) {
   607         moonbr_log(LOG_DEBUG, "Sending control message \"%c\" to child process in pool #%i (PID %i)", (int)status, worker->pool->poolnum, (int)worker->pid);
   608       } else {
   609         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);
   610       }
   611     }
   612     if (fd != -1) {
   613       /* attach control message with file descriptor */
   614       message.msg_control = control_message_buffer;
   615       message.msg_controllen = CMSG_SPACE(sizeof(int));
   616       {
   617         struct cmsghdr *control_message = CMSG_FIRSTHDR(&message);
   618         control_message->cmsg_level = SOL_SOCKET;
   619         control_message->cmsg_type = SCM_RIGHTS;
   620         control_message->cmsg_len = CMSG_LEN(sizeof(int));
   621         memcpy(CMSG_DATA(control_message), &fd, sizeof(int));
   622       }
   623     }
   624     while (sendmsg(worker->controlfd, &message, MSG_NOSIGNAL) < 0) {
   625       if (errno == EPIPE) {
   626         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));
   627         return;  /* do not close socket; socket is closed when reading from it */
   628       }
   629       if (errno != EINTR) {
   630         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));
   631         moonbr_terminate_error();
   632       }
   633     }
   634   }
   635   if (ptr) {
   636     char buf[sizeof(void *)];
   637     char *pos = buf;
   638     int len = sizeof(void *);
   639     ssize_t written;
   640     if (moonbr_debug) {
   641       moonbr_log(LOG_DEBUG, "Sending memory pointer to child process in pool #%i (PID %i)", (int)status, worker->pool->poolnum, (int)worker->pid);
   642     }
   643     memcpy(buf, &ptr, sizeof(void *));
   644     while (len) {
   645       written = send(worker->controlfd, pos, len, MSG_NOSIGNAL);
   646       if (written > 0) {
   647         pos += written;
   648         len -= written;
   649       } else if (errno == EPIPE) {
   650         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));
   651         return;  /* do not close socket; socket is closed when reading from it */
   652       } else if (errno != EINTR) {
   653         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));
   654         moonbr_terminate_error();
   655       }
   656     }
   657   }
   658 }
   661 /*** Functions running in child process ***/
   663 /* Logs an error in child process */
   664 static void moonbr_child_log(const char *message) {
   665   fprintf(stderr, "%s\n", message);
   666 }
   668 /* Logs a fatal error in child process and terminates process with error status */
   669 static void moonbr_child_log_fatal(const char *message) {
   670   moonbr_child_log(message);
   671   exit(1);
   672 }
   674 /* Logs an error in child process while appending error string for global errno variable */
   675 static void moonbr_child_log_errno(const char *message) {
   676   char errmsg[MOONBR_MAXSTRERRORLEN] = MOONBR_STRERROR_R_MSG;
   677   strerror_r(errno, errmsg, MOONBR_MAXSTRERRORLEN);  /* use thread-safe call in case child created threads */
   678   fprintf(stderr, "%s: %s\n", message, errmsg);
   679 }
   681 /* Logs a fatal error in child process while appending error string for errno and terminating process */
   682 static void moonbr_child_log_errno_fatal(const char *message) {
   683   moonbr_child_log_errno(message);
   684   exit(1);
   685 }
   687 /* Receives a control message consisting of one character plus an optional file descriptor from parent process */
   688 static void moonbr_child_receive_control_message(int socketfd, char *status, int *fd) {
   689   struct iovec iovector = { .iov_base = status, .iov_len = 1 };  /* reference to status byte variable */
   690   char control_message_buffer[CMSG_SPACE(sizeof(int))] = {0, };  /* used to receive file descriptor */
   691   struct msghdr message = {  /* data structure passed to recvmsg() call */
   692     .msg_iov = &iovector,
   693     .msg_iovlen = 1,
   694     .msg_control = control_message_buffer,
   695     .msg_controllen = CMSG_SPACE(sizeof(int))
   696   };
   697   {
   698     int received;
   699     while ((received = recvmsg(socketfd, &message, MSG_CMSG_CLOEXEC)) < 0) {
   700       if (errno != EINTR) {
   701         moonbr_child_log_errno_fatal("Error while trying to receive connection socket from parent process");
   702       }
   703     }
   704     if (!received) {
   705       moonbr_child_log_fatal("Unexpected EOF while trying to receive connection socket from parent process");
   706     }
   707   }
   708   {
   709     struct cmsghdr *control_message = CMSG_FIRSTHDR(&message);
   710     if (control_message) {
   711       if (control_message->cmsg_level != SOL_SOCKET) {
   712         moonbr_child_log_fatal("Received control message with cmsg_level not equal to SOL_SOCKET");
   713       }
   714       if (control_message->cmsg_type != SCM_RIGHTS) {
   715         moonbr_child_log_fatal("Received control message with cmsg_type not equal to SCM_RIGHTS");
   716       }
   717       memcpy(fd, CMSG_DATA(control_message), sizeof(int));
   718     } else {
   719       *fd = -1;
   720     }
   721   }
   722 }
   724 /* Receives a pointer from parent process */
   725 static void *moonbr_child_receive_pointer(int socketfd) {
   726   char buf[sizeof(void *)];
   727   char *pos = buf;
   728   int len = sizeof(void *);
   729   ssize_t bytes_read;
   730   while (len) {
   731     bytes_read = recv(socketfd, pos, len, 0);
   732     if (bytes_read > 0) {
   733       pos += bytes_read;
   734       len -= bytes_read;
   735     } else if (!bytes_read) {
   736       moonbr_child_log_fatal("Unexpected EOF while trying to receive memory pointer from parent process");
   737     } else if (errno != EINTR) {
   738       moonbr_child_log_errno_fatal("Error while trying to receive memory pointer from parent process");
   739     }
   740   }
   741   {
   742     void *ptr;  /* avoid breaking strict-aliasing rules */
   743     memcpy(&ptr, buf, sizeof(void *));
   744     return ptr;
   745   }
   746 }
   748 /* Main function of child process to be called after fork() and file descriptor rearrangement */
   749 void moonbr_child_run(struct moonbr_pool *pool, lua_State *L) {
   750   char controlmsg;
   751   int fd;
   752   struct itimerval notimer = { { 0, }, { 0, } };
   753   lua_rawgetp(L, LUA_REGISTRYINDEX, moonbr_luakey_prepare_func(pool));
   754   if (lua_isnil(L, -1)) lua_pop(L, 1);
   755   else if (lua_pcall(L, 0, 0, 1)) {
   756     fprintf(stderr, "Error in \"prepare\" function: %s\n", lua_tostring(L, -1));
   757     exit(1);
   758   }
   759   while (1) {
   760     struct moonbr_listener *listener;
   761     if (setitimer(ITIMER_REAL, ¬imer, NULL)) {
   762       moonbr_child_log_errno_fatal("Could not reset ITIMER_REAL via setitimer()");
   763     }
   764     controlmsg = MOONBR_STATUS_IDLE;
   765     if (write(MOONBR_FD_CONTROL, &controlmsg, 1) <= 0) {
   766       moonbr_child_log_errno_fatal("Error while sending ready message to parent process");
   767     }
   768     moonbr_child_receive_control_message(MOONBR_FD_CONTROL, &controlmsg, &fd);
   769     if (!(
   770       (controlmsg == MOONBR_COMMAND_TERMINATE && fd == -1) ||
   771       (controlmsg == MOONBR_COMMAND_CONNECT)
   772     )) {
   773       moonbr_child_log_fatal("Received illegal control message from parent process");
   774     }
   775     if (controlmsg == MOONBR_COMMAND_TERMINATE) break;
   776     listener = moonbr_child_receive_pointer(MOONBR_FD_CONTROL);
   777     if (
   778       listener->proto != MOONBR_PROTO_LOCAL &&
   779       listener->proto != MOONBR_PROTO_TCP &&
   780       fd >= 0
   781     ) {
   782       moonbr_child_log_fatal("Received unexpected file descriptor from parent process");
   783     } else if (
   784       listener->proto != MOONBR_PROTO_MAIN &&
   785       listener->proto != MOONBR_PROTO_INTERVAL &&
   786       fd < 0
   787     ) {
   788       moonbr_child_log_fatal("Missing file descriptor from parent process");
   789     }
   790     if (fd >= 0) moonbr_io_pushhandle(L, fd);
   791     lua_rawgetp(L, LUA_REGISTRYINDEX, moonbr_luakey_connect_func(pool));
   792     if (fd < 0) {
   793       lua_newtable(L);
   794       if (listener->proto == MOONBR_PROTO_MAIN) {
   795         lua_pushboolean(L, 1);
   796         lua_setfield(L, -2, "main");
   797       } else if (listener->proto == MOONBR_PROTO_INTERVAL) {
   798         lua_pushstring(L,
   799           listener->type_specific.interval.name ?
   800           listener->type_specific.interval.name : ""
   801         );
   802         lua_setfield(L, -2, "interval");
   803       }
   804     } else {
   805       lua_pushvalue(L, -2);
   806     }
   807     if (lua_pcall(L, 1, 1, 1)) {
   808       fprintf(stderr, "Error in \"connect\" function: %s\n", lua_tostring(L, -1));
   809       exit(1);
   810     }
   811     if (fd >= 0) moonbr_io_closehandle(L, -2, 0);  /* attemt clean close */
   812     if (lua_type(L, -1) != LUA_TBOOLEAN || !lua_toboolean(L, -1)) break;
   813 #ifdef MOONBR_LUA_PANIC_BUG_WORKAROUND
   814     lua_settop(L, 2);
   815 #else
   816     lua_settop(L, 1);
   817 #endif
   818   }
   819   controlmsg = MOONBR_STATUS_GOODBYE;
   820   if (write(MOONBR_FD_CONTROL, &controlmsg, 1) <= 0) {
   821     moonbr_child_log_errno_fatal("Error while sending goodbye message to parent process");
   822   }
   823   if (close(MOONBR_FD_CONTROL) && errno != EINTR) {
   824     moonbr_child_log_errno("Error while closing control socket");
   825   }
   826   lua_rawgetp(L, LUA_REGISTRYINDEX, moonbr_luakey_finish_func(pool));
   827   if (lua_isnil(L, -1)) lua_pop(L, 1);
   828   else if (lua_pcall(L, 0, 0, 1)) {
   829     fprintf(stderr, "Error in \"finish\" function: %s\n", lua_tostring(L, -1));
   830     exit(1);
   831   }
   832   lua_close(L);
   833   exit(0);
   834 }
   837 /*** Functions to spawn child process ***/
   839 /* Helper function to send an error message to a file descriptor (not needing a file stream) */
   840 static void moonbr_child_emergency_print(int fd, char *message) {
   841   size_t len = strlen(message);
   842   ssize_t written;
   843   while (len) {
   844     written = write(fd, message, len);
   845     if (written > 0) {
   846       message += written;
   847       len -= written;
   848     } else {
   849       if (written != -1 || errno != EINTR) break;
   850     }
   851   }
   852 }
   854 /* Helper function to send an error message plus a text for errno to a file descriptor and terminate the process */
   855 static void moonbr_child_emergency_error(int fd, char *message) {
   856   int errno2 = errno;
   857   moonbr_child_emergency_print(fd, message);
   858   moonbr_child_emergency_print(fd, ": ");
   859   moonbr_child_emergency_print(fd, strerror(errno2));
   860   moonbr_child_emergency_print(fd, "\n");
   861   exit(1);
   862 }
   864 /* Creates a child process and (in case of success) registers it in the 'struct moonbr_pool' structure */
   865 static int moonbr_create_worker(struct moonbr_pool *pool, lua_State *L) {
   866   struct moonbr_worker *worker;
   867   worker = calloc(1, sizeof(struct moonbr_worker));
   868   if (!worker) {
   869     moonbr_log(LOG_CRIT, "Memory allocation error");
   870     return -1;
   871   }
   872   worker->pool = pool;
   873   {
   874     int controlfds[2];
   875     int errorfds[2];
   876     if (socketpair(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0, controlfds)) {
   877       moonbr_log(LOG_ERR, "Could not create control socket pair for communcation with child process: %s", strerror(errno));
   878       free(worker);
   879       return -1;
   880     }
   881     if (socketpair(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0, errorfds)) {
   882       moonbr_log(LOG_ERR, "Could not create socket pair to redirect stderr of child process: %s", strerror(errno));
   883       close(controlfds[0]);
   884       close(controlfds[1]);
   885       free(worker);
   886       return -1;
   887     }
   888     if (moonbr_logfile && fflush(moonbr_logfile)) {
   889       moonbr_log(LOG_CRIT, "Could not flush log file prior to forking: %s", strerror(errno));
   890       moonbr_terminate_error();
   891     }
   892     worker->pid = fork();
   893     if (worker->pid == -1) {
   894       moonbr_log(LOG_ERR, "Could not fork: %s", strerror(errno));
   895       close(controlfds[0]);
   896       close(controlfds[1]);
   897       close(errorfds[0]);
   898       close(errorfds[1]);
   899       free(worker);
   900       return -1;
   901     } else if (!worker->pid) {
   902       moonbr_pstate = MOONBR_PSTATE_FORKED;
   903 #ifdef MOONBR_LUA_PANIC_BUG_WORKAROUND
   904       lua_pushliteral(L, "Failed to pass error message due to bug in Lua panic handler (hint: not enough memory?)");
   905 #endif
   906       moonbr_memory_limit = pool->memory_limit;
   907       if (moonbr_pidfh && pidfile_close(moonbr_pidfh)) {
   908         moonbr_child_emergency_error(errorfds[1], "Could not close PID file in forked child process");
   909       }
   910       if (moonbr_logfile && moonbr_logfile != stderr && fclose(moonbr_logfile)) {
   911         moonbr_child_emergency_error(errorfds[1], "Could not close log file in forked child process");
   912       }
   913       if (dup2(errorfds[1], MOONBR_FD_STDERR) == -1) {
   914         moonbr_child_emergency_error(errorfds[1], "Could not duplicate socket to stderr file descriptor");
   915       }
   916       if (dup2(controlfds[1], MOONBR_FD_CONTROL) == -1) {
   917         moonbr_child_emergency_error(errorfds[1], "Could not duplicate control socket");
   918       }
   919       closefrom(MOONBR_FD_END);
   920       moonbr_child_run(pool, L);
   921     }
   922     if (moonbr_stat) {
   923       moonbr_log(LOG_INFO, "Created new worker in pool #%i with PID %i", worker->pool->poolnum, (int)worker->pid);
   924     }
   925     worker->controlfd = controlfds[0];
   926     worker->errorfd = errorfds[0];
   927     if (close(controlfds[1]) && errno != EINTR) {
   928       moonbr_log(LOG_CRIT, "Could not close opposite end of control file descriptor after forking");
   929       moonbr_terminate_error();
   930     }
   931     if (close(errorfds[1]) && errno != EINTR) {
   932       moonbr_log(LOG_CRIT, "Could not close opposite end of control file descriptor after forking");
   933       moonbr_terminate_error();
   934     }
   935   }
   936   worker->prev_worker = pool->last_worker;
   937   if (worker->prev_worker) worker->prev_worker->next_worker = worker;
   938   else pool->first_worker = worker;
   939   pool->last_worker = worker;
   940   pool->unassigned_worker_count++;
   941   pool->total_worker_count++;
   942   pool->worker_count_stat = 1;
   943   moonbr_poll_refresh_needed = 1;
   944   return 0;  /* return zero only in case of success */
   945 }
   948 /*** Functions for queues of 'struct moonbr_listener' ***/
   950 /* Appends a 'struct moonbr_listener' to the queue of idle listeners and registers it for poll() */
   951 static void moonbr_add_idle_listener(struct moonbr_listener *listener) {
   952   listener->prev_listener = listener->pool->last_idle_listener;
   953   if (listener->prev_listener) listener->prev_listener->next_listener = listener;
   954   else listener->pool->first_idle_listener = listener;
   955   listener->pool->last_idle_listener = listener;
   956   if (listener->pollidx != -1) moonbr_poll_fds[listener->pollidx].events |= POLLIN;
   957 }
   959 /* Removes a 'struct moonbr_listener' from the queue of idle listeners and unregisters it from poll() */
   960 static void moonbr_remove_idle_listener(struct moonbr_listener *listener) {
   961   if (listener->prev_listener) listener->prev_listener->next_listener = listener->next_listener;
   962   else listener->pool->first_idle_listener = listener->next_listener;
   963   if (listener->next_listener) listener->next_listener->prev_listener = listener->prev_listener;
   964   else listener->pool->last_idle_listener = listener->prev_listener;
   965   listener->prev_listener = NULL;
   966   listener->next_listener = NULL;
   967   if (listener->pollidx != -1) moonbr_poll_fds[listener->pollidx].events &= ~POLLIN;
   968 }
   970 /* Adds a listener to the queue of connected listeners (i.e. waiting to have their incoming connection accepted) */
   971 static void moonbr_add_connected_listener(struct moonbr_listener *listener) {
   972   listener->prev_listener = listener->pool->last_connected_listener;
   973   if (listener->prev_listener) listener->prev_listener->next_listener = listener;
   974   else listener->pool->first_connected_listener = listener;
   975   listener->pool->last_connected_listener = listener;
   976 }
   978 /* Removes and returns the first connected listener in the queue */
   979 static struct moonbr_listener *moonbr_pop_connected_listener(struct moonbr_pool *pool) {
   980   struct moonbr_listener *listener = pool->first_connected_listener;
   981   listener->pool->first_connected_listener = listener->next_listener;
   982   if (listener->pool->first_connected_listener) listener->pool->first_connected_listener->prev_listener = NULL;
   983   else listener->pool->last_connected_listener = NULL;
   984   listener->next_listener = NULL;
   985   return listener;
   986 }
   989 /*** Functions to handle polling ***/
   991 /* Returns an index to a new initialized entry in moonbr_poll_fds[] */
   992 int moonbr_poll_fds_nextindex() {
   993   if (moonbr_poll_fds_count >= moonbr_poll_fds_bufsize) {
   994     if (moonbr_poll_fds_bufsize) moonbr_poll_fds_bufsize *= 2;
   995     else moonbr_poll_fds_bufsize = 1;
   996     moonbr_poll_fds = realloc(
   997       moonbr_poll_fds, moonbr_poll_fds_bufsize * sizeof(struct pollfd)
   998     );
   999     if (!moonbr_poll_fds) {
  1000       moonbr_log(LOG_CRIT, "Memory allocation error");
  1001       moonbr_terminate_error();
  1002     }
  1003   }
  1004   moonbr_poll_fds[moonbr_poll_fds_count] = (struct pollfd){0, };
  1005   return moonbr_poll_fds_count++;
  1006 }
  1008 /* Returns an index to a new initialized entry in moonbr_poll_workers[] */
  1009 int moonbr_poll_workers_nextindex() {
  1010   if (moonbr_poll_worker_count >= moonbr_poll_workers_bufsize) {
  1011     if (moonbr_poll_workers_bufsize) moonbr_poll_workers_bufsize *= 2;
  1012     else moonbr_poll_workers_bufsize = 1;
  1013     moonbr_poll_workers = realloc(
  1014       moonbr_poll_workers, moonbr_poll_workers_bufsize * sizeof(struct moonbr_poll_worker)
  1015     );
  1016     if (!moonbr_poll_workers) {
  1017       moonbr_log(LOG_CRIT, "Memory allocation error");
  1018       moonbr_terminate_error();
  1019     }
  1020   }
  1021   moonbr_poll_workers[moonbr_poll_worker_count] = (struct moonbr_poll_worker){0, };
  1022   return moonbr_poll_worker_count++;
  1023 }
  1025 /* Queues all listeners as idle, and initializes static part of moonbr_poll_fds[], which is passed to poll() */
  1026 static void moonbr_poll_init() {
  1027   if (socketpair(
  1028     PF_LOCAL,
  1029     SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
  1030     0,
  1031     moonbr_poll_signalfds
  1032   )) {
  1033     moonbr_log(LOG_CRIT, "Could not create socket pair for signal delivery during polling: %s", strerror(errno));
  1034     moonbr_terminate_error();
  1035   }
  1036   {
  1037     int j = moonbr_poll_fds_nextindex();
  1038     struct pollfd *pollfd = &moonbr_poll_fds[j];
  1039     pollfd->fd = moonbr_poll_signalfd_read;
  1040     pollfd->events = POLLIN;
  1041   }
  1042   {
  1043     struct moonbr_pool *pool;
  1044     for (pool=moonbr_first_pool; pool; pool=pool->next_pool) {
  1045       int i;
  1046       for (i=0; i<pool->listener_count; i++) {
  1047         struct moonbr_listener *listener = &pool->listener[i];
  1048         if (listener->listenfd != -1) {
  1049           int j = moonbr_poll_fds_nextindex();
  1050           listener->pollidx = j;
  1051           moonbr_poll_fds[j].fd = listener->listenfd;
  1052         }
  1053         moonbr_add_idle_listener(listener);
  1054       }
  1055     }
  1056   }
  1057   moonbr_poll_fds_static_count = moonbr_poll_fds_count;  /* remember size of static part of array */
  1058 }
  1060 /* Disables polling of all listeners (required for clean shutdown) */
  1061 static void moonbr_poll_shutdown() {
  1062   int i;
  1063   for (i=1; i<moonbr_poll_fds_static_count; i++) {
  1064     moonbr_poll_fds[i].fd = -1;
  1065   }
  1066 }
  1068 /* (Re)builds dynamic part of moonbr_poll_fds[] array, and (re)builds moonbr_poll_workers[] array */
  1069 static void moonbr_poll_refresh() {
  1070   moonbr_poll_refresh_needed = 0;
  1071   moonbr_poll_fds_count = moonbr_poll_fds_static_count;
  1072   moonbr_poll_worker_count = 0;
  1073   {
  1074     struct moonbr_pool *pool;
  1075     for (pool=moonbr_first_pool; pool; pool=pool->next_pool) {
  1076       struct moonbr_worker *worker;
  1077       for (worker=pool->first_worker; worker; worker=worker->next_worker) {
  1078         if (worker->controlfd != -1) {
  1079           int j = moonbr_poll_fds_nextindex();
  1080           int k = moonbr_poll_workers_nextindex();
  1081           struct pollfd *pollfd = &moonbr_poll_fds[j];
  1082           struct moonbr_poll_worker *poll_worker = &moonbr_poll_workers[k];
  1083           pollfd->fd = worker->controlfd;
  1084           pollfd->events = POLLIN;
  1085           poll_worker->channel = MOONBR_POLL_WORKER_CONTROLCHANNEL;
  1086           poll_worker->worker = worker;
  1087         }
  1088         if (worker->errorfd != -1) {
  1089           int j = moonbr_poll_fds_nextindex();
  1090           int k = moonbr_poll_workers_nextindex();
  1091           struct pollfd *pollfd = &moonbr_poll_fds[j];
  1092           struct moonbr_poll_worker *poll_worker = &moonbr_poll_workers[k];
  1093           pollfd->fd = worker->errorfd;
  1094           pollfd->events = POLLIN;
  1095           poll_worker->channel = MOONBR_POLL_WORKER_ERRORCHANNEL;
  1096           poll_worker->worker = worker;
  1097         }
  1098       }
  1099     }
  1100   }
  1101 }
  1103 /* resets socket and 'revents' field of moonbr_poll_fds[] for signal delivery just before poll() is called */
  1104 static void moonbr_poll_reset_signal() {
  1105   ssize_t readcount;
  1106   char buf[1];
  1107   moonbr_poll_fds[0].revents = 0;
  1108   while ((readcount = read(moonbr_poll_signalfd_read, buf, 1)) < 0) {
  1109     if (errno == EAGAIN) break;
  1110     if (errno != EINTR) {
  1111       moonbr_log(LOG_CRIT, "Error while reading from signal delivery socket: %s", strerror(errno));
  1112       moonbr_terminate_error();
  1113     }
  1114   }
  1115   if (!readcount) {
  1116     moonbr_log(LOG_CRIT, "Unexpected EOF when reading from signal delivery socket: %s", strerror(errno));
  1117     moonbr_terminate_error();
  1118   }
  1119 }
  1122 /*** Shutdown initiation ***/
  1124 /* Sets global variable 'moonbr_shutdown_in_progress', closes listeners, and demands worker termination */
  1125 static void moonbr_initiate_shutdown() {
  1126   struct moonbr_pool *pool;
  1127   int i;
  1128   if (moonbr_shutdown_in_progress) {
  1129     moonbr_log(LOG_NOTICE, "Shutdown already in progress");
  1130     return;
  1131   }
  1132   moonbr_shutdown_in_progress = 1;
  1133   moonbr_log(LOG_NOTICE, "Initiate shutdown");
  1134   for (pool = moonbr_first_pool; pool; pool = pool->next_pool) {
  1135     for (i=0; i<pool->listener_count; i++) {
  1136       struct moonbr_listener *listener = &pool->listener[i];
  1137       if (listener->listenfd != -1) {
  1138         if (close(listener->listenfd) && errno != EINTR) {
  1139           moonbr_log(LOG_CRIT, "Could not close listening socket: %s", strerror(errno));
  1140           moonbr_terminate_error();
  1141         }
  1142       }
  1143     }
  1144   }
  1145   moonbr_poll_shutdown();  /* avoids loops due to error condition when polling closed listeners */
  1146   /* sending SIGUSR1 to children might be used to terminate children gracefully */
  1147   /*
  1148   {
  1149     pid_t pgrp = getpgrp();
  1150     moonbr_log(LOG_INFO, "Sending SIGUSR1 to all processes in group %i", (int)pgrp);
  1151     if (killpg(pgrp, SIGUSR1)) {
  1152       moonbr_log(LOG_WARNING, "Error while sending SIGUSR1 to own process group: %s", strerror(errno));
  1153     }
  1154   }
  1155   */
  1156 }
  1159 /*** Functions to handle previously created 'struct moonbr_worker' structures ***/
  1161 #define moonbr_try_destroy_worker_stat(str, field) \
  1162   moonbr_log(LOG_INFO, "Resource usage in pool #%i for PID %i: " str " %li", worker->pool->poolnum, (int)worker->pid, (long)childusage.field);
  1164 /* Destroys a worker structure if socket connections have been closed and child process has terminated */
  1165 static int moonbr_try_destroy_worker(struct moonbr_worker *worker) {
  1166   if (worker->controlfd != -1 || worker->errorfd != -1) return MOONBR_DESTROY_NONE;
  1167   {
  1168     int childstatus;
  1169     struct rusage childusage;
  1170     {
  1171       pid_t waitedpid;
  1172       while (
  1173         (waitedpid = wait4(worker->pid, &childstatus, WNOHANG, &childusage)) == -1
  1174       ) {
  1175         if (errno != EINTR) {
  1176           moonbr_log(LOG_CRIT, "Error in wait4() call: %s", strerror(errno));
  1177           moonbr_terminate_error();
  1178         }
  1179       }
  1180       if (!waitedpid) return 0;  /* return 0 if worker couldn't be destroyed */
  1181       if (waitedpid != worker->pid) {
  1182         moonbr_log(LOG_CRIT, "Wrong PID returned by wait4() call");
  1183         moonbr_terminate_error();
  1184       }
  1185     }
  1186     if (WIFEXITED(childstatus)) {
  1187       if (WEXITSTATUS(childstatus) || moonbr_stat) {
  1188         moonbr_log(
  1189           WEXITSTATUS(childstatus) ? LOG_WARNING : LOG_INFO,
  1190           "Child process in pool #%i with PID %i returned with exit code %i", worker->pool->poolnum, (int)worker->pid, WEXITSTATUS(childstatus)
  1191         );
  1192       }
  1193     } else if (WIFSIGNALED(childstatus)) {
  1194       if (WCOREDUMP(childstatus)) {
  1195         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));
  1196       } else if (WTERMSIG(childstatus) == SIGALRM) {
  1197         moonbr_log(LOG_WARNING, "Child process in pool #%i with PID %i exited prematurely due to timeout", worker->pool->poolnum, (int)worker->pid);
  1198       } else {
  1199         moonbr_log(LOG_ERR, "Child process in pool #%i with PID %i died from signal %i", worker->pool->poolnum, (int)worker->pid, WTERMSIG(childstatus));
  1200       }
  1201     } else {
  1202       moonbr_log(LOG_CRIT, "Illegal exit status from child process in pool #%i with PID %i", worker->pool->poolnum, (int)worker->pid);
  1203       moonbr_terminate_error();
  1204     }
  1205     if (moonbr_stat) {
  1206       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));
  1207       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));
  1208       moonbr_try_destroy_worker_stat("max resident set size", ru_maxrss);
  1209       moonbr_try_destroy_worker_stat("integral shared memory size", ru_ixrss);
  1210       moonbr_try_destroy_worker_stat("integral unshared data", ru_idrss);
  1211       moonbr_try_destroy_worker_stat("integral unshared stack", ru_isrss);
  1212       moonbr_try_destroy_worker_stat("page replaims", ru_minflt);
  1213       moonbr_try_destroy_worker_stat("page faults", ru_majflt);
  1214       moonbr_try_destroy_worker_stat("swaps", ru_nswap);
  1215       moonbr_try_destroy_worker_stat("block input operations", ru_inblock);
  1216       moonbr_try_destroy_worker_stat("block output operations", ru_oublock);
  1217       moonbr_try_destroy_worker_stat("messages sent", ru_msgsnd);
  1218       moonbr_try_destroy_worker_stat("messages received", ru_msgrcv);
  1219       moonbr_try_destroy_worker_stat("signals received", ru_nsignals);
  1220       moonbr_try_destroy_worker_stat("voluntary context switches", ru_nvcsw);
  1221       moonbr_try_destroy_worker_stat("involuntary context switches", ru_nivcsw);
  1222     }
  1223   }
  1224   {
  1225     int retval = (
  1226       (worker->idle || worker->assigned) ?
  1227       MOONBR_DESTROY_IDLE_OR_ASSIGNED :
  1228       MOONBR_DESTROY_PREPARE
  1229     );
  1230     if (worker->main) moonbr_initiate_shutdown();
  1231     if (worker->prev_worker) worker->prev_worker->next_worker = worker->next_worker;
  1232     else worker->pool->first_worker = worker->next_worker;
  1233     if (worker->next_worker) worker->next_worker->prev_worker = worker->prev_worker;
  1234     else worker->pool->last_worker = worker->prev_worker;
  1235     if (worker->idle) {
  1236       if (worker->prev_idle_worker) worker->prev_idle_worker->next_idle_worker = worker->next_idle_worker;
  1237       else worker->pool->first_idle_worker = worker->next_idle_worker;
  1238       if (worker->next_idle_worker) worker->next_idle_worker->prev_idle_worker = worker->prev_idle_worker;
  1239       else worker->pool->last_idle_worker  = worker->prev_idle_worker;
  1240       worker->pool->idle_worker_count--;
  1241     }
  1242     if (!worker->assigned) worker->pool->unassigned_worker_count--;
  1243     worker->pool->total_worker_count--;
  1244     worker->pool->worker_count_stat = 1;
  1245     if (worker->errorlinebuf) free(worker->errorlinebuf);
  1246     free(worker);
  1247     return retval;
  1248   }
  1249 }
  1251 /* Marks a worker as idle and stores it in a queue, optionally setting 'idle_expiration' value */
  1252 static void moonbr_add_idle_worker(struct moonbr_worker *worker) {
  1253   worker->prev_idle_worker = worker->pool->last_idle_worker;
  1254   if (worker->prev_idle_worker) worker->prev_idle_worker->next_idle_worker = worker;
  1255   else worker->pool->first_idle_worker = worker;
  1256   worker->pool->last_idle_worker = worker;
  1257   worker->idle = 1;
  1258   worker->pool->idle_worker_count++;
  1259   if (worker->assigned) {
  1260     worker->assigned = 0;
  1261     worker->pool->unassigned_worker_count++;
  1262   }
  1263   worker->pool->worker_count_stat = 1;
  1264   if (timerisset(&worker->pool->idle_timeout)) {
  1265     struct timeval now;
  1266     moonbr_now(&now);
  1267     timeradd(&now, &worker->pool->idle_timeout, &worker->idle_expiration);
  1268   }
  1269 }
  1271 /* Pops a worker from the queue of idle workers (idle queue must not be empty) */
  1272 static struct moonbr_worker *moonbr_pop_idle_worker(struct moonbr_pool *pool) {
  1273   struct moonbr_worker *worker;
  1274   worker = pool->first_idle_worker;
  1275   pool->first_idle_worker = worker->next_idle_worker;
  1276   if (pool->first_idle_worker) pool->first_idle_worker->prev_idle_worker = NULL;
  1277   else pool->last_idle_worker = NULL;
  1278   worker->next_idle_worker = NULL;
  1279   worker->idle = 0;
  1280   worker->pool->idle_worker_count--;
  1281   worker->assigned = 1;
  1282   worker->pool->unassigned_worker_count--;
  1283   worker->pool->worker_count_stat = 1;
  1284   return worker;
  1285 }
  1288 /*** Functions to communicate with child processes ***/
  1290 /* Tells child process to terminate */
  1291 static void moonbr_terminate_idle_worker(struct moonbr_worker *worker) {
  1292   moonbr_send_control_message(worker, MOONBR_COMMAND_TERMINATE, -1, NULL);
  1293 }
  1295 /* Handles status messages from child process */
  1296 static void moonbr_read_controlchannel(struct moonbr_worker *worker) {
  1297   char controlmsg;
  1298   {
  1299     ssize_t bytes_read;
  1300     while ((bytes_read = read(worker->controlfd, &controlmsg, 1)) <= 0) {
  1301       if (bytes_read == 0 || errno == ECONNRESET) {
  1302         moonbr_log(LOG_WARNING, "Child process in pool #%i with PID %i unexpectedly closed control socket", worker->pool->poolnum, (int)worker->pid);
  1303         if (close(worker->controlfd) && errno != EINTR) {
  1304           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));
  1305           moonbr_terminate_error();
  1306         }
  1307         worker->controlfd = -1;
  1308         moonbr_poll_refresh_needed = 1;
  1309         return;
  1310       }
  1311       if (errno != EINTR) {
  1312         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));
  1313         moonbr_terminate_error();
  1314       }
  1315     }
  1316   }
  1317   if (worker->idle) {
  1318     moonbr_log(LOG_CRIT, "Unexpected data from supposedly idle child process in pool #%i with PID %i", worker->pool->poolnum, (int)worker->pid);
  1319     moonbr_terminate_error();
  1320   }
  1321   if (moonbr_debug) {
  1322     moonbr_log(LOG_DEBUG, "Received control message from child in pool #%i with PID %i: \"%c\"", worker->pool->poolnum, (int)worker->pid, (int)controlmsg);
  1323   }
  1324   switch (controlmsg) {
  1325   case MOONBR_STATUS_IDLE:
  1326     if (moonbr_stat) {
  1327       moonbr_log(LOG_INFO, "Child process in pool #%i with PID %i reports as idle", worker->pool->poolnum, (int)worker->pid);
  1328     }
  1329     moonbr_add_idle_worker(worker);
  1330     break;
  1331   case MOONBR_STATUS_GOODBYE:
  1332     if (moonbr_stat) {
  1333       moonbr_log(LOG_INFO, "Child process in pool #%i with PID %i announced termination", worker->pool->poolnum, (int)worker->pid);
  1334     }
  1335     if (close(worker->controlfd) && errno != EINTR) {
  1336       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));
  1337       moonbr_terminate_error();
  1338     }
  1339     worker->controlfd = -1;
  1340     moonbr_poll_refresh_needed = 1;
  1341     break;
  1342   default:
  1343     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);
  1344     moonbr_terminate_error();
  1345   }
  1346 }
  1348 /* Handles stderr stream from child process */
  1349 static void moonbr_read_errorchannel(struct moonbr_worker *worker) {
  1350   char staticbuf[MOONBR_MAXERRORLINELEN+1];
  1351   char *buf = worker->errorlinebuf;
  1352   if (!buf) buf = staticbuf;
  1353   {
  1354     ssize_t bytes_read;
  1355     while (
  1356       (bytes_read = read(
  1357         worker->errorfd,
  1358         buf + worker->errorlinelen,
  1359         MOONBR_MAXERRORLINELEN+1 - worker->errorlinelen
  1360       )) <= 0
  1361     ) {
  1362       if (bytes_read == 0 || errno == ECONNRESET) {
  1363         if (moonbr_debug) {
  1364           moonbr_log(LOG_DEBUG, "Child process in pool #%i with PID %i closed stderr socket", worker->pool->poolnum, (int)worker->pid);
  1365         }
  1366         if (close(worker->errorfd) && errno != EINTR) {
  1367           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));
  1368           moonbr_terminate_error();
  1369         }
  1370         worker->errorfd = -1;
  1371         moonbr_poll_refresh_needed = 1;
  1372         break;
  1373       }
  1374       if (errno != EINTR) {
  1375         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));
  1376         moonbr_terminate_error();
  1377       }
  1378     }
  1379     worker->errorlinelen += bytes_read;
  1380   }
  1381   {
  1382     int i;
  1383     for (i=0; i<worker->errorlinelen; i++) {
  1384       if (buf[i] == '\n') buf[i] = 0;
  1385       if (!buf[i]) {
  1386         if (worker->errorlineovf) {
  1387           worker->errorlineovf = 0;
  1388         } else {
  1389           moonbr_log(LOG_WARNING, "Error log from process in pool #%i with PID %i: %s", worker->pool->poolnum, (int)worker->pid, buf);
  1390         }
  1391         worker->errorlinelen -= i+1;
  1392         memmove(buf, buf+i+1, worker->errorlinelen);
  1393         i = -1;
  1394       }
  1395     }
  1396     if (i > MOONBR_MAXERRORLINELEN) {
  1397       buf[MOONBR_MAXERRORLINELEN] = 0;
  1398       if (!worker->errorlineovf) {
  1399         moonbr_log(LOG_WARNING, "Error log from process in pool #%i with PID %i (line has been truncated): %s", worker->pool->poolnum, (int)worker->pid, buf);
  1400       }
  1401       worker->errorlinelen = 0;
  1402       worker->errorlineovf = 1;
  1403     }
  1404   }
  1405   if (!worker->errorlinebuf && worker->errorlinelen) {  /* allocate buffer on heap only if necessary */
  1406     worker->errorlinebuf = malloc((MOONBR_MAXERRORLINELEN+1) * sizeof(char));
  1407     if (!worker->errorlinebuf) {
  1408       moonbr_log(LOG_CRIT, "Memory allocation error");
  1409       moonbr_terminate_error();
  1410     }
  1411     memcpy(worker->errorlinebuf, staticbuf, worker->errorlinelen);
  1412   }
  1413 }
  1416 /*** Handler for incoming connections ***/
  1418 /* Accepts one or more incoming connections on listener socket and passes it to worker(s) popped from idle queue */
  1419 static void moonbr_connect(struct moonbr_pool *pool) {
  1420   struct moonbr_listener *listener = moonbr_pop_connected_listener(pool);
  1421   struct moonbr_worker *worker;
  1422   if (listener->proto == MOONBR_PROTO_MAIN) {
  1423     worker = moonbr_pop_idle_worker(pool);
  1424     if (moonbr_stat) {
  1425       moonbr_log(LOG_INFO, "Dispatching main thread of pool #%i to PID %i", listener->pool->poolnum, (int)worker->pid);
  1426     }
  1427     worker->main = 1;
  1428     moonbr_send_control_message(worker, MOONBR_COMMAND_CONNECT, -1, listener);
  1429     /* do not push listener to queue of idle listeners */
  1430   } else if (listener->proto == MOONBR_PROTO_INTERVAL) {
  1431     worker = moonbr_pop_idle_worker(pool);
  1432     if (moonbr_stat) {
  1433       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);
  1434     }
  1435     worker->restart_interval_listener = listener;
  1436     moonbr_send_control_message(worker, MOONBR_COMMAND_CONNECT, -1, listener);
  1437     /* do not push listener to queue of idle listeners yet */
  1438   } else {
  1439     int peerfd;
  1440     do {
  1441 #if defined(__linux__) && !defined(_GNU_SOURCE)
  1442       peerfd = accept(listener->listenfd, NULL, NULL);
  1443       if (peerfd != -1) {
  1444         if (fcntl(peerfd, F_SETFD, FD_CLOEXEC) == -1) {
  1445           moonbr_log(LOG_ERR, "Error in fcntl() call: %s", strerror(errno));
  1446           moonbr_terminate_error();
  1447         }
  1448       }
  1449 #else
  1450       peerfd = accept4(listener->listenfd, NULL, NULL, SOCK_CLOEXEC);
  1451 #endif
  1452       if (peerfd == -1) {
  1453         if (errno == EWOULDBLOCK) {
  1454           break;
  1455         } else if (errno == ECONNABORTED) {
  1456           moonbr_log(LOG_WARNING, "Connection aborted before accepting it");
  1457           break;
  1458         } else if (errno != EINTR) {
  1459           moonbr_log(LOG_ERR, "Could not accept socket connection: %s", strerror(errno));
  1460           moonbr_terminate_error();
  1461         }
  1462       } else {
  1463         worker = moonbr_pop_idle_worker(pool);
  1464         if (moonbr_stat) {
  1465           moonbr_log(LOG_INFO, "Dispatching connection for pool #%i to PID %i", listener->pool->poolnum, (int)worker->pid);
  1466         }
  1467         moonbr_send_control_message(worker, MOONBR_COMMAND_CONNECT, peerfd, listener);
  1468         if (close(peerfd) && errno != EINTR) {
  1469           moonbr_log(LOG_ERR, "Could not close incoming socket connection in parent process: %s", strerror(errno));
  1470           moonbr_terminate_error();
  1471         }
  1472       }
  1473     } while (pool->first_idle_worker);
  1474     moonbr_add_idle_listener(listener);
  1475   }
  1476 }
  1479 /*** Functions to initialize and restart interval timers ***/
  1481 /* Initializes all interval timers */
  1482 static void moonbr_interval_initialize() {
  1483   struct timeval now;
  1484   struct moonbr_pool *pool;
  1485   moonbr_now(&now);
  1486   for (pool=moonbr_first_pool; pool; pool=pool->next_pool) {
  1487     int i;
  1488     for (i=0; i<pool->listener_count; i++) {
  1489       struct moonbr_listener *listener = &pool->listener[i];
  1490       if (listener->proto == MOONBR_PROTO_INTERVAL) {
  1491         timeradd(
  1492           &now,
  1493           &listener->type_specific.interval.delay,
  1494           &listener->type_specific.interval.wakeup
  1495         );
  1496       }
  1497     }
  1498   }
  1499 }
  1501 /* If necessary, restarts interval timers and queues interval listener as idle after a worker changed status */
  1502 static void moonbr_interval_restart(
  1503   struct moonbr_worker *worker,
  1504   struct timeval *now           /* passed to synchronize with moonbr_run() function */
  1505 ) {
  1506   struct moonbr_listener *listener = worker->restart_interval_listener;
  1507   if (listener) {
  1508     moonbr_add_idle_listener(listener);
  1509     worker->restart_interval_listener = NULL;
  1510     if (listener->type_specific.interval.strict) {
  1511       timeradd(
  1512         &listener->type_specific.interval.wakeup,
  1513         &listener->type_specific.interval.delay,
  1514         &listener->type_specific.interval.wakeup
  1515       );
  1516       if (timercmp(&listener->type_specific.interval.wakeup, now, <)) {
  1517         listener->type_specific.interval.wakeup = *now;
  1518       }
  1519     } else {
  1520       timeradd(
  1521         now,
  1522         &listener->type_specific.interval.delay,
  1523         &listener->type_specific.interval.wakeup
  1524       );
  1525     }
  1526   }
  1527 }
  1530 /*** Main loop and helper functions ***/
  1532 /* Stores the earliest required wakeup time in 'wait' variable */
  1533 static void moonbr_calc_wait(struct timeval *wait, struct timeval *wakeup) {
  1534   if (!timerisset(wait) || timercmp(wakeup, wait, <)) *wait = *wakeup;
  1535 }
  1537 /* Main loop of Moonbridge system (including initialization of signal handlers and polling structures) */
  1538 static void moonbr_run(lua_State *L) {
  1539   struct timeval now;
  1540   struct moonbr_pool *pool;
  1541   struct moonbr_worker *worker;
  1542   struct moonbr_worker *next_worker;  /* needed when worker is removed during iteration of workers */
  1543   struct moonbr_listener *listener;
  1544   struct moonbr_listener *next_listener;  /* needed when listener is removed during iteration of listeners */
  1545   int i;
  1546   moonbr_poll_init();    /* must be executed before moonbr_signal_init() */
  1547   moonbr_signal_init();
  1548   moonbr_interval_initialize();
  1549   moonbr_pstate = MOONBR_PSTATE_RUNNING;
  1550   while (1) {
  1551     struct timeval wait = {0, };  /* point in time when premature wakeup of poll() is required */
  1552     if (moonbr_cond_interrupt) {
  1553       moonbr_log(LOG_WARNING, "Fast shutdown requested");
  1554       moonbr_terminate(MOONBR_EXITCODE_GRACEFUL);
  1555     }
  1556     if (moonbr_cond_terminate) {
  1557       moonbr_initiate_shutdown();
  1558       moonbr_cond_terminate = 0;
  1559     }
  1560     moonbr_cond_child = 0;  /* must not be reset between moonbr_try_destroy_worker() and poll() */
  1561     moonbr_now(&now);
  1562     for (pool=moonbr_first_pool; pool; pool=pool->next_pool) {
  1563       int terminated_worker_count = 0;  /* allows shortcut for new worker creation */
  1564       /* terminate idle workers when expired */
  1565       if (timerisset(&pool->idle_timeout)) {
  1566         while ((worker = pool->first_idle_worker) != NULL) {
  1567           if (timercmp(&worker->idle_expiration, &now, >)) break;
  1568           moonbr_pop_idle_worker(pool);
  1569           moonbr_terminate_idle_worker(worker);
  1570         }
  1571       }
  1572       /* mark listeners as connected when incoming connection is pending */
  1573       for (listener=pool->first_idle_listener; listener; listener=next_listener) {
  1574         next_listener = listener->next_listener;  /* extra variable necessary due to changing list */
  1575         if (listener->pollidx != -1) {
  1576           if (moonbr_poll_fds[listener->pollidx].revents) {
  1577             moonbr_poll_fds[listener->pollidx].revents = 0;
  1578             moonbr_remove_idle_listener(listener);
  1579             moonbr_add_connected_listener(listener);
  1580           }
  1581         } else if (
  1582           listener->proto != MOONBR_PROTO_INTERVAL ||
  1583           !timercmp(&listener->type_specific.interval.wakeup, &now, >)
  1584         ) {
  1585           moonbr_remove_idle_listener(listener);
  1586           moonbr_add_connected_listener(listener);
  1587         }
  1588       }
  1589       /* process input from child processes */
  1590       for (i=0; i<moonbr_poll_worker_count; i++) {
  1591         if (moonbr_poll_worker_fds[i].revents) {
  1592           moonbr_poll_worker_fds[i].revents = 0;
  1593           struct moonbr_poll_worker *poll_worker = &moonbr_poll_workers[i];
  1594           switch (poll_worker->channel) {
  1595           case MOONBR_POLL_WORKER_CONTROLCHANNEL:
  1596             moonbr_read_controlchannel(poll_worker->worker);
  1597             moonbr_interval_restart(poll_worker->worker, &now);
  1598             break;
  1599           case MOONBR_POLL_WORKER_ERRORCHANNEL:
  1600             moonbr_read_errorchannel(poll_worker->worker);
  1601             break;
  1602           }
  1603         }
  1604       }
  1605       /* collect dead child processes */
  1606       for (worker=pool->first_worker; worker; worker=next_worker) {
  1607         next_worker = worker->next_worker;  /* extra variable necessary due to changing list */
  1608         switch (moonbr_try_destroy_worker(worker)) {
  1609         case MOONBR_DESTROY_PREPARE:
  1610           pool->use_fork_error_wakeup = 1;
  1611           break;
  1612         case MOONBR_DESTROY_IDLE_OR_ASSIGNED:
  1613           terminated_worker_count++;
  1614           break;
  1615         }
  1616       }
  1617       if (!moonbr_shutdown_in_progress) {
  1618         /* connect listeners with idle workers */
  1619         while (pool->first_connected_listener && pool->first_idle_worker) {
  1620           moonbr_connect(pool);
  1621         }
  1622         /* create new worker processes */
  1623         while (
  1624           pool->total_worker_count < pool->max_fork && (
  1625             pool->unassigned_worker_count < pool->pre_fork ||
  1626             pool->total_worker_count < pool->min_fork
  1627           )
  1628         ) {
  1629           if (pool->use_fork_error_wakeup) {
  1630             if (timercmp(&pool->fork_error_wakeup, &now, >)) {
  1631             moonbr_calc_wait(&wait, &pool->fork_error_wakeup);
  1632             break;
  1633             }
  1634           } else {
  1635             if (terminated_worker_count) {
  1636               terminated_worker_count--;
  1637             } else if (timercmp(&pool->fork_wakeup, &now, >)) {
  1638               moonbr_calc_wait(&wait, &pool->fork_wakeup);
  1639               break;
  1640             }
  1641           }
  1642           if (moonbr_create_worker(pool, L)) {
  1643             /* on error, enforce error delay */
  1644             timeradd(&now, &pool->fork_error_delay, &pool->fork_error_wakeup);
  1645             pool->use_fork_error_wakeup = 1;
  1646             moonbr_calc_wait(&wait, &pool->fork_error_wakeup);
  1647             break;
  1648           } else {
  1649             /* normal fork delay on success */
  1650             timeradd(&now, &pool->fork_delay, &pool->fork_wakeup);
  1651             timeradd(&now, &pool->fork_error_delay, &pool->fork_error_wakeup);
  1652             pool->use_fork_error_wakeup = 0;  /* gets set later if error occures during preparation */
  1653           }
  1654         }
  1655         /* terminate excessive worker processes */
  1656         while (
  1657           pool->total_worker_count > pool->min_fork &&
  1658           pool->idle_worker_count > pool->pre_fork
  1659         ) {
  1660           if (timerisset(&pool->exit_wakeup)) {
  1661             if (timercmp(&pool->exit_wakeup, &now, >)) {
  1662               moonbr_calc_wait(&wait, &pool->exit_wakeup);
  1663               break;
  1664             }
  1665             moonbr_terminate_idle_worker(moonbr_pop_idle_worker(pool));
  1666             timeradd(&now, &pool->exit_delay, &pool->exit_wakeup);
  1667           } else {
  1668             timeradd(&now, &pool->exit_delay, &pool->exit_wakeup);
  1669             break;
  1670           }
  1671         }
  1672         if (!(
  1673           pool->total_worker_count > pool->min_fork &&
  1674           pool->idle_worker_count > pool->pre_fork
  1675         )) {
  1676           timerclear(&pool->exit_wakeup);  /* timer gets restarted later when there are excessive workers */
  1677         }
  1678       }
  1679       /* optionally output worker count stats */
  1680       if (moonbr_stat && pool->worker_count_stat) {
  1681         pool->worker_count_stat = 0;
  1682         moonbr_log(
  1683           LOG_INFO,
  1684           "Worker count for pool #%i: %i idle, %i assigned, %i total",
  1685           pool->poolnum, pool->idle_worker_count,
  1686           pool->total_worker_count - pool->unassigned_worker_count,
  1687           pool->total_worker_count);
  1688       }
  1689       /* calculate wakeup time for interval listeners */
  1690       for (listener=pool->first_idle_listener; listener; listener=listener->next_listener) {
  1691         if (listener->proto == MOONBR_PROTO_INTERVAL) {
  1692           moonbr_calc_wait(&wait, &listener->type_specific.interval.wakeup);
  1693         }
  1694       }
  1695       /* calculate wakeup time for idle workers (only first idle worker is significant) */
  1696       if (timerisset(&pool->idle_timeout) && pool->first_idle_worker) {
  1697         moonbr_calc_wait(&wait, &pool->first_idle_worker->idle_expiration);
  1698       }
  1699     }
  1700     /* terminate idle workers in case of shutdown and check if shutdown is complete */
  1701     if (moonbr_shutdown_in_progress) {
  1702       int remaining = 0;
  1703       for (pool=moonbr_first_pool; pool; pool=pool->next_pool) {
  1704         while (pool->idle_worker_count) {
  1705           moonbr_terminate_idle_worker(moonbr_pop_idle_worker(pool));
  1706         }
  1707         if (pool->first_worker) remaining = 1;
  1708       }
  1709       if (!remaining) {
  1710         moonbr_log(LOG_INFO, "All worker threads have terminated");
  1711         moonbr_terminate(MOONBR_EXITCODE_GRACEFUL);
  1712       }
  1713     }
  1714     if (moonbr_poll_refresh_needed) moonbr_poll_refresh();
  1715     moonbr_cond_poll = 1;
  1716     if (!moonbr_cond_child && !moonbr_cond_terminate && !moonbr_cond_interrupt) {
  1717       int timeout;
  1718       if (timerisset(&wait)) {
  1719         if (timercmp(&wait, &now, <)) {
  1720           moonbr_log(LOG_CRIT, "Internal error (should not happen): Future is in the past");
  1721           moonbr_terminate_error();
  1722         }
  1723         timersub(&wait, &now, &wait);
  1724         timeout = wait.tv_sec * 1000 + wait.tv_usec / 1000;
  1725       } else {
  1726         timeout = INFTIM;
  1727       }
  1728       if (moonbr_debug) {
  1729         moonbr_log(LOG_DEBUG, "Waiting for I/O");
  1730       }
  1731       poll(moonbr_poll_fds, moonbr_poll_fds_count, timeout);
  1732     } else {
  1733       if (moonbr_debug) {
  1734         moonbr_log(LOG_DEBUG, "Do not wait for I/O");
  1735       }
  1736     }
  1737     moonbr_cond_poll = 0;
  1738     moonbr_poll_reset_signal();
  1739   }
  1740 }
  1743 /*** Lua interface ***/
  1745 static int moonbr_lua_panic(lua_State *L) {
  1746   const char *errmsg;
  1747   errmsg = lua_tostring(L, -1);
  1748   if (!errmsg) {
  1749     if (lua_isnoneornil(L, -1)) errmsg = "(error message is nil)";
  1750     else errmsg = "(error message is not a string)";
  1751   }
  1752   if (moonbr_pstate == MOONBR_PSTATE_FORKED) {
  1753     fprintf(stderr, "Uncaught Lua error: %s\n", errmsg);
  1754     exit(1);
  1755   } else {
  1756     moonbr_log(LOG_CRIT, "Uncaught Lua error: %s", errmsg);
  1757     moonbr_terminate_error();
  1758   }
  1759   return 0;
  1760 }
  1762 static int moonbr_addtraceback(lua_State *L) {
  1763   luaL_traceback(L, L, luaL_tolstring(L, 1, NULL), 1);
  1764   return 1;
  1765 }
  1767 /* Memory allocator that allows limiting memory consumption */
  1768 static void *moonbr_alloc (void *ud, void *ptr, size_t osize, size_t nsize) {
  1769   (void)ud;  /* not used */
  1770   if (nsize == 0) {
  1771     if (ptr) {
  1772       moonbr_memory_usage -= osize;
  1773       free(ptr);
  1774     }
  1775     return NULL;
  1776   } else if (ptr) {
  1777     if (
  1778       moonbr_memory_limit &&
  1779       nsize > osize &&
  1780       moonbr_memory_usage + (nsize - osize) > moonbr_memory_limit
  1781     ) {
  1782       return NULL;
  1783     } else {
  1784       ptr = realloc(ptr, nsize);
  1785       if (ptr) moonbr_memory_usage += nsize - osize;
  1786     }
  1787   } else {
  1788     if (
  1789       moonbr_memory_limit &&
  1790       moonbr_memory_usage + nsize > moonbr_memory_limit
  1791     ) {
  1792       return NULL;
  1793     } else {
  1794       ptr = realloc(ptr, nsize);
  1795       if (ptr) moonbr_memory_usage += nsize;
  1796     }
  1797   }
  1798   return ptr;
  1799 }
  1801 static int moonbr_lua_tonatural(lua_State *L, int idx) {
  1802   int isnum;
  1803   lua_Number n;
  1804   n = lua_tonumberx(L, idx, &isnum);
  1805   if (isnum && n>=0 && n<INT_MAX && (lua_Number)(int)n == n) return n;
  1806   else return -1;
  1807 }
  1809 static int moonbr_lua_totimeval(lua_State *L, int idx, struct timeval *value) {
  1810   int isnum;
  1811   lua_Number n;
  1812   n = lua_tonumberx(L, idx, &isnum);
  1813   if (isnum && n>=0 && n<=100000000) {
  1814     value->tv_sec = n;
  1815     value->tv_usec = 1e6 * (n - value->tv_sec);
  1816     return 1;
  1817   } else {
  1818     return 0;
  1819   }
  1820 }
  1822 static int moonbr_timeout(lua_State *L) {
  1823   struct itimerval oldval;
  1824   if (lua_isnoneornil(L, 1) && lua_isnoneornil(L, 2)) {
  1825     getitimer(ITIMER_REAL, &oldval);
  1826   } else {
  1827     struct itimerval newval = {};
  1828     timerclear(&newval.it_interval);
  1829     timerclear(&newval.it_value);
  1830     if (lua_toboolean(L, 1)) {
  1831       luaL_argcheck(
  1832         L, moonbr_lua_totimeval(L, 1, &newval.it_value), 1,
  1833         "interval in seconds expected"
  1834       );
  1835     }
  1836     if (lua_isnoneornil(L, 2)) {
  1837       if (setitimer(ITIMER_REAL, &newval, &oldval)) {
  1838         moonbr_log(LOG_CRIT, "Could not set ITIMER_REAL via setitimer()");
  1839         moonbr_terminate_error();
  1840       }
  1841     } else {
  1842       getitimer(ITIMER_REAL, &oldval);
  1843       if (!timerisset(&oldval.it_value)) {
  1844         if (setitimer(ITIMER_REAL, &newval, NULL)) {
  1845           moonbr_log(LOG_CRIT, "Could not set ITIMER_REAL via setitimer()");
  1846           moonbr_terminate_error();
  1847         }
  1848         lua_call(L, lua_gettop(L) - 2, LUA_MULTRET);
  1849         timerclear(&newval.it_value);
  1850         if (setitimer(ITIMER_REAL, &newval, NULL)) {
  1851           moonbr_log(LOG_CRIT, "Could not set ITIMER_REAL via setitimer()");
  1852           moonbr_terminate_error();
  1853         }
  1854       } else if (timercmp(&newval.it_value, &oldval.it_value, <)) {
  1855         struct itimerval remval;
  1856         if (setitimer(ITIMER_REAL, &newval, NULL)) {
  1857           moonbr_log(LOG_CRIT, "Could not set ITIMER_REAL via setitimer()");
  1858           moonbr_terminate_error();
  1859         }
  1860         lua_call(L, lua_gettop(L) - 2, LUA_MULTRET);
  1861         getitimer(ITIMER_REAL, &remval);
  1862         timersub(&oldval.it_value, &newval.it_value, &newval.it_value);
  1863         timeradd(&newval.it_value, &remval.it_value, &newval.it_value);
  1864         if (setitimer(ITIMER_REAL, &newval, NULL)) {
  1865           moonbr_log(LOG_CRIT, "Could not set ITIMER_REAL via setitimer()");
  1866           moonbr_terminate_error();
  1867         }
  1868       } else {
  1869         lua_call(L, lua_gettop(L) - 2, LUA_MULTRET);
  1870       }
  1871       return lua_gettop(L) - 1;
  1872     }
  1873   }
  1874   lua_pushnumber(L, oldval.it_value.tv_sec + 1e-6 * oldval.it_value.tv_usec);
  1875   return 1;
  1876 }
  1878 #define moonbr_listen_init_pool_forkoption(luaname, cname, defval) { \
  1879   lua_getfield(L, 2, luaname); \
  1880   pool->cname = lua_isnil(L, -1) ? (defval) : moonbr_lua_tonatural(L, -1); \
  1881 } while(0)
  1883 #define moonbr_listen_init_pool_timeoption(luaname, cname, defval, defvalu) ( \
  1884   lua_getfield(L, 2, luaname), \
  1885   lua_isnil(L, -1) ? ( \
  1886     pool->cname.tv_sec = (defval), pool->cname.tv_usec = (defvalu), \
  1887     1 \
  1888   ) : ( \
  1889     (lua_isboolean(L, -1) && !lua_toboolean(L, -1)) ? ( \
  1890       pool->cname.tv_sec = 0, pool->cname.tv_usec = 0, \
  1891       1 \
  1892     ) : ( \
  1893       moonbr_lua_totimeval(L, -1, &pool->cname) \
  1894     ) \
  1895   ) \
  1896 )
  1898 static int moonbr_listen_init_pool(lua_State *L) {
  1899   struct moonbr_pool *pool;
  1900   const char *proto;
  1901   int i;
  1902   int dynamic = 0;  /* nonzero = listeners exist which require dynamic worker creation */
  1903   pool = lua_touserdata(L, 1);
  1904   for (i=0; i<pool->listener_count; i++) {
  1905     struct moonbr_listener *listener = &pool->listener[i];
  1906     lua_settop(L, 2);
  1907 #if LUA_VERSION_NUM >= 503
  1908     lua_geti(L, 2, i+1);
  1909 #else
  1910     lua_pushinteger(L, i+1);
  1911     lua_gettable(L, 2);
  1912 #endif
  1913     lua_getfield(L, 3, "proto");
  1914     proto = lua_tostring(L, -1);
  1915     if (proto && !strcmp(proto, "main")) {
  1916       listener->proto = MOONBR_PROTO_MAIN;
  1917     } else if (proto && !strcmp(proto, "interval")) {
  1918       dynamic = 1;
  1919       listener->proto = MOONBR_PROTO_INTERVAL;
  1920       lua_getfield(L, 3, "name");
  1921       {
  1922         const char *name = lua_tostring(L, -1);
  1923         if (name) {
  1924           char *name_dup = strdup(name);
  1925           if (!name_dup) {
  1926             moonbr_log(LOG_CRIT, "Memory allocation_error");
  1927             moonbr_terminate_error();
  1928           }
  1929           listener->type_specific.interval.name = name_dup;
  1930         }
  1931       }
  1932       lua_getfield(L, 3, "delay");
  1933       if (
  1934         !moonbr_lua_totimeval(L, -1, &listener->type_specific.interval.delay) ||
  1935         !timerisset(&listener->type_specific.interval.delay)
  1936       ) {
  1937         luaL_error(L, "No valid interval delay specified; use listen{{proto=\"interval\", delay=...}, ...}");
  1938       }
  1939       lua_getfield(L, 3, "strict");
  1940       if (!lua_isnil(L, -1)) {
  1941         if (lua_isboolean(L, -1)) {
  1942           if (lua_toboolean(L, -1)) listener->type_specific.interval.strict = 1;
  1943         } else {
  1944           luaL_error(L, "Option \"strict\" must be a boolean if set; use listen{{proto=\"interval\", strict=true, ...}, ...}");
  1945         }
  1946       }
  1947     } else if (proto && !strcmp(proto, "local")) {
  1948       const char *path;
  1949       const int path_maxlen = (
  1950         sizeof(listener->type_specific.socket.addr.addr_un) -
  1951         ((void *)listener->type_specific.socket.addr.addr_un.sun_path - (void *)&listener->type_specific.socket.addr.addr_un)
  1952       ) - 1;  /* one byte for termination */
  1953       dynamic = 1;
  1954       listener->proto = MOONBR_PROTO_LOCAL;
  1955       lua_getfield(L, 3, "path");
  1956       path = lua_tostring(L, -1);
  1957       if (!path) {
  1958         luaL_error(L, "No valid path specified for local socket; use listen{{proto=\"local\", path=...}, ...}");
  1959       }
  1960       if (strlen(path) > path_maxlen) {
  1961         luaL_error(L, "Path name for local socket exceeded maximum length of %i characters", path_maxlen);
  1962       }
  1963       strcpy(listener->type_specific.socket.addr.addr_un.sun_path, path);
  1964     } else if (proto && !strcmp(proto, "tcp")) {
  1965       const char *host, *port;
  1966       struct addrinfo hints = { 0, };
  1967       struct addrinfo *res, *addrinfo;
  1968       int errcode;
  1969       const char *ip;
  1970       dynamic = 1;
  1971       lua_getfield(L, 3, "host");
  1972       host = lua_isnil(L, -1) ? "::" : lua_tostring(L, -1);
  1973       if (!host) {
  1974         luaL_error(L, "No host specified; use listen{{proto=\"tcp\", host=...}, ...}");
  1975       }
  1976       lua_getfield(L, 3, "port");
  1977       port = lua_tostring(L, -1);
  1978       if (!port) {
  1979         luaL_error(L, "No port specified; use listen{{proto=\"tcp\", host=...}, ...}");
  1980       }
  1981       hints.ai_family = AF_UNSPEC;
  1982       hints.ai_socktype = SOCK_STREAM;
  1983       hints.ai_protocol = IPPROTO_TCP;
  1984       hints.ai_flags = AI_ADDRCONFIG | AI_PASSIVE;
  1985       errcode = getaddrinfo(host, port, &hints, &res);
  1986       if (errcode) {
  1987         freeaddrinfo(res);
  1988         if (errcode == EAI_SYSTEM) {
  1989           char errmsg[MOONBR_MAXSTRERRORLEN] = MOONBR_STRERROR_R_MSG;
  1990           strerror_r(errno, errmsg, MOONBR_MAXSTRERRORLEN);  /* use thread-safe call in case child created threads */
  1991           luaL_error(L, "Could not resolve host: %s: %s", gai_strerror(errcode), errmsg);
  1992         } else {
  1993           luaL_error(L, "Could not resolve host: %s", gai_strerror(errcode));
  1994         }
  1995       }
  1996       for (addrinfo=res; addrinfo; addrinfo=addrinfo->ai_next) {
  1997         if (addrinfo->ai_family == AF_INET6) goto moonbr_listen_init_pool_found;
  1998       }
  1999       for (addrinfo=res; addrinfo; addrinfo=addrinfo->ai_next) {
  2000         if (addrinfo->ai_family == AF_INET) goto moonbr_listen_init_pool_found;
  2001       }
  2002       addrinfo = res;
  2003       moonbr_listen_init_pool_found:
  2004       if (addrinfo->ai_addrlen > sizeof(listener->type_specific.socket.addr)) {
  2005         moonbr_log(LOG_CRIT, "Size of ai_addrlen is unexpectedly big (should not happen)");
  2006         moonbr_terminate_error();
  2007       }
  2008       memcpy(&listener->type_specific.socket.addr, addrinfo->ai_addr, addrinfo->ai_addrlen);
  2009       listener->type_specific.socket.addrlen = addrinfo->ai_addrlen;
  2010       switch (addrinfo->ai_family) {
  2011       case AF_INET6:
  2012         ip = inet_ntop(
  2013           addrinfo->ai_family,
  2014           &((struct sockaddr_in6 *)addrinfo->ai_addr)->sin6_addr,
  2015           listener->proto_specific.tcp.ip,
  2016           INET6_ADDRSTRLEN
  2017         );
  2018         if (!ip) {
  2019           moonbr_log(LOG_CRIT, "System error in inet_ntop call: %s", strerror(errno));
  2020           moonbr_terminate_error();
  2021         }
  2022         listener->proto_specific.tcp.port = ntohs(((struct sockaddr_in6 *)addrinfo->ai_addr)->sin6_port);
  2023         break;
  2024       case AF_INET:
  2025         ip = inet_ntop(
  2026           addrinfo->ai_family,
  2027           &((struct sockaddr_in *)addrinfo->ai_addr)->sin_addr,
  2028           listener->proto_specific.tcp.ip,
  2029           INET6_ADDRSTRLEN
  2030         );
  2031         if (!ip) {
  2032           moonbr_log(LOG_CRIT, "System error in inet_ntop call: %s", strerror(errno));
  2033           moonbr_terminate_error();
  2034         }
  2035         listener->proto_specific.tcp.port = ntohs(((struct sockaddr_in *)addrinfo->ai_addr)->sin_port);
  2036         break;
  2037       default:
  2038         strcpy(listener->proto_specific.tcp.ip, "unknown");
  2039         listener->proto_specific.tcp.port = 0;
  2040       }
  2041       listener->proto = MOONBR_PROTO_TCP;
  2042     } else if (proto) {
  2043       luaL_error(L, "Unknown protocol \"%s\"", proto);
  2044     } else {
  2045       luaL_error(L, "No valid protocol specified; use listen{{proto=..., ...}, ...}");
  2046     }
  2047   }
  2048   lua_settop(L, 2);
  2049   if (dynamic) {
  2050     moonbr_listen_init_pool_forkoption("pre_fork", pre_fork, 1);
  2051     moonbr_listen_init_pool_forkoption("min_fork", min_fork, pool->pre_fork > 2 ? pool->pre_fork : 2);
  2052     moonbr_listen_init_pool_forkoption("max_fork", max_fork, pool->min_fork > 16 ? pool->min_fork : 16);
  2053     if (!moonbr_listen_init_pool_timeoption("fork_delay", fork_delay, 0, 250000)) {
  2054       luaL_error(L, "Option \"fork_delay\" is expected to be a non-negative number");
  2055     }
  2056     if (!moonbr_listen_init_pool_timeoption("fork_error_delay", fork_error_delay, 2, 0)) {
  2057       luaL_error(L, "Option \"fork_error_delay\" is expected to be a non-negative number");
  2058     }
  2059     if (!moonbr_listen_init_pool_timeoption("exit_delay", exit_delay, 60, 0)) {
  2060       luaL_error(L, "Option \"exit_delay\" is expected to be a non-negative number");
  2061     }
  2062     if (timercmp(&pool->fork_error_delay, &pool->fork_delay, <)) {
  2063       pool->fork_error_delay = pool->fork_delay;
  2064     }
  2065     if (!moonbr_listen_init_pool_timeoption("idle_timeout", idle_timeout, 0, 0)) {
  2066       luaL_error(L, "Option \"idle_timeout\" is expected to be a non-negative number");
  2067     }
  2068   } else {
  2069     pool->pre_fork = 0;
  2070     pool->min_fork = pool->listener_count;
  2071     pool->max_fork = pool->listener_count;
  2072   }
  2073   lua_getfield(L, 2, "memory_limit");
  2074   if (!lua_isnil(L, -1)) {
  2075     int isnum;
  2076     lua_Number n;
  2077     n = lua_tonumberx(L, -1, &isnum);
  2078     if (n < 0 || !isnum) {
  2079       luaL_error(L, "Option \"memory_limit\" is expected to be a non-negative number");
  2080     }
  2081     pool->memory_limit = n;
  2082   }
  2083   lua_settop(L, 2);
  2084   lua_getfield(L, 2, "prepare");
  2085   if (!lua_isnil(L, -1) && !lua_isfunction(L, -1)) {
  2086     luaL_error(L, "Option \"prepare\" must be nil or a function");
  2087   }
  2088   lua_rawsetp(L, LUA_REGISTRYINDEX, moonbr_luakey_prepare_func(pool));
  2089   lua_getfield(L, 2, "connect");
  2090   if (!lua_isfunction(L, -1)) {
  2091     luaL_error(L, "Option \"connect\" must be a function; use listen{{...}, {...}, connect=function(socket) ... end, ...}");
  2092   }
  2093   lua_rawsetp(L, LUA_REGISTRYINDEX, moonbr_luakey_connect_func(pool));
  2094   lua_getfield(L, 2, "finish");
  2095   if (!lua_isnil(L, -1) && !lua_isfunction(L, -1)) {
  2096     luaL_error(L, "Option \"finish\" must be nil or a function");
  2097   }
  2098   lua_rawsetp(L, LUA_REGISTRYINDEX, moonbr_luakey_finish_func(pool));
  2099   return 0;
  2100 }
  2102 static int moonbr_listen(lua_State *L) {
  2103   struct moonbr_pool *pool;
  2104   lua_Integer listener_count;
  2105   if (moonbr_booted) luaL_error(L, "Moonbridge bootup is already complete");
  2106   luaL_checktype(L, 1, LUA_TTABLE);
  2107   listener_count = luaL_len(L, 1);
  2108   if (!listener_count) luaL_error(L, "No listen ports specified; use listen{{proto=..., port=...},...}");
  2109   if (listener_count > 100) luaL_error(L, "Too many listeners");
  2110   pool = moonbr_create_pool(listener_count);
  2111   lua_pushcfunction(L, moonbr_listen_init_pool);
  2112   lua_pushlightuserdata(L, pool);
  2113   lua_pushvalue(L, 1);
  2114   if (lua_pcall(L, 2, 0, 0)) goto moonbr_listen_error;
  2115   {
  2116     int i;
  2117     i = moonbr_start_pool(pool);
  2118     if (i >= 0) {
  2119       lua_pushfstring(L, "Could not initialize listener #%d: %s", i+1, strerror(errno));
  2120       moonbr_listen_error:
  2121       moonbr_destroy_pool(pool);
  2122       lua_pushnil(L);
  2123       lua_rawsetp(L, LUA_REGISTRYINDEX, moonbr_luakey_prepare_func(pool));
  2124       lua_pushnil(L);
  2125       lua_rawsetp(L, LUA_REGISTRYINDEX, moonbr_luakey_connect_func(pool));
  2126       lua_pushnil(L);
  2127       lua_rawsetp(L, LUA_REGISTRYINDEX, moonbr_luakey_finish_func(pool));
  2128       lua_error(L);
  2129     }
  2130   }
  2131   return 0;
  2132 }
  2135 /*** Function to modify Lua's library path and/or cpath ***/
  2137 #if defined(MOONBR_LUA_PATH) || defined(MOONBR_LUA_CPATH)
  2138 static void moonbr_modify_path(lua_State *L, char *key, char *value) {
  2139   int stackbase;
  2140   stackbase = lua_gettop(L);
  2141   lua_getglobal(L, "package");
  2142   lua_getfield(L, stackbase+1, key);
  2143   {
  2144     const char *current_str;
  2145     size_t current_strlen;
  2146     luaL_Buffer buf;
  2147     current_str = lua_tolstring(L, stackbase+2, ¤t_strlen);
  2148     luaL_buffinit(L, &buf);
  2149     if (current_str) {
  2150       lua_pushvalue(L, stackbase+2);
  2151       luaL_addvalue(&buf);
  2152       if (current_strlen && current_str[current_strlen-1] != ';') {
  2153         luaL_addchar(&buf, ';');
  2154       }
  2155     }
  2156     luaL_addstring(&buf, value);
  2157     luaL_pushresult(&buf);
  2158   }
  2159   lua_setfield(L, stackbase+1, key);
  2160   lua_settop(L, stackbase);
  2161 }
  2162 #endif
  2165 /*** Main function and command line invokation ***/
  2167 static void moonbr_usage(int err, const char *cmd) {
  2168   FILE *out;
  2169   out = err ? stderr : stdout;
  2170   if (!cmd) cmd = "moonbridge";
  2171   fprintf(out, "Get this help message: %s {-h|--help}\n", cmd);
  2172   fprintf(out, "Usage: %s \\\n", cmd);
  2173   fprintf(out, "           [-b|--background] \\\n");
  2174   fprintf(out, "           [-d|--debug] \\\n");
  2175   fprintf(out, "           [-f|--logfacility {DAEMON|USER|0|1|...|7}] \\\n");
  2176   fprintf(out, "           [-i|--logident <syslog ident> \\\n");
  2177   fprintf(out, "           [-l|--logfile <logfile>] \\\n");
  2178   fprintf(out, "           [-p|--pidfile <pidfile>] \\\n");
  2179   fprintf(out, "           [-s|--stats] \\\n");
  2180   fprintf(out, "           -- <Lua script> [<cmdline options for Lua script>]\n");
  2181   exit(err);
  2182 }
  2184 #define moonbr_usage_error() moonbr_usage(MOONBR_EXITCODE_CMDLINEERROR, argc ? argv[0] : NULL)
  2186 int main(int argc, char **argv) {
  2187   {
  2188     int daemonize = 0;
  2189     int log_facility = LOG_USER;
  2190     const char *log_ident = "moonbridge";
  2191     const char *log_filename = NULL;
  2192     const char *pid_filename = NULL;
  2193     int option;
  2194     struct option longopts[] = {
  2195       { "background",  no_argument,       NULL, 'b' },
  2196       { "debug",       no_argument,       NULL, 'd' },
  2197       { "logfacility", required_argument, NULL, 'f' },
  2198       { "help",        no_argument,       NULL, 'h' },
  2199       { "logident",    required_argument, NULL, 'i' },
  2200       { "logfile",     required_argument, NULL, 'l' },
  2201       { "pidfile",     required_argument, NULL, 'p' },
  2202       { "stats",       no_argument,       NULL, 's' },
  2203       { NULL,          0,                 NULL, 0   }
  2204     };
  2205     while ((option = getopt_long(argc, argv, "bdf:hi:l:p:s", longopts, NULL)) != -1) {
  2206       switch (option) {
  2207       case 'b':
  2208         daemonize = 1;
  2209         break;
  2210       case 'd':
  2211         moonbr_debug = 1;
  2212         moonbr_stat = 1;
  2213         break;
  2214       case 'f':
  2215         if (!strcmp(optarg, "DAEMON")) {
  2216           log_facility = LOG_DAEMON;
  2217         } else if (!strcmp(optarg, "USER")) {
  2218           log_facility = LOG_USER;
  2219         } else if (!strcmp(optarg, "0")) {
  2220           log_facility = LOG_LOCAL0;
  2221         } else if (!strcmp(optarg, "1")) {
  2222           log_facility = LOG_LOCAL1;
  2223         } else if (!strcmp(optarg, "2")) {
  2224           log_facility = LOG_LOCAL2;
  2225         } else if (!strcmp(optarg, "3")) {
  2226           log_facility = LOG_LOCAL3;
  2227         } else if (!strcmp(optarg, "4")) {
  2228           log_facility = LOG_LOCAL4;
  2229         } else if (!strcmp(optarg, "5")) {
  2230           log_facility = LOG_LOCAL5;
  2231         } else if (!strcmp(optarg, "6")) {
  2232           log_facility = LOG_LOCAL6;
  2233         } else if (!strcmp(optarg, "7")) {
  2234           log_facility = LOG_LOCAL7;
  2235         } else {
  2236           moonbr_usage_error();
  2237         }
  2238         moonbr_use_syslog = 1;
  2239         break;
  2240       case 'h':
  2241         moonbr_usage(MOONBR_EXITCODE_GRACEFUL, argv[0]);
  2242         break;
  2243       case 'i':
  2244         log_ident = optarg;
  2245         moonbr_use_syslog = 1;
  2246         break;
  2247       case 'l':
  2248         log_filename = optarg;
  2249         break;
  2250       case 'p':
  2251         pid_filename = optarg;
  2252         break;
  2253       case 's':
  2254         moonbr_stat = 1;
  2255         break;
  2256       default:
  2257         moonbr_usage_error();
  2258       }
  2259     }
  2260     if (argc - optind < 1) moonbr_usage_error();
  2261     if (pid_filename) {
  2262       pid_t otherpid;
  2263       while ((moonbr_pidfh = pidfile_open(pid_filename, 0644, &otherpid)) == NULL) {
  2264         if (errno == EEXIST) {
  2265           if (otherpid == -1) {
  2266             fprintf(stderr, "PID file \"%s\" is already locked\n", pid_filename);
  2267           } else {
  2268             fprintf(stderr, "PID file \"%s\" is already locked by process with PID: %i\n", pid_filename, (int)otherpid);
  2269           }
  2270           exit(MOONBR_EXITCODE_ALREADYRUNNING);
  2271         } else if (errno != EINTR) {
  2272           fprintf(stderr, "Could not write PID file \"%s\": %s\n", pid_filename, strerror(errno));
  2273           exit(MOONBR_EXITCODE_STARTUPERROR);
  2274         }
  2275       }
  2276     }
  2277     if (log_filename) {
  2278       int logfd;
  2279       while (
  2280         ( logfd = flopen(
  2281             log_filename,
  2282             O_WRONLY|O_NONBLOCK|O_CREAT|O_APPEND|O_CLOEXEC,
  2283             0640
  2284           )
  2285         ) < 0
  2286       ) {
  2287         if (errno == EWOULDBLOCK) {
  2288           fprintf(stderr, "Logfile \"%s\" is locked\n", log_filename);
  2289           exit(MOONBR_EXITCODE_ALREADYRUNNING);
  2290         } else if (errno != EINTR) {
  2291           fprintf(stderr, "Could not open logfile \"%s\": %s\n", log_filename, strerror(errno));
  2292           exit(MOONBR_EXITCODE_STARTUPERROR);
  2293         }
  2294       }
  2295       moonbr_logfile = fdopen(logfd, "a");
  2296       if (!moonbr_logfile) {
  2297         fprintf(stderr, "Could not open write stream to logfile \"%s\": %s\n", log_filename, strerror(errno));
  2298         exit(MOONBR_EXITCODE_STARTUPERROR);
  2299       }
  2300     }
  2301     if (daemonize == 0 && !moonbr_logfile) moonbr_logfile = stderr;
  2302     if (moonbr_logfile) setlinebuf(moonbr_logfile);
  2303     else moonbr_use_syslog = 1;
  2304     if (moonbr_use_syslog) openlog(log_ident, LOG_NDELAY | LOG_PID, log_facility);
  2305     if (daemonize) {
  2306       if (daemon(1, 0)) {
  2307         moonbr_log(LOG_ERR, "Could not daemonize moonbridge process");
  2308         moonbr_terminate_error();
  2309       }
  2310     }
  2311   }
  2312   moonbr_log(LOG_NOTICE, "Starting moonbridge server");
  2313   if (moonbr_pidfh && pidfile_write(moonbr_pidfh)) {
  2314     moonbr_log(LOG_ERR, "Could not write pidfile (after locking)");
  2315   }
  2316   {
  2317     lua_State *L;
  2318     L = lua_newstate(moonbr_alloc, NULL);
  2319     if (!L) {
  2320       moonbr_log(LOG_CRIT, "Could not initialize Lua state");
  2321       moonbr_terminate_error();
  2322     }
  2323     lua_atpanic(L, moonbr_lua_panic);
  2324     lua_pushliteral(L, MOONBR_VERSION_STRING);
  2325     lua_setglobal(L, "_MOONBRIDGE_VERSION");
  2326     luaL_openlibs(L);
  2327     luaL_requiref(L, "moonbridge_io", luaopen_moonbridge_io, 1);
  2328     lua_pop(L, 1);
  2329 #ifdef MOONBR_LUA_PATH
  2330     moonbr_modify_path(L, "path", MOONBR_LUA_PATH);
  2331 #endif
  2332 #ifdef MOONBR_LUA_CPATH
  2333     moonbr_modify_path(L, "cpath", MOONBR_LUA_CPATH);
  2334 #endif
  2335     lua_pushcfunction(L, moonbr_timeout);
  2336     lua_setglobal(L, "timeout");
  2337     lua_pushcfunction(L, moonbr_listen);
  2338     lua_setglobal(L, "listen");
  2339     lua_pushcfunction(L, moonbr_addtraceback);  /* on stack position 1 */
  2340     moonbr_log(LOG_INFO, "Loading \"%s\"", argv[optind]);
  2341     if (luaL_loadfile(L, argv[optind])) {
  2342       moonbr_log(LOG_ERR, "Error while loading \"%s\": %s", argv[optind], lua_tostring(L, -1));
  2343       moonbr_terminate_error();
  2344     }
  2345     { int i; for (i=optind+1; i<argc; i++) lua_pushstring(L, argv[i]); }
  2346     if (lua_pcall(L, argc-(optind+1), 0, 1)) {
  2347       moonbr_log(LOG_ERR, "Error while executing \"%s\": %s", argv[optind], lua_tostring(L, -1));
  2348       moonbr_terminate_error();
  2349     }
  2350     if (!moonbr_first_pool) {
  2351       moonbr_log(LOG_WARNING, "No listener initialized.");
  2352       moonbr_terminate_error();
  2353     }
  2354     lua_getglobal(L, "listen");
  2355     lua_pushcfunction(L, moonbr_listen);
  2356     if (lua_compare(L, -2, -1, LUA_OPEQ)) {
  2357       lua_pushnil(L);
  2358       lua_setglobal(L, "listen");
  2359     }
  2360     lua_settop(L, 1);
  2361     lua_gc(L, LUA_GCCOLLECT, 0);  /* collect garbage before forking later */
  2362     moonbr_run(L);
  2363   }
  2364   return 0;
  2365 }
