Commit 578f5882 authored by Mark Andrews's avatar Mark Andrews
Browse files

1627. [bug] win32: sockets were not being closed when the

                        last external reference was removed. [RT# 11179]
parent cdebaff6
1627. [bug] win32: sockets were not being closed when the
last external reference was removed. [RT# 11179]
1626. [bug] --enable-getifaddrs was broken. [RT#11259]
1625. [placeholder] rt11237
......
......@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: config.h.win32,v 1.10 2004/04/19 05:52:21 marka Exp $ */
/* $Id: config.h.win32,v 1.11 2004/05/03 23:54:37 marka Exp $ */
/*
* win32 configuration file
......@@ -104,6 +104,10 @@
/* Define if you have h_errno */
#define HAVE_H_ERRNO
#define ISC_PLATFORM_NEEDSTRLCAT
#define ISC_PLATFORM_NEEDSTRLCPY
#define S_IFMT _S_IFMT /* file type mask */
#define S_IFDIR _S_IFDIR /* directory */
#define S_IFCHR _S_IFCHR /* character special */
......
......@@ -433,6 +433,8 @@ isc_task_getcurrenttime
isc_net_probe_ipv6only
isc_timermgr_poke
isc_net_probe_ipv6pktinfo
isc_string_strlcat
isc_string_strlcpy
; Exported Data
......
......@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: socket.c,v 1.30 2004/03/05 05:11:59 marka Exp $ */
/* $Id: socket.c,v 1.31 2004/05/03 23:54:38 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;