/*
- * Copyright (C) 2000-2002 Internet Software Consortium.
+ * Copyright (C) 2000, 2001 Internet Software Consortium.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: socket.c,v 1.18 2002/05/27 00:40:23 marka Exp $ */
+/* $Id: socket.c,v 1.19 2002/08/01 03:46:21 mayer Exp $ */
#define MAKE_EXTERNAL 1
#include <config.h>
#include <unistd.h>
#include <io.h>
#include <fcntl.h>
+#include <process.h>
#include <isc/buffer.h>
#include <isc/bufferlist.h>
#include <isc/msgs.h>
#include <isc/mutex.h>
#include <isc/net.h>
+#include <isc/os.h>
#include <isc/platform.h>
#include <isc/print.h>
#include <isc/region.h>
#include <isc/socket.h>
+#include <isc/strerror.h>
+#include <isc/syslog.h>
#include <isc/task.h>
#include <isc/thread.h>
#include <isc/util.h>
+#include <isc/win32os.h>
#include "errno2result.h"
-#define MAX_SELECT_SECONDS 0
-#define MAX_SELECT_MILLISECONDS 400
+/*
+ * Define this macro to control the behavior of connection
+ * resets on UDP sockets. See Microsoft KnowledgeBase Article Q263823
+ * for details.
+ * NOTE: This requires that Windows 2000 systems install Service Pack 2
+ * or later.
+ */
+#ifndef SIO_UDP_CONNRESET
+#define SIO_UDP_CONNRESET _WSAIOW(IOC_VENDOR,12)
+#endif
+
/*
* Some systems define the socket length argument as an int, some as size_t,
* some as socklen_t. This is here so it can be easily changed if needed.
* work around it here.
*/
#define SOFT_ERROR(e) ((e) == WSAEINTR || \
+ (e) == WSA_IO_PENDING || \
(e) == WSAEWOULDBLOCK || \
(e) == EWOULDBLOCK || \
(e) == EINTR || \
* a setsockopt() like interface to request timestamps, and if the OS
* doesn't do it for us, call gettimeofday() on every UDP receive?
*/
-#ifdef SO_TIMESTAMP
-#ifndef USE_CMSG
-#define USE_CMSG 1
-#endif
-#endif
-
-/*
- * Check to see if we have even basic support for cracking messages from
- * the control data returned from/sent via recvmsg()/sendmsg().
- */
-#if defined(USE_CMSG) && (!defined(CMSG_LEN) || !defined(CMSG_SPACE))
-#undef USE_CMSG
-#endif
/*
* We really don't want to try and use these control messages. Win32
* Message header for recvmsg and sendmsg calls.
* Used value-result for recvmsg, value only for sendmsg.
*/
-struct iovec {
- void *iov_base; /* starting address of buffer */
- size_t iov_len; /* size of buffer */
-};
+
struct msghdr {
void *msg_name; /* optional address */
u_int msg_controllen; /* ancillary data buffer len */
int msg_flags; /* flags on received message */
} msghdr;
-
+
/*
* The number of times a send operation is repeated if the result is EINTR.
*/
isc_socketmgr_t *manager;
isc_mutex_t lock;
isc_sockettype_t type;
+ OVERLAPPED overlapped;
+ /* Pointers to scatter/gather buffers */
+ WSABUF iov[ISC_SOCKET_MAXSCATTERGATHER];
+ struct msghdr *messagehdr;
+ size_t totalBytes;
+ int iEvent; /* Index into Event Array */
+ WSAEVENT hEvent; /* Event Handle */
+ long wait_type; /* Events to wait on */
/* Locked by socket lock. */
ISC_LINK(isc_socket_t) link;
unsigned int references;
- int fd;
+ SOCKET fd;
int pf;
ISC_LIST(isc_socketevent_t) send_list;
isc_sockaddr_t address; /* remote address */
- unsigned int pending_recv : 1,
- pending_send : 1,
+ unsigned int pending_close : 1,
pending_accept : 1,
- listener : 1, /* listener socket */
+ iocp : 1, /* I/O Completion Port */
+ listener : 1, /* listener socket */
connected : 1,
connecting : 1, /* connect pending */
- bound : 1; /* bound to local addr */
+ bound : 1; /* bound to local addr */
-#ifdef ISC_NET_RECVOVERFLOW
- unsigned char overflow; /* used for MSG_TRUNC fake */
-#endif
};
+/*
+ * I/O Completion ports Info structures
+ */
+
+static HANDLE hHeapHandle = NULL;
+static int iocp_total = 0;
+typedef struct IoCompletionInfo {
+ OVERLAPPED overlapped;
+ isc_socketevent_t *dev;
+ int request_type;
+} IoCompletionInfo;
+
+/*
+ * Define a maximum number of I/O Completion Port worker threads
+ * to handle the load on the Completion Port
+ */
+#define MAX_IOCPTHREADS 20
+
+/*
+ * event_change structure to handle adds and deletes from the list of
+ * events in the Wait
+ */
+typedef struct event_change event_change_t;
+
+struct event_change {
+ isc_socket_t *sock;
+ int iEvent;
+ SOCKET fd;
+ unsigned int action;
+ ISC_LINK(event_change_t) link;
+};
+
+/*
+ * Note: We are using an array here since *WaitForMultiple* wants an array
+ */
+
+#define MAX_EVENTS 64
+
+/*
+ * List of events being waited on and their associated sockets
+ */
+typedef struct sock_event_list {
+ int max_event;
+ int total_events;
+ isc_socket_t *aSockList[MAX_EVENTS];
+ WSAEVENT aEventList[MAX_EVENTS];
+ isc_mutex_t EventLock;
+ ISC_LIST(event_change_t) event_updates;
+} sock_event_list;
+
#define SOCKET_MANAGER_MAGIC ISC_MAGIC('I', 'O', 'm', 'g')
#define VALID_MANAGER(m) ISC_MAGIC_VALID(m, SOCKET_MANAGER_MAGIC)
isc_mutex_t lock;
/* Locked by manager lock. */
ISC_LIST(isc_socket_t) socklist;
- fd_set read_fds;
- fd_set write_fds;
- fd_set except_fds;
- isc_socket_t *fds[FD_SETSIZE];
- int fdstate[FD_SETSIZE];
- int maxfd;
- int minfd;
+ sock_event_list sockev_list;
+ int event_written;
+ isc_boolean_t bShutdown;
isc_thread_t watcher;
isc_condition_t shutdown_ok;
- int pipe_fds[2];
+ HANDLE hIoCompletionPort;
+ int maxIOCPThreads;
+ HANDLE hIOCPThreads[MAX_IOCPTHREADS];
+ DWORD dwIOCPThreadIds[MAX_IOCPTHREADS];
};
#define CLOSED 0 /* this one must be zero */
* send() and recv() iovec counts
*/
#define MAXSCATTERGATHER_SEND (ISC_SOCKET_MAXSCATTERGATHER)
-#ifdef ISC_NET_RECVOVERFLOW
-# define MAXSCATTERGATHER_RECV (ISC_SOCKET_MAXSCATTERGATHER + 1)
-#else
-# define MAXSCATTERGATHER_RECV (ISC_SOCKET_MAXSCATTERGATHER)
-#endif
+#define MAXSCATTERGATHER_RECV (ISC_SOCKET_MAXSCATTERGATHER)
+static isc_threadresult_t WINAPI SocketIoThread(LPVOID ThreadContext);
static void send_recvdone_event(isc_socket_t *, isc_socketevent_t **);
static void send_senddone_event(isc_socket_t *, isc_socketevent_t **);
static void free_socket(isc_socket_t **);
static isc_result_t allocate_socket(isc_socketmgr_t *, isc_sockettype_t,
isc_socket_t **);
-static void destroy(isc_socket_t **);
-static void internal_accept(isc_task_t *, isc_event_t *);
-static void internal_connect(isc_task_t *, isc_event_t *);
-static void internal_recv(isc_task_t *, isc_event_t *);
-static void internal_send(isc_task_t *, isc_event_t *);
-static void process_cmsg(isc_socket_t *, struct msghdr *, isc_socketevent_t *);
+static isc_result_t
+socket_recv(isc_socket_t *, isc_socketevent_t *, isc_task_t *, unsigned int);
+static void destroy_socket(isc_socket_t **);
+static void internal_accept(isc_socket_t *, int);
+static void internal_connect(isc_socket_t *, int);
+static void internal_recv(isc_socket_t *, isc_socketevent_t *, int, int);
+static void internal_send(isc_socket_t *, isc_socketevent_t *, int, int);
static void build_msghdr_send(isc_socket_t *, isc_socketevent_t *,
struct msghdr *, char *cmsg,
WSABUF *, size_t *);
struct msghdr *, char *cmsg,
WSABUF *, size_t *);
-#define SELECT_POKE_SHUTDOWN (-1)
-#define SELECT_POKE_NOTHING (-2)
-#define SELECT_POKE_READ (-3)
-#define SELECT_POKE_ACCEPT (-3) /* Same as _READ */
-#define SELECT_POKE_WRITE (-4)
-#define SELECT_POKE_CONNECT (-5)
-#define SELECT_POKE_CLOSE (-6)
-long bpipe_written = 0;
+enum {
+ SOCKET_CANCEL,
+ SOCKET_SHUTDOWN,
+ SOCKET_RECV,
+ SOCKET_SEND,
+ SOCK_ACCEPT
+};
+
+enum {
+ EVENT_ADD,
+ EVENT_DELETE
+};
#define SOCK_DEAD(s) ((s)->references == 0)
+
+#if defined(ISC_SOCKET_DEBUG)
+/*
+ * This is used to duump the contents of the sock structure
+ * You should make sure that the sock is locked before
+ * dumping it. Since the code uses simple printf() statements
+ * it should only be used interactively.
+ */
+void
+sock_dump(isc_socket_t *sock) {
+ isc_socketevent_t *ldev;
+ isc_socket_newconnev_t *ndev;
+ isc_sockaddr_t addr;
+ char socktext[256];
+
+
+ isc_socket_getpeername(sock, &addr);
+ isc_sockaddr_format(&addr, socktext, sizeof(socktext));
+ printf("Remote Socket: %s\n", socktext);
+ isc_socket_getsockname(sock, &addr);
+ isc_sockaddr_format(&addr, socktext, sizeof(socktext));
+ printf("This Socket: %s\n", socktext);
+
+ printf("\n\t\tSock Dump\n");
+ printf("\t\tfd: %u\n", sock->fd);
+ printf("\t\treferences: %d\n", sock->references);
+ printf("\t\tpending_accept: %d\n", sock->pending_accept);
+ printf("\t\tpending_close: %d\n", sock->pending_close);
+ printf("\t\tconnecting: %d\n", sock->connecting);
+ printf("\t\tconnected: %d\n", sock->connected);
+ printf("\t\tbound: %d\n", sock->bound);
+ printf("\t\tiocp: %d\n", sock->iocp);
+ printf("\t\tsocket type: %d\n", sock->type);
+
+ printf("\n\t\tSock Recv List\n");
+ ldev = ISC_LIST_HEAD(sock->recv_list);
+ while (ldev != NULL) {
+ printf("\t\tdev: %p\n", ldev);
+ ldev = ISC_LIST_NEXT(ldev, ev_link);
+ }
+ printf("\n\t\tSock Send List\n");
+ ldev = ISC_LIST_HEAD(sock->send_list);
+ while (ldev != NULL) {
+ printf("\t\tdev: %p\n", ldev);
+ ldev = ISC_LIST_NEXT(ldev, ev_link);
+ }
+ printf("\n\t\tSock Accept List\n");
+ ndev = ISC_LIST_HEAD(sock->accept_list);
+ while (ndev != NULL) {
+ printf("\t\tdev: %p\n", ldev);
+ ndev = ISC_LIST_NEXT(ndev, ev_link);
+ }
+}
+#endif
+
+/* This function will add an entry to the I/O completion port
+ * that will signal the I/O thread to exit (gracefully)
+ */
+static void
+signal_iocompletionport_exit(isc_socketmgr_t *manager) {
+ int i;
+ int errval;
+ char strbuf[ISC_STRERRORSIZE];
+
+ for (i = 0; i < manager->maxIOCPThreads; i++) {
+ if (!PostQueuedCompletionStatus(manager->hIoCompletionPort, 0, 0, 0)) {
+ errval = GetLastError();
+ isc__strerror(errval, strbuf, sizeof(strbuf));
+ FATAL_ERROR(__FILE__, __LINE__,
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKET,
+ ISC_MSG_FAILED,
+ "Can't request service thread to exit: %s"),
+ strbuf);
+ }
+ }
+}
+
+/*
+ * Create the worker threads for the I/O Completion Port
+ */
+void
+iocompletionport_createthreads(int total_threads, isc_socketmgr_t *manager) {
+ int errval;
+ char strbuf[ISC_STRERRORSIZE];
+ int i = 0;
+
+ /*
+ * We need at least one
+ */
+ for (i = 0; i < total_threads; i++) {
+ manager->hIOCPThreads[i] = CreateThread( NULL, 0, SocketIoThread,
+ manager, 0,
+ &manager->dwIOCPThreadIds[i]);
+ if(manager->hIOCPThreads[i] == NULL) {
+ errval = GetLastError();
+ isc__strerror(errval, strbuf, sizeof(strbuf));
+ FATAL_ERROR(__FILE__, __LINE__,
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKET,
+ ISC_MSG_FAILED,
+ "Can't create IOCP thread: %s"),
+ strbuf);
+ }
+ }
+}
+
/*
- * Routine to handle error messages
+ * Create/initialise the I/O completion port
*/
+void
+iocompletionport_init(isc_socketmgr_t *manager) {
+ int errval;
+ char strbuf[ISC_STRERRORSIZE];
+ /*
+ * Create a private heap to handle the socket overlapped structure
+ * The miniumum number of structures is 10, there is no maximum
+ */
+ hHeapHandle = HeapCreate(0, 10*sizeof(IoCompletionInfo), 0);
+ manager->maxIOCPThreads = min(isc_os_ncpus() + 1,
+ MAX_IOCPTHREADS);
+
+ /* Now Create the Completion Port */
+ manager->hIoCompletionPort = CreateIoCompletionPort(
+ INVALID_HANDLE_VALUE, NULL,
+ 0, manager->maxIOCPThreads);
+ if (manager->hIoCompletionPort == NULL) {
+ errval = GetLastError();
+ isc__strerror(errval, strbuf, sizeof(strbuf));
+ FATAL_ERROR(__FILE__, __LINE__,
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKET,
+ ISC_MSG_FAILED,
+ "CreateIoCompletionPort() failed "
+ "during initialization: %s"),
+ strbuf);
+ exit(1);
+ }
+
+ /*
+ * Worker threads for servicing the I/O
+ */
+ iocompletionport_createthreads(manager->maxIOCPThreads, manager);
+}
+
-#define ISC_STRERRORSIZE 128
+void
+iocompletionport_exit(isc_socketmgr_t *manager) {
+ if (manager->hIoCompletionPort != NULL) {
+ /* Get each of the service threads to exit
+ */
+ signal_iocompletionport_exit(manager);
+ }
+}
+/*
+ * Add sockets in here and pass the sock data in as part of the information needed
+ */
void
-isc__strerror(int num, char *buf, size_t size) {
- char *msg;
- unsigned int unum = num;
+iocompletionport_update(isc_socket_t *sock) {
- REQUIRE(buf != NULL);
+ HANDLE hiocp;
+ if(sock->iocp == 0) {
+ sock->iocp = 1;
+ hiocp = CreateIoCompletionPort((HANDLE) sock->fd,
+ sock->manager->hIoCompletionPort, (DWORD) sock,
+ sock->manager->maxIOCPThreads);
+ InterlockedIncrement(&iocp_total);
+
+ }
+}
+
+void
+socket_event_minit(sock_event_list *evlist) {
+ BOOL bReset;
+ int i;
+
+ /* Initialize the Event List */
+ evlist->max_event = 0;
+ evlist->total_events = 0;
+ for (i = 0; i < MAX_EVENTS; i++) {
+ evlist->aSockList[i] = NULL;
+ evlist->aEventList[i] = (WSAEVENT) 0;
+ }
+
+ /*
+ * initialize the lock
+ */
+ if (isc_mutex_init(&(evlist->EventLock)) != ISC_R_SUCCESS) {
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "isc_mutex_init() %s Event Lock",
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+ ISC_MSG_FAILED, "failed"));
+ }
+ evlist->aEventList[0] = WSACreateEvent();
+ (evlist->max_event)++;
+ bReset = WSAResetEvent(evlist->aEventList[0]);
+
+ ISC_LIST_INIT(evlist->event_updates);
+}
+
+/*
+ * Note that the eventLock is already locked before calling this function
+ */
+isc_result_t
+socket_eventlist_add(isc_socket_t *sock, sock_event_list *evlist) {
+ int max_event;
+
+ REQUIRE(sock != NULL);
+ REQUIRE(sock->hEvent != NULL);
+ REQUIRE(evlist != NULL);
+
+ max_event = evlist->max_event;
+ if(max_event >= MAX_EVENTS) {
+ return(ISC_R_NOSPACE);
+ }
+
+ sock->iEvent = max_event;
+ evlist->aSockList[max_event] = sock;
+ evlist->aEventList[max_event] = sock->hEvent;
+ evlist->max_event++;
+ evlist->total_events++;
+ return (ISC_R_SUCCESS);
+}
+/*
+ * Note that the eventLock is locked before calling this function
+ * All Events and associated sockets are closed here
+ */
+void
+socket_eventlist_delete(isc_socket_t *sock, SOCKET fd, int iEvent,
+ sock_event_list *evlist) {
+ int i;
+ WSAEVENT hEvent;
+
+ REQUIRE(evlist != NULL);
+ REQUIRE(iEvent > 0);
+
+ hEvent = evlist->aEventList[iEvent];
+ if (hEvent != NULL)
+ WSACloseEvent(hEvent);
+
+
+ for(i = iEvent; i < evlist->max_event; i++) {
+ evlist->aEventList[i] = evlist->aEventList[i + 1];
+ evlist->aSockList[i] = evlist->aSockList[i + 1];
+ if(evlist->aSockList[i] != NULL)
+ evlist->aSockList[i]->iEvent = i;
+ }
+ evlist->aEventList[evlist->max_event] = 0;
+ evlist->aSockList[evlist->max_event] = NULL;
+ if(sock != NULL) {
+ sock->iEvent = 0;
+ sock->pending_close = 1;
+ }
+ if (fd >= 0)
+ closesocket(fd);
+ evlist->max_event--;
+ evlist->total_events--;
- msg = NTstrerror(num);
- if (msg != NULL)
- snprintf(buf, size, "%s", msg);
- else
- snprintf(buf, size, "Unknown error: %u", unum);
}
+/*
+ * Get the event changes off of the list and apply the
+ * requested changes
+ */
+isc_result_t
+process_eventlist(sock_event_list *evlist, isc_socketmgr_t *manager) {
+ event_change_t *evchange;
+
+ evchange = ISC_LIST_HEAD(evlist->event_updates);
+ while (evchange != NULL) {
+ switch (evchange->action) {
+ case EVENT_ADD:
+ socket_eventlist_add(evchange->sock, evlist);
+ break;
+ case EVENT_DELETE:
+ socket_eventlist_delete(evchange->sock, evchange->fd,
+ evchange->iEvent, evlist);
+ break;
+ default:
+ break;
+ }
+
+ ISC_LIST_DEQUEUE(evlist->event_updates, evchange, link);
+ HeapFree(hHeapHandle, 0, evchange);
+ manager->event_written--;
+ evchange = ISC_LIST_HEAD(evlist->event_updates);
+ }
+ manager->event_written = 0;
+ 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, sock_event_list *evlist,
+ unsigned int action) {
+
+ event_change_t *evchange;
+
+ evchange = HeapAlloc(hHeapHandle, HEAP_ZERO_MEMORY,
+ sizeof(event_change_t));
+ evchange->sock = sock;
+ evchange->action = action;
+ evchange->iEvent = sock->iEvent;
+ evchange->fd = sock->fd;
+
+ LOCK(&evlist->EventLock);
+ ISC_LIST_APPEND(evlist->event_updates, evchange, link);
+
+ sock->manager->event_written++;
+ UNLOCK(&evlist->EventLock);
+ WSASetEvent(evlist->aEventList[0]); /* Alert the Wait List */
+}
+/*
+ * Note that the socket is already locked before calling this function
+ */
+isc_result_t
+socket_event_add(isc_socket_t *sock, long type) {
+ int stat;
+ WSAEVENT hEvent;
+ sock_event_list *evlist;
+
+ REQUIRE(sock != NULL);
+ evlist = &(sock->manager->sockev_list);
+ hEvent = WSACreateEvent();
+ if (hEvent == WSA_INVALID_EVENT) {
+ stat = WSAGetLastError();
+ return (ISC_R_UNEXPECTED);
+ }
+ if (WSAEventSelect(sock->fd, hEvent, type) != 0) {
+ stat = WSAGetLastError();
+ WSACloseEvent(hEvent);
+ return (ISC_R_UNEXPECTED);
+ }
+ sock->hEvent = hEvent;
+ sock->wait_type = type;
+ notify_eventlist(sock, evlist, EVENT_ADD);
+ return (ISC_R_SUCCESS);
+}
/*
- * The following routines are here to handle Unix emulation until we
- * can rewrite the the routines in Winsock2 style.
+ * Note that the socket is not locked before calling this function
*/
+void
+socket_event_delete(isc_socket_t *sock) {
+ sock_event_list *evlist;
+
+ REQUIRE(sock != NULL);
+ REQUIRE(sock->hEvent != NULL);
+ evlist = &(sock->manager->sockev_list);
+ if (sock->hEvent != NULL) {
+ sock->wait_type = 0;
+ sock->pending_close = 1;
+ notify_eventlist(sock, evlist, EVENT_DELETE);
+ sock->hEvent = NULL;
+ }
+
+}
+/*
+ * Routine to cleanup and then close the socket.
+ * Only close the socket here if it is NOT associated
+ * with an event, otherwise the WSAWaitForMultipleEvents
+ * may fail due to the fact that the the Wait should not
+ * be running while closing an event or a socket.
+ */
+void
+socket_close(isc_socket_t *sock) {
+ sock->pending_close = 1;
+ if (sock->hEvent != NULL)
+ socket_event_delete(sock);
+ else {
+ closesocket(sock->fd);
+ }
+ if (sock->iocp) {
+ sock->iocp = 0;
+ InterlockedDecrement(&iocp_total);
+ }
+
+}
/*
* Initialize socket services
*/
err = WSAStartup(wVersionRequested, &wsaData);
if ( err != 0 ) {
/* Tell the user that we could not find a usable Winsock DLL */
- return (FALSE);
+ NTReportError("named",
+ "Application Requires Winsock 2.0 or later. Exiting");
+ return(FALSE);
}
-
- return (TRUE);
+ return(TRUE);
}
int
-internal_pipe(int filedes[2]) {
- int status;
- unsigned int pipesize = 65535;
- int mode = _O_TEXT;
-
- status = _pipe(filedes, pipesize, mode);
- return (status);
- InterlockedExchange(&bpipe_written, 0);
-}
-
-int
-internal_sendmsg(int sock, const struct msghdr *msg, int flags, int *merror) {
+internal_sendmsg(isc_socket_t *sock, IoCompletionInfo *lpo, int flags,
+ int *Error) {
+ int Result;
DWORD BytesSent;
DWORD Flags = flags;
-
- *merror = WSASendTo((SOCKET) sock,
- msg->msg_iov,
- msg->msg_iovlen,
- &BytesSent,
- Flags,
- msg->msg_name,
- msg->msg_namelen,
- NULL,
- NULL);
+ int total_sent;
+
+ *Error = 0;
+ Result = WSASendTo((SOCKET) sock->fd,
+ sock->messagehdr->msg_iov,
+ sock->messagehdr->msg_iovlen,
+ &BytesSent,
+ Flags,
+ sock->messagehdr->msg_name,
+ sock->messagehdr->msg_namelen,
+ (LPOVERLAPPED) lpo,
+ NULL);
+
+ total_sent = (int) BytesSent;
- if (*merror == SOCKET_ERROR) {
- BytesSent = -1;
- /* There is an error... */
- *merror = WSAGetLastError();
- if (*merror == WSA_IO_PENDING) {
- /* Overlapped send successfully initiated. */
- errno = EAGAIN;
- } else {
- /* An unexpected error occurred. */
- errno = *merror;
- }
- }
+ /* Check for errors.*/
+ if (Result == SOCKET_ERROR) {
+
+ *Error = WSAGetLastError();
+
+ switch (*Error) {
- /* No error -- the I/O request was completed immediately... */
- return (BytesSent);
+ case NO_ERROR :
+ case WSA_IO_INCOMPLETE :
+ case WSA_WAIT_IO_COMPLETION :
+ case WSA_IO_PENDING :
+ break ;
+
+ default :
+ return (-1);
+ break;
+ }
+ }
+ if(lpo != NULL)
+ return (0);
+ else
+ return (total_sent);
}
int
-internal_recvmsg(int sock, struct msghdr *msg, int flags, int *merror) {
- DWORD Flags = flags;
- DWORD NumBytes;
+internal_recvmsg(isc_socket_t *sock, IoCompletionInfo *lpo, int flags,
+ int *Error) {
+ DWORD Flags = 0;
+ DWORD NumBytes = 0;
+ int total_bytes = 0;
int Result;
- Result = WSARecvFrom((SOCKET) sock,
- msg->msg_iov,
- msg->msg_iovlen,
- &NumBytes,
- &Flags,
- msg->msg_name,
- (int *)&(msg->msg_namelen),
- NULL,
- NULL);
+ *Error = 0;
+ Result = WSARecvFrom((SOCKET) sock->fd,
+ sock->messagehdr->msg_iov,
+ sock->messagehdr->msg_iovlen,
+ &NumBytes,
+ &Flags,
+ sock->messagehdr->msg_name,
+ (int *)&(sock->messagehdr->msg_namelen),
+ (LPOVERLAPPED) lpo,
+ NULL);
+ total_bytes = (int) NumBytes;
/* Check for errors. */
if (Result == SOCKET_ERROR) {
- *merror = WSAGetLastError();
- NumBytes = -1;
+
+ *Error = WSAGetLastError();
- switch (*merror) {
- case WSAEWOULDBLOCK:
- /*
- * No data received; return to wait for another
- * read event.
- */
- errno = EAGAIN;
- break;
+ switch (*Error) {
- default:
- /* Some other error... hit the panic button. */
- errno = *merror;
- break;
- }
+ case NO_ERROR :
+ case WSA_IO_INCOMPLETE :
+ case WSA_WAIT_IO_COMPLETION :
+ case WSA_IO_PENDING :
+ break ;
+
+ default :
+ return (-1);
+ break;
+ }
}
- msg->msg_flags = Flags; /* Return the flags received in header */
-
- return (NumBytes);
-}
+ /* Return the flags received in header */
+ sock->messagehdr->msg_flags = Flags;
+ 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, ...)
-{
+ const char *fmt, ...) {
char msgbuf[2048];
va_list ap;
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;
isc_log_iwrite(isc_lctx, category, module, level,
msgcat, msgset, message,
"socket %p: %s", sock, msgbuf);
- } else {
- isc_sockaddr_format(address, peerbuf, sizeof(peerbuf));
- isc_log_iwrite(isc_lctx, category, module, level,
- msgcat, msgset, message,
- "socket %p %s: %s", sock, peerbuf, msgbuf);
- }
-}
-
-static void
-wakeup_socket(isc_socketmgr_t *manager, int fd, int msg) {
- isc_socket_t *sock;
-
- /*
- * This is a wakeup on a socket. If the socket is not in the
- * process of being closed, start watching it for either reads
- * or writes.
- */
-
- INSIST(fd >= 0 && fd < FD_SETSIZE);
-
- if (manager->fdstate[fd] == CLOSE_PENDING) {
- manager->fdstate[fd] = CLOSED;
- FD_CLR(fd, &manager->read_fds);
- FD_CLR(fd, &manager->write_fds);
- FD_CLR(fd, &manager->except_fds);
- closesocket(fd);
- return;
- }
- if (manager->fdstate[fd] != MANAGED)
- return;
-
- sock = manager->fds[fd];
-
- /*
- * If there are no events, or there is an event but we
- * have already queued up the internal event on a task's
- * queue, clear the bit. Otherwise, set it.
- */
- if (msg == SELECT_POKE_READ)
- FD_SET(sock->fd, &manager->read_fds);
- if (msg == SELECT_POKE_WRITE)
- FD_SET(sock->fd, &manager->write_fds);
- if (msg == SELECT_POKE_CONNECT) { /* Need both here */
- FD_SET(sock->fd, &manager->write_fds);
- FD_SET(sock->fd, &manager->except_fds);
- }
-}
-
-/*
- * Poke the select loop when there is something for us to do.
- * The write is required (by POSIX) to complete. That is, we
- * will not get partial writes.
- */
-static void
-select_poke(isc_socketmgr_t *mgr, int fd, int msg) {
- int cc;
- int buf[2];
- char strbuf[ISC_STRERRORSIZE];
-
- buf[0] = fd;
- buf[1] = msg;
-
- if (msg == SELECT_POKE_SHUTDOWN) {
- do {
- cc = _write(mgr->pipe_fds[1], buf, sizeof(buf));
- } while (cc < 0 && SOFT_ERROR(errno));
-
- if (cc < 0) {
- isc__strerror(errno, strbuf, sizeof(strbuf));
- FATAL_ERROR(__FILE__, __LINE__,
- isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKET,
- ISC_MSG_WRITEFAILED,
- "write() failed "
- "during watcher poke: %s"),
- strbuf);
- }
-
- INSIST(cc == sizeof(buf));
-
- InterlockedIncrement(&bpipe_written);
- } else {
- wakeup_socket(mgr, fd, msg);
- }
-}
-
-/*
- * Read a message on the internal fd.
- */
-static void
-select_readmsg(isc_socketmgr_t *mgr, int *fd, int *msg) {
- int buf[2];
- int cc;
- char strbuf[ISC_STRERRORSIZE];
-
- cc = _read(mgr->pipe_fds[0], buf, sizeof(buf));
- if (cc < 0) {
- *msg = SELECT_POKE_NOTHING;
- if (SOFT_ERROR(errno))
- return;
-
- isc__strerror(errno, strbuf, sizeof(strbuf));
- FATAL_ERROR(__FILE__, __LINE__,
- isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKET,
- ISC_MSG_READFAILED,
- "read() failed "
- "during watcher poke: %s"),
- strbuf);
-
- return;
+ } else {
+ isc_sockaddr_format(address, peerbuf, sizeof peerbuf);
+ isc_log_iwrite(isc_lctx, category, module, level,
+ msgcat, msgset, message,
+ "socket %p %s: %s", sock, peerbuf, msgbuf);
}
- INSIST(cc == sizeof(buf));
- *fd = buf[0];
- *msg = buf[1];
-
}
+
/*
- * Make a fd non-blocking.
+ * Make an fd SOCKET non-blocking.
*/
static isc_result_t
-make_nonblock(int fd) {
+make_nonblock(SOCKET fd) {
int ret;
unsigned long flags = 1;
char strbuf[ISC_STRERRORSIZE];
/* Set the socket to non-blocking */
- ret = ioctlsocket((SOCKET) fd, FIONBIO, &flags);
+ ret = ioctlsocket(fd, FIONBIO, &flags);
if (ret == -1) {
- isc__strerror(WSAGetLastError(), strbuf, sizeof(strbuf));
+ isc__strerror(errno, strbuf, sizeof(strbuf));
UNEXPECTED_ERROR(__FILE__, __LINE__,
"ioctlsocket(%d, FIOBIO, %d): %s",
fd, flags, strbuf);
return (ISC_R_SUCCESS);
}
-
/*
- * Process control messages received on a socket.
+ * Windows 2000 systems incorrectly cause UDP sockets using WASRecvFrom
+ * to not work correctly, returning a WSACONNRESET error when a WSASendTo
+ * fails with an "ICMP port unreachable" response and preventing the
+ * socket from using the WSARecvFrom in subsequent operations.
+ * The function below fixes this, but requires that Windows 2000
+ * Service Pack 2 or later be installed on the system. NT 4.0
+ * systems are not affected by this and work correctly.
+ * See Microsoft Knowledge Base Article Q263823 for details of this.
*/
-static void
-process_cmsg(isc_socket_t *sock, struct msghdr *msg, isc_socketevent_t *dev) {
-#ifdef USE_CMSG
- struct cmsghdr *cmsgp;
-#ifdef ISC_PLATFORM_HAVEIPV6
- struct in6_pktinfo *pktinfop;
-#endif
-#ifdef SO_TIMESTAMP
- struct timeval *timevalp;
-#endif
-#endif
-
- /*
- * sock is used only when ISC_NET_BSD44MSGHDR and USE_CMSG are defined.
- * msg and dev are used only when ISC_NET_BSD44MSGHDR is defined.
- * They are all here, outside of the CPP tests, because it is
- * more consistent with the usual ISC coding style.
- */
- UNUSED(sock);
- UNUSED(msg);
- UNUSED(dev);
-
-#ifndef ISC_NET_BSD44MSGHDR
- return;
-
-#else /* defined ISC_NET_BSD44MSGHDR */
-
-#ifdef MSG_TRUNC
- if ((msg->msg_flags & MSG_TRUNC) == MSG_TRUNC)
- dev->attributes |= ISC_SOCKEVENTATTR_TRUNC;
-#endif
-
-#ifdef MSG_CTRUNC
- if ((msg->msg_flags & MSG_CTRUNC) == MSG_CTRUNC)
- dev->attributes |= ISC_SOCKEVENTATTR_CTRUNC;
-#endif
-
-#ifndef USE_CMSG
- return;
-#else
- if (msg->msg_controllen == 0 || msg->msg_control == NULL)
- return;
-
-#ifdef SO_TIMESTAMP
- timevalp = NULL;
-#endif
-#ifdef ISC_PLATFORM_HAVEIPV6
- pktinfop = NULL;
-#endif
-
- cmsgp = CMSG_FIRSTHDR(msg);
- while (cmsgp != NULL) {
- socket_log(sock, NULL, TRACE,
- isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_PROCESSCMSG,
- "processing cmsg %p", cmsgp);
-
-#ifdef ISC_PLATFORM_HAVEIPV6
- if (cmsgp->cmsg_level == IPPROTO_IPV6
- && cmsgp->cmsg_type == IPV6_PKTINFO) {
-
- pktinfop = (struct in6_pktinfo *)CMSG_DATA(cmsgp);
- memcpy(&dev->pktinfo, pktinfop,
- sizeof(struct in6_pktinfo));
- dev->attributes |= ISC_SOCKEVENTATTR_PKTINFO;
- socket_log(sock, NULL, TRACE,
- isc_msgcat, ISC_MSGSET_SOCKET,
- ISC_MSG_IFRECEIVED,
- "interface received on ifindex %u",
- dev->pktinfo.ipi6_ifindex);
- if (IN6_IS_ADDR_MULTICAST(&pktinfop->ipi6_addr))
- dev->attributes |= ISC_SOCKEVENTATTR_MULTICAST;
- goto next;
- }
-#endif
-
-#ifdef SO_TIMESTAMP
- if (cmsgp->cmsg_level == SOL_SOCKET
- && cmsgp->cmsg_type == SCM_TIMESTAMP) {
- timevalp = (struct timeval *)CMSG_DATA(cmsgp);
- dev->timestamp.seconds = timevalp->tv_sec;
- dev->timestamp.nanoseconds = timevalp->tv_usec * 1000;
- dev->attributes |= ISC_SOCKEVENTATTR_TIMESTAMP;
- goto next;
- }
-#endif
-
- next:
- cmsgp = CMSG_NXTHDR(msg, cmsgp);
- }
-#endif /* USE_CMSG */
-
-#endif /* ISC_NET_BSD44MSGHDR */
-
+isc_result_t
+connection_reset_fix(SOCKET fd) {
+ DWORD dwBytesReturned = 0;
+ BOOL bNewBehavior = FALSE;
+ DWORD status;
+
+ if(isc_win32os_majorversion() < 5)
+ return (ISC_R_SUCCESS); /* NT 4.0 has no problem */
+
+ /* disable new behavior using IOCTL: SIO_UDP_CONNRESET */
+ status = WSAIoctl(fd, SIO_UDP_CONNRESET, &bNewBehavior,
+ sizeof(bNewBehavior), NULL, 0,
+ &dwBytesReturned, NULL, NULL);
+ if (status != SOCKET_ERROR)
+ return (ISC_R_SUCCESS);
+ else
+ return (ISC_R_UNEXPECTED);
}
/*
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;
size_t write_count;
size_t skip_count;
-#ifndef USE_CMSG
- UNUSED(cmsg);
-#endif
-
memset(msg, 0, sizeof (*msg));
if (sock->type == isc_sockettype_udp) {
if (used.length > 0) {
iov[iovcount].buf = (void *)(used.base
- + skip_count);
+ + skip_count);
iov[iovcount].len = used.length - skip_count;
write_count += (used.length - skip_count);
skip_count = 0;
msg->msg_iov = iov;
msg->msg_iovlen = iovcount;
-#ifdef ISC_NET_BSD44MSGHDR
- msg->msg_control = NULL;
- msg->msg_controllen = 0;
- msg->msg_flags = 0;
-#if defined(USE_CMSG) && defined(ISC_PLATFORM_HAVEIPV6)
- if ((sock->type == isc_sockettype_udp)
- && ((dev->attributes & ISC_SOCKEVENTATTR_PKTINFO) != 0)) {
- struct cmsghdr *cmsgp;
- struct in6_pktinfo *pktinfop;
-
- socket_log(sock, NULL, TRACE,
- isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_SENDTODATA,
- "sendto pktinfo data, ifindex %u",
- dev->pktinfo.ipi6_ifindex);
-
- msg->msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo));
- msg->msg_control = (void *)cmsg;
-
- cmsgp = (struct cmsghdr *)cmsg;
- cmsgp->cmsg_level = IPPROTO_IPV6;
- cmsgp->cmsg_type = IPV6_PKTINFO;
- cmsgp->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
- pktinfop = (struct in6_pktinfo *)CMSG_DATA(cmsgp);
- memcpy(pktinfop, &dev->pktinfo, sizeof(struct in6_pktinfo));
- }
-#endif /* USE_CMSG && ISC_PLATFORM_HAVEIPV6 */
-#endif /* ISC_NET_BSD44MSGHDR */
-
if (write_countp != NULL)
*write_countp = write_count;
}
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;
size_t read_count;
-#ifndef USE_CMSG
- UNUSED(cmsg);
-#endif
-
memset(msg, 0, sizeof (struct msghdr));
if (sock->type == isc_sockettype_udp) {
memset(&dev->address, 0, sizeof(dev->address));
msg->msg_name = (void *)&dev->address.type.sa;
msg->msg_namelen = sizeof(dev->address.type);
-#ifdef ISC_NET_RECVOVERFLOW
- /* If needed, steal one iovec for overflow detection. */
- maxiov--;
-#endif
} else { /* TCP */
msg->msg_name = NULL;
msg->msg_namelen = 0;
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)
* we know there is at least one iov left, since we stole it
* at the top of this function.
*/
-#ifdef ISC_NET_RECVOVERFLOW
- if (sock->type == isc_sockettype_udp) {
- iov[iovcount].iov_base = (void *)(&sock->overflow);
- iov[iovcount].iov_len = 1;
- iovcount++;
- }
-#endif
msg->msg_iov = iov;
msg->msg_iovlen = iovcount;
-#ifdef ISC_NET_BSD44MSGHDR
- msg->msg_control = NULL;
- msg->msg_controllen = 0;
- msg->msg_flags = 0;
-#if defined(USE_CMSG)
- if (sock->type == isc_sockettype_udp) {
- msg->msg_control = cmsg;
- msg->msg_controllen = CMSG_BUF_SIZE;
- }
-#endif /* USE_CMSG */
-#endif /* ISC_NET_BSD44MSGHDR */
-
if (read_countp != NULL)
*read_countp = read_count;
}
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;
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,
dump_msg(struct msghdr *msg, isc_socket_t *sock) {
unsigned int i;
- printf("MSGHDR %p, Socket #: %d\n", msg, sock->fd);
+ printf("MSGHDR %p, Socket #: %u\n", msg, sock->fd);
printf("\tname %p, namelen %d\n", msg->msg_name, msg->msg_namelen);
printf("\tiov %p, iovlen %d\n", msg->msg_iov, msg->msg_iovlen);
for (i = 0 ; i < (unsigned int)msg->msg_iovlen ; i++)
printf("\t\t%d\tbase %p, len %d\n", i,
msg->msg_iov[i].buf,
msg->msg_iov[i].len);
-#ifdef ISC_NET_BSD44MSGHDR
- printf("\tcontrol %p, controllen %d\n", msg->msg_control,
- msg->msg_controllen);
-#endif
}
#endif
#define DOIO_EOF 3 /* EOF, no event sent */
static int
-doio_recv(isc_socket_t *sock, isc_socketevent_t *dev) {
- int cc;
- WSABUF iov[MAXSCATTERGATHER_RECV];
- size_t read_count;
+completeio_recv(isc_socket_t *sock, isc_socketevent_t *dev, int cc,
+ int recv_errno) {
size_t actual_count;
- struct msghdr msghdr;
isc_buffer_t *buffer;
- int recv_errno = 0;
-#if USE_CMSG
- char cmsg[CMSG_BUF_SIZE];
-#else
- char *cmsg = NULL;
-#endif
- char strbuf[ISC_STRERRORSIZE];
-
- build_msghdr_recv(sock, dev, &msghdr, cmsg, iov, &read_count);
-
-#if defined(ISC_SOCKET_DEBUG)
- dump_msg(&msghdr,sock);
-#endif
-
- cc = internal_recvmsg(sock->fd, &msghdr, 0, &recv_errno);
-
- if (cc < 0) {
- if (SOFT_ERROR(recv_errno))
- return (DOIO_SOFT);
-
- if (isc_log_wouldlog(isc_lctx, IOEVENT_LEVEL)) {
- isc__strerror(recv_errno, strbuf, sizeof(strbuf));
- socket_log(sock, NULL, IOEVENT,
- isc_msgcat, ISC_MSGSET_SOCKET,
- ISC_MSG_DOIORECV,
- "doio_recv: recvmsg(%d) %d bytes, err %d/%s",
- sock->fd, cc, recv_errno, strbuf);
- }
#define SOFT_OR_HARD(_system, _isc) \
if (recv_errno == _system) { \
} \
return (DOIO_SOFT); \
}
+
#define ALWAYS_HARD(_system, _isc) \
if (recv_errno == _system) { \
dev->result = _isc; \
return (DOIO_HARD); \
}
+ if (recv_errno != 0) {
+
+ if (SOFT_ERROR(recv_errno))
+ return (DOIO_SOFT);
+
SOFT_OR_HARD(WSAECONNREFUSED, ISC_R_CONNREFUSED);
SOFT_OR_HARD(WSAENETUNREACH, ISC_R_NETUNREACH);
SOFT_OR_HARD(WSAEHOSTUNREACH, ISC_R_HOSTUNREACH);
SOFT_OR_HARD(WSAECONNRESET, ISC_R_CONNECTIONRESET);
SOFT_OR_HARD(WSAENETRESET, ISC_R_CONNECTIONRESET);
+ SOFT_OR_HARD(WSAECONNABORTED, ISC_R_CONNECTIONRESET);
SOFT_OR_HARD(WSAEDISCON, ISC_R_CONNECTIONRESET);
SOFT_OR_HARD(WSAENETDOWN, ISC_R_NETDOWN);
+ ALWAYS_HARD(ERROR_OPERATION_ABORTED, ISC_R_CONNECTIONRESET);
+ ALWAYS_HARD(ERROR_PORT_UNREACHABLE, ISC_R_HOSTUNREACH);
+ ALWAYS_HARD(ERROR_HOST_UNREACHABLE, ISC_R_HOSTUNREACH);
+ ALWAYS_HARD(ERROR_NETWORK_UNREACHABLE, ISC_R_NETUNREACH);
ALWAYS_HARD(WSAENOBUFS, ISC_R_NORESOURCES);
#undef SOFT_OR_HARD
return (DOIO_EOF);
if (sock->type == isc_sockettype_udp) {
- dev->address.length = msghdr.msg_namelen;
+ dev->address.length = sock->messagehdr->msg_namelen;
if (isc_sockaddr_getport(&dev->address) == 0) {
if (isc_log_wouldlog(isc_lctx, IOEVENT_LEVEL)) {
socket_log(sock, &dev->address, IOEVENT,
}
#endif
- /*
- * If there are control messages attached, run through them and pull
- * out the interesting bits.
- */
- if (sock->type == isc_sockettype_udp)
- process_cmsg(sock, &msghdr, dev);
-
/*
* update the buffers (if any) and the i/o count
*/
* If we read less than we expected, update counters,
* and let the upper layer poke the descriptor.
*/
- if (((size_t)cc != read_count) && (dev->n < dev->minimum))
+ if (((size_t)cc != sock->totalBytes) && (dev->n < dev->minimum))
return (DOIO_SOFT);
/*
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) {
+ char *cmsg = NULL;
+ char strbuf[ISC_STRERRORSIZE];
+ IoCompletionInfo *lpo;
+ int status;
+
+ if (!bwait) {
+ lpo = (IoCompletionInfo *) HeapAlloc(hHeapHandle,
+ HEAP_ZERO_MEMORY, sizeof(IoCompletionInfo));
+ lpo->request_type = SOCKET_RECV;
+ lpo->dev = dev;
+ } else { /* Wait for recv to complete */
+ lpo = NULL;
+ }
+ sock->references++;
+
+ build_msghdr_recv(sock, dev, sock->messagehdr, cmsg, sock->iov,
+ &(sock->totalBytes));
+#if defined(ISC_SOCKET_DEBUG)
+ dump_msg(sock->messagehdr, sock);
+#endif
+
+ *nbytes = internal_recvmsg(sock, lpo, 0, recv_errno);
+
+ if (*nbytes < 0) {
+ if (SOFT_ERROR(*recv_errno))
+ return (DOIO_SOFT);
+
+ if (isc_log_wouldlog(isc_lctx, IOEVENT_LEVEL)) {
+ isc__strerror(*recv_errno, strbuf, sizeof(strbuf));
+ socket_log(sock, NULL, IOEVENT,
+ isc_msgcat, ISC_MSGSET_SOCKET,
+ ISC_MSG_DOIORECV,
+ "startio_recv: recvmsg(%d) %d bytes, err %d/%s",
+ sock->fd, *nbytes, *recv_errno, strbuf);
+ }
+ status = completeio_recv(sock, dev, *nbytes, *recv_errno);
+ if(status != DOIO_SOFT) {
+ sock->references--;
+ }
+ return (status);
+ }
+ dev->result = ISC_R_SUCCESS;
+ return(DOIO_SOFT);
+}
/*
* Returns:
* DOIO_SUCCESS The operation succeeded. dev->result contains
* No other return values are possible.
*/
static int
-doio_send(isc_socket_t *sock, isc_socketevent_t *dev) {
- int cc;
- WSABUF iov[MAXSCATTERGATHER_SEND];
- size_t write_count;
- struct msghdr msghdr;
+completeio_send(isc_socket_t *sock, isc_socketevent_t *dev, int cc,
+ int send_errno) {
char addrbuf[ISC_SOCKADDR_FORMATSIZE];
-#if USE_CMSG
- char cmsg[CMSG_BUF_SIZE];
-#else
- char *cmsg = NULL;
-#endif
- int attempts = 0;
- int send_errno = 0;
char strbuf[ISC_STRERRORSIZE];
- build_msghdr_send(sock, dev, &msghdr, cmsg, iov, &write_count);
-
-resend:
- cc = internal_sendmsg(sock->fd, &msghdr, 0, &send_errno);
-
- /*
- * Check for error or block condition.
- */
- if (cc < 0) {
- if (send_errno == WSAEINTR && ++attempts < NRETRIES)
- goto resend;
+ if(send_errno != 0) {
if (SOFT_ERROR(send_errno))
return (DOIO_SOFT);
SOFT_OR_HARD(WSAECONNREFUSED, ISC_R_CONNREFUSED);
SOFT_OR_HARD(WSAENOTCONN, ISC_R_CONNREFUSED);
SOFT_OR_HARD(WSAECONNRESET, ISC_R_CONNECTIONRESET);
+ SOFT_OR_HARD(WSAECONNABORTED, ISC_R_CONNECTIONRESET);
SOFT_OR_HARD(WSAENETRESET, ISC_R_CONNECTIONRESET);
SOFT_OR_HARD(WSAEDISCON, ISC_R_CONNECTIONRESET);
SOFT_OR_HARD(WSAENETDOWN, ISC_R_NETDOWN);
+ ALWAYS_HARD(ERROR_OPERATION_ABORTED, ISC_R_CONNECTIONRESET);
+ ALWAYS_HARD(ERROR_PORT_UNREACHABLE, ISC_R_HOSTUNREACH);
+ ALWAYS_HARD(ERROR_HOST_UNREACHABLE, ISC_R_HOSTUNREACH);
+ ALWAYS_HARD(ERROR_NETWORK_UNREACHABLE, ISC_R_NETUNREACH);
ALWAYS_HARD(WSAEADDRNOTAVAIL, ISC_R_ADDRNOTAVAIL);
ALWAYS_HARD(WSAEHOSTUNREACH, ISC_R_HOSTUNREACH);
ALWAYS_HARD(WSAEHOSTDOWN, ISC_R_HOSTUNREACH);
*/
isc_sockaddr_format(&dev->address, addrbuf, sizeof(addrbuf));
isc__strerror(send_errno, strbuf, sizeof(strbuf));
- UNEXPECTED_ERROR(__FILE__, __LINE__, "internal_send: %s: %s",
+ UNEXPECTED_ERROR(__FILE__, __LINE__, "completeio_send: %s: %s",
addrbuf, strbuf);
dev->result = isc__errno2result(send_errno);
- return (DOIO_HARD);
+ return (DOIO_HARD);
}
- if (cc == 0)
- UNEXPECTED_ERROR(__FILE__, __LINE__,
- "internal_send: send() %s 0",
- isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
- ISC_MSG_RETURNED, "returned"));
-
/*
* If we write less than we expected, update counters, poke.
*/
dev->n += cc;
- if ((size_t)cc != write_count)
+ if ((size_t)cc != sock->totalBytes)
return (DOIO_SOFT);
/*
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) {
+ char *cmsg = NULL;
+ char strbuf[ISC_STRERRORSIZE];
+ IoCompletionInfo *lpo;
+ int status;
+
+ if (!bwait) {
+ lpo = (IoCompletionInfo *) HeapAlloc(hHeapHandle,
+ HEAP_ZERO_MEMORY, sizeof(IoCompletionInfo));
+ lpo->request_type = SOCKET_SEND;
+ lpo->dev = dev;
+ } else { /* Wait for send to complete */
+ lpo = NULL;
+ }
+ sock->references++;
+
+ build_msghdr_send(sock, dev, sock->messagehdr, cmsg, sock->iov,
+ &(sock->totalBytes));
+
+ *nbytes = internal_sendmsg(sock, lpo, 0, send_errno);
+
+ if (*nbytes < 0) {
+ if (SOFT_ERROR(*send_errno))
+ return (DOIO_SOFT);
+ if (isc_log_wouldlog(isc_lctx, IOEVENT_LEVEL)) {
+ isc__strerror(*send_errno, strbuf, sizeof(strbuf));
+ socket_log(sock, NULL, IOEVENT,
+ isc_msgcat, ISC_MSGSET_SOCKET,
+ ISC_MSG_INTERNALSEND,
+ "startio_send: internal_sendmsg(%d) %d bytes, err %d/%s",
+ sock->fd, *nbytes, *send_errno, strbuf);
+ }
+ status = completeio_send(sock, dev, *nbytes, *send_errno);
+ if(status != DOIO_SOFT) {
+ sock->references--;
+ }
+ return (status);
+ }
+ dev->result = ISC_R_SUCCESS;
+ return(DOIO_SOFT);
+}
/*
* Kill.
*
* references exist.
*/
static void
-destroy(isc_socket_t **sockp) {
+destroy_socket(isc_socket_t **sockp) {
isc_socket_t *sock = *sockp;
isc_socketmgr_t *manager = sock->manager;
socket_log(sock, NULL, CREATION, isc_msgcat, ISC_MSGSET_SOCKET,
- ISC_MSG_DESTROYING, "destroying");
+ ISC_MSG_DESTROYING, "destroying socket %d", sock->fd);
INSIST(ISC_LIST_EMPTY(sock->accept_list));
INSIST(ISC_LIST_EMPTY(sock->recv_list));
INSIST(ISC_LIST_EMPTY(sock->send_list));
INSIST(sock->connect_ev == NULL);
- REQUIRE(sock->fd >= 0 && sock->fd < FD_SETSIZE);
+ REQUIRE(sock->fd >= 0);
LOCK(&manager->lock);
/*
- * No one has this socket open, so the watcher doesn't have to be
- * poked, and the socket doesn't have to be locked.
+ * 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.
*/
- manager->fds[sock->fd] = NULL;
- manager->fdstate[sock->fd] = CLOSE_PENDING;
- select_poke(manager, sock->fd, SELECT_POKE_CLOSE);
+ socket_close(sock);
+
ISC_LIST_UNLINK(manager->socklist, sock, link);
-#ifdef ISC_PLATFORM_USETHREADS
if (ISC_LIST_EMPTY(manager->socklist))
SIGNAL(&manager->shutdown_ok);
-#endif /* ISC_PLATFORM_USETHREADS */
/*
* XXX should reset manager->maxfd here
static isc_result_t
allocate_socket(isc_socketmgr_t *manager, isc_sockettype_t type,
- isc_socket_t **socketp)
-{
+ isc_socket_t **socketp) {
isc_socket_t *sock;
isc_result_t ret;
- sock = isc_mem_get(manager->mctx, sizeof(*sock));
+ sock = isc_mem_get(manager->mctx, sizeof *sock);
if (sock == NULL)
return (ISC_R_NOMEMORY);
sock->manager = manager;
sock->type = type;
- sock->fd = -1;
+ sock->fd = INVALID_SOCKET;
ISC_LINK_INIT(sock, link);
+ sock->messagehdr = isc_mem_get(manager->mctx, sizeof(struct msghdr));
+ memset(sock->messagehdr, 0, sizeof(struct msghdr));
+
/*
* set up list of readers and writers to be initially empty
*/
ISC_LIST_INIT(sock->send_list);
ISC_LIST_INIT(sock->accept_list);
sock->connect_ev = NULL;
- sock->pending_recv = 0;
- sock->pending_send = 0;
sock->pending_accept = 0;
+ sock->pending_close = 0;
+ sock->iocp = 0;
sock->listener = 0;
sock->connected = 0;
sock->connecting = 0;
sock->bound = 0;
+ sock->iEvent = 0;
+ sock->hEvent = NULL;
+ sock->wait_type = 0;
/*
* initialize the lock
return (ret);
}
-
/*
* This event requires that the various lists be empty, that the reference
* count be 1, and that the magic number is valid. The other socket bits,
* like the lock, must be initialized as well. The fd associated must be
- * marked as closed, by setting it to -1 on close, or this routine will
- * also close the socket.
+ * marked as closed, by setting it to INVALID_SOCKET on close, or this
+ * routine will also close the socket.
*/
static void
free_socket(isc_socket_t **socketp) {
INSIST(sock->references == 0);
INSIST(VALID_SOCKET(sock));
INSIST(!sock->connecting);
- INSIST(!sock->pending_recv);
- INSIST(!sock->pending_send);
INSIST(!sock->pending_accept);
INSIST(ISC_LIST_EMPTY(sock->recv_list));
INSIST(ISC_LIST_EMPTY(sock->send_list));
sock->magic = 0;
+ isc_mem_put(sock->manager->mctx, sock->messagehdr, sizeof(struct msghdr));
+
DESTROYLOCK(&sock->lock);
isc_mem_put(sock->manager->mctx, sock, sizeof(*sock));
#if defined(USE_CMSG) || defined(SO_BSDCOMPAT)
int on = 1;
#endif
- int socket_errno = 0;
+ int socket_errno;
char strbuf[ISC_STRERRORSIZE];
REQUIRE(VALID_MANAGER(manager));
switch (type) {
case isc_sockettype_udp:
sock->fd = socket(pf, SOCK_DGRAM, IPPROTO_UDP);
+ if (connection_reset_fix(sock->fd) != ISC_R_SUCCESS) {
+ free_socket(&sock);
+ return (ISC_R_UNEXPECTED);
+ }
break;
case isc_sockettype_tcp:
sock->fd = socket(pf, SOCK_STREAM, IPPROTO_TCP);
break;
}
-
- if (sock->fd >= FD_SETSIZE) {
- (void)closesocket(sock->fd);
- isc_log_iwrite(isc_lctx, ISC_LOGCATEGORY_GENERAL,
- ISC_LOGMODULE_SOCKET, ISC_LOG_ERROR,
- isc_msgcat, ISC_MSGSET_SOCKET,
- ISC_MSG_TOOMANYFDS,
- "%s: too many open file descriptors", "socket");
- free_socket(&sock);
- return (ISC_R_NORESOURCES);
- }
- if (sock->fd < 0) {
+ if (sock->fd == INVALID_SOCKET) {
socket_errno = WSAGetLastError();
free_socket(&sock);
return (ISC_R_UNEXPECTED);
}
-#ifdef SO_BSDCOMPAT
- if (setsockopt(sock->fd, SOL_SOCKET, SO_BSDCOMPAT,
- (void *)&on, sizeof(on)) < 0) {
- socket_errno = WSAGetLastError();
- isc__strerror(socket_errno, strbuf, sizeof(strbuf));
- UNEXPECTED_ERROR(__FILE__, __LINE__,
- "setsockopt(%d, SO_BSDCOMPAT) %s: %s",
- sock->fd,
- isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
- ISC_MSG_FAILED, "failed"),
- strbuf);
- /* Press on... */
- }
-#endif
#if defined(USE_CMSG)
if (type == isc_sockettype_udp) {
-#if defined(SO_TIMESTAMP)
- if (setsockopt(sock->fd, SOL_SOCKET, SO_TIMESTAMP,
- (void *)&on, sizeof(on)) < 0
- && WSAGetLastError() != WSAENOPROTOOPT) {
- isc__strerror(WSAGetLastError(), strbuf, sizeof(strbuf));
- UNEXPECTED_ERROR(__FILE__, __LINE__,
- "setsockopt(%d, SO_TIMESTAMP) %s: %s",
- sock->fd,
- isc_msgcat_get(isc_msgcat,
- ISC_MSGSET_GENERAL,
- ISC_MSG_FAILED,
- "failed"),
- strbuf);
- /* Press on... */
- }
-#endif /* SO_TIMESTAMP */
-
#if defined(ISC_PLATFORM_HAVEIPV6)
#ifdef IPV6_RECVPKTINFO
/* 2292bis */
* there are no external references to it yet.
*/
- manager->fds[sock->fd] = sock;
- manager->fdstate[sock->fd] = MANAGED;
ISC_LIST_APPEND(manager->socklist, sock, link);
- if (manager->maxfd < sock->fd)
- manager->maxfd = sock->fd;
- manager->minfd = min(manager->minfd, sock->fd);
-
UNLOCK(&manager->lock);
socket_log(sock, NULL, CREATION, isc_msgcat, ISC_MSGSET_SOCKET,
* Attach to a socket. Caller must explicitly detach when it is done.
*/
void
-isc_socket_attach(isc_socket_t *sock, isc_socket_t **socketp) {
- REQUIRE(VALID_SOCKET(sock));
- REQUIRE(socketp != NULL && *socketp == NULL);
-
- LOCK(&sock->lock);
- sock->references++;
- UNLOCK(&sock->lock);
-
- *socketp = sock;
-}
-
-/*
- * Dereference a socket. If this is the last reference to it, clean things
- * up by destroying the socket.
- */
-void
-isc_socket_detach(isc_socket_t **socketp) {
- isc_socket_t *sock;
- isc_boolean_t kill_socket = ISC_FALSE;
-
- REQUIRE(socketp != NULL);
- sock = *socketp;
- REQUIRE(VALID_SOCKET(sock));
-
- LOCK(&sock->lock);
- REQUIRE(sock->references > 0);
- sock->references--;
- if (sock->references == 0)
- kill_socket = ISC_TRUE;
- UNLOCK(&sock->lock);
-
- if (kill_socket)
- destroy(&sock);
-
- *socketp = NULL;
-}
-
-/*
- * I/O is possible on a given socket. Schedule an event to this task that
- * will call an internal function to do the I/O. This will charge the
- * task with the I/O operation and let our select loop handler get back
- * to doing something real as fast as possible.
- *
- * The socket and manager must be locked before calling this function.
- */
-static void
-dispatch_recv(isc_socket_t *sock) {
- intev_t *iev;
- isc_socketevent_t *ev;
-
- INSIST(!sock->pending_recv);
-
- ev = ISC_LIST_HEAD(sock->recv_list);
- if (ev == NULL)
- return;
-
- sock->pending_recv = 1;
- iev = &sock->readable_ev;
-
- socket_log(sock, NULL, EVENT, NULL, 0, 0,
- "dispatch_recv: event %p -> task %p", ev, ev->ev_sender);
-
- sock->references++;
- iev->ev_sender = sock;
- iev->ev_action = internal_recv;
- iev->ev_arg = sock;
-
- isc_task_send(ev->ev_sender, (isc_event_t **)&iev);
-}
-
-static void
-dispatch_send(isc_socket_t *sock) {
- intev_t *iev;
- isc_socketevent_t *ev;
-
- INSIST(!sock->pending_send);
-
- ev = ISC_LIST_HEAD(sock->send_list);
- if (ev == NULL)
- return;
-
- sock->pending_send = 1;
- iev = &sock->writable_ev;
-
- socket_log(sock, NULL, EVENT, NULL, 0, 0,
- "dispatch_send: event %p -> task %p", ev, ev->ev_sender);
+isc_socket_attach(isc_socket_t *sock, isc_socket_t **socketp) {
+ REQUIRE(VALID_SOCKET(sock));
+ REQUIRE(socketp != NULL && *socketp == NULL);
+ LOCK(&sock->lock);
sock->references++;
- iev->ev_sender = sock;
- iev->ev_action = internal_send;
- iev->ev_arg = sock;
+ UNLOCK(&sock->lock);
- isc_task_send(ev->ev_sender, (isc_event_t **)&iev);
+ *socketp = sock;
}
/*
- * Dispatch an internal accept event.
+ * Dereference a socket. If this is the last reference to it, clean things
+ * up by destroying the socket.
*/
-static void
-dispatch_accept(isc_socket_t *sock) {
- intev_t *iev;
- isc_socket_newconnev_t *ev;
-
- INSIST(!sock->pending_accept);
-
- /*
- * Are there any done events left, or were they all canceled
- * before the manager got the socket lock?
- */
- ev = ISC_LIST_HEAD(sock->accept_list);
- if (ev == NULL)
- return;
-
- sock->pending_accept = 1;
- iev = &sock->readable_ev;
-
- sock->references++; /* keep socket around for this internal event */
- iev->ev_sender = sock;
- iev->ev_action = internal_accept;
- iev->ev_arg = sock;
-
- isc_task_send(ev->ev_sender, (isc_event_t **)&iev);
-}
-
-static void
-dispatch_connect(isc_socket_t *sock) {
- intev_t *iev;
- isc_socket_connev_t *ev;
-
- iev = &sock->writable_ev;
+void
+isc_socket_detach(isc_socket_t **socketp) {
+ isc_socket_t *sock;
+ isc_boolean_t kill_socket = ISC_FALSE;
- ev = sock->connect_ev;
- INSIST(ev != NULL); /* XXX */
+ REQUIRE(socketp != NULL);
+ sock = *socketp;
+ REQUIRE(VALID_SOCKET(sock));
- INSIST(sock->connecting);
+ LOCK(&sock->lock);
+ REQUIRE(sock->references > 0);
+ sock->references--;
+ if (sock->references == 0)
+ kill_socket = ISC_TRUE;
+ UNLOCK(&sock->lock);
- sock->references++; /* keep socket around for this internal event */
- iev->ev_sender = sock;
- iev->ev_action = internal_connect;
- iev->ev_arg = sock;
+ if (kill_socket)
+ destroy_socket(&sock);
- isc_task_send(ev->ev_sender, (isc_event_t **)&iev);
+ *socketp = NULL;
}
/*
(*dev)->ev_sender = sock;
- if (ISC_LINK_LINKED(*dev, ev_link))
+ if (ISC_LINK_LINKED(*dev, ev_link)) {
ISC_LIST_DEQUEUE(sock->recv_list, *dev, ev_link);
+ }
if (((*dev)->attributes & ISC_SOCKEVENTATTR_ATTACHED)
== ISC_SOCKEVENTATTR_ATTACHED)
task = (*dev)->ev_sender;
(*dev)->ev_sender = sock;
- if (ISC_LINK_LINKED(*dev, ev_link))
+ if (ISC_LINK_LINKED(*dev, ev_link)) {
ISC_LIST_DEQUEUE(sock->send_list, *dev, ev_link);
+ }
if (((*dev)->attributes & ISC_SOCKEVENTATTR_ATTACHED)
== ISC_SOCKEVENTATTR_ATTACHED)
* so just unlock and return.
*/
static void
-internal_accept(isc_task_t *me, isc_event_t *ev) {
- isc_socket_t *sock;
+internal_accept(isc_socket_t *sock, int accept_errno) {
isc_socketmgr_t *manager;
isc_socket_newconnev_t *dev;
isc_task_t *task;
ISC_SOCKADDR_LEN_T addrlen;
- int fd;
+ SOCKET fd;
isc_result_t result = ISC_R_SUCCESS;
- int accept_errno = 0;
char strbuf[ISC_STRERRORSIZE];
- UNUSED(me);
-
- sock = ev->ev_sender;
INSIST(VALID_SOCKET(sock));
LOCK(&sock->lock);
INSIST(VALID_MANAGER(manager));
INSIST(sock->listener);
+ INSIST(sock->iEvent);
INSIST(sock->pending_accept == 1);
sock->pending_accept = 0;
sock->references--; /* the internal event is done with this socket */
if (sock->references == 0) {
UNLOCK(&sock->lock);
- destroy(&sock);
+ destroy_socket(&sock);
return;
}
* EAGAIN or EINTR, simply poke the watcher to watch this socket
* again.
*/
- addrlen = sizeof(dev->newsocket->address.type);
+ addrlen = sizeof dev->newsocket->address.type;
memset(&dev->newsocket->address.type.sa, 0, addrlen);
fd = accept(sock->fd, &dev->newsocket->address.type.sa,
(void *)&addrlen);
- if (fd < 0) {
+ if (fd == INVALID_SOCKET) {
accept_errno = WSAGetLastError();
if (SOFT_ERROR(accept_errno) || accept_errno == WSAECONNRESET) {
goto soft_error;
ISC_MSG_FAILED,
"failed"),
strbuf);
- fd = -1;
+ fd = INVALID_SOCKET;
result = ISC_R_UNEXPECTED;
}
} else {
sock->pf);
(void)closesocket(fd);
goto soft_error;
- } else if (fd >= FD_SETSIZE) {
- isc_log_iwrite(isc_lctx, ISC_LOGCATEGORY_GENERAL,
- ISC_LOGMODULE_SOCKET, ISC_LOG_ERROR,
- isc_msgcat, ISC_MSGSET_SOCKET,
- ISC_MSG_TOOMANYFDS,
- "%s: too many open file descriptors",
- "accept");
- (void)closesocket(fd);
- goto soft_error;
}
}
- if (fd != -1) {
+ if (fd != INVALID_SOCKET) {
dev->newsocket->address.length = addrlen;
dev->newsocket->pf = sock->pf;
}
*/
ISC_LIST_UNLINK(sock->accept_list, dev, ev_link);
- /*
- * Poke watcher if there are more pending accepts.
- */
- if (!ISC_LIST_EMPTY(sock->accept_list))
- select_poke(sock->manager, sock->fd, SELECT_POKE_ACCEPT);
-
UNLOCK(&sock->lock);
- if (fd != -1 && (make_nonblock(fd) != ISC_R_SUCCESS)) {
+ if (fd != INVALID_SOCKET && (make_nonblock(fd) != ISC_R_SUCCESS)) {
closesocket(fd);
- fd = -1;
+ fd = INVALID_SOCKET;
result = ISC_R_UNEXPECTED;
}
/*
- * -1 means the new socket didn't happen.
+ * INVALID_SOCKET means the new socket didn't happen.
*/
- if (fd != -1) {
+ if (fd != INVALID_SOCKET) {
LOCK(&manager->lock);
ISC_LIST_APPEND(manager->socklist, dev->newsocket, link);
*/
dev->address = dev->newsocket->address;
- manager->fds[fd] = dev->newsocket;
- manager->fdstate[fd] = MANAGED;
- if (manager->maxfd < fd)
- manager->maxfd = fd;
- manager->minfd = min(manager->minfd, sock->fd);
-
socket_log(sock, &dev->newsocket->address, CREATION,
isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_ACCEPTEDCXN,
"accepted connection, new socket %p",
dev->newsocket);
- UNLOCK(&manager->lock);
+ UNLOCK(&manager->lock);
} else {
dev->newsocket->references--;
free_socket(&dev->newsocket);
return;
soft_error:
- select_poke(sock->manager, sock->fd, SELECT_POKE_ACCEPT);
UNLOCK(&sock->lock);
return;
}
static void
-internal_recv(isc_task_t *me, isc_event_t *ev) {
- isc_socketevent_t *dev;
- isc_socket_t *sock;
-
- INSIST(ev->ev_type == ISC_SOCKEVENT_INTR);
+internal_recv(isc_socket_t *sock, isc_socketevent_t *dev, int nbytes, int recv_errno) {
+ isc_socketevent_t *ldev;
+ int io_state;
+ int cc;
- sock = ev->ev_sender;
INSIST(VALID_SOCKET(sock));
LOCK(&sock->lock);
socket_log(sock, NULL, IOEVENT,
isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_INTERNALRECV,
- "internal_recv: task %p got event %p", me, ev);
-
- INSIST(sock->pending_recv == 1);
- sock->pending_recv = 0;
+ "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(&sock);
+ destroy_socket(&sock);
return;
}
+ /* 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) {
+ ldev = ISC_LIST_NEXT(ldev, ev_link);
+ }
+ if (ldev == NULL)
+ goto done;
+
/*
* Try to do as much I/O as possible on this socket. There are no
* limits here, currently.
*/
- dev = ISC_LIST_HEAD(sock->recv_list);
- while (dev != NULL) {
- switch (doio_recv(sock, dev)) {
+ switch (completeio_recv(sock, dev, nbytes, recv_errno)) {
case DOIO_SOFT:
- goto poke;
+ cc = 0;
+ recv_errno = 0;
+ io_state = startio_recv(sock, dev, &cc, FALSE, &recv_errno);
+ goto done;
case DOIO_EOF:
/*
* Run through the event queue and dispatch all
* the events with an EOF result code.
*/
- do {
- dev->result = ISC_R_EOF;
- send_recvdone_event(sock, &dev);
- dev = ISC_LIST_HEAD(sock->recv_list);
- } while (dev != NULL);
- goto poke;
+ dev->result = ISC_R_EOF;
+ send_recvdone_event(sock, &dev);
+ goto done;
case DOIO_SUCCESS:
case DOIO_HARD:
send_recvdone_event(sock, &dev);
break;
}
-
- dev = ISC_LIST_HEAD(sock->recv_list);
- }
-
- poke:
- if (!ISC_LIST_EMPTY(sock->recv_list))
- select_poke(sock->manager, sock->fd, SELECT_POKE_READ);
-
+ done:
UNLOCK(&sock->lock);
}
static void
-internal_send(isc_task_t *me, isc_event_t *ev) {
- isc_socketevent_t *dev;
- isc_socket_t *sock;
-
- INSIST(ev->ev_type == ISC_SOCKEVENT_INTW);
+internal_send(isc_socket_t *sock, isc_socketevent_t *dev, int nbytes, int send_errno) {
+ isc_socketevent_t *ldev;
+ int io_state;
+ int cc;
/*
* Find out what socket this is and lock it.
*/
- sock = (isc_socket_t *)ev->ev_sender;
INSIST(VALID_SOCKET(sock));
LOCK(&sock->lock);
socket_log(sock, NULL, IOEVENT,
isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_INTERNALSEND,
- "internal_send: task %p got event %p", me, ev);
-
- INSIST(sock->pending_send == 1);
- sock->pending_send = 0;
+ "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(&sock);
+ destroy_socket(&sock);
return;
}
+ /* If the event is no longer in the list we can just return */
+ ldev = ISC_LIST_HEAD(sock->send_list);
+ while (ldev != NULL && ldev != dev) {
+ ldev = ISC_LIST_NEXT(ldev, ev_link);
+ }
+ if (ldev == NULL)
+ goto done;
/*
* Try to do as much I/O as possible on this socket. There are no
* limits here, currently.
*/
- dev = ISC_LIST_HEAD(sock->send_list);
- while (dev != NULL) {
- switch (doio_send(sock, dev)) {
- case DOIO_SOFT:
- goto poke;
-
- case DOIO_HARD:
- case DOIO_SUCCESS:
- send_senddone_event(sock, &dev);
- break;
- }
+ switch (completeio_send(sock, dev, nbytes, send_errno)) {
+ case DOIO_SOFT:
+ cc = 0;
+ send_errno = 0;
+ io_state = startio_send(sock, dev, &cc, FALSE, &send_errno);
+ goto done;
- dev = ISC_LIST_HEAD(sock->send_list);
+ case DOIO_HARD:
+ case DOIO_SUCCESS:
+ send_senddone_event(sock, &dev);
+ break;
}
- poke:
- if (!ISC_LIST_EMPTY(sock->send_list))
- select_poke(sock->manager, sock->fd, SELECT_POKE_WRITE);
+ done:
UNLOCK(&sock->lock);
}
-static void
-process_fds(isc_socketmgr_t *manager, int maxfd, int minfd,
- fd_set *readfds, fd_set *writefds, fd_set *exceptfds)
-{
- int i;
- isc_socket_t *sock;
- isc_boolean_t unlock_sock;
- BOOL conn_check = FALSE;
-
- REQUIRE(maxfd <= FD_SETSIZE);
+static isc_threadresult_t WINAPI
+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;
+ isc_socketevent_t *dev = NULL;
+ int errval;
+ char strbuf[ISC_STRERRORSIZE];
+ int errstatus;
- /*
- * Process read/writes on other fds here. Avoid locking
- * and unlocking twice if both reads and writes are possible.
+ /* Set the thread priority high enough so I/O will
+ * preempt normal recv packet processing, but not
+ * higher than the timer sync thread.
*/
- for (i = minfd ; i <= maxfd ; i++) {
- if (manager->fdstate[i] == CLOSE_PENDING) {
- manager->fdstate[i] = CLOSED;
- FD_CLR(i, &manager->read_fds);
- FD_CLR(i, &manager->write_fds);
- FD_CLR(i, &manager->except_fds);
-
- closesocket(i);
+ if (!SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL)) {
+ errval = GetLastError();
+ isc__strerror(errval, strbuf, sizeof(strbuf));
+ FATAL_ERROR(__FILE__, __LINE__,
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKET,
+ ISC_MSG_FAILED,
+ "Can't set thread priority: %s"),
+ strbuf);
+ }
- continue;
- }
- sock = manager->fds[i];
- unlock_sock = ISC_FALSE;
- if (FD_ISSET(i, readfds)) {
- if (sock == NULL) {
- FD_CLR(i, &manager->read_fds);
- goto check_write;
- }
- unlock_sock = ISC_TRUE;
- LOCK(&sock->lock);
- if (!SOCK_DEAD(sock)) {
- if (sock->listener)
- dispatch_accept(sock);
- else
- dispatch_recv(sock);
- }
- FD_CLR(i, &manager->read_fds);
- }
- check_write:
- if (FD_ISSET(i, writefds)) {
- if (sock == NULL) {
- FD_CLR(i, &manager->write_fds);
- continue;
- }
- if (!unlock_sock) {
- unlock_sock = ISC_TRUE;
- LOCK(&sock->lock);
- }
- if (!SOCK_DEAD(sock)) {
- if (sock->connecting) {
- dispatch_connect(sock);
- conn_check = TRUE;
- }
- else
- dispatch_send(sock);
- }
- FD_CLR(i, &manager->write_fds);
- FD_CLR(i, &manager->except_fds);
+ /*
+ * Loop forever waiting on I/O Completions and then processing them
+ */
+ while(TRUE) {
+ bSuccess = GetQueuedCompletionStatus (
+ manager->hIoCompletionPort,
+ &nbytes,
+ (LPDWORD) &sock,
+ (LPOVERLAPPED *)&lpo,
+ INFINITE
+ );
+ if(lpo == NULL ) {
+ /*
+ * Received request to exit
+ */
+ break;
}
- if (FD_ISSET(i, exceptfds)) {
- if (sock == NULL) {
- FD_CLR(i, &manager->except_fds);
- continue;
- }
- if (!unlock_sock) {
- unlock_sock = ISC_TRUE;
- LOCK(&sock->lock);
- }
- if (!SOCK_DEAD(sock)) {
- if (sock->connecting) {
- dispatch_connect(sock);
- conn_check = TRUE;
- }
- }
- FD_CLR(i, &manager->write_fds);
- FD_CLR(i, &manager->except_fds);
+ errstatus = 0;
+ if(!bSuccess) {
+ /*
+ * I/O Failure
+ * Find out why
+ */
+ WSAGetOverlappedResult(sock->fd, (LPWSAOVERLAPPED) &lpo,
+ &tbytes, FALSE, &tflags);
+ errstatus = WSAGetLastError();
+ isc__strerror(errstatus, strbuf, sizeof(strbuf));
+ dev = lpo->dev;
}
- if (unlock_sock)
- UNLOCK(&sock->lock);
+ request = lpo->request_type;
+ dev = lpo->dev;
+
+ switch (request) {
+ case SOCKET_CANCEL:
+ break;
+ case SOCKET_RECV:
+ internal_recv(sock, dev, nbytes, errstatus);
+ break;
+ case SOCKET_SEND:
+ internal_send(sock, dev, nbytes, errstatus);
+ break;
+ default:
+ break; /* Unknown: Just ignore it */
+ }
+ if (lpo != NULL)
+ HeapFree(hHeapHandle, 0, lpo);
}
+ /*
+ * Exit Completion Port Thread
+ */
+ manager_log(manager, TRACE,
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+ ISC_MSG_EXITING, "SocketIoThread exiting"));
+ return ((isc_threadresult_t)0);
}
-
-#ifdef ISC_PLATFORM_USETHREADS
/*
- * This is the thread that will loop forever, always in a select or poll
- * call.
+ * This is the thread that will loop forever, waiting for an event to
+ * happen.
*
- * When select returns something to do, track down what thread gets to do
- * this I/O and post the event to it.
+ * When the wait returns something to do, find the signaled event
+ * and issue the request for the given socket
*/
static isc_threadresult_t WINAPI
-watcher(void *uap) {
+event_wait(void *uap) {
isc_socketmgr_t *manager = uap;
- isc_boolean_t done;
- int ctlfd;
int cc;
- fd_set readfds;
- fd_set writefds;
- fd_set exceptfds;
- int msg, fd;
- int maxfd;
- int minfd;
- int watcher_errno = 0;
+ int event_errno;
char strbuf[ISC_STRERRORSIZE];
+ isc_socket_t *wsock;
+ int iEvent;
+ int max_event;
+ sock_event_list *evlist;
+ WSANETWORKEVENTS NetworkEvents;
+ int err;
- /* Timeout on select in case it's necesasary */
- struct timeval tv;
- tv.tv_sec = MAX_SELECT_SECONDS;
- tv.tv_usec = MAX_SELECT_MILLISECONDS;
+ evlist = &(manager->sockev_list);
/*
- * Get the control fd here. This will never change.
+ * Get the Event Lock here.
*/
- LOCK(&manager->lock);
- ctlfd = manager->pipe_fds[0];
+ LOCK(&evlist->EventLock);
- done = ISC_FALSE;
- while (!done) {
+ while (!manager->bShutdown) {
do {
- readfds = manager->read_fds;
- writefds = manager->write_fds;
- exceptfds = manager->except_fds;
- maxfd = manager->maxfd; /* Pipe not included */
- minfd = manager->minfd;
- watcher_errno = 0;
-
- UNLOCK(&manager->lock);
-
- if(maxfd > 0) {
- cc = select(maxfd, &readfds, &writefds,
- &exceptfds, &tv);
- if (cc < 0 && bpipe_written <= 0) {
- watcher_errno = WSAGetLastError();
- if (!SOFT_ERROR(watcher_errno) &&
- watcher_errno != WSAEINVAL) {
- isc__strerror(watcher_errno,
- strbuf, sizeof(strbuf));
- FATAL_ERROR(__FILE__, __LINE__,
- "select() %s: %s",
- isc_msgcat_get(isc_msgcat,
- ISC_MSGSET_GENERAL,
- ISC_MSG_FAILED,
- "failed"),
- strbuf);
- }
- }
- } else {
- /*
- * Nothing to select on yet, so sleep
- * and check again for work
- */
- Sleep(MAX_SELECT_SECONDS*1000
- + MAX_SELECT_MILLISECONDS);
+ max_event = evlist->max_event;
+ event_errno = 0;
+
+ WSAResetEvent(evlist->aEventList[0]);
+ UNLOCK(&evlist->EventLock);
+ cc = WSAWaitForMultipleEvents(max_event,
+ evlist->aEventList,FALSE, WSA_INFINITE,
+ FALSE);
+ if (cc == WSA_WAIT_FAILED) {
+ event_errno = WSAGetLastError();
+ if (!SOFT_ERROR(event_errno)) {
+ isc__strerror(event_errno, strbuf,
+ sizeof(strbuf));
+ FATAL_ERROR(__FILE__, __LINE__,
+ "WSAWaitForMultipleEvents() %s: %s",
+ isc_msgcat_get(isc_msgcat,
+ ISC_MSGSET_GENERAL,
+ ISC_MSG_FAILED,
+ "failed"),
+ strbuf);
+ }
}
- LOCK(&manager->lock);
- } while (cc < 0 && bpipe_written <= 0);
+ LOCK(&evlist->EventLock);
+ } while (cc < 0 && !manager->bShutdown
+ && manager->event_written == 0);
+ if (manager->bShutdown)
+ break;
+
+ iEvent = cc - WSA_WAIT_EVENT_0;
+
+ /*
+ * Add or delete events as requested
+ */
+ if (manager->event_written > 0)
+ process_eventlist(evlist, manager);
/*
- * Process reads on internal, control fd.
+ * Stopped to add and delete events on the list
*/
- while (bpipe_written > 0) {
- select_readmsg(manager, &fd, &msg);
- InterlockedDecrement(&bpipe_written);
+ if(iEvent == 0)
+ continue;
- manager_log(manager, IOEVENT,
- isc_msgcat_get(isc_msgcat,
- ISC_MSGSET_SOCKET,
- ISC_MSG_WATCHERMSG,
- "watcher got message %d"),
- msg);
-
- /*
- * Nothing to read?
- */
- if (msg == SELECT_POKE_NOTHING)
- break;
+ wsock = evlist->aSockList[iEvent];
+ if (wsock == NULL)
+ continue;
- /*
- * Handle shutdown message. We really should
- * jump out of this loop right away, but
- * it doesn't matter if we have to do a little
- * more work first.
- */
- if (msg == SELECT_POKE_SHUTDOWN) {
- done = ISC_TRUE;
+ if (WSAEnumNetworkEvents( wsock->fd, 0,
+ &NetworkEvents) == SOCKET_ERROR)
+ err = WSAGetLastError();
- break;
- }
+ if(NetworkEvents.lNetworkEvents == 0 ) {
+ WSAResetEvent(wsock->hEvent);
+ continue;
+ }
+
+ if(NetworkEvents.lNetworkEvents & FD_CLOSE) {
+ WSAResetEvent(wsock->hEvent);
+ continue;
+ }
+
+ if (wsock->references > 0 && wsock->pending_close == 0) {
+ 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);
+ }
}
- process_fds(manager, maxfd, minfd, &readfds, &writefds, &exceptfds);
+ if (wsock->hEvent != NULL)
+ WSAResetEvent(wsock->hEvent);
}
manager_log(manager, TRACE,
isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
- ISC_MSG_EXITING, "watcher exiting"));
+ ISC_MSG_EXITING, "event_wait exiting"));
- UNLOCK(&manager->lock);
+ UNLOCK(&evlist->EventLock);
return ((isc_threadresult_t)0);
}
-#endif /* ISC_PLATFORM_USETHREADS */
-
/*
* Create a new socket manager.
*/
isc_result_t
isc_socketmgr_create(isc_mem_t *mctx, isc_socketmgr_t **managerp) {
isc_socketmgr_t *manager;
-#ifdef ISC_PLATFORM_USETHREADS
- char strbuf[ISC_STRERRORSIZE];
-#endif
REQUIRE(managerp != NULL && *managerp == NULL);
-#ifndef ISC_PLATFORM_USETHREADS
- if (socketmgr != NULL) {
- socketmgr->refs++;
- *managerp = socketmgr;
- return (ISC_R_SUCCESS);
- }
-#endif /* ISC_PLATFORM_USETHREADS */
-
- manager = isc_mem_get(mctx, sizeof(*manager));
+ manager = isc_mem_get(mctx, sizeof *manager);
if (manager == NULL)
return (ISC_R_NOMEMORY);
manager->magic = SOCKET_MANAGER_MAGIC;
manager->mctx = NULL;
- memset(manager->fds, 0, sizeof(manager->fds));
ISC_LIST_INIT(manager->socklist);
if (isc_mutex_init(&manager->lock) != ISC_R_SUCCESS) {
- isc_mem_put(mctx, manager, sizeof(*manager));
+ isc_mem_put(mctx, manager, sizeof *manager);
UNEXPECTED_ERROR(__FILE__, __LINE__,
"isc_mutex_init() %s",
isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
}
if (isc_condition_init(&manager->shutdown_ok) != ISC_R_SUCCESS) {
DESTROYLOCK(&manager->lock);
- isc_mem_put(mctx, manager, sizeof(*manager));
+ isc_mem_put(mctx, manager, sizeof *manager);
UNEXPECTED_ERROR(__FILE__, __LINE__,
"isc_condition_init() %s",
isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
return (ISC_R_UNEXPECTED);
}
- /*
- * Create the special fds that will be used to wake up the
- * select/poll loop when something internal needs to be done.
- */
- if (internal_pipe(manager->pipe_fds) != 0) {
- DESTROYLOCK(&manager->lock);
- isc_mem_put(mctx, manager, sizeof(*manager));
- isc__strerror(errno, strbuf, sizeof(strbuf));
- UNEXPECTED_ERROR(__FILE__, __LINE__,
- "pipe() %s: %s",
- isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
- ISC_MSG_FAILED, "failed"),
- strbuf);
-
- return (ISC_R_UNEXPECTED);
- }
-
+ iocompletionport_init(manager); /* Create the Completion Ports */
- /*
- * Set up initial state for the select loop
- */
- FD_ZERO(&manager->read_fds);
- FD_ZERO(&manager->write_fds);
- FD_ZERO(&manager->except_fds);
- manager->maxfd = 0;
- manager->minfd = FD_SETSIZE;
- memset(manager->fdstate, 0, sizeof(manager->fdstate));
+ socket_event_minit(&manager->sockev_list);
+ manager->event_written = 0;
+ manager->bShutdown = ISC_FALSE;
/*
* Start up the select/poll thread.
*/
- if (isc_thread_create(watcher, manager, &manager->watcher) !=
+ if (isc_thread_create(event_wait, manager, &manager->watcher) !=
ISC_R_SUCCESS) {
DESTROYLOCK(&manager->lock);
- isc_mem_put(mctx, manager, sizeof(*manager));
+ isc_mem_put(mctx, manager, sizeof *manager);
UNEXPECTED_ERROR(__FILE__, __LINE__,
"isc_thread_create() %s",
isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
ISC_MSG_FAILED, "failed"));
- _close(manager->pipe_fds[0]);
- _close(manager->pipe_fds[1]);
return (ISC_R_UNEXPECTED);
}
isc_mem_attach(mctx, &manager->mctx);
manager = *managerp;
REQUIRE(VALID_MANAGER(manager));
-#ifndef ISC_PLATFORM_USETHREADS
- if (manager->refs > 1) {
- manager->refs--;
- *managerp = NULL;
- return;
- }
-#endif /* ISC_PLATFORM_USETHREADS */
-
LOCK(&manager->lock);
-#ifdef ISC_PLATFORM_USETHREADS
/*
* Wait for all sockets to be destroyed.
*/
"sockets exist"));
WAIT(&manager->shutdown_ok, &manager->lock);
}
-#else /* ISC_PLATFORM_USETHREADS */
- /*
- * Hope all sockets have been destroyed.
- */
- if (!ISC_LIST_EMPTY(manager->socklist)) {
- manager_log(manager, CREATION,
- isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKET,
- ISC_MSG_SOCKETSREMAIN,
- "sockets exist"));
- INSIST(0);
- }
-#endif /* ISC_PLATFORM_USETHREADS */
UNLOCK(&manager->lock);
/*
- * Here, poke our select/poll thread. Do this by closing the write
- * half of the pipe, which will send EOF to the read half.
- * This is currently a no-op in the non-threaded case.
+ * Here, we need to had some wait code for the completion port
+ * thread.
*/
- select_poke(manager, 0, SELECT_POKE_SHUTDOWN);
+ signal_iocompletionport_exit(manager);
+ manager->bShutdown = ISC_TRUE;
+ WSASetEvent(manager->sockev_list.aEventList[0]);
-#ifdef ISC_PLATFORM_USETHREADS
/*
* Wait for thread to exit.
*/
+
if (isc_thread_join(manager->watcher, NULL) != ISC_R_SUCCESS)
UNEXPECTED_ERROR(__FILE__, __LINE__,
"isc_thread_join() %s",
isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
ISC_MSG_FAILED, "failed"));
-#endif /* ISC_PLATFORM_USETHREADS */
-
+ /*
+ * Now the I/O Completion Port Worker Threads
+ */
+ for (i = 0; i < manager->maxIOCPThreads; i++) {
+ if (isc_thread_join((isc_thread_t) manager->hIOCPThreads[i], NULL)
+ != ISC_R_SUCCESS)
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "isc_thread_join() for Completion Port %s",
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+ ISC_MSG_FAILED, "failed"));
+ }
/*
* Clean up.
*/
-#ifdef ISC_PLATFORM_USETHREADS
- _close(manager->pipe_fds[0]);
- _close(manager->pipe_fds[1]);
- (void)isc_condition_destroy(&manager->shutdown_ok);
-#endif /* ISC_PLATFORM_USETHREADS */
- for (i = 0 ; i < FD_SETSIZE ; i++)
- if (manager->fdstate[i] == CLOSE_PENDING)
- closesocket(i);
+ CloseHandle(manager->hIoCompletionPort);
+
+ (void)isc_condition_destroy(&manager->shutdown_ok);
DESTROYLOCK(&manager->lock);
manager->magic = 0;
mctx= manager->mctx;
- isc_mem_put(mctx, manager, sizeof(*manager));
+ isc_mem_put(mctx, manager, sizeof *manager);
isc_mem_detach(&mctx);
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;
- isc_boolean_t have_lock = ISC_FALSE;
+ int cc = 0;
isc_task_t *ntask = NULL;
isc_result_t result = ISC_R_SUCCESS;
+ int recv_errno = 0;
dev->ev_sender = task;
- if (sock->type == isc_sockettype_udp) {
- io_state = doio_recv(sock, dev);
- } else {
- LOCK(&sock->lock);
- have_lock = ISC_TRUE;
-
- if (ISC_LIST_EMPTY(sock->recv_list))
- io_state = doio_recv(sock, dev);
- else
- io_state = DOIO_SOFT;
- }
+ LOCK(&sock->lock);
+ iocompletionport_update(sock);
+ io_state = startio_recv(sock, dev, &cc, FALSE, &recv_errno);
switch (io_state) {
case DOIO_SOFT:
isc_task_attach(task, &ntask);
dev->attributes |= ISC_SOCKEVENTATTR_ATTACHED;
- if (!have_lock) {
- LOCK(&sock->lock);
- have_lock = ISC_TRUE;
- }
-
/*
- * Enqueue the request. If the socket was previously not being
- * watched, poke the watcher to start paying attention to it.
+ * Enqueue the request.
*/
- if (ISC_LIST_EMPTY(sock->recv_list))
- select_poke(sock->manager, sock->fd, SELECT_POKE_READ);
ISC_LIST_ENQUEUE(sock->recv_list, dev, ev_link);
socket_log(sock, NULL, EVENT, NULL, 0, 0,
send_recvdone_event(sock, &dev);
break;
}
-
- if (have_lock)
- UNLOCK(&sock->lock);
+ UNLOCK(&sock->lock);
return (result);
}
unsigned int flags)
{
int io_state;
+ int send_errno = 0;
+ int cc = 0;
isc_boolean_t have_lock = ISC_FALSE;
isc_task_t *ntask = NULL;
isc_result_t result = ISC_R_SUCCESS;
dev->pktinfo.ipi6_ifindex = 0;
}
- if (sock->type == isc_sockettype_udp)
- io_state = doio_send(sock, dev);
- else {
- LOCK(&sock->lock);
- have_lock = ISC_TRUE;
-
- if (ISC_LIST_EMPTY(sock->send_list))
- io_state = doio_send(sock, dev);
- else
- io_state = DOIO_SOFT;
- }
+ LOCK(&sock->lock);
+ have_lock = ISC_TRUE;
+ iocompletionport_update(sock);
+ io_state = startio_send(sock, dev, &cc, FALSE, &send_errno);
switch (io_state) {
case DOIO_SOFT:
* We couldn't send all or part of the request right now, so
* queue it unless ISC_SOCKFLAG_NORETRY is set.
*/
- if ((flags & ISC_SOCKFLAG_NORETRY) == 0) {
+// if ((flags & ISC_SOCKFLAG_NORETRY) == 0) {
isc_task_attach(task, &ntask);
dev->attributes |= ISC_SOCKEVENTATTR_ATTACHED;
}
/*
- * Enqueue the request. If the socket was previously not being
- * watched, poke the watcher to start paying attention to it.
+ * Enqueue the request.
*/
- if (ISC_LIST_EMPTY(sock->send_list))
- select_poke(sock->manager, sock->fd,
- SELECT_POKE_WRITE);
ISC_LIST_ENQUEUE(sock->send_list, dev, ev_link);
socket_log(sock, NULL, EVENT, NULL, 0, 0,
if ((flags & ISC_SOCKFLAG_IMMEDIATE) != 0)
result = ISC_R_INPROGRESS;
break;
- }
+// }
- case DOIO_HARD:
case DOIO_SUCCESS:
- if ((flags & ISC_SOCKFLAG_IMMEDIATE) == 0)
- send_senddone_event(sock, &dev);
+// result = ISC_R_INPROGRESS;
break;
}
if (dev == NULL) {
return (ISC_R_NOMEMORY);
}
-
dev->region = *region;
return (socket_send(sock, dev, task, address, pktinfo, 0));
isc_result_t
isc_socket_bind(isc_socket_t *sock, isc_sockaddr_t *sockaddr) {
- int bind_errno = 0;
+ int bind_errno;
char strbuf[ISC_STRERRORSIZE];
int on = 1;
return (ISC_R_FAMILYMISMATCH);
}
if (setsockopt(sock->fd, SOL_SOCKET, SO_REUSEADDR, (void *)&on,
- sizeof(on)) < 0) {
+ sizeof on) < 0) {
UNEXPECTED_ERROR(__FILE__, __LINE__,
"setsockopt(%d) %s", sock->fd,
isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
isc_result_t
isc_socket_listen(isc_socket_t *sock, unsigned int backlog) {
char strbuf[ISC_STRERRORSIZE];
+ isc_result_t retstat;
REQUIRE(VALID_SOCKET(sock));
sock->listener = 1;
+ /* Add the socket to the list of events to accept */
+ retstat = socket_event_add(sock, FD_ACCEPT | FD_CLOSE);
+ if (retstat != ISC_R_SUCCESS) {
+ UNLOCK(&sock->lock);
+ if (retstat != ISC_R_NOSPACE) {
+ isc__strerror(WSAGetLastError(), strbuf,
+ sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "isc_socket_listen: socket_event_add: %s", strbuf);
+ }
+ return (retstat);
+ }
+
+
UNLOCK(&sock->lock);
return (ISC_R_SUCCESS);
}
isc_task_t *ntask = NULL;
isc_socket_t *nsock;
isc_result_t ret;
- isc_boolean_t do_poke = ISC_FALSE;
REQUIRE(VALID_SOCKET(sock));
manager = sock->manager;
dev->newsocket = nsock;
/*
- * Poke watcher here. We still have the socket locked, so there
- * is no race condition. We will keep the lock for such a short
- * bit of time waking it up now or later won't matter all that much.
+ * Enqueue the event
*/
- if (ISC_LIST_EMPTY(sock->accept_list))
- do_poke = ISC_TRUE;
-
ISC_LIST_ENQUEUE(sock->accept_list, dev, ev_link);
- if (do_poke)
- select_poke(manager, sock->fd, SELECT_POKE_ACCEPT);
-
UNLOCK(&sock->lock);
return (ISC_R_SUCCESS);
}
isc_task_t *ntask = NULL;
isc_socketmgr_t *manager;
int cc;
+ int retstat;
int errval;
char strbuf[ISC_STRERRORSIZE];
ERROR_MATCH(WSAENOBUFS, ISC_R_NORESOURCES);
ERROR_MATCH(EPERM, ISC_R_HOSTUNREACH);
ERROR_MATCH(EPIPE, ISC_R_NOTCONNECTED);
- ERROR_MATCH(WSAECONNRESET, ISC_R_CONNECTIONRESET);
#undef ERROR_MATCH
}
dev->ev_sender = ntask;
/*
- * Poke watcher here. We still have the socket locked, so there
- * is no race condition. We will keep the lock for such a short
- * bit of time waking it up now or later won't matter all that much.
+ * Enqueue the request.
*/
- if (sock->connect_ev == NULL)
- select_poke(manager, sock->fd, SELECT_POKE_CONNECT);
-
sock->connect_ev = dev;
+ /* Add the socket to the list of events to connect */
+ retstat = socket_event_add(sock, FD_CONNECT | FD_CLOSE);
+ if (retstat != ISC_R_SUCCESS) {
+ UNLOCK(&sock->lock);
+ if (retstat != ISC_R_NOSPACE) {
+ isc__strerror(WSAGetLastError(), strbuf,
+ sizeof(strbuf));
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "isc_socket_connect: socket_event_add: %s", strbuf);
+ }
+ return (retstat);
+ }
UNLOCK(&sock->lock);
return (ISC_R_SUCCESS);
* Called when a socket with a pending connect() finishes.
*/
static void
-internal_connect(isc_task_t *me, isc_event_t *ev) {
- isc_socket_t *sock;
+internal_connect(isc_socket_t *sock, int connect_errno) {
isc_socket_connev_t *dev;
isc_task_t *task;
int cc;
ISC_SOCKADDR_LEN_T optlen;
- int connect_errno = 0;
char strbuf[ISC_STRERRORSIZE];
- UNUSED(me);
- INSIST(ev->ev_type == ISC_SOCKEVENT_INTW);
-
- sock = ev->ev_sender;
INSIST(VALID_SOCKET(sock));
LOCK(&sock->lock);
+ WSAResetEvent(sock->hEvent);
/*
* When the internal event was sent the reference count was bumped
sock->references--;
if (sock->references == 0) {
UNLOCK(&sock->lock);
- destroy(&sock);
+ destroy_socket(&sock);
return;
}
if (getsockopt(sock->fd, SOL_SOCKET, SO_ERROR,
(void *)&cc, (void *)&optlen) < 0)
connect_errno = WSAGetLastError();
+ else
+ connect_errno = 0;
if (connect_errno != 0) {
/*
- * If the error is WSAEAGAIN, just re-select on this
+ * If the error is EAGAIN, just try again on this
* fd and pretend nothing strange happened.
*/
if (SOFT_ERROR(connect_errno) || connect_errno == WSAEINPROGRESS) {
sock->connecting = 1;
- select_poke(sock->manager, sock->fd,
- SELECT_POKE_CONNECT);
UNLOCK(&sock->lock);
return;
ERROR_MATCH(EPERM, ISC_R_HOSTUNREACH);
ERROR_MATCH(EPIPE, ISC_R_NOTCONNECTED);
ERROR_MATCH(WSAETIMEDOUT, ISC_R_TIMEDOUT);
- ERROR_MATCH(WSAECONNRESET, ISC_R_CONNECTIONRESET);
#undef ERROR_MATCH
default:
dev->result = ISC_R_UNEXPECTED;
ret = ISC_R_SUCCESS;
- len = sizeof(addressp->type);
+ len = sizeof addressp->type;
if (getsockname(sock->fd, &addressp->type.sa, (void *)&len) < 0) {
isc__strerror(WSAGetLastError(), strbuf, sizeof(strbuf));
UNEXPECTED_ERROR(__FILE__, __LINE__, "getsockname: %s",
*/
void
isc_socket_cancel(isc_socket_t *sock, isc_task_t *task, unsigned int how) {
+// IoCompletionInfo *CancelRequest;
REQUIRE(VALID_SOCKET(sock));
while (dev != NULL) {
current_task = dev->ev_sender;
next = ISC_LIST_NEXT(dev, ev_link);
-
if ((task == NULL) || (task == current_task)) {
dev->result = ISC_R_CANCELED;
send_recvdone_event(sock, &dev);
}
+/* if (sock->iocp == 1) {
+ CancelRequest = (IoCompletionInfo *) HeapAlloc(hHeapHandle,
+ HEAP_ZERO_MEMORY, sizeof(IoCompletionInfo));
+ CancelRequest->request_type = SOCKET_CANCEL;
+ CancelRequest->dev = dev;
+ PostQueuedCompletionStatus(hIoCompletionPort, 0,
+ (DWORD) sock, &CancelRequest->overlapped);
+ } */
dev = next;
}
}
while (dev != NULL) {
current_task = dev->ev_sender;
next = ISC_LIST_NEXT(dev, ev_link);
-
if ((task == NULL) || (task == current_task)) {
dev->result = ISC_R_CANCELED;
send_senddone_event(sock, &dev);
}
+/* if (sock->iocp == 1) {
+ CancelRequest = (IoCompletionInfo *) HeapAlloc(hHeapHandle,
+ HEAP_ZERO_MEMORY, sizeof(IoCompletionInfo));
+ CancelRequest->request_type = SOCKET_CANCEL;
+ CancelRequest->dev = dev;
+ PostQueuedCompletionStatus(hIoCompletionPort, 0,
+ (DWORD) sock, &CancelRequest->overlapped);
+ } */
dev = next;
}
}
isc_task_t *current_task;
dev = ISC_LIST_HEAD(sock->accept_list);
+ socket_event_delete(sock);
+
while (dev != NULL) {
current_task = dev->ev_sender;
next = ISC_LIST_NEXT(dev, ev_link);
return (val);
}
+
+void
+isc_socket_ipv6only(isc_socket_t *sock, isc_boolean_t yes) {
+#if defined(IPV6_V6ONLY)
+ int onoff = yes ? 1 : 0;
+#else
+ UNUSED(yes);
+ UNUSED(sock);
+#endif
+
+ REQUIRE(VALID_SOCKET(sock));
+
+#ifdef IPV6_V6ONLY
+ if (sock->pf == AF_INET6) {
+ (void)setsockopt(sock->fd, IPPROTO_IPV6, IPV6_V6ONLY,
+ (void *)&onoff, sizeof(onoff));
+ }
+#endif
+}