]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
1627. [bug] win32: sockets were not being closed when the
authorMark Andrews <marka@isc.org>
Tue, 4 May 2004 00:14:47 +0000 (00:14 +0000)
committerMark Andrews <marka@isc.org>
Tue, 4 May 2004 00:14:47 +0000 (00:14 +0000)
                        last external reference was removed. [RT# 11179]

CHANGES
lib/isc/win32/socket.c

diff --git a/CHANGES b/CHANGES
index 0e1675d911475a128bba7cf1dc9a48484bb09a06..ed887fd0dba6fde9f8dcc7b52f9a837eb8a8ee1e 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,4 +1,7 @@
 
+1627.  [bug]           win32: sockets were not being closed when the
+                       last external reference was removed. [RT# 11179]
+
        --- 9.2.4rc3 released ---
 
 1623.  [bug]           A serial number of zero was being displayed in the
index 3d4423d8a388296603696a23313850c90f94f5fa..4f6513b5de9339248bcd4519e58f93363f930062 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: socket.c,v 1.5.2.19 2004/03/09 06:12:19 marka Exp $ */
+/* $Id: socket.c,v 1.5.2.20 2004/05/04 00:14:47 marka Exp $ */
 
 /* This code has been rewritten to take advantage of Windows Sockets
  * I/O Completion Ports and Events. I/O Completion Ports is ONLY
@@ -239,8 +239,10 @@ struct isc_socket {
                                listener : 1,   /* listener socket */
                                connected : 1,
                                connecting : 1, /* connect pending */
-                               bound : 1;      /* bound to local addr */
-
+                               bound : 1,      /* bound to local addr */
+                               pending_free: 1;
+       unsigned int            pending_recv;
+       unsigned int            pending_send;
 };
 
 /*
@@ -346,11 +348,8 @@ static isc_threadresult_t WINAPI SocketIoThread(LPVOID ThreadContext);
 static void free_socket(isc_socket_t **);
 
 enum {
-       SOCKET_CANCEL,
-       SOCKET_SHUTDOWN,
        SOCKET_RECV,
        SOCKET_SEND,
-       SOCK_ACCEPT
 };
 
 enum {
@@ -358,9 +357,6 @@ enum {
        EVENT_DELETE
 };
 
-#define SOCK_DEAD(s)                   ((s)->references == 0)
-
-
 #if defined(ISC_SOCKET_DEBUG)
 /*
  * This is used to dump the contents of the sock structure
@@ -454,7 +450,7 @@ iocompletionport_createthreads(int total_threads, isc_socketmgr_t *manager) {
         * We need at least one
         */
        for (i = 0; i < total_threads; i++) {
-               manager->hIOCPThreads[i] = CreateThread( NULL, 0, SocketIoThread,
+               manager->hIOCPThreads[i] = CreateThread(NULL, 0, SocketIoThread,
                                                manager, 0,
                                                &manager->dwIOCPThreadIds[i]);
                if(manager->hIOCPThreads[i] == NULL) {
@@ -521,7 +517,8 @@ iocompletionport_exit(isc_socketmgr_t *manager) {
 }
 
 /*
- * Add sockets in here and pass the sock data in as part of the information needed
+ * Add sockets in here and pass the sock data in as part of the
+ * information needed.
  */
 void
 iocompletionport_update(isc_socket_t *sock) {
@@ -652,9 +649,10 @@ socket_eventlist_add(event_change_t *evchange, sock_event_list *evlist,
        sock->evthread_id = GetCurrentThreadId();
        return (ISC_TRUE);
 }
+
 /*
- * Note that the eventLock is locked before calling this function
- * All Events and associated sockes are closed here
+ * Note that the eventLock is locked before calling this function.
+ * All Events and associated sockets are closed here.
  */
 isc_boolean_t
 socket_eventlist_delete(event_change_t *evchange, sock_event_list *evlist) {
@@ -664,7 +662,7 @@ socket_eventlist_delete(event_change_t *evchange, sock_event_list *evlist) {
 
        REQUIRE(evchange != NULL);
        /*  Make sure this is the right thread from which to delete the event */
-       if(evchange->evthread_id != GetCurrentThreadId())
+       if (evchange->evthread_id != GetCurrentThreadId())
                return (ISC_FALSE);
 
        REQUIRE(evlist != NULL);
@@ -678,6 +676,7 @@ socket_eventlist_delete(event_change_t *evchange, sock_event_list *evlist) {
                        break;
                }
        }
+
        /* Actual event start at 1 */
        if (iEvent < 1)
                return (ISC_FALSE);
@@ -686,6 +685,7 @@ socket_eventlist_delete(event_change_t *evchange, sock_event_list *evlist) {
                evlist->aEventList[i] = evlist->aEventList[i + 1];
                evlist->aSockList[i] = evlist->aSockList[i + 1];
        }
+
        evlist->aEventList[evlist->max_event - 1] = 0;
        evlist->aSockList[evlist->max_event - 1] = NULL;
 
@@ -698,6 +698,7 @@ socket_eventlist_delete(event_change_t *evchange, sock_event_list *evlist) {
 
        return (ISC_TRUE);
 }
+
 /*
  * Get the event changes off of the list and apply the
  * requested changes. The manager lock is taken out at
@@ -722,15 +723,20 @@ process_eventlist(sock_event_list *evlist, isc_socketmgr_t *manager) {
 
        LOCK(&manager->lock);
 
-       /* First the deletes */
+       /*
+        * First the deletes.
+        */
        evchange = ISC_LIST_HEAD(manager->event_updates);
        while (evchange != NULL) {
                next = ISC_LIST_NEXT(evchange, link);
                del = ISC_FALSE;
-               if(evchange->action == EVENT_DELETE) {
+               if (evchange->action == EVENT_DELETE) {
                        del = socket_eventlist_delete(evchange, evlist);
 
-                       /* Delete only if this thread's socket list was updated */
+                       /*
+                        * Delete only if this thread's socket list was
+                        * updated.
+                        */
                        if (del) {
                                ISC_LIST_DEQUEUE(manager->event_updates,
                                                 evchange, link);
@@ -740,15 +746,21 @@ process_eventlist(sock_event_list *evlist, isc_socketmgr_t *manager) {
                }
                evchange = next;
        }
-       /* Now the adds */
+
+       /*
+        * Now the adds.
+        */
        evchange = ISC_LIST_HEAD(manager->event_updates);
        while (evchange != NULL) {
                next = ISC_LIST_NEXT(evchange, link);
                del = ISC_FALSE;
-               if(evchange->action == EVENT_ADD) {
+               if (evchange->action == EVENT_ADD) {
                        del = socket_eventlist_add(evchange, evlist, manager);
 
-                       /* Delete only if this thread's socket list was updated */
+                       /*
+                        * Delete only if this thread's socket list was
+                        * updated.
+                        */
                        if (del) {
                                ISC_LIST_DEQUEUE(manager->event_updates,
                                                 evchange, link);
@@ -761,13 +773,15 @@ process_eventlist(sock_event_list *evlist, isc_socketmgr_t *manager) {
        UNLOCK(&manager->lock);
        return (ISC_R_SUCCESS);
 }
+
 /*
  * Add the event list changes to the queue and notify the
  * event loop
  */
 static void
 notify_eventlist(isc_socket_t *sock, isc_socketmgr_t *manager,
-                unsigned int action) {
+                unsigned int action)
+{
 
        event_change_t *evchange;
 
@@ -793,6 +807,7 @@ notify_eventlist(isc_socket_t *sock, isc_socketmgr_t *manager,
        else
                WSASetEvent(manager->prime_alert);
 }
+
 /*
  * Note that the socket is already locked before calling this function
  */
@@ -830,6 +845,7 @@ socket_event_add(isc_socket_t *sock, long type) {
        notify_eventlist(sock, sock->manager, EVENT_ADD);
        return (ISC_R_SUCCESS);
 }
+
 /*
  * Note that the socket is not locked before calling this function
  */
@@ -847,8 +863,8 @@ socket_event_delete(isc_socket_t *sock) {
                sock->hAlert = NULL;
                sock->evthread_id = 0;
        }
-
 }
+
 /*
  * Routine to cleanup and then close the socket.
  * Only close the socket here if it is NOT associated
@@ -872,6 +888,7 @@ socket_close(isc_socket_t *sock) {
        }
 
 }
+
 /*
  * Initialize socket services
  */
@@ -893,7 +910,8 @@ BOOL InitSockets() {
 
 int
 internal_sendmsg(isc_socket_t *sock, IoCompletionInfo *lpo,
-                struct msghdr *messagehdr, int flags, int *Error) {
+                struct msghdr *messagehdr, int flags, int *Error)
+{
        int Result;
        DWORD BytesSent;
        DWORD Flags = flags;
@@ -918,19 +936,20 @@ internal_sendmsg(isc_socket_t *sock, IoCompletionInfo *lpo,
                *Error = WSAGetLastError();
         
                switch (*Error) {
+               case WSA_IO_INCOMPLETE :
+               case WSA_WAIT_IO_COMPLETION :
+               case WSA_IO_PENDING :
+                       sock->pending_send++;
+               case NO_ERROR :
+                       break;
 
-                       case NO_ERROR :
-                       case WSA_IO_INCOMPLETE :
-                       case WSA_WAIT_IO_COMPLETION :
-                       case WSA_IO_PENDING :
-                               break;
-
-                       default :
-                               return (-1);
-                               break;
-                       }
-       }
-       if(lpo != NULL)
+               default :
+                       return (-1);
+                       break;
+               }
+       } else
+               sock->pending_send++;
+       if (lpo != NULL)
                return (0);
        else
                return (total_sent);
@@ -938,7 +957,8 @@ internal_sendmsg(isc_socket_t *sock, IoCompletionInfo *lpo,
 
 int
 internal_recvmsg(isc_socket_t *sock, IoCompletionInfo *lpo,
-                struct msghdr *messagehdr, int flags, int *Error) {
+                struct msghdr *messagehdr, int flags, int *Error)
+{
        DWORD Flags = 0;
        DWORD NumBytes = 0;
        int total_bytes = 0;
@@ -946,14 +966,14 @@ internal_recvmsg(isc_socket_t *sock, IoCompletionInfo *lpo,
 
        *Error = 0;
        Result = WSARecvFrom((SOCKET) sock->fd,
-                       messagehdr->msg_iov,
-                       messagehdr->msg_iovlen,
-                       &NumBytes,
-                       &Flags,
-                       messagehdr->msg_name,
-                       (int *)&(messagehdr->msg_namelen),
-                       (LPOVERLAPPED) lpo,
-                       NULL);
+                            messagehdr->msg_iov,
+                            messagehdr->msg_iovlen,
+                            &NumBytes,
+                            &Flags,
+                            messagehdr->msg_name,
+                            (int *)&(messagehdr->msg_namelen),
+                            (LPOVERLAPPED) lpo,
+                            NULL);
 
        total_bytes = (int) NumBytes;
 
@@ -963,31 +983,32 @@ internal_recvmsg(isc_socket_t *sock, IoCompletionInfo *lpo,
                *Error = WSAGetLastError();
         
                switch (*Error) {
+               case WSA_IO_INCOMPLETE:
+               case WSA_WAIT_IO_COMPLETION:
+               case WSA_IO_PENDING:
+                       sock->pending_recv++;
+               case NO_ERROR:
+                       break;
 
-                       case NO_ERROR :
-                       case WSA_IO_INCOMPLETE :
-                       case WSA_WAIT_IO_COMPLETION :
-                       case WSA_IO_PENDING :
-                                       break;
+               default :
+                       return (-1);
+                       break;
+               }
+       } else
+               sock->pending_recv++;
 
-                       default :
-                                       return (-1);
-                                       break;
-                       }
-       }
        /* Return the flags received in header */
        messagehdr->msg_flags = Flags;
-       if(lpo != NULL)
+       if (lpo != NULL)
                return (-1);
        else
                return (total_bytes);
-
 } 
 
 static void
-manager_log(isc_socketmgr_t *sockmgr,
-           isc_logcategory_t *category, isc_logmodule_t *module, int level,
-           const char *fmt, ...) {
+manager_log(isc_socketmgr_t *sockmgr, isc_logcategory_t *category,
+           isc_logmodule_t *module, int level, const char *fmt, ...)
+{
        char msgbuf[2048];
        va_list ap;
 
@@ -1007,11 +1028,13 @@ socket_log(isc_socket_t *sock, isc_sockaddr_t *address,
           isc_logcategory_t *category, isc_logmodule_t *module, int level,
           isc_msgcat_t *msgcat, int msgset, int message,
           const char *fmt, ...) ISC_FORMAT_PRINTF(9, 10);
+
 static void
 socket_log(isc_socket_t *sock, isc_sockaddr_t *address,
           isc_logcategory_t *category, isc_logmodule_t *module, int level,
           isc_msgcat_t *msgcat, int msgset, int message,
-          const char *fmt, ...) {
+          const char *fmt, ...)
+{
        char msgbuf[2048];
        char peerbuf[256];
        va_list ap;
@@ -1058,6 +1081,7 @@ make_nonblock(SOCKET fd) {
 
        return (ISC_R_SUCCESS);
 }
+
 /*
  * Windows 2000 systems incorrectly cause UDP sockets using WASRecvFrom
  * to not work correctly, returning a WSACONNRESET error when a WSASendTo
@@ -1107,7 +1131,8 @@ connection_reset_fix(SOCKET fd) {
 static void
 build_msghdr_send(isc_socket_t *sock, isc_socketevent_t *dev,
                  struct msghdr *msg, char *cmsg,
-                 WSABUF *iov, size_t *write_countp) {
+                 WSABUF *iov, size_t *write_countp)
+{
        unsigned int iovcount;
        isc_buffer_t *buffer;
        isc_region_t used;
@@ -1194,7 +1219,8 @@ build_msghdr_send(isc_socket_t *sock, isc_socketevent_t *dev,
 static void
 build_msghdr_recv(isc_socket_t *sock, isc_socketevent_t *dev,
                  struct msghdr *msg, char *cmsg,
-                 WSABUF *iov, size_t *read_countp) {
+                 WSABUF *iov, size_t *read_countp)
+{
        unsigned int iovcount;
        isc_buffer_t *buffer;
        isc_region_t available;
@@ -1224,10 +1250,10 @@ build_msghdr_recv(isc_socket_t *sock, isc_socketevent_t *dev,
                iov[0].len = read_count;
                iovcount = 1;
        } else {
-       /*
-        * Multibuffer I/O.
-        * Skip empty buffers.
-        */
+               /*
+                * Multibuffer I/O.
+                * Skip empty buffers.
+                */
                while (buffer != NULL) {
                        REQUIRE(ISC_BUFFER_VALID(buffer));
                        if (isc_buffer_availablelength(buffer) != 0)
@@ -1266,7 +1292,8 @@ build_msghdr_recv(isc_socket_t *sock, isc_socketevent_t *dev,
 
 static void
 set_dev_address(isc_sockaddr_t *address, isc_socket_t *sock,
-               isc_socketevent_t *dev) {
+               isc_socketevent_t *dev)
+{
        if (sock->type == isc_sockettype_udp) {
                if (address != NULL)
                        dev->address = *address;
@@ -1280,14 +1307,14 @@ set_dev_address(isc_sockaddr_t *address, isc_socket_t *sock,
 
 static isc_socketevent_t *
 allocate_socketevent(isc_socket_t *sock, isc_eventtype_t eventtype,
-                    isc_taskaction_t action, const void *arg) {
+                    isc_taskaction_t action, const void *arg)
+{
        isc_socketevent_t *ev;
 
        ev = (isc_socketevent_t *)isc_event_allocate(sock->manager->mctx,
                                                     sock, eventtype,
                                                     action, arg,
                                                     sizeof(*ev));
-
        if (ev == NULL)
                return (NULL);
 
@@ -1324,7 +1351,8 @@ dump_msg(struct msghdr *msg, isc_socket_t *sock) {
 
 static int
 completeio_recv(isc_socket_t *sock, isc_socketevent_t *dev,
-               struct msghdr *messagehdr, int cc, int recv_errno) {
+               struct msghdr *messagehdr, int cc, int recv_errno)
+{
        size_t actual_count;
        isc_buffer_t *buffer;
 
@@ -1442,31 +1470,27 @@ completeio_recv(isc_socket_t *sock, isc_socketevent_t *dev,
        dev->result = ISC_R_SUCCESS;
        return (DOIO_SUCCESS);
 }
+
 static int
 startio_recv(isc_socket_t *sock, isc_socketevent_t *dev, int *nbytes,
-            BOOL bwait, int *recv_errno) {
+            int *recv_errno)
+{
        char *cmsg = NULL;
        char strbuf[ISC_STRERRORSIZE];
        IoCompletionInfo *lpo;
        int status;
-       struct msghdr messagehdr;
        struct msghdr *msghdr;
 
-       if (!bwait) {
-               lpo = (IoCompletionInfo *) HeapAlloc(hHeapHandle,
-                       HEAP_ZERO_MEMORY, sizeof(IoCompletionInfo));
-               lpo->request_type = SOCKET_RECV;
-               lpo->dev = dev;
-               msghdr = &lpo->messagehdr;
-       } else {        /* Wait for recv to complete */
-               lpo = NULL;
-               msghdr = &messagehdr;
-       }
-       sock->references++;
+       lpo = (IoCompletionInfo *) HeapAlloc(hHeapHandle,
+                                            HEAP_ZERO_MEMORY,
+                                            sizeof(IoCompletionInfo));
+       lpo->request_type = SOCKET_RECV;
+       lpo->dev = dev;
+       msghdr = &lpo->messagehdr;
        memset(msghdr, 0, sizeof(struct msghdr));
 
        build_msghdr_recv(sock, dev, msghdr, cmsg, sock->iov,
-                       &(sock->totalBytes));
+                         &(sock->totalBytes));
 
 #if defined(ISC_SOCKET_DEBUG)
        dump_msg(msghdr, sock);
@@ -1485,13 +1509,12 @@ startio_recv(isc_socket_t *sock, isc_socketevent_t *dev, int *nbytes,
                        socket_log(sock, NULL, IOEVENT,
                                   isc_msgcat, ISC_MSGSET_SOCKET,
                                   ISC_MSG_DOIORECV, 
-                                 "startio_recv: recvmsg(%d) %d bytes, err %d/%s",
+                                 "startio_recv: recvmsg(%d) %d bytes, "
+                                 "err %d/%s",
                                   sock->fd, *nbytes, *recv_errno, strbuf);
                }
-               status = completeio_recv(sock, dev, msghdr, *nbytes, *recv_errno);
-               if(status != DOIO_SOFT) {
-                       sock->references--;
-               }
+               status = completeio_recv(sock, dev, msghdr,
+                                        *nbytes, *recv_errno);
                goto done;
        }
        dev->result = ISC_R_SUCCESS;
@@ -1499,6 +1522,7 @@ startio_recv(isc_socket_t *sock, isc_socketevent_t *dev, int *nbytes,
 done:
        return (status);
 }
+
 /*
  * Returns:
  *     DOIO_SUCCESS    The operation succeeded.  dev->result contains
@@ -1513,8 +1537,9 @@ done:
  *     No other return values are possible.
  */
 static int
-completeio_send(isc_socket_t *sock, isc_socketevent_t *dev, struct msghdr *messagehdr, int cc,
-               int send_errno) {
+completeio_send(isc_socket_t *sock, isc_socketevent_t *dev,
+               struct msghdr *messagehdr, int cc, int send_errno)
+{
        char addrbuf[ISC_SOCKADDR_FORMATSIZE];
        char strbuf[ISC_STRERRORSIZE];
 
@@ -1592,28 +1617,24 @@ completeio_send(isc_socket_t *sock, isc_socketevent_t *dev, struct msghdr *messa
        dev->result = ISC_R_SUCCESS;
        return (DOIO_SUCCESS);
 }
+
 static int
 startio_send(isc_socket_t *sock, isc_socketevent_t *dev, int *nbytes,
-            BOOL bwait, int *send_errno) {
+            int *send_errno)
+{
        char *cmsg = NULL;
        char strbuf[ISC_STRERRORSIZE];
        IoCompletionInfo *lpo;
        int status;
-       struct msghdr messagehdr;
        struct msghdr *msghdr;
 
-       if (!bwait) {
-               lpo = (IoCompletionInfo *) HeapAlloc(hHeapHandle,
-                       HEAP_ZERO_MEMORY, sizeof(IoCompletionInfo));
-               lpo->request_type = SOCKET_SEND;
-               lpo->dev = dev;
-               msghdr = &lpo->messagehdr;
-       } else {        /* Wait for send to complete */
-               lpo = NULL;
-               msghdr = &messagehdr;
-       }
+       lpo = (IoCompletionInfo *) HeapAlloc(hHeapHandle,
+                                            HEAP_ZERO_MEMORY,
+                                            sizeof(IoCompletionInfo));
+       lpo->request_type = SOCKET_SEND;
+       lpo->dev = dev;
+       msghdr = &lpo->messagehdr;
        memset(msghdr, 0, sizeof(struct msghdr));
-       sock->references++;
 
        build_msghdr_send(sock, dev, msghdr, cmsg, sock->iov,
                        &(sock->totalBytes));
@@ -1631,13 +1652,12 @@ startio_send(isc_socket_t *sock, isc_socketevent_t *dev, int *nbytes,
                        socket_log(sock, NULL, IOEVENT,
                                   isc_msgcat, ISC_MSGSET_SOCKET,
                                   ISC_MSG_INTERNALSEND, 
-                                 "startio_send: internal_sendmsg(%d) %d bytes, err %d/%s",
+                                  "startio_send: internal_sendmsg(%d) %d "
+                                  "bytes, err %d/%s",
                                   sock->fd, *nbytes, *send_errno, strbuf);
                }
-               status = completeio_send(sock, dev, msghdr, *nbytes, *send_errno);
-               if(status != DOIO_SOFT) {
-                       sock->references--;
-               }
+               status = completeio_send(sock, dev, msghdr,
+                                        *nbytes, *send_errno);
                goto done;
        }
        dev->result = ISC_R_SUCCESS;
@@ -1645,6 +1665,7 @@ startio_send(isc_socket_t *sock, isc_socketevent_t *dev, int *nbytes,
 done:
        return (status);
 }
+
 /*
  * Kill.
  *
@@ -1655,6 +1676,7 @@ static void
 destroy_socket(isc_socket_t **sockp) {
        isc_socket_t *sock = *sockp;
        isc_socketmgr_t *manager = sock->manager;
+       isc_boolean_t dofree = ISC_TRUE;
 
        REQUIRE(sock != NULL);
 
@@ -1668,15 +1690,14 @@ destroy_socket(isc_socket_t **sockp) {
 
        LOCK(&manager->lock);
 
-       /*
-        * No one has this socket open and the socket doesn't have to be
-        * locked. The socket_close function makes sure that if needed
-        * the event_wait loop removes any associated event from the list
-        * of events being waited on.
-        */
+       LOCK(&sock->lock);
        socket_close(sock);
-
+       if (sock->pending_recv != 0 || sock->pending_send != 0) {
+               dofree = ISC_FALSE;
+               sock->pending_free = 1;
+       }
        ISC_LIST_UNLINK(manager->socklist, sock, link);
+       UNLOCK(&sock->lock);
 
        if (ISC_LIST_EMPTY(manager->socklist))
                SIGNAL(&manager->shutdown_ok);
@@ -1684,10 +1705,10 @@ destroy_socket(isc_socket_t **sockp) {
        /*
         * XXX should reset manager->maxfd here
         */
-
        UNLOCK(&manager->lock);
 
-       free_socket(sockp);
+       if (dofree)
+               free_socket(sockp);
 }
 
 static isc_result_t
@@ -1721,6 +1742,9 @@ allocate_socket(isc_socketmgr_t *manager, isc_sockettype_t type,
        sock->connect_ev = NULL;
        sock->pending_accept = 0;
        sock->pending_close = 0;
+       sock->pending_recv = 0;
+       sock->pending_send = 0;
+       sock->pending_free = 0;
        sock->iocp = 0;
        sock->listener = 0;
        sock->connected = 0;
@@ -2066,14 +2090,6 @@ internal_accept(isc_socket_t *sock, int accept_errno) {
        INSIST(sock->pending_accept == 1);
        sock->pending_accept = 0;
 
-       INSIST(sock->references > 0);
-       sock->references--;  /* the internal event is done with this socket */
-       if (sock->references == 0) {
-               UNLOCK(&sock->lock);
-               destroy_socket(&sock);
-               return;
-       }
-
        /*
         * Check any possible error status from the event notification here.
         * Note that we don't take any action since it was only
@@ -2284,18 +2300,6 @@ internal_connect(isc_socket_t *sock, int connect_errno) {
 
        LOCK(&sock->lock);
 
-       /*
-        * When the internal event was sent the reference count was bumped
-        * to keep the socket around for us.  Decrement the count here.
-        */
-       INSIST(sock->references > 0);
-       sock->references--;
-       if (sock->references == 0) {
-               UNLOCK(&sock->lock);
-               destroy_socket(&sock);
-               return;
-       }
-
        /*
         * Has this event been canceled?
         */
@@ -2366,7 +2370,9 @@ internal_connect(isc_socket_t *sock, int connect_errno) {
 }
 
 static void
-internal_recv(isc_socket_t *sock, isc_socketevent_t *dev, struct msghdr *messagehdr, int nbytes, int recv_errno) {
+internal_recv(isc_socket_t *sock, isc_socketevent_t *dev,
+             struct msghdr *messagehdr, int nbytes, int recv_errno)
+{
        isc_socketevent_t *ldev;
        int io_state;
        int cc;
@@ -2378,14 +2384,8 @@ internal_recv(isc_socket_t *sock, isc_socketevent_t *dev, struct msghdr *message
                   isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_INTERNALRECV,
                   "internal_recv: task got socket event %p", dev);
 
-       INSIST(sock->references > 0);
-       sock->references--;  /* the internal event is done with this socket */
-       if (sock->references == 0) {
-               UNLOCK(&sock->lock);
-               destroy_socket(&sock);
-               return;
-       }
-
+       INSIST(sock->pending_recv > 0);
+       sock->pending_recv--;
        /* If the event is no longer in the list we can just return */
        ldev = ISC_LIST_HEAD(sock->recv_list);
        while (ldev != NULL && ldev != dev) {
@@ -2398,34 +2398,36 @@ internal_recv(isc_socket_t *sock, isc_socketevent_t *dev, struct msghdr *message
         * Try to do as much I/O as possible on this socket.  There are no
         * limits here, currently.
         */
-               switch (completeio_recv(sock, dev, messagehdr, nbytes, recv_errno)) {
-               case DOIO_SOFT:
-                       cc = 0;
-                       recv_errno = 0;
-                       io_state = startio_recv(sock, dev, &cc, FALSE, &recv_errno);
-                       goto done;
+       switch (completeio_recv(sock, dev, messagehdr, nbytes, recv_errno)) {
+       case DOIO_SOFT:
+               cc = 0;
+               recv_errno = 0;
+               io_state = startio_recv(sock, dev, &cc, &recv_errno);
+               goto done;
 
-               case DOIO_EOF:
-                       /*
-                        * read of 0 means the remote end was closed.
-                        * Run through the event queue and dispatch all
-                        * the events with an EOF result code.
-                        */
-                       dev->result = ISC_R_EOF;
-                       send_recvdone_event(sock, &dev);
-                       goto done;
+       case DOIO_EOF:
+               /*
+                * read of 0 means the remote end was closed.
+                * Run through the event queue and dispatch all
+                * the events with an EOF result code.
+                */
+               dev->result = ISC_R_EOF;
+               send_recvdone_event(sock, &dev);
+               goto done;
 
-               case DOIO_SUCCESS:
-               case DOIO_HARD:
-                       send_recvdone_event(sock, &dev);
-                       break;
-               }
+       case DOIO_SUCCESS:
+       case DOIO_HARD:
+               send_recvdone_event(sock, &dev);
+               break;
+       }
  done:
        UNLOCK(&sock->lock);
 }
 
 static void
-internal_send(isc_socket_t *sock, isc_socketevent_t *dev, struct msghdr *messagehdr, int nbytes, int send_errno) {
+internal_send(isc_socket_t *sock, isc_socketevent_t *dev,
+             struct msghdr *messagehdr, int nbytes, int send_errno)
+{
        isc_socketevent_t *ldev;
        int io_state;
        int cc;
@@ -2440,13 +2442,8 @@ internal_send(isc_socket_t *sock, isc_socketevent_t *dev, struct msghdr *message
                   isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_INTERNALSEND,
                   "internal_send: task got socket event %p", dev);
 
-       INSIST(sock->references > 0);
-       sock->references--;  /* the internal event is done with this socket */
-       if (sock->references == 0) {
-               UNLOCK(&sock->lock);
-               destroy_socket(&sock);
-               return;
-       }
+       INSIST(sock->pending_send > 0);
+       sock->pending_send--;
 
        /* If the event is no longer in the list we can just return */
        ldev = ISC_LIST_HEAD(sock->send_list);
@@ -2463,7 +2460,7 @@ internal_send(isc_socket_t *sock, isc_socketevent_t *dev, struct msghdr *message
        case DOIO_SOFT:
                cc = 0;
                send_errno = 0;
-               io_state = startio_send(sock, dev, &cc, FALSE, &send_errno);
+               io_state = startio_send(sock, dev, &cc, &send_errno);
                goto done;
 
        case DOIO_HARD:
@@ -2487,8 +2484,6 @@ SocketIoThread(LPVOID ThreadContext) {
        isc_socketmgr_t *manager = ThreadContext;
        BOOL bSuccess = FALSE;
        DWORD nbytes;
-       DWORD tbytes;
-       DWORD tflags;
        IoCompletionInfo *lpo = NULL;
        isc_socket_t *sock = NULL;
        int request;
@@ -2504,7 +2499,9 @@ SocketIoThread(LPVOID ThreadContext) {
         *      preempt normal recv packet processing, but not
         *      higher than the timer sync thread.
         */
-       if (!SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL)) {
+       if (!SetThreadPriority(GetCurrentThread(),
+                              THREAD_PRIORITY_ABOVE_NORMAL))
+       {
                errval = GetLastError();
                isc__strerror(errval, strbuf, sizeof(strbuf));
                FATAL_ERROR(__FILE__, __LINE__,
@@ -2514,33 +2511,53 @@ SocketIoThread(LPVOID ThreadContext) {
                                strbuf);
        }
 
-
        /*
         * Loop forever waiting on I/O Completions and then processing them
         */
-       while(TRUE) {
+       while (TRUE) {
                bSuccess = GetQueuedCompletionStatus (
                                        manager->hIoCompletionPort,
                                        &nbytes,
                                        (LPDWORD) &sock,
                                        (LPOVERLAPPED *)&lpo,
-                                       INFINITE
-                                       );
-               if(lpo == NULL ) {
+                                       INFINITE);
+               if (lpo == NULL) {
                        /*
                         * Received request to exit
                         */
                        break;
                }
                errstatus = 0;
-               if(!bSuccess) {
+               if (!bSuccess) {
+                       isc_boolean_t dofree = ISC_FALSE;
+                       REQUIRE(VALID_SOCKET(sock));
                        /*
-                        * I/O Failure
-                        * Find out why
+                        * Was this the socket closed under us?
                         */
-                       WSAGetOverlappedResult(sock->fd, (LPWSAOVERLAPPED) &lpo,
-                                               &tbytes, FALSE, &tflags);
-                       dev = lpo->dev;
+                       errstatus = WSAGetLastError();
+                       if (nbytes == 0 && errstatus == WSA_OPERATION_ABORTED) {
+                               LOCK(&sock->lock);
+                               switch (lpo->request_type) {
+                               case SOCKET_RECV:
+                                       INSIST(sock->pending_recv > 0);
+                                       sock->pending_recv--;
+                                       break;
+                               case SOCKET_SEND:
+                                       INSIST(sock->pending_send > 0);
+                                       sock->pending_send--;
+                                       break;
+                               }
+                               if (sock->pending_recv == 0 &&
+                                   sock->pending_send == 0 &&
+                                   sock->pending_free)
+                                       dofree = ISC_TRUE;
+                               UNLOCK(&sock->lock);
+                               if (dofree)
+                                       free_socket(&sock);
+                               if (lpo != NULL)
+                                       HeapFree(hHeapHandle, 0, lpo);
+                               continue;
+                       }
                }
 
                request = lpo->request_type;
@@ -2548,20 +2565,17 @@ SocketIoThread(LPVOID ThreadContext) {
                messagehdr = &lpo->messagehdr;
 
                switch (request) {
-               case SOCKET_CANCEL:
-                       break;
                case SOCKET_RECV:
                        internal_recv(sock, dev, messagehdr, nbytes, errstatus);
                        break;
                case SOCKET_SEND:
                        internal_send(sock, dev, messagehdr, nbytes, errstatus);
                        break;
-               default:
-                       break;  /* Unknown: Just ignore it */
                }
                if (lpo != NULL)
                        HeapFree(hHeapHandle, 0, lpo);
        }
+
        /*
         * Exit Completion Port Thread
         */
@@ -2570,6 +2584,7 @@ SocketIoThread(LPVOID ThreadContext) {
                                   ISC_MSG_EXITING, "SocketIoThread exiting"));
        return ((isc_threadresult_t)0);
 }
+
 /*
  * This is the thread that will loop forever, waiting for an event to
  * happen.
@@ -2631,7 +2646,6 @@ event_wait(void *uap) {
                } while (cc < 0 && !manager->bShutdown
                         && manager->event_written == 0);
 
-
                if (manager->bShutdown)
                        break;
 
@@ -2690,11 +2704,9 @@ event_wait(void *uap) {
                        if (wsock->listener == 1 &&
                            wsock->pending_accept == 0) {
                                wsock->pending_accept = 1;
-                               wsock->references++;
                                internal_accept(wsock, event_errno);
                        }
                        else {
-                               wsock->references++;
                                internal_connect(wsock, event_errno);
                        }
                }
@@ -2706,6 +2718,7 @@ event_wait(void *uap) {
 
        return ((isc_threadresult_t)0);
 }
+
 /*
  * Create a new socket manager.
  */
@@ -2861,7 +2874,8 @@ isc_socketmgr_destroy(isc_socketmgr_t **managerp) {
 
 static isc_result_t
 socket_recv(isc_socket_t *sock, isc_socketevent_t *dev, isc_task_t *task,
-           unsigned int flags) {
+           unsigned int flags)
+{
        int io_state;
        int cc = 0;
        isc_task_t *ntask = NULL;
@@ -2872,7 +2886,7 @@ socket_recv(isc_socket_t *sock, isc_socketevent_t *dev, isc_task_t *task,
 
        LOCK(&sock->lock);
        iocompletionport_update(sock);
-       io_state = startio_recv(sock, dev, &cc, FALSE, &recv_errno);
+       io_state = startio_recv(sock, dev, &cc, &recv_errno);
 
        switch (io_state) {
        case DOIO_SOFT:
@@ -3050,7 +3064,7 @@ socket_send(isc_socket_t *sock, isc_socketevent_t *dev, isc_task_t *task,
        LOCK(&sock->lock);
        have_lock = ISC_TRUE;
        iocompletionport_update(sock);
-       io_state = startio_send(sock, dev, &cc, FALSE, &send_errno);
+       io_state = startio_send(sock, dev, &cc, &send_errno);
 
        switch (io_state) {
        case DOIO_SOFT:
@@ -3642,8 +3656,8 @@ isc_socket_cancel(isc_socket_t *sock, isc_task_t *task, unsigned int how) {
                isc_socket_newconnev_t *next;
                isc_task_t             *current_task;
 
-               dev = ISC_LIST_HEAD(sock->accept_list);
                socket_event_delete(sock);
+               dev = ISC_LIST_HEAD(sock->accept_list);
 
                while (dev != NULL) {
                        current_task = dev->ev_sender;