PageRenderTime 62ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/liquidfeedback/moonbridge/moonbridge.c

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