-/* $Cambridge: exim/src/src/smtp_out.c,v 1.4 2005/02/17 11:58:26 ph10 Exp $ */
-
/*************************************************
* Exim - an Internet mail transport agent *
*************************************************/
-/* Copyright (c) University of Cambridge 1995 - 2005 */
+/* Copyright (c) University of Cambridge 1995 - 2009 */
/* See the file NOTICE for conditions of use and distribution. */
/* A number of functions for driving outgoing SMTP calls. */
host->address will always be an IPv4 address.
The port field in the host item is used if it is set (usually router from SRV
-records). In other cases, the default passed as an argument is used.
+records or elsewhere). In other cases, the default passed as an argument is
+used, and the host item is updated with its value.
Arguments:
host host item containing name and address (and sometimes port)
host_af AF_INET or AF_INET6
- port default, remote port to connect to, in host byte order for those
+ port default remote port to connect to, in host byte order, for those
hosts whose port setting is PORT_NONE
interface outgoing interface address or NULL
timeout timeout value or 0
keepalive TRUE to use keepalive
+ dscp DSCP value to assign to socket
Returns: connected socket number, or -1 with errno set
*/
int
smtp_connect(host_item *host, int host_af, int port, uschar *interface,
- int timeout, BOOL keepalive)
+ int timeout, BOOL keepalive, const uschar *dscp)
{
int on = 1;
int save_errno = 0;
+int dscp_value;
+int dscp_level;
+int dscp_option;
int sock;
if (host->port != PORT_NONE)
host->port);
port = host->port;
}
+else host->port = port; /* Set the port actually used */
HDEBUG(D_transport|D_acl|D_v)
{
setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (uschar *)(&on), sizeof(on));
+/* 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. */
+
+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);
+ 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));
+ /* 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 &&
+ dscp_lookup(dscp, AF_INET, &dscp_level, &dscp_option, &dscp_value))
+ {
+ (void) setsockopt(sock, dscp_level, dscp_option, &dscp_value, sizeof(dscp_value));
+ }
+ }
+
/* Bind to a specific interface if requested. Caller must ensure the interface
is the same type (IPv4 or IPv6) as the outgoing address. */
debug_printf(" (timeout=%s)", readconf_printtime(timeout));
debug_printf("\n");
}
- close(sock);
+ (void)close(sock);
errno = save_errno;
return -1;
}
else
{
+ union sockaddr_46 interface_sock;
+ EXIM_SOCKLEN_T size = sizeof(interface_sock);
HDEBUG(D_transport|D_acl|D_v) debug_printf("connected\n");
+ if (getsockname(sock, (struct sockaddr *)(&interface_sock), &size) == 0)
+ sending_ip_address = host_ntoa(-1, &interface_sock, NULL, &sending_port);
+ else
+ {
+ log_write(0, LOG_MAIN | ((errno == ECONNRESET)? 0 : LOG_PANIC),
+ "getsockname() failed: %s", strerror(errno));
+ close(sock);
+ return -1;
+ }
if (keepalive) ip_keepalive(sock, host->address, TRUE);
return sock;
}
int rc;
#ifdef SUPPORT_TLS
-if (tls_active == outblock->sock)
- rc = tls_write(outblock->buffer, outblock->ptr - outblock->buffer);
+if (tls_out.active == outblock->sock)
+ rc = tls_write(FALSE, outblock->buffer, outblock->ptr - outblock->buffer);
else
#endif
*/
int
-smtp_write_command(smtp_outblock *outblock, BOOL noflush, char *format, ...)
+smtp_write_command(smtp_outblock *outblock, BOOL noflush, const char *format, ...)
{
int count;
int rc = 0;