Annotation of embedaddon/ntp/lib/isc/unix/socket.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  * Copyright (C) 2004-2009  Internet Systems Consortium, Inc. ("ISC")
        !             3:  * Copyright (C) 1998-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.308.12.8 2009/04/18 01:29:26 jinmei Exp $ */
        !            19: 
        !            20: /*! \file */
        !            21: 
        !            22: #include <config.h>
        !            23: 
        !            24: #include <sys/param.h>
        !            25: #include <sys/types.h>
        !            26: #include <sys/socket.h>
        !            27: #include <sys/stat.h>
        !            28: #include <sys/time.h>
        !            29: #include <sys/uio.h>
        !            30: 
        !            31: #include <errno.h>
        !            32: #include <fcntl.h>
        !            33: #include <stddef.h>
        !            34: #include <stdlib.h>
        !            35: #include <string.h>
        !            36: #include <unistd.h>
        !            37: 
        !            38: #include <isc/buffer.h>
        !            39: #include <isc/bufferlist.h>
        !            40: #include <isc/condition.h>
        !            41: #include <isc/formatcheck.h>
        !            42: #include <isc/list.h>
        !            43: #include <isc/log.h>
        !            44: #include <isc/mem.h>
        !            45: #include <isc/msgs.h>
        !            46: #include <isc/mutex.h>
        !            47: #include <isc/net.h>
        !            48: #include <isc/once.h>
        !            49: #include <isc/platform.h>
        !            50: #include <isc/print.h>
        !            51: #include <isc/region.h>
        !            52: #include <isc/socket.h>
        !            53: #include <isc/stats.h>
        !            54: #include <isc/strerror.h>
        !            55: #include <isc/task.h>
        !            56: #include <isc/thread.h>
        !            57: #include <isc/util.h>
        !            58: #include <isc/xml.h>
        !            59: 
        !            60: #ifdef ISC_PLATFORM_HAVESYSUNH
        !            61: #include <sys/un.h>
        !            62: #endif
        !            63: #ifdef ISC_PLATFORM_HAVEKQUEUE
        !            64: #include <sys/event.h>
        !            65: #endif
        !            66: #ifdef ISC_PLATFORM_HAVEEPOLL
        !            67: #include <sys/epoll.h>
        !            68: #endif
        !            69: #ifdef ISC_PLATFORM_HAVEDEVPOLL
        !            70: #include <sys/devpoll.h>
        !            71: #endif
        !            72: 
        !            73: #include "errno2result.h"
        !            74: 
        !            75: #ifndef ISC_PLATFORM_USETHREADS
        !            76: #include "socket_p.h"
        !            77: #endif /* ISC_PLATFORM_USETHREADS */
        !            78: 
        !            79: #if defined(SO_BSDCOMPAT) && defined(__linux__)
        !            80: #include <sys/utsname.h>
        !            81: #endif
        !            82: 
        !            83: /*%
        !            84:  * Choose the most preferable multiplex method.
        !            85:  */
        !            86: #ifdef ISC_PLATFORM_HAVEKQUEUE
        !            87: #define USE_KQUEUE
        !            88: #elif defined (ISC_PLATFORM_HAVEEPOLL)
        !            89: #define USE_EPOLL
        !            90: #elif defined (ISC_PLATFORM_HAVEDEVPOLL)
        !            91: #define USE_DEVPOLL
        !            92: typedef struct {
        !            93:        unsigned int want_read : 1,
        !            94:                want_write : 1;
        !            95: } pollinfo_t;
        !            96: #else
        !            97: #define USE_SELECT
        !            98: #endif /* ISC_PLATFORM_HAVEKQUEUE */
        !            99: 
        !           100: #ifndef ISC_PLATFORM_USETHREADS
        !           101: #if defined(USE_KQUEUE) || defined(USE_EPOLL) || defined(USE_DEVPOLL)
        !           102: struct isc_socketwait {
        !           103:        int nevents;
        !           104: };
        !           105: #elif defined (USE_SELECT)
        !           106: struct isc_socketwait {
        !           107:        fd_set *readset;
        !           108:        fd_set *writeset;
        !           109:        int nfds;
        !           110:        int maxfd;
        !           111: };
        !           112: #endif /* USE_KQUEUE */
        !           113: #endif /* !ISC_PLATFORM_USETHREADS */
        !           114: 
        !           115: /*%
        !           116:  * Maximum number of allowable open sockets.  This is also the maximum
        !           117:  * allowable socket file descriptor.
        !           118:  *
        !           119:  * Care should be taken before modifying this value for select():
        !           120:  * The API standard doesn't ensure select() accept more than (the system default
        !           121:  * of) FD_SETSIZE descriptors, and the default size should in fact be fine in
        !           122:  * the vast majority of cases.  This constant should therefore be increased only
        !           123:  * when absolutely necessary and possible, i.e., the server is exhausting all
        !           124:  * available file descriptors (up to FD_SETSIZE) and the select() function
        !           125:  * and FD_xxx macros support larger values than FD_SETSIZE (which may not
        !           126:  * always by true, but we keep using some of them to ensure as much
        !           127:  * portability as possible).  Note also that overall server performance
        !           128:  * may be rather worsened with a larger value of this constant due to
        !           129:  * inherent scalability problems of select().
        !           130:  *
        !           131:  * As a special note, this value shouldn't have to be touched if
        !           132:  * this is a build for an authoritative only DNS server.
        !           133:  */
        !           134: #ifndef ISC_SOCKET_MAXSOCKETS
        !           135: #if defined(USE_KQUEUE) || defined(USE_EPOLL) || defined(USE_DEVPOLL)
        !           136: #define ISC_SOCKET_MAXSOCKETS 4096
        !           137: #elif defined(USE_SELECT)
        !           138: #define ISC_SOCKET_MAXSOCKETS FD_SETSIZE
        !           139: #endif /* USE_KQUEUE... */
        !           140: #endif /* ISC_SOCKET_MAXSOCKETS */
        !           141: 
        !           142: #ifdef USE_SELECT
        !           143: /*%
        !           144:  * Mac OS X needs a special definition to support larger values in select().
        !           145:  * We always define this because a larger value can be specified run-time.
        !           146:  */
        !           147: #ifdef __APPLE__
        !           148: #define _DARWIN_UNLIMITED_SELECT
        !           149: #endif /* __APPLE__ */
        !           150: #endif /* USE_SELECT */
        !           151: 
        !           152: #ifdef ISC_SOCKET_USE_POLLWATCH
        !           153: /*%
        !           154:  * If this macro is defined, enable workaround for a Solaris /dev/poll kernel
        !           155:  * bug: DP_POLL ioctl could keep sleeping even if socket I/O is possible for
        !           156:  * some of the specified FD.  The idea is based on the observation that it's
        !           157:  * likely for a busy server to keep receiving packets.  It specifically works
        !           158:  * as follows: the socket watcher is first initialized with the state of
        !           159:  * "poll_idle".  While it's in the idle state it keeps sleeping until a socket
        !           160:  * event occurs.  When it wakes up for a socket I/O event, it moves to the
        !           161:  * poll_active state, and sets the poll timeout to a short period
        !           162:  * (ISC_SOCKET_POLLWATCH_TIMEOUT msec).  If timeout occurs in this state, the
        !           163:  * watcher goes to the poll_checking state with the same timeout period.
        !           164:  * In this state, the watcher tries to detect whether this is a break
        !           165:  * during intermittent events or the kernel bug is triggered.  If the next
        !           166:  * polling reports an event within the short period, the previous timeout is
        !           167:  * likely to be a kernel bug, and so the watcher goes back to the active state.
        !           168:  * Otherwise, it moves to the idle state again.
        !           169:  *
        !           170:  * It's not clear whether this is a thread-related bug, but since we've only
        !           171:  * seen this with threads, this workaround is used only when enabling threads.
        !           172:  */
        !           173: 
        !           174: typedef enum { poll_idle, poll_active, poll_checking } pollstate_t;
        !           175: 
        !           176: #ifndef ISC_SOCKET_POLLWATCH_TIMEOUT
        !           177: #define ISC_SOCKET_POLLWATCH_TIMEOUT 10
        !           178: #endif /* ISC_SOCKET_POLLWATCH_TIMEOUT */
        !           179: #endif /* ISC_SOCKET_USE_POLLWATCH */
        !           180: 
        !           181: /*%
        !           182:  * Size of per-FD lock buckets.
        !           183:  */
        !           184: #ifdef ISC_PLATFORM_USETHREADS
        !           185: #define FDLOCK_COUNT           1024
        !           186: #define FDLOCK_ID(fd)          ((fd) % FDLOCK_COUNT)
        !           187: #else
        !           188: #define FDLOCK_COUNT           1
        !           189: #define FDLOCK_ID(fd)          0
        !           190: #endif /* ISC_PLATFORM_USETHREADS */
        !           191: 
        !           192: /*%
        !           193:  * Maximum number of events communicated with the kernel.  There should normally
        !           194:  * be no need for having a large number.
        !           195:  */
        !           196: #if defined(USE_KQUEUE) || defined(USE_EPOLL) || defined(USE_DEVPOLL)
        !           197: #ifndef ISC_SOCKET_MAXEVENTS
        !           198: #define ISC_SOCKET_MAXEVENTS   64
        !           199: #endif
        !           200: #endif
        !           201: 
        !           202: /*%
        !           203:  * Some systems define the socket length argument as an int, some as size_t,
        !           204:  * some as socklen_t.  This is here so it can be easily changed if needed.
        !           205:  */
        !           206: #ifndef ISC_SOCKADDR_LEN_T
        !           207: #define ISC_SOCKADDR_LEN_T unsigned int
        !           208: #endif
        !           209: 
        !           210: /*%
        !           211:  * Define what the possible "soft" errors can be.  These are non-fatal returns
        !           212:  * of various network related functions, like recv() and so on.
        !           213:  *
        !           214:  * For some reason, BSDI (and perhaps others) will sometimes return <0
        !           215:  * from recv() but will have errno==0.  This is broken, but we have to
        !           216:  * work around it here.
        !           217:  */
        !           218: #define SOFT_ERROR(e)  ((e) == EAGAIN || \
        !           219:                         (e) == EWOULDBLOCK || \
        !           220:                         (e) == EINTR || \
        !           221:                         (e) == 0)
        !           222: 
        !           223: #define DLVL(x) ISC_LOGCATEGORY_GENERAL, ISC_LOGMODULE_SOCKET, ISC_LOG_DEBUG(x)
        !           224: 
        !           225: /*!<
        !           226:  * DLVL(90)  --  Function entry/exit and other tracing.
        !           227:  * DLVL(70)  --  Socket "correctness" -- including returning of events, etc.
        !           228:  * DLVL(60)  --  Socket data send/receive
        !           229:  * DLVL(50)  --  Event tracing, including receiving/sending completion events.
        !           230:  * DLVL(20)  --  Socket creation/destruction.
        !           231:  */
        !           232: #define TRACE_LEVEL            90
        !           233: #define CORRECTNESS_LEVEL      70
        !           234: #define IOEVENT_LEVEL          60
        !           235: #define EVENT_LEVEL            50
        !           236: #define CREATION_LEVEL         20
        !           237: 
        !           238: #define TRACE          DLVL(TRACE_LEVEL)
        !           239: #define CORRECTNESS    DLVL(CORRECTNESS_LEVEL)
        !           240: #define IOEVENT                DLVL(IOEVENT_LEVEL)
        !           241: #define EVENT          DLVL(EVENT_LEVEL)
        !           242: #define CREATION       DLVL(CREATION_LEVEL)
        !           243: 
        !           244: typedef isc_event_t intev_t;
        !           245: 
        !           246: #define SOCKET_MAGIC           ISC_MAGIC('I', 'O', 'i', 'o')
        !           247: #define VALID_SOCKET(t)                ISC_MAGIC_VALID(t, SOCKET_MAGIC)
        !           248: 
        !           249: /*!
        !           250:  * IPv6 control information.  If the socket is an IPv6 socket we want
        !           251:  * to collect the destination address and interface so the client can
        !           252:  * set them on outgoing packets.
        !           253:  */
        !           254: #ifdef ISC_PLATFORM_HAVEIN6PKTINFO
        !           255: #ifndef USE_CMSG
        !           256: #define USE_CMSG       1
        !           257: #endif
        !           258: #endif
        !           259: 
        !           260: /*%
        !           261:  * NetBSD and FreeBSD can timestamp packets.  XXXMLG Should we have
        !           262:  * a setsockopt() like interface to request timestamps, and if the OS
        !           263:  * doesn't do it for us, call gettimeofday() on every UDP receive?
        !           264:  */
        !           265: #ifdef SO_TIMESTAMP
        !           266: #ifndef USE_CMSG
        !           267: #define USE_CMSG       1
        !           268: #endif
        !           269: #endif
        !           270: 
        !           271: /*%
        !           272:  * The size to raise the receive buffer to (from BIND 8).
        !           273:  */
        !           274: #define RCVBUFSIZE (32*1024)
        !           275: 
        !           276: /*%
        !           277:  * The number of times a send operation is repeated if the result is EINTR.
        !           278:  */
        !           279: #define NRETRIES 10
        !           280: 
        !           281: struct isc_socket {
        !           282:        /* Not locked. */
        !           283:        unsigned int            magic;
        !           284:        isc_socketmgr_t        *manager;
        !           285:        isc_mutex_t             lock;
        !           286:        isc_sockettype_t        type;
        !           287:        const isc_statscounter_t        *statsindex;
        !           288: 
        !           289:        /* Locked by socket lock. */
        !           290:        ISC_LINK(isc_socket_t)  link;
        !           291:        unsigned int            references;
        !           292:        int                     fd;
        !           293:        int                     pf;
        !           294:        char                            name[16];
        !           295:        void *                          tag;
        !           296: 
        !           297:        ISC_LIST(isc_socketevent_t)             send_list;
        !           298:        ISC_LIST(isc_socketevent_t)             recv_list;
        !           299:        ISC_LIST(isc_socket_newconnev_t)        accept_list;
        !           300:        isc_socket_connev_t                    *connect_ev;
        !           301: 
        !           302:        /*
        !           303:         * Internal events.  Posted when a descriptor is readable or
        !           304:         * writable.  These are statically allocated and never freed.
        !           305:         * They will be set to non-purgable before use.
        !           306:         */
        !           307:        intev_t                 readable_ev;
        !           308:        intev_t                 writable_ev;
        !           309: 
        !           310:        isc_sockaddr_t          peer_address;  /* remote address */
        !           311: 
        !           312:        unsigned int            pending_recv : 1,
        !           313:                                pending_send : 1,
        !           314:                                pending_accept : 1,
        !           315:                                listener : 1, /* listener socket */
        !           316:                                connected : 1,
        !           317:                                connecting : 1, /* connect pending */
        !           318:                                bound : 1; /* bound to local addr */
        !           319: 
        !           320: #ifdef ISC_NET_RECVOVERFLOW
        !           321:        unsigned char           overflow; /* used for MSG_TRUNC fake */
        !           322: #endif
        !           323: 
        !           324:        char                    *recvcmsgbuf;
        !           325:        ISC_SOCKADDR_LEN_T      recvcmsgbuflen;
        !           326:        char                    *sendcmsgbuf;
        !           327:        ISC_SOCKADDR_LEN_T      sendcmsgbuflen;
        !           328: 
        !           329:        void                    *fdwatcharg;
        !           330:        isc_sockfdwatch_t       fdwatchcb;
        !           331:        int                     fdwatchflags;
        !           332:        isc_task_t              *fdwatchtask;
        !           333: };
        !           334: 
        !           335: #define SOCKET_MANAGER_MAGIC   ISC_MAGIC('I', 'O', 'm', 'g')
        !           336: #define VALID_MANAGER(m)       ISC_MAGIC_VALID(m, SOCKET_MANAGER_MAGIC)
        !           337: 
        !           338: struct isc_socketmgr {
        !           339:        /* Not locked. */
        !           340:        unsigned int            magic;
        !           341:        isc_mem_t              *mctx;
        !           342:        isc_mutex_t             lock;
        !           343:        isc_mutex_t             *fdlock;
        !           344:        isc_stats_t             *stats;
        !           345: #ifdef USE_KQUEUE
        !           346:        int                     kqueue_fd;
        !           347:        int                     nevents;
        !           348:        struct kevent           *events;
        !           349: #endif /* USE_KQUEUE */
        !           350: #ifdef USE_EPOLL
        !           351:        int                     epoll_fd;
        !           352:        int                     nevents;
        !           353:        struct epoll_event      *events;
        !           354: #endif /* USE_EPOLL */
        !           355: #ifdef USE_DEVPOLL
        !           356:        int                     devpoll_fd;
        !           357:        int                     nevents;
        !           358:        struct pollfd           *events;
        !           359: #endif /* USE_DEVPOLL */
        !           360: #ifdef USE_SELECT
        !           361:        int                     fd_bufsize;
        !           362: #endif /* USE_SELECT */
        !           363:        unsigned int            maxsocks;
        !           364: #ifdef ISC_PLATFORM_USETHREADS
        !           365:        int                     pipe_fds[2];
        !           366: #endif
        !           367: 
        !           368:        /* Locked by fdlock. */
        !           369:        isc_socket_t           **fds;
        !           370:        int                     *fdstate;
        !           371: #ifdef USE_DEVPOLL
        !           372:        pollinfo_t              *fdpollinfo;
        !           373: #endif
        !           374: 
        !           375:        /* Locked by manager lock. */
        !           376:        ISC_LIST(isc_socket_t)  socklist;
        !           377: #ifdef USE_SELECT
        !           378:        fd_set                  *read_fds;
        !           379:        fd_set                  *read_fds_copy;
        !           380:        fd_set                  *write_fds;
        !           381:        fd_set                  *write_fds_copy;
        !           382:        int                     maxfd;
        !           383: #endif /* USE_SELECT */
        !           384:        int                     reserved;       /* unlocked */
        !           385: #ifdef ISC_PLATFORM_USETHREADS
        !           386:        isc_thread_t            watcher;
        !           387:        isc_condition_t         shutdown_ok;
        !           388: #else /* ISC_PLATFORM_USETHREADS */
        !           389:        unsigned int            refs;
        !           390: #endif /* ISC_PLATFORM_USETHREADS */
        !           391: };
        !           392: 
        !           393: #ifndef ISC_PLATFORM_USETHREADS
        !           394: static isc_socketmgr_t *socketmgr = NULL;
        !           395: #endif /* ISC_PLATFORM_USETHREADS */
        !           396: 
        !           397: #define CLOSED                 0       /* this one must be zero */
        !           398: #define MANAGED                        1
        !           399: #define CLOSE_PENDING          2
        !           400: 
        !           401: /*
        !           402:  * send() and recv() iovec counts
        !           403:  */
        !           404: #define MAXSCATTERGATHER_SEND  (ISC_SOCKET_MAXSCATTERGATHER)
        !           405: #ifdef ISC_NET_RECVOVERFLOW
        !           406: # define MAXSCATTERGATHER_RECV (ISC_SOCKET_MAXSCATTERGATHER + 1)
        !           407: #else
        !           408: # define MAXSCATTERGATHER_RECV (ISC_SOCKET_MAXSCATTERGATHER)
        !           409: #endif
        !           410: 
        !           411: static void send_recvdone_event(isc_socket_t *, isc_socketevent_t **);
        !           412: static void send_senddone_event(isc_socket_t *, isc_socketevent_t **);
        !           413: static void free_socket(isc_socket_t **);
        !           414: static isc_result_t allocate_socket(isc_socketmgr_t *, isc_sockettype_t,
        !           415:                                    isc_socket_t **);
        !           416: static void destroy(isc_socket_t **);
        !           417: static void internal_accept(isc_task_t *, isc_event_t *);
        !           418: static void internal_connect(isc_task_t *, isc_event_t *);
        !           419: static void internal_recv(isc_task_t *, isc_event_t *);
        !           420: static void internal_send(isc_task_t *, isc_event_t *);
        !           421: static void internal_fdwatch_write(isc_task_t *, isc_event_t *);
        !           422: static void internal_fdwatch_read(isc_task_t *, isc_event_t *);
        !           423: static void process_cmsg(isc_socket_t *, struct msghdr *, isc_socketevent_t *);
        !           424: static void build_msghdr_send(isc_socket_t *, isc_socketevent_t *,
        !           425:                              struct msghdr *, struct iovec *, size_t *);
        !           426: static void build_msghdr_recv(isc_socket_t *, isc_socketevent_t *,
        !           427:                              struct msghdr *, struct iovec *, size_t *);
        !           428: #ifdef ISC_PLATFORM_USETHREADS
        !           429: static isc_boolean_t process_ctlfd(isc_socketmgr_t *manager);
        !           430: #endif
        !           431: 
        !           432: #define SELECT_POKE_SHUTDOWN           (-1)
        !           433: #define SELECT_POKE_NOTHING            (-2)
        !           434: #define SELECT_POKE_READ               (-3)
        !           435: #define SELECT_POKE_ACCEPT             (-3) /*%< Same as _READ */
        !           436: #define SELECT_POKE_WRITE              (-4)
        !           437: #define SELECT_POKE_CONNECT            (-4) /*%< Same as _WRITE */
        !           438: #define SELECT_POKE_CLOSE              (-5)
        !           439: 
        !           440: #define SOCK_DEAD(s)                   ((s)->references == 0)
        !           441: 
        !           442: /*%
        !           443:  * Shortcut index arrays to get access to statistics counters.
        !           444:  */
        !           445: enum {
        !           446:        STATID_OPEN = 0,
        !           447:        STATID_OPENFAIL = 1,
        !           448:        STATID_CLOSE = 2,
        !           449:        STATID_BINDFAIL = 3,
        !           450:        STATID_CONNECTFAIL = 4,
        !           451:        STATID_CONNECT = 5,
        !           452:        STATID_ACCEPTFAIL = 6,
        !           453:        STATID_ACCEPT = 7,
        !           454:        STATID_SENDFAIL = 8,
        !           455:        STATID_RECVFAIL = 9
        !           456: };
        !           457: static const isc_statscounter_t upd4statsindex[] = {
        !           458:        isc_sockstatscounter_udp4open,
        !           459:        isc_sockstatscounter_udp4openfail,
        !           460:        isc_sockstatscounter_udp4close,
        !           461:        isc_sockstatscounter_udp4bindfail,
        !           462:        isc_sockstatscounter_udp4connectfail,
        !           463:        isc_sockstatscounter_udp4connect,
        !           464:        -1,
        !           465:        -1,
        !           466:        isc_sockstatscounter_udp4sendfail,
        !           467:        isc_sockstatscounter_udp4recvfail
        !           468: };
        !           469: static const isc_statscounter_t upd6statsindex[] = {
        !           470:        isc_sockstatscounter_udp6open,
        !           471:        isc_sockstatscounter_udp6openfail,
        !           472:        isc_sockstatscounter_udp6close,
        !           473:        isc_sockstatscounter_udp6bindfail,
        !           474:        isc_sockstatscounter_udp6connectfail,
        !           475:        isc_sockstatscounter_udp6connect,
        !           476:        -1,
        !           477:        -1,
        !           478:        isc_sockstatscounter_udp6sendfail,
        !           479:        isc_sockstatscounter_udp6recvfail
        !           480: };
        !           481: static const isc_statscounter_t tcp4statsindex[] = {
        !           482:        isc_sockstatscounter_tcp4open,
        !           483:        isc_sockstatscounter_tcp4openfail,
        !           484:        isc_sockstatscounter_tcp4close,
        !           485:        isc_sockstatscounter_tcp4bindfail,
        !           486:        isc_sockstatscounter_tcp4connectfail,
        !           487:        isc_sockstatscounter_tcp4connect,
        !           488:        isc_sockstatscounter_tcp4acceptfail,
        !           489:        isc_sockstatscounter_tcp4accept,
        !           490:        isc_sockstatscounter_tcp4sendfail,
        !           491:        isc_sockstatscounter_tcp4recvfail
        !           492: };
        !           493: static const isc_statscounter_t tcp6statsindex[] = {
        !           494:        isc_sockstatscounter_tcp6open,
        !           495:        isc_sockstatscounter_tcp6openfail,
        !           496:        isc_sockstatscounter_tcp6close,
        !           497:        isc_sockstatscounter_tcp6bindfail,
        !           498:        isc_sockstatscounter_tcp6connectfail,
        !           499:        isc_sockstatscounter_tcp6connect,
        !           500:        isc_sockstatscounter_tcp6acceptfail,
        !           501:        isc_sockstatscounter_tcp6accept,
        !           502:        isc_sockstatscounter_tcp6sendfail,
        !           503:        isc_sockstatscounter_tcp6recvfail
        !           504: };
        !           505: static const isc_statscounter_t unixstatsindex[] = {
        !           506:        isc_sockstatscounter_unixopen,
        !           507:        isc_sockstatscounter_unixopenfail,
        !           508:        isc_sockstatscounter_unixclose,
        !           509:        isc_sockstatscounter_unixbindfail,
        !           510:        isc_sockstatscounter_unixconnectfail,
        !           511:        isc_sockstatscounter_unixconnect,
        !           512:        isc_sockstatscounter_unixacceptfail,
        !           513:        isc_sockstatscounter_unixaccept,
        !           514:        isc_sockstatscounter_unixsendfail,
        !           515:        isc_sockstatscounter_unixrecvfail
        !           516: };
        !           517: static const isc_statscounter_t fdwatchstatsindex[] = {
        !           518:        -1,
        !           519:        -1,
        !           520:        isc_sockstatscounter_fdwatchclose,
        !           521:        isc_sockstatscounter_fdwatchbindfail,
        !           522:        isc_sockstatscounter_fdwatchconnectfail,
        !           523:        isc_sockstatscounter_fdwatchconnect,
        !           524:        -1,
        !           525:        -1,
        !           526:        isc_sockstatscounter_fdwatchsendfail,
        !           527:        isc_sockstatscounter_fdwatchrecvfail
        !           528: };
        !           529: 
        !           530: static void
        !           531: manager_log(isc_socketmgr_t *sockmgr,
        !           532:            isc_logcategory_t *category, isc_logmodule_t *module, int level,
        !           533:            const char *fmt, ...) ISC_FORMAT_PRINTF(5, 6);
        !           534: static void
        !           535: manager_log(isc_socketmgr_t *sockmgr,
        !           536:            isc_logcategory_t *category, isc_logmodule_t *module, int level,
        !           537:            const char *fmt, ...)
        !           538: {
        !           539:        char msgbuf[2048];
        !           540:        va_list ap;
        !           541: 
        !           542:        if (! isc_log_wouldlog(isc_lctx, level))
        !           543:                return;
        !           544: 
        !           545:        va_start(ap, fmt);
        !           546:        vsnprintf(msgbuf, sizeof(msgbuf), fmt, ap);
        !           547:        va_end(ap);
        !           548: 
        !           549:        isc_log_write(isc_lctx, category, module, level,
        !           550:                      "sockmgr %p: %s", sockmgr, msgbuf);
        !           551: }
        !           552: 
        !           553: static void
        !           554: socket_log(isc_socket_t *sock, isc_sockaddr_t *address,
        !           555:           isc_logcategory_t *category, isc_logmodule_t *module, int level,
        !           556:           isc_msgcat_t *msgcat, int msgset, int message,
        !           557:           const char *fmt, ...) ISC_FORMAT_PRINTF(9, 10);
        !           558: static void
        !           559: socket_log(isc_socket_t *sock, isc_sockaddr_t *address,
        !           560:           isc_logcategory_t *category, isc_logmodule_t *module, int level,
        !           561:           isc_msgcat_t *msgcat, int msgset, int message,
        !           562:           const char *fmt, ...)
        !           563: {
        !           564:        char msgbuf[2048];
        !           565:        char peerbuf[ISC_SOCKADDR_FORMATSIZE];
        !           566:        va_list ap;
        !           567: 
        !           568:        if (! isc_log_wouldlog(isc_lctx, level))
        !           569:                return;
        !           570: 
        !           571:        va_start(ap, fmt);
        !           572:        vsnprintf(msgbuf, sizeof(msgbuf), fmt, ap);
        !           573:        va_end(ap);
        !           574: 
        !           575:        if (address == NULL) {
        !           576:                isc_log_iwrite(isc_lctx, category, module, level,
        !           577:                               msgcat, msgset, message,
        !           578:                               "socket %p: %s", sock, msgbuf);
        !           579:        } else {
        !           580:                isc_sockaddr_format(address, peerbuf, sizeof(peerbuf));
        !           581:                isc_log_iwrite(isc_lctx, category, module, level,
        !           582:                               msgcat, msgset, message,
        !           583:                               "socket %p %s: %s", sock, peerbuf, msgbuf);
        !           584:        }
        !           585: }
        !           586: 
        !           587: #if defined(_AIX) && defined(ISC_NET_BSD44MSGHDR) && \
        !           588:     defined(USE_CMSG) && defined(IPV6_RECVPKTINFO)
        !           589: /*
        !           590:  * AIX has a kernel bug where IPV6_RECVPKTINFO gets cleared by
        !           591:  * setting IPV6_V6ONLY.
        !           592:  */
        !           593: static void
        !           594: FIX_IPV6_RECVPKTINFO(isc_socket_t *sock)
        !           595: {
        !           596:        char strbuf[ISC_STRERRORSIZE];
        !           597:        int on = 1;
        !           598: 
        !           599:        if (sock->pf != AF_INET6 || sock->type != isc_sockettype_udp)
        !           600:                return;
        !           601: 
        !           602:        if (setsockopt(sock->fd, IPPROTO_IPV6, IPV6_RECVPKTINFO,
        !           603:                       (void *)&on, sizeof(on)) < 0) {
        !           604: 
        !           605:                UNEXPECTED_ERROR(__FILE__, __LINE__,
        !           606:                                 "setsockopt(%d, IPV6_RECVPKTINFO) "
        !           607:                                 "%s: %s", sock->fd,
        !           608:                                 isc_msgcat_get(isc_msgcat,
        !           609:                                                ISC_MSGSET_GENERAL,
        !           610:                                                ISC_MSG_FAILED,
        !           611:                                                "failed"),
        !           612:                                 strbuf);
        !           613:        }
        !           614: }
        !           615: #else
        !           616: #define FIX_IPV6_RECVPKTINFO(sock) (void)0
        !           617: #endif
        !           618: 
        !           619: /*%
        !           620:  * Increment socket-related statistics counters.
        !           621:  */
        !           622: static inline void
        !           623: inc_stats(isc_stats_t *stats, isc_statscounter_t counterid) {
        !           624:        REQUIRE(counterid != -1);
        !           625: 
        !           626:        if (stats != NULL)
        !           627:                isc_stats_increment(stats, counterid);
        !           628: }
        !           629: 
        !           630: static inline isc_result_t
        !           631: watch_fd(isc_socketmgr_t *manager, int fd, int msg) {
        !           632:        isc_result_t result = ISC_R_SUCCESS;
        !           633: 
        !           634: #ifdef USE_KQUEUE
        !           635:        struct kevent evchange;
        !           636: 
        !           637:        memset(&evchange, 0, sizeof(evchange));
        !           638:        if (msg == SELECT_POKE_READ)
        !           639:                evchange.filter = EVFILT_READ;
        !           640:        else
        !           641:                evchange.filter = EVFILT_WRITE;
        !           642:        evchange.flags = EV_ADD;
        !           643:        evchange.ident = fd;
        !           644:        if (kevent(manager->kqueue_fd, &evchange, 1, NULL, 0, NULL) != 0)
        !           645:                result = isc__errno2result(errno);
        !           646: 
        !           647:        return (result);
        !           648: #elif defined(USE_EPOLL)
        !           649:        struct epoll_event event;
        !           650: 
        !           651:        if (msg == SELECT_POKE_READ)
        !           652:                event.events = EPOLLIN;
        !           653:        else
        !           654:                event.events = EPOLLOUT;
        !           655:        event.data.fd = fd;
        !           656:        if (epoll_ctl(manager->epoll_fd, EPOLL_CTL_ADD, fd, &event) == -1 &&
        !           657:            errno != EEXIST) {
        !           658:                result = isc__errno2result(errno);
        !           659:        }
        !           660: 
        !           661:        return (result);
        !           662: #elif defined(USE_DEVPOLL)
        !           663:        struct pollfd pfd;
        !           664:        int lockid = FDLOCK_ID(fd);
        !           665: 
        !           666:        memset(&pfd, 0, sizeof(pfd));
        !           667:        if (msg == SELECT_POKE_READ)
        !           668:                pfd.events = POLLIN;
        !           669:        else
        !           670:                pfd.events = POLLOUT;
        !           671:        pfd.fd = fd;
        !           672:        pfd.revents = 0;
        !           673:        LOCK(&manager->fdlock[lockid]);
        !           674:        if (write(manager->devpoll_fd, &pfd, sizeof(pfd)) == -1)
        !           675:                result = isc__errno2result(errno);
        !           676:        else {
        !           677:                if (msg == SELECT_POKE_READ)
        !           678:                        manager->fdpollinfo[fd].want_read = 1;
        !           679:                else
        !           680:                        manager->fdpollinfo[fd].want_write = 1;
        !           681:        }
        !           682:        UNLOCK(&manager->fdlock[lockid]);
        !           683: 
        !           684:        return (result);
        !           685: #elif defined(USE_SELECT)
        !           686:        LOCK(&manager->lock);
        !           687:        if (msg == SELECT_POKE_READ)
        !           688:                FD_SET(fd, manager->read_fds);
        !           689:        if (msg == SELECT_POKE_WRITE)
        !           690:                FD_SET(fd, manager->write_fds);
        !           691:        UNLOCK(&manager->lock);
        !           692: 
        !           693:        return (result);
        !           694: #endif
        !           695: }
        !           696: 
        !           697: static inline isc_result_t
        !           698: unwatch_fd(isc_socketmgr_t *manager, int fd, int msg) {
        !           699:        isc_result_t result = ISC_R_SUCCESS;
        !           700: 
        !           701: #ifdef USE_KQUEUE
        !           702:        struct kevent evchange;
        !           703: 
        !           704:        memset(&evchange, 0, sizeof(evchange));
        !           705:        if (msg == SELECT_POKE_READ)
        !           706:                evchange.filter = EVFILT_READ;
        !           707:        else
        !           708:                evchange.filter = EVFILT_WRITE;
        !           709:        evchange.flags = EV_DELETE;
        !           710:        evchange.ident = fd;
        !           711:        if (kevent(manager->kqueue_fd, &evchange, 1, NULL, 0, NULL) != 0)
        !           712:                result = isc__errno2result(errno);
        !           713: 
        !           714:        return (result);
        !           715: #elif defined(USE_EPOLL)
        !           716:        struct epoll_event event;
        !           717: 
        !           718:        if (msg == SELECT_POKE_READ)
        !           719:                event.events = EPOLLIN;
        !           720:        else
        !           721:                event.events = EPOLLOUT;
        !           722:        event.data.fd = fd;
        !           723:        if (epoll_ctl(manager->epoll_fd, EPOLL_CTL_DEL, fd, &event) == -1 &&
        !           724:            errno != ENOENT) {
        !           725:                char strbuf[ISC_STRERRORSIZE];
        !           726:                isc__strerror(errno, strbuf, sizeof(strbuf));
        !           727:                UNEXPECTED_ERROR(__FILE__, __LINE__,
        !           728:                                 "epoll_ctl(DEL), %d: %s", fd, strbuf);
        !           729:                result = ISC_R_UNEXPECTED;
        !           730:        }
        !           731:        return (result);
        !           732: #elif defined(USE_DEVPOLL)
        !           733:        struct pollfd pfds[2];
        !           734:        size_t writelen = sizeof(pfds[0]);
        !           735:        int lockid = FDLOCK_ID(fd);
        !           736: 
        !           737:        memset(pfds, 0, sizeof(pfds));
        !           738:        pfds[0].events = POLLREMOVE;
        !           739:        pfds[0].fd = fd;
        !           740: 
        !           741:        /*
        !           742:         * Canceling read or write polling via /dev/poll is tricky.  Since it
        !           743:         * only provides a way of canceling per FD, we may need to re-poll the
        !           744:         * socket for the other operation.
        !           745:         */
        !           746:        LOCK(&manager->fdlock[lockid]);
        !           747:        if (msg == SELECT_POKE_READ &&
        !           748:            manager->fdpollinfo[fd].want_write == 1) {
        !           749:                pfds[1].events = POLLOUT;
        !           750:                pfds[1].fd = fd;
        !           751:                writelen += sizeof(pfds[1]);
        !           752:        }
        !           753:        if (msg == SELECT_POKE_WRITE &&
        !           754:            manager->fdpollinfo[fd].want_read == 1) {
        !           755:                pfds[1].events = POLLIN;
        !           756:                pfds[1].fd = fd;
        !           757:                writelen += sizeof(pfds[1]);
        !           758:        }
        !           759: 
        !           760:        if (write(manager->devpoll_fd, pfds, writelen) == -1)
        !           761:                result = isc__errno2result(errno);
        !           762:        else {
        !           763:                if (msg == SELECT_POKE_READ)
        !           764:                        manager->fdpollinfo[fd].want_read = 0;
        !           765:                else
        !           766:                        manager->fdpollinfo[fd].want_write = 0;
        !           767:        }
        !           768:        UNLOCK(&manager->fdlock[lockid]);
        !           769: 
        !           770:        return (result);
        !           771: #elif defined(USE_SELECT)
        !           772:        LOCK(&manager->lock);
        !           773:        if (msg == SELECT_POKE_READ)
        !           774:                FD_CLR(fd, manager->read_fds);
        !           775:        else if (msg == SELECT_POKE_WRITE)
        !           776:                FD_CLR(fd, manager->write_fds);
        !           777:        UNLOCK(&manager->lock);
        !           778: 
        !           779:        return (result);
        !           780: #endif
        !           781: }
        !           782: 
        !           783: static void
        !           784: wakeup_socket(isc_socketmgr_t *manager, int fd, int msg) {
        !           785:        isc_result_t result;
        !           786:        int lockid = FDLOCK_ID(fd);
        !           787: 
        !           788:        /*
        !           789:         * This is a wakeup on a socket.  If the socket is not in the
        !           790:         * process of being closed, start watching it for either reads
        !           791:         * or writes.
        !           792:         */
        !           793: 
        !           794:        INSIST(fd >= 0 && fd < (int)manager->maxsocks);
        !           795: 
        !           796:        if (msg == SELECT_POKE_CLOSE) {
        !           797:                /* No one should be updating fdstate, so no need to lock it */
        !           798:                INSIST(manager->fdstate[fd] == CLOSE_PENDING);
        !           799:                manager->fdstate[fd] = CLOSED;
        !           800:                (void)unwatch_fd(manager, fd, SELECT_POKE_READ);
        !           801:                (void)unwatch_fd(manager, fd, SELECT_POKE_WRITE);
        !           802:                (void)close(fd);
        !           803:                return;
        !           804:        }
        !           805: 
        !           806:        LOCK(&manager->fdlock[lockid]);
        !           807:        if (manager->fdstate[fd] == CLOSE_PENDING) {
        !           808:                UNLOCK(&manager->fdlock[lockid]);
        !           809: 
        !           810:                /*
        !           811:                 * We accept (and ignore) any error from unwatch_fd() as we are
        !           812:                 * closing the socket, hoping it doesn't leave dangling state in
        !           813:                 * the kernel.
        !           814:                 * Note that unwatch_fd() must be called after releasing the
        !           815:                 * fdlock; otherwise it could cause deadlock due to a lock order
        !           816:                 * reversal.
        !           817:                 */
        !           818:                (void)unwatch_fd(manager, fd, SELECT_POKE_READ);
        !           819:                (void)unwatch_fd(manager, fd, SELECT_POKE_WRITE);
        !           820:                return;
        !           821:        }
        !           822:        if (manager->fdstate[fd] != MANAGED) {
        !           823:                UNLOCK(&manager->fdlock[lockid]);
        !           824:                return;
        !           825:        }
        !           826:        UNLOCK(&manager->fdlock[lockid]);
        !           827: 
        !           828:        /*
        !           829:         * Set requested bit.
        !           830:         */
        !           831:        result = watch_fd(manager, fd, msg);
        !           832:        if (result != ISC_R_SUCCESS) {
        !           833:                /*
        !           834:                 * XXXJT: what should we do?  Ignoring the failure of watching
        !           835:                 * a socket will make the application dysfunctional, but there
        !           836:                 * seems to be no reasonable recovery process.
        !           837:                 */
        !           838:                isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
        !           839:                              ISC_LOGMODULE_SOCKET, ISC_LOG_ERROR,
        !           840:                              "failed to start watching FD (%d): %s",
        !           841:                              fd, isc_result_totext(result));
        !           842:        }
        !           843: }
        !           844: 
        !           845: #ifdef ISC_PLATFORM_USETHREADS
        !           846: /*
        !           847:  * Poke the select loop when there is something for us to do.
        !           848:  * The write is required (by POSIX) to complete.  That is, we
        !           849:  * will not get partial writes.
        !           850:  */
        !           851: static void
        !           852: select_poke(isc_socketmgr_t *mgr, int fd, int msg) {
        !           853:        int cc;
        !           854:        int buf[2];
        !           855:        char strbuf[ISC_STRERRORSIZE];
        !           856: 
        !           857:        buf[0] = fd;
        !           858:        buf[1] = msg;
        !           859: 
        !           860:        do {
        !           861:                cc = write(mgr->pipe_fds[1], buf, sizeof(buf));
        !           862: #ifdef ENOSR
        !           863:                /*
        !           864:                 * Treat ENOSR as EAGAIN but loop slowly as it is
        !           865:                 * unlikely to clear fast.
        !           866:                 */
        !           867:                if (cc < 0 && errno == ENOSR) {
        !           868:                        sleep(1);
        !           869:                        errno = EAGAIN;
        !           870:                }
        !           871: #endif
        !           872:        } while (cc < 0 && SOFT_ERROR(errno));
        !           873: 
        !           874:        if (cc < 0) {
        !           875:                isc__strerror(errno, strbuf, sizeof(strbuf));
        !           876:                FATAL_ERROR(__FILE__, __LINE__,
        !           877:                            isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKET,
        !           878:                                           ISC_MSG_WRITEFAILED,
        !           879:                                           "write() failed "
        !           880:                                           "during watcher poke: %s"),
        !           881:                            strbuf);
        !           882:        }
        !           883: 
        !           884:        INSIST(cc == sizeof(buf));
        !           885: }
        !           886: 
        !           887: /*
        !           888:  * Read a message on the internal fd.
        !           889:  */
        !           890: static void
        !           891: select_readmsg(isc_socketmgr_t *mgr, int *fd, int *msg) {
        !           892:        int buf[2];
        !           893:        int cc;
        !           894:        char strbuf[ISC_STRERRORSIZE];
        !           895: 
        !           896:        cc = read(mgr->pipe_fds[0], buf, sizeof(buf));
        !           897:        if (cc < 0) {
        !           898:                *msg = SELECT_POKE_NOTHING;
        !           899:                *fd = -1;       /* Silence compiler. */
        !           900:                if (SOFT_ERROR(errno))
        !           901:                        return;
        !           902: 
        !           903:                isc__strerror(errno, strbuf, sizeof(strbuf));
        !           904:                FATAL_ERROR(__FILE__, __LINE__,
        !           905:                            isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKET,
        !           906:                                           ISC_MSG_READFAILED,
        !           907:                                           "read() failed "
        !           908:                                           "during watcher poke: %s"),
        !           909:                            strbuf);
        !           910: 
        !           911:                return;
        !           912:        }
        !           913:        INSIST(cc == sizeof(buf));
        !           914: 
        !           915:        *fd = buf[0];
        !           916:        *msg = buf[1];
        !           917: }
        !           918: #else /* ISC_PLATFORM_USETHREADS */
        !           919: /*
        !           920:  * Update the state of the socketmgr when something changes.
        !           921:  */
        !           922: static void
        !           923: select_poke(isc_socketmgr_t *manager, int fd, int msg) {
        !           924:        if (msg == SELECT_POKE_SHUTDOWN)
        !           925:                return;
        !           926:        else if (fd >= 0)
        !           927:                wakeup_socket(manager, fd, msg);
        !           928:        return;
        !           929: }
        !           930: #endif /* ISC_PLATFORM_USETHREADS */
        !           931: 
        !           932: /*
        !           933:  * Make a fd non-blocking.
        !           934:  */
        !           935: static isc_result_t
        !           936: make_nonblock(int fd) {
        !           937:        int ret;
        !           938:        int flags;
        !           939:        char strbuf[ISC_STRERRORSIZE];
        !           940: #ifdef USE_FIONBIO_IOCTL
        !           941:        int on = 1;
        !           942: 
        !           943:        ret = ioctl(fd, FIONBIO, (char *)&on);
        !           944: #else
        !           945:        flags = fcntl(fd, F_GETFL, 0);
        !           946:        flags |= PORT_NONBLOCK;
        !           947:        ret = fcntl(fd, F_SETFL, flags);
        !           948: #endif
        !           949: 
        !           950:        if (ret == -1) {
        !           951:                isc__strerror(errno, strbuf, sizeof(strbuf));
        !           952:                UNEXPECTED_ERROR(__FILE__, __LINE__,
        !           953: #ifdef USE_FIONBIO_IOCTL
        !           954:                                 "ioctl(%d, FIONBIO, &on): %s", fd,
        !           955: #else
        !           956:                                 "fcntl(%d, F_SETFL, %d): %s", fd, flags,
        !           957: #endif
        !           958:                                 strbuf);
        !           959: 
        !           960:                return (ISC_R_UNEXPECTED);
        !           961:        }
        !           962: 
        !           963:        return (ISC_R_SUCCESS);
        !           964: }
        !           965: 
        !           966: #ifdef USE_CMSG
        !           967: /*
        !           968:  * Not all OSes support advanced CMSG macros: CMSG_LEN and CMSG_SPACE.
        !           969:  * In order to ensure as much portability as possible, we provide wrapper
        !           970:  * functions of these macros.
        !           971:  * Note that cmsg_space() could run slow on OSes that do not have
        !           972:  * CMSG_SPACE.
        !           973:  */
        !           974: static inline ISC_SOCKADDR_LEN_T
        !           975: cmsg_len(ISC_SOCKADDR_LEN_T len) {
        !           976: #ifdef CMSG_LEN
        !           977:        return (CMSG_LEN(len));
        !           978: #else
        !           979:        ISC_SOCKADDR_LEN_T hdrlen;
        !           980: 
        !           981:        /*
        !           982:         * Cast NULL so that any pointer arithmetic performed by CMSG_DATA
        !           983:         * is correct.
        !           984:         */
        !           985:        hdrlen = (ISC_SOCKADDR_LEN_T)CMSG_DATA(((struct cmsghdr *)NULL));
        !           986:        return (hdrlen + len);
        !           987: #endif
        !           988: }
        !           989: 
        !           990: static inline ISC_SOCKADDR_LEN_T
        !           991: cmsg_space(ISC_SOCKADDR_LEN_T len) {
        !           992: #ifdef CMSG_SPACE
        !           993:        return (CMSG_SPACE(len));
        !           994: #else
        !           995:        struct msghdr msg;
        !           996:        struct cmsghdr *cmsgp;
        !           997:        /*
        !           998:         * XXX: The buffer length is an ad-hoc value, but should be enough
        !           999:         * in a practical sense.
        !          1000:         */
        !          1001:        char dummybuf[sizeof(struct cmsghdr) + 1024];
        !          1002: 
        !          1003:        memset(&msg, 0, sizeof(msg));
        !          1004:        msg.msg_control = dummybuf;
        !          1005:        msg.msg_controllen = sizeof(dummybuf);
        !          1006: 
        !          1007:        cmsgp = (struct cmsghdr *)dummybuf;
        !          1008:        cmsgp->cmsg_len = cmsg_len(len);
        !          1009: 
        !          1010:        cmsgp = CMSG_NXTHDR(&msg, cmsgp);
        !          1011:        if (cmsgp != NULL)
        !          1012:                return ((char *)cmsgp - (char *)msg.msg_control);
        !          1013:        else
        !          1014:                return (0);
        !          1015: #endif
        !          1016: }
        !          1017: #endif /* USE_CMSG */
        !          1018: 
        !          1019: /*
        !          1020:  * Process control messages received on a socket.
        !          1021:  */
        !          1022: static void
        !          1023: process_cmsg(isc_socket_t *sock, struct msghdr *msg, isc_socketevent_t *dev) {
        !          1024: #ifdef USE_CMSG
        !          1025:        struct cmsghdr *cmsgp;
        !          1026: #ifdef ISC_PLATFORM_HAVEIN6PKTINFO
        !          1027:        struct in6_pktinfo *pktinfop;
        !          1028: #endif
        !          1029: #ifdef SO_TIMESTAMP
        !          1030:        struct timeval *timevalp;
        !          1031: #endif
        !          1032: #endif
        !          1033: 
        !          1034:        /*
        !          1035:         * sock is used only when ISC_NET_BSD44MSGHDR and USE_CMSG are defined.
        !          1036:         * msg and dev are used only when ISC_NET_BSD44MSGHDR is defined.
        !          1037:         * They are all here, outside of the CPP tests, because it is
        !          1038:         * more consistent with the usual ISC coding style.
        !          1039:         */
        !          1040:        UNUSED(sock);
        !          1041:        UNUSED(msg);
        !          1042:        UNUSED(dev);
        !          1043: 
        !          1044: #ifdef ISC_NET_BSD44MSGHDR
        !          1045: 
        !          1046: #ifdef MSG_TRUNC
        !          1047:        if ((msg->msg_flags & MSG_TRUNC) == MSG_TRUNC)
        !          1048:                dev->attributes |= ISC_SOCKEVENTATTR_TRUNC;
        !          1049: #endif
        !          1050: 
        !          1051: #ifdef MSG_CTRUNC
        !          1052:        if ((msg->msg_flags & MSG_CTRUNC) == MSG_CTRUNC)
        !          1053:                dev->attributes |= ISC_SOCKEVENTATTR_CTRUNC;
        !          1054: #endif
        !          1055: 
        !          1056: #ifndef USE_CMSG
        !          1057:        return;
        !          1058: #else
        !          1059:        if (msg->msg_controllen == 0U || msg->msg_control == NULL)
        !          1060:                return;
        !          1061: 
        !          1062: #ifdef SO_TIMESTAMP
        !          1063:        timevalp = NULL;
        !          1064: #endif
        !          1065: #ifdef ISC_PLATFORM_HAVEIN6PKTINFO
        !          1066:        pktinfop = NULL;
        !          1067: #endif
        !          1068: 
        !          1069:        cmsgp = CMSG_FIRSTHDR(msg);
        !          1070:        while (cmsgp != NULL) {
        !          1071:                socket_log(sock, NULL, TRACE,
        !          1072:                           isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_PROCESSCMSG,
        !          1073:                           "processing cmsg %p", cmsgp);
        !          1074: 
        !          1075: #ifdef ISC_PLATFORM_HAVEIN6PKTINFO
        !          1076:                if (cmsgp->cmsg_level == IPPROTO_IPV6
        !          1077:                    && cmsgp->cmsg_type == IPV6_PKTINFO) {
        !          1078: 
        !          1079:                        pktinfop = (struct in6_pktinfo *)CMSG_DATA(cmsgp);
        !          1080:                        memcpy(&dev->pktinfo, pktinfop,
        !          1081:                               sizeof(struct in6_pktinfo));
        !          1082:                        dev->attributes |= ISC_SOCKEVENTATTR_PKTINFO;
        !          1083:                        socket_log(sock, NULL, TRACE,
        !          1084:                                   isc_msgcat, ISC_MSGSET_SOCKET,
        !          1085:                                   ISC_MSG_IFRECEIVED,
        !          1086:                                   "interface received on ifindex %u",
        !          1087:                                   dev->pktinfo.ipi6_ifindex);
        !          1088:                        if (IN6_IS_ADDR_MULTICAST(&pktinfop->ipi6_addr))
        !          1089:                                dev->attributes |= ISC_SOCKEVENTATTR_MULTICAST;
        !          1090:                        goto next;
        !          1091:                }
        !          1092: #endif
        !          1093: 
        !          1094: #ifdef SO_TIMESTAMP
        !          1095:                if (cmsgp->cmsg_level == SOL_SOCKET
        !          1096:                    && cmsgp->cmsg_type == SCM_TIMESTAMP) {
        !          1097:                        timevalp = (struct timeval *)CMSG_DATA(cmsgp);
        !          1098:                        dev->timestamp.seconds = timevalp->tv_sec;
        !          1099:                        dev->timestamp.nanoseconds = timevalp->tv_usec * 1000;
        !          1100:                        dev->attributes |= ISC_SOCKEVENTATTR_TIMESTAMP;
        !          1101:                        goto next;
        !          1102:                }
        !          1103: #endif
        !          1104: 
        !          1105:        next:
        !          1106:                cmsgp = CMSG_NXTHDR(msg, cmsgp);
        !          1107:        }
        !          1108: #endif /* USE_CMSG */
        !          1109: 
        !          1110: #endif /* ISC_NET_BSD44MSGHDR */
        !          1111: }
        !          1112: 
        !          1113: /*
        !          1114:  * Construct an iov array and attach it to the msghdr passed in.  This is
        !          1115:  * the SEND constructor, which will use the used region of the buffer
        !          1116:  * (if using a buffer list) or will use the internal region (if a single
        !          1117:  * buffer I/O is requested).
        !          1118:  *
        !          1119:  * Nothing can be NULL, and the done event must list at least one buffer
        !          1120:  * on the buffer linked list for this function to be meaningful.
        !          1121:  *
        !          1122:  * If write_countp != NULL, *write_countp will hold the number of bytes
        !          1123:  * this transaction can send.
        !          1124:  */
        !          1125: static void
        !          1126: build_msghdr_send(isc_socket_t *sock, isc_socketevent_t *dev,
        !          1127:                  struct msghdr *msg, struct iovec *iov, size_t *write_countp)
        !          1128: {
        !          1129:        unsigned int iovcount;
        !          1130:        isc_buffer_t *buffer;
        !          1131:        isc_region_t used;
        !          1132:        size_t write_count;
        !          1133:        size_t skip_count;
        !          1134: 
        !          1135:        memset(msg, 0, sizeof(*msg));
        !          1136: 
        !          1137:        if (!sock->connected) {
        !          1138:                msg->msg_name = (void *)&dev->address.type.sa;
        !          1139:                msg->msg_namelen = dev->address.length;
        !          1140:        } else {
        !          1141:                msg->msg_name = NULL;
        !          1142:                msg->msg_namelen = 0;
        !          1143:        }
        !          1144: 
        !          1145:        buffer = ISC_LIST_HEAD(dev->bufferlist);
        !          1146:        write_count = 0;
        !          1147:        iovcount = 0;
        !          1148: 
        !          1149:        /*
        !          1150:         * Single buffer I/O?  Skip what we've done so far in this region.
        !          1151:         */
        !          1152:        if (buffer == NULL) {
        !          1153:                write_count = dev->region.length - dev->n;
        !          1154:                iov[0].iov_base = (void *)(dev->region.base + dev->n);
        !          1155:                iov[0].iov_len = write_count;
        !          1156:                iovcount = 1;
        !          1157: 
        !          1158:                goto config;
        !          1159:        }
        !          1160: 
        !          1161:        /*
        !          1162:         * Multibuffer I/O.
        !          1163:         * Skip the data in the buffer list that we have already written.
        !          1164:         */
        !          1165:        skip_count = dev->n;
        !          1166:        while (buffer != NULL) {
        !          1167:                REQUIRE(ISC_BUFFER_VALID(buffer));
        !          1168:                if (skip_count < isc_buffer_usedlength(buffer))
        !          1169:                        break;
        !          1170:                skip_count -= isc_buffer_usedlength(buffer);
        !          1171:                buffer = ISC_LIST_NEXT(buffer, link);
        !          1172:        }
        !          1173: 
        !          1174:        while (buffer != NULL) {
        !          1175:                INSIST(iovcount < MAXSCATTERGATHER_SEND);
        !          1176: 
        !          1177:                isc_buffer_usedregion(buffer, &used);
        !          1178: 
        !          1179:                if (used.length > 0) {
        !          1180:                        iov[iovcount].iov_base = (void *)(used.base
        !          1181:                                                          + skip_count);
        !          1182:                        iov[iovcount].iov_len = used.length - skip_count;
        !          1183:                        write_count += (used.length - skip_count);
        !          1184:                        skip_count = 0;
        !          1185:                        iovcount++;
        !          1186:                }
        !          1187:                buffer = ISC_LIST_NEXT(buffer, link);
        !          1188:        }
        !          1189: 
        !          1190:        INSIST(skip_count == 0U);
        !          1191: 
        !          1192:  config:
        !          1193:        msg->msg_iov = iov;
        !          1194:        msg->msg_iovlen = iovcount;
        !          1195: 
        !          1196: #ifdef ISC_NET_BSD44MSGHDR
        !          1197:        msg->msg_control = NULL;
        !          1198:        msg->msg_controllen = 0;
        !          1199:        msg->msg_flags = 0;
        !          1200: #if defined(USE_CMSG) && defined(ISC_PLATFORM_HAVEIN6PKTINFO)
        !          1201:        if ((sock->type == isc_sockettype_udp)
        !          1202:            && ((dev->attributes & ISC_SOCKEVENTATTR_PKTINFO) != 0)) {
        !          1203:                struct cmsghdr *cmsgp;
        !          1204:                struct in6_pktinfo *pktinfop;
        !          1205: 
        !          1206:                socket_log(sock, NULL, TRACE,
        !          1207:                           isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_SENDTODATA,
        !          1208:                           "sendto pktinfo data, ifindex %u",
        !          1209:                           dev->pktinfo.ipi6_ifindex);
        !          1210: 
        !          1211:                msg->msg_controllen = cmsg_space(sizeof(struct in6_pktinfo));
        !          1212:                INSIST(msg->msg_controllen <= sock->sendcmsgbuflen);
        !          1213:                msg->msg_control = (void *)sock->sendcmsgbuf;
        !          1214: 
        !          1215:                cmsgp = (struct cmsghdr *)sock->sendcmsgbuf;
        !          1216:                cmsgp->cmsg_level = IPPROTO_IPV6;
        !          1217:                cmsgp->cmsg_type = IPV6_PKTINFO;
        !          1218:                cmsgp->cmsg_len = cmsg_len(sizeof(struct in6_pktinfo));
        !          1219:                pktinfop = (struct in6_pktinfo *)CMSG_DATA(cmsgp);
        !          1220:                memcpy(pktinfop, &dev->pktinfo, sizeof(struct in6_pktinfo));
        !          1221:        }
        !          1222: #endif /* USE_CMSG && ISC_PLATFORM_HAVEIPV6 */
        !          1223: #else /* ISC_NET_BSD44MSGHDR */
        !          1224:        msg->msg_accrights = NULL;
        !          1225:        msg->msg_accrightslen = 0;
        !          1226: #endif /* ISC_NET_BSD44MSGHDR */
        !          1227: 
        !          1228:        if (write_countp != NULL)
        !          1229:                *write_countp = write_count;
        !          1230: }
        !          1231: 
        !          1232: /*
        !          1233:  * Construct an iov array and attach it to the msghdr passed in.  This is
        !          1234:  * the RECV constructor, which will use the available region of the buffer
        !          1235:  * (if using a buffer list) or will use the internal region (if a single
        !          1236:  * buffer I/O is requested).
        !          1237:  *
        !          1238:  * Nothing can be NULL, and the done event must list at least one buffer
        !          1239:  * on the buffer linked list for this function to be meaningful.
        !          1240:  *
        !          1241:  * If read_countp != NULL, *read_countp will hold the number of bytes
        !          1242:  * this transaction can receive.
        !          1243:  */
        !          1244: static void
        !          1245: build_msghdr_recv(isc_socket_t *sock, isc_socketevent_t *dev,
        !          1246:                  struct msghdr *msg, struct iovec *iov, size_t *read_countp)
        !          1247: {
        !          1248:        unsigned int iovcount;
        !          1249:        isc_buffer_t *buffer;
        !          1250:        isc_region_t available;
        !          1251:        size_t read_count;
        !          1252: 
        !          1253:        memset(msg, 0, sizeof(struct msghdr));
        !          1254: 
        !          1255:        if (sock->type == isc_sockettype_udp) {
        !          1256:                memset(&dev->address, 0, sizeof(dev->address));
        !          1257: #ifdef BROKEN_RECVMSG
        !          1258:                if (sock->pf == AF_INET) {
        !          1259:                        msg->msg_name = (void *)&dev->address.type.sin;
        !          1260:                        msg->msg_namelen = sizeof(dev->address.type.sin6);
        !          1261:                } else if (sock->pf == AF_INET6) {
        !          1262:                        msg->msg_name = (void *)&dev->address.type.sin6;
        !          1263:                        msg->msg_namelen = sizeof(dev->address.type.sin6);
        !          1264: #ifdef ISC_PLATFORM_HAVESYSUNH
        !          1265:                } else if (sock->pf == AF_UNIX) {
        !          1266:                        msg->msg_name = (void *)&dev->address.type.sunix;
        !          1267:                        msg->msg_namelen = sizeof(dev->address.type.sunix);
        !          1268: #endif
        !          1269:                } else {
        !          1270:                        msg->msg_name = (void *)&dev->address.type.sa;
        !          1271:                        msg->msg_namelen = sizeof(dev->address.type);
        !          1272:                }
        !          1273: #else
        !          1274:                msg->msg_name = (void *)&dev->address.type.sa;
        !          1275:                msg->msg_namelen = sizeof(dev->address.type);
        !          1276: #endif
        !          1277: #ifdef ISC_NET_RECVOVERFLOW
        !          1278:                /* If needed, steal one iovec for overflow detection. */
        !          1279:                maxiov--;
        !          1280: #endif
        !          1281:        } else { /* TCP */
        !          1282:                msg->msg_name = NULL;
        !          1283:                msg->msg_namelen = 0;
        !          1284:                dev->address = sock->peer_address;
        !          1285:        }
        !          1286: 
        !          1287:        buffer = ISC_LIST_HEAD(dev->bufferlist);
        !          1288:        read_count = 0;
        !          1289: 
        !          1290:        /*
        !          1291:         * Single buffer I/O?  Skip what we've done so far in this region.
        !          1292:         */
        !          1293:        if (buffer == NULL) {
        !          1294:                read_count = dev->region.length - dev->n;
        !          1295:                iov[0].iov_base = (void *)(dev->region.base + dev->n);
        !          1296:                iov[0].iov_len = read_count;
        !          1297:                iovcount = 1;
        !          1298: 
        !          1299:                goto config;
        !          1300:        }
        !          1301: 
        !          1302:        /*
        !          1303:         * Multibuffer I/O.
        !          1304:         * Skip empty buffers.
        !          1305:         */
        !          1306:        while (buffer != NULL) {
        !          1307:                REQUIRE(ISC_BUFFER_VALID(buffer));
        !          1308:                if (isc_buffer_availablelength(buffer) != 0)
        !          1309:                        break;
        !          1310:                buffer = ISC_LIST_NEXT(buffer, link);
        !          1311:        }
        !          1312: 
        !          1313:        iovcount = 0;
        !          1314:        while (buffer != NULL) {
        !          1315:                INSIST(iovcount < MAXSCATTERGATHER_RECV);
        !          1316: 
        !          1317:                isc_buffer_availableregion(buffer, &available);
        !          1318: 
        !          1319:                if (available.length > 0) {
        !          1320:                        iov[iovcount].iov_base = (void *)(available.base);
        !          1321:                        iov[iovcount].iov_len = available.length;
        !          1322:                        read_count += available.length;
        !          1323:                        iovcount++;
        !          1324:                }
        !          1325:                buffer = ISC_LIST_NEXT(buffer, link);
        !          1326:        }
        !          1327: 
        !          1328:  config:
        !          1329: 
        !          1330:        /*
        !          1331:         * If needed, set up to receive that one extra byte.  Note that
        !          1332:         * we know there is at least one iov left, since we stole it
        !          1333:         * at the top of this function.
        !          1334:         */
        !          1335: #ifdef ISC_NET_RECVOVERFLOW
        !          1336:        if (sock->type == isc_sockettype_udp) {
        !          1337:                iov[iovcount].iov_base = (void *)(&sock->overflow);
        !          1338:                iov[iovcount].iov_len = 1;
        !          1339:                iovcount++;
        !          1340:        }
        !          1341: #endif
        !          1342: 
        !          1343:        msg->msg_iov = iov;
        !          1344:        msg->msg_iovlen = iovcount;
        !          1345: 
        !          1346: #ifdef ISC_NET_BSD44MSGHDR
        !          1347:        msg->msg_control = NULL;
        !          1348:        msg->msg_controllen = 0;
        !          1349:        msg->msg_flags = 0;
        !          1350: #if defined(USE_CMSG)
        !          1351:        if (sock->type == isc_sockettype_udp) {
        !          1352:                msg->msg_control = sock->recvcmsgbuf;
        !          1353:                msg->msg_controllen = sock->recvcmsgbuflen;
        !          1354:        }
        !          1355: #endif /* USE_CMSG */
        !          1356: #else /* ISC_NET_BSD44MSGHDR */
        !          1357:        msg->msg_accrights = NULL;
        !          1358:        msg->msg_accrightslen = 0;
        !          1359: #endif /* ISC_NET_BSD44MSGHDR */
        !          1360: 
        !          1361:        if (read_countp != NULL)
        !          1362:                *read_countp = read_count;
        !          1363: }
        !          1364: 
        !          1365: static void
        !          1366: set_dev_address(isc_sockaddr_t *address, isc_socket_t *sock,
        !          1367:                isc_socketevent_t *dev)
        !          1368: {
        !          1369:        if (sock->type == isc_sockettype_udp) {
        !          1370:                if (address != NULL)
        !          1371:                        dev->address = *address;
        !          1372:                else
        !          1373:                        dev->address = sock->peer_address;
        !          1374:        } else if (sock->type == isc_sockettype_tcp) {
        !          1375:                INSIST(address == NULL);
        !          1376:                dev->address = sock->peer_address;
        !          1377:        }
        !          1378: }
        !          1379: 
        !          1380: static void
        !          1381: destroy_socketevent(isc_event_t *event) {
        !          1382:        isc_socketevent_t *ev = (isc_socketevent_t *)event;
        !          1383: 
        !          1384:        INSIST(ISC_LIST_EMPTY(ev->bufferlist));
        !          1385: 
        !          1386:        (ev->destroy)(event);
        !          1387: }
        !          1388: 
        !          1389: static isc_socketevent_t *
        !          1390: allocate_socketevent(isc_socket_t *sock, isc_eventtype_t eventtype,
        !          1391:                     isc_taskaction_t action, const void *arg)
        !          1392: {
        !          1393:        isc_socketevent_t *ev;
        !          1394: 
        !          1395:        ev = (isc_socketevent_t *)isc_event_allocate(sock->manager->mctx,
        !          1396:                                                     sock, eventtype,
        !          1397:                                                     action, arg,
        !          1398:                                                     sizeof(*ev));
        !          1399: 
        !          1400:        if (ev == NULL)
        !          1401:                return (NULL);
        !          1402: 
        !          1403:        ev->result = ISC_R_UNEXPECTED;
        !          1404:        ISC_LINK_INIT(ev, ev_link);
        !          1405:        ISC_LIST_INIT(ev->bufferlist);
        !          1406:        ev->region.base = NULL;
        !          1407:        ev->n = 0;
        !          1408:        ev->offset = 0;
        !          1409:        ev->attributes = 0;
        !          1410:        ev->destroy = ev->ev_destroy;
        !          1411:        ev->ev_destroy = destroy_socketevent;
        !          1412: 
        !          1413:        return (ev);
        !          1414: }
        !          1415: 
        !          1416: #if defined(ISC_SOCKET_DEBUG)
        !          1417: static void
        !          1418: dump_msg(struct msghdr *msg) {
        !          1419:        unsigned int i;
        !          1420: 
        !          1421:        printf("MSGHDR %p\n", msg);
        !          1422:        printf("\tname %p, namelen %ld\n", msg->msg_name,
        !          1423:               (long) msg->msg_namelen);
        !          1424:        printf("\tiov %p, iovlen %ld\n", msg->msg_iov,
        !          1425:               (long) msg->msg_iovlen);
        !          1426:        for (i = 0; i < (unsigned int)msg->msg_iovlen; i++)
        !          1427:                printf("\t\t%d\tbase %p, len %ld\n", i,
        !          1428:                       msg->msg_iov[i].iov_base,
        !          1429:                       (long) msg->msg_iov[i].iov_len);
        !          1430: #ifdef ISC_NET_BSD44MSGHDR
        !          1431:        printf("\tcontrol %p, controllen %ld\n", msg->msg_control,
        !          1432:               (long) msg->msg_controllen);
        !          1433: #endif
        !          1434: }
        !          1435: #endif
        !          1436: 
        !          1437: #define DOIO_SUCCESS           0       /* i/o ok, event sent */
        !          1438: #define DOIO_SOFT              1       /* i/o ok, soft error, no event sent */
        !          1439: #define DOIO_HARD              2       /* i/o error, event sent */
        !          1440: #define DOIO_EOF               3       /* EOF, no event sent */
        !          1441: 
        !          1442: static int
        !          1443: doio_recv(isc_socket_t *sock, isc_socketevent_t *dev) {
        !          1444:        int cc;
        !          1445:        struct iovec iov[MAXSCATTERGATHER_RECV];
        !          1446:        size_t read_count;
        !          1447:        size_t actual_count;
        !          1448:        struct msghdr msghdr;
        !          1449:        isc_buffer_t *buffer;
        !          1450:        int recv_errno;
        !          1451:        char strbuf[ISC_STRERRORSIZE];
        !          1452: 
        !          1453:        build_msghdr_recv(sock, dev, &msghdr, iov, &read_count);
        !          1454: 
        !          1455: #if defined(ISC_SOCKET_DEBUG)
        !          1456:        dump_msg(&msghdr);
        !          1457: #endif
        !          1458: 
        !          1459:        cc = recvmsg(sock->fd, &msghdr, 0);
        !          1460:        recv_errno = errno;
        !          1461: 
        !          1462: #if defined(ISC_SOCKET_DEBUG)
        !          1463:        dump_msg(&msghdr);
        !          1464: #endif
        !          1465: 
        !          1466:        if (cc < 0) {
        !          1467:                if (SOFT_ERROR(recv_errno))
        !          1468:                        return (DOIO_SOFT);
        !          1469: 
        !          1470:                if (isc_log_wouldlog(isc_lctx, IOEVENT_LEVEL)) {
        !          1471:                        isc__strerror(recv_errno, strbuf, sizeof(strbuf));
        !          1472:                        socket_log(sock, NULL, IOEVENT,
        !          1473:                                   isc_msgcat, ISC_MSGSET_SOCKET,
        !          1474:                                   ISC_MSG_DOIORECV,
        !          1475:                                  "doio_recv: recvmsg(%d) %d bytes, err %d/%s",
        !          1476:                                   sock->fd, cc, recv_errno, strbuf);
        !          1477:                }
        !          1478: 
        !          1479: #define SOFT_OR_HARD(_system, _isc) \
        !          1480:        if (recv_errno == _system) { \
        !          1481:                if (sock->connected) { \
        !          1482:                        dev->result = _isc; \
        !          1483:                        inc_stats(sock->manager->stats, \
        !          1484:                                  sock->statsindex[STATID_RECVFAIL]); \
        !          1485:                        return (DOIO_HARD); \
        !          1486:                } \
        !          1487:                return (DOIO_SOFT); \
        !          1488:        }
        !          1489: #define ALWAYS_HARD(_system, _isc) \
        !          1490:        if (recv_errno == _system) { \
        !          1491:                dev->result = _isc; \
        !          1492:                inc_stats(sock->manager->stats, \
        !          1493:                          sock->statsindex[STATID_RECVFAIL]); \
        !          1494:                return (DOIO_HARD); \
        !          1495:        }
        !          1496: 
        !          1497:                SOFT_OR_HARD(ECONNREFUSED, ISC_R_CONNREFUSED);
        !          1498:                SOFT_OR_HARD(ENETUNREACH, ISC_R_NETUNREACH);
        !          1499:                SOFT_OR_HARD(EHOSTUNREACH, ISC_R_HOSTUNREACH);
        !          1500:                SOFT_OR_HARD(EHOSTDOWN, ISC_R_HOSTDOWN);
        !          1501:                /* HPUX 11.11 can return EADDRNOTAVAIL. */
        !          1502:                SOFT_OR_HARD(EADDRNOTAVAIL, ISC_R_ADDRNOTAVAIL);
        !          1503:                ALWAYS_HARD(ENOBUFS, ISC_R_NORESOURCES);
        !          1504:                /*
        !          1505:                 * HPUX returns EPROTO and EINVAL on receiving some ICMP/ICMPv6
        !          1506:                 * errors.
        !          1507:                 */
        !          1508: #ifdef EPROTO
        !          1509:                SOFT_OR_HARD(EPROTO, ISC_R_HOSTUNREACH);
        !          1510: #endif
        !          1511:                SOFT_OR_HARD(EINVAL, ISC_R_HOSTUNREACH);
        !          1512: 
        !          1513: #undef SOFT_OR_HARD
        !          1514: #undef ALWAYS_HARD
        !          1515: 
        !          1516:                dev->result = isc__errno2result(recv_errno);
        !          1517:                inc_stats(sock->manager->stats,
        !          1518:                          sock->statsindex[STATID_RECVFAIL]);
        !          1519:                return (DOIO_HARD);
        !          1520:        }
        !          1521: 
        !          1522:        /*
        !          1523:         * On TCP, zero length reads indicate EOF, while on
        !          1524:         * UDP, zero length reads are perfectly valid, although
        !          1525:         * strange.
        !          1526:         */
        !          1527:        if ((sock->type == isc_sockettype_tcp) && (cc == 0))
        !          1528:                return (DOIO_EOF);
        !          1529: 
        !          1530:        if (sock->type == isc_sockettype_udp) {
        !          1531:                dev->address.length = msghdr.msg_namelen;
        !          1532:                if (isc_sockaddr_getport(&dev->address) == 0) {
        !          1533:                        if (isc_log_wouldlog(isc_lctx, IOEVENT_LEVEL)) {
        !          1534:                                socket_log(sock, &dev->address, IOEVENT,
        !          1535:                                           isc_msgcat, ISC_MSGSET_SOCKET,
        !          1536:                                           ISC_MSG_ZEROPORT,
        !          1537:                                           "dropping source port zero packet");
        !          1538:                        }
        !          1539:                        return (DOIO_SOFT);
        !          1540:                }
        !          1541:        }
        !          1542: 
        !          1543:        socket_log(sock, &dev->address, IOEVENT,
        !          1544:                   isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_PKTRECV,
        !          1545:                   "packet received correctly");
        !          1546: 
        !          1547:        /*
        !          1548:         * Overflow bit detection.  If we received MORE bytes than we should,
        !          1549:         * this indicates an overflow situation.  Set the flag in the
        !          1550:         * dev entry and adjust how much we read by one.
        !          1551:         */
        !          1552: #ifdef ISC_NET_RECVOVERFLOW
        !          1553:        if ((sock->type == isc_sockettype_udp) && ((size_t)cc > read_count)) {
        !          1554:                dev->attributes |= ISC_SOCKEVENTATTR_TRUNC;
        !          1555:                cc--;
        !          1556:        }
        !          1557: #endif
        !          1558: 
        !          1559:        /*
        !          1560:         * If there are control messages attached, run through them and pull
        !          1561:         * out the interesting bits.
        !          1562:         */
        !          1563:        if (sock->type == isc_sockettype_udp)
        !          1564:                process_cmsg(sock, &msghdr, dev);
        !          1565: 
        !          1566:        /*
        !          1567:         * update the buffers (if any) and the i/o count
        !          1568:         */
        !          1569:        dev->n += cc;
        !          1570:        actual_count = cc;
        !          1571:        buffer = ISC_LIST_HEAD(dev->bufferlist);
        !          1572:        while (buffer != NULL && actual_count > 0U) {
        !          1573:                REQUIRE(ISC_BUFFER_VALID(buffer));
        !          1574:                if (isc_buffer_availablelength(buffer) <= actual_count) {
        !          1575:                        actual_count -= isc_buffer_availablelength(buffer);
        !          1576:                        isc_buffer_add(buffer,
        !          1577:                                       isc_buffer_availablelength(buffer));
        !          1578:                } else {
        !          1579:                        isc_buffer_add(buffer, actual_count);
        !          1580:                        actual_count = 0;
        !          1581:                        break;
        !          1582:                }
        !          1583:                buffer = ISC_LIST_NEXT(buffer, link);
        !          1584:                if (buffer == NULL) {
        !          1585:                        INSIST(actual_count == 0U);
        !          1586:                }
        !          1587:        }
        !          1588: 
        !          1589:        /*
        !          1590:         * If we read less than we expected, update counters,
        !          1591:         * and let the upper layer poke the descriptor.
        !          1592:         */
        !          1593:        if (((size_t)cc != read_count) && (dev->n < dev->minimum))
        !          1594:                return (DOIO_SOFT);
        !          1595: 
        !          1596:        /*
        !          1597:         * Full reads are posted, or partials if partials are ok.
        !          1598:         */
        !          1599:        dev->result = ISC_R_SUCCESS;
        !          1600:        return (DOIO_SUCCESS);
        !          1601: }
        !          1602: 
        !          1603: /*
        !          1604:  * Returns:
        !          1605:  *     DOIO_SUCCESS    The operation succeeded.  dev->result contains
        !          1606:  *                     ISC_R_SUCCESS.
        !          1607:  *
        !          1608:  *     DOIO_HARD       A hard or unexpected I/O error was encountered.
        !          1609:  *                     dev->result contains the appropriate error.
        !          1610:  *
        !          1611:  *     DOIO_SOFT       A soft I/O error was encountered.  No senddone
        !          1612:  *                     event was sent.  The operation should be retried.
        !          1613:  *
        !          1614:  *     No other return values are possible.
        !          1615:  */
        !          1616: static int
        !          1617: doio_send(isc_socket_t *sock, isc_socketevent_t *dev) {
        !          1618:        int cc;
        !          1619:        struct iovec iov[MAXSCATTERGATHER_SEND];
        !          1620:        size_t write_count;
        !          1621:        struct msghdr msghdr;
        !          1622:        char addrbuf[ISC_SOCKADDR_FORMATSIZE];
        !          1623:        int attempts = 0;
        !          1624:        int send_errno;
        !          1625:        char strbuf[ISC_STRERRORSIZE];
        !          1626: 
        !          1627:        build_msghdr_send(sock, dev, &msghdr, iov, &write_count);
        !          1628: 
        !          1629:  resend:
        !          1630:        cc = sendmsg(sock->fd, &msghdr, 0);
        !          1631:        send_errno = errno;
        !          1632: 
        !          1633:        /*
        !          1634:         * Check for error or block condition.
        !          1635:         */
        !          1636:        if (cc < 0) {
        !          1637:                if (send_errno == EINTR && ++attempts < NRETRIES)
        !          1638:                        goto resend;
        !          1639: 
        !          1640:                if (SOFT_ERROR(send_errno))
        !          1641:                        return (DOIO_SOFT);
        !          1642: 
        !          1643: #define SOFT_OR_HARD(_system, _isc) \
        !          1644:        if (send_errno == _system) { \
        !          1645:                if (sock->connected) { \
        !          1646:                        dev->result = _isc; \
        !          1647:                        inc_stats(sock->manager->stats, \
        !          1648:                                  sock->statsindex[STATID_SENDFAIL]); \
        !          1649:                        return (DOIO_HARD); \
        !          1650:                } \
        !          1651:                return (DOIO_SOFT); \
        !          1652:        }
        !          1653: #define ALWAYS_HARD(_system, _isc) \
        !          1654:        if (send_errno == _system) { \
        !          1655:                dev->result = _isc; \
        !          1656:                inc_stats(sock->manager->stats, \
        !          1657:                          sock->statsindex[STATID_SENDFAIL]); \
        !          1658:                return (DOIO_HARD); \
        !          1659:        }
        !          1660: 
        !          1661:                SOFT_OR_HARD(ECONNREFUSED, ISC_R_CONNREFUSED);
        !          1662:                ALWAYS_HARD(EACCES, ISC_R_NOPERM);
        !          1663:                ALWAYS_HARD(EAFNOSUPPORT, ISC_R_ADDRNOTAVAIL);
        !          1664:                ALWAYS_HARD(EADDRNOTAVAIL, ISC_R_ADDRNOTAVAIL);
        !          1665:                ALWAYS_HARD(EHOSTUNREACH, ISC_R_HOSTUNREACH);
        !          1666: #ifdef EHOSTDOWN
        !          1667:                ALWAYS_HARD(EHOSTDOWN, ISC_R_HOSTUNREACH);
        !          1668: #endif
        !          1669:                ALWAYS_HARD(ENETUNREACH, ISC_R_NETUNREACH);
        !          1670:                ALWAYS_HARD(ENOBUFS, ISC_R_NORESOURCES);
        !          1671:                ALWAYS_HARD(EPERM, ISC_R_HOSTUNREACH);
        !          1672:                ALWAYS_HARD(EPIPE, ISC_R_NOTCONNECTED);
        !          1673:                ALWAYS_HARD(ECONNRESET, ISC_R_CONNECTIONRESET);
        !          1674: 
        !          1675: #undef SOFT_OR_HARD
        !          1676: #undef ALWAYS_HARD
        !          1677: 
        !          1678:                /*
        !          1679:                 * The other error types depend on whether or not the
        !          1680:                 * socket is UDP or TCP.  If it is UDP, some errors
        !          1681:                 * that we expect to be fatal under TCP are merely
        !          1682:                 * annoying, and are really soft errors.
        !          1683:                 *
        !          1684:                 * However, these soft errors are still returned as
        !          1685:                 * a status.
        !          1686:                 */
        !          1687:                isc_sockaddr_format(&dev->address, addrbuf, sizeof(addrbuf));
        !          1688:                isc__strerror(send_errno, strbuf, sizeof(strbuf));
        !          1689:                UNEXPECTED_ERROR(__FILE__, __LINE__, "internal_send: %s: %s",
        !          1690:                                 addrbuf, strbuf);
        !          1691:                dev->result = isc__errno2result(send_errno);
        !          1692:                inc_stats(sock->manager->stats,
        !          1693:                          sock->statsindex[STATID_SENDFAIL]);
        !          1694:                return (DOIO_HARD);
        !          1695:        }
        !          1696: 
        !          1697:        if (cc == 0) {
        !          1698:                inc_stats(sock->manager->stats,
        !          1699:                          sock->statsindex[STATID_SENDFAIL]);
        !          1700:                UNEXPECTED_ERROR(__FILE__, __LINE__,
        !          1701:                                 "doio_send: send() %s 0",
        !          1702:                                 isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
        !          1703:                                                ISC_MSG_RETURNED, "returned"));
        !          1704:        }
        !          1705: 
        !          1706:        /*
        !          1707:         * If we write less than we expected, update counters, poke.
        !          1708:         */
        !          1709:        dev->n += cc;
        !          1710:        if ((size_t)cc != write_count)
        !          1711:                return (DOIO_SOFT);
        !          1712: 
        !          1713:        /*
        !          1714:         * Exactly what we wanted to write.  We're done with this
        !          1715:         * entry.  Post its completion event.
        !          1716:         */
        !          1717:        dev->result = ISC_R_SUCCESS;
        !          1718:        return (DOIO_SUCCESS);
        !          1719: }
        !          1720: 
        !          1721: /*
        !          1722:  * Kill.
        !          1723:  *
        !          1724:  * Caller must ensure that the socket is not locked and no external
        !          1725:  * references exist.
        !          1726:  */
        !          1727: static void
        !          1728: closesocket(isc_socketmgr_t *manager, isc_socket_t *sock, int fd) {
        !          1729:        isc_sockettype_t type = sock->type;
        !          1730:        int lockid = FDLOCK_ID(fd);
        !          1731: 
        !          1732:        /*
        !          1733:         * No one has this socket open, so the watcher doesn't have to be
        !          1734:         * poked, and the socket doesn't have to be locked.
        !          1735:         */
        !          1736:        LOCK(&manager->fdlock[lockid]);
        !          1737:        manager->fds[fd] = NULL;
        !          1738:        if (type == isc_sockettype_fdwatch)
        !          1739:                manager->fdstate[fd] = CLOSED;
        !          1740:        else
        !          1741:                manager->fdstate[fd] = CLOSE_PENDING;
        !          1742:        UNLOCK(&manager->fdlock[lockid]);
        !          1743:        if (type == isc_sockettype_fdwatch) {
        !          1744:                /*
        !          1745:                 * The caller may close the socket once this function returns,
        !          1746:                 * and `fd' may be reassigned for a new socket.  So we do
        !          1747:                 * unwatch_fd() here, rather than defer it via select_poke().
        !          1748:                 * Note: this may complicate data protection among threads and
        !          1749:                 * may reduce performance due to additional locks.  One way to
        !          1750:                 * solve this would be to dup() the watched descriptor, but we
        !          1751:                 * take a simpler approach at this moment.
        !          1752:                 */
        !          1753:                (void)unwatch_fd(manager, fd, SELECT_POKE_READ);
        !          1754:                (void)unwatch_fd(manager, fd, SELECT_POKE_WRITE);
        !          1755:        } else
        !          1756:                select_poke(manager, fd, SELECT_POKE_CLOSE);
        !          1757: 
        !          1758:        inc_stats(manager->stats, sock->statsindex[STATID_CLOSE]);
        !          1759: 
        !          1760:        /*
        !          1761:         * update manager->maxfd here (XXX: this should be implemented more
        !          1762:         * efficiently)
        !          1763:         */
        !          1764: #ifdef USE_SELECT
        !          1765:        LOCK(&manager->lock);
        !          1766:        if (manager->maxfd == fd) {
        !          1767:                int i;
        !          1768: 
        !          1769:                manager->maxfd = 0;
        !          1770:                for (i = fd - 1; i >= 0; i--) {
        !          1771:                        lockid = FDLOCK_ID(i);
        !          1772: 
        !          1773:                        LOCK(&manager->fdlock[lockid]);
        !          1774:                        if (manager->fdstate[i] == MANAGED) {
        !          1775:                                manager->maxfd = i;
        !          1776:                                UNLOCK(&manager->fdlock[lockid]);
        !          1777:                                break;
        !          1778:                        }
        !          1779:                        UNLOCK(&manager->fdlock[lockid]);
        !          1780:                }
        !          1781: #ifdef ISC_PLATFORM_USETHREADS
        !          1782:                if (manager->maxfd < manager->pipe_fds[0])
        !          1783:                        manager->maxfd = manager->pipe_fds[0];
        !          1784: #endif
        !          1785:        }
        !          1786:        UNLOCK(&manager->lock);
        !          1787: #endif /* USE_SELECT */
        !          1788: }
        !          1789: 
        !          1790: static void
        !          1791: destroy(isc_socket_t **sockp) {
        !          1792:        int fd;
        !          1793:        isc_socket_t *sock = *sockp;
        !          1794:        isc_socketmgr_t *manager = sock->manager;
        !          1795: 
        !          1796:        socket_log(sock, NULL, CREATION, isc_msgcat, ISC_MSGSET_SOCKET,
        !          1797:                   ISC_MSG_DESTROYING, "destroying");
        !          1798: 
        !          1799:        INSIST(ISC_LIST_EMPTY(sock->accept_list));
        !          1800:        INSIST(ISC_LIST_EMPTY(sock->recv_list));
        !          1801:        INSIST(ISC_LIST_EMPTY(sock->send_list));
        !          1802:        INSIST(sock->connect_ev == NULL);
        !          1803:        REQUIRE(sock->fd == -1 || sock->fd < (int)manager->maxsocks);
        !          1804: 
        !          1805:        if (sock->fd >= 0) {
        !          1806:                fd = sock->fd;
        !          1807:                sock->fd = -1;
        !          1808:                closesocket(manager, sock, fd);
        !          1809:        }
        !          1810: 
        !          1811:        LOCK(&manager->lock);
        !          1812: 
        !          1813:        ISC_LIST_UNLINK(manager->socklist, sock, link);
        !          1814: 
        !          1815: #ifdef ISC_PLATFORM_USETHREADS
        !          1816:        if (ISC_LIST_EMPTY(manager->socklist))
        !          1817:                SIGNAL(&manager->shutdown_ok);
        !          1818: #endif /* ISC_PLATFORM_USETHREADS */
        !          1819: 
        !          1820:        UNLOCK(&manager->lock);
        !          1821: 
        !          1822:        free_socket(sockp);
        !          1823: }
        !          1824: 
        !          1825: static isc_result_t
        !          1826: allocate_socket(isc_socketmgr_t *manager, isc_sockettype_t type,
        !          1827:                isc_socket_t **socketp)
        !          1828: {
        !          1829:        isc_socket_t *sock;
        !          1830:        isc_result_t result;
        !          1831:        ISC_SOCKADDR_LEN_T cmsgbuflen;
        !          1832: 
        !          1833:        sock = isc_mem_get(manager->mctx, sizeof(*sock));
        !          1834: 
        !          1835:        if (sock == NULL)
        !          1836:                return (ISC_R_NOMEMORY);
        !          1837: 
        !          1838:        result = ISC_R_UNEXPECTED;
        !          1839: 
        !          1840:        sock->magic = 0;
        !          1841:        sock->references = 0;
        !          1842: 
        !          1843:        sock->manager = manager;
        !          1844:        sock->type = type;
        !          1845:        sock->fd = -1;
        !          1846:        sock->statsindex = NULL;
        !          1847: 
        !          1848:        ISC_LINK_INIT(sock, link);
        !          1849: 
        !          1850:        sock->recvcmsgbuf = NULL;
        !          1851:        sock->sendcmsgbuf = NULL;
        !          1852: 
        !          1853:        /*
        !          1854:         * set up cmsg buffers
        !          1855:         */
        !          1856:        cmsgbuflen = 0;
        !          1857: #if defined(USE_CMSG) && defined(ISC_PLATFORM_HAVEIN6PKTINFO)
        !          1858:        cmsgbuflen = cmsg_space(sizeof(struct in6_pktinfo));
        !          1859: #endif
        !          1860: #if defined(USE_CMSG) && defined(SO_TIMESTAMP)
        !          1861:        cmsgbuflen += cmsg_space(sizeof(struct timeval));
        !          1862: #endif
        !          1863:        sock->recvcmsgbuflen = cmsgbuflen;
        !          1864:        if (sock->recvcmsgbuflen != 0U) {
        !          1865:                sock->recvcmsgbuf = isc_mem_get(manager->mctx, cmsgbuflen);
        !          1866:                if (sock->recvcmsgbuf == NULL)
        !          1867:                        goto error;
        !          1868:        }
        !          1869: 
        !          1870:        cmsgbuflen = 0;
        !          1871: #if defined(USE_CMSG) && defined(ISC_PLATFORM_HAVEIN6PKTINFO)
        !          1872:        cmsgbuflen = cmsg_space(sizeof(struct in6_pktinfo));
        !          1873: #endif
        !          1874:        sock->sendcmsgbuflen = cmsgbuflen;
        !          1875:        if (sock->sendcmsgbuflen != 0U) {
        !          1876:                sock->sendcmsgbuf = isc_mem_get(manager->mctx, cmsgbuflen);
        !          1877:                if (sock->sendcmsgbuf == NULL)
        !          1878:                        goto error;
        !          1879:        }
        !          1880: 
        !          1881:        memset(sock->name, 0, sizeof(sock->name));
        !          1882:        sock->tag = NULL;
        !          1883: 
        !          1884:        /*
        !          1885:         * set up list of readers and writers to be initially empty
        !          1886:         */
        !          1887:        ISC_LIST_INIT(sock->recv_list);
        !          1888:        ISC_LIST_INIT(sock->send_list);
        !          1889:        ISC_LIST_INIT(sock->accept_list);
        !          1890:        sock->connect_ev = NULL;
        !          1891:        sock->pending_recv = 0;
        !          1892:        sock->pending_send = 0;
        !          1893:        sock->pending_accept = 0;
        !          1894:        sock->listener = 0;
        !          1895:        sock->connected = 0;
        !          1896:        sock->connecting = 0;
        !          1897:        sock->bound = 0;
        !          1898: 
        !          1899:        /*
        !          1900:         * initialize the lock
        !          1901:         */
        !          1902:        result = isc_mutex_init(&sock->lock);
        !          1903:        if (result != ISC_R_SUCCESS) {
        !          1904:                sock->magic = 0;
        !          1905:                goto error;
        !          1906:        }
        !          1907: 
        !          1908:        /*
        !          1909:         * Initialize readable and writable events
        !          1910:         */
        !          1911:        ISC_EVENT_INIT(&sock->readable_ev, sizeof(intev_t),
        !          1912:                       ISC_EVENTATTR_NOPURGE, NULL, ISC_SOCKEVENT_INTR,
        !          1913:                       NULL, sock, sock, NULL, NULL);
        !          1914:        ISC_EVENT_INIT(&sock->writable_ev, sizeof(intev_t),
        !          1915:                       ISC_EVENTATTR_NOPURGE, NULL, ISC_SOCKEVENT_INTW,
        !          1916:                       NULL, sock, sock, NULL, NULL);
        !          1917: 
        !          1918:        sock->magic = SOCKET_MAGIC;
        !          1919:        *socketp = sock;
        !          1920: 
        !          1921:        return (ISC_R_SUCCESS);
        !          1922: 
        !          1923:  error:
        !          1924:        if (sock->recvcmsgbuf != NULL)
        !          1925:                isc_mem_put(manager->mctx, sock->recvcmsgbuf,
        !          1926:                            sock->recvcmsgbuflen);
        !          1927:        if (sock->sendcmsgbuf != NULL)
        !          1928:                isc_mem_put(manager->mctx, sock->sendcmsgbuf,
        !          1929:                            sock->sendcmsgbuflen);
        !          1930:        isc_mem_put(manager->mctx, sock, sizeof(*sock));
        !          1931: 
        !          1932:        return (result);
        !          1933: }
        !          1934: 
        !          1935: /*
        !          1936:  * This event requires that the various lists be empty, that the reference
        !          1937:  * count be 1, and that the magic number is valid.  The other socket bits,
        !          1938:  * like the lock, must be initialized as well.  The fd associated must be
        !          1939:  * marked as closed, by setting it to -1 on close, or this routine will
        !          1940:  * also close the socket.
        !          1941:  */
        !          1942: static void
        !          1943: free_socket(isc_socket_t **socketp) {
        !          1944:        isc_socket_t *sock = *socketp;
        !          1945: 
        !          1946:        INSIST(sock->references == 0);
        !          1947:        INSIST(VALID_SOCKET(sock));
        !          1948:        INSIST(!sock->connecting);
        !          1949:        INSIST(!sock->pending_recv);
        !          1950:        INSIST(!sock->pending_send);
        !          1951:        INSIST(!sock->pending_accept);
        !          1952:        INSIST(ISC_LIST_EMPTY(sock->recv_list));
        !          1953:        INSIST(ISC_LIST_EMPTY(sock->send_list));
        !          1954:        INSIST(ISC_LIST_EMPTY(sock->accept_list));
        !          1955:        INSIST(!ISC_LINK_LINKED(sock, link));
        !          1956: 
        !          1957:        if (sock->recvcmsgbuf != NULL)
        !          1958:                isc_mem_put(sock->manager->mctx, sock->recvcmsgbuf,
        !          1959:                            sock->recvcmsgbuflen);
        !          1960:        if (sock->sendcmsgbuf != NULL)
        !          1961:                isc_mem_put(sock->manager->mctx, sock->sendcmsgbuf,
        !          1962:                            sock->sendcmsgbuflen);
        !          1963: 
        !          1964:        sock->magic = 0;
        !          1965: 
        !          1966:        DESTROYLOCK(&sock->lock);
        !          1967: 
        !          1968:        isc_mem_put(sock->manager->mctx, sock, sizeof(*sock));
        !          1969: 
        !          1970:        *socketp = NULL;
        !          1971: }
        !          1972: 
        !          1973: #ifdef SO_BSDCOMPAT
        !          1974: /*
        !          1975:  * This really should not be necessary to do.  Having to workout
        !          1976:  * which kernel version we are on at run time so that we don't cause
        !          1977:  * the kernel to issue a warning about us using a deprecated socket option.
        !          1978:  * Such warnings should *never* be on by default in production kernels.
        !          1979:  *
        !          1980:  * We can't do this a build time because executables are moved between
        !          1981:  * machines and hence kernels.
        !          1982:  *
        !          1983:  * We can't just not set SO_BSDCOMAT because some kernels require it.
        !          1984:  */
        !          1985: 
        !          1986: static isc_once_t         bsdcompat_once = ISC_ONCE_INIT;
        !          1987: isc_boolean_t bsdcompat = ISC_TRUE;
        !          1988: 
        !          1989: static void
        !          1990: clear_bsdcompat(void) {
        !          1991: #ifdef __linux__
        !          1992:         struct utsname buf;
        !          1993:         char *endp;
        !          1994:         long int major;
        !          1995:         long int minor;
        !          1996: 
        !          1997:         uname(&buf);    /* Can only fail if buf is bad in Linux. */
        !          1998: 
        !          1999:         /* Paranoia in parsing can be increased, but we trust uname(). */
        !          2000:         major = strtol(buf.release, &endp, 10);
        !          2001:         if (*endp == '.') {
        !          2002:                minor = strtol(endp+1, &endp, 10);
        !          2003:                if ((major > 2) || ((major == 2) && (minor >= 4))) {
        !          2004:                        bsdcompat = ISC_FALSE;
        !          2005:                }
        !          2006:         }
        !          2007: #endif /* __linux __ */
        !          2008: }
        !          2009: #endif
        !          2010: 
        !          2011: static isc_result_t
        !          2012: opensocket(isc_socketmgr_t *manager, isc_socket_t *sock) {
        !          2013:        char strbuf[ISC_STRERRORSIZE];
        !          2014:        const char *err = "socket";
        !          2015:        int tries = 0;
        !          2016: #if defined(USE_CMSG) || defined(SO_BSDCOMPAT)
        !          2017:        int on = 1;
        !          2018: #endif
        !          2019: #if defined(SO_RCVBUF)
        !          2020:        ISC_SOCKADDR_LEN_T optlen;
        !          2021:        int size;
        !          2022: #endif
        !          2023: 
        !          2024:  again:
        !          2025:        switch (sock->type) {
        !          2026:        case isc_sockettype_udp:
        !          2027:                sock->fd = socket(sock->pf, SOCK_DGRAM, IPPROTO_UDP);
        !          2028:                break;
        !          2029:        case isc_sockettype_tcp:
        !          2030:                sock->fd = socket(sock->pf, SOCK_STREAM, IPPROTO_TCP);
        !          2031:                break;
        !          2032:        case isc_sockettype_unix:
        !          2033:                sock->fd = socket(sock->pf, SOCK_STREAM, 0);
        !          2034:                break;
        !          2035:        case isc_sockettype_fdwatch:
        !          2036:                /*
        !          2037:                 * We should not be called for isc_sockettype_fdwatch sockets.
        !          2038:                 */
        !          2039:                INSIST(0);
        !          2040:                break;
        !          2041:        }
        !          2042:        if (sock->fd == -1 && errno == EINTR && tries++ < 42)
        !          2043:                goto again;
        !          2044: 
        !          2045: #ifdef F_DUPFD
        !          2046:        /*
        !          2047:         * Leave a space for stdio and TCP to work in.
        !          2048:         */
        !          2049:        if (manager->reserved != 0 && sock->type == isc_sockettype_udp &&
        !          2050:            sock->fd >= 0 && sock->fd < manager->reserved) {
        !          2051:                int new, tmp;
        !          2052:                new = fcntl(sock->fd, F_DUPFD, manager->reserved);
        !          2053:                tmp = errno;
        !          2054:                (void)close(sock->fd);
        !          2055:                errno = tmp;
        !          2056:                sock->fd = new;
        !          2057:                err = "isc_socket_create: fcntl/reserved";
        !          2058:        } else if (sock->fd >= 0 && sock->fd < 20) {
        !          2059:                int new, tmp;
        !          2060:                new = fcntl(sock->fd, F_DUPFD, 20);
        !          2061:                tmp = errno;
        !          2062:                (void)close(sock->fd);
        !          2063:                errno = tmp;
        !          2064:                sock->fd = new;
        !          2065:                err = "isc_socket_create: fcntl";
        !          2066:        }
        !          2067: #endif
        !          2068: 
        !          2069:        if (sock->fd >= (int)manager->maxsocks) {
        !          2070:                (void)close(sock->fd);
        !          2071:                isc_log_iwrite(isc_lctx, ISC_LOGCATEGORY_GENERAL,
        !          2072:                               ISC_LOGMODULE_SOCKET, ISC_LOG_ERROR,
        !          2073:                               isc_msgcat, ISC_MSGSET_SOCKET,
        !          2074:                               ISC_MSG_TOOMANYFDS,
        !          2075:                               "socket: file descriptor exceeds limit (%d/%u)",
        !          2076:                               sock->fd, manager->maxsocks);
        !          2077:                return (ISC_R_NORESOURCES);
        !          2078:        }
        !          2079: 
        !          2080:        if (sock->fd < 0) {
        !          2081:                switch (errno) {
        !          2082:                case EMFILE:
        !          2083:                case ENFILE:
        !          2084:                        isc__strerror(errno, strbuf, sizeof(strbuf));
        !          2085:                        isc_log_iwrite(isc_lctx, ISC_LOGCATEGORY_GENERAL,
        !          2086:                                       ISC_LOGMODULE_SOCKET, ISC_LOG_ERROR,
        !          2087:                                       isc_msgcat, ISC_MSGSET_SOCKET,
        !          2088:                                       ISC_MSG_TOOMANYFDS,
        !          2089:                                       "%s: %s", err, strbuf);
        !          2090:                        /* fallthrough */
        !          2091:                case ENOBUFS:
        !          2092:                        return (ISC_R_NORESOURCES);
        !          2093: 
        !          2094:                case EPROTONOSUPPORT:
        !          2095:                case EPFNOSUPPORT:
        !          2096:                case EAFNOSUPPORT:
        !          2097:                /*
        !          2098:                 * Linux 2.2 (and maybe others) return EINVAL instead of
        !          2099:                 * EAFNOSUPPORT.
        !          2100:                 */
        !          2101:                case EINVAL:
        !          2102:                        return (ISC_R_FAMILYNOSUPPORT);
        !          2103: 
        !          2104:                default:
        !          2105:                        isc__strerror(errno, strbuf, sizeof(strbuf));
        !          2106:                        UNEXPECTED_ERROR(__FILE__, __LINE__,
        !          2107:                                         "%s() %s: %s", err,
        !          2108:                                         isc_msgcat_get(isc_msgcat,
        !          2109:                                                        ISC_MSGSET_GENERAL,
        !          2110:                                                        ISC_MSG_FAILED,
        !          2111:                                                        "failed"),
        !          2112:                                         strbuf);
        !          2113:                        return (ISC_R_UNEXPECTED);
        !          2114:                }
        !          2115:        }
        !          2116: 
        !          2117:        if (make_nonblock(sock->fd) != ISC_R_SUCCESS) {
        !          2118:                (void)close(sock->fd);
        !          2119:                return (ISC_R_UNEXPECTED);
        !          2120:        }
        !          2121: 
        !          2122: #ifdef SO_BSDCOMPAT
        !          2123:        RUNTIME_CHECK(isc_once_do(&bsdcompat_once,
        !          2124:                                  clear_bsdcompat) == ISC_R_SUCCESS);
        !          2125:        if (sock->type != isc_sockettype_unix && bsdcompat &&
        !          2126:            setsockopt(sock->fd, SOL_SOCKET, SO_BSDCOMPAT,
        !          2127:                       (void *)&on, sizeof(on)) < 0) {
        !          2128:                isc__strerror(errno, strbuf, sizeof(strbuf));
        !          2129:                UNEXPECTED_ERROR(__FILE__, __LINE__,
        !          2130:                                 "setsockopt(%d, SO_BSDCOMPAT) %s: %s",
        !          2131:                                 sock->fd,
        !          2132:                                 isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
        !          2133:                                                ISC_MSG_FAILED, "failed"),
        !          2134:                                 strbuf);
        !          2135:                /* Press on... */
        !          2136:        }
        !          2137: #endif
        !          2138: 
        !          2139: #ifdef SO_NOSIGPIPE
        !          2140:        if (setsockopt(sock->fd, SOL_SOCKET, SO_NOSIGPIPE,
        !          2141:                       (void *)&on, sizeof(on)) < 0) {
        !          2142:                isc__strerror(errno, strbuf, sizeof(strbuf));
        !          2143:                UNEXPECTED_ERROR(__FILE__, __LINE__,
        !          2144:                                 "setsockopt(%d, SO_NOSIGPIPE) %s: %s",
        !          2145:                                 sock->fd,
        !          2146:                                 isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
        !          2147:                                                ISC_MSG_FAILED, "failed"),
        !          2148:                                 strbuf);
        !          2149:                /* Press on... */
        !          2150:        }
        !          2151: #endif
        !          2152: 
        !          2153: #if defined(USE_CMSG) || defined(SO_RCVBUF)
        !          2154:        if (sock->type == isc_sockettype_udp) {
        !          2155: 
        !          2156: #if defined(USE_CMSG)
        !          2157: #if defined(SO_TIMESTAMP)
        !          2158:                if (setsockopt(sock->fd, SOL_SOCKET, SO_TIMESTAMP,
        !          2159:                               (void *)&on, sizeof(on)) < 0
        !          2160:                    && errno != ENOPROTOOPT) {
        !          2161:                        isc__strerror(errno, strbuf, sizeof(strbuf));
        !          2162:                        UNEXPECTED_ERROR(__FILE__, __LINE__,
        !          2163:                                         "setsockopt(%d, SO_TIMESTAMP) %s: %s",
        !          2164:                                         sock->fd,
        !          2165:                                         isc_msgcat_get(isc_msgcat,
        !          2166:                                                        ISC_MSGSET_GENERAL,
        !          2167:                                                        ISC_MSG_FAILED,
        !          2168:                                                        "failed"),
        !          2169:                                         strbuf);
        !          2170:                        /* Press on... */
        !          2171:                }
        !          2172: #endif /* SO_TIMESTAMP */
        !          2173: 
        !          2174: #if defined(ISC_PLATFORM_HAVEIPV6)
        !          2175:                if (sock->pf == AF_INET6 && sock->recvcmsgbuflen == 0U) {
        !          2176:                        /*
        !          2177:                         * Warn explicitly because this anomaly can be hidden
        !          2178:                         * in usual operation (and unexpectedly appear later).
        !          2179:                         */
        !          2180:                        UNEXPECTED_ERROR(__FILE__, __LINE__,
        !          2181:                                         "No buffer available to receive "
        !          2182:                                         "IPv6 destination");
        !          2183:                }
        !          2184: #ifdef ISC_PLATFORM_HAVEIN6PKTINFO
        !          2185: #ifdef IPV6_RECVPKTINFO
        !          2186:                /* RFC 3542 */
        !          2187:                if ((sock->pf == AF_INET6)
        !          2188:                    && (setsockopt(sock->fd, IPPROTO_IPV6, IPV6_RECVPKTINFO,
        !          2189:                                   (void *)&on, sizeof(on)) < 0)) {
        !          2190:                        isc__strerror(errno, strbuf, sizeof(strbuf));
        !          2191:                        UNEXPECTED_ERROR(__FILE__, __LINE__,
        !          2192:                                         "setsockopt(%d, IPV6_RECVPKTINFO) "
        !          2193:                                         "%s: %s", sock->fd,
        !          2194:                                         isc_msgcat_get(isc_msgcat,
        !          2195:                                                        ISC_MSGSET_GENERAL,
        !          2196:                                                        ISC_MSG_FAILED,
        !          2197:                                                        "failed"),
        !          2198:                                         strbuf);
        !          2199:                }
        !          2200: #else
        !          2201:                /* RFC 2292 */
        !          2202:                if ((sock->pf == AF_INET6)
        !          2203:                    && (setsockopt(sock->fd, IPPROTO_IPV6, IPV6_PKTINFO,
        !          2204:                                   (void *)&on, sizeof(on)) < 0)) {
        !          2205:                        isc__strerror(errno, strbuf, sizeof(strbuf));
        !          2206:                        UNEXPECTED_ERROR(__FILE__, __LINE__,
        !          2207:                                         "setsockopt(%d, IPV6_PKTINFO) %s: %s",
        !          2208:                                         sock->fd,
        !          2209:                                         isc_msgcat_get(isc_msgcat,
        !          2210:                                                        ISC_MSGSET_GENERAL,
        !          2211:                                                        ISC_MSG_FAILED,
        !          2212:                                                        "failed"),
        !          2213:                                         strbuf);
        !          2214:                }
        !          2215: #endif /* IPV6_RECVPKTINFO */
        !          2216: #endif /* ISC_PLATFORM_HAVEIN6PKTINFO */
        !          2217: #ifdef IPV6_USE_MIN_MTU        /* RFC 3542, not too common yet*/
        !          2218:                /* use minimum MTU */
        !          2219:                if (sock->pf == AF_INET6) {
        !          2220:                        (void)setsockopt(sock->fd, IPPROTO_IPV6,
        !          2221:                                         IPV6_USE_MIN_MTU,
        !          2222:                                         (void *)&on, sizeof(on));
        !          2223:                }
        !          2224: #endif
        !          2225: #endif /* ISC_PLATFORM_HAVEIPV6 */
        !          2226: #endif /* defined(USE_CMSG) */
        !          2227: 
        !          2228: #if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
        !          2229:                /*
        !          2230:                 * Turn off Path MTU discovery on IPv4/UDP sockets.
        !          2231:                 */
        !          2232:                if (sock->pf == AF_INET) {
        !          2233:                        int action = IP_PMTUDISC_DONT;
        !          2234:                        (void)setsockopt(sock->fd, IPPROTO_IP, IP_MTU_DISCOVER,
        !          2235:                                         &action, sizeof(action));
        !          2236:                }
        !          2237: #endif
        !          2238: #if defined(IP_DONTFRAG)
        !          2239:                /*
        !          2240:                 * Turn off Path MTU discovery on IPv4/UDP sockets.
        !          2241:                 */
        !          2242:                if (sock->pf == AF_INET) {
        !          2243:                        int off = 0;
        !          2244:                        (void)setsockopt(sock->fd, IPPROTO_IP, IP_DONTFRAG,
        !          2245:                                         &off, sizeof(off));
        !          2246:                }
        !          2247: #endif
        !          2248: 
        !          2249: #if defined(SO_RCVBUF)
        !          2250:                optlen = sizeof(size);
        !          2251:                if (getsockopt(sock->fd, SOL_SOCKET, SO_RCVBUF,
        !          2252:                               (void *)&size, &optlen) >= 0 &&
        !          2253:                     size < RCVBUFSIZE) {
        !          2254:                        size = RCVBUFSIZE;
        !          2255:                        if (setsockopt(sock->fd, SOL_SOCKET, SO_RCVBUF,
        !          2256:                                       (void *)&size, sizeof(size)) == -1) {
        !          2257:                                isc__strerror(errno, strbuf, sizeof(strbuf));
        !          2258:                                UNEXPECTED_ERROR(__FILE__, __LINE__,
        !          2259:                                        "setsockopt(%d, SO_RCVBUF, %d) %s: %s",
        !          2260:                                        sock->fd, size,
        !          2261:                                        isc_msgcat_get(isc_msgcat,
        !          2262:                                                       ISC_MSGSET_GENERAL,
        !          2263:                                                       ISC_MSG_FAILED,
        !          2264:                                                       "failed"),
        !          2265:                                        strbuf);
        !          2266:                        }
        !          2267:                }
        !          2268: #endif
        !          2269:        }
        !          2270: #endif /* defined(USE_CMSG) || defined(SO_RCVBUF) */
        !          2271: 
        !          2272:        inc_stats(manager->stats, sock->statsindex[STATID_OPEN]);
        !          2273: 
        !          2274:        return (ISC_R_SUCCESS);
        !          2275: }
        !          2276: 
        !          2277: /*%
        !          2278:  * Create a new 'type' socket managed by 'manager'.  Events
        !          2279:  * will be posted to 'task' and when dispatched 'action' will be
        !          2280:  * called with 'arg' as the arg value.  The new socket is returned
        !          2281:  * in 'socketp'.
        !          2282:  */
        !          2283: isc_result_t
        !          2284: isc_socket_create(isc_socketmgr_t *manager, int pf, isc_sockettype_t type,
        !          2285:                  isc_socket_t **socketp)
        !          2286: {
        !          2287:        isc_socket_t *sock = NULL;
        !          2288:        isc_result_t result;
        !          2289:        int lockid;
        !          2290: 
        !          2291:        REQUIRE(VALID_MANAGER(manager));
        !          2292:        REQUIRE(socketp != NULL && *socketp == NULL);
        !          2293:        REQUIRE(type != isc_sockettype_fdwatch);
        !          2294: 
        !          2295:        result = allocate_socket(manager, type, &sock);
        !          2296:        if (result != ISC_R_SUCCESS)
        !          2297:                return (result);
        !          2298: 
        !          2299:        switch (sock->type) {
        !          2300:        case isc_sockettype_udp:
        !          2301:                sock->statsindex =
        !          2302:                        (pf == AF_INET) ? upd4statsindex : upd6statsindex;
        !          2303:                break;
        !          2304:        case isc_sockettype_tcp:
        !          2305:                sock->statsindex =
        !          2306:                        (pf == AF_INET) ? tcp4statsindex : tcp6statsindex;
        !          2307:                break;
        !          2308:        case isc_sockettype_unix:
        !          2309:                sock->statsindex = unixstatsindex;
        !          2310:                break;
        !          2311:        default:
        !          2312:                INSIST(0);
        !          2313:        }
        !          2314: 
        !          2315:        sock->pf = pf;
        !          2316:        result = opensocket(manager, sock);
        !          2317:        if (result != ISC_R_SUCCESS) {
        !          2318:                inc_stats(manager->stats, sock->statsindex[STATID_OPENFAIL]);
        !          2319:                free_socket(&sock);
        !          2320:                return (result);
        !          2321:        }
        !          2322: 
        !          2323:        sock->references = 1;
        !          2324:        *socketp = sock;
        !          2325: 
        !          2326:        /*
        !          2327:         * Note we don't have to lock the socket like we normally would because
        !          2328:         * there are no external references to it yet.
        !          2329:         */
        !          2330: 
        !          2331:        lockid = FDLOCK_ID(sock->fd);
        !          2332:        LOCK(&manager->fdlock[lockid]);
        !          2333:        manager->fds[sock->fd] = sock;
        !          2334:        manager->fdstate[sock->fd] = MANAGED;
        !          2335: #ifdef USE_DEVPOLL
        !          2336:        INSIST(sock->manager->fdpollinfo[sock->fd].want_read == 0 &&
        !          2337:               sock->manager->fdpollinfo[sock->fd].want_write == 0);
        !          2338: #endif
        !          2339:        UNLOCK(&manager->fdlock[lockid]);
        !          2340: 
        !          2341:        LOCK(&manager->lock);
        !          2342:        ISC_LIST_APPEND(manager->socklist, sock, link);
        !          2343: #ifdef USE_SELECT
        !          2344:        if (manager->maxfd < sock->fd)
        !          2345:                manager->maxfd = sock->fd;
        !          2346: #endif
        !          2347:        UNLOCK(&manager->lock);
        !          2348: 
        !          2349:        socket_log(sock, NULL, CREATION, isc_msgcat, ISC_MSGSET_SOCKET,
        !          2350:                   ISC_MSG_CREATED, "created");
        !          2351: 
        !          2352:        return (ISC_R_SUCCESS);
        !          2353: }
        !          2354: 
        !          2355: isc_result_t
        !          2356: isc_socket_open(isc_socket_t *sock) {
        !          2357:        isc_result_t result;
        !          2358: 
        !          2359:        REQUIRE(VALID_SOCKET(sock));
        !          2360: 
        !          2361:        LOCK(&sock->lock);
        !          2362:        REQUIRE(sock->references == 1);
        !          2363:        REQUIRE(sock->type != isc_sockettype_fdwatch);
        !          2364:        UNLOCK(&sock->lock);
        !          2365:        /*
        !          2366:         * We don't need to retain the lock hereafter, since no one else has
        !          2367:         * this socket.
        !          2368:         */
        !          2369:        REQUIRE(sock->fd == -1);
        !          2370: 
        !          2371:        result = opensocket(sock->manager, sock);
        !          2372:        if (result != ISC_R_SUCCESS)
        !          2373:                sock->fd = -1;
        !          2374: 
        !          2375:        if (result == ISC_R_SUCCESS) {
        !          2376:                int lockid = FDLOCK_ID(sock->fd);
        !          2377: 
        !          2378:                LOCK(&sock->manager->fdlock[lockid]);
        !          2379:                sock->manager->fds[sock->fd] = sock;
        !          2380:                sock->manager->fdstate[sock->fd] = MANAGED;
        !          2381: #ifdef USE_DEVPOLL
        !          2382:                INSIST(sock->manager->fdpollinfo[sock->fd].want_read == 0 &&
        !          2383:                       sock->manager->fdpollinfo[sock->fd].want_write == 0);
        !          2384: #endif
        !          2385:                UNLOCK(&sock->manager->fdlock[lockid]);
        !          2386: 
        !          2387: #ifdef USE_SELECT
        !          2388:                LOCK(&sock->manager->lock);
        !          2389:                if (sock->manager->maxfd < sock->fd)
        !          2390:                        sock->manager->maxfd = sock->fd;
        !          2391:                UNLOCK(&sock->manager->lock);
        !          2392: #endif
        !          2393:        }
        !          2394: 
        !          2395:        return (result);
        !          2396: }
        !          2397: 
        !          2398: /*
        !          2399:  * Create a new 'type' socket managed by 'manager'.  Events
        !          2400:  * will be posted to 'task' and when dispatched 'action' will be
        !          2401:  * called with 'arg' as the arg value.  The new socket is returned
        !          2402:  * in 'socketp'.
        !          2403:  */
        !          2404: isc_result_t
        !          2405: isc_socket_fdwatchcreate(isc_socketmgr_t *manager, int fd, int flags,
        !          2406:                         isc_sockfdwatch_t callback, void *cbarg,
        !          2407:                         isc_task_t *task, isc_socket_t **socketp)
        !          2408: {
        !          2409:        isc_socket_t *sock = NULL;
        !          2410:        isc_result_t result;
        !          2411:        int lockid;
        !          2412: 
        !          2413:        REQUIRE(VALID_MANAGER(manager));
        !          2414:        REQUIRE(socketp != NULL && *socketp == NULL);
        !          2415: 
        !          2416:        result = allocate_socket(manager, isc_sockettype_fdwatch, &sock);
        !          2417:        if (result != ISC_R_SUCCESS)
        !          2418:                return (result);
        !          2419: 
        !          2420:        sock->fd = fd;
        !          2421:        sock->fdwatcharg = cbarg;
        !          2422:        sock->fdwatchcb = callback;
        !          2423:        sock->fdwatchflags = flags;
        !          2424:        sock->fdwatchtask = task;
        !          2425:        sock->statsindex = fdwatchstatsindex;
        !          2426: 
        !          2427:        sock->references = 1;
        !          2428:        *socketp = sock;
        !          2429: 
        !          2430:        /*
        !          2431:         * Note we don't have to lock the socket like we normally would because
        !          2432:         * there are no external references to it yet.
        !          2433:         */
        !          2434: 
        !          2435:        lockid = FDLOCK_ID(sock->fd);
        !          2436:        LOCK(&manager->fdlock[lockid]);
        !          2437:        manager->fds[sock->fd] = sock;
        !          2438:        manager->fdstate[sock->fd] = MANAGED;
        !          2439:        UNLOCK(&manager->fdlock[lockid]);
        !          2440: 
        !          2441:        LOCK(&manager->lock);
        !          2442:        ISC_LIST_APPEND(manager->socklist, sock, link);
        !          2443: #ifdef USE_SELECT
        !          2444:        if (manager->maxfd < sock->fd)
        !          2445:                manager->maxfd = sock->fd;
        !          2446: #endif
        !          2447:        UNLOCK(&manager->lock);
        !          2448: 
        !          2449:        if (flags & ISC_SOCKFDWATCH_READ)
        !          2450:                select_poke(sock->manager, sock->fd, SELECT_POKE_READ);
        !          2451:        if (flags & ISC_SOCKFDWATCH_WRITE)
        !          2452:                select_poke(sock->manager, sock->fd, SELECT_POKE_WRITE);
        !          2453: 
        !          2454:        socket_log(sock, NULL, CREATION, isc_msgcat, ISC_MSGSET_SOCKET,
        !          2455:                   ISC_MSG_CREATED, "fdwatch-created");
        !          2456: 
        !          2457:        return (ISC_R_SUCCESS);
        !          2458: }
        !          2459: 
        !          2460: /*
        !          2461:  * Attach to a socket.  Caller must explicitly detach when it is done.
        !          2462:  */
        !          2463: void
        !          2464: isc_socket_attach(isc_socket_t *sock, isc_socket_t **socketp) {
        !          2465:        REQUIRE(VALID_SOCKET(sock));
        !          2466:        REQUIRE(socketp != NULL && *socketp == NULL);
        !          2467: 
        !          2468:        LOCK(&sock->lock);
        !          2469:        sock->references++;
        !          2470:        UNLOCK(&sock->lock);
        !          2471: 
        !          2472:        *socketp = sock;
        !          2473: }
        !          2474: 
        !          2475: /*
        !          2476:  * Dereference a socket.  If this is the last reference to it, clean things
        !          2477:  * up by destroying the socket.
        !          2478:  */
        !          2479: void
        !          2480: isc_socket_detach(isc_socket_t **socketp) {
        !          2481:        isc_socket_t *sock;
        !          2482:        isc_boolean_t kill_socket = ISC_FALSE;
        !          2483: 
        !          2484:        REQUIRE(socketp != NULL);
        !          2485:        sock = *socketp;
        !          2486:        REQUIRE(VALID_SOCKET(sock));
        !          2487: 
        !          2488:        LOCK(&sock->lock);
        !          2489:        REQUIRE(sock->references > 0);
        !          2490:        sock->references--;
        !          2491:        if (sock->references == 0)
        !          2492:                kill_socket = ISC_TRUE;
        !          2493:        UNLOCK(&sock->lock);
        !          2494: 
        !          2495:        if (kill_socket)
        !          2496:                destroy(&sock);
        !          2497: 
        !          2498:        *socketp = NULL;
        !          2499: }
        !          2500: 
        !          2501: isc_result_t
        !          2502: isc_socket_close(isc_socket_t *sock) {
        !          2503:        int fd;
        !          2504:        isc_socketmgr_t *manager;
        !          2505:        isc_sockettype_t type;
        !          2506: 
        !          2507:        REQUIRE(VALID_SOCKET(sock));
        !          2508: 
        !          2509:        LOCK(&sock->lock);
        !          2510: 
        !          2511:        REQUIRE(sock->references == 1);
        !          2512:        REQUIRE(sock->type != isc_sockettype_fdwatch);
        !          2513:        REQUIRE(sock->fd >= 0 && sock->fd < (int)sock->manager->maxsocks);
        !          2514: 
        !          2515:        INSIST(!sock->connecting);
        !          2516:        INSIST(!sock->pending_recv);
        !          2517:        INSIST(!sock->pending_send);
        !          2518:        INSIST(!sock->pending_accept);
        !          2519:        INSIST(ISC_LIST_EMPTY(sock->recv_list));
        !          2520:        INSIST(ISC_LIST_EMPTY(sock->send_list));
        !          2521:        INSIST(ISC_LIST_EMPTY(sock->accept_list));
        !          2522:        INSIST(sock->connect_ev == NULL);
        !          2523: 
        !          2524:        manager = sock->manager;
        !          2525:        type = sock->type;
        !          2526:        fd = sock->fd;
        !          2527:        sock->fd = -1;
        !          2528:        memset(sock->name, 0, sizeof(sock->name));
        !          2529:        sock->tag = NULL;
        !          2530:        sock->listener = 0;
        !          2531:        sock->connected = 0;
        !          2532:        sock->connecting = 0;
        !          2533:        sock->bound = 0;
        !          2534:        isc_sockaddr_any(&sock->peer_address);
        !          2535: 
        !          2536:        UNLOCK(&sock->lock);
        !          2537: 
        !          2538:        closesocket(manager, sock, fd);
        !          2539: 
        !          2540:        return (ISC_R_SUCCESS);
        !          2541: }
        !          2542: 
        !          2543: /*
        !          2544:  * I/O is possible on a given socket.  Schedule an event to this task that
        !          2545:  * will call an internal function to do the I/O.  This will charge the
        !          2546:  * task with the I/O operation and let our select loop handler get back
        !          2547:  * to doing something real as fast as possible.
        !          2548:  *
        !          2549:  * The socket and manager must be locked before calling this function.
        !          2550:  */
        !          2551: static void
        !          2552: dispatch_recv(isc_socket_t *sock) {
        !          2553:        intev_t *iev;
        !          2554:        isc_socketevent_t *ev;
        !          2555:        isc_task_t *sender;
        !          2556: 
        !          2557:        INSIST(!sock->pending_recv);
        !          2558: 
        !          2559:        if (sock->type != isc_sockettype_fdwatch) {
        !          2560:                ev = ISC_LIST_HEAD(sock->recv_list);
        !          2561:                if (ev == NULL)
        !          2562:                        return;
        !          2563:                socket_log(sock, NULL, EVENT, NULL, 0, 0,
        !          2564:                           "dispatch_recv:  event %p -> task %p",
        !          2565:                           ev, ev->ev_sender);
        !          2566:                sender = ev->ev_sender;
        !          2567:        } else {
        !          2568:                sender = sock->fdwatchtask;
        !          2569:        }
        !          2570: 
        !          2571:        sock->pending_recv = 1;
        !          2572:        iev = &sock->readable_ev;
        !          2573: 
        !          2574:        sock->references++;
        !          2575:        iev->ev_sender = sock;
        !          2576:        if (sock->type == isc_sockettype_fdwatch)
        !          2577:                iev->ev_action = internal_fdwatch_read;
        !          2578:        else
        !          2579:                iev->ev_action = internal_recv;
        !          2580:        iev->ev_arg = sock;
        !          2581: 
        !          2582:        isc_task_send(sender, (isc_event_t **)&iev);
        !          2583: }
        !          2584: 
        !          2585: static void
        !          2586: dispatch_send(isc_socket_t *sock) {
        !          2587:        intev_t *iev;
        !          2588:        isc_socketevent_t *ev;
        !          2589:        isc_task_t *sender;
        !          2590: 
        !          2591:        INSIST(!sock->pending_send);
        !          2592: 
        !          2593:        if (sock->type != isc_sockettype_fdwatch) {
        !          2594:                ev = ISC_LIST_HEAD(sock->send_list);
        !          2595:                if (ev == NULL)
        !          2596:                        return;
        !          2597:                socket_log(sock, NULL, EVENT, NULL, 0, 0,
        !          2598:                           "dispatch_send:  event %p -> task %p",
        !          2599:                           ev, ev->ev_sender);
        !          2600:                sender = ev->ev_sender;
        !          2601:        } else {
        !          2602:                sender = sock->fdwatchtask;
        !          2603:        }
        !          2604: 
        !          2605:        sock->pending_send = 1;
        !          2606:        iev = &sock->writable_ev;
        !          2607: 
        !          2608:        sock->references++;
        !          2609:        iev->ev_sender = sock;
        !          2610:        if (sock->type == isc_sockettype_fdwatch)
        !          2611:                iev->ev_action = internal_fdwatch_write;
        !          2612:        else
        !          2613:                iev->ev_action = internal_send;
        !          2614:        iev->ev_arg = sock;
        !          2615: 
        !          2616:        isc_task_send(sender, (isc_event_t **)&iev);
        !          2617: }
        !          2618: 
        !          2619: /*
        !          2620:  * Dispatch an internal accept event.
        !          2621:  */
        !          2622: static void
        !          2623: dispatch_accept(isc_socket_t *sock) {
        !          2624:        intev_t *iev;
        !          2625:        isc_socket_newconnev_t *ev;
        !          2626: 
        !          2627:        INSIST(!sock->pending_accept);
        !          2628: 
        !          2629:        /*
        !          2630:         * Are there any done events left, or were they all canceled
        !          2631:         * before the manager got the socket lock?
        !          2632:         */
        !          2633:        ev = ISC_LIST_HEAD(sock->accept_list);
        !          2634:        if (ev == NULL)
        !          2635:                return;
        !          2636: 
        !          2637:        sock->pending_accept = 1;
        !          2638:        iev = &sock->readable_ev;
        !          2639: 
        !          2640:        sock->references++;  /* keep socket around for this internal event */
        !          2641:        iev->ev_sender = sock;
        !          2642:        iev->ev_action = internal_accept;
        !          2643:        iev->ev_arg = sock;
        !          2644: 
        !          2645:        isc_task_send(ev->ev_sender, (isc_event_t **)&iev);
        !          2646: }
        !          2647: 
        !          2648: static void
        !          2649: dispatch_connect(isc_socket_t *sock) {
        !          2650:        intev_t *iev;
        !          2651:        isc_socket_connev_t *ev;
        !          2652: 
        !          2653:        iev = &sock->writable_ev;
        !          2654: 
        !          2655:        ev = sock->connect_ev;
        !          2656:        INSIST(ev != NULL); /* XXX */
        !          2657: 
        !          2658:        INSIST(sock->connecting);
        !          2659: 
        !          2660:        sock->references++;  /* keep socket around for this internal event */
        !          2661:        iev->ev_sender = sock;
        !          2662:        iev->ev_action = internal_connect;
        !          2663:        iev->ev_arg = sock;
        !          2664: 
        !          2665:        isc_task_send(ev->ev_sender, (isc_event_t **)&iev);
        !          2666: }
        !          2667: 
        !          2668: /*
        !          2669:  * Dequeue an item off the given socket's read queue, set the result code
        !          2670:  * in the done event to the one provided, and send it to the task it was
        !          2671:  * destined for.
        !          2672:  *
        !          2673:  * If the event to be sent is on a list, remove it before sending.  If
        !          2674:  * asked to, send and detach from the socket as well.
        !          2675:  *
        !          2676:  * Caller must have the socket locked if the event is attached to the socket.
        !          2677:  */
        !          2678: static void
        !          2679: send_recvdone_event(isc_socket_t *sock, isc_socketevent_t **dev) {
        !          2680:        isc_task_t *task;
        !          2681: 
        !          2682:        task = (*dev)->ev_sender;
        !          2683: 
        !          2684:        (*dev)->ev_sender = sock;
        !          2685: 
        !          2686:        if (ISC_LINK_LINKED(*dev, ev_link))
        !          2687:                ISC_LIST_DEQUEUE(sock->recv_list, *dev, ev_link);
        !          2688: 
        !          2689:        if (((*dev)->attributes & ISC_SOCKEVENTATTR_ATTACHED)
        !          2690:            == ISC_SOCKEVENTATTR_ATTACHED)
        !          2691:                isc_task_sendanddetach(&task, (isc_event_t **)dev);
        !          2692:        else
        !          2693:                isc_task_send(task, (isc_event_t **)dev);
        !          2694: }
        !          2695: 
        !          2696: /*
        !          2697:  * See comments for send_recvdone_event() above.
        !          2698:  *
        !          2699:  * Caller must have the socket locked if the event is attached to the socket.
        !          2700:  */
        !          2701: static void
        !          2702: send_senddone_event(isc_socket_t *sock, isc_socketevent_t **dev) {
        !          2703:        isc_task_t *task;
        !          2704: 
        !          2705:        INSIST(dev != NULL && *dev != NULL);
        !          2706: 
        !          2707:        task = (*dev)->ev_sender;
        !          2708:        (*dev)->ev_sender = sock;
        !          2709: 
        !          2710:        if (ISC_LINK_LINKED(*dev, ev_link))
        !          2711:                ISC_LIST_DEQUEUE(sock->send_list, *dev, ev_link);
        !          2712: 
        !          2713:        if (((*dev)->attributes & ISC_SOCKEVENTATTR_ATTACHED)
        !          2714:            == ISC_SOCKEVENTATTR_ATTACHED)
        !          2715:                isc_task_sendanddetach(&task, (isc_event_t **)dev);
        !          2716:        else
        !          2717:                isc_task_send(task, (isc_event_t **)dev);
        !          2718: }
        !          2719: 
        !          2720: /*
        !          2721:  * Call accept() on a socket, to get the new file descriptor.  The listen
        !          2722:  * socket is used as a prototype to create a new isc_socket_t.  The new
        !          2723:  * socket has one outstanding reference.  The task receiving the event
        !          2724:  * will be detached from just after the event is delivered.
        !          2725:  *
        !          2726:  * On entry to this function, the event delivered is the internal
        !          2727:  * readable event, and the first item on the accept_list should be
        !          2728:  * the done event we want to send.  If the list is empty, this is a no-op,
        !          2729:  * so just unlock and return.
        !          2730:  */
        !          2731: static void
        !          2732: internal_accept(isc_task_t *me, isc_event_t *ev) {
        !          2733:        isc_socket_t *sock;
        !          2734:        isc_socketmgr_t *manager;
        !          2735:        isc_socket_newconnev_t *dev;
        !          2736:        isc_task_t *task;
        !          2737:        ISC_SOCKADDR_LEN_T addrlen;
        !          2738:        int fd;
        !          2739:        isc_result_t result = ISC_R_SUCCESS;
        !          2740:        char strbuf[ISC_STRERRORSIZE];
        !          2741:        const char *err = "accept";
        !          2742: 
        !          2743:        UNUSED(me);
        !          2744: 
        !          2745:        sock = ev->ev_sender;
        !          2746:        INSIST(VALID_SOCKET(sock));
        !          2747: 
        !          2748:        LOCK(&sock->lock);
        !          2749:        socket_log(sock, NULL, TRACE,
        !          2750:                   isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_ACCEPTLOCK,
        !          2751:                   "internal_accept called, locked socket");
        !          2752: 
        !          2753:        manager = sock->manager;
        !          2754:        INSIST(VALID_MANAGER(manager));
        !          2755: 
        !          2756:        INSIST(sock->listener);
        !          2757:        INSIST(sock->pending_accept == 1);
        !          2758:        sock->pending_accept = 0;
        !          2759: 
        !          2760:        INSIST(sock->references > 0);
        !          2761:        sock->references--;  /* the internal event is done with this socket */
        !          2762:        if (sock->references == 0) {
        !          2763:                UNLOCK(&sock->lock);
        !          2764:                destroy(&sock);
        !          2765:                return;
        !          2766:        }
        !          2767: 
        !          2768:        /*
        !          2769:         * Get the first item off the accept list.
        !          2770:         * If it is empty, unlock the socket and return.
        !          2771:         */
        !          2772:        dev = ISC_LIST_HEAD(sock->accept_list);
        !          2773:        if (dev == NULL) {
        !          2774:                UNLOCK(&sock->lock);
        !          2775:                return;
        !          2776:        }
        !          2777: 
        !          2778:        /*
        !          2779:         * Try to accept the new connection.  If the accept fails with
        !          2780:         * EAGAIN or EINTR, simply poke the watcher to watch this socket
        !          2781:         * again.  Also ignore ECONNRESET, which has been reported to
        !          2782:         * be spuriously returned on Linux 2.2.19 although it is not
        !          2783:         * a documented error for accept().  ECONNABORTED has been
        !          2784:         * reported for Solaris 8.  The rest are thrown in not because
        !          2785:         * we have seen them but because they are ignored by other
        !          2786:         * daemons such as BIND 8 and Apache.
        !          2787:         */
        !          2788: 
        !          2789:        addrlen = sizeof(dev->newsocket->peer_address.type);
        !          2790:        memset(&dev->newsocket->peer_address.type, 0, addrlen);
        !          2791:        fd = accept(sock->fd, &dev->newsocket->peer_address.type.sa,
        !          2792:                    (void *)&addrlen);
        !          2793: 
        !          2794: #ifdef F_DUPFD
        !          2795:        /*
        !          2796:         * Leave a space for stdio to work in.
        !          2797:         */
        !          2798:        if (fd >= 0 && fd < 20) {
        !          2799:                int new, tmp;
        !          2800:                new = fcntl(fd, F_DUPFD, 20);
        !          2801:                tmp = errno;
        !          2802:                (void)close(fd);
        !          2803:                errno = tmp;
        !          2804:                fd = new;
        !          2805:                err = "accept/fcntl";
        !          2806:        }
        !          2807: #endif
        !          2808: 
        !          2809:        if (fd < 0) {
        !          2810:                if (SOFT_ERROR(errno))
        !          2811:                        goto soft_error;
        !          2812:                switch (errno) {
        !          2813:                case ENFILE:
        !          2814:                case EMFILE:
        !          2815:                        isc_log_iwrite(isc_lctx, ISC_LOGCATEGORY_GENERAL,
        !          2816:                                       ISC_LOGMODULE_SOCKET, ISC_LOG_ERROR,
        !          2817:                                       isc_msgcat, ISC_MSGSET_SOCKET,
        !          2818:                                       ISC_MSG_TOOMANYFDS,
        !          2819:                                       "%s: too many open file descriptors",
        !          2820:                                       err);
        !          2821:                        goto soft_error;
        !          2822: 
        !          2823:                case ENOBUFS:
        !          2824:                case ENOMEM:
        !          2825:                case ECONNRESET:
        !          2826:                case ECONNABORTED:
        !          2827:                case EHOSTUNREACH:
        !          2828:                case EHOSTDOWN:
        !          2829:                case ENETUNREACH:
        !          2830:                case ENETDOWN:
        !          2831:                case ECONNREFUSED:
        !          2832: #ifdef EPROTO
        !          2833:                case EPROTO:
        !          2834: #endif
        !          2835: #ifdef ENONET
        !          2836:                case ENONET:
        !          2837: #endif
        !          2838:                        goto soft_error;
        !          2839:                default:
        !          2840:                        break;
        !          2841:                }
        !          2842:                isc__strerror(errno, strbuf, sizeof(strbuf));
        !          2843:                UNEXPECTED_ERROR(__FILE__, __LINE__,
        !          2844:                                 "internal_accept: %s() %s: %s", err,
        !          2845:                                 isc_msgcat_get(isc_msgcat,
        !          2846:                                                ISC_MSGSET_GENERAL,
        !          2847:                                                ISC_MSG_FAILED,
        !          2848:                                                "failed"),
        !          2849:                                 strbuf);
        !          2850:                fd = -1;
        !          2851:                result = ISC_R_UNEXPECTED;
        !          2852:        } else {
        !          2853:                if (addrlen == 0U) {
        !          2854:                        UNEXPECTED_ERROR(__FILE__, __LINE__,
        !          2855:                                         "internal_accept(): "
        !          2856:                                         "accept() failed to return "
        !          2857:                                         "remote address");
        !          2858: 
        !          2859:                        (void)close(fd);
        !          2860:                        goto soft_error;
        !          2861:                } else if (dev->newsocket->peer_address.type.sa.sa_family !=
        !          2862:                           sock->pf)
        !          2863:                {
        !          2864:                        UNEXPECTED_ERROR(__FILE__, __LINE__,
        !          2865:                                         "internal_accept(): "
        !          2866:                                         "accept() returned peer address "
        !          2867:                                         "family %u (expected %u)",
        !          2868:                                         dev->newsocket->peer_address.
        !          2869:                                         type.sa.sa_family,
        !          2870:                                         sock->pf);
        !          2871:                        (void)close(fd);
        !          2872:                        goto soft_error;
        !          2873:                } else if (fd >= (int)manager->maxsocks) {
        !          2874:                        isc_log_iwrite(isc_lctx, ISC_LOGCATEGORY_GENERAL,
        !          2875:                                       ISC_LOGMODULE_SOCKET, ISC_LOG_ERROR,
        !          2876:                                       isc_msgcat, ISC_MSGSET_SOCKET,
        !          2877:                                       ISC_MSG_TOOMANYFDS,
        !          2878:                                       "accept: "
        !          2879:                                       "file descriptor exceeds limit (%d/%u)",
        !          2880:                                       fd, manager->maxsocks);
        !          2881:                        (void)close(fd);
        !          2882:                        goto soft_error;
        !          2883:                }
        !          2884:        }
        !          2885: 
        !          2886:        if (fd != -1) {
        !          2887:                dev->newsocket->peer_address.length = addrlen;
        !          2888:                dev->newsocket->pf = sock->pf;
        !          2889:        }
        !          2890: 
        !          2891:        /*
        !          2892:         * Pull off the done event.
        !          2893:         */
        !          2894:        ISC_LIST_UNLINK(sock->accept_list, dev, ev_link);
        !          2895: 
        !          2896:        /*
        !          2897:         * Poke watcher if there are more pending accepts.
        !          2898:         */
        !          2899:        if (!ISC_LIST_EMPTY(sock->accept_list))
        !          2900:                select_poke(sock->manager, sock->fd, SELECT_POKE_ACCEPT);
        !          2901: 
        !          2902:        UNLOCK(&sock->lock);
        !          2903: 
        !          2904:        if (fd != -1 && (make_nonblock(fd) != ISC_R_SUCCESS)) {
        !          2905:                (void)close(fd);
        !          2906:                fd = -1;
        !          2907:                result = ISC_R_UNEXPECTED;
        !          2908:        }
        !          2909: 
        !          2910:        /*
        !          2911:         * -1 means the new socket didn't happen.
        !          2912:         */
        !          2913:        if (fd != -1) {
        !          2914:                int lockid = FDLOCK_ID(fd);
        !          2915: 
        !          2916:                LOCK(&manager->fdlock[lockid]);
        !          2917:                manager->fds[fd] = dev->newsocket;
        !          2918:                manager->fdstate[fd] = MANAGED;
        !          2919:                UNLOCK(&manager->fdlock[lockid]);
        !          2920: 
        !          2921:                LOCK(&manager->lock);
        !          2922:                ISC_LIST_APPEND(manager->socklist, dev->newsocket, link);
        !          2923: 
        !          2924:                dev->newsocket->fd = fd;
        !          2925:                dev->newsocket->bound = 1;
        !          2926:                dev->newsocket->connected = 1;
        !          2927: 
        !          2928:                /*
        !          2929:                 * Save away the remote address
        !          2930:                 */
        !          2931:                dev->address = dev->newsocket->peer_address;
        !          2932: 
        !          2933: #ifdef USE_SELECT
        !          2934:                if (manager->maxfd < fd)
        !          2935:                        manager->maxfd = fd;
        !          2936: #endif
        !          2937: 
        !          2938:                socket_log(sock, &dev->newsocket->peer_address, CREATION,
        !          2939:                           isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_ACCEPTEDCXN,
        !          2940:                           "accepted connection, new socket %p",
        !          2941:                           dev->newsocket);
        !          2942: 
        !          2943:                UNLOCK(&manager->lock);
        !          2944: 
        !          2945:                inc_stats(manager->stats, sock->statsindex[STATID_ACCEPT]);
        !          2946:        } else {
        !          2947:                inc_stats(manager->stats, sock->statsindex[STATID_ACCEPTFAIL]);
        !          2948:                dev->newsocket->references--;
        !          2949:                free_socket(&dev->newsocket);
        !          2950:        }
        !          2951: 
        !          2952:        /*
        !          2953:         * Fill in the done event details and send it off.
        !          2954:         */
        !          2955:        dev->result = result;
        !          2956:        task = dev->ev_sender;
        !          2957:        dev->ev_sender = sock;
        !          2958: 
        !          2959:        isc_task_sendanddetach(&task, ISC_EVENT_PTR(&dev));
        !          2960:        return;
        !          2961: 
        !          2962:  soft_error:
        !          2963:        select_poke(sock->manager, sock->fd, SELECT_POKE_ACCEPT);
        !          2964:        UNLOCK(&sock->lock);
        !          2965: 
        !          2966:        inc_stats(manager->stats, sock->statsindex[STATID_ACCEPTFAIL]);
        !          2967:        return;
        !          2968: }
        !          2969: 
        !          2970: static void
        !          2971: internal_recv(isc_task_t *me, isc_event_t *ev) {
        !          2972:        isc_socketevent_t *dev;
        !          2973:        isc_socket_t *sock;
        !          2974: 
        !          2975:        INSIST(ev->ev_type == ISC_SOCKEVENT_INTR);
        !          2976: 
        !          2977:        sock = ev->ev_sender;
        !          2978:        INSIST(VALID_SOCKET(sock));
        !          2979: 
        !          2980:        LOCK(&sock->lock);
        !          2981:        socket_log(sock, NULL, IOEVENT,
        !          2982:                   isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_INTERNALRECV,
        !          2983:                   "internal_recv: task %p got event %p", me, ev);
        !          2984: 
        !          2985:        INSIST(sock->pending_recv == 1);
        !          2986:        sock->pending_recv = 0;
        !          2987: 
        !          2988:        INSIST(sock->references > 0);
        !          2989:        sock->references--;  /* the internal event is done with this socket */
        !          2990:        if (sock->references == 0) {
        !          2991:                UNLOCK(&sock->lock);
        !          2992:                destroy(&sock);
        !          2993:                return;
        !          2994:        }
        !          2995: 
        !          2996:        /*
        !          2997:         * Try to do as much I/O as possible on this socket.  There are no
        !          2998:         * limits here, currently.
        !          2999:         */
        !          3000:        dev = ISC_LIST_HEAD(sock->recv_list);
        !          3001:        while (dev != NULL) {
        !          3002:                switch (doio_recv(sock, dev)) {
        !          3003:                case DOIO_SOFT:
        !          3004:                        goto poke;
        !          3005: 
        !          3006:                case DOIO_EOF:
        !          3007:                        /*
        !          3008:                         * read of 0 means the remote end was closed.
        !          3009:                         * Run through the event queue and dispatch all
        !          3010:                         * the events with an EOF result code.
        !          3011:                         */
        !          3012:                        do {
        !          3013:                                dev->result = ISC_R_EOF;
        !          3014:                                send_recvdone_event(sock, &dev);
        !          3015:                                dev = ISC_LIST_HEAD(sock->recv_list);
        !          3016:                        } while (dev != NULL);
        !          3017:                        goto poke;
        !          3018: 
        !          3019:                case DOIO_SUCCESS:
        !          3020:                case DOIO_HARD:
        !          3021:                        send_recvdone_event(sock, &dev);
        !          3022:                        break;
        !          3023:                }
        !          3024: 
        !          3025:                dev = ISC_LIST_HEAD(sock->recv_list);
        !          3026:        }
        !          3027: 
        !          3028:  poke:
        !          3029:        if (!ISC_LIST_EMPTY(sock->recv_list))
        !          3030:                select_poke(sock->manager, sock->fd, SELECT_POKE_READ);
        !          3031: 
        !          3032:        UNLOCK(&sock->lock);
        !          3033: }
        !          3034: 
        !          3035: static void
        !          3036: internal_send(isc_task_t *me, isc_event_t *ev) {
        !          3037:        isc_socketevent_t *dev;
        !          3038:        isc_socket_t *sock;
        !          3039: 
        !          3040:        INSIST(ev->ev_type == ISC_SOCKEVENT_INTW);
        !          3041: 
        !          3042:        /*
        !          3043:         * Find out what socket this is and lock it.
        !          3044:         */
        !          3045:        sock = (isc_socket_t *)ev->ev_sender;
        !          3046:        INSIST(VALID_SOCKET(sock));
        !          3047: 
        !          3048:        LOCK(&sock->lock);
        !          3049:        socket_log(sock, NULL, IOEVENT,
        !          3050:                   isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_INTERNALSEND,
        !          3051:                   "internal_send: task %p got event %p", me, ev);
        !          3052: 
        !          3053:        INSIST(sock->pending_send == 1);
        !          3054:        sock->pending_send = 0;
        !          3055: 
        !          3056:        INSIST(sock->references > 0);
        !          3057:        sock->references--;  /* the internal event is done with this socket */
        !          3058:        if (sock->references == 0) {
        !          3059:                UNLOCK(&sock->lock);
        !          3060:                destroy(&sock);
        !          3061:                return;
        !          3062:        }
        !          3063: 
        !          3064:        /*
        !          3065:         * Try to do as much I/O as possible on this socket.  There are no
        !          3066:         * limits here, currently.
        !          3067:         */
        !          3068:        dev = ISC_LIST_HEAD(sock->send_list);
        !          3069:        while (dev != NULL) {
        !          3070:                switch (doio_send(sock, dev)) {
        !          3071:                case DOIO_SOFT:
        !          3072:                        goto poke;
        !          3073: 
        !          3074:                case DOIO_HARD:
        !          3075:                case DOIO_SUCCESS:
        !          3076:                        send_senddone_event(sock, &dev);
        !          3077:                        break;
        !          3078:                }
        !          3079: 
        !          3080:                dev = ISC_LIST_HEAD(sock->send_list);
        !          3081:        }
        !          3082: 
        !          3083:  poke:
        !          3084:        if (!ISC_LIST_EMPTY(sock->send_list))
        !          3085:                select_poke(sock->manager, sock->fd, SELECT_POKE_WRITE);
        !          3086: 
        !          3087:        UNLOCK(&sock->lock);
        !          3088: }
        !          3089: 
        !          3090: static void
        !          3091: internal_fdwatch_write(isc_task_t *me, isc_event_t *ev) {
        !          3092:        isc_socket_t *sock;
        !          3093:        int more_data;
        !          3094: 
        !          3095:        INSIST(ev->ev_type == ISC_SOCKEVENT_INTW);
        !          3096: 
        !          3097:        /*
        !          3098:         * Find out what socket this is and lock it.
        !          3099:         */
        !          3100:        sock = (isc_socket_t *)ev->ev_sender;
        !          3101:        INSIST(VALID_SOCKET(sock));
        !          3102: 
        !          3103:        LOCK(&sock->lock);
        !          3104:        socket_log(sock, NULL, IOEVENT,
        !          3105:                   isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_INTERNALSEND,
        !          3106:                   "internal_fdwatch_write: task %p got event %p", me, ev);
        !          3107: 
        !          3108:        INSIST(sock->pending_send == 1);
        !          3109: 
        !          3110:        UNLOCK(&sock->lock);
        !          3111:        more_data = (sock->fdwatchcb)(me, sock, sock->fdwatcharg);
        !          3112:        LOCK(&sock->lock);
        !          3113: 
        !          3114:        sock->pending_send = 0;
        !          3115: 
        !          3116:        INSIST(sock->references > 0);
        !          3117:        sock->references--;  /* the internal event is done with this socket */
        !          3118:        if (sock->references == 0) {
        !          3119:                UNLOCK(&sock->lock);
        !          3120:                destroy(&sock);
        !          3121:                return;
        !          3122:        }
        !          3123: 
        !          3124:        if (more_data)
        !          3125:                select_poke(sock->manager, sock->fd, SELECT_POKE_WRITE);
        !          3126: 
        !          3127:        UNLOCK(&sock->lock);
        !          3128: }
        !          3129: 
        !          3130: static void
        !          3131: internal_fdwatch_read(isc_task_t *me, isc_event_t *ev) {
        !          3132:        isc_socket_t *sock;
        !          3133:        int more_data;
        !          3134: 
        !          3135:        INSIST(ev->ev_type == ISC_SOCKEVENT_INTR);
        !          3136: 
        !          3137:        /*
        !          3138:         * Find out what socket this is and lock it.
        !          3139:         */
        !          3140:        sock = (isc_socket_t *)ev->ev_sender;
        !          3141:        INSIST(VALID_SOCKET(sock));
        !          3142: 
        !          3143:        LOCK(&sock->lock);
        !          3144:        socket_log(sock, NULL, IOEVENT,
        !          3145:                   isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_INTERNALRECV,
        !          3146:                   "internal_fdwatch_read: task %p got event %p", me, ev);
        !          3147: 
        !          3148:        INSIST(sock->pending_recv == 1);
        !          3149: 
        !          3150:        UNLOCK(&sock->lock);
        !          3151:        more_data = (sock->fdwatchcb)(me, sock, sock->fdwatcharg);
        !          3152:        LOCK(&sock->lock);
        !          3153: 
        !          3154:        sock->pending_recv = 0;
        !          3155: 
        !          3156:        INSIST(sock->references > 0);
        !          3157:        sock->references--;  /* the internal event is done with this socket */
        !          3158:        if (sock->references == 0) {
        !          3159:                UNLOCK(&sock->lock);
        !          3160:                destroy(&sock);
        !          3161:                return;
        !          3162:        }
        !          3163: 
        !          3164:        if (more_data)
        !          3165:                select_poke(sock->manager, sock->fd, SELECT_POKE_READ);
        !          3166: 
        !          3167:        UNLOCK(&sock->lock);
        !          3168: }
        !          3169: 
        !          3170: /*
        !          3171:  * Process read/writes on each fd here.  Avoid locking
        !          3172:  * and unlocking twice if both reads and writes are possible.
        !          3173:  */
        !          3174: static void
        !          3175: process_fd(isc_socketmgr_t *manager, int fd, isc_boolean_t readable,
        !          3176:           isc_boolean_t writeable)
        !          3177: {
        !          3178:        isc_socket_t *sock;
        !          3179:        isc_boolean_t unlock_sock;
        !          3180:        isc_boolean_t unwatch_read = ISC_FALSE, unwatch_write = ISC_FALSE;
        !          3181:        int lockid = FDLOCK_ID(fd);
        !          3182: 
        !          3183:        /*
        !          3184:         * If the socket is going to be closed, don't do more I/O.
        !          3185:         */
        !          3186:        LOCK(&manager->fdlock[lockid]);
        !          3187:        if (manager->fdstate[fd] == CLOSE_PENDING) {
        !          3188:                UNLOCK(&manager->fdlock[lockid]);
        !          3189: 
        !          3190:                (void)unwatch_fd(manager, fd, SELECT_POKE_READ);
        !          3191:                (void)unwatch_fd(manager, fd, SELECT_POKE_WRITE);
        !          3192:                return;
        !          3193:        }
        !          3194: 
        !          3195:        sock = manager->fds[fd];
        !          3196:        unlock_sock = ISC_FALSE;
        !          3197:        if (readable) {
        !          3198:                if (sock == NULL) {
        !          3199:                        unwatch_read = ISC_TRUE;
        !          3200:                        goto check_write;
        !          3201:                }
        !          3202:                unlock_sock = ISC_TRUE;
        !          3203:                LOCK(&sock->lock);
        !          3204:                if (!SOCK_DEAD(sock)) {
        !          3205:                        if (sock->listener)
        !          3206:                                dispatch_accept(sock);
        !          3207:                        else
        !          3208:                                dispatch_recv(sock);
        !          3209:                }
        !          3210:                unwatch_read = ISC_TRUE;
        !          3211:        }
        !          3212: check_write:
        !          3213:        if (writeable) {
        !          3214:                if (sock == NULL) {
        !          3215:                        unwatch_write = ISC_TRUE;
        !          3216:                        goto unlock_fd;
        !          3217:                }
        !          3218:                if (!unlock_sock) {
        !          3219:                        unlock_sock = ISC_TRUE;
        !          3220:                        LOCK(&sock->lock);
        !          3221:                }
        !          3222:                if (!SOCK_DEAD(sock)) {
        !          3223:                        if (sock->connecting)
        !          3224:                                dispatch_connect(sock);
        !          3225:                        else
        !          3226:                                dispatch_send(sock);
        !          3227:                }
        !          3228:                unwatch_write = ISC_TRUE;
        !          3229:        }
        !          3230:        if (unlock_sock)
        !          3231:                UNLOCK(&sock->lock);
        !          3232: 
        !          3233:  unlock_fd:
        !          3234:        UNLOCK(&manager->fdlock[lockid]);
        !          3235:        if (unwatch_read)
        !          3236:                (void)unwatch_fd(manager, fd, SELECT_POKE_READ);
        !          3237:        if (unwatch_write)
        !          3238:                (void)unwatch_fd(manager, fd, SELECT_POKE_WRITE);
        !          3239: 
        !          3240: }
        !          3241: 
        !          3242: #ifdef USE_KQUEUE
        !          3243: static isc_boolean_t
        !          3244: process_fds(isc_socketmgr_t *manager, struct kevent *events, int nevents) {
        !          3245:        int i;
        !          3246:        isc_boolean_t readable, writable;
        !          3247:        isc_boolean_t done = ISC_FALSE;
        !          3248: #ifdef ISC_PLATFORM_USETHREADS
        !          3249:        isc_boolean_t have_ctlevent = ISC_FALSE;
        !          3250: #endif
        !          3251: 
        !          3252:        if (nevents == manager->nevents) {
        !          3253:                /*
        !          3254:                 * This is not an error, but something unexpected.  If this
        !          3255:                 * happens, it may indicate the need for increasing
        !          3256:                 * ISC_SOCKET_MAXEVENTS.
        !          3257:                 */
        !          3258:                manager_log(manager, ISC_LOGCATEGORY_GENERAL,
        !          3259:                            ISC_LOGMODULE_SOCKET, ISC_LOG_INFO,
        !          3260:                            "maximum number of FD events (%d) received",
        !          3261:                            nevents);
        !          3262:        }
        !          3263: 
        !          3264:        for (i = 0; i < nevents; i++) {
        !          3265:                REQUIRE(events[i].ident < manager->maxsocks);
        !          3266: #ifdef ISC_PLATFORM_USETHREADS
        !          3267:                if (events[i].ident == (uintptr_t)manager->pipe_fds[0]) {
        !          3268:                        have_ctlevent = ISC_TRUE;
        !          3269:                        continue;
        !          3270:                }
        !          3271: #endif
        !          3272:                readable = ISC_TF(events[i].filter == EVFILT_READ);
        !          3273:                writable = ISC_TF(events[i].filter == EVFILT_WRITE);
        !          3274:                process_fd(manager, events[i].ident, readable, writable);
        !          3275:        }
        !          3276: 
        !          3277: #ifdef ISC_PLATFORM_USETHREADS
        !          3278:        if (have_ctlevent)
        !          3279:                done = process_ctlfd(manager);
        !          3280: #endif
        !          3281: 
        !          3282:        return (done);
        !          3283: }
        !          3284: #elif defined(USE_EPOLL)
        !          3285: static isc_boolean_t
        !          3286: process_fds(isc_socketmgr_t *manager, struct epoll_event *events, int nevents) {
        !          3287:        int i;
        !          3288:        isc_boolean_t done = ISC_FALSE;
        !          3289: #ifdef ISC_PLATFORM_USETHREADS
        !          3290:        isc_boolean_t have_ctlevent = ISC_FALSE;
        !          3291: #endif
        !          3292: 
        !          3293:        if (nevents == manager->nevents) {
        !          3294:                manager_log(manager, ISC_LOGCATEGORY_GENERAL,
        !          3295:                            ISC_LOGMODULE_SOCKET, ISC_LOG_INFO,
        !          3296:                            "maximum number of FD events (%d) received",
        !          3297:                            nevents);
        !          3298:        }
        !          3299: 
        !          3300:        for (i = 0; i < nevents; i++) {
        !          3301:                REQUIRE(events[i].data.fd < (int)manager->maxsocks);
        !          3302: #ifdef ISC_PLATFORM_USETHREADS
        !          3303:                if (events[i].data.fd == manager->pipe_fds[0]) {
        !          3304:                        have_ctlevent = ISC_TRUE;
        !          3305:                        continue;
        !          3306:                }
        !          3307: #endif
        !          3308:                if ((events[i].events & EPOLLERR) != 0 ||
        !          3309:                    (events[i].events & EPOLLHUP) != 0) {
        !          3310:                        /*
        !          3311:                         * epoll does not set IN/OUT bits on an erroneous
        !          3312:                         * condition, so we need to try both anyway.  This is a
        !          3313:                         * bit inefficient, but should be okay for such rare
        !          3314:                         * events.  Note also that the read or write attempt
        !          3315:                         * won't block because we use non-blocking sockets.
        !          3316:                         */
        !          3317:                        events[i].events |= (EPOLLIN | EPOLLOUT);
        !          3318:                }
        !          3319:                process_fd(manager, events[i].data.fd,
        !          3320:                           (events[i].events & EPOLLIN) != 0,
        !          3321:                           (events[i].events & EPOLLOUT) != 0);
        !          3322:        }
        !          3323: 
        !          3324: #ifdef ISC_PLATFORM_USETHREADS
        !          3325:        if (have_ctlevent)
        !          3326:                done = process_ctlfd(manager);
        !          3327: #endif
        !          3328: 
        !          3329:        return (done);
        !          3330: }
        !          3331: #elif defined(USE_DEVPOLL)
        !          3332: static isc_boolean_t
        !          3333: process_fds(isc_socketmgr_t *manager, struct pollfd *events, int nevents) {
        !          3334:        int i;
        !          3335:        isc_boolean_t done = ISC_FALSE;
        !          3336: #ifdef ISC_PLATFORM_USETHREADS
        !          3337:        isc_boolean_t have_ctlevent = ISC_FALSE;
        !          3338: #endif
        !          3339: 
        !          3340:        if (nevents == manager->nevents) {
        !          3341:                manager_log(manager, ISC_LOGCATEGORY_GENERAL,
        !          3342:                            ISC_LOGMODULE_SOCKET, ISC_LOG_INFO,
        !          3343:                            "maximum number of FD events (%d) received",
        !          3344:                            nevents);
        !          3345:        }
        !          3346: 
        !          3347:        for (i = 0; i < nevents; i++) {
        !          3348:                REQUIRE(events[i].fd < (int)manager->maxsocks);
        !          3349: #ifdef ISC_PLATFORM_USETHREADS
        !          3350:                if (events[i].fd == manager->pipe_fds[0]) {
        !          3351:                        have_ctlevent = ISC_TRUE;
        !          3352:                        continue;
        !          3353:                }
        !          3354: #endif
        !          3355:                process_fd(manager, events[i].fd,
        !          3356:                           (events[i].events & POLLIN) != 0,
        !          3357:                           (events[i].events & POLLOUT) != 0);
        !          3358:        }
        !          3359: 
        !          3360: #ifdef ISC_PLATFORM_USETHREADS
        !          3361:        if (have_ctlevent)
        !          3362:                done = process_ctlfd(manager);
        !          3363: #endif
        !          3364: 
        !          3365:        return (done);
        !          3366: }
        !          3367: #elif defined(USE_SELECT)
        !          3368: static void
        !          3369: process_fds(isc_socketmgr_t *manager, int maxfd,
        !          3370:            fd_set *readfds, fd_set *writefds)
        !          3371: {
        !          3372:        int i;
        !          3373: 
        !          3374:        REQUIRE(maxfd <= (int)manager->maxsocks);
        !          3375: 
        !          3376:        for (i = 0; i < maxfd; i++) {
        !          3377: #ifdef ISC_PLATFORM_USETHREADS
        !          3378:                if (i == manager->pipe_fds[0] || i == manager->pipe_fds[1])
        !          3379:                        continue;
        !          3380: #endif /* ISC_PLATFORM_USETHREADS */
        !          3381:                process_fd(manager, i, FD_ISSET(i, readfds),
        !          3382:                           FD_ISSET(i, writefds));
        !          3383:        }
        !          3384: }
        !          3385: #endif
        !          3386: 
        !          3387: #ifdef ISC_PLATFORM_USETHREADS
        !          3388: static isc_boolean_t
        !          3389: process_ctlfd(isc_socketmgr_t *manager) {
        !          3390:        int msg, fd;
        !          3391: 
        !          3392:        for (;;) {
        !          3393:                select_readmsg(manager, &fd, &msg);
        !          3394: 
        !          3395:                manager_log(manager, IOEVENT,
        !          3396:                            isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKET,
        !          3397:                                           ISC_MSG_WATCHERMSG,
        !          3398:                                           "watcher got message %d "
        !          3399:                                           "for socket %d"), msg, fd);
        !          3400: 
        !          3401:                /*
        !          3402:                 * Nothing to read?
        !          3403:                 */
        !          3404:                if (msg == SELECT_POKE_NOTHING)
        !          3405:                        break;
        !          3406: 
        !          3407:                /*
        !          3408:                 * Handle shutdown message.  We really should
        !          3409:                 * jump out of this loop right away, but
        !          3410:                 * it doesn't matter if we have to do a little
        !          3411:                 * more work first.
        !          3412:                 */
        !          3413:                if (msg == SELECT_POKE_SHUTDOWN)
        !          3414:                        return (ISC_TRUE);
        !          3415: 
        !          3416:                /*
        !          3417:                 * This is a wakeup on a socket.  Look
        !          3418:                 * at the event queue for both read and write,
        !          3419:                 * and decide if we need to watch on it now
        !          3420:                 * or not.
        !          3421:                 */
        !          3422:                wakeup_socket(manager, fd, msg);
        !          3423:        }
        !          3424: 
        !          3425:        return (ISC_FALSE);
        !          3426: }
        !          3427: 
        !          3428: /*
        !          3429:  * This is the thread that will loop forever, always in a select or poll
        !          3430:  * call.
        !          3431:  *
        !          3432:  * When select returns something to do, track down what thread gets to do
        !          3433:  * this I/O and post the event to it.
        !          3434:  */
        !          3435: static isc_threadresult_t
        !          3436: watcher(void *uap) {
        !          3437:        isc_socketmgr_t *manager = uap;
        !          3438:        isc_boolean_t done;
        !          3439:        int ctlfd;
        !          3440:        int cc;
        !          3441: #ifdef USE_KQUEUE
        !          3442:        const char *fnname = "kevent()";
        !          3443: #elif defined (USE_EPOLL)
        !          3444:        const char *fnname = "epoll_wait()";
        !          3445: #elif defined(USE_DEVPOLL)
        !          3446:        const char *fnname = "ioctl(DP_POLL)";
        !          3447:        struct dvpoll dvp;
        !          3448: #elif defined (USE_SELECT)
        !          3449:        const char *fnname = "select()";
        !          3450:        int maxfd;
        !          3451: #endif
        !          3452:        char strbuf[ISC_STRERRORSIZE];
        !          3453: #ifdef ISC_SOCKET_USE_POLLWATCH
        !          3454:        pollstate_t pollstate = poll_idle;
        !          3455: #endif
        !          3456: 
        !          3457:        /*
        !          3458:         * Get the control fd here.  This will never change.
        !          3459:         */
        !          3460:        ctlfd = manager->pipe_fds[0];
        !          3461:        done = ISC_FALSE;
        !          3462:        while (!done) {
        !          3463:                do {
        !          3464: #ifdef USE_KQUEUE
        !          3465:                        cc = kevent(manager->kqueue_fd, NULL, 0,
        !          3466:                                    manager->events, manager->nevents, NULL);
        !          3467: #elif defined(USE_EPOLL)
        !          3468:                        cc = epoll_wait(manager->epoll_fd, manager->events,
        !          3469:                                        manager->nevents, -1);
        !          3470: #elif defined(USE_DEVPOLL)
        !          3471:                        dvp.dp_fds = manager->events;
        !          3472:                        dvp.dp_nfds = manager->nevents;
        !          3473: #ifndef ISC_SOCKET_USE_POLLWATCH
        !          3474:                        dvp.dp_timeout = -1;
        !          3475: #else
        !          3476:                        if (pollstate == poll_idle)
        !          3477:                                dvp.dp_timeout = -1;
        !          3478:                        else
        !          3479:                                dvp.dp_timeout = ISC_SOCKET_POLLWATCH_TIMEOUT;
        !          3480: #endif /* ISC_SOCKET_USE_POLLWATCH */
        !          3481:                        cc = ioctl(manager->devpoll_fd, DP_POLL, &dvp);
        !          3482: #elif defined(USE_SELECT)
        !          3483:                        LOCK(&manager->lock);
        !          3484:                        memcpy(manager->read_fds_copy, manager->read_fds,
        !          3485:                               manager->fd_bufsize);
        !          3486:                        memcpy(manager->write_fds_copy, manager->write_fds,
        !          3487:                               manager->fd_bufsize);
        !          3488:                        maxfd = manager->maxfd + 1;
        !          3489:                        UNLOCK(&manager->lock);
        !          3490: 
        !          3491:                        cc = select(maxfd, manager->read_fds_copy,
        !          3492:                                    manager->write_fds_copy, NULL, NULL);
        !          3493: #endif /* USE_KQUEUE */
        !          3494: 
        !          3495:                        if (cc < 0 && !SOFT_ERROR(errno)) {
        !          3496:                                isc__strerror(errno, strbuf, sizeof(strbuf));
        !          3497:                                FATAL_ERROR(__FILE__, __LINE__,
        !          3498:                                            "%s %s: %s", fnname,
        !          3499:                                            isc_msgcat_get(isc_msgcat,
        !          3500:                                                           ISC_MSGSET_GENERAL,
        !          3501:                                                           ISC_MSG_FAILED,
        !          3502:                                                           "failed"), strbuf);
        !          3503:                        }
        !          3504: 
        !          3505: #if defined(USE_DEVPOLL) && defined(ISC_SOCKET_USE_POLLWATCH)
        !          3506:                        if (cc == 0) {
        !          3507:                                if (pollstate == poll_active)
        !          3508:                                        pollstate = poll_checking;
        !          3509:                                else if (pollstate == poll_checking)
        !          3510:                                        pollstate = poll_idle;
        !          3511:                        } else if (cc > 0) {
        !          3512:                                if (pollstate == poll_checking) {
        !          3513:                                        /*
        !          3514:                                         * XXX: We'd like to use a more
        !          3515:                                         * verbose log level as it's actually an
        !          3516:                                         * unexpected event, but the kernel bug
        !          3517:                                         * reportedly happens pretty frequently
        !          3518:                                         * (and it can also be a false positive)
        !          3519:                                         * so it would be just too noisy.
        !          3520:                                         */
        !          3521:                                        manager_log(manager,
        !          3522:                                                    ISC_LOGCATEGORY_GENERAL,
        !          3523:                                                    ISC_LOGMODULE_SOCKET,
        !          3524:                                                    ISC_LOG_DEBUG(1),
        !          3525:                                                    "unexpected POLL timeout");
        !          3526:                                }
        !          3527:                                pollstate = poll_active;
        !          3528:                        }
        !          3529: #endif
        !          3530:                } while (cc < 0);
        !          3531: 
        !          3532: #if defined(USE_KQUEUE) || defined (USE_EPOLL) || defined (USE_DEVPOLL)
        !          3533:                done = process_fds(manager, manager->events, cc);
        !          3534: #elif defined(USE_SELECT)
        !          3535:                process_fds(manager, maxfd, manager->read_fds_copy,
        !          3536:                            manager->write_fds_copy);
        !          3537: 
        !          3538:                /*
        !          3539:                 * Process reads on internal, control fd.
        !          3540:                 */
        !          3541:                if (FD_ISSET(ctlfd, manager->read_fds_copy))
        !          3542:                        done = process_ctlfd(manager);
        !          3543: #endif
        !          3544:        }
        !          3545: 
        !          3546:        manager_log(manager, TRACE, "%s",
        !          3547:                    isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
        !          3548:                                   ISC_MSG_EXITING, "watcher exiting"));
        !          3549: 
        !          3550:        return ((isc_threadresult_t)0);
        !          3551: }
        !          3552: #endif /* ISC_PLATFORM_USETHREADS */
        !          3553: 
        !          3554: void
        !          3555: isc__socketmgr_setreserved(isc_socketmgr_t *manager, isc_uint32_t reserved) {
        !          3556: 
        !          3557:        REQUIRE(VALID_MANAGER(manager));
        !          3558: 
        !          3559:        manager->reserved = reserved;
        !          3560: }
        !          3561: 
        !          3562: /*
        !          3563:  * Create a new socket manager.
        !          3564:  */
        !          3565: 
        !          3566: static isc_result_t
        !          3567: setup_watcher(isc_mem_t *mctx, isc_socketmgr_t *manager) {
        !          3568:        isc_result_t result;
        !          3569: #if defined(USE_KQUEUE) || defined(USE_EPOLL) || defined(USE_DEVPOLL)
        !          3570:        char strbuf[ISC_STRERRORSIZE];
        !          3571: #endif
        !          3572: 
        !          3573: #ifdef USE_KQUEUE
        !          3574:        manager->nevents = ISC_SOCKET_MAXEVENTS;
        !          3575:        manager->events = isc_mem_get(mctx, sizeof(struct kevent) *
        !          3576:                                      manager->nevents);
        !          3577:        if (manager->events == NULL)
        !          3578:                return (ISC_R_NOMEMORY);
        !          3579:        manager->kqueue_fd = kqueue();
        !          3580:        if (manager->kqueue_fd == -1) {
        !          3581:                result = isc__errno2result(errno);
        !          3582:                isc__strerror(errno, strbuf, sizeof(strbuf));
        !          3583:                UNEXPECTED_ERROR(__FILE__, __LINE__,
        !          3584:                                 "kqueue %s: %s",
        !          3585:                                 isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
        !          3586:                                                ISC_MSG_FAILED, "failed"),
        !          3587:                                 strbuf);
        !          3588:                isc_mem_put(mctx, manager->events,
        !          3589:                            sizeof(struct kevent) * manager->nevents);
        !          3590:                return (result);
        !          3591:        }
        !          3592: 
        !          3593: #ifdef ISC_PLATFORM_USETHREADS
        !          3594:        result = watch_fd(manager, manager->pipe_fds[0], SELECT_POKE_READ);
        !          3595:        if (result != ISC_R_SUCCESS) {
        !          3596:                close(manager->kqueue_fd);
        !          3597:                isc_mem_put(mctx, manager->events,
        !          3598:                            sizeof(struct kevent) * manager->nevents);
        !          3599:                return (result);
        !          3600:        }
        !          3601: #endif /* ISC_PLATFORM_USETHREADS */
        !          3602: #elif defined(USE_EPOLL)
        !          3603:        manager->nevents = ISC_SOCKET_MAXEVENTS;
        !          3604:        manager->events = isc_mem_get(mctx, sizeof(struct epoll_event) *
        !          3605:                                      manager->nevents);
        !          3606:        if (manager->events == NULL)
        !          3607:                return (ISC_R_NOMEMORY);
        !          3608:        manager->epoll_fd = epoll_create(manager->nevents);
        !          3609:        if (manager->epoll_fd == -1) {
        !          3610:                result = isc__errno2result(errno);
        !          3611:                isc__strerror(errno, strbuf, sizeof(strbuf));
        !          3612:                UNEXPECTED_ERROR(__FILE__, __LINE__,
        !          3613:                                 "epoll_create %s: %s",
        !          3614:                                 isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
        !          3615:                                                ISC_MSG_FAILED, "failed"),
        !          3616:                                 strbuf);
        !          3617:                isc_mem_put(mctx, manager->events,
        !          3618:                            sizeof(struct epoll_event) * manager->nevents);
        !          3619:                return (result);
        !          3620:        }
        !          3621: #ifdef ISC_PLATFORM_USETHREADS
        !          3622:        result = watch_fd(manager, manager->pipe_fds[0], SELECT_POKE_READ);
        !          3623:        if (result != ISC_R_SUCCESS) {
        !          3624:                close(manager->epoll_fd);
        !          3625:                isc_mem_put(mctx, manager->events,
        !          3626:                            sizeof(struct epoll_event) * manager->nevents);
        !          3627:                return (result);
        !          3628:        }
        !          3629: #endif /* ISC_PLATFORM_USETHREADS */
        !          3630: #elif defined(USE_DEVPOLL)
        !          3631:        /*
        !          3632:         * XXXJT: /dev/poll seems to reject large numbers of events,
        !          3633:         * so we should be careful about redefining ISC_SOCKET_MAXEVENTS.
        !          3634:         */
        !          3635:        manager->nevents = ISC_SOCKET_MAXEVENTS;
        !          3636:        manager->events = isc_mem_get(mctx, sizeof(struct pollfd) *
        !          3637:                                      manager->nevents);
        !          3638:        if (manager->events == NULL)
        !          3639:                return (ISC_R_NOMEMORY);
        !          3640:        /*
        !          3641:         * Note: fdpollinfo should be able to support all possible FDs, so
        !          3642:         * it must have maxsocks entries (not nevents).
        !          3643:         */
        !          3644:        manager->fdpollinfo = isc_mem_get(mctx, sizeof(pollinfo_t) *
        !          3645:                                          manager->maxsocks);
        !          3646:        if (manager->fdpollinfo == NULL) {
        !          3647:                isc_mem_put(mctx, manager->events,
        !          3648:                            sizeof(pollinfo_t) * manager->maxsocks);
        !          3649:                return (ISC_R_NOMEMORY);
        !          3650:        }
        !          3651:        memset(manager->fdpollinfo, 0, sizeof(pollinfo_t) * manager->maxsocks);
        !          3652:        manager->devpoll_fd = open("/dev/poll", O_RDWR);
        !          3653:        if (manager->devpoll_fd == -1) {
        !          3654:                result = isc__errno2result(errno);
        !          3655:                isc__strerror(errno, strbuf, sizeof(strbuf));
        !          3656:                UNEXPECTED_ERROR(__FILE__, __LINE__,
        !          3657:                                 "open(/dev/poll) %s: %s",
        !          3658:                                 isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
        !          3659:                                                ISC_MSG_FAILED, "failed"),
        !          3660:                                 strbuf);
        !          3661:                isc_mem_put(mctx, manager->events,
        !          3662:                            sizeof(struct pollfd) * manager->nevents);
        !          3663:                isc_mem_put(mctx, manager->fdpollinfo,
        !          3664:                            sizeof(pollinfo_t) * manager->maxsocks);
        !          3665:                return (result);
        !          3666:        }
        !          3667: #ifdef ISC_PLATFORM_USETHREADS
        !          3668:        result = watch_fd(manager, manager->pipe_fds[0], SELECT_POKE_READ);
        !          3669:        if (result != ISC_R_SUCCESS) {
        !          3670:                close(manager->devpoll_fd);
        !          3671:                isc_mem_put(mctx, manager->events,
        !          3672:                            sizeof(struct pollfd) * manager->nevents);
        !          3673:                isc_mem_put(mctx, manager->fdpollinfo,
        !          3674:                            sizeof(pollinfo_t) * manager->maxsocks);
        !          3675:                return (result);
        !          3676:        }
        !          3677: #endif /* ISC_PLATFORM_USETHREADS */
        !          3678: #elif defined(USE_SELECT)
        !          3679:        UNUSED(result);
        !          3680: 
        !          3681: #if ISC_SOCKET_MAXSOCKETS > FD_SETSIZE
        !          3682:        /*
        !          3683:         * Note: this code should also cover the case of MAXSOCKETS <=
        !          3684:         * FD_SETSIZE, but we separate the cases to avoid possible portability
        !          3685:         * issues regarding howmany() and the actual representation of fd_set.
        !          3686:         */
        !          3687:        manager->fd_bufsize = howmany(manager->maxsocks, NFDBITS) *
        !          3688:                sizeof(fd_mask);
        !          3689: #else
        !          3690:        manager->fd_bufsize = sizeof(fd_set);
        !          3691: #endif
        !          3692: 
        !          3693:        manager->read_fds = NULL;
        !          3694:        manager->read_fds_copy = NULL;
        !          3695:        manager->write_fds = NULL;
        !          3696:        manager->write_fds_copy = NULL;
        !          3697: 
        !          3698:        manager->read_fds = isc_mem_get(mctx, manager->fd_bufsize);
        !          3699:        if (manager->read_fds != NULL)
        !          3700:                manager->read_fds_copy = isc_mem_get(mctx, manager->fd_bufsize);
        !          3701:        if (manager->read_fds_copy != NULL)
        !          3702:                manager->write_fds = isc_mem_get(mctx, manager->fd_bufsize);
        !          3703:        if (manager->write_fds != NULL) {
        !          3704:                manager->write_fds_copy = isc_mem_get(mctx,
        !          3705:                                                      manager->fd_bufsize);
        !          3706:        }
        !          3707:        if (manager->write_fds_copy == NULL) {
        !          3708:                if (manager->write_fds != NULL) {
        !          3709:                        isc_mem_put(mctx, manager->write_fds,
        !          3710:                                    manager->fd_bufsize);
        !          3711:                }
        !          3712:                if (manager->read_fds_copy != NULL) {
        !          3713:                        isc_mem_put(mctx, manager->read_fds_copy,
        !          3714:                                    manager->fd_bufsize);
        !          3715:                }
        !          3716:                if (manager->read_fds != NULL) {
        !          3717:                        isc_mem_put(mctx, manager->read_fds,
        !          3718:                                    manager->fd_bufsize);
        !          3719:                }
        !          3720:                return (ISC_R_NOMEMORY);
        !          3721:        }
        !          3722:        memset(manager->read_fds, 0, manager->fd_bufsize);
        !          3723:        memset(manager->write_fds, 0, manager->fd_bufsize);
        !          3724: 
        !          3725: #ifdef ISC_PLATFORM_USETHREADS
        !          3726:        (void)watch_fd(manager, manager->pipe_fds[0], SELECT_POKE_READ);
        !          3727:        manager->maxfd = manager->pipe_fds[0];
        !          3728: #else /* ISC_PLATFORM_USETHREADS */
        !          3729:        manager->maxfd = 0;
        !          3730: #endif /* ISC_PLATFORM_USETHREADS */
        !          3731: #endif /* USE_KQUEUE */
        !          3732: 
        !          3733:        return (ISC_R_SUCCESS);
        !          3734: }
        !          3735: 
        !          3736: static void
        !          3737: cleanup_watcher(isc_mem_t *mctx, isc_socketmgr_t *manager) {
        !          3738: #ifdef ISC_PLATFORM_USETHREADS
        !          3739:        isc_result_t result;
        !          3740: 
        !          3741:        result = unwatch_fd(manager, manager->pipe_fds[0], SELECT_POKE_READ);
        !          3742:        if (result != ISC_R_SUCCESS) {
        !          3743:                UNEXPECTED_ERROR(__FILE__, __LINE__,
        !          3744:                                 "epoll_ctl(DEL) %s",
        !          3745:                                 isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
        !          3746:                                                ISC_MSG_FAILED, "failed"));
        !          3747:        }
        !          3748: #endif /* ISC_PLATFORM_USETHREADS */
        !          3749: 
        !          3750: #ifdef USE_KQUEUE
        !          3751:        close(manager->kqueue_fd);
        !          3752:        isc_mem_put(mctx, manager->events,
        !          3753:                    sizeof(struct kevent) * manager->nevents);
        !          3754: #elif defined(USE_EPOLL)
        !          3755:        close(manager->epoll_fd);
        !          3756:        isc_mem_put(mctx, manager->events,
        !          3757:                    sizeof(struct epoll_event) * manager->nevents);
        !          3758: #elif defined(USE_DEVPOLL)
        !          3759:        close(manager->devpoll_fd);
        !          3760:        isc_mem_put(mctx, manager->events,
        !          3761:                    sizeof(struct pollfd) * manager->nevents);
        !          3762:        isc_mem_put(mctx, manager->fdpollinfo,
        !          3763:                    sizeof(pollinfo_t) * manager->maxsocks);
        !          3764: #elif defined(USE_SELECT)
        !          3765:        if (manager->read_fds != NULL)
        !          3766:                isc_mem_put(mctx, manager->read_fds, manager->fd_bufsize);
        !          3767:        if (manager->read_fds_copy != NULL)
        !          3768:                isc_mem_put(mctx, manager->read_fds_copy, manager->fd_bufsize);
        !          3769:        if (manager->write_fds != NULL)
        !          3770:                isc_mem_put(mctx, manager->write_fds, manager->fd_bufsize);
        !          3771:        if (manager->write_fds_copy != NULL)
        !          3772:                isc_mem_put(mctx, manager->write_fds_copy, manager->fd_bufsize);
        !          3773: #endif /* USE_KQUEUE */
        !          3774: }
        !          3775: 
        !          3776: isc_result_t
        !          3777: isc_socketmgr_create(isc_mem_t *mctx, isc_socketmgr_t **managerp) {
        !          3778:        return (isc_socketmgr_create2(mctx, managerp, 0));
        !          3779: }
        !          3780: 
        !          3781: isc_result_t
        !          3782: isc_socketmgr_create2(isc_mem_t *mctx, isc_socketmgr_t **managerp,
        !          3783:                      unsigned int maxsocks)
        !          3784: {
        !          3785:        int i;
        !          3786:        isc_socketmgr_t *manager;
        !          3787: #ifdef ISC_PLATFORM_USETHREADS
        !          3788:        char strbuf[ISC_STRERRORSIZE];
        !          3789: #endif
        !          3790:        isc_result_t result;
        !          3791: 
        !          3792:        REQUIRE(managerp != NULL && *managerp == NULL);
        !          3793: 
        !          3794: #ifndef ISC_PLATFORM_USETHREADS
        !          3795:        if (socketmgr != NULL) {
        !          3796:                /* Don't allow maxsocks to be updated */
        !          3797:                if (maxsocks > 0 && socketmgr->maxsocks != maxsocks)
        !          3798:                        return (ISC_R_EXISTS);
        !          3799: 
        !          3800:                socketmgr->refs++;
        !          3801:                *managerp = socketmgr;
        !          3802:                return (ISC_R_SUCCESS);
        !          3803:        }
        !          3804: #endif /* ISC_PLATFORM_USETHREADS */
        !          3805: 
        !          3806:        if (maxsocks == 0)
        !          3807:                maxsocks = ISC_SOCKET_MAXSOCKETS;
        !          3808: 
        !          3809:        manager = isc_mem_get(mctx, sizeof(*manager));
        !          3810:        if (manager == NULL)
        !          3811:                return (ISC_R_NOMEMORY);
        !          3812: 
        !          3813:        /* zero-clear so that necessary cleanup on failure will be easy */
        !          3814:        memset(manager, 0, sizeof(*manager));
        !          3815:        manager->maxsocks = maxsocks;
        !          3816:        manager->reserved = 0;
        !          3817:        manager->fds = isc_mem_get(mctx,
        !          3818:                                   manager->maxsocks * sizeof(isc_socket_t *));
        !          3819:        if (manager->fds == NULL) {
        !          3820:                result = ISC_R_NOMEMORY;
        !          3821:                goto free_manager;
        !          3822:        }
        !          3823:        manager->fdstate = isc_mem_get(mctx, manager->maxsocks * sizeof(int));
        !          3824:        if (manager->fdstate == NULL) {
        !          3825:                result = ISC_R_NOMEMORY;
        !          3826:                goto free_manager;
        !          3827:        }
        !          3828:        manager->stats = NULL;
        !          3829: 
        !          3830:        manager->magic = SOCKET_MANAGER_MAGIC;
        !          3831:        manager->mctx = NULL;
        !          3832:        memset(manager->fds, 0, manager->maxsocks * sizeof(isc_socket_t *));
        !          3833:        ISC_LIST_INIT(manager->socklist);
        !          3834:        result = isc_mutex_init(&manager->lock);
        !          3835:        if (result != ISC_R_SUCCESS)
        !          3836:                goto free_manager;
        !          3837:        manager->fdlock = isc_mem_get(mctx, FDLOCK_COUNT * sizeof(isc_mutex_t));
        !          3838:        if (manager->fdlock == NULL) {
        !          3839:                result = ISC_R_NOMEMORY;
        !          3840:                goto cleanup_lock;
        !          3841:        }
        !          3842:        for (i = 0; i < FDLOCK_COUNT; i++) {
        !          3843:                result = isc_mutex_init(&manager->fdlock[i]);
        !          3844:                if (result != ISC_R_SUCCESS) {
        !          3845:                        while (--i >= 0)
        !          3846:                                DESTROYLOCK(&manager->fdlock[i]);
        !          3847:                        isc_mem_put(mctx, manager->fdlock,
        !          3848:                                    FDLOCK_COUNT * sizeof(isc_mutex_t));
        !          3849:                        manager->fdlock = NULL;
        !          3850:                        goto cleanup_lock;
        !          3851:                }
        !          3852:        }
        !          3853: 
        !          3854: #ifdef ISC_PLATFORM_USETHREADS
        !          3855:        if (isc_condition_init(&manager->shutdown_ok) != ISC_R_SUCCESS) {
        !          3856:                UNEXPECTED_ERROR(__FILE__, __LINE__,
        !          3857:                                 "isc_condition_init() %s",
        !          3858:                                 isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
        !          3859:                                                ISC_MSG_FAILED, "failed"));
        !          3860:                result = ISC_R_UNEXPECTED;
        !          3861:                goto cleanup_lock;
        !          3862:        }
        !          3863: 
        !          3864:        /*
        !          3865:         * Create the special fds that will be used to wake up the
        !          3866:         * select/poll loop when something internal needs to be done.
        !          3867:         */
        !          3868:        if (pipe(manager->pipe_fds) != 0) {
        !          3869:                isc__strerror(errno, strbuf, sizeof(strbuf));
        !          3870:                UNEXPECTED_ERROR(__FILE__, __LINE__,
        !          3871:                                 "pipe() %s: %s",
        !          3872:                                 isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
        !          3873:                                                ISC_MSG_FAILED, "failed"),
        !          3874:                                 strbuf);
        !          3875:                result = ISC_R_UNEXPECTED;
        !          3876:                goto cleanup_condition;
        !          3877:        }
        !          3878: 
        !          3879:        RUNTIME_CHECK(make_nonblock(manager->pipe_fds[0]) == ISC_R_SUCCESS);
        !          3880: #if 0
        !          3881:        RUNTIME_CHECK(make_nonblock(manager->pipe_fds[1]) == ISC_R_SUCCESS);
        !          3882: #endif
        !          3883: #else /* ISC_PLATFORM_USETHREADS */
        !          3884:        manager->refs = 1;
        !          3885: #endif /* ISC_PLATFORM_USETHREADS */
        !          3886: 
        !          3887:        /*
        !          3888:         * Set up initial state for the select loop
        !          3889:         */
        !          3890:        result = setup_watcher(mctx, manager);
        !          3891:        if (result != ISC_R_SUCCESS)
        !          3892:                goto cleanup;
        !          3893:        memset(manager->fdstate, 0, manager->maxsocks * sizeof(int));
        !          3894: #ifdef ISC_PLATFORM_USETHREADS
        !          3895:        /*
        !          3896:         * Start up the select/poll thread.
        !          3897:         */
        !          3898:        if (isc_thread_create(watcher, manager, &manager->watcher) !=
        !          3899:            ISC_R_SUCCESS) {
        !          3900:                UNEXPECTED_ERROR(__FILE__, __LINE__,
        !          3901:                                 "isc_thread_create() %s",
        !          3902:                                 isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
        !          3903:                                                ISC_MSG_FAILED, "failed"));
        !          3904:                cleanup_watcher(mctx, manager);
        !          3905:                result = ISC_R_UNEXPECTED;
        !          3906:                goto cleanup;
        !          3907:        }
        !          3908: #endif /* ISC_PLATFORM_USETHREADS */
        !          3909:        isc_mem_attach(mctx, &manager->mctx);
        !          3910: 
        !          3911: #ifndef ISC_PLATFORM_USETHREADS
        !          3912:        socketmgr = manager;
        !          3913: #endif /* ISC_PLATFORM_USETHREADS */
        !          3914:        *managerp = manager;
        !          3915: 
        !          3916:        return (ISC_R_SUCCESS);
        !          3917: 
        !          3918: cleanup:
        !          3919: #ifdef ISC_PLATFORM_USETHREADS
        !          3920:        (void)close(manager->pipe_fds[0]);
        !          3921:        (void)close(manager->pipe_fds[1]);
        !          3922: #endif /* ISC_PLATFORM_USETHREADS */
        !          3923: 
        !          3924: #ifdef ISC_PLATFORM_USETHREADS
        !          3925: cleanup_condition:
        !          3926:        (void)isc_condition_destroy(&manager->shutdown_ok);
        !          3927: #endif /* ISC_PLATFORM_USETHREADS */
        !          3928: 
        !          3929: 
        !          3930: cleanup_lock:
        !          3931:        if (manager->fdlock != NULL) {
        !          3932:                for (i = 0; i < FDLOCK_COUNT; i++)
        !          3933:                        DESTROYLOCK(&manager->fdlock[i]);
        !          3934:        }
        !          3935:        DESTROYLOCK(&manager->lock);
        !          3936: 
        !          3937: free_manager:
        !          3938:        if (manager->fdlock != NULL) {
        !          3939:                isc_mem_put(mctx, manager->fdlock,
        !          3940:                            FDLOCK_COUNT * sizeof(isc_mutex_t));
        !          3941:        }
        !          3942:        if (manager->fdstate != NULL) {
        !          3943:                isc_mem_put(mctx, manager->fdstate,
        !          3944:                            manager->maxsocks * sizeof(int));
        !          3945:        }
        !          3946:        if (manager->fds != NULL) {
        !          3947:                isc_mem_put(mctx, manager->fds,
        !          3948:                            manager->maxsocks * sizeof(isc_socket_t *));
        !          3949:        }
        !          3950:        isc_mem_put(mctx, manager, sizeof(*manager));
        !          3951: 
        !          3952:        return (result);
        !          3953: }
        !          3954: 
        !          3955: isc_result_t
        !          3956: isc_socketmgr_getmaxsockets(isc_socketmgr_t *manager, unsigned int *nsockp) {
        !          3957:        REQUIRE(VALID_MANAGER(manager));
        !          3958:        REQUIRE(nsockp != NULL);
        !          3959: 
        !          3960:        *nsockp = manager->maxsocks;
        !          3961: 
        !          3962:        return (ISC_R_SUCCESS);
        !          3963: }
        !          3964: 
        !          3965: void
        !          3966: isc_socketmgr_setstats(isc_socketmgr_t *manager, isc_stats_t *stats) {
        !          3967:        REQUIRE(VALID_MANAGER(manager));
        !          3968:        REQUIRE(ISC_LIST_EMPTY(manager->socklist));
        !          3969:        REQUIRE(manager->stats == NULL);
        !          3970:        REQUIRE(isc_stats_ncounters(stats) == isc_sockstatscounter_max);
        !          3971: 
        !          3972:        isc_stats_attach(stats, &manager->stats);
        !          3973: }
        !          3974: 
        !          3975: void
        !          3976: isc_socketmgr_destroy(isc_socketmgr_t **managerp) {
        !          3977:        isc_socketmgr_t *manager;
        !          3978:        int i;
        !          3979:        isc_mem_t *mctx;
        !          3980: 
        !          3981:        /*
        !          3982:         * Destroy a socket manager.
        !          3983:         */
        !          3984: 
        !          3985:        REQUIRE(managerp != NULL);
        !          3986:        manager = *managerp;
        !          3987:        REQUIRE(VALID_MANAGER(manager));
        !          3988: 
        !          3989: #ifndef ISC_PLATFORM_USETHREADS
        !          3990:        if (manager->refs > 1) {
        !          3991:                manager->refs--;
        !          3992:                *managerp = NULL;
        !          3993:                return;
        !          3994:        }
        !          3995: #endif /* ISC_PLATFORM_USETHREADS */
        !          3996: 
        !          3997:        LOCK(&manager->lock);
        !          3998: 
        !          3999: #ifdef ISC_PLATFORM_USETHREADS
        !          4000:        /*
        !          4001:         * Wait for all sockets to be destroyed.
        !          4002:         */
        !          4003:        while (!ISC_LIST_EMPTY(manager->socklist)) {
        !          4004:                manager_log(manager, CREATION, "%s",
        !          4005:                            isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKET,
        !          4006:                                           ISC_MSG_SOCKETSREMAIN,
        !          4007:                                           "sockets exist"));
        !          4008:                WAIT(&manager->shutdown_ok, &manager->lock);
        !          4009:        }
        !          4010: #else /* ISC_PLATFORM_USETHREADS */
        !          4011:        /*
        !          4012:         * Hope all sockets have been destroyed.
        !          4013:         */
        !          4014:        if (!ISC_LIST_EMPTY(manager->socklist)) {
        !          4015:                manager_log(manager, CREATION, "%s",
        !          4016:                            isc_msgcat_get(isc_msgcat, ISC_MSGSET_SOCKET,
        !          4017:                                           ISC_MSG_SOCKETSREMAIN,
        !          4018:                                           "sockets exist"));
        !          4019:                INSIST(0);
        !          4020:        }
        !          4021: #endif /* ISC_PLATFORM_USETHREADS */
        !          4022: 
        !          4023:        UNLOCK(&manager->lock);
        !          4024: 
        !          4025:        /*
        !          4026:         * Here, poke our select/poll thread.  Do this by closing the write
        !          4027:         * half of the pipe, which will send EOF to the read half.
        !          4028:         * This is currently a no-op in the non-threaded case.
        !          4029:         */
        !          4030:        select_poke(manager, 0, SELECT_POKE_SHUTDOWN);
        !          4031: 
        !          4032: #ifdef ISC_PLATFORM_USETHREADS
        !          4033:        /*
        !          4034:         * Wait for thread to exit.
        !          4035:         */
        !          4036:        if (isc_thread_join(manager->watcher, NULL) != ISC_R_SUCCESS)
        !          4037:                UNEXPECTED_ERROR(__FILE__, __LINE__,
        !          4038:                                 "isc_thread_join() %s",
        !          4039:                                 isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
        !          4040:                                                ISC_MSG_FAILED, "failed"));
        !          4041: #endif /* ISC_PLATFORM_USETHREADS */
        !          4042: 
        !          4043:        /*
        !          4044:         * Clean up.
        !          4045:         */
        !          4046:        cleanup_watcher(manager->mctx, manager);
        !          4047: 
        !          4048: #ifdef ISC_PLATFORM_USETHREADS
        !          4049:        (void)close(manager->pipe_fds[0]);
        !          4050:        (void)close(manager->pipe_fds[1]);
        !          4051:        (void)isc_condition_destroy(&manager->shutdown_ok);
        !          4052: #endif /* ISC_PLATFORM_USETHREADS */
        !          4053: 
        !          4054:        for (i = 0; i < (int)manager->maxsocks; i++)
        !          4055:                if (manager->fdstate[i] == CLOSE_PENDING) /* no need to lock */
        !          4056:                        (void)close(i);
        !          4057: 
        !          4058:        isc_mem_put(manager->mctx, manager->fds,
        !          4059:                    manager->maxsocks * sizeof(isc_socket_t *));
        !          4060:        isc_mem_put(manager->mctx, manager->fdstate,
        !          4061:                    manager->maxsocks * sizeof(int));
        !          4062: 
        !          4063:        if (manager->stats != NULL)
        !          4064:                isc_stats_detach(&manager->stats);
        !          4065: 
        !          4066:        if (manager->fdlock != NULL) {
        !          4067:                for (i = 0; i < FDLOCK_COUNT; i++)
        !          4068:                        DESTROYLOCK(&manager->fdlock[i]);
        !          4069:                isc_mem_put(manager->mctx, manager->fdlock,
        !          4070:                            FDLOCK_COUNT * sizeof(isc_mutex_t));
        !          4071:        }
        !          4072:        DESTROYLOCK(&manager->lock);
        !          4073:        manager->magic = 0;
        !          4074:        mctx= manager->mctx;
        !          4075:        isc_mem_put(mctx, manager, sizeof(*manager));
        !          4076: 
        !          4077:        isc_mem_detach(&mctx);
        !          4078: 
        !          4079:        *managerp = NULL;
        !          4080: }
        !          4081: 
        !          4082: static isc_result_t
        !          4083: socket_recv(isc_socket_t *sock, isc_socketevent_t *dev, isc_task_t *task,
        !          4084:            unsigned int flags)
        !          4085: {
        !          4086:        int io_state;
        !          4087:        isc_boolean_t have_lock = ISC_FALSE;
        !          4088:        isc_task_t *ntask = NULL;
        !          4089:        isc_result_t result = ISC_R_SUCCESS;
        !          4090: 
        !          4091:        dev->ev_sender = task;
        !          4092: 
        !          4093:        if (sock->type == isc_sockettype_udp) {
        !          4094:                io_state = doio_recv(sock, dev);
        !          4095:        } else {
        !          4096:                LOCK(&sock->lock);
        !          4097:                have_lock = ISC_TRUE;
        !          4098: 
        !          4099:                if (ISC_LIST_EMPTY(sock->recv_list))
        !          4100:                        io_state = doio_recv(sock, dev);
        !          4101:                else
        !          4102:                        io_state = DOIO_SOFT;
        !          4103:        }
        !          4104: 
        !          4105:        switch (io_state) {
        !          4106:        case DOIO_SOFT:
        !          4107:                /*
        !          4108:                 * We couldn't read all or part of the request right now, so
        !          4109:                 * queue it.
        !          4110:                 *
        !          4111:                 * Attach to socket and to task
        !          4112:                 */
        !          4113:                isc_task_attach(task, &ntask);
        !          4114:                dev->attributes |= ISC_SOCKEVENTATTR_ATTACHED;
        !          4115: 
        !          4116:                if (!have_lock) {
        !          4117:                        LOCK(&sock->lock);
        !          4118:                        have_lock = ISC_TRUE;
        !          4119:                }
        !          4120: 
        !          4121:                /*
        !          4122:                 * Enqueue the request.  If the socket was previously not being
        !          4123:                 * watched, poke the watcher to start paying attention to it.
        !          4124:                 */
        !          4125:                if (ISC_LIST_EMPTY(sock->recv_list) && !sock->pending_recv)
        !          4126:                        select_poke(sock->manager, sock->fd, SELECT_POKE_READ);
        !          4127:                ISC_LIST_ENQUEUE(sock->recv_list, dev, ev_link);
        !          4128: 
        !          4129:                socket_log(sock, NULL, EVENT, NULL, 0, 0,
        !          4130:                           "socket_recv: event %p -> task %p",
        !          4131:                           dev, ntask);
        !          4132: 
        !          4133:                if ((flags & ISC_SOCKFLAG_IMMEDIATE) != 0)
        !          4134:                        result = ISC_R_INPROGRESS;
        !          4135:                break;
        !          4136: 
        !          4137:        case DOIO_EOF:
        !          4138:                dev->result = ISC_R_EOF;
        !          4139:                /* fallthrough */
        !          4140: 
        !          4141:        case DOIO_HARD:
        !          4142:        case DOIO_SUCCESS:
        !          4143:                if ((flags & ISC_SOCKFLAG_IMMEDIATE) == 0)
        !          4144:                        send_recvdone_event(sock, &dev);
        !          4145:                break;
        !          4146:        }
        !          4147: 
        !          4148:        if (have_lock)
        !          4149:                UNLOCK(&sock->lock);
        !          4150: 
        !          4151:        return (result);
        !          4152: }
        !          4153: 
        !          4154: isc_result_t
        !          4155: isc_socket_recvv(isc_socket_t *sock, isc_bufferlist_t *buflist,
        !          4156:                 unsigned int minimum, isc_task_t *task,
        !          4157:                 isc_taskaction_t action, const void *arg)
        !          4158: {
        !          4159:        isc_socketevent_t *dev;
        !          4160:        isc_socketmgr_t *manager;
        !          4161:        unsigned int iocount;
        !          4162:        isc_buffer_t *buffer;
        !          4163: 
        !          4164:        REQUIRE(VALID_SOCKET(sock));
        !          4165:        REQUIRE(buflist != NULL);
        !          4166:        REQUIRE(!ISC_LIST_EMPTY(*buflist));
        !          4167:        REQUIRE(task != NULL);
        !          4168:        REQUIRE(action != NULL);
        !          4169: 
        !          4170:        manager = sock->manager;
        !          4171:        REQUIRE(VALID_MANAGER(manager));
        !          4172: 
        !          4173:        iocount = isc_bufferlist_availablecount(buflist);
        !          4174:        REQUIRE(iocount > 0);
        !          4175: 
        !          4176:        INSIST(sock->bound);
        !          4177: 
        !          4178:        dev = allocate_socketevent(sock, ISC_SOCKEVENT_RECVDONE, action, arg);
        !          4179:        if (dev == NULL) {
        !          4180:                return (ISC_R_NOMEMORY);
        !          4181:        }
        !          4182: 
        !          4183:        /*
        !          4184:         * UDP sockets are always partial read
        !          4185:         */
        !          4186:        if (sock->type == isc_sockettype_udp)
        !          4187:                dev->minimum = 1;
        !          4188:        else {
        !          4189:                if (minimum == 0)
        !          4190:                        dev->minimum = iocount;
        !          4191:                else
        !          4192:                        dev->minimum = minimum;
        !          4193:        }
        !          4194: 
        !          4195:        /*
        !          4196:         * Move each buffer from the passed in list to our internal one.
        !          4197:         */
        !          4198:        buffer = ISC_LIST_HEAD(*buflist);
        !          4199:        while (buffer != NULL) {
        !          4200:                ISC_LIST_DEQUEUE(*buflist, buffer, link);
        !          4201:                ISC_LIST_ENQUEUE(dev->bufferlist, buffer, link);
        !          4202:                buffer = ISC_LIST_HEAD(*buflist);
        !          4203:        }
        !          4204: 
        !          4205:        return (socket_recv(sock, dev, task, 0));
        !          4206: }
        !          4207: 
        !          4208: isc_result_t
        !          4209: isc_socket_recv(isc_socket_t *sock, isc_region_t *region, unsigned int minimum,
        !          4210:                isc_task_t *task, isc_taskaction_t action, const void *arg)
        !          4211: {
        !          4212:        isc_socketevent_t *dev;
        !          4213:        isc_socketmgr_t *manager;
        !          4214: 
        !          4215:        REQUIRE(VALID_SOCKET(sock));
        !          4216:        REQUIRE(action != NULL);
        !          4217: 
        !          4218:        manager = sock->manager;
        !          4219:        REQUIRE(VALID_MANAGER(manager));
        !          4220: 
        !          4221:        INSIST(sock->bound);
        !          4222: 
        !          4223:        dev = allocate_socketevent(sock, ISC_SOCKEVENT_RECVDONE, action, arg);
        !          4224:        if (dev == NULL)
        !          4225:                return (ISC_R_NOMEMORY);
        !          4226: 
        !          4227:        return (isc_socket_recv2(sock, region, minimum, task, dev, 0));
        !          4228: }
        !          4229: 
        !          4230: isc_result_t
        !          4231: isc_socket_recv2(isc_socket_t *sock, isc_region_t *region,
        !          4232:                 unsigned int minimum, isc_task_t *task,
        !          4233:                 isc_socketevent_t *event, unsigned int flags)
        !          4234: {
        !          4235:        event->ev_sender = sock;
        !          4236:        event->result = ISC_R_UNEXPECTED;
        !          4237:        ISC_LIST_INIT(event->bufferlist);
        !          4238:        event->region = *region;
        !          4239:        event->n = 0;
        !          4240:        event->offset = 0;
        !          4241:        event->attributes = 0;
        !          4242: 
        !          4243:        /*
        !          4244:         * UDP sockets are always partial read.
        !          4245:         */
        !          4246:        if (sock->type == isc_sockettype_udp)
        !          4247:                event->minimum = 1;
        !          4248:        else {
        !          4249:                if (minimum == 0)
        !          4250:                        event->minimum = region->length;
        !          4251:                else
        !          4252:                        event->minimum = minimum;
        !          4253:        }
        !          4254: 
        !          4255:        return (socket_recv(sock, event, task, flags));
        !          4256: }
        !          4257: 
        !          4258: static isc_result_t
        !          4259: socket_send(isc_socket_t *sock, isc_socketevent_t *dev, isc_task_t *task,
        !          4260:            isc_sockaddr_t *address, struct in6_pktinfo *pktinfo,
        !          4261:            unsigned int flags)
        !          4262: {
        !          4263:        int io_state;
        !          4264:        isc_boolean_t have_lock = ISC_FALSE;
        !          4265:        isc_task_t *ntask = NULL;
        !          4266:        isc_result_t result = ISC_R_SUCCESS;
        !          4267: 
        !          4268:        dev->ev_sender = task;
        !          4269: 
        !          4270:        set_dev_address(address, sock, dev);
        !          4271:        if (pktinfo != NULL) {
        !          4272:                dev->attributes |= ISC_SOCKEVENTATTR_PKTINFO;
        !          4273:                dev->pktinfo = *pktinfo;
        !          4274: 
        !          4275:                if (!isc_sockaddr_issitelocal(&dev->address) &&
        !          4276:                    !isc_sockaddr_islinklocal(&dev->address)) {
        !          4277:                        socket_log(sock, NULL, TRACE, isc_msgcat,
        !          4278:                                   ISC_MSGSET_SOCKET, ISC_MSG_PKTINFOPROVIDED,
        !          4279:                                   "pktinfo structure provided, ifindex %u "
        !          4280:                                   "(set to 0)", pktinfo->ipi6_ifindex);
        !          4281: 
        !          4282:                        /*
        !          4283:                         * Set the pktinfo index to 0 here, to let the
        !          4284:                         * kernel decide what interface it should send on.
        !          4285:                         */
        !          4286:                        dev->pktinfo.ipi6_ifindex = 0;
        !          4287:                }
        !          4288:        }
        !          4289: 
        !          4290:        if (sock->type == isc_sockettype_udp)
        !          4291:                io_state = doio_send(sock, dev);
        !          4292:        else {
        !          4293:                LOCK(&sock->lock);
        !          4294:                have_lock = ISC_TRUE;
        !          4295: 
        !          4296:                if (ISC_LIST_EMPTY(sock->send_list))
        !          4297:                        io_state = doio_send(sock, dev);
        !          4298:                else
        !          4299:                        io_state = DOIO_SOFT;
        !          4300:        }
        !          4301: 
        !          4302:        switch (io_state) {
        !          4303:        case DOIO_SOFT:
        !          4304:                /*
        !          4305:                 * We couldn't send all or part of the request right now, so
        !          4306:                 * queue it unless ISC_SOCKFLAG_NORETRY is set.
        !          4307:                 */
        !          4308:                if ((flags & ISC_SOCKFLAG_NORETRY) == 0) {
        !          4309:                        isc_task_attach(task, &ntask);
        !          4310:                        dev->attributes |= ISC_SOCKEVENTATTR_ATTACHED;
        !          4311: 
        !          4312:                        if (!have_lock) {
        !          4313:                                LOCK(&sock->lock);
        !          4314:                                have_lock = ISC_TRUE;
        !          4315:                        }
        !          4316: 
        !          4317:                        /*
        !          4318:                         * Enqueue the request.  If the socket was previously
        !          4319:                         * not being watched, poke the watcher to start
        !          4320:                         * paying attention to it.
        !          4321:                         */
        !          4322:                        if (ISC_LIST_EMPTY(sock->send_list) &&
        !          4323:                            !sock->pending_send)
        !          4324:                                select_poke(sock->manager, sock->fd,
        !          4325:                                            SELECT_POKE_WRITE);
        !          4326:                        ISC_LIST_ENQUEUE(sock->send_list, dev, ev_link);
        !          4327: 
        !          4328:                        socket_log(sock, NULL, EVENT, NULL, 0, 0,
        !          4329:                                   "socket_send: event %p -> task %p",
        !          4330:                                   dev, ntask);
        !          4331: 
        !          4332:                        if ((flags & ISC_SOCKFLAG_IMMEDIATE) != 0)
        !          4333:                                result = ISC_R_INPROGRESS;
        !          4334:                        break;
        !          4335:                }
        !          4336: 
        !          4337:        case DOIO_HARD:
        !          4338:        case DOIO_SUCCESS:
        !          4339:                if ((flags & ISC_SOCKFLAG_IMMEDIATE) == 0)
        !          4340:                        send_senddone_event(sock, &dev);
        !          4341:                break;
        !          4342:        }
        !          4343: 
        !          4344:        if (have_lock)
        !          4345:                UNLOCK(&sock->lock);
        !          4346: 
        !          4347:        return (result);
        !          4348: }
        !          4349: 
        !          4350: isc_result_t
        !          4351: isc_socket_send(isc_socket_t *sock, isc_region_t *region,
        !          4352:                isc_task_t *task, isc_taskaction_t action, const void *arg)
        !          4353: {
        !          4354:        /*
        !          4355:         * REQUIRE() checking is performed in isc_socket_sendto().
        !          4356:         */
        !          4357:        return (isc_socket_sendto(sock, region, task, action, arg, NULL,
        !          4358:                                  NULL));
        !          4359: }
        !          4360: 
        !          4361: isc_result_t
        !          4362: isc_socket_sendto(isc_socket_t *sock, isc_region_t *region,
        !          4363:                  isc_task_t *task, isc_taskaction_t action, const void *arg,
        !          4364:                  isc_sockaddr_t *address, struct in6_pktinfo *pktinfo)
        !          4365: {
        !          4366:        isc_socketevent_t *dev;
        !          4367:        isc_socketmgr_t *manager;
        !          4368: 
        !          4369:        REQUIRE(VALID_SOCKET(sock));
        !          4370:        REQUIRE(region != NULL);
        !          4371:        REQUIRE(task != NULL);
        !          4372:        REQUIRE(action != NULL);
        !          4373: 
        !          4374:        manager = sock->manager;
        !          4375:        REQUIRE(VALID_MANAGER(manager));
        !          4376: 
        !          4377:        INSIST(sock->bound);
        !          4378: 
        !          4379:        dev = allocate_socketevent(sock, ISC_SOCKEVENT_SENDDONE, action, arg);
        !          4380:        if (dev == NULL) {
        !          4381:                return (ISC_R_NOMEMORY);
        !          4382:        }
        !          4383: 
        !          4384:        dev->region = *region;
        !          4385: 
        !          4386:        return (socket_send(sock, dev, task, address, pktinfo, 0));
        !          4387: }
        !          4388: 
        !          4389: isc_result_t
        !          4390: isc_socket_sendv(isc_socket_t *sock, isc_bufferlist_t *buflist,
        !          4391:                 isc_task_t *task, isc_taskaction_t action, const void *arg)
        !          4392: {
        !          4393:        return (isc_socket_sendtov(sock, buflist, task, action, arg, NULL,
        !          4394:                                   NULL));
        !          4395: }
        !          4396: 
        !          4397: isc_result_t
        !          4398: isc_socket_sendtov(isc_socket_t *sock, isc_bufferlist_t *buflist,
        !          4399:                   isc_task_t *task, isc_taskaction_t action, const void *arg,
        !          4400:                   isc_sockaddr_t *address, struct in6_pktinfo *pktinfo)
        !          4401: {
        !          4402:        isc_socketevent_t *dev;
        !          4403:        isc_socketmgr_t *manager;
        !          4404:        unsigned int iocount;
        !          4405:        isc_buffer_t *buffer;
        !          4406: 
        !          4407:        REQUIRE(VALID_SOCKET(sock));
        !          4408:        REQUIRE(buflist != NULL);
        !          4409:        REQUIRE(!ISC_LIST_EMPTY(*buflist));
        !          4410:        REQUIRE(task != NULL);
        !          4411:        REQUIRE(action != NULL);
        !          4412: 
        !          4413:        manager = sock->manager;
        !          4414:        REQUIRE(VALID_MANAGER(manager));
        !          4415: 
        !          4416:        iocount = isc_bufferlist_usedcount(buflist);
        !          4417:        REQUIRE(iocount > 0);
        !          4418: 
        !          4419:        dev = allocate_socketevent(sock, ISC_SOCKEVENT_SENDDONE, action, arg);
        !          4420:        if (dev == NULL) {
        !          4421:                return (ISC_R_NOMEMORY);
        !          4422:        }
        !          4423: 
        !          4424:        /*
        !          4425:         * Move each buffer from the passed in list to our internal one.
        !          4426:         */
        !          4427:        buffer = ISC_LIST_HEAD(*buflist);
        !          4428:        while (buffer != NULL) {
        !          4429:                ISC_LIST_DEQUEUE(*buflist, buffer, link);
        !          4430:                ISC_LIST_ENQUEUE(dev->bufferlist, buffer, link);
        !          4431:                buffer = ISC_LIST_HEAD(*buflist);
        !          4432:        }
        !          4433: 
        !          4434:        return (socket_send(sock, dev, task, address, pktinfo, 0));
        !          4435: }
        !          4436: 
        !          4437: isc_result_t
        !          4438: isc_socket_sendto2(isc_socket_t *sock, isc_region_t *region,
        !          4439:                   isc_task_t *task,
        !          4440:                   isc_sockaddr_t *address, struct in6_pktinfo *pktinfo,
        !          4441:                   isc_socketevent_t *event, unsigned int flags)
        !          4442: {
        !          4443:        REQUIRE((flags & ~(ISC_SOCKFLAG_IMMEDIATE|ISC_SOCKFLAG_NORETRY)) == 0);
        !          4444:        if ((flags & ISC_SOCKFLAG_NORETRY) != 0)
        !          4445:                REQUIRE(sock->type == isc_sockettype_udp);
        !          4446:        event->ev_sender = sock;
        !          4447:        event->result = ISC_R_UNEXPECTED;
        !          4448:        ISC_LIST_INIT(event->bufferlist);
        !          4449:        event->region = *region;
        !          4450:        event->n = 0;
        !          4451:        event->offset = 0;
        !          4452:        event->attributes = 0;
        !          4453: 
        !          4454:        return (socket_send(sock, event, task, address, pktinfo, flags));
        !          4455: }
        !          4456: 
        !          4457: void
        !          4458: isc_socket_cleanunix(isc_sockaddr_t *sockaddr, isc_boolean_t active) {
        !          4459: #ifdef ISC_PLATFORM_HAVESYSUNH
        !          4460:        int s;
        !          4461:        struct stat sb;
        !          4462:        char strbuf[ISC_STRERRORSIZE];
        !          4463: 
        !          4464:        if (sockaddr->type.sa.sa_family != AF_UNIX)
        !          4465:                return;
        !          4466: 
        !          4467: #ifndef S_ISSOCK
        !          4468: #if defined(S_IFMT) && defined(S_IFSOCK)
        !          4469: #define S_ISSOCK(mode) ((mode & S_IFMT)==S_IFSOCK)
        !          4470: #elif defined(_S_IFMT) && defined(S_IFSOCK)
        !          4471: #define S_ISSOCK(mode) ((mode & _S_IFMT)==S_IFSOCK)
        !          4472: #endif
        !          4473: #endif
        !          4474: 
        !          4475: #ifndef S_ISFIFO
        !          4476: #if defined(S_IFMT) && defined(S_IFIFO)
        !          4477: #define S_ISFIFO(mode) ((mode & S_IFMT)==S_IFIFO)
        !          4478: #elif defined(_S_IFMT) && defined(S_IFIFO)
        !          4479: #define S_ISFIFO(mode) ((mode & _S_IFMT)==S_IFIFO)
        !          4480: #endif
        !          4481: #endif
        !          4482: 
        !          4483: #if !defined(S_ISFIFO) && !defined(S_ISSOCK)
        !          4484: #error You need to define S_ISFIFO and S_ISSOCK as appropriate for your platform.  See <sys/stat.h>.
        !          4485: #endif
        !          4486: 
        !          4487: #ifndef S_ISFIFO
        !          4488: #define S_ISFIFO(mode) 0
        !          4489: #endif
        !          4490: 
        !          4491: #ifndef S_ISSOCK
        !          4492: #define S_ISSOCK(mode) 0
        !          4493: #endif
        !          4494: 
        !          4495:        if (active) {
        !          4496:                if (stat(sockaddr->type.sunix.sun_path, &sb) < 0) {
        !          4497:                        isc__strerror(errno, strbuf, sizeof(strbuf));
        !          4498:                        isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
        !          4499:                                      ISC_LOGMODULE_SOCKET, ISC_LOG_ERROR,
        !          4500:                                      "isc_socket_cleanunix: stat(%s): %s",
        !          4501:                                      sockaddr->type.sunix.sun_path, strbuf);
        !          4502:                        return;
        !          4503:                }
        !          4504:                if (!(S_ISSOCK(sb.st_mode) || S_ISFIFO(sb.st_mode))) {
        !          4505:                        isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
        !          4506:                                      ISC_LOGMODULE_SOCKET, ISC_LOG_ERROR,
        !          4507:                                      "isc_socket_cleanunix: %s: not a socket",
        !          4508:                                      sockaddr->type.sunix.sun_path);
        !          4509:                        return;
        !          4510:                }
        !          4511:                if (unlink(sockaddr->type.sunix.sun_path) < 0) {
        !          4512:                        isc__strerror(errno, strbuf, sizeof(strbuf));
        !          4513:                        isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
        !          4514:                                      ISC_LOGMODULE_SOCKET, ISC_LOG_ERROR,
        !          4515:                                      "isc_socket_cleanunix: unlink(%s): %s",
        !          4516:                                      sockaddr->type.sunix.sun_path, strbuf);
        !          4517:                }
        !          4518:                return;
        !          4519:        }
        !          4520: 
        !          4521:        s = socket(AF_UNIX, SOCK_STREAM, 0);
        !          4522:        if (s < 0) {
        !          4523:                isc__strerror(errno, strbuf, sizeof(strbuf));
        !          4524:                isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
        !          4525:                              ISC_LOGMODULE_SOCKET, ISC_LOG_WARNING,
        !          4526:                              "isc_socket_cleanunix: socket(%s): %s",
        !          4527:                              sockaddr->type.sunix.sun_path, strbuf);
        !          4528:                return;
        !          4529:        }
        !          4530: 
        !          4531:        if (stat(sockaddr->type.sunix.sun_path, &sb) < 0) {
        !          4532:                switch (errno) {
        !          4533:                case ENOENT:    /* We exited cleanly last time */
        !          4534:                        break;
        !          4535:                default:
        !          4536:                        isc__strerror(errno, strbuf, sizeof(strbuf));
        !          4537:                        isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
        !          4538:                                      ISC_LOGMODULE_SOCKET, ISC_LOG_WARNING,
        !          4539:                                      "isc_socket_cleanunix: stat(%s): %s",
        !          4540:                                      sockaddr->type.sunix.sun_path, strbuf);
        !          4541:                        break;
        !          4542:                }
        !          4543:                goto cleanup;
        !          4544:        }
        !          4545: 
        !          4546:        if (!(S_ISSOCK(sb.st_mode) || S_ISFIFO(sb.st_mode))) {
        !          4547:                isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
        !          4548:                              ISC_LOGMODULE_SOCKET, ISC_LOG_WARNING,
        !          4549:                              "isc_socket_cleanunix: %s: not a socket",
        !          4550:                              sockaddr->type.sunix.sun_path);
        !          4551:                goto cleanup;
        !          4552:        }
        !          4553: 
        !          4554:        if (connect(s, (struct sockaddr *)&sockaddr->type.sunix,
        !          4555:                    sizeof(sockaddr->type.sunix)) < 0) {
        !          4556:                switch (errno) {
        !          4557:                case ECONNREFUSED:
        !          4558:                case ECONNRESET:
        !          4559:                        if (unlink(sockaddr->type.sunix.sun_path) < 0) {
        !          4560:                                isc__strerror(errno, strbuf, sizeof(strbuf));
        !          4561:                                isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
        !          4562:                                              ISC_LOGMODULE_SOCKET,
        !          4563:                                              ISC_LOG_WARNING,
        !          4564:                                              "isc_socket_cleanunix: "
        !          4565:                                              "unlink(%s): %s",
        !          4566:                                              sockaddr->type.sunix.sun_path,
        !          4567:                                              strbuf);
        !          4568:                        }
        !          4569:                        break;
        !          4570:                default:
        !          4571:                        isc__strerror(errno, strbuf, sizeof(strbuf));
        !          4572:                        isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
        !          4573:                                      ISC_LOGMODULE_SOCKET, ISC_LOG_WARNING,
        !          4574:                                      "isc_socket_cleanunix: connect(%s): %s",
        !          4575:                                      sockaddr->type.sunix.sun_path, strbuf);
        !          4576:                        break;
        !          4577:                }
        !          4578:        }
        !          4579:  cleanup:
        !          4580:        close(s);
        !          4581: #else
        !          4582:        UNUSED(sockaddr);
        !          4583:        UNUSED(active);
        !          4584: #endif
        !          4585: }
        !          4586: 
        !          4587: isc_result_t
        !          4588: isc_socket_permunix(isc_sockaddr_t *sockaddr, isc_uint32_t perm,
        !          4589:                    isc_uint32_t owner, isc_uint32_t group)
        !          4590: {
        !          4591: #ifdef ISC_PLATFORM_HAVESYSUNH
        !          4592:        isc_result_t result = ISC_R_SUCCESS;
        !          4593:        char strbuf[ISC_STRERRORSIZE];
        !          4594:        char path[sizeof(sockaddr->type.sunix.sun_path)];
        !          4595: #ifdef NEED_SECURE_DIRECTORY
        !          4596:        char *slash;
        !          4597: #endif
        !          4598: 
        !          4599:        REQUIRE(sockaddr->type.sa.sa_family == AF_UNIX);
        !          4600:        INSIST(strlen(sockaddr->type.sunix.sun_path) < sizeof(path));
        !          4601:        strcpy(path, sockaddr->type.sunix.sun_path);
        !          4602: 
        !          4603: #ifdef NEED_SECURE_DIRECTORY
        !          4604:        slash = strrchr(path, '/');
        !          4605:        if (slash != NULL) {
        !          4606:                if (slash != path)
        !          4607:                        *slash = '\0';
        !          4608:                else
        !          4609:                        strcpy(path, "/");
        !          4610:        } else
        !          4611:                strcpy(path, ".");
        !          4612: #endif
        !          4613: 
        !          4614:        if (chmod(path, perm) < 0) {
        !          4615:                isc__strerror(errno, strbuf, sizeof(strbuf));
        !          4616:                isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
        !          4617:                              ISC_LOGMODULE_SOCKET, ISC_LOG_ERROR,
        !          4618:                              "isc_socket_permunix: chmod(%s, %d): %s",
        !          4619:                              path, perm, strbuf);
        !          4620:                result = ISC_R_FAILURE;
        !          4621:        }
        !          4622:        if (chown(path, owner, group) < 0) {
        !          4623:                isc__strerror(errno, strbuf, sizeof(strbuf));
        !          4624:                isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
        !          4625:                              ISC_LOGMODULE_SOCKET, ISC_LOG_ERROR,
        !          4626:                              "isc_socket_permunix: chown(%s, %d, %d): %s",
        !          4627:                              path, owner, group,
        !          4628:                              strbuf);
        !          4629:                result = ISC_R_FAILURE;
        !          4630:        }
        !          4631:        return (result);
        !          4632: #else
        !          4633:        UNUSED(sockaddr);
        !          4634:        UNUSED(perm);
        !          4635:        UNUSED(owner);
        !          4636:        UNUSED(group);
        !          4637:        return (ISC_R_NOTIMPLEMENTED);
        !          4638: #endif
        !          4639: }
        !          4640: 
        !          4641: isc_result_t
        !          4642: isc_socket_bind(isc_socket_t *sock, isc_sockaddr_t *sockaddr,
        !          4643:                unsigned int options) {
        !          4644:        char strbuf[ISC_STRERRORSIZE];
        !          4645:        int on = 1;
        !          4646: 
        !          4647:        LOCK(&sock->lock);
        !          4648: 
        !          4649:        INSIST(!sock->bound);
        !          4650: 
        !          4651:        if (sock->pf != sockaddr->type.sa.sa_family) {
        !          4652:                UNLOCK(&sock->lock);
        !          4653:                return (ISC_R_FAMILYMISMATCH);
        !          4654:        }
        !          4655:        /*
        !          4656:         * Only set SO_REUSEADDR when we want a specific port.
        !          4657:         */
        !          4658: #ifdef AF_UNIX
        !          4659:        if (sock->pf == AF_UNIX)
        !          4660:                goto bind_socket;
        !          4661: #endif
        !          4662:        if ((options & ISC_SOCKET_REUSEADDRESS) != 0 &&
        !          4663:            isc_sockaddr_getport(sockaddr) != (in_port_t)0 &&
        !          4664:            setsockopt(sock->fd, SOL_SOCKET, SO_REUSEADDR, (void *)&on,
        !          4665:                       sizeof(on)) < 0) {
        !          4666:                UNEXPECTED_ERROR(__FILE__, __LINE__,
        !          4667:                                 "setsockopt(%d) %s", sock->fd,
        !          4668:                                 isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
        !          4669:                                                ISC_MSG_FAILED, "failed"));
        !          4670:                /* Press on... */
        !          4671:        }
        !          4672: #ifdef AF_UNIX
        !          4673:  bind_socket:
        !          4674: #endif
        !          4675:        if (bind(sock->fd, &sockaddr->type.sa, sockaddr->length) < 0) {
        !          4676:                inc_stats(sock->manager->stats,
        !          4677:                          sock->statsindex[STATID_BINDFAIL]);
        !          4678: 
        !          4679:                UNLOCK(&sock->lock);
        !          4680:                switch (errno) {
        !          4681:                case EACCES:
        !          4682:                        return (ISC_R_NOPERM);
        !          4683:                case EADDRNOTAVAIL:
        !          4684:                        return (ISC_R_ADDRNOTAVAIL);
        !          4685:                case EADDRINUSE:
        !          4686:                        return (ISC_R_ADDRINUSE);
        !          4687:                case EINVAL:
        !          4688:                        return (ISC_R_BOUND);
        !          4689:                default:
        !          4690:                        isc__strerror(errno, strbuf, sizeof(strbuf));
        !          4691:                        UNEXPECTED_ERROR(__FILE__, __LINE__, "bind: %s",
        !          4692:                                         strbuf);
        !          4693:                        return (ISC_R_UNEXPECTED);
        !          4694:                }
        !          4695:        }
        !          4696: 
        !          4697:        socket_log(sock, sockaddr, TRACE,
        !          4698:                   isc_msgcat, ISC_MSGSET_SOCKET, ISC_MSG_BOUND, "bound");
        !          4699:        sock->bound = 1;
        !          4700: 
        !          4701:        UNLOCK(&sock->lock);
        !          4702:        return (ISC_R_SUCCESS);
        !          4703: }
        !          4704: 
        !          4705: isc_result_t
        !          4706: isc_socket_filter(isc_socket_t *sock, const char *filter) {
        !          4707: #ifdef SO_ACCEPTFILTER
        !          4708:        char strbuf[ISC_STRERRORSIZE];
        !          4709:        struct accept_filter_arg afa;
        !          4710: #else
        !          4711:        UNUSED(sock);
        !          4712:        UNUSED(filter);
        !          4713: #endif
        !          4714: 
        !          4715:        REQUIRE(VALID_SOCKET(sock));
        !          4716: 
        !          4717: #ifdef SO_ACCEPTFILTER
        !          4718:        bzero(&afa, sizeof(afa));
        !          4719:        strncpy(afa.af_name, filter, sizeof(afa.af_name));
        !          4720:        if (setsockopt(sock->fd, SOL_SOCKET, SO_ACCEPTFILTER,
        !          4721:                         &afa, sizeof(afa)) == -1) {
        !          4722:                isc__strerror(errno, strbuf, sizeof(strbuf));
        !          4723:                socket_log(sock, NULL, CREATION, isc_msgcat, ISC_MSGSET_SOCKET,
        !          4724:                           ISC_MSG_FILTER, "setsockopt(SO_ACCEPTFILTER): %s",
        !          4725:                           strbuf);
        !          4726:                return (ISC_R_FAILURE);
        !          4727:        }
        !          4728:        return (ISC_R_SUCCESS);
        !          4729: #else
        !          4730:        return (ISC_R_NOTIMPLEMENTED);
        !          4731: #endif
        !          4732: }
        !          4733: 
        !          4734: /*
        !          4735:  * Set up to listen on a given socket.  We do this by creating an internal
        !          4736:  * event that will be dispatched when the socket has read activity.  The
        !          4737:  * watcher will send the internal event to the task when there is a new
        !          4738:  * connection.
        !          4739:  *
        !          4740:  * Unlike in read, we don't preallocate a done event here.  Every time there
        !          4741:  * is a new connection we'll have to allocate a new one anyway, so we might
        !          4742:  * as well keep things simple rather than having to track them.
        !          4743:  */
        !          4744: isc_result_t
        !          4745: isc_socket_listen(isc_socket_t *sock, unsigned int backlog) {
        !          4746:        char strbuf[ISC_STRERRORSIZE];
        !          4747: 
        !          4748:        REQUIRE(VALID_SOCKET(sock));
        !          4749: 
        !          4750:        LOCK(&sock->lock);
        !          4751: 
        !          4752:        REQUIRE(!sock->listener);
        !          4753:        REQUIRE(sock->bound);
        !          4754:        REQUIRE(sock->type == isc_sockettype_tcp ||
        !          4755:                sock->type == isc_sockettype_unix);
        !          4756: 
        !          4757:        if (backlog == 0)
        !          4758:                backlog = SOMAXCONN;
        !          4759: 
        !          4760:        if (listen(sock->fd, (int)backlog) < 0) {
        !          4761:                UNLOCK(&sock->lock);
        !          4762:                isc__strerror(errno, strbuf, sizeof(strbuf));
        !          4763: 
        !          4764:                UNEXPECTED_ERROR(__FILE__, __LINE__, "listen: %s", strbuf);
        !          4765: 
        !          4766:                return (ISC_R_UNEXPECTED);
        !          4767:        }
        !          4768: 
        !          4769:        sock->listener = 1;
        !          4770: 
        !          4771:        UNLOCK(&sock->lock);
        !          4772:        return (ISC_R_SUCCESS);
        !          4773: }
        !          4774: 
        !          4775: /*
        !          4776:  * This should try to do aggressive accept() XXXMLG
        !          4777:  */
        !          4778: isc_result_t
        !          4779: isc_socket_accept(isc_socket_t *sock,
        !          4780:                  isc_task_t *task, isc_taskaction_t action, const void *arg)
        !          4781: {
        !          4782:        isc_socket_newconnev_t *dev;
        !          4783:        isc_socketmgr_t *manager;
        !          4784:        isc_task_t *ntask = NULL;
        !          4785:        isc_socket_t *nsock;
        !          4786:        isc_result_t result;
        !          4787:        isc_boolean_t do_poke = ISC_FALSE;
        !          4788: 
        !          4789:        REQUIRE(VALID_SOCKET(sock));
        !          4790:        manager = sock->manager;
        !          4791:        REQUIRE(VALID_MANAGER(manager));
        !          4792: 
        !          4793:        LOCK(&sock->lock);
        !          4794: 
        !          4795:        REQUIRE(sock->listener);
        !          4796: 
        !          4797:        /*
        !          4798:         * Sender field is overloaded here with the task we will be sending
        !          4799:         * this event to.  Just before the actual event is delivered the
        !          4800:         * actual ev_sender will be touched up to be the socket.
        !          4801:         */
        !          4802:        dev = (isc_socket_newconnev_t *)
        !          4803:                isc_event_allocate(manager->mctx, task, ISC_SOCKEVENT_NEWCONN,
        !          4804:                                   action, arg, sizeof(*dev));
        !          4805:        if (dev == NULL) {
        !          4806:                UNLOCK(&sock->lock);
        !          4807:                return (ISC_R_NOMEMORY);
        !          4808:        }
        !          4809:        ISC_LINK_INIT(dev, ev_link);
        !          4810: 
        !          4811:        result = allocate_socket(manager, sock->type, &nsock);
        !          4812:        if (result != ISC_R_SUCCESS) {
        !          4813:                isc_event_free(ISC_EVENT_PTR(&dev));
        !          4814:                UNLOCK(&sock->lock);
        !          4815:                return (result);
        !          4816:        }
        !          4817: 
        !          4818:        /*
        !          4819:         * Attach to socket and to task.
        !          4820:         */
        !          4821:        isc_task_attach(task, &ntask);
        !          4822:        nsock->references++;
        !          4823:        nsock->statsindex = sock->statsindex;
        !          4824: 
        !          4825:        dev->ev_sender = ntask;
        !          4826:        dev->newsocket = nsock;
        !          4827: 
        !          4828:        /*
        !          4829:         * Poke watcher here.  We still have the socket locked, so there
        !          4830:         * is no race condition.  We will keep the lock for such a short
        !          4831:         * bit of time waking it up now or later won't matter all that much.
        !          4832:         */
        !          4833:        if (ISC_LIST_EMPTY(sock->accept_list))
        !          4834:                do_poke = ISC_TRUE;
        !          4835: 
        !          4836:        ISC_LIST_ENQUEUE(sock->accept_list, dev, ev_link);
        !          4837: 
        !          4838:        if (do_poke)
        !          4839:                select_poke(manager, sock->fd, SELECT_POKE_ACCEPT);
        !          4840: 
        !          4841:        UNLOCK(&sock->lock);
        !          4842:        return (ISC_R_SUCCESS);
        !          4843: }
        !          4844: 
        !          4845: isc_result_t
        !          4846: isc_socket_connect(isc_socket_t *sock, isc_sockaddr_t *addr,
        !          4847:                   isc_task_t *task, isc_taskaction_t action, const void *arg)
        !          4848: {
        !          4849:        isc_socket_connev_t *dev;
        !          4850:        isc_task_t *ntask = NULL;
        !          4851:        isc_socketmgr_t *manager;
        !          4852:        int cc;
        !          4853:        char strbuf[ISC_STRERRORSIZE];
        !          4854: 
        !          4855:        REQUIRE(VALID_SOCKET(sock));
        !          4856:        REQUIRE(addr != NULL);
        !          4857:        REQUIRE(task != NULL);
        !          4858:        REQUIRE(action != NULL);
        !          4859: 
        !          4860:        manager = sock->manager;
        !          4861:        REQUIRE(VALID_MANAGER(manager));
        !          4862:        REQUIRE(addr != NULL);
        !          4863: 
        !          4864:        if (isc_sockaddr_ismulticast(addr))
        !          4865:                return (ISC_R_MULTICAST);
        !          4866: 
        !          4867:        LOCK(&sock->lock);
        !          4868: 
        !          4869:        REQUIRE(!sock->connecting);
        !          4870: 
        !          4871:        dev = (isc_socket_connev_t *)isc_event_allocate(manager->mctx, sock,
        !          4872:                                                        ISC_SOCKEVENT_CONNECT,
        !          4873:                                                        action, arg,
        !          4874:                                                        sizeof(*dev));
        !          4875:        if (dev == NULL) {
        !          4876:                UNLOCK(&sock->lock);
        !          4877:                return (ISC_R_NOMEMORY);
        !          4878:        }
        !          4879:        ISC_LINK_INIT(dev, ev_link);
        !          4880: 
        !          4881:        /*
        !          4882:         * Try to do the connect right away, as there can be only one
        !          4883:         * outstanding, and it might happen to complete.
        !          4884:         */
        !          4885:        sock->peer_address = *addr;
        !          4886:        cc = connect(sock->fd, &addr->type.sa, addr->length);
        !          4887:        if (cc < 0) {
        !          4888:                /*
        !          4889:                 * HP-UX "fails" to connect a UDP socket and sets errno to
        !          4890:                 * EINPROGRESS if it's non-blocking.  We'd rather regard this as
        !          4891:                 * a success and let the user detect it if it's really an error
        !          4892:                 * at the time of sending a packet on the socket.
        !          4893:                 */
        !          4894:                if (sock->type == isc_sockettype_udp && errno == EINPROGRESS) {
        !          4895:                        cc = 0;
        !          4896:                        goto success;
        !          4897:                }
        !          4898:                if (SOFT_ERROR(errno) || errno == EINPROGRESS)
        !          4899:                        goto queue;
        !          4900: 
        !          4901:                switch (errno) {
        !          4902: #define ERROR_MATCH(a, b) case a: dev->result = b; goto err_exit;
        !          4903:                        ERROR_MATCH(EACCES, ISC_R_NOPERM);
        !          4904:                        ERROR_MATCH(EADDRNOTAVAIL, ISC_R_ADDRNOTAVAIL);
        !          4905:                        ERROR_MATCH(EAFNOSUPPORT, ISC_R_ADDRNOTAVAIL);
        !          4906:                        ERROR_MATCH(ECONNREFUSED, ISC_R_CONNREFUSED);
        !          4907:                        ERROR_MATCH(EHOSTUNREACH, ISC_R_HOSTUNREACH);
        !          4908: #ifdef EHOSTDOWN
        !          4909:                        ERROR_MATCH(EHOSTDOWN, ISC_R_HOSTUNREACH);
        !          4910: #endif
        !          4911:                        ERROR_MATCH(ENETUNREACH, ISC_R_NETUNREACH);
        !          4912:                        ERROR_MATCH(ENOBUFS, ISC_R_NORESOURCES);
        !          4913:                        ERROR_MATCH(EPERM, ISC_R_HOSTUNREACH);
        !          4914:                        ERROR_MATCH(EPIPE, ISC_R_NOTCONNECTED);
        !          4915:                        ERROR_MATCH(ECONNRESET, ISC_R_CONNECTIONRESET);
        !          4916: #undef ERROR_MATCH
        !          4917:                }
        !          4918: 
        !          4919:                sock->connected = 0;
        !          4920: 
        !          4921:                isc__strerror(errno, strbuf, sizeof(strbuf));
        !          4922:                UNEXPECTED_ERROR(__FILE__, __LINE__, "%d/%s", errno, strbuf);
        !          4923: 
        !          4924:                UNLOCK(&sock->lock);
        !          4925:                inc_stats(sock->manager->stats,
        !          4926:                          sock->statsindex[STATID_CONNECTFAIL]);
        !          4927:                isc_event_free(ISC_EVENT_PTR(&dev));
        !          4928:                return (ISC_R_UNEXPECTED);
        !          4929: 
        !          4930:        err_exit:
        !          4931:                sock->connected = 0;
        !          4932:                isc_task_send(task, ISC_EVENT_PTR(&dev));
        !          4933: 
        !          4934:                UNLOCK(&sock->lock);
        !          4935:                inc_stats(sock->manager->stats,
        !          4936:                          sock->statsindex[STATID_CONNECTFAIL]);
        !          4937:                return (ISC_R_SUCCESS);
        !          4938:        }
        !          4939: 
        !          4940:        /*
        !          4941:         * If connect completed, fire off the done event.
        !          4942:         */
        !          4943:  success:
        !          4944:        if (cc == 0) {
        !          4945:                sock->connected = 1;
        !          4946:                sock->bound = 1;
        !          4947:                dev->result = ISC_R_SUCCESS;
        !          4948:                isc_task_send(task, ISC_EVENT_PTR(&dev));
        !          4949: 
        !          4950:                UNLOCK(&sock->lock);
        !          4951: 
        !          4952:                inc_stats(sock->manager->stats,
        !          4953:                          sock->statsindex[STATID_CONNECT]);
        !          4954: 
        !          4955:                return (ISC_R_SUCCESS);
        !          4956:        }
        !          4957: 
        !          4958:  queue:
        !          4959: 
        !          4960:        /*
        !          4961:         * Attach to task.
        !          4962:         */
        !          4963:        isc_task_attach(task, &ntask);
        !          4964: 
        !          4965:        sock->connecting = 1;
        !          4966: 
        !          4967:        dev->ev_sender = ntask;
        !          4968: 
        !          4969:        /*
        !          4970:         * Poke watcher here.  We still have the socket locked, so there
        !          4971:         * is no race condition.  We will keep the lock for such a short
        !          4972:         * bit of time waking it up now or later won't matter all that much.
        !          4973:         */
        !          4974:        if (sock->connect_ev == NULL)
        !          4975:                select_poke(manager, sock->fd, SELECT_POKE_CONNECT);
        !          4976: 
        !          4977:        sock->connect_ev = dev;
        !          4978: 
        !          4979:        UNLOCK(&sock->lock);
        !          4980:        return (ISC_R_SUCCESS);
        !          4981: }
        !          4982: 
        !          4983: /*
        !          4984:  * Called when a socket with a pending connect() finishes.
        !          4985:  */
        !          4986: static void
        !          4987: internal_connect(isc_task_t *me, isc_event_t *ev) {
        !          4988:        isc_socket_t *sock;
        !          4989:        isc_socket_connev_t *dev;
        !          4990:        isc_task_t *task;
        !          4991:        int cc;
        !          4992:        ISC_SOCKADDR_LEN_T optlen;
        !          4993:        char strbuf[ISC_STRERRORSIZE];
        !          4994:        char peerbuf[ISC_SOCKADDR_FORMATSIZE];
        !          4995: 
        !          4996:        UNUSED(me);
        !          4997:        INSIST(ev->ev_type == ISC_SOCKEVENT_INTW);
        !          4998: 
        !          4999:        sock = ev->ev_sender;
        !          5000:        INSIST(VALID_SOCKET(sock));
        !          5001: 
        !          5002:        LOCK(&sock->lock);
        !          5003: 
        !          5004:        /*
        !          5005:         * When the internal event was sent the reference count was bumped
        !          5006:         * to keep the socket around for us.  Decrement the count here.
        !          5007:         */
        !          5008:        INSIST(sock->references > 0);
        !          5009:        sock->references--;
        !          5010:        if (sock->references == 0) {
        !          5011:                UNLOCK(&sock->lock);
        !          5012:                destroy(&sock);
        !          5013:                return;
        !          5014:        }
        !          5015: 
        !          5016:        /*
        !          5017:         * Has this event been canceled?
        !          5018:         */
        !          5019:        dev = sock->connect_ev;
        !          5020:        if (dev == NULL) {
        !          5021:                INSIST(!sock->connecting);
        !          5022:                UNLOCK(&sock->lock);
        !          5023:                return;
        !          5024:        }
        !          5025: 
        !          5026:        INSIST(sock->connecting);
        !          5027:        sock->connecting = 0;
        !          5028: 
        !          5029:        /*
        !          5030:         * Get any possible error status here.
        !          5031:         */
        !          5032:        optlen = sizeof(cc);
        !          5033:        if (getsockopt(sock->fd, SOL_SOCKET, SO_ERROR,
        !          5034:                       (void *)&cc, (void *)&optlen) < 0)
        !          5035:                cc = errno;
        !          5036:        else
        !          5037:                errno = cc;
        !          5038: 
        !          5039:        if (errno != 0) {
        !          5040:                /*
        !          5041:                 * If the error is EAGAIN, just re-select on this
        !          5042:                 * fd and pretend nothing strange happened.
        !          5043:                 */
        !          5044:                if (SOFT_ERROR(errno) || errno == EINPROGRESS) {
        !          5045:                        sock->connecting = 1;
        !          5046:                        select_poke(sock->manager, sock->fd,
        !          5047:                                    SELECT_POKE_CONNECT);
        !          5048:                        UNLOCK(&sock->lock);
        !          5049: 
        !          5050:                        return;
        !          5051:                }
        !          5052: 
        !          5053:                inc_stats(sock->manager->stats,
        !          5054:                          sock->statsindex[STATID_CONNECTFAIL]);
        !          5055: 
        !          5056:                /*
        !          5057:                 * Translate other errors into ISC_R_* flavors.
        !          5058:                 */
        !          5059:                switch (errno) {
        !          5060: #define ERROR_MATCH(a, b) case a: dev->result = b; break;
        !          5061:                        ERROR_MATCH(EACCES, ISC_R_NOPERM);
        !          5062:                        ERROR_MATCH(EADDRNOTAVAIL, ISC_R_ADDRNOTAVAIL);
        !          5063:                        ERROR_MATCH(EAFNOSUPPORT, ISC_R_ADDRNOTAVAIL);
        !          5064:                        ERROR_MATCH(ECONNREFUSED, ISC_R_CONNREFUSED);
        !          5065:                        ERROR_MATCH(EHOSTUNREACH, ISC_R_HOSTUNREACH);
        !          5066: #ifdef EHOSTDOWN
        !          5067:                        ERROR_MATCH(EHOSTDOWN, ISC_R_HOSTUNREACH);
        !          5068: #endif
        !          5069:                        ERROR_MATCH(ENETUNREACH, ISC_R_NETUNREACH);
        !          5070:                        ERROR_MATCH(ENOBUFS, ISC_R_NORESOURCES);
        !          5071:                        ERROR_MATCH(EPERM, ISC_R_HOSTUNREACH);
        !          5072:                        ERROR_MATCH(EPIPE, ISC_R_NOTCONNECTED);
        !          5073:                        ERROR_MATCH(ETIMEDOUT, ISC_R_TIMEDOUT);
        !          5074:                        ERROR_MATCH(ECONNRESET, ISC_R_CONNECTIONRESET);
        !          5075: #undef ERROR_MATCH
        !          5076:                default:
        !          5077:                        dev->result = ISC_R_UNEXPECTED;
        !          5078:                        isc_sockaddr_format(&sock->peer_address, peerbuf,
        !          5079:                                            sizeof(peerbuf));
        !          5080:                        isc__strerror(errno, strbuf, sizeof(strbuf));
        !          5081:                        UNEXPECTED_ERROR(__FILE__, __LINE__,
        !          5082:                                         "internal_connect: connect(%s) %s",
        !          5083:                                         peerbuf, strbuf);
        !          5084:                }
        !          5085:        } else {
        !          5086:                inc_stats(sock->manager->stats,
        !          5087:                          sock->statsindex[STATID_CONNECT]);
        !          5088:                dev->result = ISC_R_SUCCESS;
        !          5089:                sock->connected = 1;
        !          5090:                sock->bound = 1;
        !          5091:        }
        !          5092: 
        !          5093:        sock->connect_ev = NULL;
        !          5094: 
        !          5095:        UNLOCK(&sock->lock);
        !          5096: 
        !          5097:        task = dev->ev_sender;
        !          5098:        dev->ev_sender = sock;
        !          5099:        isc_task_sendanddetach(&task, ISC_EVENT_PTR(&dev));
        !          5100: }
        !          5101: 
        !          5102: isc_result_t
        !          5103: isc_socket_getpeername(isc_socket_t *sock, isc_sockaddr_t *addressp) {
        !          5104:        isc_result_t result;
        !          5105: 
        !          5106:        REQUIRE(VALID_SOCKET(sock));
        !          5107:        REQUIRE(addressp != NULL);
        !          5108: 
        !          5109:        LOCK(&sock->lock);
        !          5110: 
        !          5111:        if (sock->connected) {
        !          5112:                *addressp = sock->peer_address;
        !          5113:                result = ISC_R_SUCCESS;
        !          5114:        } else {
        !          5115:                result = ISC_R_NOTCONNECTED;
        !          5116:        }
        !          5117: 
        !          5118:        UNLOCK(&sock->lock);
        !          5119: 
        !          5120:        return (result);
        !          5121: }
        !          5122: 
        !          5123: isc_result_t
        !          5124: isc_socket_getsockname(isc_socket_t *sock, isc_sockaddr_t *addressp) {
        !          5125:        ISC_SOCKADDR_LEN_T len;
        !          5126:        isc_result_t result;
        !          5127:        char strbuf[ISC_STRERRORSIZE];
        !          5128: 
        !          5129:        REQUIRE(VALID_SOCKET(sock));
        !          5130:        REQUIRE(addressp != NULL);
        !          5131: 
        !          5132:        LOCK(&sock->lock);
        !          5133: 
        !          5134:        if (!sock->bound) {
        !          5135:                result = ISC_R_NOTBOUND;
        !          5136:                goto out;
        !          5137:        }
        !          5138: 
        !          5139:        result = ISC_R_SUCCESS;
        !          5140: 
        !          5141:        len = sizeof(addressp->type);
        !          5142:        if (getsockname(sock->fd, &addressp->type.sa, (void *)&len) < 0) {
        !          5143:                isc__strerror(errno, strbuf, sizeof(strbuf));
        !          5144:                UNEXPECTED_ERROR(__FILE__, __LINE__, "getsockname: %s",
        !          5145:                                 strbuf);
        !          5146:                result = ISC_R_UNEXPECTED;
        !          5147:                goto out;
        !          5148:        }
        !          5149:        addressp->length = (unsigned int)len;
        !          5150: 
        !          5151:  out:
        !          5152:        UNLOCK(&sock->lock);
        !          5153: 
        !          5154:        return (result);
        !          5155: }
        !          5156: 
        !          5157: /*
        !          5158:  * Run through the list of events on this socket, and cancel the ones
        !          5159:  * queued for task "task" of type "how".  "how" is a bitmask.
        !          5160:  */
        !          5161: void
        !          5162: isc_socket_cancel(isc_socket_t *sock, isc_task_t *task, unsigned int how) {
        !          5163: 
        !          5164:        REQUIRE(VALID_SOCKET(sock));
        !          5165: 
        !          5166:        /*
        !          5167:         * Quick exit if there is nothing to do.  Don't even bother locking
        !          5168:         * in this case.
        !          5169:         */
        !          5170:        if (how == 0)
        !          5171:                return;
        !          5172: 
        !          5173:        LOCK(&sock->lock);
        !          5174: 
        !          5175:        /*
        !          5176:         * All of these do the same thing, more or less.
        !          5177:         * Each will:
        !          5178:         *      o If the internal event is marked as "posted" try to
        !          5179:         *        remove it from the task's queue.  If this fails, mark it
        !          5180:         *        as canceled instead, and let the task clean it up later.
        !          5181:         *      o For each I/O request for that task of that type, post
        !          5182:         *        its done event with status of "ISC_R_CANCELED".
        !          5183:         *      o Reset any state needed.
        !          5184:         */
        !          5185:        if (((how & ISC_SOCKCANCEL_RECV) == ISC_SOCKCANCEL_RECV)
        !          5186:            && !ISC_LIST_EMPTY(sock->recv_list)) {
        !          5187:                isc_socketevent_t      *dev;
        !          5188:                isc_socketevent_t      *next;
        !          5189:                isc_task_t             *current_task;
        !          5190: 
        !          5191:                dev = ISC_LIST_HEAD(sock->recv_list);
        !          5192: 
        !          5193:                while (dev != NULL) {
        !          5194:                        current_task = dev->ev_sender;
        !          5195:                        next = ISC_LIST_NEXT(dev, ev_link);
        !          5196: 
        !          5197:                        if ((task == NULL) || (task == current_task)) {
        !          5198:                                dev->result = ISC_R_CANCELED;
        !          5199:                                send_recvdone_event(sock, &dev);
        !          5200:                        }
        !          5201:                        dev = next;
        !          5202:                }
        !          5203:        }
        !          5204: 
        !          5205:        if (((how & ISC_SOCKCANCEL_SEND) == ISC_SOCKCANCEL_SEND)
        !          5206:            && !ISC_LIST_EMPTY(sock->send_list)) {
        !          5207:                isc_socketevent_t      *dev;
        !          5208:                isc_socketevent_t      *next;
        !          5209:                isc_task_t             *current_task;
        !          5210: 
        !          5211:                dev = ISC_LIST_HEAD(sock->send_list);
        !          5212: 
        !          5213:                while (dev != NULL) {
        !          5214:                        current_task = dev->ev_sender;
        !          5215:                        next = ISC_LIST_NEXT(dev, ev_link);
        !          5216: 
        !          5217:                        if ((task == NULL) || (task == current_task)) {
        !          5218:                                dev->result = ISC_R_CANCELED;
        !          5219:                                send_senddone_event(sock, &dev);
        !          5220:                        }
        !          5221:                        dev = next;
        !          5222:                }
        !          5223:        }
        !          5224: 
        !          5225:        if (((how & ISC_SOCKCANCEL_ACCEPT) == ISC_SOCKCANCEL_ACCEPT)
        !          5226:            && !ISC_LIST_EMPTY(sock->accept_list)) {
        !          5227:                isc_socket_newconnev_t *dev;
        !          5228:                isc_socket_newconnev_t *next;
        !          5229:                isc_task_t             *current_task;
        !          5230: 
        !          5231:                dev = ISC_LIST_HEAD(sock->accept_list);
        !          5232:                while (dev != NULL) {
        !          5233:                        current_task = dev->ev_sender;
        !          5234:                        next = ISC_LIST_NEXT(dev, ev_link);
        !          5235: 
        !          5236:                        if ((task == NULL) || (task == current_task)) {
        !          5237: 
        !          5238:                                ISC_LIST_UNLINK(sock->accept_list, dev,
        !          5239:                                                ev_link);
        !          5240: 
        !          5241:                                dev->newsocket->references--;
        !          5242:                                free_socket(&dev->newsocket);
        !          5243: 
        !          5244:                                dev->result = ISC_R_CANCELED;
        !          5245:                                dev->ev_sender = sock;
        !          5246:                                isc_task_sendanddetach(&current_task,
        !          5247:                                                       ISC_EVENT_PTR(&dev));
        !          5248:                        }
        !          5249: 
        !          5250:                        dev = next;
        !          5251:                }
        !          5252:        }
        !          5253: 
        !          5254:        /*
        !          5255:         * Connecting is not a list.
        !          5256:         */
        !          5257:        if (((how & ISC_SOCKCANCEL_CONNECT) == ISC_SOCKCANCEL_CONNECT)
        !          5258:            && sock->connect_ev != NULL) {
        !          5259:                isc_socket_connev_t    *dev;
        !          5260:                isc_task_t             *current_task;
        !          5261: 
        !          5262:                INSIST(sock->connecting);
        !          5263:                sock->connecting = 0;
        !          5264: 
        !          5265:                dev = sock->connect_ev;
        !          5266:                current_task = dev->ev_sender;
        !          5267: 
        !          5268:                if ((task == NULL) || (task == current_task)) {
        !          5269:                        sock->connect_ev = NULL;
        !          5270: 
        !          5271:                        dev->result = ISC_R_CANCELED;
        !          5272:                        dev->ev_sender = sock;
        !          5273:                        isc_task_sendanddetach(&current_task,
        !          5274:                                               ISC_EVENT_PTR(&dev));
        !          5275:                }
        !          5276:        }
        !          5277: 
        !          5278:        UNLOCK(&sock->lock);
        !          5279: }
        !          5280: 
        !          5281: isc_sockettype_t
        !          5282: isc_socket_gettype(isc_socket_t *sock) {
        !          5283:        REQUIRE(VALID_SOCKET(sock));
        !          5284: 
        !          5285:        return (sock->type);
        !          5286: }
        !          5287: 
        !          5288: isc_boolean_t
        !          5289: isc_socket_isbound(isc_socket_t *sock) {
        !          5290:        isc_boolean_t val;
        !          5291: 
        !          5292:        LOCK(&sock->lock);
        !          5293:        val = ((sock->bound) ? ISC_TRUE : ISC_FALSE);
        !          5294:        UNLOCK(&sock->lock);
        !          5295: 
        !          5296:        return (val);
        !          5297: }
        !          5298: 
        !          5299: void
        !          5300: isc_socket_ipv6only(isc_socket_t *sock, isc_boolean_t yes) {
        !          5301: #if defined(IPV6_V6ONLY)
        !          5302:        int onoff = yes ? 1 : 0;
        !          5303: #else
        !          5304:        UNUSED(yes);
        !          5305:        UNUSED(sock);
        !          5306: #endif
        !          5307: 
        !          5308:        REQUIRE(VALID_SOCKET(sock));
        !          5309: 
        !          5310: #ifdef IPV6_V6ONLY
        !          5311:        if (sock->pf == AF_INET6) {
        !          5312:                if (setsockopt(sock->fd, IPPROTO_IPV6, IPV6_V6ONLY,
        !          5313:                               (void *)&onoff, sizeof(int)) < 0) {
        !          5314:                        char strbuf[ISC_STRERRORSIZE];
        !          5315: 
        !          5316:                        UNEXPECTED_ERROR(__FILE__, __LINE__,
        !          5317:                                         "setsockopt(%d, IPV6_V6ONLY) "
        !          5318:                                         "%s: %s", sock->fd,
        !          5319:                                         isc_msgcat_get(isc_msgcat,
        !          5320:                                                        ISC_MSGSET_GENERAL,
        !          5321:                                                        ISC_MSG_FAILED,
        !          5322:                                                        "failed"),
        !          5323:                                         strbuf);
        !          5324:                }
        !          5325:        }
        !          5326:        FIX_IPV6_RECVPKTINFO(sock);     /* AIX */
        !          5327: #endif
        !          5328: }
        !          5329: 
        !          5330: #ifndef ISC_PLATFORM_USETHREADS
        !          5331: /* In our assumed scenario, we can simply use a single static object. */
        !          5332: static isc_socketwait_t swait_private;
        !          5333: 
        !          5334: int
        !          5335: isc__socketmgr_waitevents(struct timeval *tvp, isc_socketwait_t **swaitp) {
        !          5336:        int n;
        !          5337: #ifdef USE_KQUEUE
        !          5338:        struct timespec ts, *tsp;
        !          5339: #endif
        !          5340: #ifdef USE_EPOLL
        !          5341:        int timeout;
        !          5342: #endif
        !          5343: #ifdef USE_DEVPOLL
        !          5344:        struct dvpoll dvp;
        !          5345: #endif
        !          5346: 
        !          5347:        REQUIRE(swaitp != NULL && *swaitp == NULL);
        !          5348: 
        !          5349:        if (socketmgr == NULL)
        !          5350:                return (0);
        !          5351: 
        !          5352: #ifdef USE_KQUEUE
        !          5353:        if (tvp != NULL) {
        !          5354:                ts.tv_sec = tvp->tv_sec;
        !          5355:                ts.tv_nsec = tvp->tv_usec * 1000;
        !          5356:                tsp = &ts;
        !          5357:        } else
        !          5358:                tsp = NULL;
        !          5359:        swait_private.nevents = kevent(socketmgr->kqueue_fd, NULL, 0,
        !          5360:                                       socketmgr->events, socketmgr->nevents,
        !          5361:                                       tsp);
        !          5362:        n = swait_private.nevents;
        !          5363: #elif defined(USE_EPOLL)
        !          5364:        if (tvp != NULL)
        !          5365:                timeout = tvp->tv_sec * 1000 + (tvp->tv_usec + 999) / 1000;
        !          5366:        else
        !          5367:                timeout = -1;
        !          5368:        swait_private.nevents = epoll_wait(socketmgr->epoll_fd,
        !          5369:                                           socketmgr->events,
        !          5370:                                           socketmgr->nevents, timeout);
        !          5371:        n = swait_private.nevents;
        !          5372: #elif defined(USE_DEVPOLL)
        !          5373:        dvp.dp_fds = socketmgr->events;
        !          5374:        dvp.dp_nfds = socketmgr->nevents;
        !          5375:        if (tvp != NULL) {
        !          5376:                dvp.dp_timeout = tvp->tv_sec * 1000 +
        !          5377:                        (tvp->tv_usec + 999) / 1000;
        !          5378:        } else
        !          5379:                dvp.dp_timeout = -1;
        !          5380:        swait_private.nevents = ioctl(socketmgr->devpoll_fd, DP_POLL, &dvp);
        !          5381:        n = swait_private.nevents;
        !          5382: #elif defined(USE_SELECT)
        !          5383:        memcpy(socketmgr->read_fds_copy, socketmgr->read_fds,
        !          5384:               socketmgr->fd_bufsize);
        !          5385:        memcpy(socketmgr->write_fds_copy, socketmgr->write_fds,
        !          5386:               socketmgr->fd_bufsize);
        !          5387: 
        !          5388:        swait_private.readset = socketmgr->read_fds_copy;
        !          5389:        swait_private.writeset = socketmgr->write_fds_copy;
        !          5390:        swait_private.maxfd = socketmgr->maxfd + 1;
        !          5391: 
        !          5392:        n = select(swait_private.maxfd, swait_private.readset,
        !          5393:                   swait_private.writeset, NULL, tvp);
        !          5394: #endif
        !          5395: 
        !          5396:        *swaitp = &swait_private;
        !          5397:        return (n);
        !          5398: }
        !          5399: 
        !          5400: isc_result_t
        !          5401: isc__socketmgr_dispatch(isc_socketwait_t *swait) {
        !          5402:        REQUIRE(swait == &swait_private);
        !          5403: 
        !          5404:        if (socketmgr == NULL)
        !          5405:                return (ISC_R_NOTFOUND);
        !          5406: 
        !          5407: #if defined(USE_KQUEUE) || defined(USE_EPOLL) || defined(USE_DEVPOLL)
        !          5408:        (void)process_fds(socketmgr, socketmgr->events, swait->nevents);
        !          5409:        return (ISC_R_SUCCESS);
        !          5410: #elif defined(USE_SELECT)
        !          5411:        process_fds(socketmgr, swait->maxfd, swait->readset, swait->writeset);
        !          5412:        return (ISC_R_SUCCESS);
        !          5413: #endif
        !          5414: }
        !          5415: #endif /* ISC_PLATFORM_USETHREADS */
        !          5416: 
        !          5417: void
        !          5418: isc_socket_setname(isc_socket_t *socket, const char *name, void *tag) {
        !          5419: 
        !          5420:        /*
        !          5421:         * Name 'socket'.
        !          5422:         */
        !          5423: 
        !          5424:        REQUIRE(VALID_SOCKET(socket));
        !          5425: 
        !          5426:        LOCK(&socket->lock);
        !          5427:        memset(socket->name, 0, sizeof(socket->name));
        !          5428:        strncpy(socket->name, name, sizeof(socket->name) - 1);
        !          5429:        socket->tag = tag;
        !          5430:        UNLOCK(&socket->lock);
        !          5431: }
        !          5432: 
        !          5433: const char *
        !          5434: isc_socket_getname(isc_socket_t *socket) {
        !          5435:        return (socket->name);
        !          5436: }
        !          5437: 
        !          5438: void *
        !          5439: isc_socket_gettag(isc_socket_t *socket) {
        !          5440:        return (socket->tag);
        !          5441: }
        !          5442: 
        !          5443: #ifdef HAVE_LIBXML2
        !          5444: 
        !          5445: static const char *
        !          5446: _socktype(isc_sockettype_t type)
        !          5447: {
        !          5448:        if (type == isc_sockettype_udp)
        !          5449:                return ("udp");
        !          5450:        else if (type == isc_sockettype_tcp)
        !          5451:                return ("tcp");
        !          5452:        else if (type == isc_sockettype_unix)
        !          5453:                return ("unix");
        !          5454:        else if (type == isc_sockettype_fdwatch)
        !          5455:                return ("fdwatch");
        !          5456:        else
        !          5457:                return ("not-initialized");
        !          5458: }
        !          5459: 
        !          5460: void
        !          5461: isc_socketmgr_renderxml(isc_socketmgr_t *mgr, xmlTextWriterPtr writer)
        !          5462: {
        !          5463:        isc_socket_t *sock;
        !          5464:        char peerbuf[ISC_SOCKADDR_FORMATSIZE];
        !          5465:        isc_sockaddr_t addr;
        !          5466:        ISC_SOCKADDR_LEN_T len;
        !          5467: 
        !          5468:        LOCK(&mgr->lock);
        !          5469: 
        !          5470: #ifndef ISC_PLATFORM_USETHREADS
        !          5471:        xmlTextWriterStartElement(writer, ISC_XMLCHAR "references");
        !          5472:        xmlTextWriterWriteFormatString(writer, "%d", mgr->refs);
        !          5473:        xmlTextWriterEndElement(writer);
        !          5474: #endif
        !          5475: 
        !          5476:        xmlTextWriterStartElement(writer, ISC_XMLCHAR "sockets");
        !          5477:        sock = ISC_LIST_HEAD(mgr->socklist);
        !          5478:        while (sock != NULL) {
        !          5479:                LOCK(&sock->lock);
        !          5480:                xmlTextWriterStartElement(writer, ISC_XMLCHAR "socket");
        !          5481: 
        !          5482:                xmlTextWriterStartElement(writer, ISC_XMLCHAR "id");
        !          5483:                xmlTextWriterWriteFormatString(writer, "%p", sock);
        !          5484:                xmlTextWriterEndElement(writer);
        !          5485: 
        !          5486:                if (sock->name[0] != 0) {
        !          5487:                        xmlTextWriterStartElement(writer, ISC_XMLCHAR "name");
        !          5488:                        xmlTextWriterWriteFormatString(writer, "%s",
        !          5489:                                                       sock->name);
        !          5490:                        xmlTextWriterEndElement(writer); /* name */
        !          5491:                }
        !          5492: 
        !          5493:                xmlTextWriterStartElement(writer, ISC_XMLCHAR "references");
        !          5494:                xmlTextWriterWriteFormatString(writer, "%d", sock->references);
        !          5495:                xmlTextWriterEndElement(writer);
        !          5496: 
        !          5497:                xmlTextWriterWriteElement(writer, ISC_XMLCHAR "type",
        !          5498:                                          ISC_XMLCHAR _socktype(sock->type));
        !          5499: 
        !          5500:                if (sock->connected) {
        !          5501:                        isc_sockaddr_format(&sock->peer_address, peerbuf,
        !          5502:                                            sizeof(peerbuf));
        !          5503:                        xmlTextWriterWriteElement(writer,
        !          5504:                                                  ISC_XMLCHAR "peer-address",
        !          5505:                                                  ISC_XMLCHAR peerbuf);
        !          5506:                }
        !          5507: 
        !          5508:                len = sizeof(addr);
        !          5509:                if (getsockname(sock->fd, &addr.type.sa, (void *)&len) == 0) {
        !          5510:                        isc_sockaddr_format(&addr, peerbuf, sizeof(peerbuf));
        !          5511:                        xmlTextWriterWriteElement(writer,
        !          5512:                                                  ISC_XMLCHAR "local-address",
        !          5513:                                                  ISC_XMLCHAR peerbuf);
        !          5514:                }
        !          5515: 
        !          5516:                xmlTextWriterStartElement(writer, ISC_XMLCHAR "states");
        !          5517:                if (sock->pending_recv)
        !          5518:                        xmlTextWriterWriteElement(writer, ISC_XMLCHAR "state",
        !          5519:                                                ISC_XMLCHAR "pending-receive");
        !          5520:                if (sock->pending_send)
        !          5521:                        xmlTextWriterWriteElement(writer, ISC_XMLCHAR "state",
        !          5522:                                                  ISC_XMLCHAR "pending-send");
        !          5523:                if (sock->pending_accept)
        !          5524:                        xmlTextWriterWriteElement(writer, ISC_XMLCHAR "state",
        !          5525:                                                 ISC_XMLCHAR "pending_accept");
        !          5526:                if (sock->listener)
        !          5527:                        xmlTextWriterWriteElement(writer, ISC_XMLCHAR "state",
        !          5528:                                                  ISC_XMLCHAR "listener");
        !          5529:                if (sock->connected)
        !          5530:                        xmlTextWriterWriteElement(writer, ISC_XMLCHAR "state",
        !          5531:                                                  ISC_XMLCHAR "connected");
        !          5532:                if (sock->connecting)
        !          5533:                        xmlTextWriterWriteElement(writer, ISC_XMLCHAR "state",
        !          5534:                                                  ISC_XMLCHAR "connecting");
        !          5535:                if (sock->bound)
        !          5536:                        xmlTextWriterWriteElement(writer, ISC_XMLCHAR "state",
        !          5537:                                                  ISC_XMLCHAR "bound");
        !          5538: 
        !          5539:                xmlTextWriterEndElement(writer); /* states */
        !          5540: 
        !          5541:                xmlTextWriterEndElement(writer); /* socket */
        !          5542: 
        !          5543:                UNLOCK(&sock->lock);
        !          5544:                sock = ISC_LIST_NEXT(sock, link);
        !          5545:        }
        !          5546:        xmlTextWriterEndElement(writer); /* sockets */
        !          5547: 
        !          5548:        UNLOCK(&mgr->lock);
        !          5549: }
        !          5550: #endif /* HAVE_LIBXML2 */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>