1 /* This file is part of Mailfromd.
2 Copyright (C) 2005-2021 Sergey Poznyakoff
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 3, or (at your option)
7 any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
16
17 #ifdef HAVE_CONFIG_H
18 # include <config.h>
19 #endif
20
21 #include <sys/types.h>
22 #include <sys/wait.h>
23 #include <sys/stat.h>
24 #include <unistd.h>
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <stdarg.h>
28 #include <syslog.h>
29 #include <signal.h>
30 #include <sys/socket.h>
31 #include <sys/un.h>
32 #include <netinet/in.h>
33 #include <arpa/inet.h>
34 #include <netdb.h>
35
36 #include <mailutils/mailutils.h>
37 #include <mailutils/alloc.h>
38
39 #include "libmf.h"
40 #include "srvman.h"
41
42 struct mfd_server {
43 struct mfd_server *prev; /* Link to the previous server */
44 struct mfd_server *next; /* Link to the next server */
45 char *id; /* Server ID */
46 struct sockaddr *sa; /* Socket address */
47 socklen_t salen; /* Length of the sa */
48 int backlog; /* Backlog value for listen(2) */
49 int fd; /* Socket descriptor */
50 int flags; /* SRV_* flags */
51 mfd_server_prefork_hook_t prefork_hook; /* Pre-fork function */
52 mfd_server_func_t conn; /* Connection handler */
53 mfd_srvman_hook_t free_hook;
54 void *data; /* Server-specific data */
55 mu_acl_t acl; /* Access Control List */
56 size_t max_children; /* Maximum number of sub-processes to run. */
57 size_t num_children; /* Current number of running sub-processes. */
58 pid_t *pidtab; /* Array of child PIDs */
59 size_t pidtab_size; /* Number of elements in pidtab */
60 };
61
62
63 struct srvman_param srvman_param;
64
65
66 typedef RETSIGTYPE (*sig_handler_t) (int);
67
68 union srvman_sockaddr {
69 struct sockaddr sa;
70 struct sockaddr_in s_in;
71 struct sockaddr_un s_un;
72 };
73
74 struct srvman {
75 struct mfd_server *head, *tail; /* List of servers */
76 size_t num_children; /* Current number of running
77 sub-processes. */
78 sigset_t sigmask; /* A set of signals to handle by the
79 manager. */
80 sig_handler_t sigtab[NSIG]; /* Keeps old signal handlers. */
81 };
82
83 static struct srvman srvman;
84 static mu_debug_handle_t debug_handle;
85
86 static sig_handler_t
set_signal(int sig,sig_handler_t handler)87 set_signal(int sig, sig_handler_t handler)
88 {
89 #ifdef HAVE_SIGACTION
90 struct sigaction act, oldact;
91 act.sa_handler = handler;
92 sigemptyset(&act.sa_mask);
93 act.sa_flags = 0;
94 sigaction(sig, &act, &oldact);
95 return oldact.sa_handler;
96 #else
97 return signal(sig, handler);
98 #endif
99 }
100
101 static int volatile need_cleanup;
102 static int volatile stop;
103
104 void
mfd_srvman_stop()105 mfd_srvman_stop()
106 {
107 stop = 1;
108 }
109
110 static RETSIGTYPE
srvman_signal(int signo)111 srvman_signal (int signo)
112 {
113 switch (signo) {
114 case SIGCHLD:
115 need_cleanup = 1;
116 break;
117
118 default:
119 /* FIXME: */
120 stop = 1;
121 break;
122 }
123 #ifndef HAVE_SIGACTION
124 signal(signo, srvman_signal);
125 #endif
126 }
127
128 static void
set_signal_handlers()129 set_signal_handlers()
130 {
131 int i;
132
133 for (i = 0; i < NSIG; i++)
134 if (sigismember (&srvman.sigmask, i))
135 srvman.sigtab[i] = set_signal(i, srvman_signal);
136 }
137
138 static void
restore_signal_handlers()139 restore_signal_handlers()
140 {
141 int i;
142
143 for (i = 0; i < NSIG; i++)
144 if (sigismember (&srvman.sigmask, i))
145 set_signal(i, srvman.sigtab[i]);
146 }
147
148
149 struct sockaddr *
srvman_url_to_sockaddr(mu_url_t url,socklen_t * psalen)150 srvman_url_to_sockaddr(mu_url_t url, socklen_t *psalen)
151 {
152 int rc;
153 const char *sval;
154 struct sockaddr *sa;
155 socklen_t socklen;
156
157 if (rc = mu_url_sget_scheme(url, &sval)) {
158 mu_error(_("cannot get URL scheme: %s"), mu_strerror(rc));
159 return NULL;
160 }
161
162 if (strcmp(sval, "unix") == 0
163 || strcmp(sval, "local") == 0) {
164 struct sockaddr_un *s_un;
165 size_t slen;
166
167 rc = mu_url_sget_path(url, &sval);
168 if (rc) {
169 if (rc == MU_ERR_NOENT)
170 rc = mu_url_sget_host(url, &sval);
171 if (rc) {
172 mu_error(_("cannot get URL path: %s"),
173 mu_strerror(rc));
174 return NULL;
175 }
176 }
177 slen = strlen(sval);
178 if (slen >= sizeof s_un->sun_path) {
179 mu_error(_("socket path name too long: %s"),
180 sval);
181 return NULL;
182 }
183 socklen = sizeof (s_un[0]);
184 sa = mu_alloc (socklen);
185 s_un = (struct sockaddr_un *)sa;
186 s_un->sun_family = AF_UNIX;
187 strcpy(s_un->sun_path, sval);
188 } else if (strcmp(sval, "inet") == 0) {
189 struct sockaddr_in *s_in;
190 unsigned n;
191 short port;
192 struct hostent *hp;
193
194 if (rc = mu_url_get_port(url, &n)) {
195 mu_error(_("cannot get URL port: %s"),
196 mu_strerror(rc));
197 return NULL;
198 }
199
200 if (n == 0 || (port = n) != n) {
201 mu_error(_("port out of range: %u"), n);
202 return NULL;
203 }
204
205 if (rc = mu_url_sget_host(url, &sval)) {
206 mu_error(_("cannot get URL host: %s"),
207 mu_strerror(rc));
208 return NULL;
209 }
210
211 hp = gethostbyname(sval);
212 if (!hp) {
213 mu_error(_("unknown host name: %s"), sval);
214 return NULL;
215 }
216
217 if (hp->h_addrtype != AF_INET || hp->h_length != 4) {
218 mu_error(_("unsupported address family"));
219 return NULL;
220 }
221
222 socklen = sizeof s_in[0];
223 sa = mu_alloc(socklen);
224 s_in = (struct sockaddr_in *)sa;
225 s_in->sin_family = AF_INET;
226 memcpy(&s_in->sin_addr, hp->h_addr, 4);
227 s_in->sin_port = htons(port);
228 #ifdef GACOPYZ_IPV6
229 } else if (strcmp(sval, "inet6") == 0) {
230 struct addrinfo hints;
231 struct addrinfo *res;
232 const char *host = NULL;
233 const char *port;
234
235 memset(&hints, 0, sizeof(hints));
236 hints.ai_family = AF_INET6;
237 hints.ai_socktype = SOCK_STREAM;
238
239 rc = mu_url_sget_host(url, &host);
240 if (rc == MU_ERR_NOENT)
241 hints.ai_flags |= AI_PASSIVE;
242 else if (rc) {
243 mu_error(_("cannot get URL host: %s"),
244 mu_strerror(rc));
245 return NULL;
246 }
247
248 if (mu_url_sget_portstr(url, &port)) {
249 mu_error(_("cannot get URL port: %s"),
250 mu_strerror(rc));
251 return NULL;
252 }
253
254 rc = getaddrinfo(host, port, &hints, &res);
255
256 switch (rc) {
257 case 0:
258 break;
259 case EAI_SYSTEM:
260 mu_error(_("%s:%s: cannot parse address: %s"),
261 host ? host : "NULL", port, strerror(errno));
262 return NULL;
263
264 case EAI_BADFLAGS:
265 case EAI_SOCKTYPE:
266 mu_error(_("%s:%d: internal error converting %s:%s"),
267 __FILE__, __LINE__,
268 host ? host : "NULL", port);
269 return NULL;
270
271 case EAI_MEMORY:
272 mu_alloc_die();
273
274 default:
275 mu_error("%s:%s: %s",
276 host ? host : "NULL", port,
277 gai_strerror(rc));
278 return NULL;
279 }
280
281 if (res->ai_next) {
282 char hostbuf[NI_MAXHOST], servbuf[NI_MAXSERV];
283 rc = getnameinfo(res->ai_addr, res->ai_addrlen,
284 hostbuf, sizeof hostbuf,
285 servbuf, sizeof servbuf,
286 NI_NUMERICHOST|NI_NUMERICSERV);
287
288 mu_diag_output(MU_DIAG_WARNING,
289 _("%s:%s resolves to several addresses; "
290 "using %s:%s"),
291 host, port, hostbuf, servbuf);
292 }
293
294 socklen = res->ai_addrlen;
295 sa = mu_alloc(socklen);
296 memcpy(sa, res->ai_addr, res->ai_addrlen);
297 freeaddrinfo(res);
298 #endif
299 } else {
300 mu_error(_("unsupported protocol: %s"), sval);
301 return NULL;
302 }
303
304 if (psalen)
305 *psalen = socklen;
306 return sa;
307 }
308
309
310
311 /* Yield 1 if SRV has run out of the children limit */
312 #define SERVER_BUSY(srv) \
313 ((srv)->max_children && (srv)->num_children >= (srv)->max_children)
314
315 static void
register_child(struct mfd_server * srv,pid_t pid)316 register_child(struct mfd_server *srv, pid_t pid)
317 {
318 size_t i;
319
320 mu_debug(debug_handle, MU_DEBUG_TRACE5,
321 ("registering child %lu", (unsigned long)pid));
322 for (i = 0; i < srv->pidtab_size; i++)
323 if (srv->pidtab[i] == 0)
324 break;
325 if (i == srv->pidtab_size) {
326 int j;
327 if (srv->pidtab_size == 0)
328 srv->pidtab_size = DEFAULT_PIDTAB_SIZE;
329 srv->pidtab = mu_2nrealloc(srv->pidtab,
330 &srv->pidtab_size,
331 sizeof(srv->pidtab[0]));
332 for (j = i; j < srv->pidtab_size; j++)
333 srv->pidtab[j] = 0;
334
335 }
336 srv->pidtab[i] = pid;
337 srv->num_children++;
338 srvman.num_children++;
339 }
340
341 static void
report_exit_status(const char * tag,pid_t pid,int status,int expect_term)342 report_exit_status(const char *tag, pid_t pid, int status, int expect_term)
343 {
344 if (WIFEXITED(status)) {
345 if (WEXITSTATUS(status) == 0)
346 mu_debug(debug_handle, MU_DEBUG_TRACE0,
347 ("%s [%lu] exited successfully",
348 tag, (unsigned long) pid));
349 else
350 mu_error(_("%s [%lu] failed with status %d"),
351 tag, (unsigned long) pid,
352 WEXITSTATUS(status));
353 } else if (WIFSIGNALED (status)) {
354 if (expect_term && WTERMSIG(status) == SIGTERM)
355 mu_debug(debug_handle, MU_DEBUG_TRACE0,
356 ("%s [%lu] terminated on signal %d",
357 tag, (unsigned long) pid,
358 WTERMSIG(status)));
359 else
360 mu_error(_("%s [%lu] terminated on signal %d"),
361 tag, (unsigned long) pid,
362 WTERMSIG(status));
363 } else if (WIFSTOPPED(status))
364 mu_error(_("%s [%lu] stopped on signal %d"),
365 tag, (unsigned long) pid,
366 WSTOPSIG(status));
367 else
368 mu_error(_("%s [%lu] terminated with unrecognized status"),
369 tag, (unsigned long) pid);
370 }
371
372 /* Remove (unregister) PID from the list of running instances and
373 log its exit STATUS.
374 Return 1 to command main loop to recompute the set of active
375 descriptors. */
376 static int
unregister_child(pid_t pid,int status)377 unregister_child(pid_t pid, int status)
378 {
379 struct mfd_server *srv;
380
381 mu_debug(debug_handle, MU_DEBUG_TRACE5,
382 ("unregistering child %lu (status %x)",
383 (unsigned long)pid, status));
384 for (srv = srvman.head; srv; srv = srv->next) {
385 size_t i;
386
387 for (i = 0; i < srv->pidtab_size; i++)
388 if (srv->pidtab[i] == pid) {
389 int rc = SERVER_BUSY(srv);
390 srv->pidtab[i] = 0;
391 srv->num_children--;
392 srvman.num_children--;
393 /* FIXME: expect_term? */
394 report_exit_status(srv->id, pid, status, 0);
395 return rc;
396 }
397 }
398 /* FIXME */
399 return 0;
400 }
401
402 static int
children_cleanup()403 children_cleanup()
404 {
405 int rc = 0;
406 pid_t pid;
407 int status;
408
409 mu_debug(debug_handle, MU_DEBUG_TRACE1, ("cleaning up subprocesses"));
410 while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
411 rc |= unregister_child(pid, status);
412 return rc;
413 }
414
415
416 static void
server_remove(struct mfd_server * srv)417 server_remove(struct mfd_server *srv)
418 {
419 struct mfd_server *p;
420
421 mu_debug(debug_handle, MU_DEBUG_TRACE4,
422 ("removing server %s", srv->id));
423 if ((p = srv->prev) != NULL)
424 p->next = srv->next;
425 else
426 srvman.head = srv->next;
427
428 if ((p = srv->next) != NULL)
429 p->prev = srv->prev;
430 else
431 srvman.tail = srv->prev;
432 }
433
434 static void
server_signal_children(struct mfd_server * srv,int sig)435 server_signal_children(struct mfd_server *srv, int sig)
436 {
437 int i;
438
439 mu_debug(debug_handle, MU_DEBUG_TRACE4,
440 ("server %s: sending children signal %d", srv->id, sig));
441 for (i = 0; i < srv->pidtab_size; i++)
442 if (srv->pidtab[i])
443 kill(srv->pidtab[i], sig);
444 }
445
446 void
mfd_server_shutdown(struct mfd_server * srv)447 mfd_server_shutdown(struct mfd_server *srv)
448 {
449 if (srv->fd == -1)
450 return;
451
452 mu_debug(debug_handle, MU_DEBUG_TRACE1,
453 ("shutting down %s", srv->id));
454 close(srv->fd);
455 srv->fd = -1;
456 }
457
458 struct mfd_server *
mfd_server_new(const char * id,mu_url_t url,mfd_server_func_t conn,int flags)459 mfd_server_new(const char *id, mu_url_t url, mfd_server_func_t conn, int flags)
460 {
461 struct mfd_server *srv;
462 struct sockaddr *sa;
463 socklen_t salen;
464
465 sa = srvman_url_to_sockaddr(url, &salen);
466 if (!sa)
467 return NULL;
468
469 srv = mu_zalloc(sizeof(*srv));
470 srv->id = mu_strdup(id);
471 srv->sa = sa;
472 srv->salen = salen;
473 srv->backlog = 8;
474 srv->conn = conn;
475 srv->flags = flags;
476 return srv;
477 }
478
479 void
mfd_server_free(struct mfd_server * srv)480 mfd_server_free(struct mfd_server *srv)
481 {
482 server_remove(srv);
483 if (srv->free_hook)
484 srv->free_hook(srv->data);
485 free(srv->id);
486 free(srv->sa);
487 mu_acl_destroy(&srv->acl);
488 free(srv->pidtab);
489 free(srv);
490 }
491
492 void
mfd_server_set_prefork_hook(struct mfd_server * srv,mfd_server_prefork_hook_t hook)493 mfd_server_set_prefork_hook(struct mfd_server *srv,
494 mfd_server_prefork_hook_t hook)
495 {
496 srv->prefork_hook = hook;
497 }
498
499 void
mfd_server_set_data(struct mfd_server * srv,void * data,mfd_srvman_hook_t free_hook)500 mfd_server_set_data(struct mfd_server *srv,
501 void *data,
502 mfd_srvman_hook_t free_hook)
503 {
504 srv->data = data;
505 srv->free_hook = free_hook;
506 }
507
508 void
mfd_server_set_max_children(struct mfd_server * srv,size_t n)509 mfd_server_set_max_children(struct mfd_server *srv, size_t n)
510 {
511 srv->max_children = n;
512 }
513
514 void
mfd_server_set_acl(struct mfd_server * srv,mu_acl_t acl)515 mfd_server_set_acl(struct mfd_server *srv, mu_acl_t acl)
516 {
517 srv->acl = acl;
518 }
519
520 void
mfd_server_set_backlog(struct mfd_server * srv,int value)521 mfd_server_set_backlog(struct mfd_server *srv, int value)
522 {
523 srv->backlog = value;
524 }
525
526 void
mfd_srvman_attach_server(struct mfd_server * srv)527 mfd_srvman_attach_server(struct mfd_server *srv)
528 {
529 srv->next = NULL;
530 srv->prev = srvman.tail;
531 if (srvman.tail)
532 srvman.tail->next = srv;
533 else
534 srvman.head = srv;
535 srvman.tail = srv;
536 }
537
538
539 static int
check_acl(const char * id,mu_acl_t acl,struct sockaddr * sa,socklen_t salen)540 check_acl(const char *id, mu_acl_t acl, struct sockaddr *sa, socklen_t salen)
541 {
542 mu_acl_result_t res;
543 int rc = mu_acl_check_sockaddr(acl, sa, salen, &res);
544 char *p = mu_sys_sockaddr_to_astr(sa, salen);
545
546 if (rc) {
547 mu_error(_("server %s: access from %s blocked: "
548 "cannot check ACLs: %s"),
549 id, p, mu_strerror(rc));
550 } else {
551 switch (res) {
552 case mu_acl_result_undefined:
553 mu_diag_output(MU_DIAG_INFO,
554 _("server %s: undefined ACL result; "
555 "access from %s allowed"),
556 id, p);
557 break;
558
559 case mu_acl_result_accept:
560 mu_debug(debug_handle, MU_DEBUG_TRACE0,
561 ("server %s: allowed access from %s", id, p));
562 break;
563
564 case mu_acl_result_deny:
565 mu_error(_("server %s: access from %s blocked"),
566 id, p);
567 rc = 1;
568 }
569 }
570 free(p);
571 return rc;
572 }
573
574 static void
server_run(int connfd,struct mfd_server * srv,struct sockaddr * sa,socklen_t salen)575 server_run(int connfd, struct mfd_server *srv,
576 struct sockaddr *sa, socklen_t salen)
577 {
578 if (srvman_param.acl && check_acl(srv->id, srvman_param.acl,
579 sa, salen))
580 return;
581 if (srv->acl && check_acl(srv->id, srv->acl, sa, salen))
582 return;
583
584 if (((srvman_param.flags | srv->flags) & SRV_SINGLE_PROCESS)) {
585 if ((!srvman_param.prefork_hook
586 || srvman_param.prefork_hook(sa, salen,
587 srvman_param.data) == 0)
588 && (!srv->prefork_hook
589 || srv->prefork_hook(srv->id,
590 sa, salen,
591 srv->data,
592 srvman_param.data) == 0))
593 srv->conn(srv->id,
594 connfd, sa, salen,
595 srv->data,
596 srvman_param.data);
597 } else {
598 pid_t pid;
599
600 if (srv->prefork_hook
601 && srv->prefork_hook(srv->id,
602 sa, salen,
603 srv->data, srvman_param.data))
604 return;
605
606 pid = fork();
607 if (pid == -1)
608 mu_error("fork: %s", strerror(errno));
609 else if (pid == 0) {
610 /* Child. */
611 FD_SET(connfd, &srvman_param.keepfds);
612 close_fds_except(&srvman_param.keepfds);
613 restore_signal_handlers();
614 exit(srv->conn(srv->id,
615 connfd,
616 sa, salen,
617 srv->data, srvman_param.data));
618 } else
619 register_child(srv, pid);
620 }
621 }
622
623 /* Accept incoming connection for server SRV.
624 Return 1 to command main loop to recompute the set of active
625 descriptors. */
626 static int
server_accept(struct mfd_server * srv)627 server_accept(struct mfd_server *srv)
628 {
629 int connfd;
630 union srvman_sockaddr client;
631 socklen_t size = sizeof(client);
632
633 if (srv->fd == -1) {
634 mu_error(_("removing shut down server %s"),
635 srv->id);
636 mfd_server_free(srv);
637 return 1;
638 }
639
640 if (SERVER_BUSY(srv)) {
641 mu_error(_("server %s: too many children (%lu)"),
642 srv->id, (unsigned long) srv->num_children);
643 return 1;
644 }
645
646 connfd = accept(srv->fd, &client.sa, &size);
647 if (connfd == -1) {
648 if (errno != EINTR) {
649 mu_error(_("server %s: accept failed: %s"),
650 srv->id, mu_strerror(errno));
651 mfd_server_shutdown(srv);
652 mfd_server_free(srv);
653 return 1;
654 } /* FIXME: Call srv->intr otherwise? */
655 } else {
656 server_run(connfd, srv, &client.sa, size);
657 close(connfd);
658 }
659 return 0;
660 }
661
662 static int
connection_loop(fd_set * fdset)663 connection_loop(fd_set *fdset)
664 {
665 struct mfd_server *srv;
666 int rc = 0;
667 for (srv = srvman.head; srv; ) {
668 struct mfd_server *next = srv->next;
669 if (FD_ISSET(srv->fd, fdset))
670 rc |= server_accept(srv);
671 srv = next;
672 }
673 return rc;
674 }
675
676 int
compute_fdset(fd_set * fdset)677 compute_fdset(fd_set *fdset)
678 {
679 struct mfd_server *p;
680 int maxfd = 0;
681 FD_ZERO(fdset);
682 for (p = srvman.head; p; p = p->next) {
683 if (SERVER_BUSY(p))
684 continue;
685 FD_SET(p->fd, fdset);
686 if (p->fd > maxfd)
687 maxfd = p->fd;
688 }
689 mu_debug(debug_handle, MU_DEBUG_TRACE3,
690 ("recomputed fdset: %d fds", maxfd));
691 return maxfd;
692 }
693
694 void
mfd_srvman_run(sigset_t * set)695 mfd_srvman_run(sigset_t *set)
696 {
697 int recompute_fd = 1;
698 int maxfd;
699 fd_set fdset;
700
701 if (!srvman.head)
702 return;
703
704 mu_debug(debug_handle, MU_DEBUG_TRACE1, ("server manager starting"));
705 if (set)
706 srvman.sigmask = *set;
707 else
708 sigemptyset(&srvman.sigmask);
709 sigaddset(&srvman.sigmask, SIGCHLD);
710 set_signal_handlers();
711 if (srvman_param.shutdown_timeout == 0)
712 srvman_param.shutdown_timeout = DEFAULT_SHUTDOWN_TIMEOUT;
713
714 for (stop = 0; srvman.head && !stop;) {
715 int rc;
716 struct timeval *to;
717 fd_set rdset;
718
719 if (need_cleanup) {
720 need_cleanup = 0;
721 recompute_fd = children_cleanup();
722 }
723
724 if (recompute_fd) {
725 maxfd = compute_fdset(&fdset);
726 recompute_fd = 0;
727 }
728
729 if (!maxfd) {
730 mu_debug(debug_handle,
731 MU_DEBUG_TRACE1, ("no active fds, pausing"));
732 pause();
733 recompute_fd = 1;
734 continue;
735 }
736
737 if (srvman_param.max_children
738 && srvman.num_children >= srvman_param.max_children) {
739 mu_error(_("too many children (%lu)"),
740 (unsigned long) srvman.num_children);
741 pause();
742 continue;
743 }
744
745 if (srvman_param.idle_hook
746 && srvman_param.idle_hook(srvman_param.data)) {
747 mu_debug(debug_handle, MU_DEBUG_TRACE1,
748 ("break requested by idle hook"));
749 break;
750 }
751
752 if (stop)
753 break;
754
755 rdset = fdset;
756 to = NULL; /* FIXME */
757 rc = select(maxfd + 1, &rdset, NULL, NULL, to);
758 if (rc == -1 && errno == EINTR)
759 continue;
760 if (rc < 0) {
761 mu_error(_("select failed: %s"),
762 mu_strerror(errno));
763 break;
764 }
765 recompute_fd = connection_loop(&rdset);
766 }
767
768 restore_signal_handlers();
769 mu_debug(debug_handle, MU_DEBUG_TRACE1, ("server manager finishing"));
770 }
771
772 static int
server_prep(struct mfd_server * srv,int fd)773 server_prep(struct mfd_server *srv, int fd)
774 {
775 struct stat st;
776 struct sockaddr_un *s_un;
777 int t;
778
779 switch (srv->sa->sa_family) {
780 case AF_UNIX:
781 s_un = (struct sockaddr_un *) srv->sa;
782
783 if (stat(s_un->sun_path, &st)) {
784 if (errno != ENOENT) {
785 mu_error(_("%s: file %s exists but cannot be stat'd: %s"),
786 srv->id,
787 s_un->sun_path,
788 mu_strerror(errno));
789 return 1;
790 }
791 } else if (!S_ISSOCK(st.st_mode)) {
792 mu_error(_("%s: file %s is not a socket"),
793 srv->id, s_un->sun_path);
794 return 1;
795 } else if (!(srvman_param.flags & SRV_KEEP_EXISTING)
796 && !(srv->flags & SRV_KEEP_EXISTING)) {
797 if (unlink(s_un->sun_path)) {
798 mu_error(_("%s: cannot unlink file %s: %s"),
799 srv->id, s_un->sun_path,
800 mu_strerror(errno));
801 return 1;
802 }
803 } else {
804 mu_error(_("socket `%s' already exists"),
805 s_un->sun_path);
806 return 1;
807 }
808 break;
809
810 case AF_INET:
811 if (!(srvman_param.flags & SRV_KEEP_EXISTING)
812 && !(srv->flags & SRV_KEEP_EXISTING)) {
813 t = 1;
814 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
815 &t, sizeof(t));
816 }
817 }
818
819 if (bind(fd, srv->sa, srv->salen) == -1) {
820 char *p = mu_sys_sockaddr_to_astr(srv->sa, srv->salen);
821 mu_error(_("%s: cannot bind to %s: %s"),
822 srv->id, p, mu_strerror(errno));
823 free(p);
824 return 1;
825 }
826
827 if (listen(fd, srv->backlog) == -1) {
828 char *p = mu_sys_sockaddr_to_astr(srv->sa, srv->salen);
829 mu_error(_("%s: listen on %s failed: %s"),
830 srv->id, p, mu_strerror(errno));
831 free(p);
832 return 1;
833 }
834 return 0;
835 }
836
837 static int
server_open(struct mfd_server * srv)838 server_open(struct mfd_server *srv)
839 {
840 int fd = socket(srv->sa->sa_family, SOCK_STREAM, 0);
841 if (fd == -1) {
842 mu_error("%s: socket: %s", srv->id, mu_strerror(errno));
843 return 1;
844 }
845
846 if (server_prep(srv, fd)) {
847 close(fd);
848 return 1;
849 }
850 srv->fd = fd;
851 return 0;
852 }
853
854
855 int
mfd_srvman_open()856 mfd_srvman_open()
857 {
858 struct mfd_server *p;
859
860 mu_debug(debug_handle, MU_DEBUG_TRACE1, ("opening servers"));
861 if (!srvman.head)
862 mu_error(_("no servers configured"));
863 for (p = srvman.head; p; ) {
864 struct mfd_server *next = p->next;
865 if (server_open(p))
866 server_remove(p);
867 p = next;
868 }
869 return srvman.head == NULL;
870 }
871
872 void
mfd_srvman_shutdown()873 mfd_srvman_shutdown()
874 {
875 struct mfd_server *p;
876 time_t start = time(NULL);
877
878 for (p = srvman.head; p; p = p->next)
879 server_signal_children(p, SIGTERM);
880
881 do {
882 children_cleanup();
883 if (srvman.num_children == 0)
884 break;
885 sleep(1);
886 } while (time(NULL) - start < srvman_param.shutdown_timeout);
887
888 mu_debug(debug_handle, MU_DEBUG_TRACE1, ("shutting down servers"));
889 for (p = srvman.head; p; p = p->next) {
890 server_signal_children(p, SIGKILL);
891 mfd_server_shutdown(p);
892 }
893 }
894
895 void
mfd_srvman_free()896 mfd_srvman_free()
897 {
898 struct mfd_server *p;
899
900 for (p = srvman.head; p; ) {
901 struct mfd_server *next = p->next;
902 mfd_server_free(p);
903 p = next;
904 }
905 if (srvman_param.free_hook)
906 srvman_param.free_hook(srvman_param.data);
907 mu_acl_destroy(&srvman_param.acl);
908 }
909
910 size_t
mfd_srvman_count_servers()911 mfd_srvman_count_servers()
912 {
913 size_t count = 0;
914 struct mfd_server *p;
915
916 for (p = srvman.head; p; p = p->next)
917 count++;
918 return count;
919 }
920
921 void
srvman_init()922 srvman_init()
923 {
924 debug_handle = mu_debug_register_category("srvman");
925 }
926