Try to handle concurrent close on socket more gracefully
* fhandler_socket.cc (LOCK_EVENTS): Don't enter critical section with invalid mutex handle since then socket has been closed. (UNLOCK_EVENTS): Close critical section. (fhandler_socket::evaluate_events): Handle calling connect on shutdown socket. (fhandler_socket::wait_for_events): Try for pthread_testcancel in case of WAIT_FAILED. Try to come up with a better errno in case we waited on an invalid handle. (fhandler_socket::release_events): Change wsock_mtx and wsock_evt to NULL under lock to avoid accessing invalid handle. Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
This commit is contained in:
parent
6f9e2f3ed5
commit
79d65a1ed2
@ -1,3 +1,16 @@
|
|||||||
|
2015-06-15 Corinna Vinschen <corinna@vinschen.de>
|
||||||
|
|
||||||
|
* fhandler_socket.cc (LOCK_EVENTS): Don't enter critical section with
|
||||||
|
invalid mutex handle since then socket has been closed.
|
||||||
|
(UNLOCK_EVENTS): Close critical section.
|
||||||
|
(fhandler_socket::evaluate_events): Handle calling connect on shutdown
|
||||||
|
socket.
|
||||||
|
(fhandler_socket::wait_for_events): Try for pthread_testcancel in case
|
||||||
|
of WAIT_FAILED. Try to come up with a better errno in case we waited
|
||||||
|
on an invalid handle.
|
||||||
|
(fhandler_socket::release_events): Change wsock_mtx and wsock_evt to
|
||||||
|
NULL under lock to avoid accessing invalid handle.
|
||||||
|
|
||||||
2015-06-15 Corinna Vinschen <corinna@vinschen.de>
|
2015-06-15 Corinna Vinschen <corinna@vinschen.de>
|
||||||
|
|
||||||
* net.cc (errmap): Handle more Winsock error codes.
|
* net.cc (errmap): Handle more Winsock error codes.
|
||||||
|
@ -501,8 +501,14 @@ fhandler_socket::af_local_set_secret (char *buf)
|
|||||||
counted as one socket. */
|
counted as one socket. */
|
||||||
#define NUM_SOCKS (32768 / sizeof (wsa_event))
|
#define NUM_SOCKS (32768 / sizeof (wsa_event))
|
||||||
|
|
||||||
#define LOCK_EVENTS WaitForSingleObject (wsock_mtx, INFINITE)
|
#define LOCK_EVENTS \
|
||||||
#define UNLOCK_EVENTS ReleaseMutex (wsock_mtx)
|
if (wsock_mtx && \
|
||||||
|
WaitForSingleObject (wsock_mtx, INFINITE) != WAIT_FAILED) \
|
||||||
|
{
|
||||||
|
|
||||||
|
#define UNLOCK_EVENTS \
|
||||||
|
ReleaseMutex (wsock_mtx); \
|
||||||
|
}
|
||||||
|
|
||||||
static wsa_event wsa_events[NUM_SOCKS] __attribute__((section (".cygwin_dll_common"), shared));
|
static wsa_event wsa_events[NUM_SOCKS] __attribute__((section (".cygwin_dll_common"), shared));
|
||||||
|
|
||||||
@ -709,14 +715,21 @@ fhandler_socket::evaluate_events (const long event_mask, long &events,
|
|||||||
wsock_events->events &= ~FD_CONNECT;
|
wsock_events->events &= ~FD_CONNECT;
|
||||||
wsock_events->connect_errorcode = 0;
|
wsock_events->connect_errorcode = 0;
|
||||||
}
|
}
|
||||||
/* This test makes the accept function behave as on Linux when
|
/* This test makes accept/connect behave as on Linux when accept/connect
|
||||||
accept is called on a socket for which shutdown for the read side
|
is called on a socket for which shutdown has been called. The second
|
||||||
has been called. The second half of this code is in the shutdown
|
half of this code is in the shutdown method. */
|
||||||
method. See there for more info. */
|
if (events & FD_CLOSE)
|
||||||
if ((event_mask & FD_ACCEPT) && (events & FD_CLOSE))
|
|
||||||
{
|
{
|
||||||
WSASetLastError (WSAEINVAL);
|
if ((event_mask & FD_ACCEPT) && saw_shutdown_read ())
|
||||||
ret = SOCKET_ERROR;
|
{
|
||||||
|
WSASetLastError (WSAEINVAL);
|
||||||
|
ret = SOCKET_ERROR;
|
||||||
|
}
|
||||||
|
if (event_mask & FD_CONNECT)
|
||||||
|
{
|
||||||
|
WSASetLastError (WSAECONNRESET);
|
||||||
|
ret = SOCKET_ERROR;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (erase)
|
if (erase)
|
||||||
wsock_events->events &= ~(events & ~(FD_WRITE | FD_CLOSE));
|
wsock_events->events &= ~(events & ~(FD_WRITE | FD_CLOSE));
|
||||||
@ -750,7 +763,8 @@ fhandler_socket::wait_for_events (const long event_mask, const DWORD flags)
|
|||||||
{
|
{
|
||||||
case WSA_WAIT_TIMEOUT:
|
case WSA_WAIT_TIMEOUT:
|
||||||
pthread_testcancel ();
|
pthread_testcancel ();
|
||||||
/*FALLTHRU*/
|
break;
|
||||||
|
|
||||||
case WSA_WAIT_EVENT_0:
|
case WSA_WAIT_EVENT_0:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -761,19 +775,31 @@ fhandler_socket::wait_for_events (const long event_mask, const DWORD flags)
|
|||||||
return SOCKET_ERROR;
|
return SOCKET_ERROR;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
WSASetLastError (WSAEFAULT);
|
pthread_testcancel ();
|
||||||
|
/* wsock_evt can be NULL. We're generating the same errno values
|
||||||
|
as for sockets on which shutdown has been called. */
|
||||||
|
if (WSAGetLastError () != WSA_INVALID_HANDLE)
|
||||||
|
WSASetLastError (WSAEFAULT);
|
||||||
|
else
|
||||||
|
WSASetLastError ((event_mask & FD_CONNECT) ? WSAECONNRESET
|
||||||
|
: WSAEINVAL);
|
||||||
return SOCKET_ERROR;
|
return SOCKET_ERROR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
fhandler_socket::release_events ()
|
fhandler_socket::release_events ()
|
||||||
{
|
{
|
||||||
NtClose (wsock_evt);
|
HANDLE evt = wsock_evt;
|
||||||
NtClose (wsock_mtx);
|
HANDLE mtx = wsock_mtx;
|
||||||
|
|
||||||
|
LOCK_EVENTS;
|
||||||
|
wsock_evt = wsock_mtx = NULL;
|
||||||
|
} ReleaseMutex (mtx); /* == UNLOCK_EVENTS, but note using local mtx here. */
|
||||||
|
NtClose (evt);
|
||||||
|
NtClose (mtx);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Called from net.cc:fdsock() if a freshly created socket is not
|
/* Called from net.cc:fdsock() if a freshly created socket is not
|
||||||
|
Loading…
x
Reference in New Issue
Block a user