From c692bb02b039ae8fef6ba968fd13b36ad7d62a72 Mon Sep 17 00:00:00 2001 From: Landon Fuller Date: Sat, 2 Mar 2013 14:08:47 -0500 Subject: Handle EMSGSIZE on UNIX domain sockets. On some systems (eg, FreeBSD) the default SO_SNDBUF for UNIX domain sockets is to small, and EMSGSIZE is returned. Other systems provide a larger default send buffer, but there is still no guarantee that the buffer will be sized appropriately. This patch modifies the sendto() path to attempt to resize the SO_SNDBUF dynamically upon an EMSGSIZE failure, and then retry the send. This fixes local DCE/RPC errors on FreeBSD, eg: https://lists.samba.org/archive/samba-technical/2013-January/089881.html Signed-Off-By: Landon Fuller Reviewed-by: Andrew Bartlett Autobuild-User(master): Andrew Bartlett Autobuild-Date(master): Sat Mar 2 23:34:03 CET 2013 on sn-devel-104 --- source4/lib/socket/socket_unix.c | 35 ++++++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 9 deletions(-) (limited to 'source4/lib') diff --git a/source4/lib/socket/socket_unix.c b/source4/lib/socket/socket_unix.c index 4755e796a4..049e5707c8 100644 --- a/source4/lib/socket/socket_unix.c +++ b/source4/lib/socket/socket_unix.c @@ -263,26 +263,43 @@ static NTSTATUS unixdom_sendto(struct socket_context *sock, const DATA_BLOB *blob, size_t *sendlen, const struct socket_address *dest) { + struct sockaddr_un srv_addr; + const struct sockaddr *sa; + socklen_t sa_len; ssize_t len; + *sendlen = 0; - + if (dest->sockaddr) { - len = sendto(sock->fd, blob->data, blob->length, 0, - dest->sockaddr, dest->sockaddrlen); + sa = dest->sockaddr; + sa_len = dest->sockaddrlen; } else { - struct sockaddr_un srv_addr; - if (strlen(dest->addr)+1 > sizeof(srv_addr.sun_path)) { return NT_STATUS_OBJECT_PATH_INVALID; } - + ZERO_STRUCT(srv_addr); srv_addr.sun_family = AF_UNIX; - snprintf(srv_addr.sun_path, sizeof(srv_addr.sun_path), "%s", dest->addr); + snprintf(srv_addr.sun_path, sizeof(srv_addr.sun_path), "%s", + dest->addr); + sa = (struct sockaddr *) &srv_addr; + sa_len = sizeof(srv_addr); + } + + len = sendto(sock->fd, blob->data, blob->length, 0, sa, sa_len); - len = sendto(sock->fd, blob->data, blob->length, 0, - (struct sockaddr *)&srv_addr, sizeof(srv_addr)); + /* retry once */ + if (len == -1 && errno == EMSGSIZE) { + /* round up in 1K increments */ + int bufsize = ((blob->length + 1023) & (~1023)); + if (setsockopt(sock->fd, SOL_SOCKET, SO_SNDBUF, &bufsize, + sizeof(bufsize)) == -1) + { + return map_nt_error_from_unix_common(errno); + } + len = sendto(sock->fd, blob->data, blob->length, 0, sa, sa_len); } + if (len == -1) { return map_nt_error_from_unix_common(errno); } -- cgit