X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/44bc8f0c2f3576b46bd6df1b818cb29eaf84df5b..4e910c01eea401e36044816744691789ef4656fa:/src/src/smtp_out.c diff --git a/src/src/smtp_out.c b/src/src/smtp_out.c index 76181b5f1..7ade9ba67 100644 --- a/src/src/smtp_out.c +++ b/src/src/smtp_out.c @@ -41,10 +41,9 @@ const uschar * expint; uschar *iface; int sep = 0; -if (istring == NULL) return TRUE; +if (!istring) return TRUE; -expint = expand_string(istring); -if (expint == NULL) +if (!(expint = expand_string(istring))) { if (expand_string_forcedfail) return TRUE; addr->transport_return = PANIC; @@ -57,7 +56,7 @@ while (isspace(*expint)) expint++; if (*expint == 0) return TRUE; while ((iface = string_nextinlist(&expint, &sep, big_buffer, - big_buffer_size)) != NULL) + big_buffer_size))) { if (string_is_ip_address(iface, NULL) == 0) { @@ -72,7 +71,7 @@ while ((iface = string_nextinlist(&expint, &sep, big_buffer, break; } -if (iface != NULL) *interface = string_copy(iface); +if (iface) *interface = string_copy(iface); return TRUE; } @@ -152,8 +151,8 @@ int dscp_value; int dscp_level; int dscp_option; int sock; -int on = 1; int save_errno = 0; +BOOL fastopen = FALSE; #ifndef DISABLE_EVENT deliver_host_address = host->address; @@ -167,7 +166,7 @@ if ((sock = ip_socket(SOCK_STREAM, host_af)) < 0) return -1; if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, US &on, sizeof(on))) HDEBUG(D_transport|D_acl|D_v) - debug_printf("failed to set NODELAY: %s ", strerror(errno)); + debug_printf_indent("failed to set NODELAY: %s ", strerror(errno)); /* Set DSCP value, if we can. For now, if we fail to set the value, we don't bomb out, just log it and continue in default traffic class. */ @@ -175,10 +174,10 @@ bomb out, just log it and continue in default traffic class. */ if (dscp && dscp_lookup(dscp, host_af, &dscp_level, &dscp_option, &dscp_value)) { HDEBUG(D_transport|D_acl|D_v) - debug_printf("DSCP \"%s\"=%x ", dscp, dscp_value); + debug_printf_indent("DSCP \"%s\"=%x ", dscp, dscp_value); if (setsockopt(sock, dscp_level, dscp_option, &dscp_value, sizeof(dscp_value)) < 0) HDEBUG(D_transport|D_acl|D_v) - debug_printf("failed to set DSCP: %s ", strerror(errno)); + debug_printf_indent("failed to set DSCP: %s ", strerror(errno)); /* If the kernel supports IPv4 and IPv6 on an IPv6 socket, we need to set the option for both; ignore failures here */ if (host_af == AF_INET6 && @@ -186,6 +185,10 @@ if (dscp && dscp_lookup(dscp, host_af, &dscp_level, &dscp_option, &dscp_value)) (void) setsockopt(sock, dscp_level, dscp_option, &dscp_value, sizeof(dscp_value)); } +#ifdef TCP_FASTOPEN +if (verify_check_given_host (&ob->hosts_try_fastopen, host) == OK) fastopen = TRUE; +#endif + /* Bind to a specific interface if requested. Caller must ensure the interface is the same type (IPv4 or IPv6) as the outgoing address. */ @@ -193,14 +196,14 @@ if (interface && ip_bind(sock, host_af, interface, 0) < 0) { save_errno = errno; HDEBUG(D_transport|D_acl|D_v) - debug_printf("unable to bind outgoing SMTP call to %s: %s", interface, + debug_printf_indent("unable to bind outgoing SMTP call to %s: %s", interface, strerror(errno)); } /* Connect to the remote host, and add keepalive to the socket before returning it, if requested. */ -else if (ip_connect(sock, host_af, host->address, port, timeout) < 0) +else if (ip_connect(sock, host_af, host->address, port, timeout, fastopen) < 0) save_errno = errno; /* Either bind() or connect() failed */ @@ -209,7 +212,7 @@ if (save_errno != 0) { HDEBUG(D_transport|D_acl|D_v) { - debug_printf("failed: %s", CUstrerror(save_errno)); + debug_printf_indent("failed: %s", CUstrerror(save_errno)); if (save_errno == ETIMEDOUT) debug_printf(" (timeout=%s)", readconf_printtime(timeout)); debug_printf("\n"); @@ -225,7 +228,7 @@ else { union sockaddr_46 interface_sock; EXIM_SOCKLEN_T size = sizeof(interface_sock); - HDEBUG(D_transport|D_acl|D_v) debug_printf("connected\n"); + HDEBUG(D_transport|D_acl|D_v) debug_printf_indent("connected\n"); if (getsockname(sock, (struct sockaddr *)(&interface_sock), &size) == 0) sending_ip_address = host_ntoa(-1, &interface_sock, NULL, &sending_port); else @@ -277,7 +280,7 @@ smtp_transport_options_block * ob = if (host->port != PORT_NONE) { HDEBUG(D_transport|D_acl|D_v) - debug_printf("Transport port=%d replaced by host-specific port=%d\n", port, + debug_printf_indent("Transport port=%d replaced by host-specific port=%d\n", port, host->port); port = host->port; } @@ -292,7 +295,7 @@ HDEBUG(D_transport|D_acl|D_v) #ifdef SUPPORT_SOCKS if (ob->socks_proxy) s = string_sprintf("%svia proxy ", s); #endif - debug_printf("Connecting to %s %s%s... ", host->name, callout_address, s); + debug_printf_indent("Connecting to %s %s%s... ", host->name, callout_address, s); } /* Create and connect the socket */ @@ -316,25 +319,36 @@ pipelining. Argument: outblock the SMTP output block + mode more-expected, or plain Returns: TRUE if OK, FALSE on error, with errno set */ static BOOL -flush_buffer(smtp_outblock *outblock) +flush_buffer(smtp_outblock * outblock, int mode) { int rc; +int n = outblock->ptr - outblock->buffer; + +HDEBUG(D_transport|D_acl) debug_printf_indent("cmd buf flush %d bytes%s\n", n, + mode == SCMD_MORE ? " (with MORE annotation)" : ""); #ifdef SUPPORT_TLS if (tls_out.active == outblock->sock) - rc = tls_write(FALSE, outblock->buffer, outblock->ptr - outblock->buffer); + rc = tls_write(FALSE, outblock->buffer, n); else #endif + rc = send(outblock->sock, outblock->buffer, n, +#ifdef MSG_MORE + mode == SCMD_MORE ? MSG_MORE : 0 +#else + 0 +#endif + ); -rc = send(outblock->sock, outblock->buffer, outblock->ptr - outblock->buffer, 0); if (rc <= 0) { - HDEBUG(D_transport|D_acl) debug_printf("send failed: %s\n", strerror(errno)); + HDEBUG(D_transport|D_acl) debug_printf_indent("send failed: %s\n", strerror(errno)); return FALSE; } @@ -354,7 +368,7 @@ any error message. Arguments: outblock contains buffer for pipelining, and socket - noflush if TRUE, save the command in the output buffer, for pipelining + mode buffer, write-with-more-likely, write format a format, starting with one of of HELO, MAIL FROM, RCPT TO, DATA, ".", or QUIT. If NULL, flush pipeline buffer only. @@ -366,7 +380,7 @@ Returns: 0 if command added to pipelining buffer, with nothing transmitted */ int -smtp_write_command(smtp_outblock *outblock, BOOL noflush, const char *format, ...) +smtp_write_command(smtp_outblock * outblock, int mode, const char *format, ...) { int count; int rc = 0; @@ -388,7 +402,7 @@ if (format) if (count > outblock->buffersize - (outblock->ptr - outblock->buffer)) { rc = outblock->cmd_count; /* flush resets */ - if (!flush_buffer(outblock)) return -1; + if (!flush_buffer(outblock, SCMD_FLUSH)) return -1; } Ustrncpy(CS outblock->ptr, big_buffer, count); @@ -415,13 +429,13 @@ if (format) while (*p != 0) *p++ = '*'; } - HDEBUG(D_transport|D_acl|D_v) debug_printf(" SMTP>> %s\n", big_buffer); + HDEBUG(D_transport|D_acl|D_v) debug_printf_indent(" SMTP>> %s\n", big_buffer); } -if (!noflush) +if (mode != SCMD_BUFFER) { rc += outblock->cmd_count; /* flush resets */ - if (!flush_buffer(outblock)) return -1; + if (!flush_buffer(outblock, mode)) return -1; } return rc; @@ -493,15 +507,20 @@ for (;;) /* Need to read a new input packet. */ - rc = ip_recv(sock, inblock->buffer, inblock->buffersize, timeout); - if (rc <= 0) break; + if((rc = ip_recv(sock, inblock->buffer, inblock->buffersize, timeout)) <= 0) + { + DEBUG(D_deliver|D_transport|D_acl) + debug_printf_indent(errno ? " SMTP(%s)<<\n" : " SMTP(closed)<<\n", + strerror(errno)); + break; + } /* Another block of data has been successfully read. Set up the pointers and let the loop continue. */ ptrend = inblock->ptrend = inblock->buffer + rc; ptr = inblock->buffer; - DEBUG(D_transport|D_acl) debug_printf("read response data: size=%d\n", rc); + DEBUG(D_transport|D_acl) debug_printf_indent("read response data: size=%d\n", rc); } /* Get here if there has been some kind of recv() error; errno is set, but we @@ -531,7 +550,7 @@ Arguments: buffer where to put the response size the size of the buffer okdigit the expected first digit of the response - timeout the timeout to use + timeout the timeout to use, in seconds Returns: TRUE if a valid, non-error response was received; else FALSE */ @@ -545,7 +564,7 @@ int count; errno = 0; /* Ensure errno starts out zero */ -/* This is a loop to read and concatentate the lines that make up a multi-line +/* This is a loop to read and concatenate the lines that make up a multi-line response. */ for (;;) @@ -554,7 +573,7 @@ for (;;) return FALSE; HDEBUG(D_transport|D_acl|D_v) - debug_printf(" %s %s\n", (ptr == buffer)? "SMTP<<" : " ", ptr); + debug_printf_indent(" %s %s\n", (ptr == buffer)? "SMTP<<" : " ", ptr); /* Check the format of the response: it must start with three digits; if these are followed by a space or end of line, the response is complete. If