X-Git-Url: https://git.exim.org/users/jgh/exim.git/blobdiff_plain/584ddd64e2f0caa3673bb219407e084826f5d965..4c04137d73637107669e02b21f890387aaa2ef34:/src/src/transports/smtp.c diff --git a/src/src/transports/smtp.c b/src/src/transports/smtp.c index e8a675750..870827170 100644 --- a/src/src/transports/smtp.c +++ b/src/src/transports/smtp.c @@ -124,6 +124,8 @@ optionlist smtp_transport_options[] = { { "hosts_try_dane", opt_stringptr, (void *)offsetof(smtp_transport_options_block, hosts_try_dane) }, #endif + { "hosts_try_fastopen", opt_stringptr, + (void *)offsetof(smtp_transport_options_block, hosts_try_fastopen) }, #ifndef DISABLE_PRDR { "hosts_try_prdr", opt_stringptr, (void *)offsetof(smtp_transport_options_block, hosts_try_prdr) }, @@ -209,6 +211,7 @@ smtp_transport_options_block smtp_transport_option_defaults = { NULL, /* hosts_try_dane */ NULL, /* hosts_require_dane */ #endif + NULL, /* hosts_try_fastopen */ #ifndef DISABLE_PRDR US"*", /* hosts_try_prdr */ #endif @@ -282,10 +285,11 @@ static uschar *rf_names[] = { US"NEVER", US"SUCCESS", US"FAILURE", US"DELAY" }; /* Local statics */ -static uschar *smtp_command; /* Points to last cmd for error messages */ -static uschar *mail_command; /* Points to MAIL cmd for error messages */ -static BOOL update_waiting; /* TRUE to update the "wait" database */ -static BOOL pipelining_active; /* current transaction is in pipe mode */ +static uschar *smtp_command; /* Points to last cmd for error messages */ +static uschar *mail_command; /* Points to MAIL cmd for error messages */ +static uschar *data_command = US""; /* Points to DATA cmd for error messages */ +static BOOL update_waiting; /* TRUE to update the "wait" database */ +static BOOL pipelining_active; /* current transaction is in pipe mode */ /************************************************* @@ -504,7 +508,7 @@ Arguments: more_errno from the top address for use with ERRNO_FILTER_FAIL buffer the SMTP response buffer yield where to put a one-digit SMTP response code - message where to put an errror message + message where to put an error message pass_message set TRUE if message is an SMTP response Returns: TRUE if an SMTP "QUIT" command should be sent, else FALSE @@ -1387,10 +1391,14 @@ uschar * buffer = tctx->buffer; /* Write SMTP chunk header command */ if (chunk_size > 0) + { if((cmd_count = smtp_write_command(tctx->outblock, FALSE, "BDAT %u%s\r\n", chunk_size, flags & tc_chunk_last ? " LAST" : "") ) < 0) return ERROR; + if (flags & tc_chunk_last) + data_command = string_copy(big_buffer); /* Save for later error message */ + } prev_cmd_count = cmd_count += tctx->cmd_count; @@ -1574,10 +1582,6 @@ lflags.send_quit = TRUE; lflags.setting_up = TRUE; lflags.esmtp = TRUE; lflags.esmtp_sent = FALSE; -lflags.pending_MAIL; -#ifndef DISABLE_PRDR -lflags.prdr_active; -#endif #ifdef SUPPORT_I18N lflags.utf8_needed = FALSE; #endif @@ -1589,6 +1593,7 @@ lflags.dane_required = verify_check_given_host(&ob->hosts_require_dane, host) == *message_defer = FALSE; smtp_command = US"initial connection"; +buffer[0] = '\0'; if (max_rcpt == 0) max_rcpt = 999999; /* Set up the buffer for reading SMTP response packets. */ @@ -1709,7 +1714,12 @@ if (continue_hostname == NULL) if (!lflags.smtps) { - BOOL good_response = smtp_read_response(&inblock, buffer, sizeof(buffer), + BOOL good_response; + +#ifdef TCP_QUICKACK + (void) setsockopt(inblock.sock, IPPROTO_TCP, TCP_QUICKACK, US &off, sizeof(off)); +#endif + good_response = smtp_read_response(&inblock, buffer, sizeof(buffer), '2', ob->command_timeout); #ifdef EXPERIMENTAL_DSN_INFO smtp_greeting = string_copy(buffer); @@ -1736,7 +1746,7 @@ if (continue_hostname == NULL) /* Now check if the helo_data expansion went well, and sign off cleanly if it didn't. */ - if (helo_data == NULL) + if (!helo_data) { uschar *message = string_sprintf("failed to expand helo_data: %s", expand_string_message); @@ -1883,7 +1893,7 @@ set from the command line if they were set in the process that passed the connection on. */ /*XXX continue case needs to propagate DSN_INFO, prob. in deliver.c -as the contine goes via transport_pass_socket() and doublefork and exec. +as the continue goes via transport_pass_socket() and doublefork and exec. It does not wait. Unclear how we keep separate host's responses separate - we could match up by host ip+port as a bodge. */ @@ -1949,12 +1959,9 @@ if ( smtp_peer_options & PEER_OFFERED_TLS if (rc != OK) { # ifdef EXPERIMENTAL_DANE - if (rc == DEFER && lflags.dane) - { - log_write(0, LOG_MAIN, + if (lflags.dane) log_write(0, LOG_MAIN, "DANE attempt failed; no TLS connection to %s [%s]", host->name, host->address); - } # endif save_errno = ERRNO_TLSFAILURE; @@ -2172,10 +2179,10 @@ set it up. This cannot be done until the identify of the host is known. */ if (tblock->filter_command != NULL) { BOOL rc; - uschar buffer[64]; - sprintf(CS buffer, "%.50s transport", tblock->name); + uschar fbuf[64]; + sprintf(CS fbuf, "%.50s transport", tblock->name); rc = transport_set_up_command(&transport_filter_argv, tblock->filter_command, - TRUE, DEFER, addrlist, buffer, NULL); + TRUE, DEFER, addrlist, fbuf, NULL); transport_filter_timeout = tblock->filter_timeout; /* On failure, copy the error to all addresses, abandon the SMTP call, and @@ -2422,17 +2429,14 @@ for (addr = first_addr; rcpt_addr = transport_rcpt_address(addr, tblock->rcpt_include_affixes); #ifdef SUPPORT_I18N - { - uschar * dummy_errstr; if ( testflag(addrlist, af_utf8_downcvt) - && (rcpt_addr = string_address_utf8_to_alabel(rcpt_addr, &dummy_errstr), - dummy_errstr - ) ) + && !(rcpt_addr = string_address_utf8_to_alabel(rcpt_addr, NULL)) + ) { + /*XXX could we use a per-address errstr here? Not fail the whole send? */ errno = ERRNO_EXPANDFAIL; goto SEND_FAILED; } - } #endif count = smtp_write_command(&outblock, no_flush, "RCPT TO:<%s>%s%s\r\n", @@ -2510,6 +2514,7 @@ if ( !(peer_offered & PEER_OFFERED_CHUNKING) default: goto RESPONSE_FAILED; /* I/O error, or any MAIL/DATA error */ } pipelining_active = FALSE; + data_command = string_copy(big_buffer); /* Save for later error message */ } /* If there were no good recipients (but otherwise there have been no @@ -2733,7 +2738,7 @@ else #else "LMTP error after %s: %s", #endif - big_buffer, string_printing(buffer)); + data_command, string_printing(buffer)); setflag(addr, af_pass_message); /* Allow message to go to user */ if (buffer[0] == '5') addr->transport_return = FAIL; @@ -3104,7 +3109,7 @@ if (completed_address && lflags.ok && lflags.send_quit) } #endif - /* If the socket is successfully passed, we musn't send QUIT (or + /* If the socket is successfully passed, we mustn't send QUIT (or indeed anything!) from here. */ /*XXX DSN_INFO: assume likely to do new HELO; but for greet we'll want to @@ -3163,6 +3168,13 @@ specified in the transports, and therefore not visible at top level, in which case continue_more won't get set. */ HDEBUG(D_transport|D_acl|D_v) debug_printf(" SMTP(close)>>\n"); +if (lflags.send_quit) + { + shutdown(outblock.sock, SHUT_WR); + if (fcntl(inblock.sock, F_SETFL, O_NONBLOCK) == 0) + for (rc = 16; read(inblock.sock, inbuffer, sizeof(inbuffer)) > 0 && rc > 0;) + rc--; /* drain socket */ + } (void)close(inblock.sock); #ifndef DISABLE_EVENT