Just for kicks I wrote an abortable accept function. It is untested so let me know if it works. Error checking could be better.
Code:
/*
* Works like the normal accept(), except that it takes an abort event. When this event is
* signalled this function will return INVALID_SOCKET immediately.
*/
SOCKET AbortableAccept(SOCKET s, struct sockaddr* addr, int* addrlen, HANDLE hEventAbort)
{
SOCKET sockRet;
HANDLE hEvents[2];
ULONG setting[2] = { 0, 0 };
if (hEventAbort == NULL)
{
/* Normal, non-abortable accept(). */
return accept(s, addr, addrlen);
}
hEvents[0] = CreateEvent(NULL, FALSE, FALSE, NULL); /* Will be signalled for an incoming connection. */
hEvents[1] = hEventAbort; /* Will be signalled by another thread to abort the accept operation. */
WSAEventSelect(s, hEvents[0], FD_ACCEPT); /* Puts socket in non-blocking mode and
* tells windows to signal hEvents[0] when the
* accept() has completed or an error occurs. */
if (WaitForMultipleObjects(2, hEvents, FALSE, INFINITE) == WAIT_OBJECT_0)
{
/* An incoming connection has arrived or a network error has occurred. */
sockRet = accept(s, addr, addrlen);
}
else
{
/* Abort event was signalled or WaitForMultipleObjects error. */
sockRet = INVALID_SOCKET;
}
/* Cleanup event signalling */
WSAEventSelect(s, hEvents[0], 0);
CloseHandle(hEvent);
/* Put sockets back into blocking mode */
ioctlsocket(s, FIONBIO, &setting[0]);
ioctlsocket(sockRet, FIONBIO, &setting[1]);
return sockRet;
}
/* Sample usage. */
/* Create a global manual-reset event. */
g_hAbortEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
/* Start an abortable accept. */
sock = AbortableAccept(s, (struct sockaddr*) &addr, &addrlen, g_hAbortEvent);
/* In another thread - signal the event and abort the accepts that are using it. */
SetEvent(g_hAbortEvent);