X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/feef71897f2e24910009744b3aeb735cf07da31b..1843f70b733127fcba3321d9d69359e05905f8cc:/src/src/receive.c diff --git a/src/src/receive.c b/src/src/receive.c index 750744016..d2e556e32 100644 --- a/src/src/receive.c +++ b/src/src/receive.c @@ -44,42 +44,71 @@ receive_getc initially. They just call the standard functions, passing stdin as the file. (When SMTP input is occurring, different functions are used by changing the pointer variables.) */ -int -stdin_getc(unsigned lim) -{ -int c = getc(stdin); +uschar stdin_buf[4096]; +uschar * stdin_inptr = stdin_buf; +uschar * stdin_inend = stdin_buf; -if (had_data_timeout) - { - fprintf(stderr, "exim: timed out while reading - message abandoned\n"); - log_write(L_lost_incoming_connection, - LOG_MAIN, "timed out while reading local message"); - receive_bomb_out(US"data-timeout", NULL); /* Does not return */ - } -if (had_data_sigint) +static BOOL +stdin_refill(void) +{ +size_t rc = fread(stdin_buf, 1, sizeof(stdin_buf), stdin); +if (rc <= 0) { - if (filter_test == FTEST_NONE) + if (had_data_timeout) { - fprintf(stderr, "\nexim: %s received - message abandoned\n", - had_data_sigint == SIGTERM ? "SIGTERM" : "SIGINT"); - log_write(0, LOG_MAIN, "%s received while reading local message", - had_data_sigint == SIGTERM ? "SIGTERM" : "SIGINT"); + fprintf(stderr, "exim: timed out while reading - message abandoned\n"); + log_write(L_lost_incoming_connection, + LOG_MAIN, "timed out while reading local message"); + receive_bomb_out(US"data-timeout", NULL); /* Does not return */ } - receive_bomb_out(US"signal-exit", NULL); /* Does not return */ + if (had_data_sigint) + { + if (filter_test == FTEST_NONE) + { + fprintf(stderr, "\nexim: %s received - message abandoned\n", + had_data_sigint == SIGTERM ? "SIGTERM" : "SIGINT"); + log_write(0, LOG_MAIN, "%s received while reading local message", + had_data_sigint == SIGTERM ? "SIGTERM" : "SIGINT"); + } + receive_bomb_out(US"signal-exit", NULL); /* Does not return */ + } + return FALSE; } -return c; +stdin_inend = stdin_buf + rc; +stdin_inptr = stdin_buf; +return TRUE; +} + +int +stdin_getc(unsigned lim) +{ +if (stdin_inptr >= stdin_inend) + if (!stdin_refill()) + return EOF; +return *stdin_inptr++; +} + + +BOOL +stdin_hasc(void) +{ +return stdin_inptr < stdin_inend; } int stdin_ungetc(int c) { -return ungetc(c, stdin); +if (stdin_inptr <= stdin_buf) + log_write(0, LOG_MAIN|LOG_PANIC_DIE, "buffer underflow in stdin_ungetc"); + +*--stdin_inptr = c; +return c; } int stdin_feof(void) { -return feof(stdin); +return stdin_hasc() ? FALSE : feof(stdin); } int @@ -588,7 +617,7 @@ the file copy. */ static void log_close_chk(void) { -if (!receive_timeout) +if (!receive_timeout && !receive_hasc()) { struct timeval t; timesince(&t, &received_time); @@ -654,11 +683,6 @@ if (!f.dot_ends) { int last_ch = '\n'; -/*XXX we do a gettimeofday before checking for every received char, -which is hardly clever. The function-indirection doesn't help, but -an additional function to check for nonempty read buffer would help. -See stdin_getc() / smtp_getc() / tls_getc() / bdat_getc(). */ - for ( ; log_close_chk(), (ch = (receive_getc)(GETC_BUFFER_UNLIMITED)) != EOF; last_ch = ch) @@ -1663,10 +1687,9 @@ int process_info_len = Ustrlen(process_info); int error_rc = error_handling == ERRORS_SENDER ? errors_sender_rc : EXIT_FAILURE; int header_size = 256; -int start, end, domain; -int id_resolution = 0; int had_zero = 0; int prevlines_length = 0; +const int id_resolution = BASE_62 == 62 ? 5000 : 10000; int ptr = 0; @@ -1720,6 +1743,10 @@ BOOL msgid_header_newly_created = FALSE; uschar *timestamp; int tslen; +/* Time of creation of message_id */ + +static struct timeval message_id_tv = { 0, 0 }; + /* Release any open files that might have been cached while preparing to accept the message - e.g. by verifying addresses - because reading a message @@ -1786,17 +1813,40 @@ if (smtp_input && !smtp_batched_input && !f.dkim_disable_verify) if (sender_host_address) dmarc_init(); /* initialize libopendmarc */ #endif +/* In SMTP sessions we may receive several messages in one connection. Before +each subsequent one, we wait for the clock to tick at the level of message-id +granularity. +This is so that the combination of time+pid is unique, even on systems where the +pid can be re-used within our time interval. We can't shorten the interval +without re-designing the message-id. See comments above where the message id is +created. This is Something For The Future. +Do this wait any time we have previously created a message-id, even if we +rejected the message. This gives unique IDs for logging done by ACLs. +The initial timestamp must have been obtained via exim_gettime() to avoid +issues on Linux with suspend/resume. */ + +if (message_id_tv.tv_sec) + { + message_id_tv.tv_usec = (message_id_tv.tv_usec/id_resolution) * id_resolution; + exim_wait_tick(&message_id_tv, id_resolution); + } + /* Remember the time of reception. Exim uses time+pid for uniqueness of message ids, and fractions of a second are required. See the comments that precede the -message id creation below. */ +message id creation below. +We use a routine that if possible uses a monotonic clock, and can be used again +after reception for the tick-wait even under the Linux non-Posix behaviour. */ -exim_gettime(&message_id_tv); +else + exim_gettime(&message_id_tv); /* For other uses of the received time we can operate with granularity of one second, and for that we use the global variable received_time. This is for -things like ultimate message timeouts. */ +things like ultimate message timeouts. +For this we do not care about the Linux suspend/resume problem, so rather than +use exim_gettime() everywhere we use a plain gettimeofday() here. */ -received_time = message_id_tv; +gettimeofday(&received_time, NULL); /* If SMTP input, set the special handler for timeouts. The alarm() calls happen in the smtp_getc() function when it refills its buffer. */ @@ -2561,11 +2611,12 @@ if (extract_recip) &domain, FALSE); #ifdef SUPPORT_I18N - if (string_is_utf8(recipient)) - message_smtputf8 = TRUE; - else - allow_utf8_domains = b; + if (recipient) + if (string_is_utf8(recipient)) message_smtputf8 = TRUE; + else allow_utf8_domains = b; } +#else + ; #endif /* Keep a list of all the bad addresses so we can send a single @@ -2676,28 +2727,20 @@ message_id[6] = '-'; Ustrncpy(message_id + 7, string_base62((long int)getpid()), 6); /* Deal with the case where the host number is set. The value of the number was -checked when it was read, to ensure it isn't too big. The timing granularity is -left in id_resolution so that an appropriate wait can be done after receiving -the message, if necessary (we hope it won't be). */ +checked when it was read, to ensure it isn't too big. */ if (host_number_string) - { - id_resolution = BASE_62 == 62 ? 5000 : 10000; sprintf(CS(message_id + MESSAGE_ID_LENGTH - 3), "-%2s", string_base62((long int)( host_number * (1000000/id_resolution) + message_id_tv.tv_usec/id_resolution)) + 4); - } /* Host number not set: final field is just the fractional time at an appropriate resolution. */ else - { - id_resolution = BASE_62 == 62 ? 500 : 1000; sprintf(CS(message_id + MESSAGE_ID_LENGTH - 3), "-%2s", string_base62((long int)(message_id_tv.tv_usec/id_resolution)) + 4); - } /* Add the current message id onto the current process info string if it will fit. */ @@ -4079,6 +4122,8 @@ if ( LOGGING(msg_id) && msgid_header uschar * old_id; BOOL save_allow_domain_literals = allow_domain_literals; allow_domain_literals = TRUE; + int start, end, domain; + old_id = parse_extract_address(Ustrchr(msgid_header->text, ':') + 1, &errmsg, &start, &end, &domain, FALSE); allow_domain_literals = save_allow_domain_literals; @@ -4318,23 +4363,6 @@ then we can think about properly declaring the message not-received. */ TIDYUP: -/* In SMTP sessions we may receive several messages in one connection. After -each one, we wait for the clock to tick at the level of message-id granularity. -This is so that the combination of time+pid is unique, even on systems where the -pid can be re-used within our time interval. We can't shorten the interval -without re-designing the message-id. See comments above where the message id is -created. This is Something For The Future. -Do this wait any time we have created a message-id, even if we rejected the -message. This gives unique IDs for logging done by ACLs. */ - -if (id_resolution != 0) - { - message_id_tv.tv_usec = (message_id_tv.tv_usec/id_resolution) * id_resolution; - exim_wait_tick(&message_id_tv, id_resolution); - id_resolution = 0; - } - - process_info[process_info_len] = 0; /* Remove message id */ if (spool_data_file && cutthrough_done == NOT_TRIED) {