PageRenderTime 52ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 1ms

/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

Large files files are truncated, but you can click here to view the full file

  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 moon

Large files files are truncated, but you can click here to view the full file