diff options
author | Landon Fuller <landonf@bikemonkey.org> | 2013-03-02 14:08:47 -0500 |
---|---|---|
committer | Andrew Bartlett <abartlet@samba.org> | 2013-03-02 23:34:03 +0100 |
commit | c692bb02b039ae8fef6ba968fd13b36ad7d62a72 (patch) | |
tree | ef0ecae7596c009ad93132a8da797a81d76af291 /source4/lib/socket | |
parent | 606f5d6cc6b018259ba0306fe3b55e21b4b70fdb (diff) | |
download | samba-c692bb02b039ae8fef6ba968fd13b36ad7d62a72.tar.gz samba-c692bb02b039ae8fef6ba968fd13b36ad7d62a72.tar.bz2 samba-c692bb02b039ae8fef6ba968fd13b36ad7d62a72.zip |
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 <landonf@bikemonkey.org>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
Autobuild-User(master): Andrew Bartlett <abartlet@samba.org>
Autobuild-Date(master): Sat Mar 2 23:34:03 CET 2013 on sn-devel-104
Diffstat (limited to 'source4/lib/socket')
-rw-r--r-- | source4/lib/socket/socket_unix.c | 35 |
1 files changed, 26 insertions, 9 deletions
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); } |