Postfix3.3.1
event_server.c
[詳解]
1 /*++
2 /* NAME
3 /* event_server 3
4 /* SUMMARY
5 /* skeleton multi-threaded mail subsystem
6 /* SYNOPSIS
7 /* #include <mail_server.h>
8 /*
9 /* NORETURN event_server_main(argc, argv, service, key, value, ...)
10 /* int argc;
11 /* char **argv;
12 /* void (*service)(VSTREAM *stream, char *service_name, char **argv);
13 /* int key;
14 /*
15 /* void event_server_disconnect(fd)
16 /* VSTREAM *stream;
17 /*
18 /* void event_server_drain()
19 /* DESCRIPTION
20 /* This module implements a skeleton for multi-threaded
21 /* mail subsystems: mail subsystem programs that service multiple
22 /* clients at the same time. The resulting program expects to be run
23 /* from the \fBmaster\fR process.
24 /*
25 /* event_server_main() is the skeleton entry point. It should be
26 /* called from the application main program. The skeleton does all
27 /* the generic command-line processing, initialization of
28 /* configurable parameters, and connection management.
29 /* Unlike multi_server, this skeleton does not attempt to manage
30 /* all the events on a client connection.
31 /* The skeleton never returns.
32 /*
33 /* Arguments:
34 /* .IP "void (*service)(VSTREAM *stream, char *service_name, char **argv)"
35 /* A pointer to a function that is called by the skeleton each
36 /* time a client connects to the program's service port. The
37 /* function is run after the program has optionally dropped
38 /* its privileges. The application is responsible for managing
39 /* subsequent I/O events on the stream, and is responsible for
40 /* calling event_server_disconnect() when the stream is closed.
41 /* The stream initial state is non-blocking mode.
42 /* Optional connection attributes are provided as a hash that
43 /* is attached as stream context. NOTE: the attributes are
44 /* destroyed after this function is called. The service
45 /* name argument corresponds to the service name in the master.cf
46 /* file. The argv argument specifies command-line arguments
47 /* left over after options processing.
48 /* .PP
49 /* Optional arguments are specified as a null-terminated list
50 /* with macros that have zero or more arguments:
51 /* .IP "CA_MAIL_SERVER_REQ_INT_TABLE(CONFIG_INT_TABLE *)"
52 /* A table with configurable parameters, to be loaded from the
53 /* global Postfix configuration file. Tables are loaded in the
54 /* order as specified, and multiple instances of the same type
55 /* are allowed.
56 /* .IP "CA_MAIL_SERVER_REQ_LONG_TABLE(CONFIG_LONG_TABLE *)"
57 /* A table with configurable parameters, to be loaded from the
58 /* global Postfix configuration file. Tables are loaded in the
59 /* order as specified, and multiple instances of the same type
60 /* are allowed.
61 /* .IP "CA_MAIL_SERVER_REQ_STR_TABLE(CONFIG_STR_TABLE *)"
62 /* A table with configurable parameters, to be loaded from the
63 /* global Postfix configuration file. Tables are loaded in the
64 /* order as specified, and multiple instances of the same type
65 /* are allowed.
66 /* .IP "CA_MAIL_SERVER_REQ_BOOL_TABLE(CONFIG_BOOL_TABLE *)"
67 /* A table with configurable parameters, to be loaded from the
68 /* global Postfix configuration file. Tables are loaded in the
69 /* order as specified, and multiple instances of the same type
70 /* are allowed.
71 /* .IP "CA_MAIL_SERVER_REQ_TIME_TABLE(CONFIG_TIME_TABLE *)"
72 /* A table with configurable parameters, to be loaded from the
73 /* global Postfix configuration file. Tables are loaded in the
74 /* order as specified, and multiple instances of the same type
75 /* are allowed.
76 /* .IP "CA_MAIL_SERVER_REQ_RAW_TABLE(CONFIG_RAW_TABLE *)"
77 /* A table with configurable parameters, to be loaded from the
78 /* global Postfix configuration file. Tables are loaded in the
79 /* order as specified, and multiple instances of the same type
80 /* are allowed. Raw parameters are not subjected to $name
81 /* evaluation.
82 /* .IP "CA_MAIL_SERVER_REQ_NINT_TABLE(CONFIG_NINT_TABLE *)"
83 /* A table with configurable parameters, to be loaded from the
84 /* global Postfix configuration file. Tables are loaded in the
85 /* order as specified, and multiple instances of the same type
86 /* are allowed.
87 /* .IP "CA_MAIL_SERVER_REQ_NBOOL_TABLE(CONFIG_NBOOL_TABLE *)"
88 /* A table with configurable parameters, to be loaded from the
89 /* global Postfix configuration file. Tables are loaded in the
90 /* order as specified, and multiple instances of the same type
91 /* are allowed.
92 /* .IP "CA_MAIL_SERVER_REQ_PRE_INIT(void *(char *service_name, char **argv))"
93 /* A pointer to a function that is called once
94 /* by the skeleton after it has read the global configuration file
95 /* and after it has processed command-line arguments, but before
96 /* the skeleton has optionally relinquished the process privileges.
97 /* .sp
98 /* Only the last instance of this parameter type is remembered.
99 /* .IP "CA_MAIL_SERVER_REQ_POST_INIT(void *(char *service_name, char **argv))"
100 /* A pointer to a function that is called once
101 /* by the skeleton after it has optionally relinquished the process
102 /* privileges, but before servicing client connection requests.
103 /* .sp
104 /* Only the last instance of this parameter type is remembered.
105 /* .IP "CA_MAIL_SERVER_REQ_LOOP(int *(char *service_name, char **argv))"
106 /* A pointer to function that is executed from
107 /* within the event loop, whenever an I/O or timer event has happened,
108 /* or whenever nothing has happened for a specified amount of time.
109 /* The result value of the function specifies how long to wait until
110 /* the next event. Specify -1 to wait for "as long as it takes".
111 /* .sp
112 /* Only the last instance of this parameter type is remembered.
113 /* .IP "CA_MAIL_SERVER_EXIT(void *(char *service_name, char **argv))"
114 /* A pointer to function that is executed immediately before normal
115 /* process termination.
116 /* .IP "CA_MAIL_SERVER_PRE_ACCEPT(void *(char *service_name, char **argv))"
117 /* Function to be executed prior to accepting a new connection.
118 /* .sp
119 /* Only the last instance of this parameter type is remembered.
120 /* .IP "CA_MAIL_SERVER_PRE_DISCONN(VSTREAM *, char *service_name, char **argv)"
121 /* A pointer to a function that is called
122 /* by the event_server_disconnect() function (see below).
123 /* .sp
124 /* Only the last instance of this parameter type is remembered.
125 /* .IP CA_MAIL_SERVER_IN_FLOW_DELAY
126 /* Pause $in_flow_delay seconds when no "mail flow control token"
127 /* is available. A token is consumed for each connection request.
128 /* .IP CA_MAIL_SERVER_SOLITARY
129 /* This service must be configured with process limit of 1.
130 /* .IP CA_MAIL_SERVER_UNLIMITED
131 /* This service must be configured with process limit of 0.
132 /* .IP CA_MAIL_SERVER_PRIVILEGED
133 /* This service must be configured as privileged.
134 /* .IP "CA_MAIL_SERVER_SLOW_EXIT(void *(char *service_name, char **argv))"
135 /* A pointer to a function that is called after "postfix reload"
136 /* or "master exit". The application can call event_server_drain()
137 /* (see below) to finish ongoing activities in the background.
138 /* .IP "CA_MAIL_SERVER_WATCHDOG(int *)"
139 /* Override the default 1000s watchdog timeout. The value is
140 /* used after command-line and main.cf file processing.
141 /* .IP "CA_MAIL_SERVER_BOUNCE_INIT(const char *, const char **)"
142 /* Initialize the DSN filter for the bounce/defer service
143 /* clients with the specified map source and map names.
144 /* .PP
145 /* event_server_disconnect() should be called by the application
146 /* to close a client connection.
147 /*
148 /* event_server_drain() should be called when the application
149 /* no longer wishes to accept new client connections. Existing
150 /* clients are handled in a background process, and the process
151 /* terminates when the last client is disconnected. A non-zero
152 /* result means this call should be tried again later.
153 /*
154 /* The var_use_limit variable limits the number of clients
155 /* that a server can service before it commits suicide. This
156 /* value is taken from the global \fBmain.cf\fR configuration
157 /* file. Setting \fBvar_use_limit\fR to zero disables the
158 /* client limit.
159 /*
160 /* The var_idle_limit variable limits the time that a service
161 /* receives no client connection requests before it commits
162 /* suicide. This value is taken from the global \fBmain.cf\fR
163 /* configuration file. Setting \fBvar_idle_limit\fR to zero
164 /* disables the idle limit.
165 /* DIAGNOSTICS
166 /* Problems and transactions are logged to \fBsyslogd\fR(8).
167 /* SEE ALSO
168 /* master(8), master process
169 /* syslogd(8) system logging
170 /* LICENSE
171 /* .ad
172 /* .fi
173 /* The Secure Mailer license must be distributed with this software.
174 /* AUTHOR(S)
175 /* Wietse Venema
176 /* IBM T.J. Watson Research
177 /* P.O. Box 704
178 /* Yorktown Heights, NY 10598, USA
179 /*
180 /* Wietse Venema
181 /* Google, Inc.
182 /* 111 8th Avenue
183 /* New York, NY 10011, USA
184 /*--*/
185 
186 /* System library. */
187 
188 #include <sys_defs.h>
189 #include <sys/socket.h>
190 #include <sys/time.h> /* select() */
191 #include <unistd.h>
192 #include <signal.h>
193 #include <syslog.h>
194 #include <stdlib.h>
195 #include <limits.h>
196 #include <string.h>
197 #include <errno.h>
198 #include <fcntl.h>
199 #include <stdarg.h>
200 #ifdef STRCASECMP_IN_STRINGS_H
201 #include <strings.h>
202 #endif
203 #include <time.h>
204 
205 #ifdef USE_SYS_SELECT_H
206 #include <sys/select.h> /* select() */
207 #endif
208 
209 /* Utility library. */
210 
211 #include <msg.h>
212 #include <msg_syslog.h>
213 #include <msg_vstream.h>
214 #include <chroot_uid.h>
215 #include <listen.h>
216 #include <events.h>
217 #include <vstring.h>
218 #include <vstream.h>
219 #include <msg_vstream.h>
220 #include <mymalloc.h>
221 #include <iostuff.h>
222 #include <stringops.h>
223 #include <sane_accept.h>
224 #include <myflock.h>
225 #include <safe_open.h>
226 #include <listen.h>
227 #include <watchdog.h>
228 #include <split_at.h>
229 
230 /* Global library. */
231 
232 #include <mail_task.h>
233 #include <debug_process.h>
234 #include <mail_params.h>
235 #include <mail_conf.h>
236 #include <mail_dict.h>
237 #include <timed_ipc.h>
238 #include <resolve_local.h>
239 #include <mail_flow.h>
240 #include <mail_version.h>
241 #include <bounce.h>
242 
243 /* Process manager. */
244 
245 #include "master_proto.h"
246 
247 /* Application-specific */
248 
249 #include "mail_server.h"
250 
251  /*
252  * Global state.
253  */
254 static int client_count;
255 static int use_count;
256 static int socket_count = 1;
257 
258 static void (*event_server_service) (VSTREAM *, char *, char **);
259 static char *event_server_name;
260 static char **event_server_argv;
261 static void (*event_server_accept) (int, void *);
262 static void (*event_server_onexit) (char *, char **);
263 static void (*event_server_pre_accept) (char *, char **);
264 static VSTREAM *event_server_lock;
265 static int event_server_in_flow_delay;
266 static unsigned event_server_generation;
267 static void (*event_server_pre_disconn) (VSTREAM *, char *, char **);
268 static void (*event_server_slow_exit) (char *, char **);
269 static int event_server_watchdog = 1000;
270 static int event_server_saved_flags;
271 
272 /* event_server_exit - normal termination */
273 
274 static NORETURN event_server_exit(void)
275 {
276  if (event_server_onexit)
277  event_server_onexit(event_server_name, event_server_argv);
278  exit(0);
279 }
280 
281 /* event_server_abort - terminate after abnormal master exit */
282 
283 static void event_server_abort(int unused_event, void *unused_context)
284 {
285  if (msg_verbose)
286  msg_info("master disconnect -- exiting");
288  if (event_server_slow_exit)
289  event_server_slow_exit(event_server_name, event_server_argv);
290  else
291  event_server_exit();
292 }
293 
294 /* event_server_timeout - idle time exceeded */
295 
296 static void event_server_timeout(int unused_event, void *unused_context)
297 {
298  if (msg_verbose)
299  msg_info("idle timeout -- exiting");
300  event_server_exit();
301 }
302 
303 /* event_server_drain - stop accepting new clients */
304 
306 {
307  const char *myname = "event_server_drain";
308  int fd;
309 
310  switch (fork()) {
311  /* Try again later. */
312  case -1:
313  return (-1);
314  /* Finish existing clients in the background, then terminate. */
315  case 0:
316  (void) msg_cleanup((MSG_CLEANUP_FN) 0);
317  event_fork();
318  for (fd = MASTER_LISTEN_FD; fd < MASTER_LISTEN_FD + socket_count; fd++) {
320  (void) close(fd);
321  /* Play safe - don't reuse this file number. */
322  if (DUP2(STDIN_FILENO, fd) < 0)
323  msg_warn("%s: dup2(%d, %d): %m", myname, STDIN_FILENO, fd);
324  }
325  var_use_limit = 1;
326  return (0);
327  /* Let the master start a new process. */
328  default:
329  exit(0);
330  }
331 }
332 
333 /* event_server_disconnect - terminate client session */
334 
336 {
337  if (msg_verbose)
338  msg_info("connection closed fd %d", vstream_fileno(stream));
339  if (event_server_pre_disconn)
340  event_server_pre_disconn(stream, event_server_name, event_server_argv);
341  (void) vstream_fclose(stream);
342  client_count--;
343  /* Avoid integer wrap-around in a persistent process. */
344  if (use_count < INT_MAX)
345  use_count++;
346  if (client_count == 0 && var_idle_limit > 0)
347  event_request_timer(event_server_timeout, (void *) 0, var_idle_limit);
348 }
349 
350 /* event_server_execute - in case (char *) != (struct *) */
351 
352 static void event_server_execute(int unused_event, void *context)
353 {
354  VSTREAM *stream = (VSTREAM *) context;
355  HTABLE *attr = (vstream_flags(stream) == event_server_saved_flags ?
356  (HTABLE *) vstream_context(stream) : 0);
357 
358  if (event_server_lock != 0
359  && myflock(vstream_fileno(event_server_lock), INTERNAL_LOCK,
360  MYFLOCK_OP_NONE) < 0)
361  msg_fatal("select unlock: %m");
362 
363  /*
364  * Do bother the application when the client disconnected. Don't drop the
365  * already accepted client request after "postfix reload"; that would be
366  * rude.
367  */
368  if (master_notify(var_pid, event_server_generation, MASTER_STAT_TAKEN) < 0)
369  /* void */ ;
370  event_server_service(stream, event_server_name, event_server_argv);
371  if (master_notify(var_pid, event_server_generation, MASTER_STAT_AVAIL) < 0)
372  event_server_abort(EVENT_NULL_TYPE, EVENT_NULL_CONTEXT);
373  if (attr)
374  htable_free(attr, myfree);
375 }
376 
377 /* event_server_wakeup - wake up application */
378 
379 static void event_server_wakeup(int fd, HTABLE *attr)
380 {
381  VSTREAM *stream;
382  char *tmp;
383 
384 #if defined(F_DUPFD) && (EVENTS_STYLE != EVENTS_STYLE_SELECT)
385 #ifndef THRESHOLD_FD_WORKAROUND
386 #define THRESHOLD_FD_WORKAROUND 128
387 #endif
388  int new_fd;
389 
390  /*
391  * Leave some handles < FD_SETSIZE for DBMS libraries, in the unlikely
392  * case of a multi-server with a thousand clients.
393  */
394  if (fd < THRESHOLD_FD_WORKAROUND) {
395  if ((new_fd = fcntl(fd, F_DUPFD, THRESHOLD_FD_WORKAROUND)) < 0)
396  msg_fatal("fcntl F_DUPFD: %m");
397  (void) close(fd);
398  fd = new_fd;
399  }
400 #endif
401  if (msg_verbose)
402  msg_info("connection established fd %d", fd);
403  non_blocking(fd, BLOCKING);
405  client_count++;
406  stream = vstream_fdopen(fd, O_RDWR);
407  tmp = concatenate(event_server_name, " socket", (char *) 0);
408  vstream_control(stream,
409  CA_VSTREAM_CTL_PATH(tmp),
410  CA_VSTREAM_CTL_CONTEXT((void *) attr),
412  myfree(tmp);
413  timed_ipc_setup(stream);
414  event_server_saved_flags = vstream_flags(stream);
415  if (event_server_in_flow_delay && mail_flow_get(1) < 0)
416  event_request_timer(event_server_execute, (void *) stream,
418  else
419  event_server_execute(0, (void *) stream);
420 }
421 
422 /* event_server_accept_local - accept client connection request */
423 
424 static void event_server_accept_local(int unused_event, void *context)
425 {
426  int listen_fd = CAST_ANY_PTR_TO_INT(context);
427  int time_left = -1;
428  int fd;
429 
430  /*
431  * Be prepared for accept() to fail because some other process already
432  * got the connection (the number of processes competing for clients is
433  * kept small, so this is not a "thundering herd" problem). If the
434  * accept() succeeds, be sure to disable non-blocking I/O, in order to
435  * minimize confusion.
436  */
437  if (client_count == 0 && var_idle_limit > 0)
438  time_left = event_cancel_timer(event_server_timeout, (void *) 0);
439 
440  if (event_server_pre_accept)
441  event_server_pre_accept(event_server_name, event_server_argv);
442  fd = LOCAL_ACCEPT(listen_fd);
443  if (event_server_lock != 0
444  && myflock(vstream_fileno(event_server_lock), INTERNAL_LOCK,
445  MYFLOCK_OP_NONE) < 0)
446  msg_fatal("select unlock: %m");
447  if (fd < 0) {
448  if (errno != EAGAIN)
449  msg_error("accept connection: %m");
450  if (time_left >= 0)
451  event_request_timer(event_server_timeout, (void *) 0, time_left);
452  return;
453  }
454  event_server_wakeup(fd, (HTABLE *) 0);
455 }
456 
457 #ifdef MASTER_XPORT_NAME_PASS
458 
459 /* event_server_accept_pass - accept descriptor */
460 
461 static void event_server_accept_pass(int unused_event, void *context)
462 {
463  int listen_fd = CAST_ANY_PTR_TO_INT(context);
464  int time_left = -1;
465  int fd;
466  HTABLE *attr = 0;
467 
468  /*
469  * Be prepared for accept() to fail because some other process already
470  * got the connection (the number of processes competing for clients is
471  * kept small, so this is not a "thundering herd" problem). If the
472  * accept() succeeds, be sure to disable non-blocking I/O, in order to
473  * minimize confusion.
474  */
475  if (client_count == 0 && var_idle_limit > 0)
476  time_left = event_cancel_timer(event_server_timeout, (void *) 0);
477 
478  if (event_server_pre_accept)
479  event_server_pre_accept(event_server_name, event_server_argv);
480  fd = pass_accept_attr(listen_fd, &attr);
481  if (event_server_lock != 0
482  && myflock(vstream_fileno(event_server_lock), INTERNAL_LOCK,
483  MYFLOCK_OP_NONE) < 0)
484  msg_fatal("select unlock: %m");
485  if (fd < 0) {
486  if (errno != EAGAIN)
487  msg_error("accept connection: %m");
488  if (time_left >= 0)
489  event_request_timer(event_server_timeout, (void *) 0, time_left);
490  return;
491  }
492  event_server_wakeup(fd, attr);
493 }
494 
495 #endif
496 
497 /* event_server_accept_inet - accept client connection request */
498 
499 static void event_server_accept_inet(int unused_event, void *context)
500 {
501  int listen_fd = CAST_ANY_PTR_TO_INT(context);
502  int time_left = -1;
503  int fd;
504 
505  /*
506  * Be prepared for accept() to fail because some other process already
507  * got the connection (the number of processes competing for clients is
508  * kept small, so this is not a "thundering herd" problem). If the
509  * accept() succeeds, be sure to disable non-blocking I/O, in order to
510  * minimize confusion.
511  */
512  if (client_count == 0 && var_idle_limit > 0)
513  time_left = event_cancel_timer(event_server_timeout, (void *) 0);
514 
515  if (event_server_pre_accept)
516  event_server_pre_accept(event_server_name, event_server_argv);
517  fd = inet_accept(listen_fd);
518  if (event_server_lock != 0
519  && myflock(vstream_fileno(event_server_lock), INTERNAL_LOCK,
520  MYFLOCK_OP_NONE) < 0)
521  msg_fatal("select unlock: %m");
522  if (fd < 0) {
523  if (errno != EAGAIN)
524  msg_error("accept connection: %m");
525  if (time_left >= 0)
526  event_request_timer(event_server_timeout, (void *) 0, time_left);
527  return;
528  }
529  event_server_wakeup(fd, (HTABLE *) 0);
530 }
531 
532 /* event_server_main - the real main program */
533 
534 NORETURN event_server_main(int argc, char **argv, MULTI_SERVER_FN service,...)
535 {
536  const char *myname = "event_server_main";
537  VSTREAM *stream = 0;
538  char *root_dir = 0;
539  char *user_name = 0;
540  int debug_me = 0;
541  int daemon_mode = 1;
542  char *service_name = basename(argv[0]);
543  int delay;
544  int c;
545  int fd;
546  va_list ap;
547  MAIL_SERVER_INIT_FN pre_init = 0;
548  MAIL_SERVER_INIT_FN post_init = 0;
549  MAIL_SERVER_LOOP_FN loop = 0;
550  int key;
551  char *transport = 0;
552 
553 #if 0
554  char *lock_path;
555  VSTRING *why;
556 
557 #endif
558  int alone = 0;
559  int zerolimit = 0;
560  WATCHDOG *watchdog;
561  char *oname_val;
562  char *oname;
563  char *oval;
564  const char *err;
565  char *generation;
566  int msg_vstream_needed = 0;
567  int redo_syslog_init = 0;
568  const char *dsn_filter_title;
569  const char **dsn_filter_maps;
570 
571  /*
572  * Process environment options as early as we can.
573  */
574  if (getenv(CONF_ENV_VERB))
575  msg_verbose = 1;
576  if (getenv(CONF_ENV_DEBUG))
577  debug_me = 1;
578 
579  /*
580  * Don't die when a process goes away unexpectedly.
581  */
582  signal(SIGPIPE, SIG_IGN);
583 
584  /*
585  * Don't die for frivolous reasons.
586  */
587 #ifdef SIGXFSZ
588  signal(SIGXFSZ, SIG_IGN);
589 #endif
590 
591  /*
592  * May need this every now and then.
593  */
594  var_procname = mystrdup(basename(argv[0]));
596 
597  /*
598  * Initialize logging and exit handler. Do the syslog first, so that its
599  * initialization completes before we enter the optional chroot jail.
600  */
602  if (msg_verbose)
603  msg_info("daemon started");
604 
605  /*
606  * Check the Postfix library version as soon as we enable logging.
607  */
609 
610  /*
611  * Initialize from the configuration file. Allow command-line options to
612  * override compiled-in defaults or configured parameter values.
613  */
614  mail_conf_suck();
615 
616  /*
617  * After database open error, continue execution with reduced
618  * functionality.
619  */
621 
622  /*
623  * Pick up policy settings from master process. Shut up error messages to
624  * stderr, because no-one is going to see them.
625  */
626  opterr = 0;
627  while ((c = GETOPT(argc, argv, "cdDi:lm:n:o:s:St:uvVz")) > 0) {
628  switch (c) {
629  case 'c':
630  root_dir = "setme";
631  break;
632  case 'd':
633  daemon_mode = 0;
634  break;
635  case 'D':
636  debug_me = 1;
637  break;
638  case 'i':
640  break;
641  case 'l':
642  alone = 1;
643  break;
644  case 'm':
645  mail_conf_update(VAR_MAX_USE, optarg);
646  break;
647  case 'n':
648  service_name = optarg;
649  break;
650  case 'o':
651  oname_val = mystrdup(optarg);
652  if ((err = split_nameval(oname_val, &oname, &oval)) != 0)
653  msg_fatal("invalid \"-o %s\" option value: %s", optarg, err);
654  mail_conf_update(oname, oval);
655  if (strcmp(oname, VAR_SYSLOG_NAME) == 0)
656  redo_syslog_init = 1;
657  myfree(oname_val);
658  break;
659  case 's':
660  if ((socket_count = atoi(optarg)) <= 0)
661  msg_fatal("invalid socket_count: %s", optarg);
662  break;
663  case 'S':
664  stream = VSTREAM_IN;
665  break;
666  case 'u':
667  user_name = "setme";
668  break;
669  case 't':
670  transport = optarg;
671  break;
672  case 'v':
673  msg_verbose++;
674  break;
675  case 'V':
676  if (++msg_vstream_needed == 1)
678  break;
679  case 'z':
680  zerolimit = 1;
681  break;
682  default:
683  msg_fatal("invalid option: %c", optopt);
684  break;
685  }
686  }
687  set_mail_conf_str(VAR_SERVNAME, service_name);
688 
689  /*
690  * Initialize generic parameters.
691  */
693  if (redo_syslog_init)
695 
696  /*
697  * Register higher-level dictionaries and initialize the support for
698  * dynamically-loaded dictionarles.
699  */
700  mail_dict_init();
701 
702  /*
703  * If not connected to stdin, stdin must not be a terminal.
704  */
705  if (daemon_mode && stream == 0 && isatty(STDIN_FILENO)) {
707  msg_fatal("do not run this command by hand");
708  }
709 
710  /*
711  * Application-specific initialization.
712  */
713  va_start(ap, service);
714  while ((key = va_arg(ap, int)) != 0) {
715  switch (key) {
718  break;
721  break;
724  break;
727  break;
730  break;
733  break;
736  break;
739  break;
741  pre_init = va_arg(ap, MAIL_SERVER_INIT_FN);
742  break;
744  post_init = va_arg(ap, MAIL_SERVER_INIT_FN);
745  break;
746  case MAIL_SERVER_LOOP:
747  loop = va_arg(ap, MAIL_SERVER_LOOP_FN);
748  break;
749  case MAIL_SERVER_EXIT:
750  event_server_onexit = va_arg(ap, MAIL_SERVER_EXIT_FN);
751  break;
753  event_server_pre_accept = va_arg(ap, MAIL_SERVER_ACCEPT_FN);
754  break;
756  event_server_pre_disconn = va_arg(ap, MAIL_SERVER_DISCONN_FN);
757  break;
759  event_server_in_flow_delay = 1;
760  break;
762  if (stream == 0 && !alone)
763  msg_fatal("service %s requires a process limit of 1",
764  service_name);
765  break;
767  if (stream == 0 && !zerolimit)
768  msg_fatal("service %s requires a process limit of 0",
769  service_name);
770  break;
772  if (user_name)
773  msg_fatal("service %s requires privileged operation",
774  service_name);
775  break;
777  event_server_watchdog = *va_arg(ap, int *);
778  break;
780  event_server_slow_exit = va_arg(ap, MAIL_SERVER_SLOW_EXIT_FN);
781  break;
783  dsn_filter_title = va_arg(ap, const char *);
784  dsn_filter_maps = va_arg(ap, const char **);
785  bounce_client_init(dsn_filter_title, *dsn_filter_maps);
786  break;
787  default:
788  msg_panic("%s: unknown argument type: %d", myname, key);
789  }
790  }
791  va_end(ap);
792 
793  if (root_dir)
794  root_dir = var_queue_dir;
795  if (user_name)
796  user_name = var_mail_owner;
797 
798  /*
799  * Can options be required?
800  */
801  if (stream == 0) {
802  if (transport == 0)
803  msg_fatal("no transport type specified");
804  if (strcasecmp(transport, MASTER_XPORT_NAME_INET) == 0)
805  event_server_accept = event_server_accept_inet;
806  else if (strcasecmp(transport, MASTER_XPORT_NAME_UNIX) == 0)
807  event_server_accept = event_server_accept_local;
808 #ifdef MASTER_XPORT_NAME_PASS
809  else if (strcasecmp(transport, MASTER_XPORT_NAME_PASS) == 0)
810  event_server_accept = event_server_accept_pass;
811 #endif
812  else
813  msg_fatal("unsupported transport type: %s", transport);
814  }
815 
816  /*
817  * Retrieve process generation from environment.
818  */
819  if ((generation = getenv(MASTER_GEN_NAME)) != 0) {
820  if (!alldig(generation))
821  msg_fatal("bad generation: %s", generation);
822  OCTAL_TO_UNSIGNED(event_server_generation, generation);
823  if (msg_verbose)
824  msg_info("process generation: %s (%o)",
825  generation, event_server_generation);
826  }
827 
828  /*
829  * Optionally start the debugger on ourself.
830  */
831  if (debug_me)
832  debug_process();
833 
834  /*
835  * Traditionally, BSD select() can't handle multiple processes selecting
836  * on the same socket, and wakes up every process in select(). See TCP/IP
837  * Illustrated volume 2 page 532. We avoid select() collisions with an
838  * external lock file.
839  */
840 
841  /*
842  * XXX Can't compete for exclusive access to the listen socket because we
843  * also have to monitor existing client connections for service requests.
844  */
845 #if 0
846  if (stream == 0 && !alone) {
847  lock_path = concatenate(DEF_PID_DIR, "/", transport,
848  ".", service_name, (char *) 0);
849  why = vstring_alloc(1);
850  if ((event_server_lock = safe_open(lock_path, O_CREAT | O_RDWR, 0600,
851  (struct stat *) 0, -1, -1, why)) == 0)
852  msg_fatal("open lock file %s: %s", lock_path, vstring_str(why));
853  close_on_exec(vstream_fileno(event_server_lock), CLOSE_ON_EXEC);
854  myfree(lock_path);
855  vstring_free(why);
856  }
857 #endif
858 
859  /*
860  * Set up call-back info.
861  */
862  event_server_service = service;
863  event_server_name = service_name;
864  event_server_argv = argv + optind;
865 
866  /*
867  * Run pre-jail initialization.
868  */
869  if (chdir(var_queue_dir) < 0)
870  msg_fatal("chdir(\"%s\"): %m", var_queue_dir);
871  if (pre_init)
872  pre_init(event_server_name, event_server_argv);
873 
874  /*
875  * Optionally, restrict the damage that this process can do.
876  */
878  tzset();
879  chroot_uid(root_dir, user_name);
880 
881  /*
882  * Run post-jail initialization.
883  */
884  if (post_init)
885  post_init(event_server_name, event_server_argv);
886 
887  /*
888  * Are we running as a one-shot server with the client connection on
889  * standard input? If so, make sure the output is written to stdout so as
890  * to satisfy common expectation.
891  */
892  if (stream != 0) {
893  vstream_control(stream,
895  CA_VSTREAM_CTL_WRITE_FD(STDOUT_FILENO),
897  service(stream, event_server_name, event_server_argv);
898  vstream_fflush(stream);
899  event_server_exit();
900  }
901 
902  /*
903  * Running as a semi-resident server. Service connection requests.
904  * Terminate when we have serviced a sufficient number of clients, when
905  * no-one has been talking to us for a configurable amount of time, or
906  * when the master process terminated abnormally.
907  */
908  if (var_idle_limit > 0)
909  event_request_timer(event_server_timeout, (void *) 0, var_idle_limit);
910  for (fd = MASTER_LISTEN_FD; fd < MASTER_LISTEN_FD + socket_count; fd++) {
911  event_enable_read(fd, event_server_accept, CAST_INT_TO_VOID_PTR(fd));
913  }
914  event_enable_read(MASTER_STATUS_FD, event_server_abort, (void *) 0);
918  watchdog = watchdog_create(event_server_watchdog,
919  (WATCHDOG_FN) 0, (void *) 0);
920 
921  /*
922  * The event loop, at last.
923  */
924  while (var_use_limit == 0 || use_count < var_use_limit || client_count > 0) {
925  if (event_server_lock != 0) {
926  watchdog_stop(watchdog);
927  if (myflock(vstream_fileno(event_server_lock), INTERNAL_LOCK,
929  msg_fatal("select lock: %m");
930  }
931  watchdog_start(watchdog);
932  delay = loop ? loop(event_server_name, event_server_argv) : -1;
933  event_loop(delay);
934  }
935  event_server_exit();
936 }
int msg_verbose
Definition: msg.c:177
void event_enable_read(int fd, EVENT_NOTIFY_RDWR_FN callback, void *context)
Definition: events.c:729
void msg_error(const char *fmt,...)
Definition: msg.c:231
void htable_free(HTABLE *table, void(*free_fn)(void *))
Definition: htable.c:287
void mail_params_init()
Definition: mail_params.c:658
#define MAIL_SERVER_UNLIMITED
Definition: mail_server.h:39
void myfree(void *ptr)
Definition: mymalloc.c:207
const char * mail_task(const char *argv0)
Definition: mail_task.c:49
char * var_procname
Definition: mail_params.c:252
#define MAIL_SERVER_STR_TABLE
Definition: mail_server.h:25
#define LOCAL_ACCEPT
Definition: sys_defs.h:1423
char * mystrdup(const char *str)
Definition: mymalloc.c:225
#define VAR_SERVNAME
Definition: mail_params.h:2438
int master_notify(int pid, unsigned generation, int status)
Definition: master_proto.c:65
void set_mail_conf_str(const char *, const char *)
#define CAST_ANY_PTR_TO_INT(cptr)
Definition: sys_defs.h:1298
int var_pid
Definition: mail_params.c:254
#define NORETURN
Definition: sys_defs.h:1583
NORETURN msg_panic(const char *fmt,...)
Definition: msg.c:295
void(* MSG_CLEANUP_FN)(void)
Definition: msg.h:23
#define vstring_str(vp)
Definition: vstring.h:71
void chroot_uid(const char *root_dir, const char *user_name)
Definition: chroot_uid.c:43
#define MAIL_SERVER_INT_TABLE
Definition: mail_server.h:24
#define stat(p, s)
Definition: warn_stat.h:18
#define MASTER_FLOW_WRITE
Definition: master_proto.h:44
#define VAR_MAX_IDLE
Definition: mail_params.h:919
#define MYFLOCK_OP_EXCLUSIVE
Definition: myflock.h:30
#define MAIL_SERVER_SLOW_EXIT
Definition: mail_server.h:45
#define OCTAL_TO_UNSIGNED(res, str)
Definition: sys_defs.h:1450
#define VAR_PROCNAME
Definition: mail_params.h:2435
#define LOG_FACILITY
Definition: mail_params.h:357
#define MAIL_SERVER_TIME_TABLE
Definition: mail_server.h:27
#define MASTER_STATUS_FD
Definition: master_proto.h:56
void(* MAIL_SERVER_DISCONN_FN)(VSTREAM *, char *, char **)
Definition: mail_server.h:52
void get_mail_conf_nint_table(const CONFIG_NINT_TABLE *)
void(* MAIL_SERVER_EXIT_FN)(char *, char **)
Definition: mail_server.h:50
#define CA_VSTREAM_CTL_DOUBLE
Definition: vstream.h:159
#define MASTER_LISTEN_FD
Definition: master_proto.h:57
#define CA_VSTREAM_CTL_CONTEXT(v)
Definition: vstream.h:165
void get_mail_conf_nbool_table(const CONFIG_NBOOL_TABLE *)
#define MASTER_XPORT_NAME_PASS
Definition: master_proto.h:18
int var_idle_limit
Definition: mail_params.c:250
#define MASTER_FLOW_READ
Definition: master_proto.h:43
void(* MAIL_SERVER_SLOW_EXIT_FN)(char *, char **)
Definition: mail_server.h:53
#define EVENT_NULL_CONTEXT
Definition: events.h:51
#define VSTREAM_IN
Definition: vstream.h:66
int alldig(const char *string)
Definition: alldig.c:38
#define MASTER_STAT_AVAIL
Definition: master_proto.h:34
Definition: htable.h:25
const char * split_nameval(char *buf, char **name, char **value)
Definition: split_nameval.c:61
#define CONF_ENV_VERB
Definition: mail_conf.h:23
void watchdog_start(WATCHDOG *wp)
Definition: watchdog.c:251
#define MAIL_SERVER_WATCHDOG
Definition: mail_server.h:42
int inet_accept(int fd)
Definition: inet_listen.c:169
void(* WATCHDOG_FN)(WATCHDOG *, char *)
Definition: watchdog.h:18
#define vstream_context(vp)
Definition: vstream.h:117
#define MAIL_SERVER_LOOP
Definition: mail_server.h:35
void mail_conf_suck(void)
Definition: mail_conf.c:186
#define MAIL_SERVER_BOOL_TABLE
Definition: mail_server.h:26
#define MAIL_SERVER_PRIVILEGED
Definition: mail_server.h:41
#define MAIL_SERVER_POST_INIT
Definition: mail_server.h:34
#define MAIL_SERVER_BOUNCE_INIT
Definition: mail_server.h:46
int event_server_drain(void)
Definition: event_server.c:305
#define CA_VSTREAM_CTL_WRITE_FD(v)
Definition: vstream.h:161
#define CONF_ENV_DEBUG
Definition: mail_conf.h:24
void get_mail_conf_time_table(const CONFIG_TIME_TABLE *)
#define MAIL_SERVER_PRE_ACCEPT
Definition: mail_server.h:37
#define MASTER_STAT_TAKEN
Definition: master_proto.h:33
#define MAIL_SERVER_PRE_DISCONN
Definition: mail_server.h:40
void(* MAIL_SERVER_INIT_FN)(char *, char **)
Definition: mail_server.h:48
int dict_allow_surrogate
void get_mail_conf_raw_table(const CONFIG_RAW_TABLE *)
#define CAST_INT_TO_VOID_PTR(ival)
Definition: sys_defs.h:1299
int vstream_fclose(VSTREAM *stream)
Definition: vstream.c:1268
ssize_t mail_flow_get(ssize_t len)
Definition: mail_flow.c:70
#define EVENT_NULL_TYPE
Definition: events.h:50
void event_loop(int delay)
Definition: events.c:998
WATCHDOG * watchdog_create(unsigned timeout, WATCHDOG_FN action, char *context)
Definition: watchdog.c:189
void msg_warn(const char *fmt,...)
Definition: msg.c:215
#define MAIL_SERVER_IN_FLOW_DELAY
Definition: mail_server.h:44
void resolve_local_init(void)
Definition: resolve_local.c:67
VSTRING * vstring_alloc(ssize_t len)
Definition: vstring.c:353
int myflock(int fd, int lock_style, int operation)
Definition: myflock.c:87
void mail_dict_init(void)
Definition: mail_dict.c:81
int var_use_limit
Definition: mail_params.c:248
#define VAR_MAX_USE
Definition: mail_params.h:911
void event_fork(void)
Definition: events.c:689
NORETURN event_server_main(int argc, char **argv, MULTI_SERVER_FN service,...)
Definition: event_server.c:534
#define MAIL_SERVER_EXIT
Definition: mail_server.h:36
void debug_process(void)
Definition: debug_process.c:50
void event_server_disconnect(VSTREAM *stream)
Definition: event_server.c:335
#define MASTER_XPORT_NAME_INET
Definition: master_proto.h:17
void get_mail_conf_str_table(const CONFIG_STR_TABLE *)
void timed_ipc_setup(VSTREAM *stream)
Definition: timed_ipc.c:47
NORETURN msg_fatal(const char *fmt,...)
Definition: msg.c:249
#define MYFLOCK_OP_NONE
Definition: myflock.h:28
void get_mail_conf_bool_table(const CONFIG_BOOL_TABLE *)
#define MASTER_XPORT_NAME_UNIX
Definition: master_proto.h:15
#define MAIL_VERSION_CHECK
Definition: mail_version.h:90
#define MAIL_SERVER_LONG_TABLE
Definition: mail_server.h:31
int vstream_fflush(VSTREAM *stream)
Definition: vstream.c:1257
void watchdog_stop(WATCHDOG *wp)
Definition: watchdog.c:265
char * concatenate(const char *arg0,...)
Definition: concatenate.c:42
#define GETOPT(argc, argv, str)
Definition: sys_defs.h:1313
void bounce_client_init(const char *title, const char *maps)
Definition: bounce.c:532
void msg_syslog_init(const char *name, int logopt, int facility)
Definition: msg_syslog.c:173
void(* MAIL_SERVER_ACCEPT_FN)(char *, char **)
Definition: mail_server.h:51
#define VAR_SYSLOG_NAME
Definition: mail_params.h:2560
#define DEF_PID_DIR
Definition: mail_params.h:303
#define MAIL_SERVER_NINT_TABLE
Definition: mail_server.h:29
int var_in_flow_delay
Definition: mail_params.c:291
int int
Definition: smtpd_proxy.h:21
int strcasecmp(const char *s1, const char *s2)
Definition: strcasecmp.c:41
int non_blocking(int, int)
Definition: non_blocking.c:55
VSTREAM * safe_open(const char *path, int flags, mode_t mode, struct stat *st, uid_t user, gid_t group, VSTRING *why)
Definition: safe_open.c:243
VSTRING * vstring_free(VSTRING *vp)
Definition: vstring.c:380
time_t event_request_timer(EVENT_NOTIFY_TIME_FN callback, void *context, int delay)
Definition: events.c:894
#define MAIL_SERVER_PRE_INIT
Definition: mail_server.h:33
char * var_mail_owner
Definition: mail_params.c:233
void get_mail_conf_int_table(const CONFIG_INT_TABLE *)
char * var_queue_dir
Definition: mail_params.c:246
#define vstream_fileno(vp)
Definition: vstream.h:115
void msg_vstream_init(const char *name, VSTREAM *vp)
Definition: msg_vstream.c:77
#define vstream_flags(stream)
Definition: vstream.h:258
#define CA_VSTREAM_CTL_END
Definition: vstream.h:155
#define CLOSE_ON_EXEC
Definition: iostuff.h:51
#define CA_VSTREAM_CTL_PATH(v)
Definition: vstream.h:158
int(* MAIL_SERVER_LOOP_FN)(char *, char **)
Definition: mail_server.h:49
void get_mail_conf_long_table(const CONFIG_LONG_TABLE *)
#define MASTER_GEN_NAME
Definition: master_proto.h:31
void vstream_control(VSTREAM *stream, int name,...)
Definition: vstream.c:1372
void event_disable_readwrite(int fd)
Definition: events.c:839
void mail_conf_update(const char *key, const char *value)
Definition: mail_conf.c:275
#define MAIL_SERVER_NBOOL_TABLE
Definition: mail_server.h:30
#define BLOCKING
Definition: iostuff.h:48
int event_cancel_timer(EVENT_NOTIFY_TIME_FN callback, void *context)
Definition: events.c:965
#define basename
Definition: stringops.h:36
int close_on_exec(int fd, int on)
Definition: close_on_exec.c:49
#define MAIL_SERVER_RAW_TABLE
Definition: mail_server.h:28
MSG_CLEANUP_FN msg_cleanup(MSG_CLEANUP_FN cleanup_fn)
Definition: msg.c:317
int pass_accept_attr(int, HTABLE **)
Definition: pass_accept.c:78
#define MAIL_SERVER_SOLITARY
Definition: mail_server.h:38
#define DUP2
Definition: sys_defs.h:1307
#define VSTREAM_ERR
Definition: vstream.h:68
VSTREAM * vstream_fdopen(int fd, int flags)
Definition: vstream.c:1204
void(* MULTI_SERVER_FN)(VSTREAM *, char *, char **)
Definition: mail_server.h:105
void msg_info(const char *fmt,...)
Definition: msg.c:199