X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/58c09a7fadb47400d4e90a6bf11d86dcc298eea9..d12746bc15d83ab821be36975da0179672708bc1:/src/src/smtp_in.c diff --git a/src/src/smtp_in.c b/src/src/smtp_in.c index 2a83392ac..54ebf3660 100644 --- a/src/src/smtp_in.c +++ b/src/src/smtp_in.c @@ -145,6 +145,9 @@ static struct { BOOL helo_verify :1; BOOL helo_seen :1; BOOL helo_accept_junk :1; +#ifdef EXPERIMENTAL_PIPE_CONNECT + BOOL pipe_connect_acceptable :1; +#endif BOOL rcpt_smtp_response_same :1; BOOL rcpt_in_progress :1; BOOL smtp_exit_function_called :1; @@ -404,6 +407,18 @@ return TRUE; } +#ifdef EXPERIMENTAL_PIPE_CONNECT +static BOOL +pipeline_connect_sends(void) +{ +if (!sender_host_address || f.sender_host_notsocket || !fl.pipe_connect_acceptable) + return FALSE; + +if (wouldblock_reading()) return FALSE; +f.smtp_in_early_pipe_used = TRUE; +return TRUE; +} +#endif /************************************************* * Log incomplete transactions * @@ -898,18 +913,20 @@ call another vararg function, only a function which accepts a va_list. */ void smtp_vprintf(const char *format, BOOL more, va_list ap) { +gstring gs = { .size = big_buffer_size, .ptr = 0, .s = big_buffer }; BOOL yield; -yield = string_vformat(big_buffer, big_buffer_size, format, ap); +yield = !! string_vformat(&gs, FALSE, format, ap); +string_from_gstring(&gs); DEBUG(D_receive) { void *reset_point = store_get(0); uschar *msg_copy, *cr, *end; - msg_copy = string_copy(big_buffer); - end = msg_copy + Ustrlen(msg_copy); + msg_copy = string_copy(gs.s); + end = msg_copy + gs.ptr; while ((cr = Ustrchr(msg_copy, '\r')) != NULL) /* lose CRs */ - memmove(cr, cr + 1, (end--) - cr); + memmove(cr, cr + 1, (end--) - cr); debug_printf("SMTP>> %s", msg_copy); store_reset(reset_point); } @@ -942,13 +959,13 @@ if (fl.rcpt_in_progress) #ifdef SUPPORT_TLS if (tls_in.active.sock >= 0) { - if (tls_write(NULL, big_buffer, Ustrlen(big_buffer), more) < 0) + if (tls_write(NULL, gs.s, gs.ptr, more) < 0) smtp_write_error = -1; } else #endif -if (fprintf(smtp_out, "%s", big_buffer) < 0) smtp_write_error = -1; +if (fprintf(smtp_out, "%s", gs.s) < 0) smtp_write_error = -1; } @@ -1842,7 +1859,7 @@ for (i = 0; i < smtp_ch_index; i++) if (!(s = string_from_gstring(g))) s = US""; log_write(0, LOG_MAIN, "no MAIL in %sSMTP connection from %s D=%s%s", - f.tcp_in_fastopen ? US"TFO " : US"", + f.tcp_in_fastopen ? f.tcp_in_fastopen_data ? US"TFO* " : US"TFO " : US"", host_and_ident(FALSE), string_timesince(&smtp_connection_start), s); } @@ -2392,13 +2409,20 @@ tfo_in_check(void) struct tcp_info tinfo; socklen_t len = sizeof(tinfo); -if ( getsockopt(fileno(smtp_out), IPPROTO_TCP, TCP_INFO, &tinfo, &len) == 0 - && tinfo.tcpi_state == TCP_SYN_RECV - ) - { - DEBUG(D_receive) debug_printf("TCP_FASTOPEN mode connection (state TCP_SYN_RECV)\n"); - f.tcp_in_fastopen = TRUE; - } +if (getsockopt(fileno(smtp_out), IPPROTO_TCP, TCP_INFO, &tinfo, &len) == 0) +#ifdef TCPI_OPT_SYN_DATA /* FreeBSD 11 does not seem to have this yet */ + if (tinfo.tcpi_options & TCPI_OPT_SYN_DATA) + { + DEBUG(D_receive) debug_printf("TCP_FASTOPEN mode connection (ACKd data-on-SYN)\n"); + f.tcp_in_fastopen_data = f.tcp_in_fastopen = TRUE; + } + else +#endif + if (tinfo.tcpi_state == TCP_SYN_RECV) + { + DEBUG(D_receive) debug_printf("TCP_FASTOPEN mode connection (state TCP_SYN_RECV)\n"); + f.tcp_in_fastopen = TRUE; + } # endif } #endif @@ -2987,22 +3011,39 @@ while (*p); /* Before we write the banner, check that there is no input pending, unless this synchronisation check is disabled. */ +#ifdef EXPERIMENTAL_PIPE_CONNECT +fl.pipe_connect_acceptable = + sender_host_address && verify_check_host(&pipe_connect_advertise_hosts) == OK; + if (!check_sync()) - { - unsigned n = smtp_inend - smtp_inptr; - if (n > 32) n = 32; - - log_write(0, LOG_MAIN|LOG_REJECT, "SMTP protocol " - "synchronization error (input sent without waiting for greeting): " - "rejected connection from %s input=\"%s\"", host_and_ident(TRUE), - string_printing(string_copyn(smtp_inptr, n))); - smtp_printf("554 SMTP synchronization error\r\n", FALSE); - return FALSE; - } + if (fl.pipe_connect_acceptable) + f.smtp_in_early_pipe_used = TRUE; + else +#else +if (!check_sync()) +#endif + { + unsigned n = smtp_inend - smtp_inptr; + if (n > 32) n = 32; + + log_write(0, LOG_MAIN|LOG_REJECT, "SMTP protocol " + "synchronization error (input sent without waiting for greeting): " + "rejected connection from %s input=\"%s\"", host_and_ident(TRUE), + string_printing(string_copyn(smtp_inptr, n))); + smtp_printf("554 SMTP synchronization error\r\n", FALSE); + return FALSE; + } /* Now output the banner */ +/*XXX the ehlo-resp code does its own tls/nontls bit. Maybe subroutine that? */ -smtp_printf("%s", FALSE, string_from_gstring(ss)); +smtp_printf("%s", +#ifdef EXPERIMENTAL_PIPE_CONNECT + fl.pipe_connect_acceptable && pipeline_connect_sends(), +#else + FALSE, +#endif + string_from_gstring(ss)); /* Attempt to see if we sent the banner before the last ACK of the 3-way handshake arrived. If so we must have managed a TFO. */ @@ -3479,13 +3520,13 @@ if (code && defaultrespond) smtp_respond(code, 3, TRUE, user_msg); else { - uschar buffer[128]; + gstring * g; va_list ap; + va_start(ap, defaultrespond); - if (!string_vformat(buffer, sizeof(buffer), CS defaultrespond, ap)) - log_write(0, LOG_MAIN|LOG_PANIC, "string too large in smtp_notquit_exit()"); - smtp_printf("%s %s\r\n", FALSE, code, buffer); + g = string_vformat(NULL, TRUE, CS defaultrespond, ap); va_end(ap); + smtp_printf("%s %s\r\n", FALSE, code, string_from_gstring(g)); } mac_smtp_fflush(); } @@ -3953,7 +3994,13 @@ while (done <= 0) US &off, sizeof(off)); #endif - switch(smtp_read_command(TRUE, GETC_BUFFER_UNLIMITED)) + switch(smtp_read_command( +#ifdef EXPERIMENTAL_PIPE_CONNECT + !fl.pipe_connect_acceptable, +#else + TRUE, +#endif + GETC_BUFFER_UNLIMITED)) { /* The AUTH command is not permitted to occur inside a transaction, and may occur successfully only once per connection. Actually, that isn't quite @@ -4186,7 +4233,12 @@ while (done <= 0) host_build_sender_fullhost(); /* Rebuild */ break; } - else if (!check_sync()) goto SYNC_FAILURE; +#ifdef EXPERIMENTAL_PIPE_CONNECT + else if (!fl.pipe_connect_acceptable && !check_sync()) +#else + else if (!check_sync()) +#endif + goto SYNC_FAILURE; /* Generate an OK reply. The default string includes the ident if present, and also the IP address if present. Reflecting back the ident is intended @@ -4315,13 +4367,22 @@ while (done <= 0) /* Exim is quite happy with pipelining, so let the other end know that it is safe to use it, unless advertising is disabled. */ - if (f.pipelining_enable && - verify_check_host(&pipelining_advertise_hosts) == OK) + if ( f.pipelining_enable + && verify_check_host(&pipelining_advertise_hosts) == OK) { g = string_catn(g, smtp_code, 3); g = string_catn(g, US"-PIPELINING\r\n", 13); sync_cmd_limit = NON_SYNC_CMD_PIPELINING; f.smtp_in_pipelining_advertised = TRUE; + +#ifdef EXPERIMENTAL_PIPE_CONNECT + if (fl.pipe_connect_acceptable) + { + f.smtp_in_early_pipe_advertised = TRUE; + g = string_catn(g, smtp_code, 3); + g = string_catn(g, US"-" EARLY_PIPE_FEATURE_NAME "\r\n", EARLY_PIPE_FEATURE_LEN+3); + } +#endif } @@ -4442,7 +4503,14 @@ while (done <= 0) has been seen. */ #ifdef SUPPORT_TLS - if (tls_in.active.sock >= 0) (void)tls_write(NULL, g->s, g->ptr, FALSE); else + if (tls_in.active.sock >= 0) + (void)tls_write(NULL, g->s, g->ptr, +# ifdef EXPERIMENTAL_PIPE_CONNECT + fl.pipe_connect_acceptable && pipeline_connect_sends()); +# else + FALSE); +# endif + else #endif { @@ -5247,7 +5315,10 @@ while (done <= 0) HAD(SCH_DATA); f.dot_ends = TRUE; - DATA_BDAT: /* Common code for DATA and BDAT */ + DATA_BDAT: /* Common code for DATA and BDAT */ +#ifdef EXPERIMENTAL_PIPE_CONNECT + fl.pipe_connect_acceptable = FALSE; +#endif if (!discarded && recipients_count <= 0) { if (fl.rcpt_smtp_response_same && rcpt_smtp_response != NULL) @@ -5619,7 +5690,11 @@ while (done <= 0) log_write(L_lost_incoming_connection, LOG_MAIN, "unexpected %s while reading SMTP command from %s%s%s D=%s", f.sender_host_unknown ? "EOF" : "disconnection", - f.tcp_in_fastopen && !f.tcp_in_fastopen_logged ? US"TFO " : US"", + f.tcp_in_fastopen_logged + ? US"" + : f.tcp_in_fastopen + ? f.tcp_in_fastopen_data ? US"TFO* " : US"TFO " + : US"", host_and_ident(FALSE), smtp_read_error, string_timesince(&smtp_connection_start) );