2972. [bug] win32: address windows socket errors. [RT #21906]
This commit is contained in:
2
CHANGES
2
CHANGES
@@ -1,3 +1,5 @@
|
||||
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.70.54.5 2009/11/10 18:31:24 each Exp $ */
|
||||
/* $Id: socket.c,v 1.70.54.5.10.1 2010/11/18 00:40:44 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);
|
||||
|
||||
@@ -2345,6 +2303,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
|
||||
@@ -2385,6 +2400,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,
|
||||
@@ -2414,32 +2430,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)) ||
|
||||
(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);
|
||||
@@ -2461,8 +2461,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);
|
||||
|
||||
Reference in New Issue
Block a user