dispatch.c revision c6066a8e67f40c7c12925c5634485f55713c06d6
9d5ed744c46ef241b9d3ba134bf3155e0b62ac9eAutomatic Updater * Copyright (C) 1999 Internet Software Consortium.
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence * Permission to use, copy, modify, and distribute this software for any
ec5347e2c775f027573ce5648b910361aa926c01Automatic Updater * purpose with or without fee is hereby granted, provided that the above
bf43fdafa3bff9e84cb03f1a19aca74514d2516eBob Halley * copyright notice and this permission notice appear in all copies.
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
dafcb997e390efa4423883dafd100c975c4095d6Mark Andrews * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
dafcb997e390efa4423883dafd100c975c4095d6Mark Andrews * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
dafcb997e390efa4423883dafd100c975c4095d6Mark Andrews * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
dafcb997e390efa4423883dafd100c975c4095d6Mark Andrews * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
dafcb997e390efa4423883dafd100c975c4095d6Mark Andrews * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
dafcb997e390efa4423883dafd100c975c4095d6Mark Andrews * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
0ec4b862c9abd11c82c88ed62438f0cf06fed25dBob Halley#include "../isc/util.h"
09f22ac5b09e70bc526015f37168ba33e21ea91fDavid Lawrence * If we cannot send to this task, the application is broken.
09f22ac5b09e70bc526015f37168ba33e21ea91fDavid Lawrence#define ISC_TASK_SEND(a, b) do { \
09f22ac5b09e70bc526015f37168ba33e21ea91fDavid Lawrence RUNTIME_CHECK(isc_task_send(a, b) == ISC_R_SUCCESS); \
60ab03125c137c48a6b2ed6df1d2c8657757e09dMark Andrews unsigned int magic;
60ab03125c137c48a6b2ed6df1d2c8657757e09dMark Andrewstypedef ISC_LIST(dns_dispentry_t) dns_displist_t;
60ab03125c137c48a6b2ed6df1d2c8657757e09dMark Andrews /* Unlocked. */
d2ef84e07b67e72a4bd9c729c6b8228067d17584Mark Andrews isc_socket_t *socket; /* isc socket attached to */
60ab03125c137c48a6b2ed6df1d2c8657757e09dMark Andrews unsigned int buffersize; /* size of each buffer */
60ab03125c137c48a6b2ed6df1d2c8657757e09dMark Andrews /* Locked. */
60ab03125c137c48a6b2ed6df1d2c8657757e09dMark Andrews isc_mempool_t *epool; /* memory pool for events */
60ab03125c137c48a6b2ed6df1d2c8657757e09dMark Andrews isc_mempool_t *bpool; /* memory pool for buffers */
60ab03125c137c48a6b2ed6df1d2c8657757e09dMark Andrews isc_mempool_t *rpool; /* memory pool request/reply */
92ef1a9b9dbd48ecb507b42ac62c15afefdaf838David Lawrence dns_dispatchevent_t *failsafe_ev; /* failsafe cancel event */
ff30cdeb783ca7ffe69b222c56197828e882c229Mark Andrews unsigned int recvs; /* recv() calls outstanding */
bf43fdafa3bff9e84cb03f1a19aca74514d2516eBob Halley unsigned int recvs_wanted; /* recv() calls wanted */
60ab03125c137c48a6b2ed6df1d2c8657757e09dMark Andrews unsigned int requests; /* how many requests we have */
60ab03125c137c48a6b2ed6df1d2c8657757e09dMark Andrews ISC_LIST(dns_dispentry_t) rq_handlers; /* request handler list */
35541328a8c18ba1f984300dfe30ec8713c90031Mark Andrews ISC_LIST(dns_dispatchevent_t) rq_events; /* holder for rq events */
60ab03125c137c48a6b2ed6df1d2c8657757e09dMark Andrews isc_int32_t qid_state; /* state generator info */
60ab03125c137c48a6b2ed6df1d2c8657757e09dMark Andrews unsigned int qid_hashsize; /* hash table size */
35541328a8c18ba1f984300dfe30ec8713c90031Mark Andrews unsigned int qid_mask; /* mask for hash table */
35541328a8c18ba1f984300dfe30ec8713c90031Mark Andrews dns_displist_t *qid_table; /* the table itself */
60ab03125c137c48a6b2ed6df1d2c8657757e09dMark Andrews#define REQUEST_MAGIC 0x53912051 /* "random" value */
60ab03125c137c48a6b2ed6df1d2c8657757e09dMark Andrews#define VALID_REQUEST(e) ((e) != NULL && (e)->magic == REQUEST_MAGIC)
35541328a8c18ba1f984300dfe30ec8713c90031Mark Andrews#define RESPONSE_MAGIC 0x15021935 /* "random" value */
35541328a8c18ba1f984300dfe30ec8713c90031Mark Andrews#define VALID_RESPONSE(e) ((e) != NULL && (e)->magic == RESPONSE_MAGIC)
35541328a8c18ba1f984300dfe30ec8713c90031Mark Andrews#define DISPATCH_MAGIC 0x69385829 /* "random" value */
35541328a8c18ba1f984300dfe30ec8713c90031Mark Andrews#define VALID_DISPATCH(e) ((e) != NULL && (e)->magic == DISPATCH_MAGIC)
e2c3f8059e77a8e11c4378d22e5d8e78b423a28fMark Andrewsbucket_search(dns_dispatch_t *, isc_sockaddr_t *,
0ec4b862c9abd11c82c88ed62438f0cf06fed25dBob Halley dns_messageid_t, unsigned int);
23e4260821eefa5019808e18e14e2b366461aad7Brian Wellingtonstatic unsigned int
664e11f0b14c78cef7cf6b8c70323a1da494e351Mark Andrewshash(dns_dispatch_t *, isc_sockaddr_t *, dns_messageid_t);
23e4260821eefa5019808e18e14e2b366461aad7Brian Wellingtonfree_buffer(dns_dispatch_t *disp, void *buf, unsigned int len);
23e4260821eefa5019808e18e14e2b366461aad7Brian Wellingtonallocate_buffer(dns_dispatch_t *disp, unsigned int len);
ed019cabc1cc75d4412010c331876e4ae5080a4dDavid Lawrencestatic inline void
76c8294c81fb48b1da6e1fc5b83322a4cedb8e58Andreas Gustafssonfree_event(dns_dispatch_t *disp, dns_dispatchevent_t *ev);
0b09763c354ec91fb352b6b4cea383bd0195b2d8Mark Andrewsdo_next_request(dns_dispatch_t *disp, dns_dispentry_t *resp);
50105afc551903541608b11851d73278b23579a3Mark Andrewsdo_next_response(dns_dispatch_t *disp, dns_dispentry_t *resp);
5be3685b0e57677c0cc03113099cb8f99f9a070bMark Andrewsdo_cancel(dns_dispatch_t *disp, dns_dispentry_t *resp);
60ab03125c137c48a6b2ed6df1d2c8657757e09dMark Andrewslinear_next(dns_dispatch_t *disp, dns_dispentry_t *resp);
5be3685b0e57677c0cc03113099cb8f99f9a070bMark Andrews unsigned int bucket;
0ec4b862c9abd11c82c88ed62438f0cf06fed25dBob Halleylinear_next(dns_dispatch_t *disp, dns_dispentry_t *resp)
0ec4b862c9abd11c82c88ed62438f0cf06fed25dBob Halley unsigned int bucket;
0b09763c354ec91fb352b6b4cea383bd0195b2d8Mark Andrews * Return a hash of the destination and message id. For now, just return
0b09763c354ec91fb352b6b4cea383bd0195b2d8Mark Andrews * the message id bits, and mask off the low order bits of that.
0b09763c354ec91fb352b6b4cea383bd0195b2d8Mark Andrewsstatic unsigned int
0b09763c354ec91fb352b6b4cea383bd0195b2d8Mark Andrewshash(dns_dispatch_t *disp, isc_sockaddr_t *dest, dns_messageid_t id)
0b09763c354ec91fb352b6b4cea383bd0195b2d8Mark Andrews unsigned int ret;
ff30cdeb783ca7ffe69b222c56197828e882c229Mark Andrews * Return a random message ID. For now this isn't too clever...
ff30cdeb783ca7ffe69b222c56197828e882c229Mark Andrews * Called when refcount reaches 0 (and safe to destroy)
60ab03125c137c48a6b2ed6df1d2c8657757e09dMark Andrews * Final cleanup of packets on the request list.
b5debbe212097d1c573a2ba3bd9a3d526d86b0aeBrian Wellington ISC_LIST_UNLINK(disp->rq_events, ev, link);
b5debbe212097d1c573a2ba3bd9a3d526d86b0aeBrian Wellington free_buffer(disp, ev->buffer.base, ev->buffer.length);
e44487bfc23599b6b240e09d83d1c862fecfcc82Michael Graff isc_mempool_put(disp->epool, disp->failsafe_ev);
7d116211ec7b063891130f191e3ed437b45dba70Mark Andrews isc_mem_put(disp->mctx, disp, sizeof(dns_dispatch_t));
ca9af3aaf798f98624fc1dc69d8c7d51bf01334dBrian Wellingtonbucket_search(dns_dispatch_t *disp, isc_sockaddr_t *dest, dns_messageid_t id,
5c6117688525d0e8d247f50c63364f66bd8d4185Brian Wellington if ((res->id == id) && isc_sockaddr_equal(dest, &res->host))
ca9af3aaf798f98624fc1dc69d8c7d51bf01334dBrian Wellington XDEBUG(("lengths (%d, %d), ids (%d, %d)\n",
17a3fcecd069130a5f318685493b0db5639a77c9Brian Wellingtonfree_buffer(dns_dispatch_t *disp, void *buf, unsigned int len)
8839b6acbf816fedc15b8e9e1c71fd606a9cd8eaBrian Wellington socktype = isc_socket_gettype(disp->socket);
3676eeb6ca95c66aae1256f37af8c990d9f25eb4Brian Wellington XDEBUG(("Freeing buffer %p, length %d, into %s, %d remain\n",
60ab03125c137c48a6b2ed6df1d2c8657757e09dMark Andrews (len == disp->buffersize ? "mempool" : "mctx"),
48ed268b3378a8b729a0037bc4ae2ed73647a96aBrian Wellingtonallocate_buffer(dns_dispatch_t *disp, unsigned int len)
9cd6710f91bdffef5aed68ab02533e398f6134d7Brian Wellington XDEBUG(("Allocated buffer %p, length %d, from %s, %d total\n",
8839b6acbf816fedc15b8e9e1c71fd606a9cd8eaBrian Wellington (len == disp->buffersize ? "mempool" : "mctx"),
0b09763c354ec91fb352b6b4cea383bd0195b2d8Mark Andrewsstatic inline void
0b09763c354ec91fb352b6b4cea383bd0195b2d8Mark Andrewsfree_event(dns_dispatch_t *disp, dns_dispatchevent_t *ev)
8839b6acbf816fedc15b8e9e1c71fd606a9cd8eaBrian Wellington * General flow:
17a3fcecd069130a5f318685493b0db5639a77c9Brian Wellington * If I/O result == CANCELED, free the buffer and notify everyone as
0b09763c354ec91fb352b6b4cea383bd0195b2d8Mark Andrews * the various queues drain.
0b09763c354ec91fb352b6b4cea383bd0195b2d8Mark Andrews * If I/O is error (not canceled and not success) log it, free the buffer,
0b09763c354ec91fb352b6b4cea383bd0195b2d8Mark Andrews * and restart.
60ab03125c137c48a6b2ed6df1d2c8657757e09dMark Andrews * if no listeners: free the buffer, restart.
60ab03125c137c48a6b2ed6df1d2c8657757e09dMark Andrews * if listener: allocate event, fill in details.
60ab03125c137c48a6b2ed6df1d2c8657757e09dMark Andrews * If cannot allocate, free buffer, restart.
60ab03125c137c48a6b2ed6df1d2c8657757e09dMark Andrews * if rq event queue is not empty, queue. else, send.
60ab03125c137c48a6b2ed6df1d2c8657757e09dMark Andrews * If response:
60ab03125c137c48a6b2ed6df1d2c8657757e09dMark Andrews * Allocate event, fill in details.
60ab03125c137c48a6b2ed6df1d2c8657757e09dMark Andrews * If cannot allocate, free buffer, restart.
60ab03125c137c48a6b2ed6df1d2c8657757e09dMark Andrews * find target. If not found, free buffer, restart.
0b09763c354ec91fb352b6b4cea383bd0195b2d8Mark Andrews * if event queue is not empty, queue. else, send.
0b09763c354ec91fb352b6b4cea383bd0195b2d8Mark Andrews isc_socketevent_t *ev = (isc_socketevent_t *)ev_in;
0b09763c354ec91fb352b6b4cea383bd0195b2d8Mark Andrews unsigned int flags;
0b09763c354ec91fb352b6b4cea383bd0195b2d8Mark Andrews unsigned int bucket;
e2c3f8059e77a8e11c4378d22e5d8e78b423a28fMark Andrews * If the recv() was canceled pass the word on.
0b09763c354ec91fb352b6b4cea383bd0195b2d8Mark Andrews free_buffer(disp, ev->region.base, ev->region.length);
8d414d155953f89a4eff40f16878438a8c9228f3Mark Andrews * otherwise, on strange error, log it and restart.
ff30cdeb783ca7ffe69b222c56197828e882c229Mark Andrews free_buffer(disp, ev->region.base, ev->region.length);
0b09763c354ec91fb352b6b4cea383bd0195b2d8Mark Andrews XDEBUG(("length == %d, buflen = %d, addr = %p\n",
2f012d936b5ccdf6520c96a4de23721dc58a2221Automatic Updater * Peek into the buffer to see what we can see.
60ab03125c137c48a6b2ed6df1d2c8657757e09dMark Andrews isc_buffer_init(&source, ev->region.base, ev->region.length,
664e11f0b14c78cef7cf6b8c70323a1da494e351Mark Andrews dres = dns_message_peekheader(&source, &id, &flags);
0b09763c354ec91fb352b6b4cea383bd0195b2d8Mark Andrews free_buffer(disp, ev->region.base, ev->region.length);
0b09763c354ec91fb352b6b4cea383bd0195b2d8Mark Andrews /* XXXMLG log something here... */
ff30cdeb783ca7ffe69b222c56197828e882c229Mark Andrews XDEBUG(("Got valid DNS message header, /QR %c, id %d\n",
0b09763c354ec91fb352b6b4cea383bd0195b2d8Mark Andrews ((flags & DNS_MESSAGEFLAG_QR) ? '1' : '0'), id));
0b09763c354ec91fb352b6b4cea383bd0195b2d8Mark Andrews * Allocate an event to send to the query or response client, and
48ed268b3378a8b729a0037bc4ae2ed73647a96aBrian Wellington * allocate a new buffer for our use.
60ab03125c137c48a6b2ed6df1d2c8657757e09dMark Andrews * Look at flags. If query, check to see if we have someone handling
60ab03125c137c48a6b2ed6df1d2c8657757e09dMark Andrews * them. If response, look to see where it goes.
6f071989da905bb5ab2c6dfd01a71ee5ecea5918Brian Wellington free_buffer(disp, ev->region.base, ev->region.length);
8839b6acbf816fedc15b8e9e1c71fd606a9cd8eaBrian Wellington /* response */
34aa7909371f13b4bc0ba6d155cfc38bfa1e3c5cAndreas Gustafsson resp = bucket_search(disp, &ev->address, id, bucket);
ca9af3aaf798f98624fc1dc69d8c7d51bf01334dBrian Wellington XDEBUG(("Search for response in bucket %d: %s\n",
e2c3f8059e77a8e11c4378d22e5d8e78b423a28fMark Andrews bucket, (resp == NULL ? "NOT FOUND" : "FOUND")));
34aa7909371f13b4bc0ba6d155cfc38bfa1e3c5cAndreas Gustafsson free_buffer(disp, ev->region.base, ev->region.length);
ca9af3aaf798f98624fc1dc69d8c7d51bf01334dBrian Wellington free_buffer(disp, ev->region.base, ev->region.length);
1b1e1fda4638334b484aa38c15f53a131c0b0fdfAndreas Gustafsson * At this point, rev contains the event we want to fill in, and
18b7133679efa8f60fd4e396c628576f3f416b3eBrian Wellington * resp contains the information on the place to send it to.
ca9af3aaf798f98624fc1dc69d8c7d51bf01334dBrian Wellington * Send the event off.
0b09763c354ec91fb352b6b4cea383bd0195b2d8Mark Andrews isc_buffer_init(&rev->buffer, ev->region.base, ev->region.length,
0b09763c354ec91fb352b6b4cea383bd0195b2d8Mark Andrews ISC_EVENT_INIT(rev, sizeof(*rev), 0, NULL, DNS_EVENT_DISPATCH,
0b09763c354ec91fb352b6b4cea383bd0195b2d8Mark Andrews XDEBUG(("Sent event for buffer %p (len %d) to task %p\n",
0b09763c354ec91fb352b6b4cea383bd0195b2d8Mark Andrews rev->buffer.base, rev->buffer.length, resp->task));
0b09763c354ec91fb352b6b4cea383bd0195b2d8Mark Andrews ISC_TASK_SEND(resp->task, (isc_event_t **)&rev);
0b09763c354ec91fb352b6b4cea383bd0195b2d8Mark Andrews * Restart recv() to get the next packet.
0b09763c354ec91fb352b6b4cea383bd0195b2d8Mark Andrews * General flow:
e2c3f8059e77a8e11c4378d22e5d8e78b423a28fMark Andrews * If I/O result == CANCELED, free the buffer and notify everyone as
e2c3f8059e77a8e11c4378d22e5d8e78b423a28fMark Andrews * the various queues drain.
0b09763c354ec91fb352b6b4cea383bd0195b2d8Mark Andrews * If I/O is error (not canceled and not success) log it, free the buffer,
0b09763c354ec91fb352b6b4cea383bd0195b2d8Mark Andrews * and restart.
0b09763c354ec91fb352b6b4cea383bd0195b2d8Mark Andrews * if no listeners: free the buffer, restart.
50105afc551903541608b11851d73278b23579a3Mark Andrews * if listener: allocate event, fill in details.
0b09763c354ec91fb352b6b4cea383bd0195b2d8Mark Andrews * If cannot allocate, free buffer, restart.
0b09763c354ec91fb352b6b4cea383bd0195b2d8Mark Andrews * if rq event queue is not empty, queue. else, send.
0b09763c354ec91fb352b6b4cea383bd0195b2d8Mark Andrews * If response:
0b09763c354ec91fb352b6b4cea383bd0195b2d8Mark Andrews * Allocate event, fill in details.
0b09763c354ec91fb352b6b4cea383bd0195b2d8Mark Andrews * If cannot allocate, free buffer, restart.
0b09763c354ec91fb352b6b4cea383bd0195b2d8Mark Andrews * find target. If not found, free buffer, restart.
0b09763c354ec91fb352b6b4cea383bd0195b2d8Mark Andrews * if event queue is not empty, queue. else, send.
ca9af3aaf798f98624fc1dc69d8c7d51bf01334dBrian Wellingtontcp_recv(isc_task_t *task, isc_event_t *ev_in)
60ab03125c137c48a6b2ed6df1d2c8657757e09dMark Andrews unsigned int flags;
35541328a8c18ba1f984300dfe30ec8713c90031Mark Andrews unsigned int bucket;
93d6dfaf66258337985427c86181f01fc51f0bb4Mark Andrews /* FALLTHROUGH */
93d6dfaf66258337985427c86181f01fc51f0bb4Mark Andrews * If the recv() was canceled pass the word on.
35541328a8c18ba1f984300dfe30ec8713c90031Mark Andrews * otherwise, on strange error, log it and restart.
35541328a8c18ba1f984300dfe30ec8713c90031Mark Andrews XDEBUG(("result %d, length == %d, addr = %p\n",
35541328a8c18ba1f984300dfe30ec8713c90031Mark Andrews * Peek into the buffer to see what we can see.
35541328a8c18ba1f984300dfe30ec8713c90031Mark Andrews dres = dns_message_peekheader(&tcpmsg->buffer, &id, &flags);
638fe804a524ee0c028863c0301b999c79de7651Mark Andrews /* XXXMLG log something here... */
638fe804a524ee0c028863c0301b999c79de7651Mark Andrews XDEBUG(("Got valid DNS message header, /QR %c, id %d\n",
35541328a8c18ba1f984300dfe30ec8713c90031Mark Andrews ((flags & DNS_MESSAGEFLAG_QR) ? '1' : '0'), id));
1ea2595e1b33cc63ea73ee1d54b580b717d7d155Mark Andrews * Allocate an event to send to the query or response client, and
1ea2595e1b33cc63ea73ee1d54b580b717d7d155Mark Andrews * allocate a new buffer for our use.
1ea2595e1b33cc63ea73ee1d54b580b717d7d155Mark Andrews * Look at flags. If query, check to see if we have someone handling
1ea2595e1b33cc63ea73ee1d54b580b717d7d155Mark Andrews * them. If response, look to see where it goes.
35541328a8c18ba1f984300dfe30ec8713c90031Mark Andrews /* response */
35541328a8c18ba1f984300dfe30ec8713c90031Mark Andrews resp = bucket_search(disp, &tcpmsg->address, id, bucket);
35541328a8c18ba1f984300dfe30ec8713c90031Mark Andrews XDEBUG(("Search for response in bucket %d: %s\n",
35541328a8c18ba1f984300dfe30ec8713c90031Mark Andrews bucket, (resp == NULL ? "NOT FOUND" : "FOUND")));
35541328a8c18ba1f984300dfe30ec8713c90031Mark Andrews * At this point, rev contains the event we want to fill in, and
35541328a8c18ba1f984300dfe30ec8713c90031Mark Andrews * resp contains the information on the place to send it to.
ca9af3aaf798f98624fc1dc69d8c7d51bf01334dBrian Wellington * Send the event off.
ca9af3aaf798f98624fc1dc69d8c7d51bf01334dBrian Wellington dns_tcpmsg_keepbuffer(tcpmsg, &rev->buffer);
35541328a8c18ba1f984300dfe30ec8713c90031Mark Andrews ISC_EVENT_INIT(rev, sizeof(*rev), 0, NULL, DNS_EVENT_DISPATCH,
35541328a8c18ba1f984300dfe30ec8713c90031Mark Andrews XDEBUG(("Sent event for buffer %p (len %d) to task %p\n",
35541328a8c18ba1f984300dfe30ec8713c90031Mark Andrews rev->buffer.base, rev->buffer.length, resp->task));
35541328a8c18ba1f984300dfe30ec8713c90031Mark Andrews ISC_TASK_SEND(resp->task, (isc_event_t **)&rev);
35541328a8c18ba1f984300dfe30ec8713c90031Mark Andrews * Restart recv() to get the next packet.
1ea2595e1b33cc63ea73ee1d54b580b717d7d155Mark Andrews * disp must be locked
35541328a8c18ba1f984300dfe30ec8713c90031Mark Andrews unsigned int wanted;
60ab03125c137c48a6b2ed6df1d2c8657757e09dMark Andrews wanted = ISC_MIN(disp->recvs_wanted, disp->requests + 2);
94766449d6125cd5870891b70d46573e5deaceb4Brian Wellington * UDP reads are always maximal.
6f071989da905bb5ab2c6dfd01a71ee5ecea5918Brian Wellington region.base = allocate_buffer(disp, disp->buffersize);
0b09763c354ec91fb352b6b4cea383bd0195b2d8Mark Andrews XDEBUG(("Recv into %p, length %d\n", region.base,
8839b6acbf816fedc15b8e9e1c71fd606a9cd8eaBrian Wellington res = isc_socket_recv(disp->socket, ®ion, ISC_TRUE,
1ea2595e1b33cc63ea73ee1d54b580b717d7d155Mark Andrewsdns_dispatch_create(isc_mem_t *mctx, isc_socket_t *sock, isc_task_t *task,
1ea2595e1b33cc63ea73ee1d54b580b717d7d155Mark Andrews unsigned int maxbuffers, unsigned int maxrequests,
35541328a8c18ba1f984300dfe30ec8713c90031Mark Andrews unsigned int hashsize,
35541328a8c18ba1f984300dfe30ec8713c90031Mark Andrews unsigned int i;
93d6dfaf66258337985427c86181f01fc51f0bb4Mark Andrews REQUIRE(maxbuffersize >= 512 && maxbuffersize < (64 * 1024));
94766449d6125cd5870891b70d46573e5deaceb4Brian Wellington REQUIRE(socktype == isc_socket_udp || socktype == isc_socket_tcp);
94766449d6125cd5870891b70d46573e5deaceb4Brian Wellington disp = isc_mem_get(mctx, sizeof(dns_dispatch_t));
60ab03125c137c48a6b2ed6df1d2c8657757e09dMark Andrews disp->recvs_wanted = 4; /* XXXMLG config option */
ca9af3aaf798f98624fc1dc69d8c7d51bf01334dBrian Wellington for (i = 0 ; i < tablesize ; i++)
6fac7ff1f9ec9c3873d3b55c5079fa79aba1f146Mark Andrews if (isc_mutex_init(&disp->lock) != ISC_R_SUCCESS) {
6fac7ff1f9ec9c3873d3b55c5079fa79aba1f146Mark Andrews UNEXPECTED_ERROR(__FILE__, __LINE__, "isc_mutex_init failed");
6fac7ff1f9ec9c3873d3b55c5079fa79aba1f146Mark Andrews if (isc_mempool_create(mctx, sizeof(dns_dispatchevent_t),
6fac7ff1f9ec9c3873d3b55c5079fa79aba1f146Mark Andrews isc_mempool_setmaxalloc(disp->bpool, maxbuffers);
6fac7ff1f9ec9c3873d3b55c5079fa79aba1f146Mark Andrews if (isc_mempool_create(mctx, sizeof(dns_dispentry_t),
6fac7ff1f9ec9c3873d3b55c5079fa79aba1f146Mark Andrews * Keep some number of items around. This should be a config
6fac7ff1f9ec9c3873d3b55c5079fa79aba1f146Mark Andrews * option. For now, keep 8, but later keep at least two even
6fac7ff1f9ec9c3873d3b55c5079fa79aba1f146Mark Andrews * if the caller wants less. This allows us to ensure certain
6fac7ff1f9ec9c3873d3b55c5079fa79aba1f146Mark Andrews * things, like an event can be "freed" and the next allocation
6fac7ff1f9ec9c3873d3b55c5079fa79aba1f146Mark Andrews * will always succeed.
6fac7ff1f9ec9c3873d3b55c5079fa79aba1f146Mark Andrews * Note that if limits are placed on anything here, we use one
6fac7ff1f9ec9c3873d3b55c5079fa79aba1f146Mark Andrews * event internally, so the actual limit should be "wanted + 1."
6fac7ff1f9ec9c3873d3b55c5079fa79aba1f146Mark Andrews * should initialize qid_state here XXXMLG
6fac7ff1f9ec9c3873d3b55c5079fa79aba1f146Mark Andrews dns_tcpmsg_init(disp->mctx, disp->socket, &disp->tcpmsg);
6fac7ff1f9ec9c3873d3b55c5079fa79aba1f146Mark Andrews * error returns
6fac7ff1f9ec9c3873d3b55c5079fa79aba1f146Mark Andrews isc_mem_put(mctx, disp->mctx, disp->qid_hashsize * sizeof(void *));
6fac7ff1f9ec9c3873d3b55c5079fa79aba1f146Mark Andrews isc_mem_put(mctx, disp, sizeof(dns_dispatch_t));
6fac7ff1f9ec9c3873d3b55c5079fa79aba1f146Mark Andrews REQUIRE(dispp != NULL && VALID_DISPATCH(*dispp));
0b09763c354ec91fb352b6b4cea383bd0195b2d8Mark Andrews XDEBUG(("dns_dispatch_destory: refcount = %d\n", disp->refcount));
613efcd8fbd0d1ce0d0afd1ac85d95cf85bffc27Brian Wellingtondns_dispatch_addresponse(dns_dispatch_t *disp, isc_sockaddr_t *dest,
60ab03125c137c48a6b2ed6df1d2c8657757e09dMark Andrews isc_task_t *task, isc_taskaction_t action, void *arg,
0b09763c354ec91fb352b6b4cea383bd0195b2d8Mark Andrews unsigned int bucket;
613efcd8fbd0d1ce0d0afd1ac85d95cf85bffc27Brian Wellington * Try somewhat hard to find an unique ID.
0b09763c354ec91fb352b6b4cea383bd0195b2d8Mark Andrews for (i = 0 ; i < 64 ; i++) {
0b09763c354ec91fb352b6b4cea383bd0195b2d8Mark Andrews if (bucket_search(disp, dest, id, bucket) == NULL) {
0ec4b862c9abd11c82c88ed62438f0cf06fed25dBob Halley ISC_LIST_APPEND(disp->qid_table[bucket], res, link);
d6643ef587324e40d8bda63e9f80be8141e101edBrian Wellington XDEBUG(("Inserted response into bucket %d\n", bucket));
0ec4b862c9abd11c82c88ed62438f0cf06fed25dBob Halleydns_dispatch_removeresponse(dns_dispatch_t *disp, dns_dispentry_t **resp,
0ec4b862c9abd11c82c88ed62438f0cf06fed25dBob Halley unsigned int bucket;
60ab03125c137c48a6b2ed6df1d2c8657757e09dMark Andrews ISC_LIST_UNLINK(disp->qid_table[bucket], res, link);
0ec4b862c9abd11c82c88ed62438f0cf06fed25dBob Halley free_buffer(disp, ev->buffer.base, ev->buffer.length);
78951552dccf0d0004d61072bbc71fa4b1aab30fAndreas Gustafssondns_dispatch_addrequest(dns_dispatch_t *disp,
0b09763c354ec91fb352b6b4cea383bd0195b2d8Mark Andrews isc_task_t *task, isc_taskaction_t action, void *arg,
3676eeb6ca95c66aae1256f37af8c990d9f25eb4Brian Wellington * If there are queries waiting to be processed, give this critter
ca9af3aaf798f98624fc1dc69d8c7d51bf01334dBrian Wellington * one of them.
0ec4b862c9abd11c82c88ed62438f0cf06fed25dBob Halleydns_dispatch_removerequest(dns_dispatch_t *disp, dns_dispentry_t **resp,
ca9af3aaf798f98624fc1dc69d8c7d51bf01334dBrian Wellington ISC_LIST_UNLINK(disp->rq_handlers, res, link);
0b09763c354ec91fb352b6b4cea383bd0195b2d8Mark Andrews free_buffer(disp, ev->buffer.base, ev->buffer.length);
93d6dfaf66258337985427c86181f01fc51f0bb4Mark Andrewsdns_dispatch_freeevent(dns_dispatch_t *disp, dns_dispentry_t *resp,
0b09763c354ec91fb352b6b4cea383bd0195b2d8Mark Andrews REQUIRE(sockevent != NULL && *sockevent != NULL);
f1263d2aa405087e74caf001cd443079f50ee903Mark Andrews REQUIRE(VALID_RESPONSE(resp) || VALID_REQUEST(resp));
0b09763c354ec91fb352b6b4cea383bd0195b2d8Mark Andrews free_buffer(disp, ev->buffer.base, ev->buffer.length);
60ab03125c137c48a6b2ed6df1d2c8657757e09dMark Andrewsdo_next_response(dns_dispatch_t *disp, dns_dispentry_t *resp)
0b09763c354ec91fb352b6b4cea383bd0195b2d8Mark Andrews ISC_EVENT_INIT(ev, sizeof(*ev), 0, NULL, DNS_EVENT_DISPATCH,
35541328a8c18ba1f984300dfe30ec8713c90031Mark Andrews XDEBUG(("Sent event for buffer %p (len %d) to task %p\n",
fabf2ee6b01ee06a0de940b83d53cf57f9f79265Mark Andrews ev->buffer.base, ev->buffer.length, resp->task));
35541328a8c18ba1f984300dfe30ec8713c90031Mark Andrews ISC_TASK_SEND(resp->task, (isc_event_t **)&ev);
fabf2ee6b01ee06a0de940b83d53cf57f9f79265Mark Andrewsdo_next_request(dns_dispatch_t *disp, dns_dispentry_t *resp)
35541328a8c18ba1f984300dfe30ec8713c90031Mark Andrews ISC_EVENT_INIT(ev, sizeof(*ev), 0, NULL, DNS_EVENT_DISPATCH,
25496cebadd170fd5fae2aabf0469eef551259aaBrian Wellington XDEBUG(("Sent event for buffer %p (len %d) to task %p\n",
60ab03125c137c48a6b2ed6df1d2c8657757e09dMark Andrews ev->buffer.base, ev->buffer.length, resp->task));
0b09763c354ec91fb352b6b4cea383bd0195b2d8Mark Andrews ISC_TASK_SEND(resp->task, (isc_event_t **)&ev);
60ab03125c137c48a6b2ed6df1d2c8657757e09dMark Andrewsdo_cancel(dns_dispatch_t *disp, dns_dispentry_t *resp)
0ec4b862c9abd11c82c88ed62438f0cf06fed25dBob Halley * If no target given, find the first request handler. If
0ec4b862c9abd11c82c88ed62438f0cf06fed25dBob Halley * there are packets waiting for any handler, however, don't
0ec4b862c9abd11c82c88ed62438f0cf06fed25dBob Halley * kill them.
93c786e0924aeca2c258e32355349e6ae60a0f72Andreas Gustafsson if (resp != NULL && resp->item_out == ISC_TRUE)
34aa7909371f13b4bc0ba6d155cfc38bfa1e3c5cAndreas Gustafsson * Search for the first responce handler without packets outstanding.
23e4260821eefa5019808e18e14e2b366461aad7Brian Wellington * No one to send the cancel event to, so nothing to do.
0ec4b862c9abd11c82c88ed62438f0cf06fed25dBob Halley * Send the shutdown failsafe event to this resp.
35541328a8c18ba1f984300dfe30ec8713c90031Mark Andrews ISC_EVENT_INIT(ev, sizeof (*ev), 0, NULL, DNS_EVENT_DISPATCH,
b5debbe212097d1c573a2ba3bd9a3d526d86b0aeBrian Wellington XDEBUG(("Sending failsafe event to task %p\n", resp->task));