Do our very best *not* to receive SIGPIPE:

When possible do:
 * Set socket option SO_NOSIGPIPE
 * Pass MSG_NOSIGNAL to send(2)

git-svn-id: https://warzone2100.svn.sourceforge.net/svnroot/warzone2100/trunk@9917 4a71c877-e1ca-e34f-864e-861f7616d084
master
Giel van Schijndel 2010-02-20 23:55:23 +00:00 committed by Git SVN Gateway
parent d4b0ab8c21
commit 4aa213a937
1 changed files with 32 additions and 3 deletions

View File

@ -84,6 +84,11 @@ typedef SSIZE_T ssize_t;
# endif # endif
#endif #endif
// Fallback for systems that don't #define this flag
#ifndef MSG_NOSIGNAL
# define MSG_NOSIGNAL 0
#endif
static int getSockErr(void) static int getSockErr(void)
{ {
#if defined(WZ_OS_UNIX) #if defined(WZ_OS_UNIX)
@ -540,7 +545,7 @@ static ssize_t writeAll(Socket* sock, const void* buf, size_t size)
} }
} }
ret = send(sock->fd[SOCK_CONNECTION], &((char*)buf)[written], size - written, 0); ret = send(sock->fd[SOCK_CONNECTION], &((char*)buf)[written], size - written, MSG_NOSIGNAL);
if (ret == SOCKET_ERROR) if (ret == SOCKET_ERROR)
{ {
switch (getSockErr()) switch (getSockErr())
@ -843,6 +848,10 @@ static Socket* socketAccept(Socket* sock)
{ {
if (sock->fd[i] != INVALID_SOCKET) if (sock->fd[i] != INVALID_SOCKET)
{ {
#if defined(SO_NOSIGPIPE)
static const int no_sigpipe = 1;
#endif
char textAddress[40]; char textAddress[40];
struct sockaddr_storage addr; struct sockaddr_storage addr;
socklen_t addr_len = sizeof(addr); socklen_t addr_len = sizeof(addr);
@ -862,6 +871,13 @@ static Socket* socketAccept(Socket* sock)
continue; continue;
} }
#if defined(SO_NOSIGPIPE)
if (setsockopt(newConn, SOL_SOCKET, SO_NOSIGPIPE, &no_sigpipe, sizeof(no_sigpipe)) == SOCKET_ERROR)
{
debug(LOG_WARNING, "Failed to set SO_NOSIGPIPE on socket, SIGPIPE might be raised when connections gets broken. Error: %s", strSockError(getSockErr()));
}
#endif
conn = malloc(sizeof(*conn) + addr_len); conn = malloc(sizeof(*conn) + addr_len);
if (conn == NULL) if (conn == NULL)
{ {
@ -893,6 +909,10 @@ static Socket* socketAccept(Socket* sock)
static Socket* SocketOpen(const struct addrinfo* addr, unsigned int timeout) static Socket* SocketOpen(const struct addrinfo* addr, unsigned int timeout)
{ {
#if defined(SO_NOSIGPIPE)
static const int no_sigpipe = 1;
#endif
char textAddress[40]; char textAddress[40];
unsigned int i; unsigned int i;
int ret; int ret;
@ -932,6 +952,13 @@ static Socket* SocketOpen(const struct addrinfo* addr, unsigned int timeout)
return NULL; return NULL;
} }
#if defined(SO_NOSIGPIPE)
if (setsockopt(newConn, SOL_SOCKET, SO_NOSIGPIPE, &no_sigpipe, sizeof(no_sigpipe)) == SOCKET_ERROR)
{
debug(LOG_WARNING, "Failed to set SO_NOSIGPIPE on socket, SIGPIPE might be raised when connections gets broken. Error: %s", strSockError(getSockErr()));
}
#endif
ret = connect(conn->fd[SOCK_CONNECTION], addr->ai_addr, addr->ai_addrlen); ret = connect(conn->fd[SOCK_CONNECTION], addr->ai_addr, addr->ai_addrlen);
if (ret == SOCKET_ERROR) if (ret == SOCKET_ERROR)
{ {
@ -1019,7 +1046,9 @@ static Socket* socketListen(unsigned int port)
/* Enable the V4 to V6 mapping, but only when available, because it /* Enable the V4 to V6 mapping, but only when available, because it
* isn't available on all platforms. * isn't available on all platforms.
*/ */
#if defined(IPV6_V6ONLY)
static const int ipv6_v6only = 0; static const int ipv6_v6only = 0;
#endif
struct sockaddr_in addr4; struct sockaddr_in addr4;
struct sockaddr_in6 addr6; struct sockaddr_in6 addr6;
@ -1095,7 +1124,7 @@ static Socket* socketListen(unsigned int port)
if (conn->fd[SOCK_IPV4_LISTEN] != INVALID_SOCKET) if (conn->fd[SOCK_IPV4_LISTEN] != INVALID_SOCKET)
{ {
if (setsockopt(conn->fd[SOCK_IPV4_LISTEN], SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(int)) == SOCKET_ERROR) if (setsockopt(conn->fd[SOCK_IPV4_LISTEN], SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == SOCKET_ERROR)
{ {
debug(LOG_WARNING, "Failed to set SO_REUSEADDR on IPv4 socket. Error: %s", strSockError(getSockErr())); debug(LOG_WARNING, "Failed to set SO_REUSEADDR on IPv4 socket. Error: %s", strSockError(getSockErr()));
} }
@ -1116,7 +1145,7 @@ static Socket* socketListen(unsigned int port)
if (conn->fd[SOCK_IPV6_LISTEN] != INVALID_SOCKET) if (conn->fd[SOCK_IPV6_LISTEN] != INVALID_SOCKET)
{ {
if (setsockopt(conn->fd[SOCK_IPV6_LISTEN], SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(int)) == SOCKET_ERROR) if (setsockopt(conn->fd[SOCK_IPV6_LISTEN], SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == SOCKET_ERROR)
{ {
debug(LOG_WARNING, "Failed to set SO_REUSEADDR on IPv6 socket. Error: %s", strSockError(getSockErr())); debug(LOG_WARNING, "Failed to set SO_REUSEADDR on IPv6 socket. Error: %s", strSockError(getSockErr()));
} }