Annotation of embedaddon/ntp/lib/isc/win32/socket.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC")
! 3: * Copyright (C) 2000-2003 Internet Software Consortium.
! 4: *
! 5: * Permission to use, copy, modify, and/or distribute this software for any
! 6: * purpose with or without fee is hereby granted, provided that the above
! 7: * copyright notice and this permission notice appear in all copies.
! 8: *
! 9: * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
! 10: * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
! 11: * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
! 12: * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
! 13: * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
! 14: * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
! 15: * PERFORMANCE OF THIS SOFTWARE.
! 16: */
! 17:
! 18: /* $Id: socket.c,v 1.70.54.4 2009/01/29 22:40:36 jinmei Exp $ */
! 19:
! 20: /* This code uses functions which are only available on Server 2003 and
! 21: * higher, and Windows XP and higher.
! 22: *
! 23: * This code is by nature multithreaded and takes advantage of various
! 24: * features to pass on information through the completion port for
! 25: * when I/O is completed. All sends, receives, accepts, and connects are
! 26: * completed through the completion port.
! 27: *
! 28: * The number of Completion Port Worker threads used is the total number
! 29: * of CPU's + 1. This increases the likelihood that a Worker Thread is
! 30: * available for processing a completed request.
! 31: *
! 32: * XXXPDM 5 August, 2002
! 33: */
! 34:
! 35: #define MAKE_EXTERNAL 1
! 36: #include <config.h>
! 37:
! 38: #include <sys/types.h>
! 39:
! 40: #ifndef _WINSOCKAPI_
! 41: #define _WINSOCKAPI_ /* Prevent inclusion of winsock.h in windows.h */
! 42: #endif
! 43:
! 44: #include <errno.h>
! 45: #include <stddef.h>
! 46: #include <stdlib.h>
! 47: #include <string.h>
! 48: #include <unistd.h>
! 49: #include <io.h>
! 50: #include <fcntl.h>
! 51: #include <process.h>
! 52:
! 53: #include <isc/buffer.h>
! 54: #include <isc/bufferlist.h>
! 55: #include <isc/condition.h>
! 56: #include <isc/list.h>
! 57: #include <isc/log.h>
! 58: #include <isc/mem.h>
! 59: #include <isc/msgs.h>
! 60: #include <isc/mutex.h>
! 61: #include <isc/net.h>
! 62: #include <isc/once.h>
! 63: #include <isc/os.h>
! 64: #include <isc/platform.h>
! 65: #include <isc/print.h>
! 66: #include <isc/region.h>
! 67: #include <isc/socket.h>
! 68: #include <isc/stats.h>
! 69: #include <isc/strerror.h>
! 70: #include <isc/syslog.h>
! 71: #include <isc/task.h>
! 72: #include <isc/thread.h>
! 73: #include <isc/util.h>
! 74: #include <isc/win32os.h>
! 75:
! 76: #include <mswsock.h>
! 77:
! 78: #include "errno2result.h"
! 79:
! 80: /*
! 81: * How in the world can Microsoft exist with APIs like this?
! 82: * We can't actually call this directly, because it turns out
! 83: * no library exports this function. Instead, we need to
! 84: * issue a runtime call to get the address.
! 85: */
! 86: LPFN_CONNECTEX ISCConnectEx;
! 87: LPFN_ACCEPTEX ISCAcceptEx;
! 88: LPFN_GETACCEPTEXSOCKADDRS ISCGetAcceptExSockaddrs;
! 89:
! 90: /*
! 91: * Run expensive internal consistency checks.
! 92: */
! 93: #ifdef ISC_SOCKET_CONSISTENCY_CHECKS
! 94: #define CONSISTENT(sock) consistent(sock)
! 95: #else
! 96: #define CONSISTENT(sock) do {} while (0)
! 97: #endif
! 98: static void consistent(isc_socket_t *sock);
! 99:
! 100: /*
! 101: * Define this macro to control the behavior of connection
! 102: * resets on UDP sockets. See Microsoft KnowledgeBase Article Q263823
! 103: * for details.
! 104: * NOTE: This requires that Windows 2000 systems install Service Pack 2
! 105: * or later.
! 106: */
! 107: #ifndef SIO_UDP_CONNRESET
! 108: #define SIO_UDP_CONNRESET _WSAIOW(IOC_VENDOR,12)
! 109: #endif
! 110:
! 111: /*
! 112: * Some systems define the socket length argument as an int, some as size_t,
! 113: * some as socklen_t. This is here so it can be easily changed if needed.
! 114: */
! 115: #ifndef ISC_SOCKADDR_LEN_T
! 116: #define ISC_SOCKADDR_LEN_T unsigned int
! 117: #endif
! 118:
! 119: /*
! 120: * Define what the possible "soft" errors can be. These are non-fatal returns
! 121: * of various network related functions, like recv() and so on.
! 122: */
! 123: #define SOFT_ERROR(e) ((e) == WSAEINTR || \
! 124: (e) == WSAEWOULDBLOCK || \
! 125: (e) == EWOULDBLOCK || \
! 126: (e) == EINTR || \
! 127: (e) == EAGAIN || \
! 128: (e) == 0)
! 129:
! 130: /*
! 131: * Pending errors are not really errors and should be
! 132: * kept separate
! 133: */
! 134: #define PENDING_ERROR(e) ((e) == WSA_IO_PENDING || (e) == 0)
! 135:
! 136: #define DOIO_SUCCESS 0 /* i/o ok, event sent */
! 137: #define DOIO_SOFT 1 /* i/o ok, soft error, no event sent */
! 138: #define DOIO_HARD 2 /* i/o error, event sent */
! 139: #define DOIO_EOF 3 /* EOF, no event sent */
! 140: #define DOIO_PENDING 4 /* status when i/o is in process */
! 141: #define DOIO_NEEDMORE 5 /* IO was processed, but we need more due to minimum */
! 142:
! 143: #define DLVL(x) ISC_LOGCATEGORY_GENERAL, ISC_LOGMODULE_SOCKET, ISC_LOG_DEBUG(x)
! 144:
! 145: /*
! 146: * DLVL(90) -- Function entry/exit and other tracing.
! 147: * DLVL(70) -- Socket "correctness" -- including returning of events, etc.
! 148: * DLVL(60) -- Socket data send/receive
! 149: * DLVL(50) -- Event tracing, including receiving/sending completion events.
! 150: * DLVL(20) -- Socket creation/destruction.
! 151: */
! 152: #define TRACE_LEVEL 90
! 153: #define CORRECTNESS_LEVEL 70
! 154: #define IOEVENT_LEVEL 60
! 155: #define EVENT_LEVEL 50
! 156: #define CREATION_LEVEL 20
! 157:
! 158: #define TRACE DLVL(TRACE_LEVEL)
! 159: #define CORRECTNESS DLVL(CORRECTNESS_LEVEL)
! 160: #define IOEVENT DLVL(IOEVENT_LEVEL)
! 161: #define EVENT DLVL(EVENT_LEVEL)
! 162: #define CREATION DLVL(CREATION_LEVEL)
! 163:
! 164: typedef isc_event_t intev_t;
! 165:
! 166: /*
! 167: * Socket State
! 168: */
! 169: enum {
! 170: SOCK_INITIALIZED, /* Socket Initialized */
! 171: SOCK_OPEN, /* Socket opened but nothing yet to do */
! 172: SOCK_DATA, /* Socket sending or receiving data */
! 173: SOCK_LISTEN, /* TCP Socket listening for connects */
! 174: SOCK_ACCEPT, /* TCP socket is waiting to accept */
! 175: SOCK_CONNECT, /* TCP Socket connecting */
! 176: SOCK_CLOSED, /* Socket has been closed */
! 177: };
! 178:
! 179: #define SOCKET_MAGIC ISC_MAGIC('I', 'O', 'i', 'o')
! 180: #define VALID_SOCKET(t) ISC_MAGIC_VALID(t, SOCKET_MAGIC)
! 181:
! 182: /*
! 183: * IPv6 control information. If the socket is an IPv6 socket we want
! 184: * to collect the destination address and interface so the client can
! 185: * set them on outgoing packets.
! 186: */
! 187: #ifdef ISC_PLATFORM_HAVEIPV6
! 188: #ifndef USE_CMSG
! 189: #define USE_CMSG 1
! 190: #endif
! 191: #endif
! 192:
! 193: /*
! 194: * We really don't want to try and use these control messages. Win32
! 195: * doesn't have this mechanism before XP.
! 196: */
! 197: #undef USE_CMSG
! 198:
! 199: /*
! 200: * Message header for recvmsg and sendmsg calls.
! 201: * Used value-result for recvmsg, value only for sendmsg.
! 202: */
! 203: struct msghdr {
! 204: SOCKADDR_STORAGE to_addr; /* UDP send/recv address */
! 205: int to_addr_len; /* length of the address */
! 206: WSABUF *msg_iov; /* scatter/gather array */
! 207: u_int msg_iovlen; /* # elements in msg_iov */
! 208: void *msg_control; /* ancillary data, see below */
! 209: u_int msg_controllen; /* ancillary data buffer len */
! 210: int msg_totallen; /* total length of this message */
! 211: } msghdr;
! 212:
! 213: /*
! 214: * The size to raise the receive buffer to.
! 215: */
! 216: #define RCVBUFSIZE (32*1024)
! 217:
! 218: /*
! 219: * The number of times a send operation is repeated if the result
! 220: * is WSAEINTR.
! 221: */
! 222: #define NRETRIES 10
! 223:
! 224: struct isc_socket {
! 225: /* Not locked. */
! 226: unsigned int magic;
! 227: isc_socketmgr_t *manager;
! 228: isc_mutex_t lock;
! 229: isc_sockettype_t type;
! 230:
! 231: /* Pointers to scatter/gather buffers */
! 232: WSABUF iov[ISC_SOCKET_MAXSCATTERGATHER];
! 233:
! 234: /* Locked by socket lock. */
! 235: ISC_LINK(isc_socket_t) link;
! 236: unsigned int references; /* EXTERNAL references */
! 237: SOCKET fd; /* file handle */
! 238: int pf; /* protocol family */
! 239: char name[16];
! 240: void * tag;
! 241:
! 242: /*
! 243: * Each recv() call uses this buffer. It is a per-socket receive
! 244: * buffer that allows us to decouple the system recv() from the
! 245: * recv_list done events. This means the items on the recv_list
! 246: * can be removed without having to cancel pending system recv()
! 247: * calls. It also allows us to read-ahead in some cases.
! 248: */
! 249: struct {
! 250: SOCKADDR_STORAGE from_addr; // UDP send/recv address
! 251: int from_addr_len; // length of the address
! 252: char *base; // the base of the buffer
! 253: char *consume_position; // where to start copying data from next
! 254: unsigned int len; // the actual size of this buffer
! 255: unsigned int remaining; // the number of bytes remaining
! 256: } recvbuf;
! 257:
! 258: ISC_LIST(isc_socketevent_t) send_list;
! 259: ISC_LIST(isc_socketevent_t) recv_list;
! 260: ISC_LIST(isc_socket_newconnev_t) accept_list;
! 261: isc_socket_connev_t *connect_ev;
! 262:
! 263: isc_sockaddr_t address; /* remote address */
! 264:
! 265: unsigned int listener : 1, /* listener socket */
! 266: connected : 1,
! 267: pending_connect : 1, /* connect pending */
! 268: bound : 1; /* bound to local addr */
! 269: unsigned int pending_iocp; /* Should equal the counters below. Debug. */
! 270: unsigned int pending_recv; /* Number of outstanding recv() calls. */
! 271: unsigned int pending_send; /* Number of outstanding send() calls. */
! 272: unsigned int pending_accept; /* Number of outstanding accept() calls. */
! 273: unsigned int state; /* Socket state. Debugging and consistency checking. */
! 274: int state_lineno; /* line which last touched state */
! 275: };
! 276:
! 277: #define _set_state(sock, _state) do { (sock)->state = (_state); (sock)->state_lineno = __LINE__; } while (0)
! 278:
! 279: /*
! 280: * Buffer structure
! 281: */
! 282: typedef struct buflist buflist_t;
! 283:
! 284: struct buflist {
! 285: void *buf;
! 286: unsigned int buflen;
! 287: ISC_LINK(buflist_t) link;
! 288: };
! 289:
! 290: /*
! 291: * I/O Completion ports Info structures
! 292: */
! 293:
! 294: static HANDLE hHeapHandle = NULL;
! 295: typedef struct IoCompletionInfo {
! 296: OVERLAPPED overlapped;
! 297: isc_socketevent_t *dev; /* send()/recv() done event */
! 298: isc_socket_connev_t *cdev; /* connect() done event */
! 299: isc_socket_newconnev_t *adev; /* accept() done event */
! 300: void *acceptbuffer;
! 301: DWORD received_bytes;
! 302: int request_type;
! 303: struct msghdr messagehdr;
! 304: ISC_LIST(buflist_t) bufferlist; /*%< list of buffers */
! 305: } IoCompletionInfo;
! 306:
! 307: /*
! 308: * Define a maximum number of I/O Completion Port worker threads
! 309: * to handle the load on the Completion Port. The actual number
! 310: * used is the number of CPU's + 1.
! 311: */
! 312: #define MAX_IOCPTHREADS 20
! 313:
! 314: #define SOCKET_MANAGER_MAGIC ISC_MAGIC('I', 'O', 'm', 'g')
! 315: #define VALID_MANAGER(m) ISC_MAGIC_VALID(m, SOCKET_MANAGER_MAGIC)
! 316:
! 317: struct isc_socketmgr {
! 318: /* Not locked. */
! 319: unsigned int magic;
! 320: isc_mem_t *mctx;
! 321: isc_mutex_t lock;
! 322: isc_stats_t *stats;
! 323:
! 324: /* Locked by manager lock. */
! 325: ISC_LIST(isc_socket_t) socklist;
! 326: isc_boolean_t bShutdown;
! 327: isc_condition_t shutdown_ok;
! 328: HANDLE hIoCompletionPort;
! 329: int maxIOCPThreads;
! 330: HANDLE hIOCPThreads[MAX_IOCPTHREADS];
! 331: DWORD dwIOCPThreadIds[MAX_IOCPTHREADS];
! 332:
! 333: /*
! 334: * Debugging.
! 335: * Modified by InterlockedIncrement() and InterlockedDecrement()
! 336: */
! 337: LONG totalSockets;
! 338: LONG iocp_total;
! 339: };
! 340:
! 341: enum {
! 342: SOCKET_RECV,
! 343: SOCKET_SEND,
! 344: SOCKET_ACCEPT,
! 345: SOCKET_CONNECT
! 346: };
! 347:
! 348: /*
! 349: * send() and recv() iovec counts
! 350: */
! 351: #define MAXSCATTERGATHER_SEND (ISC_SOCKET_MAXSCATTERGATHER)
! 352: #define MAXSCATTERGATHER_RECV (ISC_SOCKET_MAXSCATTERGATHER)
! 353:
! 354: static isc_threadresult_t WINAPI SocketIoThread(LPVOID ThreadContext);
! 355: static void maybe_free_socket(isc_socket_t **, int);
! 356: static void free_socket(isc_socket_t **, int);
! 357: static isc_boolean_t senddone_is_active(isc_socket_t *sock, isc_socketevent_t *dev);
! 358: static isc_boolean_t acceptdone_is_active(isc_socket_t *sock, isc_socket_newconnev_t *dev);
! 359: static isc_boolean_t connectdone_is_active(isc_socket_t *sock, isc_socket_connev_t *dev);
! 360: static void send_recvdone_event(isc_socket_t *sock, isc_socketevent_t **dev);
! 361: static void send_senddone_event(isc_socket_t *sock, isc_socketevent_t **dev);
! 362: static void send_acceptdone_event(isc_socket_t *sock, isc_socket_newconnev_t **adev);
! 363: static void send_connectdone_event(isc_socket_t *sock, isc_socket_connev_t **cdev);
! 364: static void send_recvdone_abort(isc_socket_t *sock, isc_result_t result);
! 365: static void queue_receive_event(isc_socket_t *sock, isc_task_t *task, isc_socketevent_t *dev);
! 366: static void queue_receive_request(isc_socket_t *sock);
! 367:
! 368: /*
! 369: * This is used to dump the contents of the sock structure
! 370: * You should make sure that the sock is locked before
! 371: * dumping it. Since the code uses simple printf() statements
! 372: * it should only be used interactively.
! 373: */
! 374: void
! 375: sock_dump(isc_socket_t *sock) {
! 376: isc_socketevent_t *ldev;
! 377: isc_socket_newconnev_t *ndev;
! 378:
! 379: #if 0
! 380: isc_sockaddr_t addr;
! 381: char socktext[256];
! 382:
! 383: isc_socket_getpeername(sock, &addr);
! 384: isc_sockaddr_format(&addr, socktext, sizeof(socktext));
! 385: printf("Remote Socket: %s\n", socktext);
! 386: isc_socket_getsockname(sock, &addr);
! 387: isc_sockaddr_format(&addr, socktext, sizeof(socktext));
! 388: printf("This Socket: %s\n", socktext);
! 389: #endif
! 390:
! 391: printf("\n\t\tSock Dump\n");
! 392: printf("\t\tfd: %u\n", sock->fd);
! 393: printf("\t\treferences: %d\n", sock->references);
! 394: printf("\t\tpending_accept: %d\n", sock->pending_accept);
! 395: printf("\t\tconnecting: %d\n", sock->pending_connect);
! 396: printf("\t\tconnected: %d\n", sock->connected);
! 397: printf("\t\tbound: %d\n", sock->bound);
! 398: printf("\t\tpending_iocp: %d\n", sock->pending_iocp);
! 399: printf("\t\tsocket type: %d\n", sock->type);
! 400:
! 401: printf("\n\t\tSock Recv List\n");
! 402: ldev = ISC_LIST_HEAD(sock->recv_list);
! 403: while (ldev != NULL) {
! 404: printf("\t\tdev: %p\n", ldev);
! 405: ldev = ISC_LIST_NEXT(ldev, ev_link);
! 406: }
! 407:
! 408: printf("\n\t\tSock Send List\n");
! 409: ldev = ISC_LIST_HEAD(sock->send_list);
! 410: while (ldev != NULL) {
! 411: printf("\t\tdev: %p\n", ldev);
! 412: ldev = ISC_LIST_NEXT(ldev, ev_link);
! 413: }
! 414:
! 415: printf("\n\t\tSock Accept List\n");
! 416: ndev = ISC_LIST_HEAD(sock->accept_list);
! 417: while (ndev != NULL) {
! 418: printf("\t\tdev: %p\n", ldev);
! 419: ndev = ISC_LIST_NEXT(ndev, ev_link);
! 420: }
! 421: }
! 422:
! 423: static void
! 424: socket_log(int lineno, isc_socket_t *sock, isc_sockaddr_t *address,
! 425: isc_logcategory_t *category, isc_logmodule_t *module, int level,
! 426: isc_msgcat_t *msgcat, int msgset, int message,
! 427: const char *fmt, ...) ISC_FORMAT_PRINTF(9, 10);
! 428:
! 429: /* This function will add an entry to the I/O completion port
! 430: * that will signal the I/O thread to exit (gracefully)
! 431: */
! 432: static void
! 433: signal_iocompletionport_exit(isc_socketmgr_t *manager) {
! 434: int i;
! 435: int errval;
! 436: char strbuf[ISC_STRERRORSIZE];
! 437:
! 438: REQUIRE(VALID_MANAGER(manager));
! 439: for (i = 0; i < manager->maxIOCPThreads; i++) {
! 440: if (!PostQueuedCompletionStatus(manager->hIoCompletionPort,
! 441: 0, 0, 0)) {
! 442: errval = GetLastError();
! 443: isc__strerror(errval, strbuf, sizeof(strbuf));
! 444: FATAL_ERROR(__FILE__, __LINE__,
! 445: isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKET,
! 446: ISC_MSG_FAILED,
! 447: "Can't request service thread to exit: %s"),
! 448: strbuf);
! 449: }
! 450: }
! 451: }
! 452:
! 453: /*
! 454: * Create the worker threads for the I/O Completion Port
! 455: */
! 456: void
! 457: iocompletionport_createthreads(int total_threads, isc_socketmgr_t *manager) {
! 458: int errval;
! 459: char strbuf[ISC_STRERRORSIZE];
! 460: int i;
! 461:
! 462: INSIST(total_threads > 0);
! 463: REQUIRE(VALID_MANAGER(manager));
! 464: /*
! 465: * We need at least one
! 466: */
! 467: for (i = 0; i < total_threads; i++) {
! 468: manager->hIOCPThreads[i] = CreateThread(NULL, 0, SocketIoThread,
! 469: manager, 0,
! 470: &manager->dwIOCPThreadIds[i]);
! 471: if (manager->hIOCPThreads[i] == NULL) {
! 472: errval = GetLastError();
! 473: isc__strerror(errval, strbuf, sizeof(strbuf));
! 474: FATAL_ERROR(__FILE__, __LINE__,
! 475: isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKET,
! 476: ISC_MSG_FAILED,
! 477: "Can't create IOCP thread: %s"),
! 478: strbuf);
! 479: exit(1);
! 480: }
! 481: }
! 482: }
! 483:
! 484: /*
! 485: * Create/initialise the I/O completion port
! 486: */
! 487: void
! 488: iocompletionport_init(isc_socketmgr_t *manager) {
! 489: int errval;
! 490: char strbuf[ISC_STRERRORSIZE];
! 491:
! 492: REQUIRE(VALID_MANAGER(manager));
! 493: /*
! 494: * Create a private heap to handle the socket overlapped structure
! 495: * The minimum number of structures is 10, there is no maximum
! 496: */
! 497: hHeapHandle = HeapCreate(0, 10 * sizeof(IoCompletionInfo), 0);
! 498: if (hHeapHandle == NULL) {
! 499: errval = GetLastError();
! 500: isc__strerror(errval, strbuf, sizeof(strbuf));
! 501: FATAL_ERROR(__FILE__, __LINE__,
! 502: isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKET,
! 503: ISC_MSG_FAILED,
! 504: "HeapCreate() failed during "
! 505: "initialization: %s"),
! 506: strbuf);
! 507: exit(1);
! 508: }
! 509:
! 510: manager->maxIOCPThreads = min(isc_os_ncpus() + 1, MAX_IOCPTHREADS);
! 511:
! 512: /* Now Create the Completion Port */
! 513: manager->hIoCompletionPort = CreateIoCompletionPort(
! 514: INVALID_HANDLE_VALUE, NULL,
! 515: 0, manager->maxIOCPThreads);
! 516: if (manager->hIoCompletionPort == NULL) {
! 517: errval = GetLastError();
! 518: isc__strerror(errval, strbuf, sizeof(strbuf));
! 519: FATAL_ERROR(__FILE__, __LINE__,
! 520: isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKET,
! 521: ISC_MSG_FAILED,
! 522: "CreateIoCompletionPort() failed "
! 523: "during initialization: %s"),
! 524: strbuf);
! 525: exit(1);
! 526: }
! 527:
! 528: /*
! 529: * Worker threads for servicing the I/O
! 530: */
! 531: iocompletionport_createthreads(manager->maxIOCPThreads, manager);
! 532: }
! 533:
! 534: /*
! 535: * Associate a socket with an IO Completion Port. This allows us to queue events for it
! 536: * and have our worker pool of threads process them.
! 537: */
! 538: void
! 539: iocompletionport_update(isc_socket_t *sock) {
! 540: HANDLE hiocp;
! 541: char strbuf[ISC_STRERRORSIZE];
! 542:
! 543: REQUIRE(VALID_SOCKET(sock));
! 544:
! 545: hiocp = CreateIoCompletionPort((HANDLE)sock->fd,
! 546: sock->manager->hIoCompletionPort, (ULONG_PTR)sock, 0);
! 547:
! 548: if (hiocp == NULL) {
! 549: DWORD errval = GetLastError();
! 550: isc__strerror(errval, strbuf, sizeof(strbuf));
! 551: isc_log_iwrite(isc_lctx,
! 552: ISC_LOGCATEGORY_GENERAL,
! 553: ISC_LOGMODULE_SOCKET, ISC_LOG_ERROR,
! 554: isc_msgcat, ISC_MSGSET_SOCKET,
! 555: ISC_MSG_TOOMANYHANDLES,
! 556: "iocompletionport_update: failed to open"
! 557: " io completion port: %s",
! 558: strbuf);
! 559:
! 560: /* XXXMLG temporary hack to make failures detected.
! 561: * This function should return errors to the caller, not
! 562: * exit here.
! 563: */
! 564: FATAL_ERROR(__FILE__, __LINE__,
! 565: isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKET,
! 566: ISC_MSG_FAILED,
! 567: "CreateIoCompletionPort() failed "
! 568: "during initialization: %s"),
! 569: strbuf);
! 570: exit(1);
! 571: }
! 572:
! 573: InterlockedIncrement(&sock->manager->iocp_total);
! 574: }
! 575:
! 576: /*
! 577: * Routine to cleanup and then close the socket.
! 578: * Only close the socket here if it is NOT associated
! 579: * with an event, otherwise the WSAWaitForMultipleEvents
! 580: * may fail due to the fact that the Wait should not
! 581: * be running while closing an event or a socket.
! 582: * The socket is locked before calling this function
! 583: */
! 584: void
! 585: socket_close(isc_socket_t *sock) {
! 586:
! 587: REQUIRE(sock != NULL);
! 588:
! 589: if (sock->fd != INVALID_SOCKET) {
! 590: closesocket(sock->fd);
! 591: sock->fd = INVALID_SOCKET;
! 592: _set_state(sock, SOCK_CLOSED);
! 593: InterlockedDecrement(&sock->manager->totalSockets);
! 594: }
! 595: }
! 596:
! 597: static isc_once_t initialise_once = ISC_ONCE_INIT;
! 598: static isc_boolean_t initialised = ISC_FALSE;
! 599:
! 600: static void
! 601: initialise(void) {
! 602: WORD wVersionRequested;
! 603: WSADATA wsaData;
! 604: int err;
! 605: SOCKET sock;
! 606: GUID GUIDConnectEx = WSAID_CONNECTEX;
! 607: GUID GUIDAcceptEx = WSAID_ACCEPTEX;
! 608: GUID GUIDGetAcceptExSockaddrs = WSAID_GETACCEPTEXSOCKADDRS;
! 609: DWORD dwBytes;
! 610:
! 611: /* Need Winsock 2.2 or better */
! 612: wVersionRequested = MAKEWORD(2, 2);
! 613:
! 614: err = WSAStartup(wVersionRequested, &wsaData);
! 615: if (err != 0) {
! 616: char strbuf[ISC_STRERRORSIZE];
! 617: isc__strerror(err, strbuf, sizeof(strbuf));
! 618: FATAL_ERROR(__FILE__, __LINE__, "WSAStartup() %s: %s",
! 619: isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
! 620: ISC_MSG_FAILED, "failed"),
! 621: strbuf);
! 622: exit(1);
! 623: }
! 624: /*
! 625: * The following APIs do not exist as functions in a library, but we must
! 626: * ask winsock for them. They are "extensions" -- but why they cannot be
! 627: * actual functions is beyond me. So, ask winsock for the pointers to the
! 628: * functions we need.
! 629: */
! 630: sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
! 631: INSIST(sock != INVALID_SOCKET);
! 632: err = WSAIoctl(sock, SIO_GET_EXTENSION_FUNCTION_POINTER,
! 633: &GUIDConnectEx, sizeof(GUIDConnectEx),
! 634: &ISCConnectEx, sizeof(ISCConnectEx),
! 635: &dwBytes, NULL, NULL);
! 636: INSIST(err == 0);
! 637:
! 638: err = WSAIoctl(sock, SIO_GET_EXTENSION_FUNCTION_POINTER,
! 639: &GUIDAcceptEx, sizeof(GUIDAcceptEx),
! 640: &ISCAcceptEx, sizeof(ISCAcceptEx),
! 641: &dwBytes, NULL, NULL);
! 642: INSIST(err == 0);
! 643:
! 644: err = WSAIoctl(sock, SIO_GET_EXTENSION_FUNCTION_POINTER,
! 645: &GUIDGetAcceptExSockaddrs, sizeof(GUIDGetAcceptExSockaddrs),
! 646: &ISCGetAcceptExSockaddrs, sizeof(ISCGetAcceptExSockaddrs),
! 647: &dwBytes, NULL, NULL);
! 648: INSIST(err == 0);
! 649:
! 650: closesocket(sock);
! 651:
! 652: initialised = ISC_TRUE;
! 653: }
! 654:
! 655: /*
! 656: * Initialize socket services
! 657: */
! 658: void
! 659: InitSockets(void) {
! 660: RUNTIME_CHECK(isc_once_do(&initialise_once,
! 661: initialise) == ISC_R_SUCCESS);
! 662: if (!initialised)
! 663: exit(1);
! 664: }
! 665:
! 666: int
! 667: internal_sendmsg(isc_socket_t *sock, IoCompletionInfo *lpo,
! 668: struct msghdr *messagehdr, int flags, int *Error)
! 669: {
! 670: int Result;
! 671: DWORD BytesSent;
! 672: DWORD Flags = flags;
! 673: int total_sent;
! 674:
! 675: *Error = 0;
! 676: Result = WSASendTo(sock->fd, messagehdr->msg_iov,
! 677: messagehdr->msg_iovlen, &BytesSent,
! 678: Flags, (SOCKADDR *)&messagehdr->to_addr,
! 679: messagehdr->to_addr_len, (LPWSAOVERLAPPED)lpo,
! 680: NULL);
! 681:
! 682: total_sent = (int)BytesSent;
! 683:
! 684: /* Check for errors.*/
! 685: if (Result == SOCKET_ERROR) {
! 686: *Error = WSAGetLastError();
! 687:
! 688: switch (*Error) {
! 689: case WSA_IO_INCOMPLETE:
! 690: case WSA_WAIT_IO_COMPLETION:
! 691: case WSA_IO_PENDING:
! 692: case NO_ERROR: /* Strange, but okay */
! 693: sock->pending_iocp++;
! 694: sock->pending_send++;
! 695: break;
! 696:
! 697: default:
! 698: return (-1);
! 699: break;
! 700: }
! 701: } else {
! 702: sock->pending_iocp++;
! 703: sock->pending_send++;
! 704: }
! 705:
! 706: if (lpo != NULL)
! 707: return (0);
! 708: else
! 709: return (total_sent);
! 710: }
! 711:
! 712: static void
! 713: queue_receive_request(isc_socket_t *sock) {
! 714: DWORD Flags = 0;
! 715: DWORD NumBytes = 0;
! 716: int total_bytes = 0;
! 717: int Result;
! 718: int Error;
! 719: WSABUF iov[1];
! 720: IoCompletionInfo *lpo;
! 721: isc_result_t isc_result;
! 722:
! 723: /*
! 724: * If we already have a receive pending, do nothing.
! 725: */
! 726: if (sock->pending_recv > 0)
! 727: return;
! 728:
! 729: /*
! 730: * If no one is waiting, do nothing.
! 731: */
! 732: if (ISC_LIST_EMPTY(sock->recv_list))
! 733: return;
! 734:
! 735: INSIST(sock->recvbuf.remaining == 0);
! 736: INSIST(sock->fd != INVALID_SOCKET);
! 737:
! 738: iov[0].len = sock->recvbuf.len;
! 739: iov[0].buf = sock->recvbuf.base;
! 740:
! 741: lpo = (IoCompletionInfo *)HeapAlloc(hHeapHandle,
! 742: HEAP_ZERO_MEMORY,
! 743: sizeof(IoCompletionInfo));
! 744: RUNTIME_CHECK(lpo != NULL);
! 745: lpo->request_type = SOCKET_RECV;
! 746:
! 747: sock->recvbuf.from_addr_len = sizeof(sock->recvbuf.from_addr);
! 748:
! 749: Error = 0;
! 750: Result = WSARecvFrom((SOCKET)sock->fd, iov, 1,
! 751: &NumBytes, &Flags,
! 752: (SOCKADDR *)&sock->recvbuf.from_addr,
! 753: &sock->recvbuf.from_addr_len,
! 754: (LPWSAOVERLAPPED)lpo, NULL);
! 755:
! 756: /* Check for errors. */
! 757: if (Result == SOCKET_ERROR) {
! 758: Error = WSAGetLastError();
! 759:
! 760: switch (Error) {
! 761: case WSA_IO_PENDING:
! 762: sock->pending_iocp++;
! 763: sock->pending_recv++;
! 764: break;
! 765:
! 766: default:
! 767: isc_result = isc__errno2result(Error);
! 768: if (isc_result == ISC_R_UNEXPECTED)
! 769: UNEXPECTED_ERROR(__FILE__, __LINE__,
! 770: "WSARecvFrom: Windows error code: %d, isc result %d",
! 771: Error, isc_result);
! 772: send_recvdone_abort(sock, isc_result);
! 773: break;
! 774: }
! 775: } else {
! 776: /*
! 777: * The recv() finished immediately, but we will still get
! 778: * a completion event. Rather than duplicate code, let
! 779: * that thread handle sending the data along its way.
! 780: */
! 781: sock->pending_iocp++;
! 782: sock->pending_recv++;
! 783: }
! 784:
! 785: socket_log(__LINE__, sock, NULL, IOEVENT,
! 786: isc_msgcat, ISC_MSGSET_SOCKET,
! 787: ISC_MSG_DOIORECV,
! 788: "queue_io_request: fd %d result %d error %d",
! 789: sock->fd, Result, Error);
! 790:
! 791: CONSISTENT(sock);
! 792: }
! 793:
! 794: static void
! 795: manager_log(isc_socketmgr_t *sockmgr, isc_logcategory_t *category,
! 796: isc_logmodule_t *module, int level, const char *fmt, ...)
! 797: {
! 798: char msgbuf[2048];
! 799: va_list ap;
! 800:
! 801: if (!isc_log_wouldlog(isc_lctx, level))
! 802: return;
! 803:
! 804: va_start(ap, fmt);
! 805: vsnprintf(msgbuf, sizeof(msgbuf), fmt, ap);
! 806: va_end(ap);
! 807:
! 808: isc_log_write(isc_lctx, category, module, level,
! 809: "sockmgr %p: %s", sockmgr, msgbuf);
! 810: }
! 811:
! 812: static void
! 813: socket_log(int lineno, isc_socket_t *sock, isc_sockaddr_t *address,
! 814: isc_logcategory_t *category, isc_logmodule_t *module, int level,
! 815: isc_msgcat_t *msgcat, int msgset, int message,
! 816: const char *fmt, ...)
! 817: {
! 818: char msgbuf[2048];
! 819: char peerbuf[256];
! 820: va_list ap;
! 821:
! 822:
! 823: if (!isc_log_wouldlog(isc_lctx, level))
! 824: return;
! 825:
! 826: va_start(ap, fmt);
! 827: vsnprintf(msgbuf, sizeof(msgbuf), fmt, ap);
! 828: va_end(ap);
! 829:
! 830: if (address == NULL) {
! 831: isc_log_iwrite(isc_lctx, category, module, level,
! 832: msgcat, msgset, message,
! 833: "socket %p line %d: %s", sock, lineno, msgbuf);
! 834: } else {
! 835: isc_sockaddr_format(address, peerbuf, sizeof(peerbuf));
! 836: isc_log_iwrite(isc_lctx, category, module, level,
! 837: msgcat, msgset, message,
! 838: "socket %p line %d peer %s: %s", sock, lineno,
! 839: peerbuf, msgbuf);
! 840: }
! 841:
! 842: }
! 843:
! 844: /*
! 845: * Make an fd SOCKET non-blocking.
! 846: */
! 847: static isc_result_t
! 848: make_nonblock(SOCKET fd) {
! 849: int ret;
! 850: unsigned long flags = 1;
! 851: char strbuf[ISC_STRERRORSIZE];
! 852:
! 853: /* Set the socket to non-blocking */
! 854: ret = ioctlsocket(fd, FIONBIO, &flags);
! 855:
! 856: if (ret == -1) {
! 857: isc__strerror(errno, strbuf, sizeof(strbuf));
! 858: UNEXPECTED_ERROR(__FILE__, __LINE__,
! 859: "ioctlsocket(%d, FIOBIO, %d): %s",
! 860: fd, flags, strbuf);
! 861:
! 862: return (ISC_R_UNEXPECTED);
! 863: }
! 864:
! 865: return (ISC_R_SUCCESS);
! 866: }
! 867:
! 868: /*
! 869: * Windows 2000 systems incorrectly cause UDP sockets using WASRecvFrom
! 870: * to not work correctly, returning a WSACONNRESET error when a WSASendTo
! 871: * fails with an "ICMP port unreachable" response and preventing the
! 872: * socket from using the WSARecvFrom in subsequent operations.
! 873: * The function below fixes this, but requires that Windows 2000
! 874: * Service Pack 2 or later be installed on the system. NT 4.0
! 875: * systems are not affected by this and work correctly.
! 876: * See Microsoft Knowledge Base Article Q263823 for details of this.
! 877: */
! 878: isc_result_t
! 879: connection_reset_fix(SOCKET fd) {
! 880: DWORD dwBytesReturned = 0;
! 881: BOOL bNewBehavior = FALSE;
! 882: DWORD status;
! 883:
! 884: if (isc_win32os_majorversion() < 5)
! 885: return (ISC_R_SUCCESS); /* NT 4.0 has no problem */
! 886:
! 887: /* disable bad behavior using IOCTL: SIO_UDP_CONNRESET */
! 888: status = WSAIoctl(fd, SIO_UDP_CONNRESET, &bNewBehavior,
! 889: sizeof(bNewBehavior), NULL, 0,
! 890: &dwBytesReturned, NULL, NULL);
! 891: if (status != SOCKET_ERROR)
! 892: return (ISC_R_SUCCESS);
! 893: else {
! 894: UNEXPECTED_ERROR(__FILE__, __LINE__,
! 895: "WSAIoctl(SIO_UDP_CONNRESET, oldBehaviour) %s",
! 896: isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
! 897: ISC_MSG_FAILED, "failed"));
! 898: return (ISC_R_UNEXPECTED);
! 899: }
! 900: }
! 901:
! 902: /*
! 903: * Construct an iov array and attach it to the msghdr passed in. This is
! 904: * the SEND constructor, which will use the used region of the buffer
! 905: * (if using a buffer list) or will use the internal region (if a single
! 906: * buffer I/O is requested).
! 907: *
! 908: * Nothing can be NULL, and the done event must list at least one buffer
! 909: * on the buffer linked list for this function to be meaningful.
! 910: */
! 911: static void
! 912: build_msghdr_send(isc_socket_t *sock, isc_socketevent_t *dev,
! 913: struct msghdr *msg, char *cmsg, WSABUF *iov,
! 914: IoCompletionInfo *lpo)
! 915: {
! 916: unsigned int iovcount;
! 917: isc_buffer_t *buffer;
! 918: buflist_t *cpbuffer;
! 919: isc_region_t used;
! 920: size_t write_count;
! 921: size_t skip_count;
! 922:
! 923: memset(msg, 0, sizeof(*msg));
! 924:
! 925: memcpy(&msg->to_addr, &dev->address.type, dev->address.length);
! 926: msg->to_addr_len = dev->address.length;
! 927:
! 928: buffer = ISC_LIST_HEAD(dev->bufferlist);
! 929: write_count = 0;
! 930: iovcount = 0;
! 931:
! 932: /*
! 933: * Single buffer I/O? Skip what we've done so far in this region.
! 934: */
! 935: if (buffer == NULL) {
! 936: write_count = dev->region.length - dev->n;
! 937: cpbuffer = HeapAlloc(hHeapHandle, HEAP_ZERO_MEMORY, sizeof(buflist_t));
! 938: RUNTIME_CHECK(cpbuffer != NULL);
! 939: cpbuffer->buf = HeapAlloc(hHeapHandle, HEAP_ZERO_MEMORY, write_count);
! 940: RUNTIME_CHECK(cpbuffer->buf != NULL);
! 941:
! 942: socket_log(__LINE__, sock, NULL, TRACE,
! 943: isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_ACCEPTLOCK,
! 944: "alloc_buffer %p %d %p %d", cpbuffer, sizeof(buflist_t),
! 945: cpbuffer->buf, write_count);
! 946:
! 947: memcpy(cpbuffer->buf,(dev->region.base + dev->n), write_count);
! 948: cpbuffer->buflen = write_count;
! 949: ISC_LIST_ENQUEUE(lpo->bufferlist, cpbuffer, link);
! 950: iov[0].buf = cpbuffer->buf;
! 951: iov[0].len = write_count;
! 952: iovcount = 1;
! 953:
! 954: goto config;
! 955: }
! 956:
! 957: /*
! 958: * Multibuffer I/O.
! 959: * Skip the data in the buffer list that we have already written.
! 960: */
! 961: skip_count = dev->n;
! 962: while (buffer != NULL) {
! 963: REQUIRE(ISC_BUFFER_VALID(buffer));
! 964: if (skip_count < isc_buffer_usedlength(buffer))
! 965: break;
! 966: skip_count -= isc_buffer_usedlength(buffer);
! 967: buffer = ISC_LIST_NEXT(buffer, link);
! 968: }
! 969:
! 970: while (buffer != NULL) {
! 971: INSIST(iovcount < MAXSCATTERGATHER_SEND);
! 972:
! 973: isc_buffer_usedregion(buffer, &used);
! 974:
! 975: if (used.length > 0) {
! 976: int uselen = used.length - skip_count;
! 977: cpbuffer = HeapAlloc(hHeapHandle, HEAP_ZERO_MEMORY, sizeof(buflist_t));
! 978: RUNTIME_CHECK(cpbuffer != NULL);
! 979: cpbuffer->buf = HeapAlloc(hHeapHandle, HEAP_ZERO_MEMORY, uselen);
! 980: RUNTIME_CHECK(cpbuffer->buf != NULL);
! 981:
! 982: socket_log(__LINE__, sock, NULL, TRACE,
! 983: isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_ACCEPTLOCK,
! 984: "alloc_buffer %p %d %p %d", cpbuffer, sizeof(buflist_t),
! 985: cpbuffer->buf, write_count);
! 986:
! 987: memcpy(cpbuffer->buf,(used.base + skip_count), uselen);
! 988: cpbuffer->buflen = uselen;
! 989: iov[iovcount].buf = cpbuffer->buf;
! 990: iov[iovcount].len = used.length - skip_count;
! 991: write_count += uselen;
! 992: skip_count = 0;
! 993: iovcount++;
! 994: }
! 995: buffer = ISC_LIST_NEXT(buffer, link);
! 996: }
! 997:
! 998: INSIST(skip_count == 0);
! 999:
! 1000: config:
! 1001: msg->msg_iov = iov;
! 1002: msg->msg_iovlen = iovcount;
! 1003: msg->msg_totallen = write_count;
! 1004: }
! 1005:
! 1006: static void
! 1007: set_dev_address(isc_sockaddr_t *address, isc_socket_t *sock,
! 1008: isc_socketevent_t *dev)
! 1009: {
! 1010: if (sock->type == isc_sockettype_udp) {
! 1011: if (address != NULL)
! 1012: dev->address = *address;
! 1013: else
! 1014: dev->address = sock->address;
! 1015: } else if (sock->type == isc_sockettype_tcp) {
! 1016: INSIST(address == NULL);
! 1017: dev->address = sock->address;
! 1018: }
! 1019: }
! 1020:
! 1021: static void
! 1022: destroy_socketevent(isc_event_t *event) {
! 1023: isc_socketevent_t *ev = (isc_socketevent_t *)event;
! 1024:
! 1025: INSIST(ISC_LIST_EMPTY(ev->bufferlist));
! 1026:
! 1027: (ev->destroy)(event);
! 1028: }
! 1029:
! 1030: static isc_socketevent_t *
! 1031: allocate_socketevent(isc_socket_t *sock, isc_eventtype_t eventtype,
! 1032: isc_taskaction_t action, const void *arg)
! 1033: {
! 1034: isc_socketevent_t *ev;
! 1035:
! 1036: ev = (isc_socketevent_t *)isc_event_allocate(sock->manager->mctx,
! 1037: sock, eventtype,
! 1038: action, arg,
! 1039: sizeof(*ev));
! 1040: if (ev == NULL)
! 1041: return (NULL);
! 1042:
! 1043: ev->result = ISC_R_IOERROR; // XXXMLG temporary change to detect failure to set
! 1044: ISC_LINK_INIT(ev, ev_link);
! 1045: ISC_LIST_INIT(ev->bufferlist);
! 1046: ev->region.base = NULL;
! 1047: ev->n = 0;
! 1048: ev->offset = 0;
! 1049: ev->attributes = 0;
! 1050: ev->destroy = ev->ev_destroy;
! 1051: ev->ev_destroy = destroy_socketevent;
! 1052:
! 1053: return (ev);
! 1054: }
! 1055:
! 1056: #if defined(ISC_SOCKET_DEBUG)
! 1057: static void
! 1058: dump_msg(struct msghdr *msg, isc_socket_t *sock) {
! 1059: unsigned int i;
! 1060:
! 1061: printf("MSGHDR %p, Socket #: %u\n", msg, sock->fd);
! 1062: printf("\tname %p, namelen %d\n", msg->msg_name, msg->msg_namelen);
! 1063: printf("\tiov %p, iovlen %d\n", msg->msg_iov, msg->msg_iovlen);
! 1064: for (i = 0; i < (unsigned int)msg->msg_iovlen; i++)
! 1065: printf("\t\t%d\tbase %p, len %d\n", i,
! 1066: msg->msg_iov[i].buf,
! 1067: msg->msg_iov[i].len);
! 1068: }
! 1069: #endif
! 1070:
! 1071: /*
! 1072: * map the error code
! 1073: */
! 1074: int
! 1075: map_socket_error(isc_socket_t *sock, int windows_errno, int *isc_errno,
! 1076: char *errorstring, size_t bufsize) {
! 1077:
! 1078: int doreturn;
! 1079: switch (windows_errno) {
! 1080: case WSAECONNREFUSED:
! 1081: *isc_errno = ISC_R_CONNREFUSED;
! 1082: if (sock->connected)
! 1083: doreturn = DOIO_HARD;
! 1084: else
! 1085: doreturn = DOIO_SOFT;
! 1086: break;
! 1087: case WSAENETUNREACH:
! 1088: case ERROR_NETWORK_UNREACHABLE:
! 1089: *isc_errno = ISC_R_NETUNREACH;
! 1090: if (sock->connected)
! 1091: doreturn = DOIO_HARD;
! 1092: else
! 1093: doreturn = DOIO_SOFT;
! 1094: break;
! 1095: case ERROR_PORT_UNREACHABLE:
! 1096: case ERROR_HOST_UNREACHABLE:
! 1097: case WSAEHOSTUNREACH:
! 1098: *isc_errno = ISC_R_HOSTUNREACH;
! 1099: if (sock->connected)
! 1100: doreturn = DOIO_HARD;
! 1101: else
! 1102: doreturn = DOIO_SOFT;
! 1103: break;
! 1104: case WSAENETDOWN:
! 1105: *isc_errno = ISC_R_NETDOWN;
! 1106: if (sock->connected)
! 1107: doreturn = DOIO_HARD;
! 1108: else
! 1109: doreturn = DOIO_SOFT;
! 1110: break;
! 1111: case WSAEHOSTDOWN:
! 1112: *isc_errno = ISC_R_HOSTDOWN;
! 1113: if (sock->connected)
! 1114: doreturn = DOIO_HARD;
! 1115: else
! 1116: doreturn = DOIO_SOFT;
! 1117: break;
! 1118: case WSAEACCES:
! 1119: *isc_errno = ISC_R_NOPERM;
! 1120: if (sock->connected)
! 1121: doreturn = DOIO_HARD;
! 1122: else
! 1123: doreturn = DOIO_SOFT;
! 1124: break;
! 1125: case WSAECONNRESET:
! 1126: case WSAENETRESET:
! 1127: case WSAECONNABORTED:
! 1128: case WSAEDISCON:
! 1129: *isc_errno = ISC_R_CONNECTIONRESET;
! 1130: if (sock->connected)
! 1131: doreturn = DOIO_HARD;
! 1132: else
! 1133: doreturn = DOIO_SOFT;
! 1134: break;
! 1135: case WSAENOTCONN:
! 1136: *isc_errno = ISC_R_NOTCONNECTED;
! 1137: if (sock->connected)
! 1138: doreturn = DOIO_HARD;
! 1139: else
! 1140: doreturn = DOIO_SOFT;
! 1141: break;
! 1142: case ERROR_OPERATION_ABORTED:
! 1143: case ERROR_CONNECTION_ABORTED:
! 1144: case ERROR_REQUEST_ABORTED:
! 1145: *isc_errno = ISC_R_CONNECTIONRESET;
! 1146: doreturn = DOIO_HARD;
! 1147: break;
! 1148: case WSAENOBUFS:
! 1149: *isc_errno = ISC_R_NORESOURCES;
! 1150: doreturn = DOIO_HARD;
! 1151: break;
! 1152: case WSAEAFNOSUPPORT:
! 1153: *isc_errno = ISC_R_FAMILYNOSUPPORT;
! 1154: doreturn = DOIO_HARD;
! 1155: break;
! 1156: case WSAEADDRNOTAVAIL:
! 1157: *isc_errno = ISC_R_ADDRNOTAVAIL;
! 1158: doreturn = DOIO_HARD;
! 1159: break;
! 1160: case WSAEDESTADDRREQ:
! 1161: *isc_errno = ISC_R_BADADDRESSFORM;
! 1162: doreturn = DOIO_HARD;
! 1163: break;
! 1164: case ERROR_NETNAME_DELETED:
! 1165: *isc_errno = ISC_R_NETDOWN;
! 1166: doreturn = DOIO_HARD;
! 1167: break;
! 1168: default:
! 1169: *isc_errno = ISC_R_IOERROR;
! 1170: doreturn = DOIO_HARD;
! 1171: break;
! 1172: }
! 1173: if (doreturn == DOIO_HARD) {
! 1174: isc__strerror(windows_errno, errorstring, bufsize);
! 1175: }
! 1176: return (doreturn);
! 1177: }
! 1178:
! 1179: static void
! 1180: fill_recv(isc_socket_t *sock, isc_socketevent_t *dev) {
! 1181: isc_region_t r;
! 1182: int copylen;
! 1183: isc_buffer_t *buffer;
! 1184:
! 1185: INSIST(dev->n < dev->minimum);
! 1186: INSIST(sock->recvbuf.remaining > 0);
! 1187: INSIST(sock->pending_recv == 0);
! 1188:
! 1189: if (sock->type == isc_sockettype_udp) {
! 1190: dev->address.length = sock->recvbuf.from_addr_len;
! 1191: memcpy(&dev->address.type, &sock->recvbuf.from_addr,
! 1192: sock->recvbuf.from_addr_len);
! 1193: if (isc_sockaddr_getport(&dev->address) == 0) {
! 1194: if (isc_log_wouldlog(isc_lctx, IOEVENT_LEVEL)) {
! 1195: socket_log(__LINE__, sock, &dev->address, IOEVENT,
! 1196: isc_msgcat, ISC_MSGSET_SOCKET,
! 1197: ISC_MSG_ZEROPORT,
! 1198: "dropping source port zero packet");
! 1199: }
! 1200: sock->recvbuf.remaining = 0;
! 1201: return;
! 1202: }
! 1203: } else if (sock->type == isc_sockettype_tcp) {
! 1204: dev->address = sock->address;
! 1205: }
! 1206:
! 1207: /*
! 1208: * Run through the list of buffers we were given, and find the
! 1209: * first one with space. Once it is found, loop through, filling
! 1210: * the buffers as much as possible.
! 1211: */
! 1212: buffer = ISC_LIST_HEAD(dev->bufferlist);
! 1213: if (buffer != NULL) { // Multi-buffer receive
! 1214: while (buffer != NULL && sock->recvbuf.remaining > 0) {
! 1215: REQUIRE(ISC_BUFFER_VALID(buffer));
! 1216: if (isc_buffer_availablelength(buffer) > 0) {
! 1217: isc_buffer_availableregion(buffer, &r);
! 1218: copylen = min(r.length, sock->recvbuf.remaining);
! 1219: memcpy(r.base, sock->recvbuf.consume_position, copylen);
! 1220: sock->recvbuf.consume_position += copylen;
! 1221: sock->recvbuf.remaining -= copylen;
! 1222: isc_buffer_add(buffer, copylen);
! 1223: dev->n += copylen;
! 1224: }
! 1225: buffer = ISC_LIST_NEXT(buffer, link);
! 1226: }
! 1227: } else { // Single-buffer receive
! 1228: copylen = min(dev->region.length - dev->n, sock->recvbuf.remaining);
! 1229: memcpy(dev->region.base + dev->n, sock->recvbuf.consume_position, copylen);
! 1230: sock->recvbuf.consume_position += copylen;
! 1231: sock->recvbuf.remaining -= copylen;
! 1232: dev->n += copylen;
! 1233: }
! 1234:
! 1235: /*
! 1236: * UDP receives are all-consuming. That is, if we have 4k worth of
! 1237: * data in our receive buffer, and the caller only gave us
! 1238: * 1k of space, we will toss the remaining 3k of data. TCP
! 1239: * will keep the extra data around and use it for later requests.
! 1240: */
! 1241: if (sock->type == isc_sockettype_udp)
! 1242: sock->recvbuf.remaining = 0;
! 1243: }
! 1244:
! 1245: /*
! 1246: * Copy out as much data from the internal buffer to done events.
! 1247: * As each done event is filled, send it along its way.
! 1248: */
! 1249: static void
! 1250: completeio_recv(isc_socket_t *sock)
! 1251: {
! 1252: isc_socketevent_t *dev;
! 1253:
! 1254: /*
! 1255: * If we are in the process of filling our buffer, we cannot
! 1256: * touch it yet, so don't.
! 1257: */
! 1258: if (sock->pending_recv > 0)
! 1259: return;
! 1260:
! 1261: while (sock->recvbuf.remaining > 0 && !ISC_LIST_EMPTY(sock->recv_list)) {
! 1262: dev = ISC_LIST_HEAD(sock->recv_list);
! 1263:
! 1264: /*
! 1265: * See if we have sufficient data in our receive buffer
! 1266: * to handle this. If we do, copy out the data.
! 1267: */
! 1268: fill_recv(sock, dev);
! 1269:
! 1270: /*
! 1271: * Did we satisfy it?
! 1272: */
! 1273: if (dev->n >= dev->minimum) {
! 1274: dev->result = ISC_R_SUCCESS;
! 1275: send_recvdone_event(sock, &dev);
! 1276: }
! 1277: }
! 1278: }
! 1279:
! 1280: /*
! 1281: * Returns:
! 1282: * DOIO_SUCCESS The operation succeeded. dev->result contains
! 1283: * ISC_R_SUCCESS.
! 1284: *
! 1285: * DOIO_HARD A hard or unexpected I/O error was encountered.
! 1286: * dev->result contains the appropriate error.
! 1287: *
! 1288: * DOIO_SOFT A soft I/O error was encountered. No senddone
! 1289: * event was sent. The operation should be retried.
! 1290: *
! 1291: * No other return values are possible.
! 1292: */
! 1293: static int
! 1294: completeio_send(isc_socket_t *sock, isc_socketevent_t *dev,
! 1295: struct msghdr *messagehdr, int cc, int send_errno)
! 1296: {
! 1297: char addrbuf[ISC_SOCKADDR_FORMATSIZE];
! 1298: char strbuf[ISC_STRERRORSIZE];
! 1299:
! 1300: if (send_errno != 0) {
! 1301: if (SOFT_ERROR(send_errno))
! 1302: return (DOIO_SOFT);
! 1303:
! 1304: return (map_socket_error(sock, send_errno, &dev->result,
! 1305: strbuf, sizeof(strbuf)));
! 1306:
! 1307: /*
! 1308: * The other error types depend on whether or not the
! 1309: * socket is UDP or TCP. If it is UDP, some errors
! 1310: * that we expect to be fatal under TCP are merely
! 1311: * annoying, and are really soft errors.
! 1312: *
! 1313: * However, these soft errors are still returned as
! 1314: * a status.
! 1315: */
! 1316: isc_sockaddr_format(&dev->address, addrbuf, sizeof(addrbuf));
! 1317: isc__strerror(send_errno, strbuf, sizeof(strbuf));
! 1318: UNEXPECTED_ERROR(__FILE__, __LINE__, "completeio_send: %s: %s",
! 1319: addrbuf, strbuf);
! 1320: dev->result = isc__errno2result(send_errno);
! 1321: return (DOIO_HARD);
! 1322: }
! 1323:
! 1324: /*
! 1325: * If we write less than we expected, update counters, poke.
! 1326: */
! 1327: dev->n += cc;
! 1328: if (cc != messagehdr->msg_totallen)
! 1329: return (DOIO_SOFT);
! 1330:
! 1331: /*
! 1332: * Exactly what we wanted to write. We're done with this
! 1333: * entry. Post its completion event.
! 1334: */
! 1335: dev->result = ISC_R_SUCCESS;
! 1336: return (DOIO_SUCCESS);
! 1337: }
! 1338:
! 1339: static int
! 1340: startio_send(isc_socket_t *sock, isc_socketevent_t *dev, int *nbytes,
! 1341: int *send_errno)
! 1342: {
! 1343: char *cmsg = NULL;
! 1344: char strbuf[ISC_STRERRORSIZE];
! 1345: IoCompletionInfo *lpo;
! 1346: int status;
! 1347: struct msghdr *msghdr;
! 1348:
! 1349: lpo = (IoCompletionInfo *)HeapAlloc(hHeapHandle,
! 1350: HEAP_ZERO_MEMORY,
! 1351: sizeof(IoCompletionInfo));
! 1352: RUNTIME_CHECK(lpo != NULL);
! 1353: lpo->request_type = SOCKET_SEND;
! 1354: lpo->dev = dev;
! 1355: msghdr = &lpo->messagehdr;
! 1356: memset(msghdr, 0, sizeof(struct msghdr));
! 1357: ISC_LIST_INIT(lpo->bufferlist);
! 1358:
! 1359: build_msghdr_send(sock, dev, msghdr, cmsg, sock->iov, lpo);
! 1360:
! 1361: *nbytes = internal_sendmsg(sock, lpo, msghdr, 0, send_errno);
! 1362:
! 1363: if (*nbytes < 0) {
! 1364: /*
! 1365: * I/O has been initiated
! 1366: * completion will be through the completion port
! 1367: */
! 1368: if (PENDING_ERROR(*send_errno)) {
! 1369: status = DOIO_PENDING;
! 1370: goto done;
! 1371: }
! 1372:
! 1373: if (SOFT_ERROR(*send_errno)) {
! 1374: status = DOIO_SOFT;
! 1375: goto done;
! 1376: }
! 1377:
! 1378: /*
! 1379: * If we got this far then something is wrong
! 1380: */
! 1381: if (isc_log_wouldlog(isc_lctx, IOEVENT_LEVEL)) {
! 1382: isc__strerror(*send_errno, strbuf, sizeof(strbuf));
! 1383: socket_log(__LINE__, sock, NULL, IOEVENT,
! 1384: isc_msgcat, ISC_MSGSET_SOCKET,
! 1385: ISC_MSG_INTERNALSEND,
! 1386: "startio_send: internal_sendmsg(%d) %d "
! 1387: "bytes, err %d/%s",
! 1388: sock->fd, *nbytes, *send_errno, strbuf);
! 1389: }
! 1390: goto done;
! 1391: }
! 1392: dev->result = ISC_R_SUCCESS;
! 1393: status = DOIO_SOFT;
! 1394: done:
! 1395: _set_state(sock, SOCK_DATA);
! 1396: return (status);
! 1397: }
! 1398:
! 1399: static isc_result_t
! 1400: allocate_socket(isc_socketmgr_t *manager, isc_sockettype_t type,
! 1401: isc_socket_t **socketp) {
! 1402: isc_socket_t *sock;
! 1403: isc_result_t result;
! 1404:
! 1405: sock = isc_mem_get(manager->mctx, sizeof(*sock));
! 1406:
! 1407: if (sock == NULL)
! 1408: return (ISC_R_NOMEMORY);
! 1409:
! 1410: sock->magic = 0;
! 1411: sock->references = 0;
! 1412:
! 1413: sock->manager = manager;
! 1414: sock->type = type;
! 1415: sock->fd = INVALID_SOCKET;
! 1416:
! 1417: ISC_LINK_INIT(sock, link);
! 1418:
! 1419: /*
! 1420: * set up list of readers and writers to be initially empty
! 1421: */
! 1422: ISC_LIST_INIT(sock->recv_list);
! 1423: ISC_LIST_INIT(sock->send_list);
! 1424: ISC_LIST_INIT(sock->accept_list);
! 1425: sock->connect_ev = NULL;
! 1426: sock->pending_accept = 0;
! 1427: sock->pending_recv = 0;
! 1428: sock->pending_send = 0;
! 1429: sock->pending_iocp = 0;
! 1430: sock->listener = 0;
! 1431: sock->connected = 0;
! 1432: sock->pending_connect = 0;
! 1433: sock->bound = 0;
! 1434: memset(sock->name, 0, sizeof(sock->name)); // zero the name field
! 1435: _set_state(sock, SOCK_INITIALIZED);
! 1436:
! 1437: sock->recvbuf.len = 65536;
! 1438: sock->recvbuf.consume_position = sock->recvbuf.base;
! 1439: sock->recvbuf.remaining = 0;
! 1440: sock->recvbuf.base = isc_mem_get(manager->mctx, sock->recvbuf.len); // max buffer size
! 1441: if (sock->recvbuf.base == NULL) {
! 1442: sock->magic = 0;
! 1443: goto error;
! 1444: }
! 1445:
! 1446: /*
! 1447: * initialize the lock
! 1448: */
! 1449: result = isc_mutex_init(&sock->lock);
! 1450: if (result != ISC_R_SUCCESS) {
! 1451: sock->magic = 0;
! 1452: isc_mem_put(manager->mctx, sock->recvbuf.base, sock->recvbuf.len);
! 1453: sock->recvbuf.base = NULL;
! 1454: goto error;
! 1455: }
! 1456:
! 1457: socket_log(__LINE__, sock, NULL, EVENT, NULL, 0, 0,
! 1458: "allocated");
! 1459:
! 1460: sock->magic = SOCKET_MAGIC;
! 1461: *socketp = sock;
! 1462:
! 1463: return (ISC_R_SUCCESS);
! 1464:
! 1465: error:
! 1466: isc_mem_put(manager->mctx, sock, sizeof(*sock));
! 1467:
! 1468: return (result);
! 1469: }
! 1470:
! 1471: /*
! 1472: * Verify that the socket state is consistent.
! 1473: */
! 1474: static void
! 1475: consistent(isc_socket_t *sock) {
! 1476:
! 1477: isc_socketevent_t *dev;
! 1478: isc_socket_newconnev_t *nev;
! 1479: unsigned int count;
! 1480: char *crash_reason;
! 1481: isc_boolean_t crash = ISC_FALSE;
! 1482:
! 1483: REQUIRE(sock->pending_iocp == sock->pending_recv + sock->pending_send
! 1484: + sock->pending_accept + sock->pending_connect);
! 1485:
! 1486: dev = ISC_LIST_HEAD(sock->send_list);
! 1487: count = 0;
! 1488: while (dev != NULL) {
! 1489: count++;
! 1490: dev = ISC_LIST_NEXT(dev, ev_link);
! 1491: }
! 1492: if (count > sock->pending_send) {
! 1493: crash = ISC_TRUE;
! 1494: crash_reason = "send_list > sock->pending_send";
! 1495: }
! 1496:
! 1497: nev = ISC_LIST_HEAD(sock->accept_list);
! 1498: count = 0;
! 1499: while (nev != NULL) {
! 1500: count++;
! 1501: nev = ISC_LIST_NEXT(nev, ev_link);
! 1502: }
! 1503: if (count > sock->pending_accept) {
! 1504: crash = ISC_TRUE;
! 1505: crash_reason = "send_list > sock->pending_send";
! 1506: }
! 1507:
! 1508: if (crash) {
! 1509: socket_log(__LINE__, sock, NULL, CREATION, isc_msgcat, ISC_MSGSET_SOCKET,
! 1510: ISC_MSG_DESTROYING, "SOCKET INCONSISTENT: %s",
! 1511: crash_reason);
! 1512: sock_dump(sock);
! 1513: INSIST(crash == ISC_FALSE);
! 1514: }
! 1515: }
! 1516:
! 1517: /*
! 1518: * Maybe free the socket.
! 1519: *
! 1520: * This function will verify tht the socket is no longer in use in any way,
! 1521: * either internally or externally. This is the only place where this
! 1522: * check is to be made; if some bit of code believes that IT is done with
! 1523: * the socket (e.g., some reference counter reaches zero), it should call
! 1524: * this function.
! 1525: *
! 1526: * When calling this function, the socket must be locked, and the manager
! 1527: * must be unlocked.
! 1528: *
! 1529: * When this function returns, *socketp will be NULL. No tricks to try
! 1530: * to hold on to this pointer are allowed.
! 1531: */
! 1532: static void
! 1533: maybe_free_socket(isc_socket_t **socketp, int lineno) {
! 1534: isc_socket_t *sock = *socketp;
! 1535: *socketp = NULL;
! 1536:
! 1537: INSIST(VALID_SOCKET(sock));
! 1538: CONSISTENT(sock);
! 1539:
! 1540: if (sock->pending_iocp > 0
! 1541: || sock->pending_recv > 0
! 1542: || sock->pending_send > 0
! 1543: || sock->pending_accept > 0
! 1544: || sock->references > 0
! 1545: || sock->pending_connect == 1
! 1546: || !ISC_LIST_EMPTY(sock->recv_list)
! 1547: || !ISC_LIST_EMPTY(sock->send_list)
! 1548: || !ISC_LIST_EMPTY(sock->accept_list)
! 1549: || sock->fd != INVALID_SOCKET) {
! 1550: UNLOCK(&sock->lock);
! 1551: return;
! 1552: }
! 1553: UNLOCK(&sock->lock);
! 1554:
! 1555: free_socket(&sock, lineno);
! 1556: }
! 1557:
! 1558: void
! 1559: free_socket(isc_socket_t **sockp, int lineno) {
! 1560: isc_socketmgr_t *manager;
! 1561: isc_socket_t *sock = *sockp;
! 1562: *sockp = NULL;
! 1563:
! 1564: manager = sock->manager;
! 1565:
! 1566: /*
! 1567: * Seems we can free the socket after all.
! 1568: */
! 1569: manager = sock->manager;
! 1570: socket_log(__LINE__, sock, NULL, CREATION, isc_msgcat, ISC_MSGSET_SOCKET,
! 1571: ISC_MSG_DESTROYING, "freeing socket line %d fd %d lock %p semaphore %p",
! 1572: lineno, sock->fd, &sock->lock, sock->lock.LockSemaphore);
! 1573:
! 1574: sock->magic = 0;
! 1575: DESTROYLOCK(&sock->lock);
! 1576:
! 1577: if (sock->recvbuf.base != NULL)
! 1578: isc_mem_put(manager->mctx, sock->recvbuf.base, sock->recvbuf.len);
! 1579:
! 1580: LOCK(&manager->lock);
! 1581: if (ISC_LINK_LINKED(sock, link))
! 1582: ISC_LIST_UNLINK(manager->socklist, sock, link);
! 1583: isc_mem_put(manager->mctx, sock, sizeof(*sock));
! 1584:
! 1585: if (ISC_LIST_EMPTY(manager->socklist))
! 1586: SIGNAL(&manager->shutdown_ok);
! 1587: UNLOCK(&manager->lock);
! 1588: }
! 1589:
! 1590: /*
! 1591: * Create a new 'type' socket managed by 'manager'. Events
! 1592: * will be posted to 'task' and when dispatched 'action' will be
! 1593: * called with 'arg' as the arg value. The new socket is returned
! 1594: * in 'socketp'.
! 1595: */
! 1596: isc_result_t
! 1597: isc_socket_create(isc_socketmgr_t *manager, int pf, isc_sockettype_t type,
! 1598: isc_socket_t **socketp) {
! 1599: isc_socket_t *sock = NULL;
! 1600: isc_result_t result;
! 1601: #if defined(USE_CMSG)
! 1602: int on = 1;
! 1603: #endif
! 1604: #if defined(SO_RCVBUF)
! 1605: ISC_SOCKADDR_LEN_T optlen;
! 1606: int size;
! 1607: #endif
! 1608: int socket_errno;
! 1609: char strbuf[ISC_STRERRORSIZE];
! 1610:
! 1611: REQUIRE(VALID_MANAGER(manager));
! 1612: REQUIRE(socketp != NULL && *socketp == NULL);
! 1613: REQUIRE(type != isc_sockettype_fdwatch);
! 1614:
! 1615: result = allocate_socket(manager, type, &sock);
! 1616: if (result != ISC_R_SUCCESS)
! 1617: return (result);
! 1618:
! 1619: sock->pf = pf;
! 1620: switch (type) {
! 1621: case isc_sockettype_udp:
! 1622: sock->fd = socket(pf, SOCK_DGRAM, IPPROTO_UDP);
! 1623: if (sock->fd != INVALID_SOCKET) {
! 1624: result = connection_reset_fix(sock->fd);
! 1625: if (result != ISC_R_SUCCESS) {
! 1626: socket_log(__LINE__, sock, NULL, EVENT, NULL, 0, 0,
! 1627: "closed %d %d %d con_reset_fix_failed",
! 1628: sock->pending_recv, sock->pending_send,
! 1629: sock->references);
! 1630: closesocket(sock->fd);
! 1631: _set_state(sock, SOCK_CLOSED);
! 1632: sock->fd = INVALID_SOCKET;
! 1633: free_socket(&sock, __LINE__);
! 1634: return (result);
! 1635: }
! 1636: }
! 1637: break;
! 1638: case isc_sockettype_tcp:
! 1639: sock->fd = socket(pf, SOCK_STREAM, IPPROTO_TCP);
! 1640: break;
! 1641: }
! 1642:
! 1643: if (sock->fd == INVALID_SOCKET) {
! 1644: socket_errno = WSAGetLastError();
! 1645: free_socket(&sock, __LINE__);
! 1646:
! 1647: switch (socket_errno) {
! 1648: case WSAEMFILE:
! 1649: case WSAENOBUFS:
! 1650: return (ISC_R_NORESOURCES);
! 1651:
! 1652: case WSAEPROTONOSUPPORT:
! 1653: case WSAEPFNOSUPPORT:
! 1654: case WSAEAFNOSUPPORT:
! 1655: return (ISC_R_FAMILYNOSUPPORT);
! 1656:
! 1657: default:
! 1658: isc__strerror(socket_errno, strbuf, sizeof(strbuf));
! 1659: UNEXPECTED_ERROR(__FILE__, __LINE__,
! 1660: "socket() %s: %s",
! 1661: isc_msgcat_get(isc_msgcat,
! 1662: ISC_MSGSET_GENERAL,
! 1663: ISC_MSG_FAILED,
! 1664: "failed"),
! 1665: strbuf);
! 1666: return (ISC_R_UNEXPECTED);
! 1667: }
! 1668: }
! 1669:
! 1670: result = make_nonblock(sock->fd);
! 1671: if (result != ISC_R_SUCCESS) {
! 1672: socket_log(__LINE__, sock, NULL, EVENT, NULL, 0, 0,
! 1673: "closed %d %d %d make_nonblock_failed",
! 1674: sock->pending_recv, sock->pending_send,
! 1675: sock->references);
! 1676: closesocket(sock->fd);
! 1677: sock->fd = INVALID_SOCKET;
! 1678: free_socket(&sock, __LINE__);
! 1679: return (result);
! 1680: }
! 1681:
! 1682:
! 1683: #if defined(USE_CMSG) || defined(SO_RCVBUF)
! 1684: if (type == isc_sockettype_udp) {
! 1685:
! 1686: #if defined(USE_CMSG)
! 1687: #if defined(ISC_PLATFORM_HAVEIPV6)
! 1688: #ifdef IPV6_RECVPKTINFO
! 1689: /* 2292bis */
! 1690: if ((pf == AF_INET6)
! 1691: && (setsockopt(sock->fd, IPPROTO_IPV6, IPV6_RECVPKTINFO,
! 1692: (void *)&on, sizeof(on)) < 0)) {
! 1693: isc__strerror(WSAGetLastError(), strbuf, sizeof(strbuf));
! 1694: UNEXPECTED_ERROR(__FILE__, __LINE__,
! 1695: "setsockopt(%d, IPV6_RECVPKTINFO) "
! 1696: "%s: %s", sock->fd,
! 1697: isc_msgcat_get(isc_msgcat,
! 1698: ISC_MSGSET_GENERAL,
! 1699: ISC_MSG_FAILED,
! 1700: "failed"),
! 1701: strbuf);
! 1702: }
! 1703: #else
! 1704: /* 2292 */
! 1705: if ((pf == AF_INET6)
! 1706: && (setsockopt(sock->fd, IPPROTO_IPV6, IPV6_PKTINFO,
! 1707: (void *)&on, sizeof(on)) < 0)) {
! 1708: isc__strerror(WSAGetLastError(), strbuf, sizeof(strbuf));
! 1709: UNEXPECTED_ERROR(__FILE__, __LINE__,
! 1710: "setsockopt(%d, IPV6_PKTINFO) %s: %s",
! 1711: sock->fd,
! 1712: isc_msgcat_get(isc_msgcat,
! 1713: ISC_MSGSET_GENERAL,
! 1714: ISC_MSG_FAILED,
! 1715: "failed"),
! 1716: strbuf);
! 1717: }
! 1718: #endif /* IPV6_RECVPKTINFO */
! 1719: #ifdef IPV6_USE_MIN_MTU /*2292bis, not too common yet*/
! 1720: /* use minimum MTU */
! 1721: if (pf == AF_INET6) {
! 1722: (void)setsockopt(sock->fd, IPPROTO_IPV6,
! 1723: IPV6_USE_MIN_MTU,
! 1724: (void *)&on, sizeof(on));
! 1725: }
! 1726: #endif
! 1727: #endif /* ISC_PLATFORM_HAVEIPV6 */
! 1728: #endif /* defined(USE_CMSG) */
! 1729:
! 1730: #if defined(SO_RCVBUF)
! 1731: optlen = sizeof(size);
! 1732: if (getsockopt(sock->fd, SOL_SOCKET, SO_RCVBUF,
! 1733: (void *)&size, &optlen) >= 0 &&
! 1734: size < RCVBUFSIZE) {
! 1735: size = RCVBUFSIZE;
! 1736: (void)setsockopt(sock->fd, SOL_SOCKET, SO_RCVBUF,
! 1737: (void *)&size, sizeof(size));
! 1738: }
! 1739: #endif
! 1740:
! 1741: }
! 1742: #endif /* defined(USE_CMSG) || defined(SO_RCVBUF) */
! 1743:
! 1744: _set_state(sock, SOCK_OPEN);
! 1745: sock->references = 1;
! 1746: *socketp = sock;
! 1747:
! 1748: iocompletionport_update(sock);
! 1749:
! 1750: /*
! 1751: * Note we don't have to lock the socket like we normally would because
! 1752: * there are no external references to it yet.
! 1753: */
! 1754: LOCK(&manager->lock);
! 1755: ISC_LIST_APPEND(manager->socklist, sock, link);
! 1756: InterlockedIncrement(&manager->totalSockets);
! 1757: UNLOCK(&manager->lock);
! 1758:
! 1759: socket_log(__LINE__, sock, NULL, CREATION, isc_msgcat, ISC_MSGSET_SOCKET,
! 1760: ISC_MSG_CREATED, "created %u type %u", sock->fd, type);
! 1761:
! 1762: return (ISC_R_SUCCESS);
! 1763: }
! 1764:
! 1765: isc_result_t
! 1766: isc_socket_open(isc_socket_t *sock) {
! 1767: REQUIRE(VALID_SOCKET(sock));
! 1768: REQUIRE(sock->type != isc_sockettype_fdwatch);
! 1769:
! 1770: return (ISC_R_NOTIMPLEMENTED);
! 1771: }
! 1772:
! 1773: /*
! 1774: * Attach to a socket. Caller must explicitly detach when it is done.
! 1775: */
! 1776: void
! 1777: isc_socket_attach(isc_socket_t *sock, isc_socket_t **socketp) {
! 1778: REQUIRE(VALID_SOCKET(sock));
! 1779: REQUIRE(socketp != NULL && *socketp == NULL);
! 1780:
! 1781: LOCK(&sock->lock);
! 1782: CONSISTENT(sock);
! 1783: sock->references++;
! 1784: UNLOCK(&sock->lock);
! 1785:
! 1786: *socketp = sock;
! 1787: }
! 1788:
! 1789: /*
! 1790: * Dereference a socket. If this is the last reference to it, clean things
! 1791: * up by destroying the socket.
! 1792: */
! 1793: void
! 1794: isc_socket_detach(isc_socket_t **socketp) {
! 1795: isc_socket_t *sock;
! 1796: isc_boolean_t kill_socket = ISC_FALSE;
! 1797:
! 1798: REQUIRE(socketp != NULL);
! 1799: sock = *socketp;
! 1800: REQUIRE(VALID_SOCKET(sock));
! 1801: REQUIRE(sock->type != isc_sockettype_fdwatch);
! 1802:
! 1803: LOCK(&sock->lock);
! 1804: CONSISTENT(sock);
! 1805: REQUIRE(sock->references > 0);
! 1806: sock->references--;
! 1807:
! 1808: socket_log(__LINE__, sock, NULL, EVENT, NULL, 0, 0,
! 1809: "detach_socket %d %d %d",
! 1810: sock->pending_recv, sock->pending_send,
! 1811: sock->references);
! 1812:
! 1813: if (sock->references == 0 && sock->fd != INVALID_SOCKET) {
! 1814: closesocket(sock->fd);
! 1815: sock->fd = INVALID_SOCKET;
! 1816: _set_state(sock, SOCK_CLOSED);
! 1817: }
! 1818:
! 1819: maybe_free_socket(&sock, __LINE__);
! 1820:
! 1821: *socketp = NULL;
! 1822: }
! 1823:
! 1824: isc_result_t
! 1825: isc_socket_close(isc_socket_t *sock) {
! 1826: REQUIRE(VALID_SOCKET(sock));
! 1827: REQUIRE(sock->type != isc_sockettype_fdwatch);
! 1828:
! 1829: return (ISC_R_NOTIMPLEMENTED);
! 1830: }
! 1831:
! 1832: /*
! 1833: * Dequeue an item off the given socket's read queue, set the result code
! 1834: * in the done event to the one provided, and send it to the task it was
! 1835: * destined for.
! 1836: *
! 1837: * If the event to be sent is on a list, remove it before sending. If
! 1838: * asked to, send and detach from the task as well.
! 1839: *
! 1840: * Caller must have the socket locked if the event is attached to the socket.
! 1841: */
! 1842: static void
! 1843: send_recvdone_event(isc_socket_t *sock, isc_socketevent_t **dev) {
! 1844: isc_task_t *task;
! 1845:
! 1846: task = (*dev)->ev_sender;
! 1847: (*dev)->ev_sender = sock;
! 1848:
! 1849: if (ISC_LINK_LINKED(*dev, ev_link))
! 1850: ISC_LIST_DEQUEUE(sock->recv_list, *dev, ev_link);
! 1851:
! 1852: if (((*dev)->attributes & ISC_SOCKEVENTATTR_ATTACHED)
! 1853: == ISC_SOCKEVENTATTR_ATTACHED)
! 1854: isc_task_sendanddetach(&task, (isc_event_t **)dev);
! 1855: else
! 1856: isc_task_send(task, (isc_event_t **)dev);
! 1857:
! 1858: CONSISTENT(sock);
! 1859: }
! 1860:
! 1861: /*
! 1862: * See comments for send_recvdone_event() above.
! 1863: */
! 1864: static void
! 1865: send_senddone_event(isc_socket_t *sock, isc_socketevent_t **dev) {
! 1866: isc_task_t *task;
! 1867:
! 1868: INSIST(dev != NULL && *dev != NULL);
! 1869:
! 1870: task = (*dev)->ev_sender;
! 1871: (*dev)->ev_sender = sock;
! 1872:
! 1873: if (ISC_LINK_LINKED(*dev, ev_link))
! 1874: ISC_LIST_DEQUEUE(sock->send_list, *dev, ev_link);
! 1875:
! 1876: if (((*dev)->attributes & ISC_SOCKEVENTATTR_ATTACHED)
! 1877: == ISC_SOCKEVENTATTR_ATTACHED)
! 1878: isc_task_sendanddetach(&task, (isc_event_t **)dev);
! 1879: else
! 1880: isc_task_send(task, (isc_event_t **)dev);
! 1881:
! 1882: CONSISTENT(sock);
! 1883: }
! 1884:
! 1885: /*
! 1886: * See comments for send_recvdone_event() above.
! 1887: */
! 1888: static void
! 1889: send_acceptdone_event(isc_socket_t *sock, isc_socket_newconnev_t **adev) {
! 1890: isc_task_t *task;
! 1891:
! 1892: INSIST(adev != NULL && *adev != NULL);
! 1893:
! 1894: task = (*adev)->ev_sender;
! 1895: (*adev)->ev_sender = sock;
! 1896:
! 1897: if (ISC_LINK_LINKED(*adev, ev_link))
! 1898: ISC_LIST_DEQUEUE(sock->accept_list, *adev, ev_link);
! 1899:
! 1900: isc_task_sendanddetach(&task, (isc_event_t **)adev);
! 1901:
! 1902: CONSISTENT(sock);
! 1903: }
! 1904:
! 1905: /*
! 1906: * See comments for send_recvdone_event() above.
! 1907: */
! 1908: static void
! 1909: send_connectdone_event(isc_socket_t *sock, isc_socket_connev_t **cdev) {
! 1910: isc_task_t *task;
! 1911:
! 1912: INSIST(cdev != NULL && *cdev != NULL);
! 1913:
! 1914: task = (*cdev)->ev_sender;
! 1915: (*cdev)->ev_sender = sock;
! 1916:
! 1917: sock->connect_ev = NULL;
! 1918:
! 1919: isc_task_sendanddetach(&task, (isc_event_t **)cdev);
! 1920:
! 1921: CONSISTENT(sock);
! 1922: }
! 1923:
! 1924: /*
! 1925: * On entry to this function, the event delivered is the internal
! 1926: * readable event, and the first item on the accept_list should be
! 1927: * the done event we want to send. If the list is empty, this is a no-op,
! 1928: * so just close the new connection, unlock, and return.
! 1929: *
! 1930: * Note the socket is locked before entering here
! 1931: */
! 1932: static void
! 1933: internal_accept(isc_socket_t *sock, IoCompletionInfo *lpo, int accept_errno) {
! 1934: isc_socket_newconnev_t *adev;
! 1935: isc_result_t result = ISC_R_SUCCESS;
! 1936: isc_socket_t *nsock;
! 1937: struct sockaddr *localaddr;
! 1938: int localaddr_len = sizeof(*localaddr);
! 1939: struct sockaddr *remoteaddr;
! 1940: int remoteaddr_len = sizeof(*remoteaddr);
! 1941:
! 1942: INSIST(VALID_SOCKET(sock));
! 1943: LOCK(&sock->lock);
! 1944: CONSISTENT(sock);
! 1945:
! 1946: socket_log(__LINE__, sock, NULL, TRACE,
! 1947: isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_ACCEPTLOCK,
! 1948: "internal_accept called");
! 1949:
! 1950: INSIST(sock->listener);
! 1951:
! 1952: INSIST(sock->pending_iocp > 0);
! 1953: sock->pending_iocp--;
! 1954: INSIST(sock->pending_accept > 0);
! 1955: sock->pending_accept--;
! 1956:
! 1957: adev = lpo->adev;
! 1958:
! 1959: /*
! 1960: * If the event is no longer in the list we can just return.
! 1961: */
! 1962: if (!acceptdone_is_active(sock, adev))
! 1963: goto done;
! 1964:
! 1965: nsock = adev->newsocket;
! 1966:
! 1967: /*
! 1968: * Pull off the done event.
! 1969: */
! 1970: ISC_LIST_UNLINK(sock->accept_list, adev, ev_link);
! 1971:
! 1972: /*
! 1973: * Extract the addresses from the socket, copy them into the structure,
! 1974: * and return the new socket.
! 1975: */
! 1976: ISCGetAcceptExSockaddrs(lpo->acceptbuffer, 0,
! 1977: sizeof(SOCKADDR_STORAGE) + 16, sizeof(SOCKADDR_STORAGE) + 16,
! 1978: (LPSOCKADDR *)&localaddr, &localaddr_len,
! 1979: (LPSOCKADDR *)&remoteaddr, &remoteaddr_len);
! 1980: memcpy(&adev->address.type, remoteaddr, remoteaddr_len);
! 1981: adev->address.length = remoteaddr_len;
! 1982: nsock->address = adev->address;
! 1983: nsock->pf = adev->address.type.sa.sa_family;
! 1984:
! 1985: socket_log(__LINE__, nsock, &nsock->address, TRACE,
! 1986: isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_ACCEPTLOCK,
! 1987: "internal_accept parent %p", sock);
! 1988:
! 1989: result = make_nonblock(adev->newsocket->fd);
! 1990: INSIST(result == ISC_R_SUCCESS);
! 1991:
! 1992: INSIST(setsockopt(nsock->fd, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT,
! 1993: (char *)&sock->fd, sizeof(sock->fd)) == 0);
! 1994:
! 1995: /*
! 1996: * Hook it up into the manager.
! 1997: */
! 1998: nsock->bound = 1;
! 1999: nsock->connected = 1;
! 2000: _set_state(nsock, SOCK_OPEN);
! 2001:
! 2002: LOCK(&nsock->manager->lock);
! 2003: ISC_LIST_APPEND(nsock->manager->socklist, nsock, link);
! 2004: InterlockedIncrement(&nsock->manager->totalSockets);
! 2005: UNLOCK(&nsock->manager->lock);
! 2006:
! 2007: socket_log(__LINE__, sock, &nsock->address, CREATION,
! 2008: isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_ACCEPTEDCXN,
! 2009: "accepted_connection new_socket %p fd %d",
! 2010: nsock, nsock->fd);
! 2011:
! 2012: adev->result = result;
! 2013: send_acceptdone_event(sock, &adev);
! 2014:
! 2015: done:
! 2016: CONSISTENT(sock);
! 2017: UNLOCK(&sock->lock);
! 2018:
! 2019: HeapFree(hHeapHandle, 0, lpo->acceptbuffer);
! 2020: lpo->acceptbuffer = NULL;
! 2021: }
! 2022:
! 2023: /*
! 2024: * Called when a socket with a pending connect() finishes.
! 2025: * Note that the socket is locked before entering.
! 2026: */
! 2027: static void
! 2028: internal_connect(isc_socket_t *sock, IoCompletionInfo *lpo, int connect_errno) {
! 2029: isc_socket_connev_t *cdev;
! 2030: char strbuf[ISC_STRERRORSIZE];
! 2031:
! 2032: INSIST(VALID_SOCKET(sock));
! 2033:
! 2034: LOCK(&sock->lock);
! 2035:
! 2036: INSIST(sock->pending_iocp > 0);
! 2037: sock->pending_iocp--;
! 2038: INSIST(sock->pending_connect == 1);
! 2039: sock->pending_connect = 0;
! 2040:
! 2041: /*
! 2042: * Has this event been canceled?
! 2043: */
! 2044: cdev = lpo->cdev;
! 2045: if (!connectdone_is_active(sock, cdev)) {
! 2046: sock->pending_connect = 0;
! 2047: if (sock->fd != INVALID_SOCKET) {
! 2048: closesocket(sock->fd);
! 2049: sock->fd = INVALID_SOCKET;
! 2050: _set_state(sock, SOCK_CLOSED);
! 2051: }
! 2052: CONSISTENT(sock);
! 2053: UNLOCK(&sock->lock);
! 2054: return;
! 2055: }
! 2056:
! 2057: /*
! 2058: * Check possible Windows network event error status here.
! 2059: */
! 2060: if (connect_errno != 0) {
! 2061: /*
! 2062: * If the error is SOFT, just try again on this
! 2063: * fd and pretend nothing strange happened.
! 2064: */
! 2065: if (SOFT_ERROR(connect_errno) ||
! 2066: connect_errno == WSAEINPROGRESS) {
! 2067: sock->pending_connect = 1;
! 2068: CONSISTENT(sock);
! 2069: UNLOCK(&sock->lock);
! 2070: return;
! 2071: }
! 2072:
! 2073: /*
! 2074: * Translate other errors into ISC_R_* flavors.
! 2075: */
! 2076: switch (connect_errno) {
! 2077: #define ERROR_MATCH(a, b) case a: cdev->result = b; break;
! 2078: ERROR_MATCH(WSAEACCES, ISC_R_NOPERM);
! 2079: ERROR_MATCH(WSAEADDRNOTAVAIL, ISC_R_ADDRNOTAVAIL);
! 2080: ERROR_MATCH(WSAEAFNOSUPPORT, ISC_R_ADDRNOTAVAIL);
! 2081: ERROR_MATCH(WSAECONNREFUSED, ISC_R_CONNREFUSED);
! 2082: ERROR_MATCH(WSAEHOSTUNREACH, ISC_R_HOSTUNREACH);
! 2083: ERROR_MATCH(WSAEHOSTDOWN, ISC_R_HOSTDOWN);
! 2084: ERROR_MATCH(WSAENETUNREACH, ISC_R_NETUNREACH);
! 2085: ERROR_MATCH(WSAENETDOWN, ISC_R_NETDOWN);
! 2086: ERROR_MATCH(WSAENOBUFS, ISC_R_NORESOURCES);
! 2087: ERROR_MATCH(WSAECONNRESET, ISC_R_CONNECTIONRESET);
! 2088: ERROR_MATCH(WSAECONNABORTED, ISC_R_CONNECTIONRESET);
! 2089: ERROR_MATCH(WSAETIMEDOUT, ISC_R_TIMEDOUT);
! 2090: #undef ERROR_MATCH
! 2091: default:
! 2092: cdev->result = ISC_R_UNEXPECTED;
! 2093: isc__strerror(connect_errno, strbuf, sizeof(strbuf));
! 2094: UNEXPECTED_ERROR(__FILE__, __LINE__,
! 2095: "internal_connect: connect() %s",
! 2096: strbuf);
! 2097: }
! 2098: } else {
! 2099: INSIST(setsockopt(sock->fd, SOL_SOCKET, SO_UPDATE_CONNECT_CONTEXT, NULL, 0) == 0);
! 2100: cdev->result = ISC_R_SUCCESS;
! 2101: sock->connected = 1;
! 2102: socket_log(__LINE__, sock, &sock->address, IOEVENT,
! 2103: isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_ACCEPTEDCXN,
! 2104: "internal_connect: success");
! 2105: }
! 2106:
! 2107: send_connectdone_event(sock, &cdev);
! 2108:
! 2109: UNLOCK(&sock->lock);
! 2110: }
! 2111:
! 2112: /*
! 2113: * Loop through the socket, returning ISC_R_EOF for each done event pending.
! 2114: */
! 2115: static void
! 2116: send_recvdone_abort(isc_socket_t *sock, isc_result_t result) {
! 2117: isc_socketevent_t *dev;
! 2118:
! 2119: while (!ISC_LIST_EMPTY(sock->recv_list)) {
! 2120: dev = ISC_LIST_HEAD(sock->recv_list);
! 2121: dev->result = result;
! 2122: send_recvdone_event(sock, &dev);
! 2123: }
! 2124: }
! 2125:
! 2126: /*
! 2127: * Take the data we received in our private buffer, and if any recv() calls on
! 2128: * our list are satisfied, send the corresponding done event.
! 2129: *
! 2130: * If we need more data (there are still items on the recv_list after we consume all
! 2131: * our data) then arrange for another system recv() call to fill our buffers.
! 2132: */
! 2133: static void
! 2134: internal_recv(isc_socket_t *sock, int nbytes)
! 2135: {
! 2136: INSIST(VALID_SOCKET(sock));
! 2137:
! 2138: LOCK(&sock->lock);
! 2139: CONSISTENT(sock);
! 2140:
! 2141: socket_log(__LINE__, sock, NULL, IOEVENT,
! 2142: isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_INTERNALRECV,
! 2143: "internal_recv: %d bytes received", nbytes);
! 2144:
! 2145: /*
! 2146: * If we got here, the I/O operation succeeded. However, we might still have removed this
! 2147: * event from our notification list (or never placed it on it due to immediate completion.)
! 2148: * Handle the reference counting here, and handle the cancellation event just after.
! 2149: */
! 2150: INSIST(sock->pending_iocp > 0);
! 2151: sock->pending_iocp--;
! 2152: INSIST(sock->pending_recv > 0);
! 2153: sock->pending_recv--;
! 2154:
! 2155: /*
! 2156: * The only way we could have gotten here is that our I/O has successfully completed.
! 2157: * Update our pointers, and move on. The only odd case here is that we might not
! 2158: * have received enough data on a TCP stream to satisfy the minimum requirements. If
! 2159: * this is the case, we will re-issue the recv() call for what we need.
! 2160: *
! 2161: * We do check for a recv() of 0 bytes on a TCP stream. This means the remote end
! 2162: * has closed.
! 2163: */
! 2164: if (nbytes == 0 && sock->type == isc_sockettype_tcp) {
! 2165: send_recvdone_abort(sock, ISC_R_EOF);
! 2166: maybe_free_socket(&sock, __LINE__);
! 2167: return;
! 2168: }
! 2169: sock->recvbuf.remaining = nbytes;
! 2170: sock->recvbuf.consume_position = sock->recvbuf.base;
! 2171: completeio_recv(sock);
! 2172:
! 2173: /*
! 2174: * If there are more receivers waiting for data, queue another receive
! 2175: * here.
! 2176: */
! 2177: queue_receive_request(sock);
! 2178:
! 2179: /*
! 2180: * Unlock and/or destroy if we are the last thing this socket has left to do.
! 2181: */
! 2182: maybe_free_socket(&sock, __LINE__);
! 2183: }
! 2184:
! 2185: static void
! 2186: internal_send(isc_socket_t *sock, isc_socketevent_t *dev,
! 2187: struct msghdr *messagehdr, int nbytes, int send_errno, IoCompletionInfo *lpo)
! 2188: {
! 2189: buflist_t *buffer;
! 2190:
! 2191: /*
! 2192: * Find out what socket this is and lock it.
! 2193: */
! 2194: INSIST(VALID_SOCKET(sock));
! 2195:
! 2196: LOCK(&sock->lock);
! 2197: CONSISTENT(sock);
! 2198:
! 2199: socket_log(__LINE__, sock, NULL, IOEVENT,
! 2200: isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_INTERNALSEND,
! 2201: "internal_send: task got socket event %p", dev);
! 2202:
! 2203: buffer = ISC_LIST_HEAD(lpo->bufferlist);
! 2204: while (buffer != NULL) {
! 2205: ISC_LIST_DEQUEUE(lpo->bufferlist, buffer, link);
! 2206:
! 2207: socket_log(__LINE__, sock, NULL, TRACE,
! 2208: isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_ACCEPTLOCK,
! 2209: "free_buffer %p %p", buffer, buffer->buf);
! 2210:
! 2211: HeapFree(hHeapHandle, 0, buffer->buf);
! 2212: HeapFree(hHeapHandle, 0, buffer);
! 2213: buffer = ISC_LIST_HEAD(lpo->bufferlist);
! 2214: }
! 2215:
! 2216: INSIST(sock->pending_iocp > 0);
! 2217: sock->pending_iocp--;
! 2218: INSIST(sock->pending_send > 0);
! 2219: sock->pending_send--;
! 2220:
! 2221: /* If the event is no longer in the list we can just return */
! 2222: if (!senddone_is_active(sock, dev))
! 2223: goto done;
! 2224:
! 2225: /*
! 2226: * Set the error code and send things on its way.
! 2227: */
! 2228: switch (completeio_send(sock, dev, messagehdr, nbytes, send_errno)) {
! 2229: case DOIO_SOFT:
! 2230: break;
! 2231: case DOIO_HARD:
! 2232: case DOIO_SUCCESS:
! 2233: send_senddone_event(sock, &dev);
! 2234: break;
! 2235: }
! 2236:
! 2237: done:
! 2238: maybe_free_socket(&sock, __LINE__);
! 2239: }
! 2240:
! 2241: /*
! 2242: * These return if the done event passed in is on the list (or for connect, is
! 2243: * the one we're waiting for. Using these ensures we will not double-send an
! 2244: * event.
! 2245: */
! 2246: static isc_boolean_t
! 2247: senddone_is_active(isc_socket_t *sock, isc_socketevent_t *dev)
! 2248: {
! 2249: isc_socketevent_t *ldev;
! 2250:
! 2251: ldev = ISC_LIST_HEAD(sock->send_list);
! 2252: while (ldev != NULL && ldev != dev)
! 2253: ldev = ISC_LIST_NEXT(ldev, ev_link);
! 2254:
! 2255: return (ldev == NULL ? ISC_FALSE : ISC_TRUE);
! 2256: }
! 2257:
! 2258: static isc_boolean_t
! 2259: acceptdone_is_active(isc_socket_t *sock, isc_socket_newconnev_t *dev)
! 2260: {
! 2261: isc_socket_newconnev_t *ldev;
! 2262:
! 2263: ldev = ISC_LIST_HEAD(sock->accept_list);
! 2264: while (ldev != NULL && ldev != dev)
! 2265: ldev = ISC_LIST_NEXT(ldev, ev_link);
! 2266:
! 2267: return (ldev == NULL ? ISC_FALSE : ISC_TRUE);
! 2268: }
! 2269:
! 2270: static isc_boolean_t
! 2271: connectdone_is_active(isc_socket_t *sock, isc_socket_connev_t *dev)
! 2272: {
! 2273: return (sock->connect_ev == dev ? ISC_TRUE : ISC_FALSE);
! 2274: }
! 2275:
! 2276: /*
! 2277: * This is the I/O Completion Port Worker Function. It loops forever
! 2278: * waiting for I/O to complete and then forwards them for further
! 2279: * processing. There are a number of these in separate threads.
! 2280: */
! 2281: static isc_threadresult_t WINAPI
! 2282: SocketIoThread(LPVOID ThreadContext) {
! 2283: isc_socketmgr_t *manager = ThreadContext;
! 2284: BOOL bSuccess = FALSE;
! 2285: DWORD nbytes;
! 2286: IoCompletionInfo *lpo = NULL;
! 2287: isc_socket_t *sock = NULL;
! 2288: int request;
! 2289: struct msghdr *messagehdr = NULL;
! 2290: int errval;
! 2291: char strbuf[ISC_STRERRORSIZE];
! 2292: int errstatus;
! 2293:
! 2294: REQUIRE(VALID_MANAGER(manager));
! 2295:
! 2296: /*
! 2297: * Set the thread priority high enough so I/O will
! 2298: * preempt normal recv packet processing, but not
! 2299: * higher than the timer sync thread.
! 2300: */
! 2301: if (!SetThreadPriority(GetCurrentThread(),
! 2302: THREAD_PRIORITY_ABOVE_NORMAL)) {
! 2303: errval = GetLastError();
! 2304: isc__strerror(errval, strbuf, sizeof(strbuf));
! 2305: FATAL_ERROR(__FILE__, __LINE__,
! 2306: isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKET,
! 2307: ISC_MSG_FAILED,
! 2308: "Can't set thread priority: %s"),
! 2309: strbuf);
! 2310: }
! 2311:
! 2312: /*
! 2313: * Loop forever waiting on I/O Completions and then processing them
! 2314: */
! 2315: while (TRUE) {
! 2316: bSuccess = GetQueuedCompletionStatus(manager->hIoCompletionPort,
! 2317: &nbytes, (LPDWORD)&sock,
! 2318: (LPWSAOVERLAPPED *)&lpo,
! 2319: INFINITE);
! 2320: if (lpo == NULL) /* Received request to exit */
! 2321: break;
! 2322:
! 2323: REQUIRE(VALID_SOCKET(sock));
! 2324:
! 2325: request = lpo->request_type;
! 2326:
! 2327: errstatus = 0;
! 2328: if (!bSuccess) {
! 2329: isc_result_t isc_result;
! 2330:
! 2331: /*
! 2332: * Did the I/O operation complete?
! 2333: */
! 2334: errstatus = WSAGetLastError();
! 2335: isc_result = isc__errno2resultx(errstatus, __FILE__, __LINE__);
! 2336:
! 2337: LOCK(&sock->lock);
! 2338: CONSISTENT(sock);
! 2339: switch (request) {
! 2340: case SOCKET_RECV:
! 2341: INSIST(sock->pending_iocp > 0);
! 2342: sock->pending_iocp--;
! 2343: INSIST(sock->pending_recv > 0);
! 2344: sock->pending_recv--;
! 2345: send_recvdone_abort(sock, isc_result);
! 2346: if (isc_result == ISC_R_UNEXPECTED) {
! 2347: UNEXPECTED_ERROR(__FILE__, __LINE__,
! 2348: "SOCKET_RECV: Windows error code: %d, returning ISC error %d",
! 2349: errstatus, isc_result);
! 2350: }
! 2351: break;
! 2352:
! 2353: case SOCKET_SEND:
! 2354: INSIST(sock->pending_iocp > 0);
! 2355: sock->pending_iocp--;
! 2356: INSIST(sock->pending_send > 0);
! 2357: sock->pending_send--;
! 2358: if (senddone_is_active(sock, lpo->dev)) {
! 2359: lpo->dev->result = isc_result;
! 2360: socket_log(__LINE__, sock, NULL, EVENT, NULL, 0, 0,
! 2361: "canceled_send");
! 2362: send_senddone_event(sock, &lpo->dev);
! 2363: }
! 2364: break;
! 2365:
! 2366: case SOCKET_ACCEPT:
! 2367: INSIST(sock->pending_iocp > 0);
! 2368: sock->pending_iocp--;
! 2369: INSIST(sock->pending_accept > 0);
! 2370: sock->pending_accept--;
! 2371: if (acceptdone_is_active(sock, lpo->adev)) {
! 2372: closesocket(lpo->adev->newsocket->fd);
! 2373: lpo->adev->newsocket->fd = INVALID_SOCKET;
! 2374: lpo->adev->newsocket->references--;
! 2375: free_socket(&lpo->adev->newsocket, __LINE__);
! 2376: lpo->adev->result = isc_result;
! 2377: socket_log(__LINE__, sock, NULL, EVENT, NULL, 0, 0,
! 2378: "canceled_accept");
! 2379: send_acceptdone_event(sock, &lpo->adev);
! 2380: }
! 2381: break;
! 2382:
! 2383: case SOCKET_CONNECT:
! 2384: INSIST(sock->pending_iocp > 0);
! 2385: sock->pending_iocp--;
! 2386: INSIST(sock->pending_connect == 1);
! 2387: sock->pending_connect = 0;
! 2388: if (connectdone_is_active(sock, lpo->cdev)) {
! 2389: lpo->cdev->result = isc_result;
! 2390: socket_log(__LINE__, sock, NULL, EVENT, NULL, 0, 0,
! 2391: "canceled_connect");
! 2392: send_connectdone_event(sock, &lpo->cdev);
! 2393: }
! 2394: break;
! 2395: }
! 2396: maybe_free_socket(&sock, __LINE__);
! 2397:
! 2398: if (lpo != NULL)
! 2399: HeapFree(hHeapHandle, 0, lpo);
! 2400: continue;
! 2401: }
! 2402:
! 2403: messagehdr = &lpo->messagehdr;
! 2404:
! 2405: switch (request) {
! 2406: case SOCKET_RECV:
! 2407: internal_recv(sock, nbytes);
! 2408: break;
! 2409: case SOCKET_SEND:
! 2410: internal_send(sock, lpo->dev, messagehdr, nbytes, errstatus, lpo);
! 2411: break;
! 2412: case SOCKET_ACCEPT:
! 2413: internal_accept(sock, lpo, errstatus);
! 2414: break;
! 2415: case SOCKET_CONNECT:
! 2416: internal_connect(sock, lpo, errstatus);
! 2417: break;
! 2418: }
! 2419:
! 2420: if (lpo != NULL)
! 2421: HeapFree(hHeapHandle, 0, lpo);
! 2422: }
! 2423:
! 2424: /*
! 2425: * Exit Completion Port Thread
! 2426: */
! 2427: manager_log(manager, TRACE,
! 2428: isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
! 2429: ISC_MSG_EXITING, "SocketIoThread exiting"));
! 2430: return ((isc_threadresult_t)0);
! 2431: }
! 2432:
! 2433: /*
! 2434: * Create a new socket manager.
! 2435: */
! 2436: isc_result_t
! 2437: isc_socketmgr_create(isc_mem_t *mctx, isc_socketmgr_t **managerp) {
! 2438: return (isc_socketmgr_create2(mctx, managerp, 0));
! 2439: }
! 2440:
! 2441: isc_result_t
! 2442: isc_socketmgr_create2(isc_mem_t *mctx, isc_socketmgr_t **managerp,
! 2443: unsigned int maxsocks)
! 2444: {
! 2445: isc_socketmgr_t *manager;
! 2446: isc_result_t result;
! 2447:
! 2448: REQUIRE(managerp != NULL && *managerp == NULL);
! 2449:
! 2450: if (maxsocks != 0)
! 2451: return (ISC_R_NOTIMPLEMENTED);
! 2452:
! 2453: manager = isc_mem_get(mctx, sizeof(*manager));
! 2454: if (manager == NULL)
! 2455: return (ISC_R_NOMEMORY);
! 2456:
! 2457: InitSockets();
! 2458:
! 2459: manager->magic = SOCKET_MANAGER_MAGIC;
! 2460: manager->mctx = NULL;
! 2461: manager->stats = NULL;
! 2462: ISC_LIST_INIT(manager->socklist);
! 2463: result = isc_mutex_init(&manager->lock);
! 2464: if (result != ISC_R_SUCCESS) {
! 2465: isc_mem_put(mctx, manager, sizeof(*manager));
! 2466: return (result);
! 2467: }
! 2468: if (isc_condition_init(&manager->shutdown_ok) != ISC_R_SUCCESS) {
! 2469: DESTROYLOCK(&manager->lock);
! 2470: isc_mem_put(mctx, manager, sizeof(*manager));
! 2471: UNEXPECTED_ERROR(__FILE__, __LINE__,
! 2472: "isc_condition_init() %s",
! 2473: isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
! 2474: ISC_MSG_FAILED, "failed"));
! 2475: return (ISC_R_UNEXPECTED);
! 2476: }
! 2477:
! 2478: isc_mem_attach(mctx, &manager->mctx);
! 2479:
! 2480: iocompletionport_init(manager); /* Create the Completion Ports */
! 2481:
! 2482: manager->bShutdown = ISC_FALSE;
! 2483: manager->totalSockets = 0;
! 2484: manager->iocp_total = 0;
! 2485:
! 2486: *managerp = manager;
! 2487:
! 2488: return (ISC_R_SUCCESS);
! 2489: }
! 2490:
! 2491: isc_result_t
! 2492: isc_socketmgr_getmaxsockets(isc_socketmgr_t *manager, unsigned int *nsockp) {
! 2493: REQUIRE(VALID_MANAGER(manager));
! 2494: REQUIRE(nsockp != NULL);
! 2495:
! 2496: return (ISC_R_NOTIMPLEMENTED);
! 2497: }
! 2498:
! 2499: void
! 2500: isc_socketmgr_setstats(isc_socketmgr_t *manager, isc_stats_t *stats) {
! 2501: REQUIRE(VALID_MANAGER(manager));
! 2502: REQUIRE(ISC_LIST_EMPTY(manager->socklist));
! 2503: REQUIRE(manager->stats == NULL);
! 2504: REQUIRE(isc_stats_ncounters(stats) == isc_sockstatscounter_max);
! 2505:
! 2506: isc_stats_attach(stats, &manager->stats);
! 2507: }
! 2508:
! 2509: void
! 2510: isc_socketmgr_destroy(isc_socketmgr_t **managerp) {
! 2511: isc_socketmgr_t *manager;
! 2512: int i;
! 2513: isc_mem_t *mctx;
! 2514:
! 2515: /*
! 2516: * Destroy a socket manager.
! 2517: */
! 2518:
! 2519: REQUIRE(managerp != NULL);
! 2520: manager = *managerp;
! 2521: REQUIRE(VALID_MANAGER(manager));
! 2522:
! 2523: LOCK(&manager->lock);
! 2524:
! 2525: /*
! 2526: * Wait for all sockets to be destroyed.
! 2527: */
! 2528: while (!ISC_LIST_EMPTY(manager->socklist)) {
! 2529: manager_log(manager, CREATION,
! 2530: isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKET,
! 2531: ISC_MSG_SOCKETSREMAIN,
! 2532: "sockets exist"));
! 2533: WAIT(&manager->shutdown_ok, &manager->lock);
! 2534: }
! 2535:
! 2536: UNLOCK(&manager->lock);
! 2537:
! 2538: /*
! 2539: * Here, we need to had some wait code for the completion port
! 2540: * thread.
! 2541: */
! 2542: signal_iocompletionport_exit(manager);
! 2543: manager->bShutdown = ISC_TRUE;
! 2544:
! 2545: /*
! 2546: * Wait for threads to exit.
! 2547: */
! 2548: for (i = 0; i < manager->maxIOCPThreads; i++) {
! 2549: if (isc_thread_join((isc_thread_t) manager->hIOCPThreads[i],
! 2550: NULL) != ISC_R_SUCCESS)
! 2551: UNEXPECTED_ERROR(__FILE__, __LINE__,
! 2552: "isc_thread_join() for Completion Port %s",
! 2553: isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
! 2554: ISC_MSG_FAILED, "failed"));
! 2555: }
! 2556: /*
! 2557: * Clean up.
! 2558: */
! 2559:
! 2560: CloseHandle(manager->hIoCompletionPort);
! 2561:
! 2562: (void)isc_condition_destroy(&manager->shutdown_ok);
! 2563:
! 2564: DESTROYLOCK(&manager->lock);
! 2565: if (manager->stats != NULL)
! 2566: isc_stats_detach(&manager->stats);
! 2567: manager->magic = 0;
! 2568: mctx= manager->mctx;
! 2569: isc_mem_put(mctx, manager, sizeof(*manager));
! 2570:
! 2571: isc_mem_detach(&mctx);
! 2572:
! 2573: *managerp = NULL;
! 2574: }
! 2575:
! 2576: static void
! 2577: queue_receive_event(isc_socket_t *sock, isc_task_t *task, isc_socketevent_t *dev)
! 2578: {
! 2579: isc_task_t *ntask = NULL;
! 2580:
! 2581: isc_task_attach(task, &ntask);
! 2582: dev->attributes |= ISC_SOCKEVENTATTR_ATTACHED;
! 2583:
! 2584: /*
! 2585: * Enqueue the request.
! 2586: */
! 2587: INSIST(!ISC_LINK_LINKED(dev, ev_link));
! 2588: ISC_LIST_ENQUEUE(sock->recv_list, dev, ev_link);
! 2589:
! 2590: socket_log(__LINE__, sock, NULL, EVENT, NULL, 0, 0,
! 2591: "queue_receive_event: event %p -> task %p",
! 2592: dev, ntask);
! 2593: }
! 2594:
! 2595: /*
! 2596: * Check the pending receive queue, and if we have data pending, give it to this
! 2597: * caller. If we have none, queue an I/O request. If this caller is not the first
! 2598: * on the list, then we will just queue this event and return.
! 2599: *
! 2600: * Caller must have the socket locked.
! 2601: */
! 2602: static isc_result_t
! 2603: socket_recv(isc_socket_t *sock, isc_socketevent_t *dev, isc_task_t *task,
! 2604: unsigned int flags)
! 2605: {
! 2606: int cc = 0;
! 2607: isc_task_t *ntask = NULL;
! 2608: isc_result_t result = ISC_R_SUCCESS;
! 2609: int recv_errno = 0;
! 2610:
! 2611: dev->ev_sender = task;
! 2612:
! 2613: if (sock->fd == INVALID_SOCKET)
! 2614: return (ISC_R_EOF);
! 2615:
! 2616: /*
! 2617: * Queue our event on the list of things to do. Call our function to
! 2618: * attempt to fill buffers as much as possible, and return done events.
! 2619: * We are going to lie about our handling of the ISC_SOCKFLAG_IMMEDIATE
! 2620: * here and tell our caller that we could not satisfy it immediately.
! 2621: */
! 2622: queue_receive_event(sock, task, dev);
! 2623: if ((flags & ISC_SOCKFLAG_IMMEDIATE) != 0)
! 2624: result = ISC_R_INPROGRESS;
! 2625:
! 2626: completeio_recv(sock);
! 2627:
! 2628: /*
! 2629: * If there are more receivers waiting for data, queue another receive
! 2630: * here. If the
! 2631: */
! 2632: queue_receive_request(sock);
! 2633:
! 2634: return (result);
! 2635: }
! 2636:
! 2637: isc_result_t
! 2638: isc_socket_recvv(isc_socket_t *sock, isc_bufferlist_t *buflist,
! 2639: unsigned int minimum, isc_task_t *task,
! 2640: isc_taskaction_t action, const void *arg)
! 2641: {
! 2642: isc_socketevent_t *dev;
! 2643: isc_socketmgr_t *manager;
! 2644: unsigned int iocount;
! 2645: isc_buffer_t *buffer;
! 2646: isc_result_t ret;
! 2647:
! 2648: REQUIRE(VALID_SOCKET(sock));
! 2649: LOCK(&sock->lock);
! 2650: CONSISTENT(sock);
! 2651:
! 2652: /*
! 2653: * Make sure that the socket is not closed. XXXMLG change error here?
! 2654: */
! 2655: if (sock->fd == INVALID_SOCKET) {
! 2656: UNLOCK(&sock->lock);
! 2657: return (ISC_R_CONNREFUSED);
! 2658: }
! 2659:
! 2660: REQUIRE(buflist != NULL);
! 2661: REQUIRE(!ISC_LIST_EMPTY(*buflist));
! 2662: REQUIRE(task != NULL);
! 2663: REQUIRE(action != NULL);
! 2664:
! 2665: manager = sock->manager;
! 2666: REQUIRE(VALID_MANAGER(manager));
! 2667:
! 2668: iocount = isc_bufferlist_availablecount(buflist);
! 2669: REQUIRE(iocount > 0);
! 2670:
! 2671: INSIST(sock->bound);
! 2672:
! 2673: dev = allocate_socketevent(sock, ISC_SOCKEVENT_RECVDONE, action, arg);
! 2674: if (dev == NULL) {
! 2675: UNLOCK(&sock->lock);
! 2676: return (ISC_R_NOMEMORY);
! 2677: }
! 2678:
! 2679: /*
! 2680: * UDP sockets are always partial read
! 2681: */
! 2682: if (sock->type == isc_sockettype_udp)
! 2683: dev->minimum = 1;
! 2684: else {
! 2685: if (minimum == 0)
! 2686: dev->minimum = iocount;
! 2687: else
! 2688: dev->minimum = minimum;
! 2689: }
! 2690:
! 2691: /*
! 2692: * Move each buffer from the passed in list to our internal one.
! 2693: */
! 2694: buffer = ISC_LIST_HEAD(*buflist);
! 2695: while (buffer != NULL) {
! 2696: ISC_LIST_DEQUEUE(*buflist, buffer, link);
! 2697: ISC_LIST_ENQUEUE(dev->bufferlist, buffer, link);
! 2698: buffer = ISC_LIST_HEAD(*buflist);
! 2699: }
! 2700:
! 2701: ret = socket_recv(sock, dev, task, 0);
! 2702:
! 2703: UNLOCK(&sock->lock);
! 2704: return (ret);
! 2705: }
! 2706:
! 2707: isc_result_t
! 2708: isc_socket_recv(isc_socket_t *sock, isc_region_t *region, unsigned int minimum,
! 2709: isc_task_t *task, isc_taskaction_t action, const void *arg)
! 2710: {
! 2711: isc_socketevent_t *dev;
! 2712: isc_socketmgr_t *manager;
! 2713: isc_result_t ret;
! 2714:
! 2715: REQUIRE(VALID_SOCKET(sock));
! 2716: LOCK(&sock->lock);
! 2717: CONSISTENT(sock);
! 2718:
! 2719: /*
! 2720: * make sure that the socket's not closed
! 2721: */
! 2722: if (sock->fd == INVALID_SOCKET) {
! 2723: UNLOCK(&sock->lock);
! 2724: return (ISC_R_CONNREFUSED);
! 2725: }
! 2726: REQUIRE(action != NULL);
! 2727:
! 2728: manager = sock->manager;
! 2729: REQUIRE(VALID_MANAGER(manager));
! 2730:
! 2731: INSIST(sock->bound);
! 2732:
! 2733: dev = allocate_socketevent(sock, ISC_SOCKEVENT_RECVDONE, action, arg);
! 2734: if (dev == NULL) {
! 2735: UNLOCK(&sock->lock);
! 2736: return (ISC_R_NOMEMORY);
! 2737: }
! 2738:
! 2739: ret = isc_socket_recv2(sock, region, minimum, task, dev, 0);
! 2740: UNLOCK(&sock->lock);
! 2741: return (ret);
! 2742: }
! 2743:
! 2744: isc_result_t
! 2745: isc_socket_recv2(isc_socket_t *sock, isc_region_t *region,
! 2746: unsigned int minimum, isc_task_t *task,
! 2747: isc_socketevent_t *event, unsigned int flags)
! 2748: {
! 2749: isc_result_t ret;
! 2750:
! 2751: REQUIRE(VALID_SOCKET(sock));
! 2752: LOCK(&sock->lock);
! 2753: CONSISTENT(sock);
! 2754:
! 2755: event->result = ISC_R_UNEXPECTED;
! 2756: event->ev_sender = sock;
! 2757: /*
! 2758: * make sure that the socket's not closed
! 2759: */
! 2760: if (sock->fd == INVALID_SOCKET) {
! 2761: UNLOCK(&sock->lock);
! 2762: return (ISC_R_CONNREFUSED);
! 2763: }
! 2764:
! 2765: ISC_LIST_INIT(event->bufferlist);
! 2766: event->region = *region;
! 2767: event->n = 0;
! 2768: event->offset = 0;
! 2769: event->attributes = 0;
! 2770:
! 2771: /*
! 2772: * UDP sockets are always partial read.
! 2773: */
! 2774: if (sock->type == isc_sockettype_udp)
! 2775: event->minimum = 1;
! 2776: else {
! 2777: if (minimum == 0)
! 2778: event->minimum = region->length;
! 2779: else
! 2780: event->minimum = minimum;
! 2781: }
! 2782:
! 2783: ret = socket_recv(sock, event, task, flags);
! 2784: UNLOCK(&sock->lock);
! 2785: return (ret);
! 2786: }
! 2787:
! 2788: /*
! 2789: * Caller must have the socket locked.
! 2790: */
! 2791: static isc_result_t
! 2792: socket_send(isc_socket_t *sock, isc_socketevent_t *dev, isc_task_t *task,
! 2793: isc_sockaddr_t *address, struct in6_pktinfo *pktinfo,
! 2794: unsigned int flags)
! 2795: {
! 2796: int io_state;
! 2797: int send_errno = 0;
! 2798: int cc = 0;
! 2799: isc_task_t *ntask = NULL;
! 2800: isc_result_t result = ISC_R_SUCCESS;
! 2801:
! 2802: dev->ev_sender = task;
! 2803:
! 2804: set_dev_address(address, sock, dev);
! 2805: if (pktinfo != NULL) {
! 2806: socket_log(__LINE__, sock, NULL, TRACE, isc_msgcat, ISC_MSGSET_SOCKET,
! 2807: ISC_MSG_PKTINFOPROVIDED,
! 2808: "pktinfo structure provided, ifindex %u (set to 0)",
! 2809: pktinfo->ipi6_ifindex);
! 2810:
! 2811: dev->attributes |= ISC_SOCKEVENTATTR_PKTINFO;
! 2812: dev->pktinfo = *pktinfo;
! 2813: /*
! 2814: * Set the pktinfo index to 0 here, to let the kernel decide
! 2815: * what interface it should send on.
! 2816: */
! 2817: dev->pktinfo.ipi6_ifindex = 0;
! 2818: }
! 2819:
! 2820: io_state = startio_send(sock, dev, &cc, &send_errno);
! 2821: switch (io_state) {
! 2822: case DOIO_PENDING: /* I/O started. Nothing more to do */
! 2823: case DOIO_SOFT:
! 2824: /*
! 2825: * We couldn't send all or part of the request right now, so
! 2826: * queue it unless ISC_SOCKFLAG_NORETRY is set.
! 2827: */
! 2828: if ((flags & ISC_SOCKFLAG_NORETRY) == 0) {
! 2829: isc_task_attach(task, &ntask);
! 2830: dev->attributes |= ISC_SOCKEVENTATTR_ATTACHED;
! 2831:
! 2832: /*
! 2833: * Enqueue the request.
! 2834: */
! 2835: INSIST(!ISC_LINK_LINKED(dev, ev_link));
! 2836: ISC_LIST_ENQUEUE(sock->send_list, dev, ev_link);
! 2837:
! 2838: socket_log(__LINE__, sock, NULL, EVENT, NULL, 0, 0,
! 2839: "socket_send: event %p -> task %p",
! 2840: dev, ntask);
! 2841:
! 2842: if ((flags & ISC_SOCKFLAG_IMMEDIATE) != 0)
! 2843: result = ISC_R_INPROGRESS;
! 2844: break;
! 2845: }
! 2846:
! 2847: case DOIO_SUCCESS:
! 2848: break;
! 2849: }
! 2850:
! 2851: return (result);
! 2852: }
! 2853:
! 2854: isc_result_t
! 2855: isc_socket_send(isc_socket_t *sock, isc_region_t *region,
! 2856: isc_task_t *task, isc_taskaction_t action, const void *arg)
! 2857: {
! 2858: /*
! 2859: * REQUIRE() checking is performed in isc_socket_sendto().
! 2860: */
! 2861: return (isc_socket_sendto(sock, region, task, action, arg, NULL,
! 2862: NULL));
! 2863: }
! 2864:
! 2865: isc_result_t
! 2866: isc_socket_sendto(isc_socket_t *sock, isc_region_t *region,
! 2867: isc_task_t *task, isc_taskaction_t action, const void *arg,
! 2868: isc_sockaddr_t *address, struct in6_pktinfo *pktinfo)
! 2869: {
! 2870: isc_socketevent_t *dev;
! 2871: isc_socketmgr_t *manager;
! 2872: isc_result_t ret;
! 2873:
! 2874: REQUIRE(VALID_SOCKET(sock));
! 2875: REQUIRE(sock->type != isc_sockettype_fdwatch);
! 2876:
! 2877: LOCK(&sock->lock);
! 2878: CONSISTENT(sock);
! 2879:
! 2880: /*
! 2881: * make sure that the socket's not closed
! 2882: */
! 2883: if (sock->fd == INVALID_SOCKET) {
! 2884: UNLOCK(&sock->lock);
! 2885: return (ISC_R_CONNREFUSED);
! 2886: }
! 2887: REQUIRE(region != NULL);
! 2888: REQUIRE(task != NULL);
! 2889: REQUIRE(action != NULL);
! 2890:
! 2891: manager = sock->manager;
! 2892: REQUIRE(VALID_MANAGER(manager));
! 2893:
! 2894: INSIST(sock->bound);
! 2895:
! 2896: dev = allocate_socketevent(sock, ISC_SOCKEVENT_SENDDONE, action, arg);
! 2897: if (dev == NULL) {
! 2898: UNLOCK(&sock->lock);
! 2899: return (ISC_R_NOMEMORY);
! 2900: }
! 2901: dev->region = *region;
! 2902:
! 2903: ret = socket_send(sock, dev, task, address, pktinfo, 0);
! 2904: UNLOCK(&sock->lock);
! 2905: return (ret);
! 2906: }
! 2907:
! 2908: isc_result_t
! 2909: isc_socket_sendv(isc_socket_t *sock, isc_bufferlist_t *buflist,
! 2910: isc_task_t *task, isc_taskaction_t action, const void *arg)
! 2911: {
! 2912: return (isc_socket_sendtov(sock, buflist, task, action, arg, NULL,
! 2913: NULL));
! 2914: }
! 2915:
! 2916: isc_result_t
! 2917: isc_socket_sendtov(isc_socket_t *sock, isc_bufferlist_t *buflist,
! 2918: isc_task_t *task, isc_taskaction_t action, const void *arg,
! 2919: isc_sockaddr_t *address, struct in6_pktinfo *pktinfo)
! 2920: {
! 2921: isc_socketevent_t *dev;
! 2922: isc_socketmgr_t *manager;
! 2923: unsigned int iocount;
! 2924: isc_buffer_t *buffer;
! 2925: isc_result_t ret;
! 2926:
! 2927: REQUIRE(VALID_SOCKET(sock));
! 2928:
! 2929: LOCK(&sock->lock);
! 2930: CONSISTENT(sock);
! 2931:
! 2932: /*
! 2933: * make sure that the socket's not closed
! 2934: */
! 2935: if (sock->fd == INVALID_SOCKET) {
! 2936: UNLOCK(&sock->lock);
! 2937: return (ISC_R_CONNREFUSED);
! 2938: }
! 2939: REQUIRE(buflist != NULL);
! 2940: REQUIRE(!ISC_LIST_EMPTY(*buflist));
! 2941: REQUIRE(task != NULL);
! 2942: REQUIRE(action != NULL);
! 2943:
! 2944: manager = sock->manager;
! 2945: REQUIRE(VALID_MANAGER(manager));
! 2946:
! 2947: iocount = isc_bufferlist_usedcount(buflist);
! 2948: REQUIRE(iocount > 0);
! 2949:
! 2950: dev = allocate_socketevent(sock, ISC_SOCKEVENT_SENDDONE, action, arg);
! 2951: if (dev == NULL) {
! 2952: UNLOCK(&sock->lock);
! 2953: return (ISC_R_NOMEMORY);
! 2954: }
! 2955:
! 2956: /*
! 2957: * Move each buffer from the passed in list to our internal one.
! 2958: */
! 2959: buffer = ISC_LIST_HEAD(*buflist);
! 2960: while (buffer != NULL) {
! 2961: ISC_LIST_DEQUEUE(*buflist, buffer, link);
! 2962: ISC_LIST_ENQUEUE(dev->bufferlist, buffer, link);
! 2963: buffer = ISC_LIST_HEAD(*buflist);
! 2964: }
! 2965:
! 2966: ret = socket_send(sock, dev, task, address, pktinfo, 0);
! 2967: UNLOCK(&sock->lock);
! 2968: return (ret);
! 2969: }
! 2970:
! 2971: isc_result_t
! 2972: isc_socket_sendto2(isc_socket_t *sock, isc_region_t *region,
! 2973: isc_task_t *task,
! 2974: isc_sockaddr_t *address, struct in6_pktinfo *pktinfo,
! 2975: isc_socketevent_t *event, unsigned int flags)
! 2976: {
! 2977: isc_result_t ret;
! 2978:
! 2979: REQUIRE(VALID_SOCKET(sock));
! 2980: LOCK(&sock->lock);
! 2981: CONSISTENT(sock);
! 2982:
! 2983: REQUIRE((flags & ~(ISC_SOCKFLAG_IMMEDIATE|ISC_SOCKFLAG_NORETRY)) == 0);
! 2984: if ((flags & ISC_SOCKFLAG_NORETRY) != 0)
! 2985: REQUIRE(sock->type == isc_sockettype_udp);
! 2986: event->ev_sender = sock;
! 2987: event->result = ISC_R_UNEXPECTED;
! 2988: /*
! 2989: * make sure that the socket's not closed
! 2990: */
! 2991: if (sock->fd == INVALID_SOCKET) {
! 2992: UNLOCK(&sock->lock);
! 2993: return (ISC_R_CONNREFUSED);
! 2994: }
! 2995: ISC_LIST_INIT(event->bufferlist);
! 2996: event->region = *region;
! 2997: event->n = 0;
! 2998: event->offset = 0;
! 2999: event->attributes = 0;
! 3000:
! 3001: ret = socket_send(sock, event, task, address, pktinfo, flags);
! 3002: UNLOCK(&sock->lock);
! 3003: return (ret);
! 3004: }
! 3005:
! 3006: isc_result_t
! 3007: isc_socket_bind(isc_socket_t *sock, isc_sockaddr_t *sockaddr,
! 3008: unsigned int options) {
! 3009: int bind_errno;
! 3010: char strbuf[ISC_STRERRORSIZE];
! 3011: int on = 1;
! 3012:
! 3013: REQUIRE(VALID_SOCKET(sock));
! 3014: LOCK(&sock->lock);
! 3015: CONSISTENT(sock);
! 3016:
! 3017: /*
! 3018: * make sure that the socket's not closed
! 3019: */
! 3020: if (sock->fd == INVALID_SOCKET) {
! 3021: UNLOCK(&sock->lock);
! 3022: return (ISC_R_CONNREFUSED);
! 3023: }
! 3024:
! 3025: INSIST(!sock->bound);
! 3026:
! 3027: if (sock->pf != sockaddr->type.sa.sa_family) {
! 3028: UNLOCK(&sock->lock);
! 3029: return (ISC_R_FAMILYMISMATCH);
! 3030: }
! 3031: /*
! 3032: * Only set SO_REUSEADDR when we want a specific port.
! 3033: */
! 3034: if ((options & ISC_SOCKET_REUSEADDRESS) != 0 &&
! 3035: isc_sockaddr_getport(sockaddr) != (in_port_t)0 &&
! 3036: setsockopt(sock->fd, SOL_SOCKET, SO_REUSEADDR, (void *)&on,
! 3037: sizeof(on)) < 0) {
! 3038: UNEXPECTED_ERROR(__FILE__, __LINE__,
! 3039: "setsockopt(%d) %s", sock->fd,
! 3040: isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
! 3041: ISC_MSG_FAILED, "failed"));
! 3042: /* Press on... */
! 3043: }
! 3044: if (bind(sock->fd, &sockaddr->type.sa, sockaddr->length) < 0) {
! 3045: bind_errno = WSAGetLastError();
! 3046: UNLOCK(&sock->lock);
! 3047: switch (bind_errno) {
! 3048: case WSAEACCES:
! 3049: return (ISC_R_NOPERM);
! 3050: case WSAEADDRNOTAVAIL:
! 3051: return (ISC_R_ADDRNOTAVAIL);
! 3052: case WSAEADDRINUSE:
! 3053: return (ISC_R_ADDRINUSE);
! 3054: case WSAEINVAL:
! 3055: return (ISC_R_BOUND);
! 3056: default:
! 3057: isc__strerror(bind_errno, strbuf, sizeof(strbuf));
! 3058: UNEXPECTED_ERROR(__FILE__, __LINE__, "bind: %s",
! 3059: strbuf);
! 3060: return (ISC_R_UNEXPECTED);
! 3061: }
! 3062: }
! 3063:
! 3064: socket_log(__LINE__, sock, sockaddr, TRACE,
! 3065: isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_BOUND, "bound");
! 3066: sock->bound = 1;
! 3067:
! 3068: UNLOCK(&sock->lock);
! 3069: return (ISC_R_SUCCESS);
! 3070: }
! 3071:
! 3072: isc_result_t
! 3073: isc_socket_filter(isc_socket_t *sock, const char *filter) {
! 3074: UNUSED(sock);
! 3075: UNUSED(filter);
! 3076:
! 3077: REQUIRE(VALID_SOCKET(sock));
! 3078: return (ISC_R_NOTIMPLEMENTED);
! 3079: }
! 3080:
! 3081: /*
! 3082: * Set up to listen on a given socket. We do this by creating an internal
! 3083: * event that will be dispatched when the socket has read activity. The
! 3084: * watcher will send the internal event to the task when there is a new
! 3085: * connection.
! 3086: *
! 3087: * Unlike in read, we don't preallocate a done event here. Every time there
! 3088: * is a new connection we'll have to allocate a new one anyway, so we might
! 3089: * as well keep things simple rather than having to track them.
! 3090: */
! 3091: isc_result_t
! 3092: isc_socket_listen(isc_socket_t *sock, unsigned int backlog) {
! 3093: char strbuf[ISC_STRERRORSIZE];
! 3094:
! 3095: REQUIRE(VALID_SOCKET(sock));
! 3096:
! 3097: LOCK(&sock->lock);
! 3098: CONSISTENT(sock);
! 3099:
! 3100: /*
! 3101: * make sure that the socket's not closed
! 3102: */
! 3103: if (sock->fd == INVALID_SOCKET) {
! 3104: UNLOCK(&sock->lock);
! 3105: return (ISC_R_CONNREFUSED);
! 3106: }
! 3107:
! 3108: REQUIRE(!sock->listener);
! 3109: REQUIRE(sock->bound);
! 3110: REQUIRE(sock->type == isc_sockettype_tcp);
! 3111:
! 3112: if (backlog == 0)
! 3113: backlog = SOMAXCONN;
! 3114:
! 3115: if (listen(sock->fd, (int)backlog) < 0) {
! 3116: UNLOCK(&sock->lock);
! 3117: isc__strerror(WSAGetLastError(), strbuf, sizeof(strbuf));
! 3118:
! 3119: UNEXPECTED_ERROR(__FILE__, __LINE__, "listen: %s", strbuf);
! 3120:
! 3121: return (ISC_R_UNEXPECTED);
! 3122: }
! 3123:
! 3124: socket_log(__LINE__, sock, NULL, TRACE,
! 3125: isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_BOUND, "listening");
! 3126: sock->listener = 1;
! 3127: _set_state(sock, SOCK_LISTEN);
! 3128:
! 3129: UNLOCK(&sock->lock);
! 3130: return (ISC_R_SUCCESS);
! 3131: }
! 3132:
! 3133: /*
! 3134: * This should try to do aggressive accept() XXXMLG
! 3135: */
! 3136: isc_result_t
! 3137: isc_socket_accept(isc_socket_t *sock,
! 3138: isc_task_t *task, isc_taskaction_t action, const void *arg)
! 3139: {
! 3140: isc_socket_newconnev_t *adev;
! 3141: isc_socketmgr_t *manager;
! 3142: isc_task_t *ntask = NULL;
! 3143: isc_socket_t *nsock;
! 3144: isc_result_t result;
! 3145: IoCompletionInfo *lpo;
! 3146:
! 3147: REQUIRE(VALID_SOCKET(sock));
! 3148:
! 3149: manager = sock->manager;
! 3150: REQUIRE(VALID_MANAGER(manager));
! 3151:
! 3152: LOCK(&sock->lock);
! 3153: CONSISTENT(sock);
! 3154:
! 3155: /*
! 3156: * make sure that the socket's not closed
! 3157: */
! 3158: if (sock->fd == INVALID_SOCKET) {
! 3159: UNLOCK(&sock->lock);
! 3160: return (ISC_R_CONNREFUSED);
! 3161: }
! 3162:
! 3163: REQUIRE(sock->listener);
! 3164:
! 3165: /*
! 3166: * Sender field is overloaded here with the task we will be sending
! 3167: * this event to. Just before the actual event is delivered the
! 3168: * actual ev_sender will be touched up to be the socket.
! 3169: */
! 3170: adev = (isc_socket_newconnev_t *)
! 3171: isc_event_allocate(manager->mctx, task, ISC_SOCKEVENT_NEWCONN,
! 3172: action, arg, sizeof(*adev));
! 3173: if (adev == NULL) {
! 3174: UNLOCK(&sock->lock);
! 3175: return (ISC_R_NOMEMORY);
! 3176: }
! 3177: ISC_LINK_INIT(adev, ev_link);
! 3178:
! 3179: result = allocate_socket(manager, sock->type, &nsock);
! 3180: if (result != ISC_R_SUCCESS) {
! 3181: isc_event_free((isc_event_t **)&adev);
! 3182: UNLOCK(&sock->lock);
! 3183: return (result);
! 3184: }
! 3185:
! 3186: /*
! 3187: * AcceptEx() requires we pass in a socket.
! 3188: */
! 3189: nsock->fd = socket(sock->pf, SOCK_STREAM, IPPROTO_TCP);
! 3190: if (nsock->fd == INVALID_SOCKET) {
! 3191: free_socket(&nsock, __LINE__);
! 3192: isc_event_free((isc_event_t **)&adev);
! 3193: UNLOCK(&sock->lock);
! 3194: return (ISC_R_FAILURE); // XXXMLG need real error message
! 3195: }
! 3196:
! 3197: /*
! 3198: * Attach to socket and to task.
! 3199: */
! 3200: isc_task_attach(task, &ntask);
! 3201: nsock->references++;
! 3202:
! 3203: adev->ev_sender = ntask;
! 3204: adev->newsocket = nsock;
! 3205: _set_state(nsock, SOCK_ACCEPT);
! 3206:
! 3207: /*
! 3208: * Queue io completion for an accept().
! 3209: */
! 3210: lpo = (IoCompletionInfo *)HeapAlloc(hHeapHandle,
! 3211: HEAP_ZERO_MEMORY,
! 3212: sizeof(IoCompletionInfo));
! 3213: RUNTIME_CHECK(lpo != NULL);
! 3214: lpo->acceptbuffer = (void *)HeapAlloc(hHeapHandle, HEAP_ZERO_MEMORY,
! 3215: (sizeof(SOCKADDR_STORAGE) + 16) * 2);
! 3216: RUNTIME_CHECK(lpo->acceptbuffer != NULL);
! 3217:
! 3218: lpo->adev = adev;
! 3219: lpo->request_type = SOCKET_ACCEPT;
! 3220:
! 3221: ISCAcceptEx(sock->fd,
! 3222: nsock->fd, /* Accepted Socket */
! 3223: lpo->acceptbuffer, /* Buffer for initial Recv */
! 3224: 0, /* Length of Buffer */
! 3225: sizeof(SOCKADDR_STORAGE) + 16, /* Local address length + 16 */
! 3226: sizeof(SOCKADDR_STORAGE) + 16, /* Remote address lengh + 16 */
! 3227: (LPDWORD)&lpo->received_bytes, /* Bytes Recved */
! 3228: (LPOVERLAPPED)lpo /* Overlapped structure */
! 3229: );
! 3230: iocompletionport_update(nsock);
! 3231:
! 3232: socket_log(__LINE__, sock, NULL, TRACE,
! 3233: isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_BOUND,
! 3234: "accepting for nsock %p fd %d", nsock, nsock->fd);
! 3235:
! 3236: /*
! 3237: * Enqueue the event
! 3238: */
! 3239: ISC_LIST_ENQUEUE(sock->accept_list, adev, ev_link);
! 3240: sock->pending_accept++;
! 3241: sock->pending_iocp++;
! 3242:
! 3243: UNLOCK(&sock->lock);
! 3244: return (ISC_R_SUCCESS);
! 3245: }
! 3246:
! 3247: isc_result_t
! 3248: isc_socket_connect(isc_socket_t *sock, isc_sockaddr_t *addr,
! 3249: isc_task_t *task, isc_taskaction_t action, const void *arg)
! 3250: {
! 3251: char strbuf[ISC_STRERRORSIZE];
! 3252: isc_socket_connev_t *cdev;
! 3253: isc_task_t *ntask = NULL;
! 3254: isc_socketmgr_t *manager;
! 3255: IoCompletionInfo *lpo;
! 3256: int bind_errno;
! 3257:
! 3258: REQUIRE(VALID_SOCKET(sock));
! 3259: REQUIRE(addr != NULL);
! 3260: REQUIRE(task != NULL);
! 3261: REQUIRE(action != NULL);
! 3262:
! 3263: manager = sock->manager;
! 3264: REQUIRE(VALID_MANAGER(manager));
! 3265: REQUIRE(addr != NULL);
! 3266:
! 3267: if (isc_sockaddr_ismulticast(addr))
! 3268: return (ISC_R_MULTICAST);
! 3269:
! 3270: LOCK(&sock->lock);
! 3271: CONSISTENT(sock);
! 3272:
! 3273: /*
! 3274: * make sure that the socket's not closed
! 3275: */
! 3276: if (sock->fd == INVALID_SOCKET) {
! 3277: UNLOCK(&sock->lock);
! 3278: return (ISC_R_CONNREFUSED);
! 3279: }
! 3280:
! 3281: /*
! 3282: * Windows sockets won't connect unless the socket is bound.
! 3283: */
! 3284: if (!sock->bound) {
! 3285: isc_sockaddr_t any;
! 3286:
! 3287: isc_sockaddr_anyofpf(&any, isc_sockaddr_pf(addr));
! 3288: if (bind(sock->fd, &any.type.sa, any.length) < 0) {
! 3289: bind_errno = WSAGetLastError();
! 3290: UNLOCK(&sock->lock);
! 3291: switch (bind_errno) {
! 3292: case WSAEACCES:
! 3293: return (ISC_R_NOPERM);
! 3294: case WSAEADDRNOTAVAIL:
! 3295: return (ISC_R_ADDRNOTAVAIL);
! 3296: case WSAEADDRINUSE:
! 3297: return (ISC_R_ADDRINUSE);
! 3298: case WSAEINVAL:
! 3299: return (ISC_R_BOUND);
! 3300: default:
! 3301: isc__strerror(bind_errno, strbuf,
! 3302: sizeof(strbuf));
! 3303: UNEXPECTED_ERROR(__FILE__, __LINE__,
! 3304: "bind: %s", strbuf);
! 3305: return (ISC_R_UNEXPECTED);
! 3306: }
! 3307: }
! 3308: sock->bound = 1;
! 3309: }
! 3310:
! 3311: REQUIRE(!sock->pending_connect);
! 3312:
! 3313: cdev = (isc_socket_connev_t *)isc_event_allocate(manager->mctx, sock,
! 3314: ISC_SOCKEVENT_CONNECT,
! 3315: action, arg,
! 3316: sizeof(*cdev));
! 3317: if (cdev == NULL) {
! 3318: UNLOCK(&sock->lock);
! 3319: return (ISC_R_NOMEMORY);
! 3320: }
! 3321: ISC_LINK_INIT(cdev, ev_link);
! 3322:
! 3323: if (sock->type == isc_sockettype_tcp) {
! 3324: /*
! 3325: * Queue io completion for an accept().
! 3326: */
! 3327: lpo = (IoCompletionInfo *)HeapAlloc(hHeapHandle,
! 3328: HEAP_ZERO_MEMORY,
! 3329: sizeof(IoCompletionInfo));
! 3330: lpo->cdev = cdev;
! 3331: lpo->request_type = SOCKET_CONNECT;
! 3332:
! 3333: sock->address = *addr;
! 3334: ISCConnectEx(sock->fd, &addr->type.sa, addr->length,
! 3335: NULL, 0, NULL, (LPOVERLAPPED)lpo);
! 3336:
! 3337: /*
! 3338: * Attach to task.
! 3339: */
! 3340: isc_task_attach(task, &ntask);
! 3341: cdev->ev_sender = ntask;
! 3342:
! 3343: sock->pending_connect = 1;
! 3344: _set_state(sock, SOCK_CONNECT);
! 3345:
! 3346: /*
! 3347: * Enqueue the request.
! 3348: */
! 3349: sock->connect_ev = cdev;
! 3350: sock->pending_iocp++;
! 3351: } else {
! 3352: WSAConnect(sock->fd, &addr->type.sa, addr->length, NULL, NULL, NULL, NULL);
! 3353: cdev->result = ISC_R_SUCCESS;
! 3354: isc_task_send(task, (isc_event_t **)&cdev);
! 3355: }
! 3356: CONSISTENT(sock);
! 3357: UNLOCK(&sock->lock);
! 3358:
! 3359: return (ISC_R_SUCCESS);
! 3360: }
! 3361:
! 3362: isc_result_t
! 3363: isc_socket_getpeername(isc_socket_t *sock, isc_sockaddr_t *addressp) {
! 3364: isc_result_t result;
! 3365:
! 3366: REQUIRE(VALID_SOCKET(sock));
! 3367: REQUIRE(addressp != NULL);
! 3368:
! 3369: LOCK(&sock->lock);
! 3370: CONSISTENT(sock);
! 3371:
! 3372: /*
! 3373: * make sure that the socket's not closed
! 3374: */
! 3375: if (sock->fd == INVALID_SOCKET) {
! 3376: UNLOCK(&sock->lock);
! 3377: return (ISC_R_CONNREFUSED);
! 3378: }
! 3379:
! 3380: if (sock->connected) {
! 3381: *addressp = sock->address;
! 3382: result = ISC_R_SUCCESS;
! 3383: } else {
! 3384: result = ISC_R_NOTCONNECTED;
! 3385: }
! 3386:
! 3387: UNLOCK(&sock->lock);
! 3388:
! 3389: return (result);
! 3390: }
! 3391:
! 3392: isc_result_t
! 3393: isc_socket_getsockname(isc_socket_t *sock, isc_sockaddr_t *addressp) {
! 3394: ISC_SOCKADDR_LEN_T len;
! 3395: isc_result_t result;
! 3396: char strbuf[ISC_STRERRORSIZE];
! 3397:
! 3398: REQUIRE(VALID_SOCKET(sock));
! 3399: REQUIRE(addressp != NULL);
! 3400:
! 3401: LOCK(&sock->lock);
! 3402: CONSISTENT(sock);
! 3403:
! 3404: /*
! 3405: * make sure that the socket's not closed
! 3406: */
! 3407: if (sock->fd == INVALID_SOCKET) {
! 3408: UNLOCK(&sock->lock);
! 3409: return (ISC_R_CONNREFUSED);
! 3410: }
! 3411:
! 3412: if (!sock->bound) {
! 3413: result = ISC_R_NOTBOUND;
! 3414: goto out;
! 3415: }
! 3416:
! 3417: result = ISC_R_SUCCESS;
! 3418:
! 3419: len = sizeof(addressp->type);
! 3420: if (getsockname(sock->fd, &addressp->type.sa, (void *)&len) < 0) {
! 3421: isc__strerror(WSAGetLastError(), strbuf, sizeof(strbuf));
! 3422: UNEXPECTED_ERROR(__FILE__, __LINE__, "getsockname: %s",
! 3423: strbuf);
! 3424: result = ISC_R_UNEXPECTED;
! 3425: goto out;
! 3426: }
! 3427: addressp->length = (unsigned int)len;
! 3428:
! 3429: out:
! 3430: UNLOCK(&sock->lock);
! 3431:
! 3432: return (result);
! 3433: }
! 3434:
! 3435: /*
! 3436: * Run through the list of events on this socket, and cancel the ones
! 3437: * queued for task "task" of type "how". "how" is a bitmask.
! 3438: */
! 3439: void
! 3440: isc_socket_cancel(isc_socket_t *sock, isc_task_t *task, unsigned int how) {
! 3441:
! 3442: REQUIRE(VALID_SOCKET(sock));
! 3443:
! 3444: /*
! 3445: * Quick exit if there is nothing to do. Don't even bother locking
! 3446: * in this case.
! 3447: */
! 3448: if (how == 0)
! 3449: return;
! 3450:
! 3451: LOCK(&sock->lock);
! 3452: CONSISTENT(sock);
! 3453:
! 3454: /*
! 3455: * make sure that the socket's not closed
! 3456: */
! 3457: if (sock->fd == INVALID_SOCKET) {
! 3458: UNLOCK(&sock->lock);
! 3459: return;
! 3460: }
! 3461:
! 3462: /*
! 3463: * All of these do the same thing, more or less.
! 3464: * Each will:
! 3465: * o If the internal event is marked as "posted" try to
! 3466: * remove it from the task's queue. If this fails, mark it
! 3467: * as canceled instead, and let the task clean it up later.
! 3468: * o For each I/O request for that task of that type, post
! 3469: * its done event with status of "ISC_R_CANCELED".
! 3470: * o Reset any state needed.
! 3471: */
! 3472:
! 3473: if ((how & ISC_SOCKCANCEL_RECV) == ISC_SOCKCANCEL_RECV) {
! 3474: isc_socketevent_t *dev;
! 3475: isc_socketevent_t *next;
! 3476: isc_task_t *current_task;
! 3477:
! 3478: dev = ISC_LIST_HEAD(sock->recv_list);
! 3479: while (dev != NULL) {
! 3480: current_task = dev->ev_sender;
! 3481: next = ISC_LIST_NEXT(dev, ev_link);
! 3482: if ((task == NULL) || (task == current_task)) {
! 3483: dev->result = ISC_R_CANCELED;
! 3484: send_recvdone_event(sock, &dev);
! 3485: }
! 3486: dev = next;
! 3487: }
! 3488: }
! 3489: how &= ~ISC_SOCKCANCEL_RECV;
! 3490:
! 3491: if ((how & ISC_SOCKCANCEL_SEND) == ISC_SOCKCANCEL_SEND) {
! 3492: isc_socketevent_t *dev;
! 3493: isc_socketevent_t *next;
! 3494: isc_task_t *current_task;
! 3495:
! 3496: dev = ISC_LIST_HEAD(sock->send_list);
! 3497:
! 3498: while (dev != NULL) {
! 3499: current_task = dev->ev_sender;
! 3500: next = ISC_LIST_NEXT(dev, ev_link);
! 3501: if ((task == NULL) || (task == current_task)) {
! 3502: dev->result = ISC_R_CANCELED;
! 3503: send_senddone_event(sock, &dev);
! 3504: }
! 3505: dev = next;
! 3506: }
! 3507: }
! 3508: how &= ~ISC_SOCKCANCEL_SEND;
! 3509:
! 3510: if (((how & ISC_SOCKCANCEL_ACCEPT) == ISC_SOCKCANCEL_ACCEPT)
! 3511: && !ISC_LIST_EMPTY(sock->accept_list)) {
! 3512: isc_socket_newconnev_t *dev;
! 3513: isc_socket_newconnev_t *next;
! 3514: isc_task_t *current_task;
! 3515:
! 3516: dev = ISC_LIST_HEAD(sock->accept_list);
! 3517: while (dev != NULL) {
! 3518: current_task = dev->ev_sender;
! 3519: next = ISC_LIST_NEXT(dev, ev_link);
! 3520:
! 3521: if ((task == NULL) || (task == current_task)) {
! 3522:
! 3523: dev->newsocket->references--;
! 3524: closesocket(dev->newsocket->fd);
! 3525: dev->newsocket->fd = INVALID_SOCKET;
! 3526: free_socket(&dev->newsocket, __LINE__);
! 3527:
! 3528: dev->result = ISC_R_CANCELED;
! 3529: send_acceptdone_event(sock, &dev);
! 3530: }
! 3531:
! 3532: dev = next;
! 3533: }
! 3534: }
! 3535: how &= ~ISC_SOCKCANCEL_ACCEPT;
! 3536:
! 3537: /*
! 3538: * Connecting is not a list.
! 3539: */
! 3540: if (((how & ISC_SOCKCANCEL_CONNECT) == ISC_SOCKCANCEL_CONNECT)
! 3541: && sock->connect_ev != NULL) {
! 3542: isc_socket_connev_t *dev;
! 3543: isc_task_t *current_task;
! 3544:
! 3545: INSIST(sock->pending_connect);
! 3546:
! 3547: dev = sock->connect_ev;
! 3548: current_task = dev->ev_sender;
! 3549:
! 3550: if ((task == NULL) || (task == current_task)) {
! 3551: closesocket(sock->fd);
! 3552: sock->fd = INVALID_SOCKET;
! 3553: _set_state(sock, SOCK_CLOSED);
! 3554:
! 3555: sock->connect_ev = NULL;
! 3556: dev->result = ISC_R_CANCELED;
! 3557: send_connectdone_event(sock, &dev);
! 3558: }
! 3559: }
! 3560: how &= ~ISC_SOCKCANCEL_CONNECT;
! 3561:
! 3562: maybe_free_socket(&sock, __LINE__);
! 3563: }
! 3564:
! 3565: isc_sockettype_t
! 3566: isc_socket_gettype(isc_socket_t *sock) {
! 3567: isc_sockettype_t type;
! 3568:
! 3569: REQUIRE(VALID_SOCKET(sock));
! 3570:
! 3571: LOCK(&sock->lock);
! 3572:
! 3573: /*
! 3574: * make sure that the socket's not closed
! 3575: */
! 3576: if (sock->fd == INVALID_SOCKET) {
! 3577: UNLOCK(&sock->lock);
! 3578: return (ISC_R_CONNREFUSED);
! 3579: }
! 3580:
! 3581: type = sock->type;
! 3582: UNLOCK(&sock->lock);
! 3583: return (type);
! 3584: }
! 3585:
! 3586: isc_boolean_t
! 3587: isc_socket_isbound(isc_socket_t *sock) {
! 3588: isc_boolean_t val;
! 3589:
! 3590: REQUIRE(VALID_SOCKET(sock));
! 3591:
! 3592: LOCK(&sock->lock);
! 3593: CONSISTENT(sock);
! 3594:
! 3595: /*
! 3596: * make sure that the socket's not closed
! 3597: */
! 3598: if (sock->fd == INVALID_SOCKET) {
! 3599: UNLOCK(&sock->lock);
! 3600: return (ISC_FALSE);
! 3601: }
! 3602:
! 3603: val = ((sock->bound) ? ISC_TRUE : ISC_FALSE);
! 3604: UNLOCK(&sock->lock);
! 3605:
! 3606: return (val);
! 3607: }
! 3608:
! 3609: void
! 3610: isc_socket_ipv6only(isc_socket_t *sock, isc_boolean_t yes) {
! 3611: #if defined(IPV6_V6ONLY)
! 3612: int onoff = yes ? 1 : 0;
! 3613: #else
! 3614: UNUSED(yes);
! 3615: #endif
! 3616:
! 3617: REQUIRE(VALID_SOCKET(sock));
! 3618:
! 3619: #ifdef IPV6_V6ONLY
! 3620: if (sock->pf == AF_INET6) {
! 3621: (void)setsockopt(sock->fd, IPPROTO_IPV6, IPV6_V6ONLY,
! 3622: (void *)&onoff, sizeof(onoff));
! 3623: }
! 3624: #endif
! 3625: }
! 3626:
! 3627: void
! 3628: isc_socket_cleanunix(isc_sockaddr_t *addr, isc_boolean_t active) {
! 3629: UNUSED(addr);
! 3630: UNUSED(active);
! 3631: }
! 3632:
! 3633: isc_result_t
! 3634: isc_socket_permunix(isc_sockaddr_t *addr, isc_uint32_t perm,
! 3635: isc_uint32_t owner, isc_uint32_t group)
! 3636: {
! 3637: UNUSED(addr);
! 3638: UNUSED(perm);
! 3639: UNUSED(owner);
! 3640: UNUSED(group);
! 3641: return (ISC_R_NOTIMPLEMENTED);
! 3642: }
! 3643:
! 3644: void
! 3645: isc_socket_setname(isc_socket_t *socket, const char *name, void *tag) {
! 3646:
! 3647: /*
! 3648: * Name 'socket'.
! 3649: */
! 3650:
! 3651: REQUIRE(VALID_SOCKET(socket));
! 3652:
! 3653: LOCK(&socket->lock);
! 3654: memset(socket->name, 0, sizeof(socket->name));
! 3655: strncpy(socket->name, name, sizeof(socket->name) - 1);
! 3656: socket->tag = tag;
! 3657: UNLOCK(&socket->lock);
! 3658: }
! 3659:
! 3660: const char *
! 3661: isc_socket_getname(isc_socket_t *socket) {
! 3662: return (socket->name);
! 3663: }
! 3664:
! 3665: void *
! 3666: isc_socket_gettag(isc_socket_t *socket) {
! 3667: return (socket->tag);
! 3668: }
! 3669:
! 3670: void
! 3671: isc__socketmgr_setreserved(isc_socketmgr_t *manager, isc_uint32_t reserved) {
! 3672: UNUSED(manager);
! 3673: UNUSED(reserved);
! 3674: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>