Commit 5a636f99 authored by Mark Andrews's avatar Mark Andrews
Browse files

2972. [bug] win32: address windows socket errors. [RT #21906]

parent fa1d4d0c
2972. [bug] win32: address windows socket errors. [RT #21906]
2971. [bug] Fixed a bug that caused journal files not to be
compacted on Windows systems as a result of
non-POSIX-compliant rename() semantics. [RT #22434]
......
......@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: socket.c,v 1.83 2010/08/13 23:47:03 tbox Exp $ */
/* $Id: socket.c,v 1.84 2010/11/18 00:24:00 marka Exp $ */
/* This code uses functions which are only available on Server 2003 and
* higher, and Windows XP and higher.
......@@ -272,7 +272,6 @@ struct isc_socket {
unsigned int pending_accept; /* Number of outstanding accept() calls. */
unsigned int state; /* Socket state. Debugging and consistency checking. */
int state_lineno; /* line which last touched state */
int in_recovery_cnt; /* avoid recovery loop. */
};
#define _set_state(sock, _state) do { (sock)->state = (_state); (sock)->state_lineno = __LINE__; } while (0)
......@@ -365,8 +364,6 @@ static void send_connectdone_event(isc_socket_t *sock, isc_socket_connev_t **cde
static void send_recvdone_abort(isc_socket_t *sock, isc_result_t result);
static void queue_receive_event(isc_socket_t *sock, isc_task_t *task, isc_socketevent_t *dev);
static void queue_receive_request(isc_socket_t *sock);
static void hard_recover_receive_request(isc_socket_t *sock);
static void recover_receive_request(isc_socket_t *sock, void **lplpo);
/*
* This is used to dump the contents of the sock structure
......@@ -719,22 +716,31 @@ queue_receive_request(isc_socket_t *sock) {
int total_bytes = 0;
int Result;
int Error;
isc_boolean_t need_recovering = ISC_FALSE;
int need_retry;
WSABUF iov[1];
IoCompletionInfo *lpo;
IoCompletionInfo *lpo = NULL;
isc_result_t isc_result;
retry:
need_retry = ISC_FALSE;
/*
* If we already have a receive pending, do nothing.
*/
if (sock->pending_recv > 0)
if (sock->pending_recv > 0) {
if (lpo != NULL)
HeapFree(hHeapHandle, 0, lpo);
return;
}
/*
* If no one is waiting, do nothing.
*/
if (ISC_LIST_EMPTY(sock->recv_list))
if (ISC_LIST_EMPTY(sock->recv_list)) {
if (lpo != NULL)
HeapFree(hHeapHandle, 0, lpo);
return;
}
INSIST(sock->recvbuf.remaining == 0);
INSIST(sock->fd != INVALID_SOCKET);
......@@ -742,10 +748,13 @@ queue_receive_request(isc_socket_t *sock) {
iov[0].len = sock->recvbuf.len;
iov[0].buf = sock->recvbuf.base;
lpo = (IoCompletionInfo *)HeapAlloc(hHeapHandle,
HEAP_ZERO_MEMORY,
sizeof(IoCompletionInfo));
RUNTIME_CHECK(lpo != NULL);
if (lpo == NULL) {
lpo = (IoCompletionInfo *)HeapAlloc(hHeapHandle,
HEAP_ZERO_MEMORY,
sizeof(IoCompletionInfo));
RUNTIME_CHECK(lpo != NULL);
} else
ZeroMemory(lpo, sizeof(IoCompletionInfo));
lpo->request_type = SOCKET_RECV;
sock->recvbuf.from_addr_len = sizeof(sock->recvbuf.from_addr);
......@@ -767,43 +776,26 @@ queue_receive_request(isc_socket_t *sock) {
sock->pending_recv++;
break;
/* direct error: no completion event */
case ERROR_HOST_UNREACHABLE:
if (sock->type == isc_sockettype_udp) {
UNEXPECTED_ERROR(__FILE__, __LINE__,
"WSARecvFrom ERROR_HOST_UNREACHABLE: trying to recover");
need_recovering = ISC_TRUE;
break;
} else
goto fail;
case WSAENETRESET:
if (sock->type == isc_sockettype_udp) {
UNEXPECTED_ERROR(__FILE__, __LINE__,
"WSARecvFrom WSAENETRESET: trying to recover");
need_recovering = ISC_TRUE;
break;
} else
goto fail;
case WSAECONNRESET:
if (sock->type == isc_sockettype_udp) {
UNEXPECTED_ERROR(__FILE__, __LINE__,
"WSARecvFrom WSAECONNRESET: trying to recover");
need_recovering = ISC_TRUE;
if (!sock->connected) {
/* soft error */
need_retry = ISC_TRUE;
break;
} else
goto fail;
}
/* FALLTHROUGH */
default:
fail:
isc_result = isc__errno2result(Error);
if ((isc_result == ISC_R_UNEXPECTED) ||
(isc_result == ISC_R_CONNECTIONRESET) ||
(isc_result == ISC_R_HOSTUNREACH))
if (isc_result == ISC_R_UNEXPECTED)
UNEXPECTED_ERROR(__FILE__, __LINE__,
"WSARecvFrom: Windows error code: %d, isc result %d",
Error, isc_result);
send_recvdone_abort(sock, isc_result);
HeapFree(hHeapHandle, 0, lpo);
lpo = NULL;
break;
}
} else {
......@@ -814,7 +806,6 @@ queue_receive_request(isc_socket_t *sock) {
*/
sock->pending_iocp++;
sock->pending_recv++;
sock->in_recovery_cnt = 0;
}
socket_log(__LINE__, sock, NULL, IOEVENT,
......@@ -825,40 +816,8 @@ queue_receive_request(isc_socket_t *sock) {
CONSISTENT(sock);
if (need_recovering)
recover_receive_request(sock, &lpo);
}
/*
* (placeholder) Hard recovery, doing nothing useful today
* (other than to avoid unlimited recursion).
*/
static void
hard_recover_receive_request(isc_socket_t *sock)
{
UNEXPECTED_ERROR(__FILE__, __LINE__,
"can't recover fd %d sock %p",
sock->fd, sock);
send_recvdone_abort(sock, ISC_R_UNEXPECTED);
}
/*
* Recovery from a Windows 2008 Server bug
* (WSARecvFrom() getting an ERROR_HOST_UNREACHABLE).
* Free the overlapped pointer and requeue a receive request.
*/
static void
recover_receive_request(isc_socket_t *sock, void **lplpo)
{
if (*lplpo != NULL)
HeapFree(hHeapHandle, 0, *lplpo);
*lplpo = NULL;
/* limit recursion to 20 */
if (sock->in_recovery_cnt++ < 20)
queue_receive_request(sock);
else
hard_recover_receive_request(sock);
if (need_retry)
goto retry;
}
static void
......@@ -1502,7 +1461,6 @@ allocate_socket(isc_socketmgr_t *manager, isc_sockettype_t type,
sock->connected = 0;
sock->pending_connect = 0;
sock->bound = 0;
sock->in_recovery_cnt = 0;
memset(sock->name, 0, sizeof(sock->name)); // zero the name field
_set_state(sock, SOCK_INITIALIZED);
......@@ -2346,6 +2304,63 @@ connectdone_is_active(isc_socket_t *sock, isc_socket_connev_t *dev)
return (sock->connect_ev == dev ? ISC_TRUE : ISC_FALSE);
}
//
// The Windows network stack seems to have two very distinct paths depending
// on what is installed. Specifically, if something is looking at network
// connections (like an anti-virus or anti-malware application, such as
// McAfee products) Windows may return additional error conditions which
// were not previously returned.
//
// One specific one is when a TCP SYN scan is used. In this situation,
// Windows responds with the SYN-ACK, but the scanner never responds with
// the 3rd packet, the ACK. Windows consiers this a partially open connection.
// Most Unix networking stacks, and Windows without McAfee installed, will
// not return this to the caller. However, with this product installed,
// Windows returns this as a failed status on the Accept() call. Here, we
// will just re-issue the ISCAcceptEx() call as if nothing had happened.
//
// This code should only be called when the listening socket has received
// such an error. Additionally, the "parent" socket must be locked.
// Additionally, the lpo argument is re-used here, and must not be freed
// by the caller.
//
static isc_result_t
restart_accept(isc_socket_t *parent, IoCompletionInfo *lpo)
{
isc_socket_t *nsock = lpo->adev->newsocket;
SOCKET new_fd;
/*
* AcceptEx() requires we pass in a socket. Note that we carefully
* do not close the previous socket in case of an error message returned by
* our new socket() call. If we return an error here, our caller will
* clean up.
*/
new_fd = socket(parent->pf, SOCK_STREAM, IPPROTO_TCP);
if (nsock->fd == INVALID_SOCKET) {
return (ISC_R_FAILURE); // parent will ask windows for error message
}
closesocket(nsock->fd);
nsock->fd = new_fd;
memset(&lpo->overlapped, 0, sizeof(lpo->overlapped));
ISCAcceptEx(parent->fd,
nsock->fd, /* Accepted Socket */
lpo->acceptbuffer, /* Buffer for initial Recv */
0, /* Length of Buffer */
sizeof(SOCKADDR_STORAGE) + 16, /* Local address length + 16 */
sizeof(SOCKADDR_STORAGE) + 16, /* Remote address lengh + 16 */
(LPDWORD)&lpo->received_bytes, /* Bytes Recved */
(LPOVERLAPPED)lpo /* Overlapped structure */
);
InterlockedDecrement(&nsock->manager->iocp_total);
iocompletionport_update(nsock);
return (ISC_R_SUCCESS);
}
/*
* This is the I/O Completion Port Worker Function. It loops forever
* waiting for I/O to complete and then forwards them for further
......@@ -2386,6 +2401,7 @@ SocketIoThread(LPVOID ThreadContext) {
* Loop forever waiting on I/O Completions and then processing them
*/
while (TRUE) {
wait_again:
bSuccess = GetQueuedCompletionStatus(manager->hIoCompletionPort,
&nbytes, (LPDWORD)&sock,
(LPWSAOVERLAPPED *)&lpo,
......@@ -2415,33 +2431,16 @@ SocketIoThread(LPVOID ThreadContext) {
sock->pending_iocp--;
INSIST(sock->pending_recv > 0);
sock->pending_recv--;
if ((sock->type == isc_sockettype_udp) &&
(errstatus == ERROR_HOST_UNREACHABLE)) {
UNEXPECTED_ERROR(__FILE__, __LINE__,
"SOCKET_RECV ERROR_HOST_UNREACHABLE: trying to recover");
recover_receive_request(sock, &lpo);
break;
}
if ((sock->type == isc_sockettype_udp) &&
(errstatus == WSAENETRESET)) {
UNEXPECTED_ERROR(__FILE__, __LINE__,
"SOCKET_RECV WSAENETRESET: trying to recover");
recover_receive_request(sock, &lpo);
break;
}
if ((sock->type == isc_sockettype_udp) &&
(errstatus == WSAECONNRESET)) {
UNEXPECTED_ERROR(__FILE__, __LINE__,
"SOCKET_RECV WSAECONNRESET: trying to recover");
recover_receive_request(sock, &lpo);
if (!sock->connected &&
((errstatus == ERROR_HOST_UNREACHABLE) ||
(errstatus == WSAENETRESET) ||
(errstatus == WSAECONNRESET))) {
/* ignore soft errors */
queue_receive_request(sock);
break;
}
send_recvdone_abort(sock, isc_result);
if ((isc_result == ISC_R_UNEXPECTED) ||
((isc_result == ISC_R_CONNECTIONRESET) &&
(errstatus != ERROR_OPERATION_ABORTED) &&
(errstatus != ERROR_CONNECTION_ABORTED)) ||
(isc_result == ISC_R_HOSTUNREACH)) {
if (isc_result == ISC_R_UNEXPECTED) {
UNEXPECTED_ERROR(__FILE__, __LINE__,
"SOCKET_RECV: Windows error code: %d, returning ISC error %d",
errstatus, isc_result);
......@@ -2463,8 +2462,25 @@ SocketIoThread(LPVOID ThreadContext) {
case SOCKET_ACCEPT:
INSIST(sock->pending_iocp > 0);
sock->pending_iocp--;
INSIST(sock->pending_accept > 0);
socket_log(__LINE__, sock, NULL, EVENT, NULL, 0, 0,
"Accept: errstatus=%d isc_result=%d", errstatus, isc_result);
if (acceptdone_is_active(sock, lpo->adev)) {
if (restart_accept(sock, lpo) == ISC_R_SUCCESS) {
UNLOCK(&sock->lock);
goto wait_again;
} else {
errstatus = GetLastError();
isc_result = isc__errno2resultx(errstatus, __FILE__, __LINE__);
socket_log(__LINE__, sock, NULL, EVENT, NULL, 0, 0,
"restart_accept() failed: errstatus=%d isc_result=%d",
errstatus, isc_result);
}
}
sock->pending_iocp--;
sock->pending_accept--;
if (acceptdone_is_active(sock, lpo->adev)) {
closesocket(lpo->adev->newsocket->fd);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment