00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
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;
00061 unsigned int qid_increment;
00062 isc_mutex_t lock;
00063 dns_displist_t *qid_table;
00064 dispsocketlist_t *sock_table;
00065 } dns_qid_t;
00066
00067 struct dns_dispatchmgr {
00068
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;
00075
00076
00077 isc_mutex_t lock;
00078 unsigned int state;
00079 ISC_LIST(dns_dispatch_t) list;
00080
00081
00082 isc_mutex_t rng_lock;
00083 isc_rng_t *rngctx;
00084
00085
00086 dns_qid_t *qid;
00087 isc_mutex_t buffer_lock;
00088 unsigned int buffers;
00089 unsigned int buffersize;
00090 unsigned int maxbuffers;
00091
00092
00093 isc_mutex_t depool_lock;
00094 isc_mempool_t *depool;
00095 isc_mutex_t rpool_lock;
00096 isc_mempool_t *rpool;
00097 isc_mutex_t dpool_lock;
00098 isc_mempool_t *dpool;
00099 isc_mutex_t bpool_lock;
00100 isc_mempool_t *bpool;
00101 isc_mutex_t spool_lock;
00102 isc_mempool_t *spool;
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119 in_port_t *v4ports;
00120 unsigned int nv4ports;
00121 in_port_t *v6ports;
00122 unsigned int nv6ports;
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
00148
00149
00150
00151
00152
00153 #ifndef DNS_DISPATCH_POOLSOCKS
00154 #define DNS_DISPATCH_POOLSOCKS 2048
00155 #endif
00156
00157
00158
00159
00160
00161
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;
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
00183
00184
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
00200
00201
00202
00203 #define MAX_INTERNAL_TASKS 64
00204
00205 struct dns_dispatch {
00206
00207 unsigned int magic;
00208 dns_dispatchmgr_t *mgr;
00209 int ntasks;
00210
00211
00212
00213
00214
00215 isc_task_t *task[MAX_INTERNAL_TASKS];
00216 isc_socket_t *socket;
00217 isc_sockaddr_t local;
00218 in_port_t localport;
00219 isc_sockaddr_t peer;
00220 isc_dscp_t dscp;
00221 unsigned int maxrequests;
00222 isc_event_t *ctlevent;
00223
00224 isc_mutex_t sepool_lock;
00225 isc_mempool_t *sepool;
00226
00227
00228 ISC_LINK(dns_dispatch_t) link;
00229
00230
00231 isc_mutex_t lock;
00232 isc_sockettype_t socktype;
00233 unsigned int attributes;
00234 unsigned int refcount;
00235 dns_dispatchevent_t *failsafe_ev;
00236 unsigned int shutting_down : 1,
00237 shutdown_out : 1,
00238 connected : 1,
00239 tcpmsg_valid : 1,
00240 recv_pending : 1;
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;
00246 unsigned int tcpbuffers;
00247 dns_tcpmsg_t tcpmsg;
00248 dns_qid_t *qid;
00249 isc_rng_t *rngctx;
00250 dispportlist_t *port_table;
00251 isc_mempool_t *portpool;
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
00276
00277
00278
00279
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
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
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
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
00465
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
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
00511
00512
00513
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]);
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
00562
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
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
00628
00629
00630 *portentryp = NULL;
00631
00632 UNLOCK(&qid->lock);
00633 }
00634
00635
00636
00637
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
00663
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
00720
00721
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
00780
00781
00782
00783 if (sock != NULL)
00784 isc_socket_detach(&sock);
00785 destroy_dispsocket(disp, &dispsock);
00786 }
00787
00788 return (result);
00789 }
00790
00791
00792
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
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
00829
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
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
00864
00865
00866
00867 INSIST(result == ISC_R_NOTIMPLEMENTED);
00868 destroy_dispsocket(disp, &dispsock);
00869 }
00870 }
00871 }
00872
00873
00874
00875
00876
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
01028
01029
01030
01031
01032
01033
01034
01035
01036
01037
01038
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
01071
01072
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
01082
01083
01084
01085
01086
01087 deactivate_dispsocket(disp, dispsock);
01088 dispsock = NULL;
01089 }
01090
01091 if (disp->shutting_down) {
01092
01093
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
01115
01116
01117
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
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
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
01180
01181
01182 if ((flags & DNS_MESSAGEFLAG_QR) == 0) {
01183
01184 free_buffer(disp, ev->region.base, ev->region.length);
01185 goto restart;
01186 }
01187
01188
01189
01190
01191
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
01219
01220
01221
01222 if (disp != resp->disp) {
01223 isc_sockaddr_t a1;
01224 isc_sockaddr_t a2;
01225
01226
01227
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
01238
01239
01240
01241
01242
01243
01244
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
01271
01272
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
01300
01301 restart:
01302 result = startrecv(disp, dispsock);
01303 if (result != ISC_R_SUCCESS && dispsock != NULL) {
01304
01305
01306
01307
01308
01309
01310 deactivate_dispsocket(disp, dispsock);
01311 }
01312 isc_event_free(&ev_in);
01313 UNLOCK(&disp->lock);
01314 }
01315
01316
01317
01318
01319
01320
01321
01322
01323
01324
01325
01326
01327
01328
01329
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
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
01396
01397
01398
01399 isc_event_free(&ev_in);
01400
01401 disp->shutting_down = 1;
01402 disp->shutdown_why = tcpmsg->result;
01403
01404
01405
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
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
01433
01434
01435
01436
01437
01438
01439
01440 if ((flags & DNS_MESSAGEFLAG_QR) == 0) {
01441
01442
01443
01444 goto restart;
01445 }
01446
01447
01448
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
01466
01467
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
01491
01492 restart:
01493 (void)startrecv(disp, NULL);
01494
01495 isc_event_free(&ev_in);
01496 UNLOCK(&disp->lock);
01497 }
01498
01499
01500
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
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, ®ion, 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, ®ion, 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);
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);
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
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
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
01735
01736
01737
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
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
01941 return;
01942 }
01943
01944 dns_portlist_t *
01945 dns_dispatchmgr_getblackportlist(dns_dispatchmgr_t *mgr) {
01946 REQUIRE(VALID_DISPATCHMGR(mgr));
01947 return (NULL);
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);
02027 REQUIRE(increment > buckets);
02028
02029
02030
02031
02032
02033
02034
02035
02036
02037
02038
02039
02040
02041
02042 if (maxbuffers < 8)
02043 maxbuffers = 8;
02044
02045 LOCK(&mgr->buffer_lock);
02046
02047
02048 if (mgr->bpool != NULL) {
02049
02050
02051
02052
02053
02054
02055
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
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
02212
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
02222
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
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
02243
02244
02245
02246
02247
02248
02249
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
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);
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
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
02386
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
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
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;
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;
02539
02540 LOCK(&mgr->lock);
02541
02542
02543
02544
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
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
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
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
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
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
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
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);
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
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
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
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
02887
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
02909
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
02921
02922
02923 } else {
02924
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
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
03015
03016
03017
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
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]);
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
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
03141
03142
03143
03144
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
03237
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
03262
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
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
03287
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
03485
03486
03487 ISC_LIST_INIT(events);
03488 n = isc_task_unsend(res->task, res, DNS_EVENT_DISPATCH,
03489 NULL, &events);
03490
03491
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
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
03551
03552
03553 LOCK(&qid->lock);
03554 for (resp = linear_first(qid);
03555 resp != NULL && resp->item_out;
03556 )
03557 resp = linear_next(qid, resp);
03558
03559
03560
03561
03562 if (resp == NULL)
03563 goto unlock;
03564
03565
03566
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
03640
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
03651 REQUIRE((attributes & DNS_DISPATCHATTR_EXCLUSIVE) == 0);
03652
03653 REQUIRE((disp->attributes & DNS_DISPATCHATTR_EXCLUSIVE) == 0 ||
03654 (attributes & DNS_DISPATCHATTR_NOLISTEN) == 0);
03655
03656
03657
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
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