177 #include <sys/socket.h>
178 #include <sys/time.h>
188 #ifdef STRCASECMP_IN_STRINGS_H
193 #ifdef USE_SYS_SELECT_H
194 #include <sys/select.h>
242 static int client_count;
243 static int use_count;
244 static int socket_count = 1;
246 static void (*multi_server_service) (
VSTREAM *,
char *,
char **);
247 static char *multi_server_name;
248 static char **multi_server_argv;
249 static void (*multi_server_accept) (
int,
void *);
250 static void (*multi_server_onexit) (
char *,
char **);
251 static void (*multi_server_pre_accept) (
char *,
char **);
252 static VSTREAM *multi_server_lock;
253 static int multi_server_in_flow_delay;
254 static unsigned multi_server_generation;
255 static void (*multi_server_pre_disconn) (
VSTREAM *,
char *,
char **);
256 static int multi_server_saved_flags;
260 static NORETURN multi_server_exit(
void)
262 if (multi_server_onexit)
263 multi_server_onexit(multi_server_name, multi_server_argv);
269 static void multi_server_abort(
int unused_event,
void *unused_context)
272 msg_info(
"master disconnect -- exiting");
278 static void multi_server_timeout(
int unused_event,
void *unused_context)
281 msg_info(
"idle timeout -- exiting");
289 const char *myname =
"multi_server_drain";
304 if (
DUP2(STDIN_FILENO, fd) < 0)
305 msg_warn(
"%s: dup2(%d, %d): %m", myname, STDIN_FILENO, fd);
321 if (multi_server_pre_disconn)
322 multi_server_pre_disconn(stream, multi_server_name, multi_server_argv);
327 if (use_count < INT_MAX)
335 static void multi_server_execute(
int unused_event,
void *context)
341 if (multi_server_lock != 0
354 multi_server_service(stream, multi_server_name, multi_server_argv);
366 static void multi_server_enable_read(
int unused_event,
void *context)
375 static void multi_server_wakeup(
int fd,
HTABLE *attr)
380 #if defined(F_DUPFD) && (EVENTS_STYLE != EVENTS_STYLE_SELECT)
381 #ifndef THRESHOLD_FD_WORKAROUND
382 #define THRESHOLD_FD_WORKAROUND 128
390 if (fd < THRESHOLD_FD_WORKAROUND) {
391 if ((new_fd = fcntl(fd, F_DUPFD, THRESHOLD_FD_WORKAROUND)) < 0)
398 msg_info(
"connection established fd %d", fd);
403 tmp =
concatenate(multi_server_name,
" socket", (
char *) 0);
415 multi_server_enable_read(0, (
void *) stream);
420 static void multi_server_accept_local(
int unused_event,
void *context)
436 if (multi_server_pre_accept)
437 multi_server_pre_accept(multi_server_name, multi_server_argv);
439 if (multi_server_lock != 0
450 multi_server_wakeup(fd, (
HTABLE *) 0);
453 #ifdef MASTER_XPORT_NAME_PASS
457 static void multi_server_accept_pass(
int unused_event,
void *context)
474 if (multi_server_pre_accept)
475 multi_server_pre_accept(multi_server_name, multi_server_argv);
477 if (multi_server_lock != 0
488 multi_server_wakeup(fd, attr);
495 static void multi_server_accept_inet(
int unused_event,
void *context)
511 if (multi_server_pre_accept)
512 multi_server_pre_accept(multi_server_name, multi_server_argv);
514 if (multi_server_lock != 0
525 multi_server_wakeup(fd, (
HTABLE *) 0);
532 const char *myname =
"multi_server_main";
538 char *service_name =
basename(argv[0]);
562 int msg_vstream_needed = 0;
563 int redo_syslog_init = 0;
564 const char *dsn_filter_title;
565 const char **dsn_filter_maps;
578 signal(SIGPIPE, SIG_IGN);
584 signal(SIGXFSZ, SIG_IGN);
623 while ((c =
GETOPT(argc, argv,
"cdDi:lm:n:o:s:St:uvVz")) > 0) {
644 service_name = optarg;
649 msg_fatal(
"invalid \"-o %s\" option value: %s", optarg, err);
652 redo_syslog_init = 1;
656 if ((socket_count = atoi(optarg)) <= 0)
657 msg_fatal(
"invalid socket_count: %s", optarg);
672 if (++msg_vstream_needed == 1)
689 if (redo_syslog_init)
701 if (daemon_mode && stream == 0 && isatty(STDIN_FILENO)) {
703 msg_fatal(
"do not run this command by hand");
709 va_start(ap, service);
710 while ((key = va_arg(ap,
int)) != 0) {
755 multi_server_in_flow_delay = 1;
758 if (stream == 0 && !alone)
759 msg_fatal(
"service %s requires a process limit of 1",
763 if (stream == 0 && !zerolimit)
764 msg_fatal(
"service %s requires a process limit of 0",
769 msg_fatal(
"service %s requires privileged operation",
773 dsn_filter_title = va_arg(ap,
const char *);
774 dsn_filter_maps = va_arg(ap,
const char **);
778 msg_panic(
"%s: unknown argument type: %d", myname, key);
793 msg_fatal(
"no transport type specified");
795 multi_server_accept = multi_server_accept_inet;
797 multi_server_accept = multi_server_accept_local;
798 #ifdef MASTER_XPORT_NAME_PASS
800 multi_server_accept = multi_server_accept_pass;
803 msg_fatal(
"unsupported transport type: %s", transport);
811 msg_fatal(
"bad generation: %s", generation);
814 msg_info(
"process generation: %s (%o)",
815 generation, multi_server_generation);
836 if (stream == 0 && !alone) {
838 ".", service_name, (
char *) 0);
840 if ((multi_server_lock =
safe_open(lock_path, O_CREAT | O_RDWR, 0600,
841 (
struct stat *) 0, -1, -1, why)) == 0)
852 multi_server_service = service;
853 multi_server_name = service_name;
854 multi_server_argv = argv + optind;
862 pre_init(multi_server_name, multi_server_argv);
875 post_init(multi_server_name, multi_server_argv);
887 service(stream, multi_server_name, multi_server_argv);
913 while (
var_use_limit == 0 || use_count < var_use_limit || client_count > 0) {
914 if (multi_server_lock != 0) {
921 delay = loop ? loop(multi_server_name, multi_server_argv) : -1;
void event_enable_read(int fd, EVENT_NOTIFY_RDWR_FN callback, void *context)
void msg_error(const char *fmt,...)
void htable_free(HTABLE *table, void(*free_fn)(void *))
#define MAIL_SERVER_UNLIMITED
const char * mail_task(const char *argv0)
#define MAIL_SERVER_STR_TABLE
char * mystrdup(const char *str)
int master_notify(int pid, unsigned generation, int status)
void set_mail_conf_str(const char *, const char *)
#define CAST_ANY_PTR_TO_INT(cptr)
void multi_server_disconnect(VSTREAM *stream)
NORETURN msg_panic(const char *fmt,...)
void(* MSG_CLEANUP_FN)(void)
void chroot_uid(const char *root_dir, const char *user_name)
#define MAIL_SERVER_INT_TABLE
#define MASTER_FLOW_WRITE
#define MYFLOCK_OP_EXCLUSIVE
#define OCTAL_TO_UNSIGNED(res, str)
#define MAIL_SERVER_TIME_TABLE
NORETURN multi_server_main(int argc, char **argv, MULTI_SERVER_FN service,...)
void(* MAIL_SERVER_DISCONN_FN)(VSTREAM *, char *, char **)
void get_mail_conf_nint_table(const CONFIG_NINT_TABLE *)
void(* MAIL_SERVER_EXIT_FN)(char *, char **)
#define CA_VSTREAM_CTL_DOUBLE
#define CA_VSTREAM_CTL_CONTEXT(v)
void get_mail_conf_nbool_table(const CONFIG_NBOOL_TABLE *)
#define MASTER_XPORT_NAME_PASS
#define EVENT_NULL_CONTEXT
int alldig(const char *string)
#define MASTER_STAT_AVAIL
const char * split_nameval(char *buf, char **name, char **value)
void watchdog_start(WATCHDOG *wp)
void(* WATCHDOG_FN)(WATCHDOG *, char *)
#define vstream_context(vp)
void mail_conf_suck(void)
#define MAIL_SERVER_BOOL_TABLE
#define MAIL_SERVER_PRIVILEGED
#define MAIL_SERVER_POST_INIT
#define MAIL_SERVER_BOUNCE_INIT
#define CA_VSTREAM_CTL_WRITE_FD(v)
void get_mail_conf_time_table(const CONFIG_TIME_TABLE *)
#define MAIL_SERVER_PRE_ACCEPT
#define MASTER_STAT_TAKEN
#define MAIL_SERVER_PRE_DISCONN
void(* MAIL_SERVER_INIT_FN)(char *, char **)
void get_mail_conf_raw_table(const CONFIG_RAW_TABLE *)
#define CAST_INT_TO_VOID_PTR(ival)
int vstream_fclose(VSTREAM *stream)
ssize_t mail_flow_get(ssize_t len)
void event_loop(int delay)
WATCHDOG * watchdog_create(unsigned timeout, WATCHDOG_FN action, char *context)
void msg_warn(const char *fmt,...)
#define MAIL_SERVER_IN_FLOW_DELAY
void resolve_local_init(void)
VSTRING * vstring_alloc(ssize_t len)
int myflock(int fd, int lock_style, int operation)
void mail_dict_init(void)
#define MASTER_XPORT_NAME_INET
void get_mail_conf_str_table(const CONFIG_STR_TABLE *)
void timed_ipc_setup(VSTREAM *stream)
NORETURN msg_fatal(const char *fmt,...)
void get_mail_conf_bool_table(const CONFIG_BOOL_TABLE *)
#define MASTER_XPORT_NAME_UNIX
#define MAIL_VERSION_CHECK
#define MAIL_SERVER_LONG_TABLE
int vstream_fflush(VSTREAM *stream)
void watchdog_stop(WATCHDOG *wp)
char * concatenate(const char *arg0,...)
#define GETOPT(argc, argv, str)
void bounce_client_init(const char *title, const char *maps)
void msg_syslog_init(const char *name, int logopt, int facility)
void(* MAIL_SERVER_ACCEPT_FN)(char *, char **)
#define MAIL_SERVER_NINT_TABLE
int strcasecmp(const char *s1, const char *s2)
int non_blocking(int, int)
VSTREAM * safe_open(const char *path, int flags, mode_t mode, struct stat *st, uid_t user, gid_t group, VSTRING *why)
VSTRING * vstring_free(VSTRING *vp)
time_t event_request_timer(EVENT_NOTIFY_TIME_FN callback, void *context, int delay)
#define MAIL_SERVER_PRE_INIT
void get_mail_conf_int_table(const CONFIG_INT_TABLE *)
#define vstream_fileno(vp)
void msg_vstream_init(const char *name, VSTREAM *vp)
#define vstream_flags(stream)
#define CA_VSTREAM_CTL_END
#define CA_VSTREAM_CTL_PATH(v)
int(* MAIL_SERVER_LOOP_FN)(char *, char **)
void get_mail_conf_long_table(const CONFIG_LONG_TABLE *)
void vstream_control(VSTREAM *stream, int name,...)
int multi_server_drain(void)
void event_disable_readwrite(int fd)
void mail_conf_update(const char *key, const char *value)
#define MAIL_SERVER_NBOOL_TABLE
int event_cancel_timer(EVENT_NOTIFY_TIME_FN callback, void *context)
int close_on_exec(int fd, int on)
#define MAIL_SERVER_RAW_TABLE
MSG_CLEANUP_FN msg_cleanup(MSG_CLEANUP_FN cleanup_fn)
int pass_accept_attr(int, HTABLE **)
#define MAIL_SERVER_SOLITARY
VSTREAM * vstream_fdopen(int fd, int flags)
void(* MULTI_SERVER_FN)(VSTREAM *, char *, char **)
void msg_info(const char *fmt,...)