189 #include <sys/socket.h>
190 #include <sys/time.h>
200 #ifdef STRCASECMP_IN_STRINGS_H
205 #ifdef USE_SYS_SELECT_H
206 #include <sys/select.h>
254 static int client_count;
255 static int use_count;
256 static int socket_count = 1;
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;
274 static NORETURN event_server_exit(
void)
276 if (event_server_onexit)
277 event_server_onexit(event_server_name, event_server_argv);
283 static void event_server_abort(
int unused_event,
void *unused_context)
286 msg_info(
"master disconnect -- exiting");
288 if (event_server_slow_exit)
289 event_server_slow_exit(event_server_name, event_server_argv);
296 static void event_server_timeout(
int unused_event,
void *unused_context)
299 msg_info(
"idle timeout -- exiting");
307 const char *myname =
"event_server_drain";
322 if (
DUP2(STDIN_FILENO, fd) < 0)
323 msg_warn(
"%s: dup2(%d, %d): %m", myname, STDIN_FILENO, fd);
339 if (event_server_pre_disconn)
340 event_server_pre_disconn(stream, event_server_name, event_server_argv);
344 if (use_count < INT_MAX)
352 static void event_server_execute(
int unused_event,
void *context)
358 if (event_server_lock != 0
370 event_server_service(stream, event_server_name, event_server_argv);
379 static void event_server_wakeup(
int fd,
HTABLE *attr)
384 #if defined(F_DUPFD) && (EVENTS_STYLE != EVENTS_STYLE_SELECT)
385 #ifndef THRESHOLD_FD_WORKAROUND
386 #define THRESHOLD_FD_WORKAROUND 128
394 if (fd < THRESHOLD_FD_WORKAROUND) {
395 if ((new_fd = fcntl(fd, F_DUPFD, THRESHOLD_FD_WORKAROUND)) < 0)
402 msg_info(
"connection established fd %d", fd);
407 tmp =
concatenate(event_server_name,
" socket", (
char *) 0);
419 event_server_execute(0, (
void *) stream);
424 static void event_server_accept_local(
int unused_event,
void *context)
440 if (event_server_pre_accept)
441 event_server_pre_accept(event_server_name, event_server_argv);
443 if (event_server_lock != 0
454 event_server_wakeup(fd, (
HTABLE *) 0);
457 #ifdef MASTER_XPORT_NAME_PASS
461 static void event_server_accept_pass(
int unused_event,
void *context)
478 if (event_server_pre_accept)
479 event_server_pre_accept(event_server_name, event_server_argv);
481 if (event_server_lock != 0
492 event_server_wakeup(fd, attr);
499 static void event_server_accept_inet(
int unused_event,
void *context)
515 if (event_server_pre_accept)
516 event_server_pre_accept(event_server_name, event_server_argv);
518 if (event_server_lock != 0
529 event_server_wakeup(fd, (
HTABLE *) 0);
536 const char *myname =
"event_server_main";
542 char *service_name =
basename(argv[0]);
566 int msg_vstream_needed = 0;
567 int redo_syslog_init = 0;
568 const char *dsn_filter_title;
569 const char **dsn_filter_maps;
582 signal(SIGPIPE, SIG_IGN);
588 signal(SIGXFSZ, SIG_IGN);
627 while ((c =
GETOPT(argc, argv,
"cdDi:lm:n:o:s:St:uvVz")) > 0) {
648 service_name = optarg;
653 msg_fatal(
"invalid \"-o %s\" option value: %s", optarg, err);
656 redo_syslog_init = 1;
660 if ((socket_count = atoi(optarg)) <= 0)
661 msg_fatal(
"invalid socket_count: %s", optarg);
676 if (++msg_vstream_needed == 1)
693 if (redo_syslog_init)
705 if (daemon_mode && stream == 0 && isatty(STDIN_FILENO)) {
707 msg_fatal(
"do not run this command by hand");
713 va_start(ap, service);
714 while ((key = va_arg(ap,
int)) != 0) {
759 event_server_in_flow_delay = 1;
762 if (stream == 0 && !alone)
763 msg_fatal(
"service %s requires a process limit of 1",
767 if (stream == 0 && !zerolimit)
768 msg_fatal(
"service %s requires a process limit of 0",
773 msg_fatal(
"service %s requires privileged operation",
777 event_server_watchdog = *va_arg(ap,
int *);
783 dsn_filter_title = va_arg(ap,
const char *);
784 dsn_filter_maps = va_arg(ap,
const char **);
788 msg_panic(
"%s: unknown argument type: %d", myname, key);
803 msg_fatal(
"no transport type specified");
805 event_server_accept = event_server_accept_inet;
807 event_server_accept = event_server_accept_local;
808 #ifdef MASTER_XPORT_NAME_PASS
810 event_server_accept = event_server_accept_pass;
813 msg_fatal(
"unsupported transport type: %s", transport);
821 msg_fatal(
"bad generation: %s", generation);
824 msg_info(
"process generation: %s (%o)",
825 generation, event_server_generation);
846 if (stream == 0 && !alone) {
848 ".", service_name, (
char *) 0);
850 if ((event_server_lock =
safe_open(lock_path, O_CREAT | O_RDWR, 0600,
851 (
struct stat *) 0, -1, -1, why)) == 0)
862 event_server_service = service;
863 event_server_name = service_name;
864 event_server_argv = argv + optind;
872 pre_init(event_server_name, event_server_argv);
885 post_init(event_server_name, event_server_argv);
897 service(stream, event_server_name, event_server_argv);
924 while (
var_use_limit == 0 || use_count < var_use_limit || client_count > 0) {
925 if (event_server_lock != 0) {
932 delay = loop ? loop(event_server_name, event_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)
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 MAIL_SERVER_SLOW_EXIT
#define OCTAL_TO_UNSIGNED(res, str)
#define MAIL_SERVER_TIME_TABLE
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
void(* MAIL_SERVER_SLOW_EXIT_FN)(char *, char **)
#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)
#define MAIL_SERVER_WATCHDOG
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
int event_server_drain(void)
#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)
NORETURN event_server_main(int argc, char **argv, MULTI_SERVER_FN service,...)
void event_server_disconnect(VSTREAM *stream)
#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,...)
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,...)