dispatch.c revision dafcb997e390efa4423883dafd100c975c4095d6
2c35c682362049f823248542e07e7dca4008b986Mark Andrews * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
0c27b3fe77ac1d5094ba3521e8142d9e7973133fMark Andrews * Copyright (C) 1999-2003 Internet Software Consortium.
0c27b3fe77ac1d5094ba3521e8142d9e7973133fMark Andrews * Permission to use, copy, modify, and distribute this software for any
0c27b3fe77ac1d5094ba3521e8142d9e7973133fMark Andrews * purpose with or without fee is hereby granted, provided that the above
0c27b3fe77ac1d5094ba3521e8142d9e7973133fMark Andrews * copyright notice and this permission notice appear in all copies.
2c35c682362049f823248542e07e7dca4008b986Mark Andrews * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
2c35c682362049f823248542e07e7dca4008b986Mark Andrews * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
2c35c682362049f823248542e07e7dca4008b986Mark Andrews * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
2c35c682362049f823248542e07e7dca4008b986Mark Andrews * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
2c35c682362049f823248542e07e7dca4008b986Mark Andrews * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
2c35c682362049f823248542e07e7dca4008b986Mark Andrews * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
2c35c682362049f823248542e07e7dca4008b986Mark Andrews * PERFORMANCE OF THIS SOFTWARE.
2c35c682362049f823248542e07e7dca4008b986Mark Andrews/* $Id: dispatch.c,v 1.116 2004/03/05 05:09:19 marka Exp $ */
2c35c682362049f823248542e07e7dca4008b986Mark Andrewstypedef ISC_LIST(dns_dispentry_t) dns_displist_t;
2c35c682362049f823248542e07e7dca4008b986Mark Andrewstypedef struct dns_qid {
2c35c682362049f823248542e07e7dca4008b986Mark Andrews unsigned int magic;
2c35c682362049f823248542e07e7dca4008b986Mark Andrews unsigned int qid_nbuckets; /* hash table size */
2c35c682362049f823248542e07e7dca4008b986Mark Andrews unsigned int qid_increment; /* id increment on collision */
2c35c682362049f823248542e07e7dca4008b986Mark Andrews isc_lfsr_t qid_lfsr1; /* state generator info */
2c35c682362049f823248542e07e7dca4008b986Mark Andrews isc_lfsr_t qid_lfsr2; /* state generator info */
2c35c682362049f823248542e07e7dca4008b986Mark Andrews dns_displist_t *qid_table; /* the table itself */
2c35c682362049f823248542e07e7dca4008b986Mark Andrews /* Unlocked. */
2c35c682362049f823248542e07e7dca4008b986Mark Andrews unsigned int magic;
2c35c682362049f823248542e07e7dca4008b986Mark Andrews /* Locked by "lock". */
2c35c682362049f823248542e07e7dca4008b986Mark Andrews unsigned int state;
2c35c682362049f823248542e07e7dca4008b986Mark Andrews /* locked by buffer lock */
2c35c682362049f823248542e07e7dca4008b986Mark Andrews unsigned int buffersize; /* size of each buffer */
2c35c682362049f823248542e07e7dca4008b986Mark Andrews /* Locked internally. */
2c35c682362049f823248542e07e7dca4008b986Mark Andrews isc_mempool_t *epool; /* memory pool for events */
2c35c682362049f823248542e07e7dca4008b986Mark Andrews isc_mempool_t *rpool; /* memory pool for replies */
2c35c682362049f823248542e07e7dca4008b986Mark Andrews isc_mempool_t *dpool; /* dispatch allocations */
2c35c682362049f823248542e07e7dca4008b986Mark Andrews isc_mempool_t *bpool; /* memory pool for buffers */
2c35c682362049f823248542e07e7dca4008b986Mark Andrews#define MGR_IS_SHUTTINGDOWN(l) (((l)->state & MGR_SHUTTINGDOWN) != 0)
2c35c682362049f823248542e07e7dca4008b986Mark Andrews#define IS_PRIVATE(d) (((d)->attributes & DNS_DISPATCHATTR_PRIVATE) != 0)
2c35c682362049f823248542e07e7dca4008b986Mark Andrews unsigned int magic;
2c35c682362049f823248542e07e7dca4008b986Mark Andrews unsigned int bucket;
2c35c682362049f823248542e07e7dca4008b986Mark Andrews /* Unlocked. */
2c35c682362049f823248542e07e7dca4008b986Mark Andrews isc_socket_t *socket; /* isc socket attached to */
2c35c682362049f823248542e07e7dca4008b986Mark Andrews /* Locked by mgr->lock. */
2c35c682362049f823248542e07e7dca4008b986Mark Andrews /* Locked by "lock". */
2c35c682362049f823248542e07e7dca4008b986Mark Andrews dns_dispatchevent_t *failsafe_ev; /* failsafe cancel event */
2c35c682362049f823248542e07e7dca4008b986Mark Andrews unsigned int requests; /* how many requests we have */
2c35c682362049f823248542e07e7dca4008b986Mark Andrews unsigned int tcpbuffers; /* allocated buffers */
2c35c682362049f823248542e07e7dca4008b986Mark Andrews#define VALID_QID(e) ISC_MAGIC_VALID((e), QID_MAGIC)
2c35c682362049f823248542e07e7dca4008b986Mark Andrews#define RESPONSE_MAGIC ISC_MAGIC('D', 'r', 's', 'p')
2c35c682362049f823248542e07e7dca4008b986Mark Andrews#define VALID_RESPONSE(e) ISC_MAGIC_VALID((e), RESPONSE_MAGIC)
2c35c682362049f823248542e07e7dca4008b986Mark Andrews#define DISPATCH_MAGIC ISC_MAGIC('D', 'i', 's', 'p')
2c35c682362049f823248542e07e7dca4008b986Mark Andrews#define VALID_DISPATCH(e) ISC_MAGIC_VALID((e), DISPATCH_MAGIC)
2c35c682362049f823248542e07e7dca4008b986Mark Andrews#define DNS_DISPATCHMGR_MAGIC ISC_MAGIC('D', 'M', 'g', 'r')
2c35c682362049f823248542e07e7dca4008b986Mark Andrews#define VALID_DISPATCHMGR(e) ISC_MAGIC_VALID((e), DNS_DISPATCHMGR_MAGIC)
2c35c682362049f823248542e07e7dca4008b986Mark Andrews#define DNS_QID(disp) ((disp)->socktype == isc_sockettype_tcp) ? \
2c35c682362049f823248542e07e7dca4008b986Mark Andrewsstatic dns_dispentry_t *bucket_search(dns_qid_t *, isc_sockaddr_t *,
2c35c682362049f823248542e07e7dca4008b986Mark Andrews dns_messageid_t, unsigned int);
2c35c682362049f823248542e07e7dca4008b986Mark Andrewsstatic isc_boolean_t destroy_disp_ok(dns_dispatch_t *);
2c35c682362049f823248542e07e7dca4008b986Mark Andrewsstatic void destroy_disp(isc_task_t *task, isc_event_t *event);
2c35c682362049f823248542e07e7dca4008b986Mark Andrewsstatic void udp_recv(isc_task_t *, isc_event_t *);
2c35c682362049f823248542e07e7dca4008b986Mark Andrewsstatic void tcp_recv(isc_task_t *, isc_event_t *);
2c35c682362049f823248542e07e7dca4008b986Mark Andrewsstatic dns_messageid_t dns_randomid(dns_qid_t *);
2c35c682362049f823248542e07e7dca4008b986Mark Andrewsstatic isc_uint32_t dns_hash(dns_qid_t *, isc_sockaddr_t *, dns_messageid_t);
2c35c682362049f823248542e07e7dca4008b986Mark Andrewsstatic void free_buffer(dns_dispatch_t *disp, void *buf, unsigned int len);
2c35c682362049f823248542e07e7dca4008b986Mark Andrewsstatic void *allocate_udp_buffer(dns_dispatch_t *disp);
2c35c682362049f823248542e07e7dca4008b986Mark Andrewsstatic inline void free_event(dns_dispatch_t *disp, dns_dispatchevent_t *ev);
2c35c682362049f823248542e07e7dca4008b986Mark Andrewsstatic inline dns_dispatchevent_t *allocate_event(dns_dispatch_t *disp);
2c35c682362049f823248542e07e7dca4008b986Mark Andrewsstatic void do_cancel(dns_dispatch_t *disp, dns_dispentry_t *resp);
2c35c682362049f823248542e07e7dca4008b986Mark Andrewsstatic dns_dispentry_t *linear_first(dns_qid_t *disp);
2c35c682362049f823248542e07e7dca4008b986Mark Andrewsstatic dns_dispentry_t *linear_next(dns_qid_t *disp,
2c35c682362049f823248542e07e7dca4008b986Mark Andrewsstatic void dispatch_free(dns_dispatch_t **dispp);
2c35c682362049f823248542e07e7dca4008b986Mark Andrewsstatic isc_result_t dispatch_createudp(dns_dispatchmgr_t *mgr,
2c35c682362049f823248542e07e7dca4008b986Mark Andrewsstatic isc_boolean_t destroy_mgr_ok(dns_dispatchmgr_t *mgr);
2c35c682362049f823248542e07e7dca4008b986Mark Andrewsstatic void destroy_mgr(dns_dispatchmgr_t **mgrp);
2c35c682362049f823248542e07e7dca4008b986Mark Andrewsstatic isc_result_t qid_allocate(dns_dispatchmgr_t *mgr, unsigned int buckets,
2c35c682362049f823248542e07e7dca4008b986Mark Andrewsstatic void qid_destroy(isc_mem_t *mctx, dns_qid_t **qidp);
2c35c682362049f823248542e07e7dca4008b986Mark Andrewsmgr_log(dns_dispatchmgr_t *mgr, int level, const char *fmt, ...)
2c35c682362049f823248542e07e7dca4008b986Mark Andrewsmgr_log(dns_dispatchmgr_t *mgr, int level, const char *fmt, ...) {
2c35c682362049f823248542e07e7dca4008b986Mark Andrews DNS_LOGCATEGORY_DISPATCH, DNS_LOGMODULE_DISPATCH,
2c35c682362049f823248542e07e7dca4008b986Mark Andrewsdispatch_log(dns_dispatch_t *disp, int level, const char *fmt, ...)
2c35c682362049f823248542e07e7dca4008b986Mark Andrewsdispatch_log(dns_dispatch_t *disp, int level, const char *fmt, ...) {
2c35c682362049f823248542e07e7dca4008b986Mark Andrews DNS_LOGCATEGORY_DISPATCH, DNS_LOGMODULE_DISPATCH,
2c35c682362049f823248542e07e7dca4008b986Mark Andrewsrequest_log(dns_dispatch_t *disp, dns_dispentry_t *resp,
2c35c682362049f823248542e07e7dca4008b986Mark Andrewsrequest_log(dns_dispatch_t *disp, dns_dispentry_t *resp,
03958ad4b9fd6b2d6f1fbf20e85d8ff2a1f9d069Mark Andrews isc_sockaddr_format(&resp->host, peerbuf, sizeof(peerbuf));
03958ad4b9fd6b2d6f1fbf20e85d8ff2a1f9d069Mark Andrews isc_log_write(dns_lctx, DNS_LOGCATEGORY_DISPATCH,
03958ad4b9fd6b2d6f1fbf20e85d8ff2a1f9d069Mark Andrews isc_log_write(dns_lctx, DNS_LOGCATEGORY_DISPATCH,
2c35c682362049f823248542e07e7dca4008b986Mark Andrews result = isc_entropy_getdata(mgr->entropy, &val, sizeof(val),
2c35c682362049f823248542e07e7dca4008b986Mark Andrews lfsr->count = (random() & 0x1f) + 32; /* From 32 to 63 states */
2c35c682362049f823248542e07e7dca4008b986Mark Andrews * Return an unpredictable message ID.
2c35c682362049f823248542e07e7dca4008b986Mark Andrews id = isc_lfsr_generate32(&qid->qid_lfsr1, &qid->qid_lfsr2);
2c35c682362049f823248542e07e7dca4008b986Mark Andrews * Return a hash of the destination and message id.
2c35c682362049f823248542e07e7dca4008b986Mark Andrewsdns_hash(dns_qid_t *qid, isc_sockaddr_t *dest, dns_messageid_t id) {
2c35c682362049f823248542e07e7dca4008b986Mark Andrews unsigned int ret;
2c35c682362049f823248542e07e7dca4008b986Mark Andrews * Find the first entry in 'qid'. Returns NULL if there are no entries.
2c35c682362049f823248542e07e7dca4008b986Mark Andrews unsigned int bucket;
2c35c682362049f823248542e07e7dca4008b986Mark Andrews * Find the next entry after 'resp' in 'qid'. Return NULL if there are
2c35c682362049f823248542e07e7dca4008b986Mark Andrews * no more entries.
2c35c682362049f823248542e07e7dca4008b986Mark Andrewslinear_next(dns_qid_t *qid, dns_dispentry_t *resp) {
2c35c682362049f823248542e07e7dca4008b986Mark Andrews unsigned int bucket;
2c35c682362049f823248542e07e7dca4008b986Mark Andrews * The dispatch must be locked.
static isc_boolean_t
return (ISC_FALSE);
return (ISC_FALSE);
return (ISC_FALSE);
return (ISC_TRUE);
if (killmgr)
static dns_dispentry_t *
unsigned int bucket)
return (res);
return (NULL);
case isc_sockettype_tcp:
case isc_sockettype_udp:
INSIST(0);
void *temp;
return (temp);
static inline dns_dispatchevent_t *
return (NULL);
return (ev);
unsigned int flags;
unsigned int bucket;
int match;
if (killit)
match > 0)
sizeof(netaddrstr));
goto restart;
goto restart;
goto restart;
goto restart;
goto restart;
if (queue_response) {
unsigned int flags;
unsigned int bucket;
int level;
case ISC_R_CANCELED:
case ISC_R_EOF:
case ISC_R_CONNECTIONRESET:
goto logit;
if (killit)
goto restart;
goto restart;
goto restart;
goto restart;
if (queue_response) {
case isc_sockettype_udp:
case isc_sockettype_tcp:
static isc_boolean_t
return (ISC_FALSE);
return (ISC_FALSE);
return (ISC_FALSE);
return (ISC_FALSE);
return (ISC_FALSE);
return (ISC_TRUE);
static isc_result_t
return (result);
#ifndef ISC_ALLOW_MAPPED
return (result);
return (ISC_R_SUCCESS);
return (ISC_R_NOMEMORY);
goto deallocate;
goto kill_lock;
goto kill_buffer_lock;
goto kill_pool_lock;
goto kill_epool;
goto kill_rpool;
return (ISC_R_SUCCESS);
return (result);
static isc_result_t
return (ISC_R_SUCCESS);
return (ISC_R_NOMEMORY);
goto cleanup;
return (ISC_R_SUCCESS);
return (ISC_R_NOMEMORY);
if (killit)
static isc_boolean_t
return (ISC_FALSE);
return (ISC_FALSE);
return (ISC_TRUE);
return (ISC_FALSE);
static isc_boolean_t
return (ISC_TRUE);
return (ISC_FALSE);
return (ISC_TRUE);
return (ISC_FALSE);
return (ISC_FALSE);
return (ISC_FALSE);
static isc_result_t
goto out;
out:
return (result);
static isc_result_t
return (ISC_R_NOMEMORY);
return (ISC_R_NOMEMORY);
return (ISC_R_UNEXPECTED);
for (i = 0; i < buckets; i++)
return (ISC_R_SUCCESS);
static isc_result_t
return (ISC_R_NOMEMORY);
goto deallocate;
goto kill_lock;
return (ISC_R_SUCCESS);
return (res);
return (result);
goto deallocate_dispatch;
goto kill_socket;
sizeof(isc_event_t));
goto kill_task;
return (ISC_R_SUCCESS);
return (result);
unsigned int buffersize,
return (result);
return (ISC_R_SUCCESS);
return (result);
return (ISC_R_SUCCESS);
static isc_result_t
unsigned int maxrequests,
unsigned int attributes,
return (result);
goto deallocate_dispatch;
goto getsocket;
goto kill_socket;
sizeof(isc_event_t));
goto kill_task;
return (ISC_R_SUCCESS);
return (result);
if (killit)
unsigned int bucket;
return (ISC_R_SHUTTINGDOWN);
return (ISC_R_QUOTA);
if (!ok) {
return (ISC_R_NOMORE);
return (ISC_R_NOMEMORY);
return (ISC_R_SUCCESS);
unsigned int bucket;
if (killit)
return (ISC_R_SUCCESS);
return (ISC_R_NOTIMPLEMENTED);
void *buf;