X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/4e871f9b28dff4cacfd012aede1d092cc8cfbd36..90bd3832bc0ff090ac5e37dfc66b30cabb9cfc1a:/src/src/daemon.c diff --git a/src/src/daemon.c b/src/src/daemon.c index 028626c0e..3c63c6368 100644 --- a/src/src/daemon.c +++ b/src/src/daemon.c @@ -2,8 +2,8 @@ * Exim - an Internet mail transport agent * *************************************************/ -/* Copyright (c) The Exim Maintainers 2020 - 2022 */ -/* Copyright (c) University of Cambridge 1995 - 2023 */ +/* Copyright (c) The Exim Maintainers 2020 - 2023 */ +/* Copyright (c) University of Cambridge 1995 - 2018 */ /* See the file NOTICE for conditions of use and distribution. */ /* SPDX-License-Identifier: GPL-2.0-or-later */ @@ -128,7 +128,7 @@ never_error(uschar *log_msg, uschar *smtp_msg, int was_errno) uschar *emsg = was_errno <= 0 ? US"" : string_sprintf(": %s", strerror(was_errno)); log_write(0, LOG_MAIN|LOG_PANIC, "%s%s", log_msg, emsg); -if (smtp_out) smtp_printf("421 %s\r\n", FALSE, smtp_msg); +if (smtp_out) smtp_printf("421 %s\r\n", SP_NO_MORE, smtp_msg); } @@ -233,7 +233,7 @@ if (getsockname(accept_socket, (struct sockaddr *)(&interface_sockaddr), { log_write(0, LOG_MAIN | ((errno == ECONNRESET)? 0 : LOG_PANIC), "getsockname() failed: %s", strerror(errno)); - smtp_printf("421 Local problem: getsockname() failed; please try again later\r\n", FALSE); + smtp_printf("421 Local problem: getsockname() failed; please try again later\r\n", SP_NO_MORE); goto ERROR_RETURN; } @@ -263,7 +263,7 @@ if (smtp_accept_max > 0 && smtp_accept_count >= smtp_accept_max) DEBUG(D_any) debug_printf("rejecting SMTP connection: count=%d max=%d\n", smtp_accept_count, smtp_accept_max); smtp_printf("421 Too many concurrent SMTP connections; " - "please try again later.\r\n", FALSE); + "please try again later.\r\n", SP_NO_MORE); log_write(L_connection_reject, LOG_MAIN, "Connection from %Y refused: too many connections", whofrom); @@ -282,7 +282,7 @@ if (smtp_load_reserve >= 0) { DEBUG(D_any) debug_printf("rejecting SMTP connection: load average = %.2f\n", (double)load_average/1000.0); - smtp_printf("421 Too much load; please try again later.\r\n", FALSE); + smtp_printf("421 Too much load; please try again later.\r\n", SP_NO_MORE); log_write(L_connection_reject, LOG_MAIN, "Connection from %Y refused: load average = %.2f", whofrom, (double)load_average/1000.0); @@ -298,9 +298,10 @@ to provide host-specific limits according to $sender_host address, but because this is in the daemon mainline, only fast expansions (such as inline address checks) should be used. The documentation is full of warnings. */ +GET_OPTION("smtp_accept_max_per_host"); if (smtp_accept_max_per_host) { - uschar *expanded = expand_string(smtp_accept_max_per_host); + uschar * expanded = expand_string(smtp_accept_max_per_host); if (!expanded) { if (!f.expand_string_forcedfail) @@ -351,7 +352,7 @@ if (max_for_this_host > 0 && smtp_accept_count >= max_for_this_host) "IP address: count=%d max=%d\n", host_accept_count, max_for_this_host); smtp_printf("421 Too many concurrent SMTP connections " - "from this IP address; please try again later.\r\n", FALSE); + "from this IP address; please try again later.\r\n", SP_NO_MORE); log_write(L_connection_reject, LOG_MAIN, "Connection from %Y refused: too many connections " "from that IP address", whofrom); @@ -434,6 +435,7 @@ if (pid == 0) likely what it depends on.) */ smtp_active_hostname = primary_hostname; + GET_OPTION("smtp_active_hostname"); if (raw_active_hostname) { uschar * nah = expand_string(raw_active_hostname); @@ -445,7 +447,7 @@ if (pid == 0) "(smtp_active_hostname): %s", raw_active_hostname, expand_string_message); smtp_printf("421 Local configuration error; " - "please try again later.\r\n", FALSE); + "please try again later.\r\n", SP_NO_MORE); mac_smtp_fflush(); search_tidyup(); exim_underbar_exit(EXIT_FAILURE); @@ -1165,6 +1167,7 @@ return offsetof(struct sockaddr_un, sun_path) ssize_t daemon_notifier_sockname(struct sockaddr_un * sup) { +GET_OPTION("notifier_socket"); #ifdef EXIM_HAVE_ABSTRACT_UNIX_SOCKETS sup->sun_path[0] = 0; /* Abstract local socket addr - Linux-specific? */ return offsetof(struct sockaddr_un, sun_path) + 1 @@ -1258,10 +1261,9 @@ static const uschar * queuerun_msg_qname; /* The notifier socket has something to read. Pull the message from it, decode and do the action. +*/ -Return TRUE if a sigalrm should be emulated */ - -static BOOL +static void daemon_notification(void) { uschar buf[256], cbuf[256]; @@ -1277,8 +1279,8 @@ struct msghdr msg = { .msg_name = &sa_un, ssize_t sz; buf[sizeof(buf)-1] = 0; -if ((sz = recvmsg(daemon_notifier_fd, &msg, 0)) <= 0) return FALSE; -if (sz >= sizeof(buf)) return FALSE; +if ((sz = recvmsg(daemon_notifier_fd, &msg, 0)) <= 0) return; +if (sz >= sizeof(buf)) return; #ifdef notdef debug_printf("addrlen %d\n", msg.msg_namelen); @@ -1351,7 +1353,7 @@ switch (buf[0]) : !buf[1+MESSAGE_ID_LENGTH+1] ) { queuerun_msg_qname = q->name; break; } - return TRUE; + return; #endif case NOTIFY_QUEUE_SIZE_REQ: @@ -1373,7 +1375,7 @@ switch (buf[0]) regex_at_daemon(buf); break; } -return FALSE; +return; } @@ -1432,7 +1434,7 @@ for (qrunner * q = qrunners, * next; q; q = next) if (sorted) { qrunner ** p = &sorted; - for (qrunner * qq; qq = *p; p = &(qq->next)) + for (qrunner * qq; qq = *p; p = &qq->next) if ( q->next_tick < qq->next_tick || q->next_tick == qq->next_tick && q->interval < qq->interval ) @@ -1451,6 +1453,13 @@ qrunners = sorted; return qrunners ? qrunners->next_tick - time(NULL) : 0; } +/* See if we can do a queue run. If policy limit permit, kick one off. +If both notification and timer events are present, handle the former +and leave the timer outstanding. + +Return the number of seconds until the next due runner. +*/ + static int daemon_qrun(int local_queue_run_max, struct pollfd * fd_polls, int listen_socket_count) { @@ -1464,13 +1473,16 @@ DEBUG(D_any) debug_printf("%s received\n", enough queue runners on the go. If we are not running as root, a re-exec is required. In the calling process, restart the alamr timer for the next run. */ -if (is_multiple_qrun()) +if (is_multiple_qrun()) /* we are managing periodic runs */ if (local_queue_run_max <= 0 || queue_run_count < local_queue_run_max) { qrunner * q = NULL; #ifndef DISABLE_QUEUE_RAMP - if (*queuerun_msgid) /* See if we can start another runner for this queue */ + /* If this is a triggered run for a specific message, see if we can start + another runner for this queue. */ + + if (*queuerun_msgid) { for (qrunner * qq = qrunners; qq; qq = qq->next) if (qq->name == queuerun_msg_qname) @@ -1481,13 +1493,13 @@ if (is_multiple_qrun()) } else #endif - /* In order of run priority, find the first queue for which we can start - a runner */ + /* Normal periodic runL in order of run priority, find the first queue + for which we can start a runner */ for (q = qrunners; q; q = q->next) if (q->run_count < q->run_max) break; - if (q) + if (q) /* found a queue to run */ { pid_t pid; @@ -1619,19 +1631,23 @@ if (is_multiple_qrun()) } } -sigalrm_seen = FALSE; +/* The queue run has been initiated (unless we were already running enough) */ + #ifndef DISABLE_QUEUE_RAMP -if (*queuerun_msgid) /* it was a fast-ramp kick */ +if (*queuerun_msgid) /* it was a fast-ramp kick; dealt with */ *queuerun_msgid = 0; else /* periodic or one-time queue run */ #endif - { /* Impose a minimum 1s tick, even when a run was outstanding */ + /* Set up next timer callback. Impose a minimum 1s tick, + even when a run was outstanding */ + { int interval = next_qrunner_interval(); if (interval <= 0) interval = 1; + sigalrm_seen = FALSE; if (qrunners) /* there are still periodic qrunners */ { - ALARM(interval); + ALARM(interval); /* set up next qrun tick */ return interval; } } @@ -1641,7 +1657,7 @@ return 0; -const uschar * +static const uschar * describe_queue_runners(void) { gstring * g = NULL; @@ -1651,6 +1667,7 @@ if (!is_multiple_qrun()) return US"no queue runs"; for (qrunner * q = qrunners; q; q = q->next) { g = string_catn(g, US"-q", 2); + if (q->queue_2stage) g = string_catn(g, US"q", 1); if (q->name) g = string_append(g, 3, US"G", q->name, US"/"); g = string_cat(g, readconf_printtime(q->interval)); g = string_catn(g, US" ", 1); @@ -1695,12 +1712,13 @@ time_t last_connection_time = (time_t)0; int local_queue_run_max = 0; if (is_multiple_qrun()) - + { /* Nuber of runner-tracking structs needed: If the option queue_run_max has no expandable elements then it is the overall maximum; else we assume it depends on the queue name, and add them up to get the maximum. Evaluate both that and the individual limits. */ + GET_OPTION("queue_run_max"); if (Ustrchr(queue_run_max, '$') != NULL) { for (qrunner * q = qrunners; q; q = q->next) @@ -1717,6 +1735,7 @@ if (is_multiple_qrun()) for (qrunner * q = qrunners; q; q = q->next) q->run_max = local_queue_run_max; } + } process_purpose = US"daemon"; @@ -2612,7 +2631,7 @@ for (;;) The other option is that we have an inetd wait timeout specified to -bw. */ - if (sigalrm_seen) + if (sigalrm_seen || *queuerun_msgid) if (inetd_wait_timeout > 0) daemon_inetd_wtimeout(last_connection_time); /* Might not return */ else @@ -2641,7 +2660,9 @@ for (;;) select() was interrupted so that we reap the child. This might still leave a small window when a SIGCHLD could get lost. However, since we use SIGCHLD only to do the reaping more quickly, it shouldn't result in anything other - than a delay until something else causes a wake-up. */ + than a delay until something else causes a wake-up. + For the normal case, wait for either a pollable fd (eg. new connection) or + or a SIGALRM (for a periodic queue run) */ if (sigchld_seen) { @@ -2706,10 +2727,13 @@ for (;;) break; /* to top of daemon loop */ } #endif + /* Handle the daemon-notifier socket. If it was a fast-ramp + notification then queuerun_msgid will have a nonzerolength string. */ + if (dnotify_poll && dnotify_poll->revents & POLLIN) { dnotify_poll->revents = 0; - sigalrm_seen = daemon_notification(); + daemon_notification(); break; /* to top of daemon loop */ } for (struct pollfd * p = fd_polls; p < fd_polls + listen_socket_count;