dispatch.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2004-2009, 2011-2015  Internet Systems Consortium, Inc. ("ISC")
00003  * Copyright (C) 1999-2003  Internet Software Consortium.
00004  *
00005  * Permission to use, copy, modify, and/or distribute this software for any
00006  * purpose with or without fee is hereby granted, provided that the above
00007  * copyright notice and this permission notice appear in all copies.
00008  *
00009  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
00010  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
00011  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
00012  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
00013  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
00014  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
00015  * PERFORMANCE OF THIS SOFTWARE.
00016  */
00017 
00018 /*! \file */
00019 
00020 #include <config.h>
00021 
00022 #include <stdlib.h>
00023 #include <sys/types.h>
00024 #include <unistd.h>
00025 #include <stdlib.h>
00026 
00027 #include <isc/entropy.h>
00028 #include <isc/mem.h>
00029 #include <isc/mutex.h>
00030 #include <isc/portset.h>
00031 #include <isc/print.h>
00032 #include <isc/random.h>
00033 #include <isc/socket.h>
00034 #include <isc/stats.h>
00035 #include <isc/string.h>
00036 #include <isc/task.h>
00037 #include <isc/time.h>
00038 #include <isc/util.h>
00039 
00040 #include <dns/acl.h>
00041 #include <dns/dispatch.h>
00042 #include <dns/events.h>
00043 #include <dns/log.h>
00044 #include <dns/message.h>
00045 #include <dns/portlist.h>
00046 #include <dns/stats.h>
00047 #include <dns/tcpmsg.h>
00048 #include <dns/types.h>
00049 
00050 typedef ISC_LIST(dns_dispentry_t)       dns_displist_t;
00051 
00052 typedef struct dispsocket               dispsocket_t;
00053 typedef ISC_LIST(dispsocket_t)          dispsocketlist_t;
00054 
00055 typedef struct dispportentry            dispportentry_t;
00056 typedef ISC_LIST(dispportentry_t)       dispportlist_t;
00057 
00058 typedef struct dns_qid {
00059         unsigned int    magic;
00060         unsigned int    qid_nbuckets;   /*%< hash table size */
00061         unsigned int    qid_increment;  /*%< id increment on collision */
00062         isc_mutex_t     lock;
00063         dns_displist_t  *qid_table;     /*%< the table itself */
00064         dispsocketlist_t *sock_table;   /*%< socket table */
00065 } dns_qid_t;
00066 
00067 struct dns_dispatchmgr {
00068         /* Unlocked. */
00069         unsigned int                    magic;
00070         isc_mem_t                      *mctx;
00071         dns_acl_t                      *blackhole;
00072         dns_portlist_t                 *portlist;
00073         isc_stats_t                    *stats;
00074         isc_entropy_t                  *entropy; /*%< entropy source */
00075 
00076         /* Locked by "lock". */
00077         isc_mutex_t                     lock;
00078         unsigned int                    state;
00079         ISC_LIST(dns_dispatch_t)        list;
00080 
00081         /* Locked by rng_lock. */
00082         isc_mutex_t                     rng_lock;
00083         isc_rng_t                      *rngctx; /*%< RNG context for QID */
00084 
00085         /* locked by buffer_lock */
00086         dns_qid_t                       *qid;
00087         isc_mutex_t                     buffer_lock;
00088         unsigned int                    buffers;    /*%< allocated buffers */
00089         unsigned int                    buffersize; /*%< size of each buffer */
00090         unsigned int                    maxbuffers; /*%< max buffers */
00091 
00092         /* Locked internally. */
00093         isc_mutex_t                     depool_lock;
00094         isc_mempool_t                  *depool; /*%< pool for dispatch events */
00095         isc_mutex_t                     rpool_lock;
00096         isc_mempool_t                  *rpool;  /*%< pool for replies */
00097         isc_mutex_t                     dpool_lock;
00098         isc_mempool_t                  *dpool;  /*%< dispatch allocations */
00099         isc_mutex_t                     bpool_lock;
00100         isc_mempool_t                  *bpool;  /*%< pool for buffers */
00101         isc_mutex_t                     spool_lock;
00102         isc_mempool_t                  *spool;  /*%< pool for dispsocks */
00103 
00104         /*%
00105          * Locked by qid->lock if qid exists; otherwise, can be used without
00106          * being locked.
00107          * Memory footprint considerations: this is a simple implementation of
00108          * available ports, i.e., an ordered array of the actual port numbers.
00109          * This will require about 256KB of memory in the worst case (128KB for
00110          * each of IPv4 and IPv6).  We could reduce it by representing it as a
00111          * more sophisticated way such as a list (or array) of ranges that are
00112          * searched to identify a specific port.  Our decision here is the saved
00113          * memory isn't worth the implementation complexity, considering the
00114          * fact that the whole BIND9 process (which is mainly named) already
00115          * requires a pretty large memory footprint.  We may, however, have to
00116          * revisit the decision when we want to use it as a separate module for
00117          * an environment where memory requirement is severer.
00118          */
00119         in_port_t       *v4ports;       /*%< available ports for IPv4 */
00120         unsigned int    nv4ports;       /*%< # of available ports for IPv4 */
00121         in_port_t       *v6ports;       /*%< available ports for IPv4 */
00122         unsigned int    nv6ports;       /*%< # of available ports for IPv4 */
00123 };
00124 
00125 #define MGR_SHUTTINGDOWN                0x00000001U
00126 #define MGR_IS_SHUTTINGDOWN(l)  (((l)->state & MGR_SHUTTINGDOWN) != 0)
00127 
00128 #define IS_PRIVATE(d)   (((d)->attributes & DNS_DISPATCHATTR_PRIVATE) != 0)
00129 
00130 struct dns_dispentry {
00131         unsigned int                    magic;
00132         dns_dispatch_t                 *disp;
00133         dns_messageid_t                 id;
00134         in_port_t                       port;
00135         unsigned int                    bucket;
00136         isc_sockaddr_t                  host;
00137         isc_task_t                     *task;
00138         isc_taskaction_t                action;
00139         void                           *arg;
00140         isc_boolean_t                   item_out;
00141         dispsocket_t                    *dispsocket;
00142         ISC_LIST(dns_dispatchevent_t)   items;
00143         ISC_LINK(dns_dispentry_t)       link;
00144 };
00145 
00146 /*%
00147  * Maximum number of dispatch sockets that can be pooled for reuse.  The
00148  * appropriate value may vary, but experiments have shown a busy caching server
00149  * may need more than 1000 sockets concurrently opened.  The maximum allowable
00150  * number of dispatch sockets (per manager) will be set to the double of this
00151  * value.
00152  */
00153 #ifndef DNS_DISPATCH_POOLSOCKS
00154 #define DNS_DISPATCH_POOLSOCKS                  2048
00155 #endif
00156 
00157 /*%
00158  * Quota to control the number of dispatch sockets.  If a dispatch has more
00159  * than the quota of sockets, new queries will purge oldest ones, so that
00160  * a massive number of outstanding queries won't prevent subsequent queries
00161  * (especially if the older ones take longer time and result in timeout).
00162  */
00163 #ifndef DNS_DISPATCH_SOCKSQUOTA
00164 #define DNS_DISPATCH_SOCKSQUOTA                 3072
00165 #endif
00166 
00167 struct dispsocket {
00168         unsigned int                    magic;
00169         isc_socket_t                    *socket;
00170         dns_dispatch_t                  *disp;
00171         isc_sockaddr_t                  host;
00172         in_port_t                       localport; /* XXX: should be removed later */
00173         dispportentry_t                 *portentry;
00174         dns_dispentry_t                 *resp;
00175         isc_task_t                      *task;
00176         ISC_LINK(dispsocket_t)          link;
00177         unsigned int                    bucket;
00178         ISC_LINK(dispsocket_t)          blink;
00179 };
00180 
00181 /*%
00182  * A port table entry.  We remember every port we first open in a table with a
00183  * reference counter so that we can 'reuse' the same port (with different
00184  * destination addresses) using the SO_REUSEADDR socket option.
00185  */
00186 struct dispportentry {
00187         in_port_t                       port;
00188         unsigned int                    refs;
00189         ISC_LINK(struct dispportentry)  link;
00190 };
00191 
00192 #ifndef DNS_DISPATCH_PORTTABLESIZE
00193 #define DNS_DISPATCH_PORTTABLESIZE      1024
00194 #endif
00195 
00196 #define INVALID_BUCKET          (0xffffdead)
00197 
00198 /*%
00199  * Number of tasks for each dispatch that use separate sockets for different
00200  * transactions.  This must be a power of 2 as it will divide 32 bit numbers
00201  * to get an uniformly random tasks selection.  See get_dispsocket().
00202  */
00203 #define MAX_INTERNAL_TASKS      64
00204 
00205 struct dns_dispatch {
00206         /* Unlocked. */
00207         unsigned int            magic;          /*%< magic */
00208         dns_dispatchmgr_t      *mgr;            /*%< dispatch manager */
00209         int                     ntasks;
00210         /*%
00211          * internal task buckets.  We use multiple tasks to distribute various
00212          * socket events well when using separate dispatch sockets.  We use the
00213          * 1st task (task[0]) for internal control events.
00214          */
00215         isc_task_t             *task[MAX_INTERNAL_TASKS];
00216         isc_socket_t           *socket;         /*%< isc socket attached to */
00217         isc_sockaddr_t          local;          /*%< local address */
00218         in_port_t               localport;      /*%< local UDP port */
00219         isc_sockaddr_t          peer;           /*%< peer address (TCP) */
00220         isc_dscp_t              dscp;           /*%< "listen-on" DSCP value */
00221         unsigned int            maxrequests;    /*%< max requests */
00222         isc_event_t            *ctlevent;
00223 
00224         isc_mutex_t             sepool_lock;
00225         isc_mempool_t          *sepool;         /*%< pool for socket events */
00226 
00227         /*% Locked by mgr->lock. */
00228         ISC_LINK(dns_dispatch_t) link;
00229 
00230         /* Locked by "lock". */
00231         isc_mutex_t             lock;           /*%< locks all below */
00232         isc_sockettype_t        socktype;
00233         unsigned int            attributes;
00234         unsigned int            refcount;       /*%< number of users */
00235         dns_dispatchevent_t    *failsafe_ev;    /*%< failsafe cancel event */
00236         unsigned int            shutting_down : 1,
00237                                 shutdown_out : 1,
00238                                 connected : 1,
00239                                 tcpmsg_valid : 1,
00240                                 recv_pending : 1; /*%< is a recv() pending? */
00241         isc_result_t            shutdown_why;
00242         ISC_LIST(dispsocket_t)  activesockets;
00243         ISC_LIST(dispsocket_t)  inactivesockets;
00244         unsigned int            nsockets;
00245         unsigned int            requests;       /*%< how many requests we have */
00246         unsigned int            tcpbuffers;     /*%< allocated buffers */
00247         dns_tcpmsg_t            tcpmsg;         /*%< for tcp streams */
00248         dns_qid_t               *qid;
00249         isc_rng_t               *rngctx;        /*%< for QID/UDP port num */
00250         dispportlist_t          *port_table;    /*%< hold ports 'owned' by us */
00251         isc_mempool_t           *portpool;      /*%< port table entries  */
00252 };
00253 
00254 #define QID_MAGIC               ISC_MAGIC('Q', 'i', 'd', ' ')
00255 #define VALID_QID(e)            ISC_MAGIC_VALID((e), QID_MAGIC)
00256 
00257 #define RESPONSE_MAGIC          ISC_MAGIC('D', 'r', 's', 'p')
00258 #define VALID_RESPONSE(e)       ISC_MAGIC_VALID((e), RESPONSE_MAGIC)
00259 
00260 #define DISPSOCK_MAGIC          ISC_MAGIC('D', 's', 'o', 'c')
00261 #define VALID_DISPSOCK(e)       ISC_MAGIC_VALID((e), DISPSOCK_MAGIC)
00262 
00263 #define DISPATCH_MAGIC          ISC_MAGIC('D', 'i', 's', 'p')
00264 #define VALID_DISPATCH(e)       ISC_MAGIC_VALID((e), DISPATCH_MAGIC)
00265 
00266 #define DNS_DISPATCHMGR_MAGIC   ISC_MAGIC('D', 'M', 'g', 'r')
00267 #define VALID_DISPATCHMGR(e)    ISC_MAGIC_VALID((e), DNS_DISPATCHMGR_MAGIC)
00268 
00269 #define DNS_QID(disp) ((disp)->socktype == isc_sockettype_tcp) ? \
00270                        (disp)->qid : (disp)->mgr->qid
00271 #define DISP_RNGCTX(disp) ((disp)->socktype == isc_sockettype_udp) ? \
00272                         ((disp)->rngctx) : ((disp)->mgr->rngctx)
00273 
00274 /*%
00275  * Locking a query port buffer is a bit tricky.  We access the buffer without
00276  * locking until qid is created.  Technically, there is a possibility of race
00277  * between the creation of qid and access to the port buffer; in practice,
00278  * however, this should be safe because qid isn't created until the first
00279  * dispatch is created and there should be no contending situation until then.
00280  */
00281 #define PORTBUFLOCK(mgr) if ((mgr)->qid != NULL) LOCK(&((mgr)->qid->lock))
00282 #define PORTBUFUNLOCK(mgr) if ((mgr)->qid != NULL) UNLOCK((&(mgr)->qid->lock))
00283 
00284 /*
00285  * Statics.
00286  */
00287 static dns_dispentry_t *entry_search(dns_qid_t *, isc_sockaddr_t *,
00288                                      dns_messageid_t, in_port_t, unsigned int);
00289 static isc_boolean_t destroy_disp_ok(dns_dispatch_t *);
00290 static void destroy_disp(isc_task_t *task, isc_event_t *event);
00291 static void destroy_dispsocket(dns_dispatch_t *, dispsocket_t **);
00292 static void deactivate_dispsocket(dns_dispatch_t *, dispsocket_t *);
00293 static void udp_exrecv(isc_task_t *, isc_event_t *);
00294 static void udp_shrecv(isc_task_t *, isc_event_t *);
00295 static void udp_recv(isc_event_t *, dns_dispatch_t *, dispsocket_t *);
00296 static void tcp_recv(isc_task_t *, isc_event_t *);
00297 static isc_result_t startrecv(dns_dispatch_t *, dispsocket_t *);
00298 static isc_uint32_t dns_hash(dns_qid_t *, isc_sockaddr_t *, dns_messageid_t,
00299                              in_port_t);
00300 static void free_buffer(dns_dispatch_t *disp, void *buf, unsigned int len);
00301 static void *allocate_udp_buffer(dns_dispatch_t *disp);
00302 static inline void free_devent(dns_dispatch_t *disp, dns_dispatchevent_t *ev);
00303 static inline dns_dispatchevent_t *allocate_devent(dns_dispatch_t *disp);
00304 static void do_cancel(dns_dispatch_t *disp);
00305 static dns_dispentry_t *linear_first(dns_qid_t *disp);
00306 static dns_dispentry_t *linear_next(dns_qid_t *disp,
00307                                     dns_dispentry_t *resp);
00308 static void dispatch_free(dns_dispatch_t **dispp);
00309 static isc_result_t get_udpsocket(dns_dispatchmgr_t *mgr,
00310                                   dns_dispatch_t *disp,
00311                                   isc_socketmgr_t *sockmgr,
00312                                   isc_sockaddr_t *localaddr,
00313                                   isc_socket_t **sockp,
00314                                   isc_socket_t *dup_socket);
00315 static isc_result_t dispatch_createudp(dns_dispatchmgr_t *mgr,
00316                                        isc_socketmgr_t *sockmgr,
00317                                        isc_taskmgr_t *taskmgr,
00318                                        isc_sockaddr_t *localaddr,
00319                                        unsigned int maxrequests,
00320                                        unsigned int attributes,
00321                                        dns_dispatch_t **dispp,
00322                                        isc_socket_t *dup_socket);
00323 static isc_boolean_t destroy_mgr_ok(dns_dispatchmgr_t *mgr);
00324 static void destroy_mgr(dns_dispatchmgr_t **mgrp);
00325 static isc_result_t qid_allocate(dns_dispatchmgr_t *mgr, unsigned int buckets,
00326                                  unsigned int increment, dns_qid_t **qidp,
00327                                  isc_boolean_t needaddrtable);
00328 static void qid_destroy(isc_mem_t *mctx, dns_qid_t **qidp);
00329 static isc_result_t open_socket(isc_socketmgr_t *mgr, isc_sockaddr_t *local,
00330                                 unsigned int options, isc_socket_t **sockp,
00331                                 isc_socket_t *dup_socket);
00332 static isc_boolean_t portavailable(dns_dispatchmgr_t *mgr, isc_socket_t *sock,
00333                                    isc_sockaddr_t *sockaddrp);
00334 
00335 #define LVL(x) ISC_LOG_DEBUG(x)
00336 
00337 static void
00338 mgr_log(dns_dispatchmgr_t *mgr, int level, const char *fmt, ...)
00339      ISC_FORMAT_PRINTF(3, 4);
00340 
00341 static void
00342 mgr_log(dns_dispatchmgr_t *mgr, int level, const char *fmt, ...) {
00343         char msgbuf[2048];
00344         va_list ap;
00345 
00346         if (! isc_log_wouldlog(dns_lctx, level))
00347                 return;
00348 
00349         va_start(ap, fmt);
00350         vsnprintf(msgbuf, sizeof(msgbuf), fmt, ap);
00351         va_end(ap);
00352 
00353         isc_log_write(dns_lctx,
00354                       DNS_LOGCATEGORY_DISPATCH, DNS_LOGMODULE_DISPATCH,
00355                       level, "dispatchmgr %p: %s", mgr, msgbuf);
00356 }
00357 
00358 static inline void
00359 inc_stats(dns_dispatchmgr_t *mgr, isc_statscounter_t counter) {
00360         if (mgr->stats != NULL)
00361                 isc_stats_increment(mgr->stats, counter);
00362 }
00363 
00364 static inline void
00365 dec_stats(dns_dispatchmgr_t *mgr, isc_statscounter_t counter) {
00366         if (mgr->stats != NULL)
00367                 isc_stats_decrement(mgr->stats, counter);
00368 }
00369 
00370 static void
00371 dispatch_log(dns_dispatch_t *disp, int level, const char *fmt, ...)
00372      ISC_FORMAT_PRINTF(3, 4);
00373 
00374 static void
00375 dispatch_log(dns_dispatch_t *disp, int level, const char *fmt, ...) {
00376         char msgbuf[2048];
00377         va_list ap;
00378 
00379         if (! isc_log_wouldlog(dns_lctx, level))
00380                 return;
00381 
00382         va_start(ap, fmt);
00383         vsnprintf(msgbuf, sizeof(msgbuf), fmt, ap);
00384         va_end(ap);
00385 
00386         isc_log_write(dns_lctx,
00387                       DNS_LOGCATEGORY_DISPATCH, DNS_LOGMODULE_DISPATCH,
00388                       level, "dispatch %p: %s", disp, msgbuf);
00389 }
00390 
00391 static void
00392 request_log(dns_dispatch_t *disp, dns_dispentry_t *resp,
00393             int level, const char *fmt, ...)
00394      ISC_FORMAT_PRINTF(4, 5);
00395 
00396 static void
00397 request_log(dns_dispatch_t *disp, dns_dispentry_t *resp,
00398             int level, const char *fmt, ...)
00399 {
00400         char msgbuf[2048];
00401         char peerbuf[256];
00402         va_list ap;
00403 
00404         if (! isc_log_wouldlog(dns_lctx, level))
00405                 return;
00406 
00407         va_start(ap, fmt);
00408         vsnprintf(msgbuf, sizeof(msgbuf), fmt, ap);
00409         va_end(ap);
00410 
00411         if (VALID_RESPONSE(resp)) {
00412                 isc_sockaddr_format(&resp->host, peerbuf, sizeof(peerbuf));
00413                 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DISPATCH,
00414                               DNS_LOGMODULE_DISPATCH, level,
00415                               "dispatch %p response %p %s: %s", disp, resp,
00416                               peerbuf, msgbuf);
00417         } else {
00418                 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DISPATCH,
00419                               DNS_LOGMODULE_DISPATCH, level,
00420                               "dispatch %p req/resp %p: %s", disp, resp,
00421                               msgbuf);
00422         }
00423 }
00424 
00425 /*
00426  * Return a hash of the destination and message id.
00427  */
00428 static isc_uint32_t
00429 dns_hash(dns_qid_t *qid, isc_sockaddr_t *dest, dns_messageid_t id,
00430          in_port_t port)
00431 {
00432         unsigned int ret;
00433 
00434         ret = isc_sockaddr_hash(dest, ISC_TRUE);
00435         ret ^= (id << 16) | port;
00436         ret %= qid->qid_nbuckets;
00437 
00438         INSIST(ret < qid->qid_nbuckets);
00439 
00440         return (ret);
00441 }
00442 
00443 /*
00444  * Find the first entry in 'qid'.  Returns NULL if there are no entries.
00445  */
00446 static dns_dispentry_t *
00447 linear_first(dns_qid_t *qid) {
00448         dns_dispentry_t *ret;
00449         unsigned int bucket;
00450 
00451         bucket = 0;
00452 
00453         while (bucket < qid->qid_nbuckets) {
00454                 ret = ISC_LIST_HEAD(qid->qid_table[bucket]);
00455                 if (ret != NULL)
00456                         return (ret);
00457                 bucket++;
00458         }
00459 
00460         return (NULL);
00461 }
00462 
00463 /*
00464  * Find the next entry after 'resp' in 'qid'.  Return NULL if there are
00465  * no more entries.
00466  */
00467 static dns_dispentry_t *
00468 linear_next(dns_qid_t *qid, dns_dispentry_t *resp) {
00469         dns_dispentry_t *ret;
00470         unsigned int bucket;
00471 
00472         ret = ISC_LIST_NEXT(resp, link);
00473         if (ret != NULL)
00474                 return (ret);
00475 
00476         bucket = resp->bucket;
00477         bucket++;
00478         while (bucket < qid->qid_nbuckets) {
00479                 ret = ISC_LIST_HEAD(qid->qid_table[bucket]);
00480                 if (ret != NULL)
00481                         return (ret);
00482                 bucket++;
00483         }
00484 
00485         return (NULL);
00486 }
00487 
00488 /*
00489  * The dispatch must be locked.
00490  */
00491 static isc_boolean_t
00492 destroy_disp_ok(dns_dispatch_t *disp)
00493 {
00494         if (disp->refcount != 0)
00495                 return (ISC_FALSE);
00496 
00497         if (disp->recv_pending != 0)
00498                 return (ISC_FALSE);
00499 
00500         if (!ISC_LIST_EMPTY(disp->activesockets))
00501                 return (ISC_FALSE);
00502 
00503         if (disp->shutting_down == 0)
00504                 return (ISC_FALSE);
00505 
00506         return (ISC_TRUE);
00507 }
00508 
00509 /*
00510  * Called when refcount reaches 0 (and safe to destroy).
00511  *
00512  * The dispatcher must be locked.
00513  * The manager must not be locked.
00514  */
00515 static void
00516 destroy_disp(isc_task_t *task, isc_event_t *event) {
00517         dns_dispatch_t *disp;
00518         dns_dispatchmgr_t *mgr;
00519         isc_boolean_t killmgr;
00520         dispsocket_t *dispsocket;
00521         int i;
00522 
00523         INSIST(event->ev_type == DNS_EVENT_DISPATCHCONTROL);
00524 
00525         UNUSED(task);
00526 
00527         disp = event->ev_arg;
00528         mgr = disp->mgr;
00529 
00530         LOCK(&mgr->lock);
00531         ISC_LIST_UNLINK(mgr->list, disp, link);
00532 
00533         dispatch_log(disp, LVL(90),
00534                      "shutting down; detaching from sock %p, task %p",
00535                      disp->socket, disp->task[0]); /* XXXX */
00536 
00537         if (disp->sepool != NULL) {
00538                 isc_mempool_destroy(&disp->sepool);
00539                 (void)isc_mutex_destroy(&disp->sepool_lock);
00540         }
00541 
00542         if (disp->socket != NULL)
00543                 isc_socket_detach(&disp->socket);
00544         while ((dispsocket = ISC_LIST_HEAD(disp->inactivesockets)) != NULL) {
00545                 ISC_LIST_UNLINK(disp->inactivesockets, dispsocket, link);
00546                 destroy_dispsocket(disp, &dispsocket);
00547         }
00548         for (i = 0; i < disp->ntasks; i++)
00549                 isc_task_detach(&disp->task[i]);
00550         isc_event_free(&event);
00551 
00552         dispatch_free(&disp);
00553 
00554         killmgr = destroy_mgr_ok(mgr);
00555         UNLOCK(&mgr->lock);
00556         if (killmgr)
00557                 destroy_mgr(&mgr);
00558 }
00559 
00560 /*%
00561  * Manipulate port table per dispatch: find an entry for a given port number,
00562  * create a new entry, and decrement a given entry with possible clean-up.
00563  */
00564 static dispportentry_t *
00565 port_search(dns_dispatch_t *disp, in_port_t port) {
00566         dispportentry_t *portentry;
00567 
00568         REQUIRE(disp->port_table != NULL);
00569 
00570         portentry = ISC_LIST_HEAD(disp->port_table[port %
00571                                                    DNS_DISPATCH_PORTTABLESIZE]);
00572         while (portentry != NULL) {
00573                 if (portentry->port == port)
00574                         return (portentry);
00575                 portentry = ISC_LIST_NEXT(portentry, link);
00576         }
00577 
00578         return (NULL);
00579 }
00580 
00581 static dispportentry_t *
00582 new_portentry(dns_dispatch_t *disp, in_port_t port) {
00583         dispportentry_t *portentry;
00584         dns_qid_t *qid;
00585 
00586         REQUIRE(disp->port_table != NULL);
00587 
00588         portentry = isc_mempool_get(disp->portpool);
00589         if (portentry == NULL)
00590                 return (portentry);
00591 
00592         portentry->port = port;
00593         portentry->refs = 1;
00594         ISC_LINK_INIT(portentry, link);
00595         qid = DNS_QID(disp);
00596         LOCK(&qid->lock);
00597         ISC_LIST_APPEND(disp->port_table[port % DNS_DISPATCH_PORTTABLESIZE],
00598                         portentry, link);
00599         UNLOCK(&qid->lock);
00600 
00601         return (portentry);
00602 }
00603 
00604 /*%
00605  * The caller must not hold the qid->lock.
00606  */
00607 static void
00608 deref_portentry(dns_dispatch_t *disp, dispportentry_t **portentryp) {
00609         dispportentry_t *portentry = *portentryp;
00610         dns_qid_t *qid;
00611 
00612         REQUIRE(disp->port_table != NULL);
00613         REQUIRE(portentry != NULL && portentry->refs > 0);
00614 
00615         qid = DNS_QID(disp);
00616         LOCK(&qid->lock);
00617         portentry->refs--;
00618 
00619         if (portentry->refs == 0) {
00620                 ISC_LIST_UNLINK(disp->port_table[portentry->port %
00621                                                  DNS_DISPATCH_PORTTABLESIZE],
00622                                 portentry, link);
00623                 isc_mempool_put(disp->portpool, portentry);
00624         }
00625 
00626         /*
00627          * Set '*portentryp' to NULL inside the lock so that
00628          * dispsock->portentry does not change in socket_search.
00629          */
00630         *portentryp = NULL;
00631 
00632         UNLOCK(&qid->lock);
00633 }
00634 
00635 /*%
00636  * Find a dispsocket for socket address 'dest', and port number 'port'.
00637  * Return NULL if no such entry exists.  Requires qid->lock to be held.
00638  */
00639 static dispsocket_t *
00640 socket_search(dns_qid_t *qid, isc_sockaddr_t *dest, in_port_t port,
00641               unsigned int bucket)
00642 {
00643         dispsocket_t *dispsock;
00644 
00645         REQUIRE(VALID_QID(qid));
00646         REQUIRE(bucket < qid->qid_nbuckets);
00647 
00648         dispsock = ISC_LIST_HEAD(qid->sock_table[bucket]);
00649 
00650         while (dispsock != NULL) {
00651                 if (dispsock->portentry != NULL &&
00652                     dispsock->portentry->port == port &&
00653                     isc_sockaddr_equal(dest, &dispsock->host))
00654                         return (dispsock);
00655                 dispsock = ISC_LIST_NEXT(dispsock, blink);
00656         }
00657 
00658         return (NULL);
00659 }
00660 
00661 /*%
00662  * Make a new socket for a single dispatch with a random port number.
00663  * The caller must hold the disp->lock
00664  */
00665 static isc_result_t
00666 get_dispsocket(dns_dispatch_t *disp, isc_sockaddr_t *dest,
00667                isc_socketmgr_t *sockmgr, dispsocket_t **dispsockp,
00668                in_port_t *portp)
00669 {
00670         int i;
00671         isc_uint32_t r;
00672         dns_dispatchmgr_t *mgr = disp->mgr;
00673         isc_socket_t *sock = NULL;
00674         isc_result_t result = ISC_R_FAILURE;
00675         in_port_t port;
00676         isc_sockaddr_t localaddr;
00677         unsigned int bucket = 0;
00678         dispsocket_t *dispsock;
00679         unsigned int nports;
00680         in_port_t *ports;
00681         unsigned int bindoptions;
00682         dispportentry_t *portentry = NULL;
00683         dns_qid_t *qid;
00684 
00685         if (isc_sockaddr_pf(&disp->local) == AF_INET) {
00686                 nports = disp->mgr->nv4ports;
00687                 ports = disp->mgr->v4ports;
00688         } else {
00689                 nports = disp->mgr->nv6ports;
00690                 ports = disp->mgr->v6ports;
00691         }
00692         if (nports == 0)
00693                 return (ISC_R_ADDRNOTAVAIL);
00694 
00695         dispsock = ISC_LIST_HEAD(disp->inactivesockets);
00696         if (dispsock != NULL) {
00697                 ISC_LIST_UNLINK(disp->inactivesockets, dispsock, link);
00698                 sock = dispsock->socket;
00699                 dispsock->socket = NULL;
00700         } else {
00701                 dispsock = isc_mempool_get(mgr->spool);
00702                 if (dispsock == NULL)
00703                         return (ISC_R_NOMEMORY);
00704 
00705                 disp->nsockets++;
00706                 dispsock->socket = NULL;
00707                 dispsock->disp = disp;
00708                 dispsock->resp = NULL;
00709                 dispsock->portentry = NULL;
00710                 isc_random_get(&r);
00711                 dispsock->task = NULL;
00712                 isc_task_attach(disp->task[r % disp->ntasks], &dispsock->task);
00713                 ISC_LINK_INIT(dispsock, link);
00714                 ISC_LINK_INIT(dispsock, blink);
00715                 dispsock->magic = DISPSOCK_MAGIC;
00716         }
00717 
00718         /*
00719          * Pick up a random UDP port and open a new socket with it.  Avoid
00720          * choosing ports that share the same destination because it will be
00721          * very likely to fail in bind(2) or connect(2).
00722          */
00723         localaddr = disp->local;
00724         qid = DNS_QID(disp);
00725 
00726         for (i = 0; i < 64; i++) {
00727                 port = ports[isc_rng_uniformrandom(DISP_RNGCTX(disp), nports)];
00728                 isc_sockaddr_setport(&localaddr, port);
00729 
00730                 LOCK(&qid->lock);
00731                 bucket = dns_hash(qid, dest, 0, port);
00732                 if (socket_search(qid, dest, port, bucket) != NULL) {
00733                         UNLOCK(&qid->lock);
00734                         continue;
00735                 }
00736                 UNLOCK(&qid->lock);
00737                 bindoptions = 0;
00738                 portentry = port_search(disp, port);
00739 
00740                 if (portentry != NULL)
00741                         bindoptions |= ISC_SOCKET_REUSEADDRESS;
00742                 result = open_socket(sockmgr, &localaddr, bindoptions, &sock,
00743                                      NULL);
00744                 if (result == ISC_R_SUCCESS) {
00745                         if (portentry == NULL) {
00746                                 portentry = new_portentry(disp, port);
00747                                 if (portentry == NULL) {
00748                                         result = ISC_R_NOMEMORY;
00749                                         break;
00750                                 }
00751                         } else {
00752                                 LOCK(&qid->lock);
00753                                 portentry->refs++;
00754                                 UNLOCK(&qid->lock);
00755                         }
00756                         break;
00757                 } else if (result == ISC_R_NOPERM) {
00758                         char buf[ISC_SOCKADDR_FORMATSIZE];
00759                         isc_sockaddr_format(&localaddr, buf, sizeof(buf));
00760                         dispatch_log(disp, ISC_LOG_WARNING,
00761                                      "open_socket(%s) -> %s: continuing",
00762                                      buf, isc_result_totext(result));
00763                 } else if (result != ISC_R_ADDRINUSE)
00764                         break;
00765         }
00766 
00767         if (result == ISC_R_SUCCESS) {
00768                 dispsock->socket = sock;
00769                 dispsock->host = *dest;
00770                 dispsock->portentry = portentry;
00771                 dispsock->bucket = bucket;
00772                 LOCK(&qid->lock);
00773                 ISC_LIST_APPEND(qid->sock_table[bucket], dispsock, blink);
00774                 UNLOCK(&qid->lock);
00775                 *dispsockp = dispsock;
00776                 *portp = port;
00777         } else {
00778                 /*
00779                  * We could keep it in the inactive list, but since this should
00780                  * be an exceptional case and might be resource shortage, we'd
00781                  * rather destroy it.
00782                  */
00783                 if (sock != NULL)
00784                         isc_socket_detach(&sock);
00785                 destroy_dispsocket(disp, &dispsock);
00786         }
00787 
00788         return (result);
00789 }
00790 
00791 /*%
00792  * Destroy a dedicated dispatch socket.
00793  */
00794 static void
00795 destroy_dispsocket(dns_dispatch_t *disp, dispsocket_t **dispsockp) {
00796         dispsocket_t *dispsock;
00797         dns_qid_t *qid;
00798 
00799         /*
00800          * The dispatch must be locked.
00801          */
00802 
00803         REQUIRE(dispsockp != NULL && *dispsockp != NULL);
00804         dispsock = *dispsockp;
00805         REQUIRE(!ISC_LINK_LINKED(dispsock, link));
00806 
00807         disp->nsockets--;
00808         dispsock->magic = 0;
00809         if (dispsock->portentry != NULL)
00810                 deref_portentry(disp, &dispsock->portentry);
00811         if (dispsock->socket != NULL)
00812                 isc_socket_detach(&dispsock->socket);
00813         if (ISC_LINK_LINKED(dispsock, blink)) {
00814                 qid = DNS_QID(disp);
00815                 LOCK(&qid->lock);
00816                 ISC_LIST_UNLINK(qid->sock_table[dispsock->bucket], dispsock,
00817                                 blink);
00818                 UNLOCK(&qid->lock);
00819         }
00820         if (dispsock->task != NULL)
00821                 isc_task_detach(&dispsock->task);
00822         isc_mempool_put(disp->mgr->spool, dispsock);
00823 
00824         *dispsockp = NULL;
00825 }
00826 
00827 /*%
00828  * Deactivate a dedicated dispatch socket.  Move it to the inactive list for
00829  * future reuse unless the total number of sockets are exceeding the maximum.
00830  */
00831 static void
00832 deactivate_dispsocket(dns_dispatch_t *disp, dispsocket_t *dispsock) {
00833         isc_result_t result;
00834         dns_qid_t *qid;
00835 
00836         /*
00837          * The dispatch must be locked.
00838          */
00839         ISC_LIST_UNLINK(disp->activesockets, dispsock, link);
00840         if (dispsock->resp != NULL) {
00841                 INSIST(dispsock->resp->dispsocket == dispsock);
00842                 dispsock->resp->dispsocket = NULL;
00843         }
00844 
00845         INSIST(dispsock->portentry != NULL);
00846         deref_portentry(disp, &dispsock->portentry);
00847 
00848         if (disp->nsockets > DNS_DISPATCH_POOLSOCKS)
00849                 destroy_dispsocket(disp, &dispsock);
00850         else {
00851                 result = isc_socket_close(dispsock->socket);
00852 
00853                 qid = DNS_QID(disp);
00854                 LOCK(&qid->lock);
00855                 ISC_LIST_UNLINK(qid->sock_table[dispsock->bucket], dispsock,
00856                                 blink);
00857                 UNLOCK(&qid->lock);
00858 
00859                 if (result == ISC_R_SUCCESS)
00860                         ISC_LIST_APPEND(disp->inactivesockets, dispsock, link);
00861                 else {
00862                         /*
00863                          * If the underlying system does not allow this
00864                          * optimization, destroy this temporary structure (and
00865                          * create a new one for a new transaction).
00866                          */
00867                         INSIST(result == ISC_R_NOTIMPLEMENTED);
00868                         destroy_dispsocket(disp, &dispsock);
00869                 }
00870         }
00871 }
00872 
00873 /*
00874  * Find an entry for query ID 'id', socket address 'dest', and port number
00875  * 'port'.
00876  * Return NULL if no such entry exists.
00877  */
00878 static dns_dispentry_t *
00879 entry_search(dns_qid_t *qid, isc_sockaddr_t *dest, dns_messageid_t id,
00880              in_port_t port, unsigned int bucket)
00881 {
00882         dns_dispentry_t *res;
00883 
00884         REQUIRE(VALID_QID(qid));
00885         REQUIRE(bucket < qid->qid_nbuckets);
00886 
00887         res = ISC_LIST_HEAD(qid->qid_table[bucket]);
00888 
00889         while (res != NULL) {
00890                 if (res->id == id && isc_sockaddr_equal(dest, &res->host) &&
00891                     res->port == port) {
00892                         return (res);
00893                 }
00894                 res = ISC_LIST_NEXT(res, link);
00895         }
00896 
00897         return (NULL);
00898 }
00899 
00900 static void
00901 free_buffer(dns_dispatch_t *disp, void *buf, unsigned int len) {
00902         isc_mempool_t *bpool;
00903         INSIST(buf != NULL && len != 0);
00904 
00905 
00906         switch (disp->socktype) {
00907         case isc_sockettype_tcp:
00908                 INSIST(disp->tcpbuffers > 0);
00909                 disp->tcpbuffers--;
00910                 isc_mem_put(disp->mgr->mctx, buf, len);
00911                 break;
00912         case isc_sockettype_udp:
00913                 LOCK(&disp->mgr->buffer_lock);
00914                 INSIST(disp->mgr->buffers > 0);
00915                 INSIST(len == disp->mgr->buffersize);
00916                 disp->mgr->buffers--;
00917                 bpool = disp->mgr->bpool;
00918                 UNLOCK(&disp->mgr->buffer_lock);
00919                 isc_mempool_put(bpool, buf);
00920                 break;
00921         default:
00922                 INSIST(0);
00923                 break;
00924         }
00925 }
00926 
00927 static void *
00928 allocate_udp_buffer(dns_dispatch_t *disp) {
00929         isc_mempool_t *bpool;
00930         void *temp;
00931 
00932         LOCK(&disp->mgr->buffer_lock);
00933         bpool = disp->mgr->bpool;
00934         disp->mgr->buffers++;
00935         UNLOCK(&disp->mgr->buffer_lock);
00936 
00937         temp = isc_mempool_get(bpool);
00938 
00939         if (temp == NULL) {
00940                 LOCK(&disp->mgr->buffer_lock);
00941                 disp->mgr->buffers--;
00942                 UNLOCK(&disp->mgr->buffer_lock);
00943         }
00944 
00945         return (temp);
00946 }
00947 
00948 static inline void
00949 free_sevent(isc_event_t *ev) {
00950         isc_mempool_t *pool = ev->ev_destroy_arg;
00951         isc_socketevent_t *sev = (isc_socketevent_t *) ev;
00952         isc_mempool_put(pool, sev);
00953 }
00954 
00955 static inline isc_socketevent_t *
00956 allocate_sevent(dns_dispatch_t *disp, isc_socket_t *sock,
00957                 isc_eventtype_t type, isc_taskaction_t action, const void *arg)
00958 {
00959         isc_socketevent_t *ev;
00960         void *deconst_arg;
00961 
00962         ev = isc_mempool_get(disp->sepool);
00963         if (ev == NULL)
00964                 return (NULL);
00965         DE_CONST(arg, deconst_arg);
00966         ISC_EVENT_INIT(ev, sizeof(*ev), 0, NULL, type,
00967                        action, deconst_arg, sock,
00968                        free_sevent, disp->sepool);
00969         ev->result = ISC_R_UNSET;
00970         ISC_LINK_INIT(ev, ev_link);
00971         ISC_LIST_INIT(ev->bufferlist);
00972         ev->region.base = NULL;
00973         ev->n = 0;
00974         ev->offset = 0;
00975         ev->attributes = 0;
00976 
00977         return (ev);
00978 }
00979 
00980 
00981 static inline void
00982 free_devent(dns_dispatch_t *disp, dns_dispatchevent_t *ev) {
00983         if (disp->failsafe_ev == ev) {
00984                 INSIST(disp->shutdown_out == 1);
00985                 disp->shutdown_out = 0;
00986 
00987                 return;
00988         }
00989 
00990         isc_mempool_put(disp->mgr->depool, ev);
00991 }
00992 
00993 static inline dns_dispatchevent_t *
00994 allocate_devent(dns_dispatch_t *disp) {
00995         dns_dispatchevent_t *ev;
00996 
00997         ev = isc_mempool_get(disp->mgr->depool);
00998         if (ev == NULL)
00999                 return (NULL);
01000         ISC_EVENT_INIT(ev, sizeof(*ev), 0, NULL, 0,
01001                        NULL, NULL, NULL, NULL, NULL);
01002 
01003         return (ev);
01004 }
01005 
01006 static void
01007 udp_exrecv(isc_task_t *task, isc_event_t *ev) {
01008         dispsocket_t *dispsock = ev->ev_arg;
01009 
01010         UNUSED(task);
01011 
01012         REQUIRE(VALID_DISPSOCK(dispsock));
01013         udp_recv(ev, dispsock->disp, dispsock);
01014 }
01015 
01016 static void
01017 udp_shrecv(isc_task_t *task, isc_event_t *ev) {
01018         dns_dispatch_t *disp = ev->ev_arg;
01019 
01020         UNUSED(task);
01021 
01022         REQUIRE(VALID_DISPATCH(disp));
01023         udp_recv(ev, disp, NULL);
01024 }
01025 
01026 /*
01027  * General flow:
01028  *
01029  * If I/O result == CANCELED or error, free the buffer.
01030  *
01031  * If query, free the buffer, restart.
01032  *
01033  * If response:
01034  *      Allocate event, fill in details.
01035  *              If cannot allocate, free buffer, restart.
01036  *      find target.  If not found, free buffer, restart.
01037  *      if event queue is not empty, queue.  else, send.
01038  *      restart.
01039  */
01040 static void
01041 udp_recv(isc_event_t *ev_in, dns_dispatch_t *disp, dispsocket_t *dispsock) {
01042         isc_socketevent_t *ev = (isc_socketevent_t *)ev_in;
01043         dns_messageid_t id;
01044         isc_result_t dres;
01045         isc_buffer_t source;
01046         unsigned int flags;
01047         dns_dispentry_t *resp = NULL;
01048         dns_dispatchevent_t *rev;
01049         unsigned int bucket;
01050         isc_boolean_t killit;
01051         isc_boolean_t queue_response;
01052         dns_dispatchmgr_t *mgr;
01053         dns_qid_t *qid;
01054         isc_netaddr_t netaddr;
01055         int match;
01056         int result;
01057         isc_boolean_t qidlocked = ISC_FALSE;
01058 
01059         LOCK(&disp->lock);
01060 
01061         mgr = disp->mgr;
01062         qid = mgr->qid;
01063 
01064         dispatch_log(disp, LVL(90),
01065                      "got packet: requests %d, buffers %d, recvs %d",
01066                      disp->requests, disp->mgr->buffers, disp->recv_pending);
01067 
01068         if (dispsock == NULL && ev->ev_type == ISC_SOCKEVENT_RECVDONE) {
01069                 /*
01070                  * Unless the receive event was imported from a listening
01071                  * interface, in which case the event type is
01072                  * DNS_EVENT_IMPORTRECVDONE, receive operation must be pending.
01073                  */
01074                 INSIST(disp->recv_pending != 0);
01075                 disp->recv_pending = 0;
01076         }
01077 
01078         if (dispsock != NULL &&
01079             (ev->result == ISC_R_CANCELED || dispsock->resp == NULL)) {
01080                 /*
01081                  * dispsock->resp can be NULL if this transaction was canceled
01082                  * just after receiving a response.  Since this socket is
01083                  * exclusively used and there should be at most one receive
01084                  * event the canceled event should have been no effect.  So
01085                  * we can (and should) deactivate the socket right now.
01086                  */
01087                 deactivate_dispsocket(disp, dispsock);
01088                 dispsock = NULL;
01089         }
01090 
01091         if (disp->shutting_down) {
01092                 /*
01093                  * This dispatcher is shutting down.
01094                  */
01095                 free_buffer(disp, ev->region.base, ev->region.length);
01096 
01097                 isc_event_free(&ev_in);
01098                 ev = NULL;
01099 
01100                 killit = destroy_disp_ok(disp);
01101                 UNLOCK(&disp->lock);
01102                 if (killit)
01103                         isc_task_send(disp->task[0], &disp->ctlevent);
01104 
01105                 return;
01106         }
01107 
01108         if ((disp->attributes & DNS_DISPATCHATTR_EXCLUSIVE) != 0) {
01109                 if (dispsock != NULL) {
01110                         resp = dispsock->resp;
01111                         id = resp->id;
01112                         if (ev->result != ISC_R_SUCCESS) {
01113                                 /*
01114                                  * This is most likely a network error on a
01115                                  * connected socket.  It makes no sense to
01116                                  * check the address or parse the packet, but it
01117                                  * will help to return the error to the caller.
01118                                  */
01119                                 goto sendresponse;
01120                         }
01121                 } else {
01122                         free_buffer(disp, ev->region.base, ev->region.length);
01123 
01124                         isc_event_free(&ev_in);
01125                         UNLOCK(&disp->lock);
01126                         return;
01127                 }
01128         } else if (ev->result != ISC_R_SUCCESS) {
01129                 free_buffer(disp, ev->region.base, ev->region.length);
01130 
01131                 if (ev->result != ISC_R_CANCELED)
01132                         dispatch_log(disp, ISC_LOG_ERROR,
01133                                      "odd socket result in udp_recv(): %s",
01134                                      isc_result_totext(ev->result));
01135 
01136                 isc_event_free(&ev_in);
01137                 UNLOCK(&disp->lock);
01138                 return;
01139         }
01140 
01141         /*
01142          * If this is from a blackholed address, drop it.
01143          */
01144         isc_netaddr_fromsockaddr(&netaddr, &ev->address);
01145         if (disp->mgr->blackhole != NULL &&
01146             dns_acl_match(&netaddr, NULL, disp->mgr->blackhole,
01147                           NULL, &match, NULL) == ISC_R_SUCCESS &&
01148             match > 0)
01149         {
01150                 if (isc_log_wouldlog(dns_lctx, LVL(10))) {
01151                         char netaddrstr[ISC_NETADDR_FORMATSIZE];
01152                         isc_netaddr_format(&netaddr, netaddrstr,
01153                                            sizeof(netaddrstr));
01154                         dispatch_log(disp, LVL(10),
01155                                      "blackholed packet from %s",
01156                                      netaddrstr);
01157                 }
01158                 free_buffer(disp, ev->region.base, ev->region.length);
01159                 goto restart;
01160         }
01161 
01162         /*
01163          * Peek into the buffer to see what we can see.
01164          */
01165         isc_buffer_init(&source, ev->region.base, ev->region.length);
01166         isc_buffer_add(&source, ev->n);
01167         dres = dns_message_peekheader(&source, &id, &flags);
01168         if (dres != ISC_R_SUCCESS) {
01169                 free_buffer(disp, ev->region.base, ev->region.length);
01170                 dispatch_log(disp, LVL(10), "got garbage packet");
01171                 goto restart;
01172         }
01173 
01174         dispatch_log(disp, LVL(92),
01175                      "got valid DNS message header, /QR %c, id %u",
01176                      ((flags & DNS_MESSAGEFLAG_QR) ? '1' : '0'), id);
01177 
01178         /*
01179          * Look at flags.  If query, drop it. If response,
01180          * look to see where it goes.
01181          */
01182         if ((flags & DNS_MESSAGEFLAG_QR) == 0) {
01183                 /* query */
01184                 free_buffer(disp, ev->region.base, ev->region.length);
01185                 goto restart;
01186         }
01187 
01188         /*
01189          * Search for the corresponding response.  If we are using an exclusive
01190          * socket, we've already identified it and we can skip the search; but
01191          * the ID and the address must match the expected ones.
01192          */
01193         if (resp == NULL) {
01194                 bucket = dns_hash(qid, &ev->address, id, disp->localport);
01195                 LOCK(&qid->lock);
01196                 qidlocked = ISC_TRUE;
01197                 resp = entry_search(qid, &ev->address, id, disp->localport,
01198                                     bucket);
01199                 dispatch_log(disp, LVL(90),
01200                              "search for response in bucket %d: %s",
01201                              bucket, (resp == NULL ? "not found" : "found"));
01202 
01203                 if (resp == NULL) {
01204                         inc_stats(mgr, dns_resstatscounter_mismatch);
01205                         free_buffer(disp, ev->region.base, ev->region.length);
01206                         goto unlock;
01207                 }
01208         } else if (resp->id != id || !isc_sockaddr_equal(&ev->address,
01209                                                          &resp->host)) {
01210                 dispatch_log(disp, LVL(90),
01211                              "response to an exclusive socket doesn't match");
01212                 inc_stats(mgr, dns_resstatscounter_mismatch);
01213                 free_buffer(disp, ev->region.base, ev->region.length);
01214                 goto unlock;
01215         }
01216 
01217         /*
01218          * Now that we have the original dispatch the query was sent
01219          * from check that the address and port the response was
01220          * sent to make sense.
01221          */
01222         if (disp != resp->disp) {
01223                 isc_sockaddr_t a1;
01224                 isc_sockaddr_t a2;
01225 
01226                 /*
01227                  * Check that the socket types and ports match.
01228                  */
01229                 if (disp->socktype != resp->disp->socktype ||
01230                     isc_sockaddr_getport(&disp->local) !=
01231                     isc_sockaddr_getport(&resp->disp->local)) {
01232                         free_buffer(disp, ev->region.base, ev->region.length);
01233                         goto unlock;
01234                 }
01235 
01236                 /*
01237                  * If each dispatch is bound to a different address
01238                  * then fail.
01239                  *
01240                  * Note under Linux a packet can be sent out via IPv4 socket
01241                  * and the response be received via a IPv6 socket.
01242                  *
01243                  * Requests sent out via IPv6 should always come back in
01244                  * via IPv6.
01245                  */
01246                 if (isc_sockaddr_pf(&resp->disp->local) == PF_INET6 &&
01247                     isc_sockaddr_pf(&disp->local) != PF_INET6) {
01248                         free_buffer(disp, ev->region.base, ev->region.length);
01249                         goto unlock;
01250                 }
01251                 isc_sockaddr_anyofpf(&a1, isc_sockaddr_pf(&resp->disp->local));
01252                 isc_sockaddr_anyofpf(&a2, isc_sockaddr_pf(&disp->local));
01253                 if (!isc_sockaddr_eqaddr(&disp->local, &resp->disp->local) &&
01254                     !isc_sockaddr_eqaddr(&a1, &resp->disp->local) &&
01255                     !isc_sockaddr_eqaddr(&a2, &disp->local)) {
01256                         free_buffer(disp, ev->region.base, ev->region.length);
01257                         goto unlock;
01258                 }
01259         }
01260 
01261   sendresponse:
01262         queue_response = resp->item_out;
01263         rev = allocate_devent(resp->disp);
01264         if (rev == NULL) {
01265                 free_buffer(disp, ev->region.base, ev->region.length);
01266                 goto unlock;
01267         }
01268 
01269         /*
01270          * At this point, rev contains the event we want to fill in, and
01271          * resp contains the information on the place to send it to.
01272          * Send the event off.
01273          */
01274         isc_buffer_init(&rev->buffer, ev->region.base, ev->region.length);
01275         isc_buffer_add(&rev->buffer, ev->n);
01276         rev->result = ev->result;
01277         rev->id = id;
01278         rev->addr = ev->address;
01279         rev->pktinfo = ev->pktinfo;
01280         rev->attributes = ev->attributes;
01281         if (queue_response) {
01282                 ISC_LIST_APPEND(resp->items, rev, ev_link);
01283         } else {
01284                 ISC_EVENT_INIT(rev, sizeof(*rev), 0, NULL,
01285                                DNS_EVENT_DISPATCH,
01286                                resp->action, resp->arg, resp, NULL, NULL);
01287                 request_log(disp, resp, LVL(90),
01288                             "[a] Sent event %p buffer %p len %d to task %p",
01289                             rev, rev->buffer.base, rev->buffer.length,
01290                             resp->task);
01291                 resp->item_out = ISC_TRUE;
01292                 isc_task_send(resp->task, ISC_EVENT_PTR(&rev));
01293         }
01294  unlock:
01295         if (qidlocked)
01296                 UNLOCK(&qid->lock);
01297 
01298         /*
01299          * Restart recv() to get the next packet.
01300          */
01301  restart:
01302         result = startrecv(disp, dispsock);
01303         if (result != ISC_R_SUCCESS && dispsock != NULL) {
01304                 /*
01305                  * XXX: wired. There seems to be no recovery process other than
01306                  * deactivate this socket anyway (since we cannot start
01307                  * receiving, we won't be able to receive a cancel event
01308                  * from the user).
01309                  */
01310                 deactivate_dispsocket(disp, dispsock);
01311         }
01312         isc_event_free(&ev_in);
01313         UNLOCK(&disp->lock);
01314 }
01315 
01316 /*
01317  * General flow:
01318  *
01319  * If I/O result == CANCELED, EOF, or error, notify everyone as the
01320  * various queues drain.
01321  *
01322  * If query, restart.
01323  *
01324  * If response:
01325  *      Allocate event, fill in details.
01326  *              If cannot allocate, restart.
01327  *      find target.  If not found, restart.
01328  *      if event queue is not empty, queue.  else, send.
01329  *      restart.
01330  */
01331 static void
01332 tcp_recv(isc_task_t *task, isc_event_t *ev_in) {
01333         dns_dispatch_t *disp = ev_in->ev_arg;
01334         dns_tcpmsg_t *tcpmsg = &disp->tcpmsg;
01335         dns_messageid_t id;
01336         isc_result_t dres;
01337         unsigned int flags;
01338         dns_dispentry_t *resp;
01339         dns_dispatchevent_t *rev;
01340         unsigned int bucket;
01341         isc_boolean_t killit;
01342         isc_boolean_t queue_response;
01343         dns_qid_t *qid;
01344         int level;
01345         char buf[ISC_SOCKADDR_FORMATSIZE];
01346 
01347         UNUSED(task);
01348 
01349         REQUIRE(VALID_DISPATCH(disp));
01350 
01351         qid = disp->qid;
01352 
01353         dispatch_log(disp, LVL(90),
01354                      "got TCP packet: requests %d, buffers %d, recvs %d",
01355                      disp->requests, disp->tcpbuffers, disp->recv_pending);
01356 
01357         LOCK(&disp->lock);
01358 
01359         INSIST(disp->recv_pending != 0);
01360         disp->recv_pending = 0;
01361 
01362         if (disp->refcount == 0) {
01363                 /*
01364                  * This dispatcher is shutting down.  Force cancelation.
01365                  */
01366                 tcpmsg->result = ISC_R_CANCELED;
01367         }
01368 
01369         if (tcpmsg->result != ISC_R_SUCCESS) {
01370                 switch (tcpmsg->result) {
01371                 case ISC_R_CANCELED:
01372                         break;
01373 
01374                 case ISC_R_EOF:
01375                         dispatch_log(disp, LVL(90), "shutting down on EOF");
01376                         do_cancel(disp);
01377                         break;
01378 
01379                 case ISC_R_CONNECTIONRESET:
01380                         level = ISC_LOG_INFO;
01381                         goto logit;
01382 
01383                 default:
01384                         level = ISC_LOG_ERROR;
01385                 logit:
01386                         isc_sockaddr_format(&tcpmsg->address, buf, sizeof(buf));
01387                         dispatch_log(disp, level, "shutting down due to TCP "
01388                                      "receive error: %s: %s", buf,
01389                                      isc_result_totext(tcpmsg->result));
01390                         do_cancel(disp);
01391                         break;
01392                 }
01393 
01394                 /*
01395                  * The event is statically allocated in the tcpmsg
01396                  * structure, and destroy_disp() frees the tcpmsg, so we must
01397                  * free the event *before* calling destroy_disp().
01398                  */
01399                 isc_event_free(&ev_in);
01400 
01401                 disp->shutting_down = 1;
01402                 disp->shutdown_why = tcpmsg->result;
01403 
01404                 /*
01405                  * If the recv() was canceled pass the word on.
01406                  */
01407                 killit = destroy_disp_ok(disp);
01408                 UNLOCK(&disp->lock);
01409                 if (killit)
01410                         isc_task_send(disp->task[0], &disp->ctlevent);
01411                 return;
01412         }
01413 
01414         dispatch_log(disp, LVL(90), "result %d, length == %d, addr = %p",
01415                      tcpmsg->result,
01416                      tcpmsg->buffer.length, tcpmsg->buffer.base);
01417 
01418         /*
01419          * Peek into the buffer to see what we can see.
01420          */
01421         dres = dns_message_peekheader(&tcpmsg->buffer, &id, &flags);
01422         if (dres != ISC_R_SUCCESS) {
01423                 dispatch_log(disp, LVL(10), "got garbage packet");
01424                 goto restart;
01425         }
01426 
01427         dispatch_log(disp, LVL(92),
01428                      "got valid DNS message header, /QR %c, id %u",
01429                      ((flags & DNS_MESSAGEFLAG_QR) ? '1' : '0'), id);
01430 
01431         /*
01432          * Allocate an event to send to the query or response client, and
01433          * allocate a new buffer for our use.
01434          */
01435 
01436         /*
01437          * Look at flags.  If query, drop it. If response,
01438          * look to see where it goes.
01439          */
01440         if ((flags & DNS_MESSAGEFLAG_QR) == 0) {
01441                 /*
01442                  * Query.
01443                  */
01444                 goto restart;
01445         }
01446 
01447         /*
01448          * Response.
01449          */
01450         bucket = dns_hash(qid, &tcpmsg->address, id, disp->localport);
01451         LOCK(&qid->lock);
01452         resp = entry_search(qid, &tcpmsg->address, id, disp->localport, bucket);
01453         dispatch_log(disp, LVL(90),
01454                      "search for response in bucket %d: %s",
01455                      bucket, (resp == NULL ? "not found" : "found"));
01456 
01457         if (resp == NULL)
01458                 goto unlock;
01459         queue_response = resp->item_out;
01460         rev = allocate_devent(disp);
01461         if (rev == NULL)
01462                 goto unlock;
01463 
01464         /*
01465          * At this point, rev contains the event we want to fill in, and
01466          * resp contains the information on the place to send it to.
01467          * Send the event off.
01468          */
01469         dns_tcpmsg_keepbuffer(tcpmsg, &rev->buffer);
01470         disp->tcpbuffers++;
01471         rev->result = ISC_R_SUCCESS;
01472         rev->id = id;
01473         rev->addr = tcpmsg->address;
01474         if (queue_response) {
01475                 ISC_LIST_APPEND(resp->items, rev, ev_link);
01476         } else {
01477                 ISC_EVENT_INIT(rev, sizeof(*rev), 0, NULL, DNS_EVENT_DISPATCH,
01478                                resp->action, resp->arg, resp, NULL, NULL);
01479                 request_log(disp, resp, LVL(90),
01480                             "[b] Sent event %p buffer %p len %d to task %p",
01481                             rev, rev->buffer.base, rev->buffer.length,
01482                             resp->task);
01483                 resp->item_out = ISC_TRUE;
01484                 isc_task_send(resp->task, ISC_EVENT_PTR(&rev));
01485         }
01486  unlock:
01487         UNLOCK(&qid->lock);
01488 
01489         /*
01490          * Restart recv() to get the next packet.
01491          */
01492  restart:
01493         (void)startrecv(disp, NULL);
01494 
01495         isc_event_free(&ev_in);
01496         UNLOCK(&disp->lock);
01497 }
01498 
01499 /*
01500  * disp must be locked.
01501  */
01502 static isc_result_t
01503 startrecv(dns_dispatch_t *disp, dispsocket_t *dispsock) {
01504         isc_result_t res;
01505         isc_region_t region;
01506         isc_socket_t *sock;
01507 
01508         if (disp->shutting_down == 1)
01509                 return (ISC_R_SUCCESS);
01510 
01511         if ((disp->attributes & DNS_DISPATCHATTR_NOLISTEN) != 0)
01512                 return (ISC_R_SUCCESS);
01513 
01514         if (disp->recv_pending != 0 && dispsock == NULL)
01515                 return (ISC_R_SUCCESS);
01516 
01517         if (disp->mgr->buffers >= disp->mgr->maxbuffers)
01518                 return (ISC_R_NOMEMORY);
01519 
01520         if ((disp->attributes & DNS_DISPATCHATTR_EXCLUSIVE) != 0 &&
01521             dispsock == NULL)
01522                 return (ISC_R_SUCCESS);
01523 
01524         if (dispsock != NULL)
01525                 sock = dispsock->socket;
01526         else
01527                 sock = disp->socket;
01528         INSIST(sock != NULL);
01529 
01530         switch (disp->socktype) {
01531                 /*
01532                  * UDP reads are always maximal.
01533                  */
01534         case isc_sockettype_udp:
01535                 region.length = disp->mgr->buffersize;
01536                 region.base = allocate_udp_buffer(disp);
01537                 if (region.base == NULL)
01538                         return (ISC_R_NOMEMORY);
01539                 if (dispsock != NULL) {
01540                         isc_task_t *dt = dispsock->task;
01541                         isc_socketevent_t *sev =
01542                                 allocate_sevent(disp, sock,
01543                                                 ISC_SOCKEVENT_RECVDONE,
01544                                                 udp_exrecv, dispsock);
01545                         if (sev == NULL) {
01546                                 free_buffer(disp, region.base, region.length);
01547                                 return (ISC_R_NOMEMORY);
01548                         }
01549 
01550                         res = isc_socket_recv2(sock, &region, 1, dt, sev, 0);
01551                         if (res != ISC_R_SUCCESS) {
01552                                 free_buffer(disp, region.base, region.length);
01553                                 return (res);
01554                         }
01555                 } else {
01556                         isc_task_t *dt = disp->task[0];
01557                         isc_socketevent_t *sev =
01558                                 allocate_sevent(disp, sock,
01559                                                 ISC_SOCKEVENT_RECVDONE,
01560                                                 udp_shrecv, disp);
01561                         if (sev == NULL) {
01562                                 free_buffer(disp, region.base, region.length);
01563                                 return (ISC_R_NOMEMORY);
01564                         }
01565 
01566                         res = isc_socket_recv2(sock, &region, 1, dt, sev, 0);
01567                         if (res != ISC_R_SUCCESS) {
01568                                 free_buffer(disp, region.base, region.length);
01569                                 disp->shutdown_why = res;
01570                                 disp->shutting_down = 1;
01571                                 do_cancel(disp);
01572                                 return (ISC_R_SUCCESS); /* recover by cancel */
01573                         }
01574                         INSIST(disp->recv_pending == 0);
01575                         disp->recv_pending = 1;
01576                 }
01577                 break;
01578 
01579         case isc_sockettype_tcp:
01580                 res = dns_tcpmsg_readmessage(&disp->tcpmsg, disp->task[0],
01581                                              tcp_recv, disp);
01582                 if (res != ISC_R_SUCCESS) {
01583                         disp->shutdown_why = res;
01584                         disp->shutting_down = 1;
01585                         do_cancel(disp);
01586                         return (ISC_R_SUCCESS); /* recover by cancel */
01587                 }
01588                 INSIST(disp->recv_pending == 0);
01589                 disp->recv_pending = 1;
01590                 break;
01591         default:
01592                 INSIST(0);
01593                 break;
01594         }
01595 
01596         return (ISC_R_SUCCESS);
01597 }
01598 
01599 /*
01600  * Mgr must be locked when calling this function.
01601  */
01602 static isc_boolean_t
01603 destroy_mgr_ok(dns_dispatchmgr_t *mgr) {
01604         mgr_log(mgr, LVL(90),
01605                 "destroy_mgr_ok: shuttingdown=%d, listnonempty=%d, "
01606                 "depool=%d, rpool=%d, dpool=%d",
01607                 MGR_IS_SHUTTINGDOWN(mgr), !ISC_LIST_EMPTY(mgr->list),
01608                 isc_mempool_getallocated(mgr->depool),
01609                 isc_mempool_getallocated(mgr->rpool),
01610                 isc_mempool_getallocated(mgr->dpool));
01611         if (!MGR_IS_SHUTTINGDOWN(mgr))
01612                 return (ISC_FALSE);
01613         if (!ISC_LIST_EMPTY(mgr->list))
01614                 return (ISC_FALSE);
01615         if (isc_mempool_getallocated(mgr->depool) != 0)
01616                 return (ISC_FALSE);
01617         if (isc_mempool_getallocated(mgr->rpool) != 0)
01618                 return (ISC_FALSE);
01619         if (isc_mempool_getallocated(mgr->dpool) != 0)
01620                 return (ISC_FALSE);
01621 
01622         return (ISC_TRUE);
01623 }
01624 
01625 /*
01626  * Mgr must be unlocked when calling this function.
01627  */
01628 static void
01629 destroy_mgr(dns_dispatchmgr_t **mgrp) {
01630         isc_mem_t *mctx;
01631         dns_dispatchmgr_t *mgr;
01632 
01633         mgr = *mgrp;
01634         *mgrp = NULL;
01635 
01636         mctx = mgr->mctx;
01637 
01638         mgr->magic = 0;
01639         mgr->mctx = NULL;
01640         DESTROYLOCK(&mgr->lock);
01641         mgr->state = 0;
01642 
01643         if (mgr->rngctx != NULL)
01644                 isc_rng_detach(&mgr->rngctx);
01645         DESTROYLOCK(&mgr->rng_lock);
01646 
01647         isc_mempool_destroy(&mgr->depool);
01648         isc_mempool_destroy(&mgr->rpool);
01649         isc_mempool_destroy(&mgr->dpool);
01650         if (mgr->bpool != NULL)
01651                 isc_mempool_destroy(&mgr->bpool);
01652         if (mgr->spool != NULL)
01653                 isc_mempool_destroy(&mgr->spool);
01654 
01655         DESTROYLOCK(&mgr->spool_lock);
01656         DESTROYLOCK(&mgr->bpool_lock);
01657         DESTROYLOCK(&mgr->dpool_lock);
01658         DESTROYLOCK(&mgr->rpool_lock);
01659         DESTROYLOCK(&mgr->depool_lock);
01660 
01661         if (mgr->entropy != NULL)
01662                 isc_entropy_detach(&mgr->entropy);
01663         if (mgr->qid != NULL)
01664                 qid_destroy(mctx, &mgr->qid);
01665 
01666         DESTROYLOCK(&mgr->buffer_lock);
01667 
01668         if (mgr->blackhole != NULL)
01669                 dns_acl_detach(&mgr->blackhole);
01670 
01671         if (mgr->stats != NULL)
01672                 isc_stats_detach(&mgr->stats);
01673 
01674         if (mgr->v4ports != NULL) {
01675                 isc_mem_put(mctx, mgr->v4ports,
01676                             mgr->nv4ports * sizeof(in_port_t));
01677         }
01678         if (mgr->v6ports != NULL) {
01679                 isc_mem_put(mctx, mgr->v6ports,
01680                             mgr->nv6ports * sizeof(in_port_t));
01681         }
01682         isc_mem_put(mctx, mgr, sizeof(dns_dispatchmgr_t));
01683         isc_mem_detach(&mctx);
01684 }
01685 
01686 static isc_result_t
01687 open_socket(isc_socketmgr_t *mgr, isc_sockaddr_t *local,
01688             unsigned int options, isc_socket_t **sockp,
01689             isc_socket_t *dup_socket)
01690 {
01691         isc_socket_t *sock;
01692         isc_result_t result;
01693 
01694         sock = *sockp;
01695         if (sock != NULL) {
01696                 result = isc_socket_open(sock);
01697                 if (result != ISC_R_SUCCESS)
01698                         return (result);
01699         } else if (dup_socket != NULL) {
01700                 result = isc_socket_dup(dup_socket, &sock);
01701                 if (result != ISC_R_SUCCESS)
01702                         return (result);
01703 
01704                 isc_socket_setname(sock, "dispatcher", NULL);
01705                 *sockp = sock;
01706                 return (ISC_R_SUCCESS);
01707         } else {
01708                 result = isc_socket_create(mgr, isc_sockaddr_pf(local),
01709                                         isc_sockettype_udp, &sock);
01710                 if (result != ISC_R_SUCCESS)
01711                         return (result);
01712         }
01713 
01714         isc_socket_setname(sock, "dispatcher", NULL);
01715 
01716 #ifndef ISC_ALLOW_MAPPED
01717         isc_socket_ipv6only(sock, ISC_TRUE);
01718 #endif
01719         result = isc_socket_bind(sock, local, options);
01720         if (result != ISC_R_SUCCESS) {
01721                 if (*sockp == NULL)
01722                         isc_socket_detach(&sock);
01723                 else {
01724                         isc_socket_close(sock);
01725                 }
01726                 return (result);
01727         }
01728 
01729         *sockp = sock;
01730         return (ISC_R_SUCCESS);
01731 }
01732 
01733 /*%
01734  * Create a temporary port list to set the initial default set of dispatch
01735  * ports: [1024, 65535].  This is almost meaningless as the application will
01736  * normally set the ports explicitly, but is provided to fill some minor corner
01737  * cases.
01738  */
01739 static isc_result_t
01740 create_default_portset(isc_mem_t *mctx, isc_portset_t **portsetp) {
01741         isc_result_t result;
01742 
01743         result = isc_portset_create(mctx, portsetp);
01744         if (result != ISC_R_SUCCESS)
01745                 return (result);
01746         isc_portset_addrange(*portsetp, 1024, 65535);
01747 
01748         return (ISC_R_SUCCESS);
01749 }
01750 
01751 /*
01752  * Publics.
01753  */
01754 
01755 isc_result_t
01756 dns_dispatchmgr_create(isc_mem_t *mctx, isc_entropy_t *entropy,
01757                        dns_dispatchmgr_t **mgrp)
01758 {
01759         dns_dispatchmgr_t *mgr;
01760         isc_result_t result;
01761         isc_portset_t *v4portset = NULL;
01762         isc_portset_t *v6portset = NULL;
01763 
01764         REQUIRE(mctx != NULL);
01765         REQUIRE(mgrp != NULL && *mgrp == NULL);
01766 
01767         mgr = isc_mem_get(mctx, sizeof(dns_dispatchmgr_t));
01768         if (mgr == NULL)
01769                 return (ISC_R_NOMEMORY);
01770 
01771         mgr->mctx = NULL;
01772         isc_mem_attach(mctx, &mgr->mctx);
01773 
01774         mgr->blackhole = NULL;
01775         mgr->stats = NULL;
01776         mgr->rngctx = NULL;
01777 
01778         result = isc_mutex_init(&mgr->lock);
01779         if (result != ISC_R_SUCCESS)
01780                 goto deallocate;
01781 
01782         result = isc_mutex_init(&mgr->rng_lock);
01783         if (result != ISC_R_SUCCESS)
01784                 goto kill_lock;
01785 
01786         result = isc_mutex_init(&mgr->buffer_lock);
01787         if (result != ISC_R_SUCCESS)
01788                 goto kill_rng_lock;
01789 
01790         result = isc_mutex_init(&mgr->depool_lock);
01791         if (result != ISC_R_SUCCESS)
01792                 goto kill_buffer_lock;
01793 
01794         result = isc_mutex_init(&mgr->rpool_lock);
01795         if (result != ISC_R_SUCCESS)
01796                 goto kill_depool_lock;
01797 
01798         result = isc_mutex_init(&mgr->dpool_lock);
01799         if (result != ISC_R_SUCCESS)
01800                 goto kill_rpool_lock;
01801 
01802         result = isc_mutex_init(&mgr->bpool_lock);
01803         if (result != ISC_R_SUCCESS)
01804                 goto kill_dpool_lock;
01805 
01806         result = isc_mutex_init(&mgr->spool_lock);
01807         if (result != ISC_R_SUCCESS)
01808                 goto kill_bpool_lock;
01809 
01810         mgr->depool = NULL;
01811         if (isc_mempool_create(mgr->mctx, sizeof(dns_dispatchevent_t),
01812                                &mgr->depool) != ISC_R_SUCCESS) {
01813                 result = ISC_R_NOMEMORY;
01814                 goto kill_spool_lock;
01815         }
01816 
01817         mgr->rpool = NULL;
01818         if (isc_mempool_create(mgr->mctx, sizeof(dns_dispentry_t),
01819                                &mgr->rpool) != ISC_R_SUCCESS) {
01820                 result = ISC_R_NOMEMORY;
01821                 goto kill_depool;
01822         }
01823 
01824         mgr->dpool = NULL;
01825         if (isc_mempool_create(mgr->mctx, sizeof(dns_dispatch_t),
01826                                &mgr->dpool) != ISC_R_SUCCESS) {
01827                 result = ISC_R_NOMEMORY;
01828                 goto kill_rpool;
01829         }
01830 
01831         isc_mempool_setname(mgr->depool, "dispmgr_depool");
01832         isc_mempool_setmaxalloc(mgr->depool, 32768);
01833         isc_mempool_setfreemax(mgr->depool, 32768);
01834         isc_mempool_associatelock(mgr->depool, &mgr->depool_lock);
01835         isc_mempool_setfillcount(mgr->depool, 32);
01836 
01837         isc_mempool_setname(mgr->rpool, "dispmgr_rpool");
01838         isc_mempool_setmaxalloc(mgr->rpool, 32768);
01839         isc_mempool_setfreemax(mgr->rpool, 32768);
01840         isc_mempool_associatelock(mgr->rpool, &mgr->rpool_lock);
01841         isc_mempool_setfillcount(mgr->rpool, 32);
01842 
01843         isc_mempool_setname(mgr->dpool, "dispmgr_dpool");
01844         isc_mempool_setmaxalloc(mgr->dpool, 32768);
01845         isc_mempool_setfreemax(mgr->dpool, 32768);
01846         isc_mempool_associatelock(mgr->dpool, &mgr->dpool_lock);
01847         isc_mempool_setfillcount(mgr->dpool, 32);
01848 
01849         mgr->buffers = 0;
01850         mgr->buffersize = 0;
01851         mgr->maxbuffers = 0;
01852         mgr->bpool = NULL;
01853         mgr->spool = NULL;
01854         mgr->entropy = NULL;
01855         mgr->qid = NULL;
01856         mgr->state = 0;
01857         ISC_LIST_INIT(mgr->list);
01858         mgr->v4ports = NULL;
01859         mgr->v6ports = NULL;
01860         mgr->nv4ports = 0;
01861         mgr->nv6ports = 0;
01862         mgr->magic = DNS_DISPATCHMGR_MAGIC;
01863 
01864         result = create_default_portset(mctx, &v4portset);
01865         if (result == ISC_R_SUCCESS) {
01866                 result = create_default_portset(mctx, &v6portset);
01867                 if (result == ISC_R_SUCCESS) {
01868                         result = dns_dispatchmgr_setavailports(mgr,
01869                                                                v4portset,
01870                                                                v6portset);
01871                 }
01872         }
01873         if (v4portset != NULL)
01874                 isc_portset_destroy(mctx, &v4portset);
01875         if (v6portset != NULL)
01876                 isc_portset_destroy(mctx, &v6portset);
01877         if (result != ISC_R_SUCCESS)
01878                 goto kill_dpool;
01879 
01880         if (entropy != NULL)
01881                 isc_entropy_attach(entropy, &mgr->entropy);
01882 
01883         result = isc_rng_create(mctx, mgr->entropy, &mgr->rngctx);
01884         if (result != ISC_R_SUCCESS)
01885                 goto kill_dpool;
01886 
01887         *mgrp = mgr;
01888         return (ISC_R_SUCCESS);
01889 
01890  kill_dpool:
01891         isc_mempool_destroy(&mgr->dpool);
01892  kill_rpool:
01893         isc_mempool_destroy(&mgr->rpool);
01894  kill_depool:
01895         isc_mempool_destroy(&mgr->depool);
01896  kill_spool_lock:
01897         DESTROYLOCK(&mgr->spool_lock);
01898  kill_bpool_lock:
01899         DESTROYLOCK(&mgr->bpool_lock);
01900  kill_dpool_lock:
01901         DESTROYLOCK(&mgr->dpool_lock);
01902  kill_rpool_lock:
01903         DESTROYLOCK(&mgr->rpool_lock);
01904  kill_depool_lock:
01905         DESTROYLOCK(&mgr->depool_lock);
01906  kill_buffer_lock:
01907         DESTROYLOCK(&mgr->buffer_lock);
01908  kill_rng_lock:
01909         DESTROYLOCK(&mgr->rng_lock);
01910  kill_lock:
01911         DESTROYLOCK(&mgr->lock);
01912  deallocate:
01913         isc_mem_put(mctx, mgr, sizeof(dns_dispatchmgr_t));
01914         isc_mem_detach(&mctx);
01915 
01916         return (result);
01917 }
01918 
01919 void
01920 dns_dispatchmgr_setblackhole(dns_dispatchmgr_t *mgr, dns_acl_t *blackhole) {
01921         REQUIRE(VALID_DISPATCHMGR(mgr));
01922         if (mgr->blackhole != NULL)
01923                 dns_acl_detach(&mgr->blackhole);
01924         dns_acl_attach(blackhole, &mgr->blackhole);
01925 }
01926 
01927 dns_acl_t *
01928 dns_dispatchmgr_getblackhole(dns_dispatchmgr_t *mgr) {
01929         REQUIRE(VALID_DISPATCHMGR(mgr));
01930         return (mgr->blackhole);
01931 }
01932 
01933 void
01934 dns_dispatchmgr_setblackportlist(dns_dispatchmgr_t *mgr,
01935                                  dns_portlist_t *portlist)
01936 {
01937         REQUIRE(VALID_DISPATCHMGR(mgr));
01938         UNUSED(portlist);
01939 
01940         /* This function is deprecated: use dns_dispatchmgr_setavailports(). */
01941         return;
01942 }
01943 
01944 dns_portlist_t *
01945 dns_dispatchmgr_getblackportlist(dns_dispatchmgr_t *mgr) {
01946         REQUIRE(VALID_DISPATCHMGR(mgr));
01947         return (NULL);          /* this function is deprecated */
01948 }
01949 
01950 isc_result_t
01951 dns_dispatchmgr_setavailports(dns_dispatchmgr_t *mgr, isc_portset_t *v4portset,
01952                               isc_portset_t *v6portset)
01953 {
01954         in_port_t *v4ports, *v6ports, p;
01955         unsigned int nv4ports, nv6ports, i4, i6;
01956 
01957         REQUIRE(VALID_DISPATCHMGR(mgr));
01958 
01959         nv4ports = isc_portset_nports(v4portset);
01960         nv6ports = isc_portset_nports(v6portset);
01961 
01962         v4ports = NULL;
01963         if (nv4ports != 0) {
01964                 v4ports = isc_mem_get(mgr->mctx, sizeof(in_port_t) * nv4ports);
01965                 if (v4ports == NULL)
01966                         return (ISC_R_NOMEMORY);
01967         }
01968         v6ports = NULL;
01969         if (nv6ports != 0) {
01970                 v6ports = isc_mem_get(mgr->mctx, sizeof(in_port_t) * nv6ports);
01971                 if (v6ports == NULL) {
01972                         if (v4ports != NULL) {
01973                                 isc_mem_put(mgr->mctx, v4ports,
01974                                             sizeof(in_port_t) *
01975                                             isc_portset_nports(v4portset));
01976                         }
01977                         return (ISC_R_NOMEMORY);
01978                 }
01979         }
01980 
01981         p = 0;
01982         i4 = 0;
01983         i6 = 0;
01984         do {
01985                 if (isc_portset_isset(v4portset, p)) {
01986                         INSIST(i4 < nv4ports);
01987                         v4ports[i4++] = p;
01988                 }
01989                 if (isc_portset_isset(v6portset, p)) {
01990                         INSIST(i6 < nv6ports);
01991                         v6ports[i6++] = p;
01992                 }
01993         } while (p++ < 65535);
01994         INSIST(i4 == nv4ports && i6 == nv6ports);
01995 
01996         PORTBUFLOCK(mgr);
01997         if (mgr->v4ports != NULL) {
01998                 isc_mem_put(mgr->mctx, mgr->v4ports,
01999                             mgr->nv4ports * sizeof(in_port_t));
02000         }
02001         mgr->v4ports = v4ports;
02002         mgr->nv4ports = nv4ports;
02003 
02004         if (mgr->v6ports != NULL) {
02005                 isc_mem_put(mgr->mctx, mgr->v6ports,
02006                             mgr->nv6ports * sizeof(in_port_t));
02007         }
02008         mgr->v6ports = v6ports;
02009         mgr->nv6ports = nv6ports;
02010         PORTBUFUNLOCK(mgr);
02011 
02012         return (ISC_R_SUCCESS);
02013 }
02014 
02015 static isc_result_t
02016 dns_dispatchmgr_setudp(dns_dispatchmgr_t *mgr,
02017                        unsigned int buffersize, unsigned int maxbuffers,
02018                        unsigned int maxrequests, unsigned int buckets,
02019                        unsigned int increment)
02020 {
02021         isc_result_t result;
02022 
02023         REQUIRE(VALID_DISPATCHMGR(mgr));
02024         REQUIRE(buffersize >= 512 && buffersize < (64 * 1024));
02025         REQUIRE(maxbuffers > 0);
02026         REQUIRE(buckets < 2097169);  /* next prime > 65536 * 32 */
02027         REQUIRE(increment > buckets);
02028 
02029         /*
02030          * Keep some number of items around.  This should be a config
02031          * option.  For now, keep 8, but later keep at least two even
02032          * if the caller wants less.  This allows us to ensure certain
02033          * things, like an event can be "freed" and the next allocation
02034          * will always succeed.
02035          *
02036          * Note that if limits are placed on anything here, we use one
02037          * event internally, so the actual limit should be "wanted + 1."
02038          *
02039          * XXXMLG
02040          */
02041 
02042         if (maxbuffers < 8)
02043                 maxbuffers = 8;
02044 
02045         LOCK(&mgr->buffer_lock);
02046 
02047         /* Create or adjust buffer pool */
02048         if (mgr->bpool != NULL) {
02049                 /*
02050                  * We only increase the maxbuffers to avoid accidental buffer
02051                  * shortage.  Ideally we'd separate the manager-wide maximum
02052                  * from per-dispatch limits and respect the latter within the
02053                  * global limit.  But at this moment that's deemed to be
02054                  * overkilling and isn't worth additional implementation
02055                  * complexity.
02056                  */
02057                 if (maxbuffers > mgr->maxbuffers) {
02058                         isc_mempool_setmaxalloc(mgr->bpool, maxbuffers);
02059                         isc_mempool_setfreemax(mgr->bpool, maxbuffers);
02060                         mgr->maxbuffers = maxbuffers;
02061                 }
02062         } else {
02063                 result = isc_mempool_create(mgr->mctx, buffersize, &mgr->bpool);
02064                 if (result != ISC_R_SUCCESS) {
02065                         UNLOCK(&mgr->buffer_lock);
02066                         return (result);
02067                 }
02068                 isc_mempool_setname(mgr->bpool, "dispmgr_bpool");
02069                 isc_mempool_setmaxalloc(mgr->bpool, maxbuffers);
02070                 isc_mempool_setfreemax(mgr->bpool, maxbuffers);
02071                 isc_mempool_associatelock(mgr->bpool, &mgr->bpool_lock);
02072                 isc_mempool_setfillcount(mgr->bpool, 32);
02073         }
02074 
02075         /* Create or adjust socket pool */
02076         if (mgr->spool != NULL) {
02077                 if (maxrequests < DNS_DISPATCH_POOLSOCKS * 2) {
02078                         isc_mempool_setmaxalloc(mgr->spool,
02079                                                 DNS_DISPATCH_POOLSOCKS * 2);
02080                         isc_mempool_setfreemax(mgr->spool,
02081                                                DNS_DISPATCH_POOLSOCKS * 2);
02082                 }
02083                 UNLOCK(&mgr->buffer_lock);
02084                 return (ISC_R_SUCCESS);
02085         }
02086         result = isc_mempool_create(mgr->mctx, sizeof(dispsocket_t),
02087                                     &mgr->spool);
02088         if (result != ISC_R_SUCCESS) {
02089                 UNLOCK(&mgr->buffer_lock);
02090                 goto cleanup;
02091         }
02092         isc_mempool_setname(mgr->spool, "dispmgr_spool");
02093         isc_mempool_setmaxalloc(mgr->spool, maxrequests);
02094         isc_mempool_setfreemax(mgr->spool, maxrequests);
02095         isc_mempool_associatelock(mgr->spool, &mgr->spool_lock);
02096         isc_mempool_setfillcount(mgr->spool, 32);
02097 
02098         result = qid_allocate(mgr, buckets, increment, &mgr->qid, ISC_TRUE);
02099         if (result != ISC_R_SUCCESS)
02100                 goto cleanup;
02101 
02102         mgr->buffersize = buffersize;
02103         mgr->maxbuffers = maxbuffers;
02104         UNLOCK(&mgr->buffer_lock);
02105         return (ISC_R_SUCCESS);
02106 
02107  cleanup:
02108         isc_mempool_destroy(&mgr->bpool);
02109         if (mgr->spool != NULL)
02110                 isc_mempool_destroy(&mgr->spool);
02111         UNLOCK(&mgr->buffer_lock);
02112         return (result);
02113 }
02114 
02115 void
02116 dns_dispatchmgr_destroy(dns_dispatchmgr_t **mgrp) {
02117         dns_dispatchmgr_t *mgr;
02118         isc_boolean_t killit;
02119 
02120         REQUIRE(mgrp != NULL);
02121         REQUIRE(VALID_DISPATCHMGR(*mgrp));
02122 
02123         mgr = *mgrp;
02124         *mgrp = NULL;
02125 
02126         LOCK(&mgr->lock);
02127         mgr->state |= MGR_SHUTTINGDOWN;
02128         killit = destroy_mgr_ok(mgr);
02129         UNLOCK(&mgr->lock);
02130 
02131         mgr_log(mgr, LVL(90), "destroy: killit=%d", killit);
02132 
02133         if (killit)
02134                 destroy_mgr(&mgr);
02135 }
02136 
02137 void
02138 dns_dispatchmgr_setstats(dns_dispatchmgr_t *mgr, isc_stats_t *stats) {
02139         REQUIRE(VALID_DISPATCHMGR(mgr));
02140         REQUIRE(ISC_LIST_EMPTY(mgr->list));
02141         REQUIRE(mgr->stats == NULL);
02142 
02143         isc_stats_attach(stats, &mgr->stats);
02144 }
02145 
02146 static int
02147 port_cmp(const void *key, const void *ent) {
02148         in_port_t p1 = *(const in_port_t *)key;
02149         in_port_t p2 = *(const in_port_t *)ent;
02150 
02151         if (p1 < p2)
02152                 return (-1);
02153         else if (p1 == p2)
02154                 return (0);
02155         else
02156                 return (1);
02157 }
02158 
02159 static isc_boolean_t
02160 portavailable(dns_dispatchmgr_t *mgr, isc_socket_t *sock,
02161               isc_sockaddr_t *sockaddrp)
02162 {
02163         isc_sockaddr_t sockaddr;
02164         isc_result_t result;
02165         in_port_t *ports, port;
02166         unsigned int nports;
02167         isc_boolean_t available = ISC_FALSE;
02168 
02169         REQUIRE(sock != NULL || sockaddrp != NULL);
02170 
02171         PORTBUFLOCK(mgr);
02172         if (sock != NULL) {
02173                 sockaddrp = &sockaddr;
02174                 result = isc_socket_getsockname(sock, sockaddrp);
02175                 if (result != ISC_R_SUCCESS)
02176                         goto unlock;
02177         }
02178 
02179         if (isc_sockaddr_pf(sockaddrp) == AF_INET) {
02180                 ports = mgr->v4ports;
02181                 nports = mgr->nv4ports;
02182         } else {
02183                 ports = mgr->v6ports;
02184                 nports = mgr->nv6ports;
02185         }
02186         if (ports == NULL)
02187                 goto unlock;
02188 
02189         port = isc_sockaddr_getport(sockaddrp);
02190         if (bsearch(&port, ports, nports, sizeof(in_port_t), port_cmp) != NULL)
02191                 available = ISC_TRUE;
02192 
02193 unlock:
02194         PORTBUFUNLOCK(mgr);
02195         return (available);
02196 }
02197 
02198 #define ATTRMATCH(_a1, _a2, _mask) (((_a1) & (_mask)) == ((_a2) & (_mask)))
02199 
02200 static isc_boolean_t
02201 local_addr_match(dns_dispatch_t *disp, isc_sockaddr_t *addr) {
02202         isc_sockaddr_t sockaddr;
02203         isc_result_t result;
02204 
02205         REQUIRE(disp->socket != NULL);
02206 
02207         if (addr == NULL)
02208                 return (ISC_TRUE);
02209 
02210         /*
02211          * Don't match wildcard ports unless the port is available in the
02212          * current configuration.
02213          */
02214         if (isc_sockaddr_getport(addr) == 0 &&
02215             isc_sockaddr_getport(&disp->local) == 0 &&
02216             !portavailable(disp->mgr, disp->socket, NULL)) {
02217                 return (ISC_FALSE);
02218         }
02219 
02220         /*
02221          * Check if we match the binding <address,port>.
02222          * Wildcard ports match/fail here.
02223          */
02224         if (isc_sockaddr_equal(&disp->local, addr))
02225                 return (ISC_TRUE);
02226         if (isc_sockaddr_getport(addr) == 0)
02227                 return (ISC_FALSE);
02228 
02229         /*
02230          * Check if we match a bound wildcard port <address,port>.
02231          */
02232         if (!isc_sockaddr_eqaddr(&disp->local, addr))
02233                 return (ISC_FALSE);
02234         result = isc_socket_getsockname(disp->socket, &sockaddr);
02235         if (result != ISC_R_SUCCESS)
02236                 return (ISC_FALSE);
02237 
02238         return (isc_sockaddr_equal(&sockaddr, addr));
02239 }
02240 
02241 /*
02242  * Requires mgr be locked.
02243  *
02244  * No dispatcher can be locked by this thread when calling this function.
02245  *
02246  *
02247  * NOTE:
02248  *      If a matching dispatcher is found, it is locked after this function
02249  *      returns, and must be unlocked by the caller.
02250  */
02251 static isc_result_t
02252 dispatch_find(dns_dispatchmgr_t *mgr, isc_sockaddr_t *local,
02253               unsigned int attributes, unsigned int mask,
02254               dns_dispatch_t **dispp)
02255 {
02256         dns_dispatch_t *disp;
02257         isc_result_t result;
02258 
02259         /*
02260          * Make certain that we will not match a private or exclusive dispatch.
02261          */
02262         attributes &= ~(DNS_DISPATCHATTR_PRIVATE|DNS_DISPATCHATTR_EXCLUSIVE);
02263         mask |= (DNS_DISPATCHATTR_PRIVATE|DNS_DISPATCHATTR_EXCLUSIVE);
02264 
02265         disp = ISC_LIST_HEAD(mgr->list);
02266         while (disp != NULL) {
02267                 LOCK(&disp->lock);
02268                 if ((disp->shutting_down == 0)
02269                     && ATTRMATCH(disp->attributes, attributes, mask)
02270                     && local_addr_match(disp, local))
02271                         break;
02272                 UNLOCK(&disp->lock);
02273                 disp = ISC_LIST_NEXT(disp, link);
02274         }
02275 
02276         if (disp == NULL) {
02277                 result = ISC_R_NOTFOUND;
02278                 goto out;
02279         }
02280 
02281         *dispp = disp;
02282         result = ISC_R_SUCCESS;
02283  out:
02284 
02285         return (result);
02286 }
02287 
02288 static isc_result_t
02289 qid_allocate(dns_dispatchmgr_t *mgr, unsigned int buckets,
02290              unsigned int increment, dns_qid_t **qidp,
02291              isc_boolean_t needsocktable)
02292 {
02293         dns_qid_t *qid;
02294         unsigned int i;
02295         isc_result_t result;
02296 
02297         REQUIRE(VALID_DISPATCHMGR(mgr));
02298         REQUIRE(buckets < 2097169);  /* next prime > 65536 * 32 */
02299         REQUIRE(increment > buckets);
02300         REQUIRE(qidp != NULL && *qidp == NULL);
02301 
02302         qid = isc_mem_get(mgr->mctx, sizeof(*qid));
02303         if (qid == NULL)
02304                 return (ISC_R_NOMEMORY);
02305 
02306         qid->qid_table = isc_mem_get(mgr->mctx,
02307                                      buckets * sizeof(dns_displist_t));
02308         if (qid->qid_table == NULL) {
02309                 isc_mem_put(mgr->mctx, qid, sizeof(*qid));
02310                 return (ISC_R_NOMEMORY);
02311         }
02312 
02313         qid->sock_table = NULL;
02314         if (needsocktable) {
02315                 qid->sock_table = isc_mem_get(mgr->mctx, buckets *
02316                                               sizeof(dispsocketlist_t));
02317                 if (qid->sock_table == NULL) {
02318                         isc_mem_put(mgr->mctx, qid->qid_table,
02319                                     buckets * sizeof(dns_displist_t));
02320                         isc_mem_put(mgr->mctx, qid, sizeof(*qid));
02321                         return (ISC_R_NOMEMORY);
02322                 }
02323         }
02324 
02325         result = isc_mutex_init(&qid->lock);
02326         if (result != ISC_R_SUCCESS) {
02327                 if (qid->sock_table != NULL) {
02328                         isc_mem_put(mgr->mctx, qid->sock_table,
02329                                     buckets * sizeof(dispsocketlist_t));
02330                 }
02331                 isc_mem_put(mgr->mctx, qid->qid_table,
02332                             buckets * sizeof(dns_displist_t));
02333                 isc_mem_put(mgr->mctx, qid, sizeof(*qid));
02334                 return (result);
02335         }
02336 
02337         for (i = 0; i < buckets; i++) {
02338                 ISC_LIST_INIT(qid->qid_table[i]);
02339                 if (qid->sock_table != NULL)
02340                         ISC_LIST_INIT(qid->sock_table[i]);
02341         }
02342 
02343         qid->qid_nbuckets = buckets;
02344         qid->qid_increment = increment;
02345         qid->magic = QID_MAGIC;
02346         *qidp = qid;
02347         return (ISC_R_SUCCESS);
02348 }
02349 
02350 static void
02351 qid_destroy(isc_mem_t *mctx, dns_qid_t **qidp) {
02352         dns_qid_t *qid;
02353 
02354         REQUIRE(qidp != NULL);
02355         qid = *qidp;
02356 
02357         REQUIRE(VALID_QID(qid));
02358 
02359         *qidp = NULL;
02360         qid->magic = 0;
02361         isc_mem_put(mctx, qid->qid_table,
02362                     qid->qid_nbuckets * sizeof(dns_displist_t));
02363         if (qid->sock_table != NULL) {
02364                 isc_mem_put(mctx, qid->sock_table,
02365                             qid->qid_nbuckets * sizeof(dispsocketlist_t));
02366         }
02367         DESTROYLOCK(&qid->lock);
02368         isc_mem_put(mctx, qid, sizeof(*qid));
02369 }
02370 
02371 /*
02372  * Allocate and set important limits.
02373  */
02374 static isc_result_t
02375 dispatch_allocate(dns_dispatchmgr_t *mgr, unsigned int maxrequests,
02376                   dns_dispatch_t **dispp)
02377 {
02378         dns_dispatch_t *disp;
02379         isc_result_t result;
02380 
02381         REQUIRE(VALID_DISPATCHMGR(mgr));
02382         REQUIRE(dispp != NULL && *dispp == NULL);
02383 
02384         /*
02385          * Set up the dispatcher, mostly.  Don't bother setting some of
02386          * the options that are controlled by tcp vs. udp, etc.
02387          */
02388 
02389         disp = isc_mempool_get(mgr->dpool);
02390         if (disp == NULL)
02391                 return (ISC_R_NOMEMORY);
02392 
02393         disp->magic = 0;
02394         disp->mgr = mgr;
02395         disp->maxrequests = maxrequests;
02396         disp->attributes = 0;
02397         ISC_LINK_INIT(disp, link);
02398         disp->refcount = 1;
02399         disp->recv_pending = 0;
02400         memset(&disp->local, 0, sizeof(disp->local));
02401         memset(&disp->peer, 0, sizeof(disp->peer));
02402         disp->localport = 0;
02403         disp->shutting_down = 0;
02404         disp->shutdown_out = 0;
02405         disp->connected = 0;
02406         disp->tcpmsg_valid = 0;
02407         disp->shutdown_why = ISC_R_UNEXPECTED;
02408         disp->requests = 0;
02409         disp->tcpbuffers = 0;
02410         disp->qid = NULL;
02411         ISC_LIST_INIT(disp->activesockets);
02412         ISC_LIST_INIT(disp->inactivesockets);
02413         disp->nsockets = 0;
02414         disp->rngctx = NULL;
02415         isc_rng_attach(mgr->rngctx, &disp->rngctx);
02416         disp->port_table = NULL;
02417         disp->portpool = NULL;
02418         disp->dscp = -1;
02419 
02420         result = isc_mutex_init(&disp->lock);
02421         if (result != ISC_R_SUCCESS)
02422                 goto deallocate;
02423 
02424         disp->failsafe_ev = allocate_devent(disp);
02425         if (disp->failsafe_ev == NULL) {
02426                 result = ISC_R_NOMEMORY;
02427                 goto kill_lock;
02428         }
02429 
02430         disp->magic = DISPATCH_MAGIC;
02431 
02432         *dispp = disp;
02433         return (ISC_R_SUCCESS);
02434 
02435         /*
02436          * error returns
02437          */
02438  kill_lock:
02439         DESTROYLOCK(&disp->lock);
02440  deallocate:
02441         if (disp->rngctx != NULL)
02442                 isc_rng_detach(&disp->rngctx);
02443         isc_mempool_put(mgr->dpool, disp);
02444 
02445         return (result);
02446 }
02447 
02448 
02449 /*
02450  * MUST be unlocked, and not used by anything.
02451  */
02452 static void
02453 dispatch_free(dns_dispatch_t **dispp) {
02454         dns_dispatch_t *disp;
02455         dns_dispatchmgr_t *mgr;
02456         int i;
02457 
02458         REQUIRE(VALID_DISPATCH(*dispp));
02459         disp = *dispp;
02460         *dispp = NULL;
02461 
02462         mgr = disp->mgr;
02463         REQUIRE(VALID_DISPATCHMGR(mgr));
02464 
02465         if (disp->tcpmsg_valid) {
02466                 dns_tcpmsg_invalidate(&disp->tcpmsg);
02467                 disp->tcpmsg_valid = 0;
02468         }
02469 
02470         INSIST(disp->tcpbuffers == 0);
02471         INSIST(disp->requests == 0);
02472         INSIST(disp->recv_pending == 0);
02473         INSIST(ISC_LIST_EMPTY(disp->activesockets));
02474         INSIST(ISC_LIST_EMPTY(disp->inactivesockets));
02475 
02476         isc_mempool_put(mgr->depool, disp->failsafe_ev);
02477         disp->failsafe_ev = NULL;
02478 
02479         if (disp->qid != NULL)
02480                 qid_destroy(mgr->mctx, &disp->qid);
02481 
02482         if (disp->port_table != NULL) {
02483                 for (i = 0; i < DNS_DISPATCH_PORTTABLESIZE; i++)
02484                         INSIST(ISC_LIST_EMPTY(disp->port_table[i]));
02485                 isc_mem_put(mgr->mctx, disp->port_table,
02486                             sizeof(disp->port_table[0]) *
02487                             DNS_DISPATCH_PORTTABLESIZE);
02488         }
02489 
02490         if (disp->portpool != NULL)
02491                 isc_mempool_destroy(&disp->portpool);
02492 
02493         if (disp->rngctx != NULL)
02494                 isc_rng_detach(&disp->rngctx);
02495 
02496         disp->mgr = NULL;
02497         DESTROYLOCK(&disp->lock);
02498         disp->magic = 0;
02499         isc_mempool_put(mgr->dpool, disp);
02500 }
02501 
02502 isc_result_t
02503 dns_dispatch_createtcp(dns_dispatchmgr_t *mgr, isc_socket_t *sock,
02504                        isc_taskmgr_t *taskmgr, unsigned int buffersize,
02505                        unsigned int maxbuffers, unsigned int maxrequests,
02506                        unsigned int buckets, unsigned int increment,
02507                        unsigned int attributes, dns_dispatch_t **dispp)
02508 {
02509 
02510         attributes |= DNS_DISPATCHATTR_PRIVATE;  /* XXXMLG */
02511 
02512         return (dns_dispatch_createtcp2(mgr, sock, taskmgr, NULL, NULL,
02513                                         buffersize, maxbuffers, maxrequests,
02514                                         buckets, increment, attributes,
02515                                         dispp));
02516 }
02517 
02518 isc_result_t
02519 dns_dispatch_createtcp2(dns_dispatchmgr_t *mgr, isc_socket_t *sock,
02520                         isc_taskmgr_t *taskmgr, isc_sockaddr_t *localaddr,
02521                         isc_sockaddr_t *destaddr, unsigned int buffersize,
02522                         unsigned int maxbuffers, unsigned int maxrequests,
02523                         unsigned int buckets, unsigned int increment,
02524                         unsigned int attributes, dns_dispatch_t **dispp)
02525 {
02526         isc_result_t result;
02527         dns_dispatch_t *disp;
02528 
02529         UNUSED(maxbuffers);
02530         UNUSED(buffersize);
02531 
02532         REQUIRE(VALID_DISPATCHMGR(mgr));
02533         REQUIRE(isc_socket_gettype(sock) == isc_sockettype_tcp);
02534         REQUIRE((attributes & DNS_DISPATCHATTR_TCP) != 0);
02535         REQUIRE((attributes & DNS_DISPATCHATTR_UDP) == 0);
02536 
02537         if (destaddr == NULL)
02538                 attributes |= DNS_DISPATCHATTR_PRIVATE;  /* XXXMLG */
02539 
02540         LOCK(&mgr->lock);
02541 
02542         /*
02543          * dispatch_allocate() checks mgr for us.
02544          * qid_allocate() checks buckets and increment for us.
02545          */
02546         disp = NULL;
02547         result = dispatch_allocate(mgr, maxrequests, &disp);
02548         if (result != ISC_R_SUCCESS) {
02549                 UNLOCK(&mgr->lock);
02550                 return (result);
02551         }
02552 
02553         result = qid_allocate(mgr, buckets, increment, &disp->qid, ISC_FALSE);
02554         if (result != ISC_R_SUCCESS)
02555                 goto deallocate_dispatch;
02556 
02557         disp->socktype = isc_sockettype_tcp;
02558         disp->socket = NULL;
02559         isc_socket_attach(sock, &disp->socket);
02560 
02561         disp->sepool = NULL;
02562 
02563         disp->ntasks = 1;
02564         disp->task[0] = NULL;
02565         result = isc_task_create(taskmgr, 0, &disp->task[0]);
02566         if (result != ISC_R_SUCCESS)
02567                 goto kill_socket;
02568 
02569         disp->ctlevent = isc_event_allocate(mgr->mctx, disp,
02570                                             DNS_EVENT_DISPATCHCONTROL,
02571                                             destroy_disp, disp,
02572                                             sizeof(isc_event_t));
02573         if (disp->ctlevent == NULL) {
02574                 result = ISC_R_NOMEMORY;
02575                 goto kill_task;
02576         }
02577 
02578         isc_task_setname(disp->task[0], "tcpdispatch", disp);
02579 
02580         dns_tcpmsg_init(mgr->mctx, disp->socket, &disp->tcpmsg);
02581         disp->tcpmsg_valid = 1;
02582 
02583         disp->attributes = attributes;
02584 
02585         if (localaddr == NULL) {
02586                 if (destaddr != NULL) {
02587                         switch (isc_sockaddr_pf(destaddr)) {
02588                         case AF_INET:
02589                                 isc_sockaddr_any(&disp->local);
02590                                 break;
02591                         case AF_INET6:
02592                                 isc_sockaddr_any6(&disp->local);
02593                                 break;
02594                         }
02595                 }
02596         } else
02597                 disp->local = *localaddr;
02598 
02599         if (destaddr != NULL)
02600                 disp->peer = *destaddr;
02601 
02602         /*
02603          * Append it to the dispatcher list.
02604          */
02605         ISC_LIST_APPEND(mgr->list, disp, link);
02606         UNLOCK(&mgr->lock);
02607 
02608         mgr_log(mgr, LVL(90), "created TCP dispatcher %p", disp);
02609         dispatch_log(disp, LVL(90), "created task %p", disp->task[0]);
02610         *dispp = disp;
02611 
02612         return (ISC_R_SUCCESS);
02613 
02614         /*
02615          * Error returns.
02616          */
02617  kill_task:
02618         isc_task_detach(&disp->task[0]);
02619  kill_socket:
02620         isc_socket_detach(&disp->socket);
02621  deallocate_dispatch:
02622         dispatch_free(&disp);
02623 
02624         UNLOCK(&mgr->lock);
02625 
02626         return (result);
02627 }
02628 
02629 isc_result_t
02630 dns_dispatch_gettcp(dns_dispatchmgr_t *mgr, isc_sockaddr_t *destaddr,
02631                     isc_sockaddr_t *localaddr, dns_dispatch_t **dispp)
02632 {
02633         dns_dispatch_t *disp;
02634         isc_result_t result;
02635         isc_sockaddr_t peeraddr;
02636         isc_sockaddr_t sockname;
02637         unsigned int attributes, mask;
02638         isc_boolean_t match = ISC_FALSE;
02639 
02640         REQUIRE(VALID_DISPATCHMGR(mgr));
02641         REQUIRE(destaddr != NULL);
02642         REQUIRE(dispp != NULL && *dispp == NULL);
02643 
02644         attributes = DNS_DISPATCHATTR_TCP | DNS_DISPATCHATTR_CONNECTED;
02645         mask = DNS_DISPATCHATTR_TCP | DNS_DISPATCHATTR_PRIVATE |
02646                DNS_DISPATCHATTR_EXCLUSIVE | DNS_DISPATCHATTR_CONNECTED;
02647 
02648         LOCK(&mgr->lock);
02649         disp = ISC_LIST_HEAD(mgr->list);
02650         while (disp != NULL && !match) {
02651                 LOCK(&disp->lock);
02652                 if ((disp->shutting_down == 0) &&
02653                     ATTRMATCH(disp->attributes, attributes, mask) &&
02654                     (localaddr == NULL ||
02655                      isc_sockaddr_eqaddr(localaddr, &disp->local))) {
02656                         result = isc_socket_getsockname(disp->socket,
02657                                                         &sockname);
02658                         if (result == ISC_R_SUCCESS)
02659                                 result = isc_socket_getpeername(disp->socket,
02660                                                                 &peeraddr);
02661                         if (result == ISC_R_SUCCESS &&
02662                             isc_sockaddr_equal(destaddr, &peeraddr) &&
02663                             (localaddr == NULL ||
02664                              isc_sockaddr_eqaddr(localaddr, &sockname))) {
02665                                 /* attach */
02666                                 disp->refcount++;
02667                                 *dispp = disp;
02668                                 match = ISC_TRUE;
02669                         }
02670                 }
02671                 UNLOCK(&disp->lock);
02672                 disp = ISC_LIST_NEXT(disp, link);
02673         }
02674         UNLOCK(&mgr->lock);
02675         return (match ? ISC_R_SUCCESS : ISC_R_NOTFOUND);
02676 }
02677 
02678 isc_result_t
02679 dns_dispatch_gettcp2(dns_dispatchmgr_t *mgr, isc_sockaddr_t *destaddr,
02680                      isc_sockaddr_t *localaddr, isc_boolean_t *connected,
02681                      dns_dispatch_t **dispp)
02682 {
02683         dns_dispatch_t *disp;
02684         isc_result_t result;
02685         isc_sockaddr_t peeraddr;
02686         isc_sockaddr_t sockname;
02687         unsigned int attributes, mask;
02688         isc_boolean_t match = ISC_FALSE;
02689 
02690         REQUIRE(VALID_DISPATCHMGR(mgr));
02691         REQUIRE(destaddr != NULL);
02692         REQUIRE(dispp != NULL && *dispp == NULL);
02693         REQUIRE(connected != NULL);
02694 
02695         /* First pass (same as dns_dispatch_gettcp()) */
02696         attributes = DNS_DISPATCHATTR_TCP | DNS_DISPATCHATTR_CONNECTED;
02697         mask = DNS_DISPATCHATTR_TCP | DNS_DISPATCHATTR_PRIVATE |
02698                DNS_DISPATCHATTR_EXCLUSIVE | DNS_DISPATCHATTR_CONNECTED;
02699 
02700         LOCK(&mgr->lock);
02701         disp = ISC_LIST_HEAD(mgr->list);
02702         while (disp != NULL && !match) {
02703                 LOCK(&disp->lock);
02704                 if ((disp->shutting_down == 0) &&
02705                     ATTRMATCH(disp->attributes, attributes, mask) &&
02706                     (localaddr == NULL ||
02707                      isc_sockaddr_eqaddr(localaddr, &disp->local))) {
02708                         result = isc_socket_getsockname(disp->socket,
02709                                                         &sockname);
02710                         if (result == ISC_R_SUCCESS)
02711                                 result = isc_socket_getpeername(disp->socket,
02712                                                                 &peeraddr);
02713                         if (result == ISC_R_SUCCESS &&
02714                             isc_sockaddr_equal(destaddr, &peeraddr) &&
02715                             (localaddr == NULL ||
02716                              isc_sockaddr_eqaddr(localaddr, &sockname))) {
02717                                 /* attach */
02718                                 disp->refcount++;
02719                                 *dispp = disp;
02720                                 match = ISC_TRUE;
02721                                 *connected = ISC_TRUE;
02722                         }
02723                 }
02724                 UNLOCK(&disp->lock);
02725                 disp = ISC_LIST_NEXT(disp, link);
02726         }
02727         if (match) {
02728                 UNLOCK(&mgr->lock);
02729                 return (ISC_R_SUCCESS);
02730         }
02731 
02732         /* Second pass */
02733         attributes = DNS_DISPATCHATTR_TCP;
02734 
02735         disp = ISC_LIST_HEAD(mgr->list);
02736         while (disp != NULL && !match) {
02737                 LOCK(&disp->lock);
02738                 if ((disp->shutting_down == 0) &&
02739                     ATTRMATCH(disp->attributes, attributes, mask) &&
02740                     (localaddr == NULL ||
02741                      isc_sockaddr_eqaddr(localaddr, &disp->local)) &&
02742                     isc_sockaddr_equal(destaddr, &disp->peer)) {
02743                         /* attach */
02744                         disp->refcount++;
02745                         *dispp = disp;
02746                         match = ISC_TRUE;
02747                 }
02748                 UNLOCK(&disp->lock);
02749                 disp = ISC_LIST_NEXT(disp, link);
02750         }
02751         UNLOCK(&mgr->lock);
02752         return (match ? ISC_R_SUCCESS : ISC_R_NOTFOUND);
02753 }
02754 
02755 isc_result_t
02756 dns_dispatch_getudp_dup(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr,
02757                     isc_taskmgr_t *taskmgr, isc_sockaddr_t *localaddr,
02758                     unsigned int buffersize,
02759                     unsigned int maxbuffers, unsigned int maxrequests,
02760                     unsigned int buckets, unsigned int increment,
02761                     unsigned int attributes, unsigned int mask,
02762                     dns_dispatch_t **dispp, dns_dispatch_t *dup_dispatch)
02763 {
02764         isc_result_t result;
02765         dns_dispatch_t *disp = NULL;
02766 
02767         REQUIRE(VALID_DISPATCHMGR(mgr));
02768         REQUIRE(sockmgr != NULL);
02769         REQUIRE(localaddr != NULL);
02770         REQUIRE(taskmgr != NULL);
02771         REQUIRE(buffersize >= 512 && buffersize < (64 * 1024));
02772         REQUIRE(maxbuffers > 0);
02773         REQUIRE(buckets < 2097169);  /* next prime > 65536 * 32 */
02774         REQUIRE(increment > buckets);
02775         REQUIRE(dispp != NULL && *dispp == NULL);
02776         REQUIRE((attributes & DNS_DISPATCHATTR_TCP) == 0);
02777 
02778         result = dns_dispatchmgr_setudp(mgr, buffersize, maxbuffers,
02779                                         maxrequests, buckets, increment);
02780         if (result != ISC_R_SUCCESS)
02781                 return (result);
02782 
02783         LOCK(&mgr->lock);
02784 
02785         if ((attributes & DNS_DISPATCHATTR_EXCLUSIVE) != 0) {
02786                 REQUIRE(isc_sockaddr_getport(localaddr) == 0);
02787                 goto createudp;
02788         }
02789 
02790         /*
02791          * See if we have a dispatcher that matches.
02792          */
02793         if (dup_dispatch == NULL) {
02794                 result = dispatch_find(mgr, localaddr, attributes, mask, &disp);
02795                 if (result == ISC_R_SUCCESS) {
02796                         disp->refcount++;
02797 
02798                         if (disp->maxrequests < maxrequests)
02799                                 disp->maxrequests = maxrequests;
02800 
02801                         if ((disp->attributes & DNS_DISPATCHATTR_NOLISTEN) == 0
02802                             && (attributes & DNS_DISPATCHATTR_NOLISTEN) != 0)
02803                         {
02804                                 disp->attributes |= DNS_DISPATCHATTR_NOLISTEN;
02805                                 if (disp->recv_pending != 0)
02806                                         isc_socket_cancel(disp->socket,
02807                                                           disp->task[0],
02808                                                           ISC_SOCKCANCEL_RECV);
02809                         }
02810 
02811                         UNLOCK(&disp->lock);
02812                         UNLOCK(&mgr->lock);
02813 
02814                         *dispp = disp;
02815 
02816                         return (ISC_R_SUCCESS);
02817                 }
02818         }
02819 
02820  createudp:
02821         /*
02822          * Nope, create one.
02823          */
02824         result = dispatch_createudp(mgr, sockmgr, taskmgr, localaddr,
02825                                     maxrequests, attributes, &disp,
02826                                     dup_dispatch == NULL
02827                                             ? NULL
02828                                             : dup_dispatch->socket);
02829 
02830         if (result != ISC_R_SUCCESS) {
02831                 UNLOCK(&mgr->lock);
02832                 return (result);
02833         }
02834 
02835         UNLOCK(&mgr->lock);
02836         *dispp = disp;
02837 
02838         return (ISC_R_SUCCESS);
02839 }
02840 
02841 isc_result_t
02842 dns_dispatch_getudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr,
02843                     isc_taskmgr_t *taskmgr, isc_sockaddr_t *localaddr,
02844                     unsigned int buffersize,
02845                     unsigned int maxbuffers, unsigned int maxrequests,
02846                     unsigned int buckets, unsigned int increment,
02847                     unsigned int attributes, unsigned int mask,
02848                     dns_dispatch_t **dispp)
02849 {
02850         return (dns_dispatch_getudp_dup(mgr, sockmgr, taskmgr, localaddr,
02851                                         buffersize, maxbuffers, maxrequests,
02852                                         buckets, increment, attributes,
02853                                         mask, dispp, NULL));
02854 }
02855 
02856 /*
02857  * mgr should be locked.
02858  */
02859 
02860 #ifndef DNS_DISPATCH_HELD
02861 #define DNS_DISPATCH_HELD 20U
02862 #endif
02863 
02864 static isc_result_t
02865 get_udpsocket(dns_dispatchmgr_t *mgr, dns_dispatch_t *disp,
02866               isc_socketmgr_t *sockmgr, isc_sockaddr_t *localaddr,
02867               isc_socket_t **sockp, isc_socket_t *dup_socket)
02868 {
02869         unsigned int i, j;
02870         isc_socket_t *held[DNS_DISPATCH_HELD];
02871         isc_sockaddr_t localaddr_bound;
02872         isc_socket_t *sock = NULL;
02873         isc_result_t result = ISC_R_SUCCESS;
02874         isc_boolean_t anyport;
02875 
02876         INSIST(sockp != NULL && *sockp == NULL);
02877 
02878         localaddr_bound = *localaddr;
02879         anyport = ISC_TF(isc_sockaddr_getport(localaddr) == 0);
02880 
02881         if (anyport) {
02882                 unsigned int nports;
02883                 in_port_t *ports;
02884 
02885                 /*
02886                  * If no port is specified, we first try to pick up a random
02887                  * port by ourselves.
02888                  */
02889                 if (isc_sockaddr_pf(localaddr) == AF_INET) {
02890                         nports = disp->mgr->nv4ports;
02891                         ports = disp->mgr->v4ports;
02892                 } else {
02893                         nports = disp->mgr->nv6ports;
02894                         ports = disp->mgr->v6ports;
02895                 }
02896                 if (nports == 0)
02897                         return (ISC_R_ADDRNOTAVAIL);
02898 
02899                 for (i = 0; i < 1024; i++) {
02900                         in_port_t prt;
02901 
02902                         prt = ports[isc_rng_uniformrandom(DISP_RNGCTX(disp),
02903                                                           nports)];
02904                         isc_sockaddr_setport(&localaddr_bound, prt);
02905                         result = open_socket(sockmgr, &localaddr_bound,
02906                                              0, &sock, NULL);
02907                         /*
02908                          * Continue if the port choosen is already in use
02909                          * or the OS has reserved it.
02910                          */
02911                         if (result == ISC_R_NOPERM ||
02912                             result == ISC_R_ADDRINUSE)
02913                                 continue;
02914                         disp->localport = prt;
02915                         *sockp = sock;
02916                         return (result);
02917                 }
02918 
02919                 /*
02920                  * If this fails 1024 times, we then ask the kernel for
02921                  * choosing one.
02922                  */
02923         } else {
02924                 /* Allow to reuse address for non-random ports. */
02925                 result = open_socket(sockmgr, localaddr,
02926                                      ISC_SOCKET_REUSEADDRESS, &sock,
02927                                      dup_socket);
02928 
02929                 if (result == ISC_R_SUCCESS)
02930                         *sockp = sock;
02931 
02932                 return (result);
02933         }
02934 
02935         memset(held, 0, sizeof(held));
02936         i = 0;
02937 
02938         for (j = 0; j < 0xffffU; j++) {
02939                 result = open_socket(sockmgr, localaddr, 0, &sock, NULL);
02940                 if (result != ISC_R_SUCCESS)
02941                         goto end;
02942                 else if (portavailable(mgr, sock, NULL))
02943                         break;
02944                 if (held[i] != NULL)
02945                         isc_socket_detach(&held[i]);
02946                 held[i++] = sock;
02947                 sock = NULL;
02948                 if (i == DNS_DISPATCH_HELD)
02949                         i = 0;
02950         }
02951         if (j == 0xffffU) {
02952                 mgr_log(mgr, ISC_LOG_ERROR,
02953                         "avoid-v%s-udp-ports: unable to allocate "
02954                         "an available port",
02955                         isc_sockaddr_pf(localaddr) == AF_INET ? "4" : "6");
02956                 result = ISC_R_FAILURE;
02957                 goto end;
02958         }
02959         *sockp = sock;
02960 
02961 end:
02962         for (i = 0; i < DNS_DISPATCH_HELD; i++) {
02963                 if (held[i] != NULL)
02964                         isc_socket_detach(&held[i]);
02965         }
02966 
02967         return (result);
02968 }
02969 
02970 static isc_result_t
02971 dispatch_createudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr,
02972                    isc_taskmgr_t *taskmgr,
02973                    isc_sockaddr_t *localaddr,
02974                    unsigned int maxrequests,
02975                    unsigned int attributes,
02976                    dns_dispatch_t **dispp,
02977                    isc_socket_t *dup_socket)
02978 {
02979         isc_result_t result;
02980         dns_dispatch_t *disp;
02981         isc_socket_t *sock = NULL;
02982         int i = 0;
02983 
02984         /*
02985          * dispatch_allocate() checks mgr for us.
02986          */
02987         disp = NULL;
02988         result = dispatch_allocate(mgr, maxrequests, &disp);
02989         if (result != ISC_R_SUCCESS)
02990                 return (result);
02991 
02992         disp->socktype = isc_sockettype_udp;
02993 
02994         if ((attributes & DNS_DISPATCHATTR_EXCLUSIVE) == 0) {
02995                 result = get_udpsocket(mgr, disp, sockmgr, localaddr, &sock,
02996                                        dup_socket);
02997                 if (result != ISC_R_SUCCESS)
02998                         goto deallocate_dispatch;
02999 
03000                 if (isc_log_wouldlog(dns_lctx, 90)) {
03001                         char addrbuf[ISC_SOCKADDR_FORMATSIZE];
03002 
03003                         isc_sockaddr_format(localaddr, addrbuf,
03004                                             ISC_SOCKADDR_FORMATSIZE);
03005                         mgr_log(mgr, LVL(90), "dns_dispatch_createudp: Created"
03006                                 " UDP dispatch for %s with socket fd %d\n",
03007                                 addrbuf, isc_socket_getfd(sock));
03008                 }
03009 
03010         } else {
03011                 isc_sockaddr_t sa_any;
03012 
03013                 /*
03014                  * For dispatches using exclusive sockets with a specific
03015                  * source address, we only check if the specified address is
03016                  * available on the system.  Query sockets will be created later
03017                  * on demand.
03018                  */
03019                 isc_sockaddr_anyofpf(&sa_any, isc_sockaddr_pf(localaddr));
03020                 if (!isc_sockaddr_eqaddr(&sa_any, localaddr)) {
03021                         result = open_socket(sockmgr, localaddr, 0, &sock, NULL);
03022                         if (sock != NULL)
03023                                 isc_socket_detach(&sock);
03024                         if (result != ISC_R_SUCCESS)
03025                                 goto deallocate_dispatch;
03026                 }
03027 
03028                 disp->port_table = isc_mem_get(mgr->mctx,
03029                                                sizeof(disp->port_table[0]) *
03030                                                DNS_DISPATCH_PORTTABLESIZE);
03031                 if (disp->port_table == NULL)
03032                         goto deallocate_dispatch;
03033                 for (i = 0; i < DNS_DISPATCH_PORTTABLESIZE; i++)
03034                         ISC_LIST_INIT(disp->port_table[i]);
03035 
03036                 result = isc_mempool_create(mgr->mctx, sizeof(dispportentry_t),
03037                                             &disp->portpool);
03038                 if (result != ISC_R_SUCCESS)
03039                         goto deallocate_dispatch;
03040                 isc_mempool_setname(disp->portpool, "disp_portpool");
03041                 isc_mempool_setfreemax(disp->portpool, 128);
03042         }
03043         disp->socket = sock;
03044         disp->local = *localaddr;
03045 
03046         if ((attributes & DNS_DISPATCHATTR_EXCLUSIVE) != 0)
03047                 disp->ntasks = MAX_INTERNAL_TASKS;
03048         else
03049                 disp->ntasks = 1;
03050         for (i = 0; i < disp->ntasks; i++) {
03051                 disp->task[i] = NULL;
03052                 result = isc_task_create(taskmgr, 0, &disp->task[i]);
03053                 if (result != ISC_R_SUCCESS) {
03054                         while (--i >= 0) {
03055                                 isc_task_shutdown(disp->task[i]);
03056                                 isc_task_detach(&disp->task[i]);
03057                         }
03058                         goto kill_socket;
03059                 }
03060                 isc_task_setname(disp->task[i], "udpdispatch", disp);
03061         }
03062 
03063         disp->ctlevent = isc_event_allocate(mgr->mctx, disp,
03064                                             DNS_EVENT_DISPATCHCONTROL,
03065                                             destroy_disp, disp,
03066                                             sizeof(isc_event_t));
03067         if (disp->ctlevent == NULL) {
03068                 result = ISC_R_NOMEMORY;
03069                 goto kill_task;
03070         }
03071 
03072         disp->sepool = NULL;
03073         if (isc_mempool_create(mgr->mctx, sizeof(isc_socketevent_t),
03074                                &disp->sepool) != ISC_R_SUCCESS)
03075         {
03076                 result = ISC_R_NOMEMORY;
03077                 goto kill_ctlevent;
03078         }
03079 
03080         result = isc_mutex_init(&disp->sepool_lock);
03081         if (result != ISC_R_SUCCESS)
03082                 goto kill_sepool;
03083 
03084         isc_mempool_setname(disp->sepool, "disp_sepool");
03085         isc_mempool_setmaxalloc(disp->sepool, 32768);
03086         isc_mempool_setfreemax(disp->sepool, 32768);
03087         isc_mempool_associatelock(disp->sepool, &disp->sepool_lock);
03088         isc_mempool_setfillcount(disp->sepool, 16);
03089 
03090         attributes &= ~DNS_DISPATCHATTR_TCP;
03091         attributes |= DNS_DISPATCHATTR_UDP;
03092         disp->attributes = attributes;
03093 
03094         /*
03095          * Append it to the dispatcher list.
03096          */
03097         ISC_LIST_APPEND(mgr->list, disp, link);
03098 
03099         mgr_log(mgr, LVL(90), "created UDP dispatcher %p", disp);
03100         dispatch_log(disp, LVL(90), "created task %p", disp->task[0]); /* XXX */
03101         if (disp->socket != NULL)
03102                 dispatch_log(disp, LVL(90), "created socket %p", disp->socket);
03103 
03104         *dispp = disp;
03105 
03106         return (result);
03107 
03108         /*
03109          * Error returns.
03110          */
03111  kill_sepool:
03112         isc_mempool_destroy(&disp->sepool);
03113  kill_ctlevent:
03114         isc_event_free(&disp->ctlevent);
03115  kill_task:
03116         for (i = 0; i < disp->ntasks; i++)
03117                 isc_task_detach(&disp->task[i]);
03118  kill_socket:
03119         if (disp->socket != NULL)
03120                 isc_socket_detach(&disp->socket);
03121  deallocate_dispatch:
03122         dispatch_free(&disp);
03123 
03124         return (result);
03125 }
03126 
03127 void
03128 dns_dispatch_attach(dns_dispatch_t *disp, dns_dispatch_t **dispp) {
03129         REQUIRE(VALID_DISPATCH(disp));
03130         REQUIRE(dispp != NULL && *dispp == NULL);
03131 
03132         LOCK(&disp->lock);
03133         disp->refcount++;
03134         UNLOCK(&disp->lock);
03135 
03136         *dispp = disp;
03137 }
03138 
03139 /*
03140  * It is important to lock the manager while we are deleting the dispatch,
03141  * since dns_dispatch_getudp will call dispatch_find, which returns to
03142  * the caller a dispatch but does not attach to it until later.  _getudp
03143  * locks the manager, however, so locking it here will keep us from attaching
03144  * to a dispatcher that is in the process of going away.
03145  */
03146 void
03147 dns_dispatch_detach(dns_dispatch_t **dispp) {
03148         dns_dispatch_t *disp;
03149         dispsocket_t *dispsock;
03150         isc_boolean_t killit;
03151 
03152         REQUIRE(dispp != NULL && VALID_DISPATCH(*dispp));
03153 
03154         disp = *dispp;
03155         *dispp = NULL;
03156 
03157         LOCK(&disp->lock);
03158 
03159         INSIST(disp->refcount > 0);
03160         disp->refcount--;
03161         if (disp->refcount == 0) {
03162                 if (disp->recv_pending > 0)
03163                         isc_socket_cancel(disp->socket, disp->task[0],
03164                                           ISC_SOCKCANCEL_RECV);
03165                 for (dispsock = ISC_LIST_HEAD(disp->activesockets);
03166                      dispsock != NULL;
03167                      dispsock = ISC_LIST_NEXT(dispsock, link)) {
03168                         isc_socket_cancel(dispsock->socket, dispsock->task,
03169                                           ISC_SOCKCANCEL_RECV);
03170                 }
03171                 disp->shutting_down = 1;
03172         }
03173 
03174         dispatch_log(disp, LVL(90), "detach: refcount %d", disp->refcount);
03175 
03176         killit = destroy_disp_ok(disp);
03177         UNLOCK(&disp->lock);
03178         if (killit)
03179                 isc_task_send(disp->task[0], &disp->ctlevent);
03180 }
03181 
03182 isc_result_t
03183 dns_dispatch_addresponse2(dns_dispatch_t *disp, isc_sockaddr_t *dest,
03184                           isc_task_t *task, isc_taskaction_t action, void *arg,
03185                           dns_messageid_t *idp, dns_dispentry_t **resp,
03186                           isc_socketmgr_t *sockmgr)
03187 {
03188         return (dns_dispatch_addresponse3(disp, 0, dest, task, action, arg,
03189                                           idp, resp, sockmgr));
03190 }
03191 
03192 isc_result_t
03193 dns_dispatch_addresponse3(dns_dispatch_t *disp, unsigned int options,
03194                           isc_sockaddr_t *dest, isc_task_t *task,
03195                           isc_taskaction_t action, void *arg,
03196                           dns_messageid_t *idp, dns_dispentry_t **resp,
03197                           isc_socketmgr_t *sockmgr)
03198 {
03199         dns_dispentry_t *res;
03200         unsigned int bucket;
03201         in_port_t localport = 0;
03202         dns_messageid_t id;
03203         int i;
03204         isc_boolean_t ok;
03205         dns_qid_t *qid;
03206         dispsocket_t *dispsocket = NULL;
03207         isc_result_t result;
03208 
03209         REQUIRE(VALID_DISPATCH(disp));
03210         REQUIRE(task != NULL);
03211         REQUIRE(dest != NULL);
03212         REQUIRE(resp != NULL && *resp == NULL);
03213         REQUIRE(idp != NULL);
03214         if ((disp->attributes & DNS_DISPATCHATTR_EXCLUSIVE) != 0)
03215                 REQUIRE(sockmgr != NULL);
03216 
03217         LOCK(&disp->lock);
03218 
03219         if (disp->shutting_down == 1) {
03220                 UNLOCK(&disp->lock);
03221                 return (ISC_R_SHUTTINGDOWN);
03222         }
03223 
03224         if (disp->requests >= disp->maxrequests) {
03225                 UNLOCK(&disp->lock);
03226                 return (ISC_R_QUOTA);
03227         }
03228 
03229         if ((disp->attributes & DNS_DISPATCHATTR_EXCLUSIVE) != 0 &&
03230             disp->nsockets > DNS_DISPATCH_SOCKSQUOTA) {
03231                 dispsocket_t *oldestsocket;
03232                 dns_dispentry_t *oldestresp;
03233                 dns_dispatchevent_t *rev;
03234 
03235                 /*
03236                  * Kill oldest outstanding query if the number of sockets
03237                  * exceeds the quota to keep the room for new queries.
03238                  */
03239                 oldestsocket = ISC_LIST_HEAD(disp->activesockets);
03240                 oldestresp = oldestsocket->resp;
03241                 if (oldestresp != NULL && !oldestresp->item_out) {
03242                         rev = allocate_devent(oldestresp->disp);
03243                         if (rev != NULL) {
03244                                 rev->buffer.base = NULL;
03245                                 rev->result = ISC_R_CANCELED;
03246                                 rev->id = oldestresp->id;
03247                                 ISC_EVENT_INIT(rev, sizeof(*rev), 0,
03248                                                NULL, DNS_EVENT_DISPATCH,
03249                                                oldestresp->action,
03250                                                oldestresp->arg, oldestresp,
03251                                                NULL, NULL);
03252                                 oldestresp->item_out = ISC_TRUE;
03253                                 isc_task_send(oldestresp->task,
03254                                               ISC_EVENT_PTR(&rev));
03255                                 inc_stats(disp->mgr,
03256                                           dns_resstatscounter_dispabort);
03257                         }
03258                 }
03259 
03260                 /*
03261                  * Move this entry to the tail so that it won't (easily) be
03262                  * examined before actually being canceled.
03263                  */
03264                 ISC_LIST_UNLINK(disp->activesockets, oldestsocket, link);
03265                 ISC_LIST_APPEND(disp->activesockets, oldestsocket, link);
03266         }
03267 
03268         qid = DNS_QID(disp);
03269 
03270         if ((disp->attributes & DNS_DISPATCHATTR_EXCLUSIVE) != 0) {
03271                 /*
03272                  * Get a separate UDP socket with a random port number.
03273                  */
03274                 result = get_dispsocket(disp, dest, sockmgr, &dispsocket,
03275                                         &localport);
03276                 if (result != ISC_R_SUCCESS) {
03277                         UNLOCK(&disp->lock);
03278                         inc_stats(disp->mgr, dns_resstatscounter_dispsockfail);
03279                         return (result);
03280                 }
03281         } else {
03282                 localport = disp->localport;
03283         }
03284 
03285         /*
03286          * Try somewhat hard to find an unique ID unless FIXEDID is set
03287          * in which case we use the id passed in via *idp.
03288          */
03289         LOCK(&qid->lock);
03290         if ((options & DNS_DISPATCHOPT_FIXEDID) != 0)
03291                 id = *idp;
03292         else
03293                 id = (dns_messageid_t)isc_rng_random(DISP_RNGCTX(disp));
03294         ok = ISC_FALSE;
03295         i = 0;
03296         do {
03297                 bucket = dns_hash(qid, dest, id, localport);
03298                 if (entry_search(qid, dest, id, localport, bucket) == NULL) {
03299                         ok = ISC_TRUE;
03300                         break;
03301                 }
03302                 if ((disp->attributes & DNS_DISPATCHATTR_FIXEDID) != 0)
03303                         break;
03304                 id += qid->qid_increment;
03305                 id &= 0x0000ffff;
03306         } while (i++ < 64);
03307         UNLOCK(&qid->lock);
03308 
03309         if (!ok) {
03310                 UNLOCK(&disp->lock);
03311                 return (ISC_R_NOMORE);
03312         }
03313 
03314         res = isc_mempool_get(disp->mgr->rpool);
03315         if (res == NULL) {
03316                 if (dispsocket != NULL)
03317                         destroy_dispsocket(disp, &dispsocket);
03318                 UNLOCK(&disp->lock);
03319                 return (ISC_R_NOMEMORY);
03320         }
03321 
03322         disp->refcount++;
03323         disp->requests++;
03324         res->task = NULL;
03325         isc_task_attach(task, &res->task);
03326         res->disp = disp;
03327         res->id = id;
03328         res->port = localport;
03329         res->bucket = bucket;
03330         res->host = *dest;
03331         res->action = action;
03332         res->arg = arg;
03333         res->dispsocket = dispsocket;
03334         if (dispsocket != NULL)
03335                 dispsocket->resp = res;
03336         res->item_out = ISC_FALSE;
03337         ISC_LIST_INIT(res->items);
03338         ISC_LINK_INIT(res, link);
03339         res->magic = RESPONSE_MAGIC;
03340 
03341         LOCK(&qid->lock);
03342         ISC_LIST_APPEND(qid->qid_table[bucket], res, link);
03343         UNLOCK(&qid->lock);
03344 
03345         inc_stats(disp->mgr, (qid == disp->mgr->qid) ?
03346                              dns_resstatscounter_disprequdp :
03347                              dns_resstatscounter_dispreqtcp);
03348 
03349         request_log(disp, res, LVL(90),
03350                     "attached to task %p", res->task);
03351 
03352         if (((disp->attributes & DNS_DISPATCHATTR_UDP) != 0) ||
03353             ((disp->attributes & DNS_DISPATCHATTR_CONNECTED) != 0)) {
03354                 result = startrecv(disp, dispsocket);
03355                 if (result != ISC_R_SUCCESS) {
03356                         LOCK(&qid->lock);
03357                         ISC_LIST_UNLINK(qid->qid_table[bucket], res, link);
03358                         UNLOCK(&qid->lock);
03359 
03360                         if (dispsocket != NULL)
03361                                 destroy_dispsocket(disp, &dispsocket);
03362 
03363                         disp->refcount--;
03364                         disp->requests--;
03365 
03366                         dec_stats(disp->mgr, (qid == disp->mgr->qid) ?
03367                                              dns_resstatscounter_disprequdp :
03368                                              dns_resstatscounter_dispreqtcp);
03369 
03370                         UNLOCK(&disp->lock);
03371                         isc_task_detach(&res->task);
03372                         isc_mempool_put(disp->mgr->rpool, res);
03373                         return (result);
03374                 }
03375         }
03376 
03377         if (dispsocket != NULL)
03378                 ISC_LIST_APPEND(disp->activesockets, dispsocket, link);
03379 
03380         UNLOCK(&disp->lock);
03381 
03382         *idp = id;
03383         *resp = res;
03384 
03385         if ((disp->attributes & DNS_DISPATCHATTR_EXCLUSIVE) != 0)
03386                 INSIST(res->dispsocket != NULL);
03387 
03388         return (ISC_R_SUCCESS);
03389 }
03390 
03391 isc_result_t
03392 dns_dispatch_addresponse(dns_dispatch_t *disp, isc_sockaddr_t *dest,
03393                          isc_task_t *task, isc_taskaction_t action, void *arg,
03394                          dns_messageid_t *idp, dns_dispentry_t **resp)
03395 {
03396         REQUIRE(VALID_DISPATCH(disp));
03397         REQUIRE((disp->attributes & DNS_DISPATCHATTR_EXCLUSIVE) == 0);
03398 
03399         return (dns_dispatch_addresponse3(disp, 0, dest, task, action, arg,
03400                                           idp, resp, NULL));
03401 }
03402 
03403 void
03404 dns_dispatch_starttcp(dns_dispatch_t *disp) {
03405 
03406         REQUIRE(VALID_DISPATCH(disp));
03407 
03408         dispatch_log(disp, LVL(90), "starttcp %p", disp->task[0]);
03409 
03410         LOCK(&disp->lock);
03411         if ((disp->attributes & DNS_DISPATCHATTR_CONNECTED) == 0) {
03412                 disp->attributes |= DNS_DISPATCHATTR_CONNECTED;
03413                 (void)startrecv(disp, NULL);
03414         }
03415         UNLOCK(&disp->lock);
03416 }
03417 
03418 void
03419 dns_dispatch_removeresponse(dns_dispentry_t **resp,
03420                             dns_dispatchevent_t **sockevent)
03421 {
03422         dns_dispatchmgr_t *mgr;
03423         dns_dispatch_t *disp;
03424         dns_dispentry_t *res;
03425         dispsocket_t *dispsock;
03426         dns_dispatchevent_t *ev;
03427         unsigned int bucket;
03428         isc_boolean_t killit;
03429         unsigned int n;
03430         isc_eventlist_t events;
03431         dns_qid_t *qid;
03432 
03433         REQUIRE(resp != NULL);
03434         REQUIRE(VALID_RESPONSE(*resp));
03435 
03436         res = *resp;
03437         *resp = NULL;
03438 
03439         disp = res->disp;
03440         REQUIRE(VALID_DISPATCH(disp));
03441         mgr = disp->mgr;
03442         REQUIRE(VALID_DISPATCHMGR(mgr));
03443 
03444         qid = DNS_QID(disp);
03445 
03446         if (sockevent != NULL) {
03447                 REQUIRE(*sockevent != NULL);
03448                 ev = *sockevent;
03449                 *sockevent = NULL;
03450         } else {
03451                 ev = NULL;
03452         }
03453 
03454         LOCK(&disp->lock);
03455 
03456         INSIST(disp->requests > 0);
03457         disp->requests--;
03458         dec_stats(disp->mgr, (qid == disp->mgr->qid) ?
03459                              dns_resstatscounter_disprequdp :
03460                              dns_resstatscounter_dispreqtcp);
03461         INSIST(disp->refcount > 0);
03462         disp->refcount--;
03463         if (disp->refcount == 0) {
03464                 if (disp->recv_pending > 0)
03465                         isc_socket_cancel(disp->socket, disp->task[0],
03466                                           ISC_SOCKCANCEL_RECV);
03467                 for (dispsock = ISC_LIST_HEAD(disp->activesockets);
03468                      dispsock != NULL;
03469                      dispsock = ISC_LIST_NEXT(dispsock, link)) {
03470                         isc_socket_cancel(dispsock->socket, dispsock->task,
03471                                           ISC_SOCKCANCEL_RECV);
03472                 }
03473                 disp->shutting_down = 1;
03474         }
03475 
03476         bucket = res->bucket;
03477 
03478         LOCK(&qid->lock);
03479         ISC_LIST_UNLINK(qid->qid_table[bucket], res, link);
03480         UNLOCK(&qid->lock);
03481 
03482         if (ev == NULL && res->item_out) {
03483                 /*
03484                  * We've posted our event, but the caller hasn't gotten it
03485                  * yet.  Take it back.
03486                  */
03487                 ISC_LIST_INIT(events);
03488                 n = isc_task_unsend(res->task, res, DNS_EVENT_DISPATCH,
03489                                     NULL, &events);
03490                 /*
03491                  * We had better have gotten it back.
03492                  */
03493                 INSIST(n == 1);
03494                 ev = (dns_dispatchevent_t *)ISC_LIST_HEAD(events);
03495         }
03496 
03497         if (ev != NULL) {
03498                 REQUIRE(res->item_out == ISC_TRUE);
03499                 res->item_out = ISC_FALSE;
03500                 if (ev->buffer.base != NULL)
03501                         free_buffer(disp, ev->buffer.base, ev->buffer.length);
03502                 free_devent(disp, ev);
03503         }
03504 
03505         request_log(disp, res, LVL(90), "detaching from task %p", res->task);
03506         isc_task_detach(&res->task);
03507 
03508         if (res->dispsocket != NULL) {
03509                 isc_socket_cancel(res->dispsocket->socket,
03510                                   res->dispsocket->task, ISC_SOCKCANCEL_RECV);
03511                 res->dispsocket->resp = NULL;
03512         }
03513 
03514         /*
03515          * Free any buffered requests as well
03516          */
03517         ev = ISC_LIST_HEAD(res->items);
03518         while (ev != NULL) {
03519                 ISC_LIST_UNLINK(res->items, ev, ev_link);
03520                 if (ev->buffer.base != NULL)
03521                         free_buffer(disp, ev->buffer.base, ev->buffer.length);
03522                 free_devent(disp, ev);
03523                 ev = ISC_LIST_HEAD(res->items);
03524         }
03525         res->magic = 0;
03526         isc_mempool_put(disp->mgr->rpool, res);
03527         if (disp->shutting_down == 1)
03528                 do_cancel(disp);
03529         else
03530                 (void)startrecv(disp, NULL);
03531 
03532         killit = destroy_disp_ok(disp);
03533         UNLOCK(&disp->lock);
03534         if (killit)
03535                 isc_task_send(disp->task[0], &disp->ctlevent);
03536 }
03537 
03538 static void
03539 do_cancel(dns_dispatch_t *disp) {
03540         dns_dispatchevent_t *ev;
03541         dns_dispentry_t *resp;
03542         dns_qid_t *qid;
03543 
03544         if (disp->shutdown_out == 1)
03545                 return;
03546 
03547         qid = DNS_QID(disp);
03548 
03549         /*
03550          * Search for the first response handler without packets outstanding
03551          * unless a specific hander is given.
03552          */
03553         LOCK(&qid->lock);
03554         for (resp = linear_first(qid);
03555              resp != NULL && resp->item_out;
03556              /* Empty. */)
03557                 resp = linear_next(qid, resp);
03558 
03559         /*
03560          * No one to send the cancel event to, so nothing to do.
03561          */
03562         if (resp == NULL)
03563                 goto unlock;
03564 
03565         /*
03566          * Send the shutdown failsafe event to this resp.
03567          */
03568         ev = disp->failsafe_ev;
03569         ISC_EVENT_INIT(ev, sizeof(*ev), 0, NULL, DNS_EVENT_DISPATCH,
03570                        resp->action, resp->arg, resp, NULL, NULL);
03571         ev->result = disp->shutdown_why;
03572         ev->buffer.base = NULL;
03573         ev->buffer.length = 0;
03574         disp->shutdown_out = 1;
03575         request_log(disp, resp, LVL(10),
03576                     "cancel: failsafe event %p -> task %p",
03577                     ev, resp->task);
03578         resp->item_out = ISC_TRUE;
03579         isc_task_send(resp->task, ISC_EVENT_PTR(&ev));
03580  unlock:
03581         UNLOCK(&qid->lock);
03582 }
03583 
03584 isc_socket_t *
03585 dns_dispatch_getsocket(dns_dispatch_t *disp) {
03586         REQUIRE(VALID_DISPATCH(disp));
03587 
03588         return (disp->socket);
03589 }
03590 
03591 isc_socket_t *
03592 dns_dispatch_getentrysocket(dns_dispentry_t *resp) {
03593         REQUIRE(VALID_RESPONSE(resp));
03594 
03595         if (resp->dispsocket != NULL)
03596                 return (resp->dispsocket->socket);
03597         else
03598                 return (NULL);
03599 }
03600 
03601 isc_result_t
03602 dns_dispatch_getlocaladdress(dns_dispatch_t *disp, isc_sockaddr_t *addrp) {
03603 
03604         REQUIRE(VALID_DISPATCH(disp));
03605         REQUIRE(addrp != NULL);
03606 
03607         if (disp->socktype == isc_sockettype_udp) {
03608                 *addrp = disp->local;
03609                 return (ISC_R_SUCCESS);
03610         }
03611         return (ISC_R_NOTIMPLEMENTED);
03612 }
03613 
03614 void
03615 dns_dispatch_cancel(dns_dispatch_t *disp) {
03616         REQUIRE(VALID_DISPATCH(disp));
03617 
03618         LOCK(&disp->lock);
03619 
03620         if (disp->shutting_down == 1) {
03621                 UNLOCK(&disp->lock);
03622                 return;
03623         }
03624 
03625         disp->shutdown_why = ISC_R_CANCELED;
03626         disp->shutting_down = 1;
03627         do_cancel(disp);
03628 
03629         UNLOCK(&disp->lock);
03630 
03631         return;
03632 }
03633 
03634 unsigned int
03635 dns_dispatch_getattributes(dns_dispatch_t *disp) {
03636         REQUIRE(VALID_DISPATCH(disp));
03637 
03638         /*
03639          * We don't bother locking disp here; it's the caller's responsibility
03640          * to use only non volatile flags.
03641          */
03642         return (disp->attributes);
03643 }
03644 
03645 void
03646 dns_dispatch_changeattributes(dns_dispatch_t *disp,
03647                               unsigned int attributes, unsigned int mask)
03648 {
03649         REQUIRE(VALID_DISPATCH(disp));
03650         /* Exclusive attribute can only be set on creation */
03651         REQUIRE((attributes & DNS_DISPATCHATTR_EXCLUSIVE) == 0);
03652         /* Also, a dispatch with randomport specified cannot start listening */
03653         REQUIRE((disp->attributes & DNS_DISPATCHATTR_EXCLUSIVE) == 0 ||
03654                 (attributes & DNS_DISPATCHATTR_NOLISTEN) == 0);
03655 
03656         /* XXXMLG
03657          * Should check for valid attributes here!
03658          */
03659 
03660         LOCK(&disp->lock);
03661 
03662         if ((mask & DNS_DISPATCHATTR_NOLISTEN) != 0) {
03663                 if ((disp->attributes & DNS_DISPATCHATTR_NOLISTEN) != 0 &&
03664                     (attributes & DNS_DISPATCHATTR_NOLISTEN) == 0) {
03665                         disp->attributes &= ~DNS_DISPATCHATTR_NOLISTEN;
03666                         (void)startrecv(disp, NULL);
03667                 } else if ((disp->attributes & DNS_DISPATCHATTR_NOLISTEN)
03668                            == 0 &&
03669                            (attributes & DNS_DISPATCHATTR_NOLISTEN) != 0) {
03670                         disp->attributes |= DNS_DISPATCHATTR_NOLISTEN;
03671                         if (disp->recv_pending != 0)
03672                                 isc_socket_cancel(disp->socket, disp->task[0],
03673                                                   ISC_SOCKCANCEL_RECV);
03674                 }
03675         }
03676 
03677         disp->attributes &= ~mask;
03678         disp->attributes |= (attributes & mask);
03679         UNLOCK(&disp->lock);
03680 }
03681 
03682 void
03683 dns_dispatch_importrecv(dns_dispatch_t *disp, isc_event_t *event) {
03684         void *buf;
03685         isc_socketevent_t *sevent, *newsevent;
03686 
03687         REQUIRE(VALID_DISPATCH(disp));
03688         REQUIRE((disp->attributes & DNS_DISPATCHATTR_NOLISTEN) != 0);
03689         REQUIRE(event != NULL);
03690 
03691         sevent = (isc_socketevent_t *)event;
03692 
03693         INSIST(sevent->n <= disp->mgr->buffersize);
03694         newsevent = (isc_socketevent_t *)
03695                     isc_event_allocate(disp->mgr->mctx, NULL,
03696                                       DNS_EVENT_IMPORTRECVDONE, udp_shrecv,
03697                                       disp, sizeof(isc_socketevent_t));
03698         if (newsevent == NULL)
03699                 return;
03700 
03701         buf = allocate_udp_buffer(disp);
03702         if (buf == NULL) {
03703                 isc_event_free(ISC_EVENT_PTR(&newsevent));
03704                 return;
03705         }
03706         memmove(buf, sevent->region.base, sevent->n);
03707         newsevent->region.base = buf;
03708         newsevent->region.length = disp->mgr->buffersize;
03709         newsevent->n = sevent->n;
03710         newsevent->result = sevent->result;
03711         newsevent->address = sevent->address;
03712         newsevent->timestamp = sevent->timestamp;
03713         newsevent->pktinfo = sevent->pktinfo;
03714         newsevent->attributes = sevent->attributes;
03715 
03716         isc_task_send(disp->task[0], ISC_EVENT_PTR(&newsevent));
03717 }
03718 
03719 dns_dispatch_t *
03720 dns_dispatchset_get(dns_dispatchset_t *dset) {
03721         dns_dispatch_t *disp;
03722 
03723         /* check that dispatch set is configured */
03724         if (dset == NULL || dset->ndisp == 0)
03725                 return (NULL);
03726 
03727         LOCK(&dset->lock);
03728         disp = dset->dispatches[dset->cur];
03729         dset->cur++;
03730         if (dset->cur == dset->ndisp)
03731                 dset->cur = 0;
03732         UNLOCK(&dset->lock);
03733 
03734         return (disp);
03735 }
03736 
03737 isc_result_t
03738 dns_dispatchset_create(isc_mem_t *mctx, isc_socketmgr_t *sockmgr,
03739                        isc_taskmgr_t *taskmgr, dns_dispatch_t *source,
03740                        dns_dispatchset_t **dsetp, int n)
03741 {
03742         isc_result_t result;
03743         dns_dispatchset_t *dset;
03744         dns_dispatchmgr_t *mgr;
03745         int i, j;
03746 
03747         REQUIRE(VALID_DISPATCH(source));
03748         REQUIRE((source->attributes & DNS_DISPATCHATTR_UDP) != 0);
03749         REQUIRE(dsetp != NULL && *dsetp == NULL);
03750 
03751         mgr = source->mgr;
03752 
03753         dset = isc_mem_get(mctx, sizeof(dns_dispatchset_t));
03754         if (dset == NULL)
03755                 return (ISC_R_NOMEMORY);
03756         memset(dset, 0, sizeof(*dset));
03757 
03758         result = isc_mutex_init(&dset->lock);
03759         if (result != ISC_R_SUCCESS)
03760                 goto fail_alloc;
03761 
03762         dset->dispatches = isc_mem_get(mctx, sizeof(dns_dispatch_t *) * n);
03763         if (dset->dispatches == NULL) {
03764                 result = ISC_R_NOMEMORY;
03765                 goto fail_lock;
03766         }
03767 
03768         isc_mem_attach(mctx, &dset->mctx);
03769         dset->ndisp = n;
03770         dset->cur = 0;
03771 
03772         dset->dispatches[0] = NULL;
03773         dns_dispatch_attach(source, &dset->dispatches[0]);
03774 
03775         LOCK(&mgr->lock);
03776         for (i = 1; i < n; i++) {
03777                 dset->dispatches[i] = NULL;
03778                 result = dispatch_createudp(mgr, sockmgr, taskmgr,
03779                                             &source->local,
03780                                             source->maxrequests,
03781                                             source->attributes,
03782                                             &dset->dispatches[i],
03783                                             source->socket);
03784                 if (result != ISC_R_SUCCESS)
03785                         goto fail;
03786         }
03787 
03788         UNLOCK(&mgr->lock);
03789         *dsetp = dset;
03790 
03791         return (ISC_R_SUCCESS);
03792 
03793  fail:
03794         UNLOCK(&mgr->lock);
03795 
03796         for (j = 0; j < i; j++)
03797                 dns_dispatch_detach(&(dset->dispatches[j]));
03798         isc_mem_put(mctx, dset->dispatches, sizeof(dns_dispatch_t *) * n);
03799         if (dset->mctx == mctx)
03800                 isc_mem_detach(&dset->mctx);
03801 
03802  fail_lock:
03803         DESTROYLOCK(&dset->lock);
03804 
03805  fail_alloc:
03806         isc_mem_put(mctx, dset, sizeof(dns_dispatchset_t));
03807         return (result);
03808 }
03809 
03810 void
03811 dns_dispatchset_cancelall(dns_dispatchset_t *dset, isc_task_t *task) {
03812         int i;
03813 
03814         REQUIRE(dset != NULL);
03815 
03816         for (i = 0; i < dset->ndisp; i++) {
03817                 isc_socket_t *sock;
03818                 sock = dns_dispatch_getsocket(dset->dispatches[i]);
03819                 isc_socket_cancel(sock, task, ISC_SOCKCANCEL_ALL);
03820         }
03821 }
03822 
03823 void
03824 dns_dispatchset_destroy(dns_dispatchset_t **dsetp) {
03825         dns_dispatchset_t *dset;
03826         int i;
03827 
03828         REQUIRE(dsetp != NULL && *dsetp != NULL);
03829 
03830         dset = *dsetp;
03831         for (i = 0; i < dset->ndisp; i++)
03832                 dns_dispatch_detach(&(dset->dispatches[i]));
03833         isc_mem_put(dset->mctx, dset->dispatches,
03834                     sizeof(dns_dispatch_t *) * dset->ndisp);
03835         DESTROYLOCK(&dset->lock);
03836         isc_mem_putanddetach(&dset->mctx, dset, sizeof(dns_dispatchset_t));
03837 
03838         *dsetp = NULL;
03839 }
03840 
03841 void
03842 dns_dispatch_setdscp(dns_dispatch_t *disp, isc_dscp_t dscp) {
03843         REQUIRE(VALID_DISPATCH(disp));
03844         disp->dscp = dscp;
03845 }
03846 
03847 isc_dscp_t
03848 dns_dispatch_getdscp(dns_dispatch_t *disp) {
03849         REQUIRE(VALID_DISPATCH(disp));
03850         return (disp->dscp);
03851 }
03852 
03853 #if 0
03854 void
03855 dns_dispatchmgr_dump(dns_dispatchmgr_t *mgr) {
03856         dns_dispatch_t *disp;
03857         char foo[1024];
03858 
03859         disp = ISC_LIST_HEAD(mgr->list);
03860         while (disp != NULL) {
03861                 isc_sockaddr_format(&disp->local, foo, sizeof(foo));
03862                 printf("\tdispatch %p, addr %s\n", disp, foo);
03863                 disp = ISC_LIST_NEXT(disp, link);
03864         }
03865 }
03866 #endif

Generated on Tue Apr 28 17:40:56 2015 by Doxygen 1.5.4 for BIND9 Internals 9.11.0pre-alpha