mirror of
https://gitlab.isc.org/isc-projects/bind9
synced 2025-08-29 13:38:26 +00:00
checkpoint
This commit is contained in:
parent
2b71bc3d51
commit
1ec39fc7a8
@ -35,6 +35,14 @@
|
|||||||
|
|
||||||
#include "../isc/util.h"
|
#include "../isc/util.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we cannot send to this task, the application is broken.
|
||||||
|
*/
|
||||||
|
#define ISC_TASK_SEND(a, b) do { \
|
||||||
|
RUNTIME_CHECK(isc_task_send(a, b) == ISC_R_SUCCESS); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
|
||||||
struct dns_dispentry {
|
struct dns_dispentry {
|
||||||
unsigned int magic;
|
unsigned int magic;
|
||||||
dns_messageid_t id;
|
dns_messageid_t id;
|
||||||
@ -43,8 +51,9 @@ struct dns_dispentry {
|
|||||||
isc_task_t *task;
|
isc_task_t *task;
|
||||||
isc_taskaction_t action;
|
isc_taskaction_t action;
|
||||||
void *arg;
|
void *arg;
|
||||||
|
isc_boolean_t item_out;
|
||||||
ISC_LIST(dns_dispatchevent_t) items;
|
ISC_LIST(dns_dispatchevent_t) items;
|
||||||
ISC_LINK(dns_dispentry_t) link;
|
ISC_LINK(dns_dispentry_t) link;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define INVALID_BUCKET (0xffffdead)
|
#define INVALID_BUCKET (0xffffdead)
|
||||||
@ -63,6 +72,12 @@ struct dns_dispatch {
|
|||||||
isc_mempool_t *epool; /* memory pool for events */
|
isc_mempool_t *epool; /* memory pool for events */
|
||||||
isc_mempool_t *bpool; /* memory pool for buffers */
|
isc_mempool_t *bpool; /* memory pool for buffers */
|
||||||
isc_mempool_t *rpool; /* memory pool request/reply */
|
isc_mempool_t *rpool; /* memory pool request/reply */
|
||||||
|
dns_dispatchevent_t *failsafe_ev; /* failsafe cancel event */
|
||||||
|
unsigned int recvs; /* recv() calls outstanding */
|
||||||
|
unsigned int recvs_wanted; /* recv() calls wanted */
|
||||||
|
unsigned int shutting_down : 1,
|
||||||
|
shutdown_out : 1;
|
||||||
|
dns_result_t shutdown_why;
|
||||||
ISC_LIST(dns_dispentry_t) rq_handlers; /* request handler list */
|
ISC_LIST(dns_dispentry_t) rq_handlers; /* request handler list */
|
||||||
ISC_LIST(dns_dispatchevent_t) rq_events; /* holder for rq events */
|
ISC_LIST(dns_dispatchevent_t) rq_events; /* holder for rq events */
|
||||||
isc_int32_t qid_state; /* state generator info */
|
isc_int32_t qid_state; /* state generator info */
|
||||||
@ -83,13 +98,93 @@ struct dns_dispatch {
|
|||||||
/*
|
/*
|
||||||
* statics.
|
* statics.
|
||||||
*/
|
*/
|
||||||
static dns_dispentry_t *bucket_search(dns_dispatch_t *, isc_sockaddr_t *,
|
static dns_dispentry_t *
|
||||||
dns_messageid_t, unsigned int);
|
bucket_search(dns_dispatch_t *, isc_sockaddr_t *,
|
||||||
static void destroy(dns_dispatch_t *);
|
dns_messageid_t, unsigned int);
|
||||||
static void udp_recv(isc_task_t *, isc_event_t *);
|
|
||||||
static dns_result_t startrecv(dns_dispatch_t *);
|
static void
|
||||||
static dns_messageid_t randomid(dns_dispatch_t *);
|
destroy(dns_dispatch_t *);
|
||||||
static unsigned int hash(dns_dispatch_t *, isc_sockaddr_t *, dns_messageid_t);
|
|
||||||
|
static void
|
||||||
|
udp_recv(isc_task_t *, isc_event_t *);
|
||||||
|
|
||||||
|
static void
|
||||||
|
startrecv(dns_dispatch_t *);
|
||||||
|
|
||||||
|
static dns_messageid_t
|
||||||
|
randomid(dns_dispatch_t *);
|
||||||
|
|
||||||
|
static unsigned int
|
||||||
|
hash(dns_dispatch_t *, isc_sockaddr_t *, dns_messageid_t);
|
||||||
|
|
||||||
|
static void
|
||||||
|
free_buffer(dns_dispatch_t *disp, void *buf, unsigned int len);
|
||||||
|
|
||||||
|
static void *
|
||||||
|
allocate_buffer(dns_dispatch_t *disp, unsigned int len);
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
free_event(dns_dispatch_t *disp, dns_dispatchevent_t *ev);
|
||||||
|
|
||||||
|
static inline dns_dispatchevent_t *
|
||||||
|
allocate_event(dns_dispatch_t *disp);
|
||||||
|
|
||||||
|
static inline isc_boolean_t
|
||||||
|
ok_to_kill(dns_dispatch_t *disp);
|
||||||
|
|
||||||
|
static void
|
||||||
|
do_next_request(dns_dispatch_t *disp, dns_dispentry_t *resp);
|
||||||
|
|
||||||
|
static void
|
||||||
|
do_next_response(dns_dispatch_t *disp, dns_dispentry_t *resp);
|
||||||
|
|
||||||
|
static void
|
||||||
|
do_cancel(dns_dispatch_t *disp, dns_dispentry_t *resp);
|
||||||
|
|
||||||
|
static dns_dispentry_t *
|
||||||
|
linear_first(dns_dispatch_t *disp);
|
||||||
|
|
||||||
|
static dns_dispentry_t *
|
||||||
|
linear_next(dns_dispatch_t *disp, dns_dispentry_t *resp);
|
||||||
|
|
||||||
|
static dns_dispentry_t *
|
||||||
|
linear_first(dns_dispatch_t *disp)
|
||||||
|
{
|
||||||
|
dns_dispentry_t *ret;
|
||||||
|
unsigned int bucket;
|
||||||
|
|
||||||
|
bucket = 0;
|
||||||
|
|
||||||
|
while (bucket < disp->qid_hashsize) {
|
||||||
|
ret = ISC_LIST_HEAD(disp->qid_table[bucket]);
|
||||||
|
if (ret != NULL)
|
||||||
|
return (ret);
|
||||||
|
bucket++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static dns_dispentry_t *
|
||||||
|
linear_next(dns_dispatch_t *disp, dns_dispentry_t *resp)
|
||||||
|
{
|
||||||
|
dns_dispentry_t *ret;
|
||||||
|
unsigned int bucket;
|
||||||
|
|
||||||
|
ret = ISC_LIST_NEXT(resp, link);
|
||||||
|
if (ret != NULL)
|
||||||
|
return (ret);
|
||||||
|
|
||||||
|
bucket = resp->bucket;
|
||||||
|
while (bucket < disp->qid_hashsize) {
|
||||||
|
ret = ISC_LIST_HEAD(disp->qid_table[bucket]);
|
||||||
|
if (ret != NULL)
|
||||||
|
return (ret);
|
||||||
|
bucket++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Return a hash of the destination and message id. For now, just return
|
* Return a hash of the destination and message id. For now, just return
|
||||||
@ -120,17 +215,45 @@ randomid(dns_dispatch_t *disp)
|
|||||||
return ((dns_messageid_t)disp->qid_state);
|
return ((dns_messageid_t)disp->qid_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline isc_boolean_t
|
||||||
|
ok_to_kill(dns_dispatch_t *disp)
|
||||||
|
{
|
||||||
|
if (disp->recvs > 0)
|
||||||
|
return (ISC_FALSE);
|
||||||
|
|
||||||
|
if (disp->refcount > 0)
|
||||||
|
return (ISC_FALSE);
|
||||||
|
|
||||||
|
return (ISC_TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Called when refcount reaches 0 at any time.
|
* Called when refcount reaches 0 at any time.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
destroy(dns_dispatch_t *disp)
|
destroy(dns_dispatch_t *disp)
|
||||||
{
|
{
|
||||||
|
dns_dispatchevent_t *ev;
|
||||||
|
|
||||||
disp->magic = 0;
|
disp->magic = 0;
|
||||||
|
|
||||||
isc_task_detach(&disp->task);
|
isc_task_detach(&disp->task);
|
||||||
isc_socket_detach(&disp->socket);
|
isc_socket_detach(&disp->socket);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Final cleanup of packets on the request list.
|
||||||
|
*/
|
||||||
|
ev = ISC_LIST_HEAD(disp->rq_events);
|
||||||
|
while (ev != NULL) {
|
||||||
|
ISC_LIST_UNLINK(disp->rq_events, ev, link);
|
||||||
|
free_buffer(disp, ev->buffer.base, ev->buffer.length);
|
||||||
|
free_event(disp, ev);
|
||||||
|
ev = ISC_LIST_HEAD(disp->rq_events);
|
||||||
|
}
|
||||||
|
|
||||||
|
isc_mempool_put(disp->epool, disp->failsafe_ev);
|
||||||
|
disp->failsafe_ev = NULL;
|
||||||
|
|
||||||
isc_mempool_destroy(&disp->rpool);
|
isc_mempool_destroy(&disp->rpool);
|
||||||
isc_mempool_destroy(&disp->bpool);
|
isc_mempool_destroy(&disp->bpool);
|
||||||
isc_mempool_destroy(&disp->epool);
|
isc_mempool_destroy(&disp->epool);
|
||||||
@ -158,6 +281,75 @@ bucket_search(dns_dispatch_t *disp, isc_sockaddr_t *dest, dns_messageid_t id,
|
|||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
free_buffer(dns_dispatch_t *disp, void *buf, unsigned int len)
|
||||||
|
{
|
||||||
|
if (len == disp->buffersize)
|
||||||
|
isc_mempool_put(disp->bpool, buf);
|
||||||
|
else
|
||||||
|
isc_mem_put(disp->mctx, buf, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *
|
||||||
|
allocate_buffer(dns_dispatch_t *disp, unsigned int len)
|
||||||
|
{
|
||||||
|
void *temp;
|
||||||
|
|
||||||
|
INSIST(len > 0);
|
||||||
|
|
||||||
|
if (len == disp->buffersize)
|
||||||
|
temp = isc_mempool_get(disp->bpool);
|
||||||
|
else
|
||||||
|
temp = isc_mem_get(disp->mctx, len);
|
||||||
|
|
||||||
|
return (temp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
free_event(dns_dispatch_t *disp, dns_dispatchevent_t *ev)
|
||||||
|
{
|
||||||
|
if (disp->failsafe_ev == ev) {
|
||||||
|
INSIST(disp->shutdown_out == 1);
|
||||||
|
disp->shutdown_out = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
isc_mempool_put(disp->epool, ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline dns_dispatchevent_t *
|
||||||
|
allocate_event(dns_dispatch_t *disp)
|
||||||
|
{
|
||||||
|
dns_dispatchevent_t *ev;
|
||||||
|
|
||||||
|
ev = isc_mempool_get(disp->epool);
|
||||||
|
|
||||||
|
return (ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* General flow:
|
||||||
|
*
|
||||||
|
* If I/O result == CANCELED, free the buffer and notify everyone as
|
||||||
|
* the various queues drain.
|
||||||
|
*
|
||||||
|
* If I/O is error (not canceled and not success) log it, free the buffer,
|
||||||
|
* and restart.
|
||||||
|
*
|
||||||
|
* If query:
|
||||||
|
* if no listeners: free the buffer, restart.
|
||||||
|
* if listener: allocate event, fill in details.
|
||||||
|
* If cannot allocate, free buffer, restart.
|
||||||
|
* if rq event queue is not empty, queue. else, send.
|
||||||
|
* restart.
|
||||||
|
*
|
||||||
|
* If response:
|
||||||
|
* Allocate event, fill in details.
|
||||||
|
* If cannot allocate, free buffer, restart.
|
||||||
|
* find target. If not found, free buffer, restart.
|
||||||
|
* if event queue is not empty, queue. else, send.
|
||||||
|
* restart.
|
||||||
|
*/
|
||||||
static void
|
static void
|
||||||
udp_recv(isc_task_t *task, isc_event_t *ev_in)
|
udp_recv(isc_task_t *task, isc_event_t *ev_in)
|
||||||
{
|
{
|
||||||
@ -167,19 +359,29 @@ udp_recv(isc_task_t *task, isc_event_t *ev_in)
|
|||||||
dns_result_t dres;
|
dns_result_t dres;
|
||||||
isc_buffer_t source;
|
isc_buffer_t source;
|
||||||
unsigned int flags;
|
unsigned int flags;
|
||||||
|
dns_dispentry_t *resp;
|
||||||
|
dns_dispatchevent_t *rev;
|
||||||
|
unsigned int bucket;
|
||||||
|
|
||||||
(void)task; /* shut up compiler */
|
(void)task; /* shut up compiler */
|
||||||
|
|
||||||
LOCK(&disp->lock);
|
LOCK(&disp->lock);
|
||||||
|
|
||||||
if (ev->result != ISC_R_SUCCESS) {
|
if (ev->result != ISC_R_SUCCESS) {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the recv() was canceled pass the word on.
|
* If the recv() was canceled pass the word on.
|
||||||
* XXXMLG
|
|
||||||
*/
|
*/
|
||||||
if (ev->result == ISC_R_CANCELED) {
|
if (ev->result == ISC_R_CANCELED) {
|
||||||
|
free_buffer(disp, ev->region.base, ev->region.length);
|
||||||
isc_event_free(&ev_in);
|
isc_event_free(&ev_in);
|
||||||
|
|
||||||
|
INSIST(disp->recvs > 0);
|
||||||
|
disp->recvs--;
|
||||||
|
if (disp->recvs == 0 && disp->shutting_down == 0) {
|
||||||
|
disp->shutdown_why = ISC_R_CANCELED;
|
||||||
|
disp->shutting_down = 1;
|
||||||
|
do_cancel(disp, NULL);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -187,6 +389,7 @@ udp_recv(isc_task_t *task, isc_event_t *ev_in)
|
|||||||
* otherwise, on strange error, log it and restart.
|
* otherwise, on strange error, log it and restart.
|
||||||
* XXXMLG
|
* XXXMLG
|
||||||
*/
|
*/
|
||||||
|
free_buffer(disp, ev->region.base, ev->region.length);
|
||||||
goto restart;
|
goto restart;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -197,28 +400,52 @@ udp_recv(isc_task_t *task, isc_event_t *ev_in)
|
|||||||
ISC_BUFFERTYPE_BINARY);
|
ISC_BUFFERTYPE_BINARY);
|
||||||
dres = dns_message_peekheader(&source, &id, &flags);
|
dres = dns_message_peekheader(&source, &id, &flags);
|
||||||
if (dres != DNS_R_SUCCESS) {
|
if (dres != DNS_R_SUCCESS) {
|
||||||
|
free_buffer(disp, ev->region.base, ev->region.length);
|
||||||
/* XXXMLG log something here... */
|
/* XXXMLG log something here... */
|
||||||
goto restart;
|
goto restart;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Allocate an event to send to the query or response client, and
|
||||||
|
* allocate a new buffer for our use.
|
||||||
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Look at flags. If query, check to see if we have someone handling
|
* Look at flags. If query, check to see if we have someone handling
|
||||||
* them. If response, look to see where it goes.
|
* them. If response, look to see where it goes.
|
||||||
*/
|
*/
|
||||||
if ((flags & DNS_MESSAGEFLAG_QR) == 0) {
|
if ((flags & DNS_MESSAGEFLAG_QR) == 0) {
|
||||||
/* XXXLMG query */
|
resp = ISC_LIST_HEAD(disp->rq_handlers);
|
||||||
|
if (resp == NULL) {
|
||||||
|
free_buffer(disp, ev->region.base, ev->region.length);
|
||||||
|
goto restart;
|
||||||
|
}
|
||||||
|
rev = allocate_event(disp);
|
||||||
|
if (rev == NULL) {
|
||||||
|
free_buffer(disp, ev->region.base, ev->region.length);
|
||||||
|
goto restart;
|
||||||
|
}
|
||||||
|
/* query */
|
||||||
} else {
|
} else {
|
||||||
/* XXXMLG response */
|
/* response */
|
||||||
|
rev = allocate_event(disp);
|
||||||
|
if (rev == NULL) {
|
||||||
|
free_buffer(disp, ev->region.base, ev->region.length);
|
||||||
|
goto restart;
|
||||||
|
}
|
||||||
|
bucket = hash(disp, &ev->address, id);
|
||||||
|
resp = bucket_search(disp, &ev->address, id, bucket);
|
||||||
|
if (resp == NULL) {
|
||||||
|
free_buffer(disp, ev->region.base, ev->region.length);
|
||||||
|
goto restart;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Restart recv() to get the next packet.
|
* Restart recv() to get the next packet.
|
||||||
*/
|
*/
|
||||||
restart:
|
restart:
|
||||||
dres = startrecv(disp);
|
startrecv(disp);
|
||||||
if (dres != DNS_R_SUCCESS) {
|
|
||||||
/* XXXMLG kill all people listening, try again? */
|
|
||||||
}
|
|
||||||
|
|
||||||
UNLOCK(&disp->lock);
|
UNLOCK(&disp->lock);
|
||||||
|
|
||||||
@ -228,35 +455,46 @@ udp_recv(isc_task_t *task, isc_event_t *ev_in)
|
|||||||
/*
|
/*
|
||||||
* disp must be locked
|
* disp must be locked
|
||||||
*/
|
*/
|
||||||
static dns_result_t
|
static void
|
||||||
startrecv(dns_dispatch_t *disp)
|
startrecv(dns_dispatch_t *disp)
|
||||||
{
|
{
|
||||||
isc_sockettype_t socktype;
|
isc_sockettype_t socktype;
|
||||||
isc_result_t res;
|
isc_result_t res;
|
||||||
isc_region_t region;
|
isc_region_t region;
|
||||||
|
|
||||||
|
if (disp->shutting_down == 1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (disp->recvs >= disp->recvs_wanted)
|
||||||
|
return;
|
||||||
|
|
||||||
socktype = isc_socket_gettype(disp->socket);
|
socktype = isc_socket_gettype(disp->socket);
|
||||||
|
|
||||||
switch (socktype) {
|
while (disp->recvs < disp->recvs_wanted) {
|
||||||
/*
|
switch (socktype) {
|
||||||
* UDP reads are always maximal.
|
/*
|
||||||
*/
|
* UDP reads are always maximal.
|
||||||
case isc_socket_udp:
|
*/
|
||||||
region.length = disp->buffersize;
|
case isc_socket_udp:
|
||||||
region.base = isc_mempool_get(disp->bpool);
|
region.length = disp->buffersize;
|
||||||
if (region.base == NULL)
|
region.base = allocate_buffer(disp, disp->buffersize);
|
||||||
return (DNS_R_NOMEMORY);
|
if (region.base == NULL)
|
||||||
res = isc_socket_recv(disp->socket, ®ion, ISC_TRUE,
|
return;
|
||||||
disp->task, udp_recv, disp);
|
res = isc_socket_recv(disp->socket, ®ion, ISC_TRUE,
|
||||||
if (res != ISC_R_SUCCESS)
|
disp->task, udp_recv, disp);
|
||||||
return (res);
|
if (res != ISC_R_SUCCESS) {
|
||||||
break;
|
disp->shutdown_why = res;
|
||||||
case isc_socket_tcp:
|
do_cancel(disp, NULL);
|
||||||
INSIST(1); /* XXXMLG */
|
return;
|
||||||
break;
|
}
|
||||||
}
|
disp->recvs++;
|
||||||
|
break;
|
||||||
|
|
||||||
return (DNS_R_SUCCESS);
|
case isc_socket_tcp:
|
||||||
|
INSIST(1); /* XXXMLG */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -298,6 +536,11 @@ dns_dispatch_create(isc_mem_t *mctx, isc_socket_t *sock, isc_task_t *task,
|
|||||||
disp->socket = NULL; /* set below */
|
disp->socket = NULL; /* set below */
|
||||||
disp->buffersize = maxbuffersize;
|
disp->buffersize = maxbuffersize;
|
||||||
disp->refcount = 1;
|
disp->refcount = 1;
|
||||||
|
disp->recvs = 0;
|
||||||
|
disp->recvs_wanted = 1;
|
||||||
|
disp->shutting_down = 0;
|
||||||
|
disp->shutdown_out = 0;
|
||||||
|
disp->shutdown_why = ISC_R_UNEXPECTED;
|
||||||
ISC_LIST_INIT(disp->rq_handlers);
|
ISC_LIST_INIT(disp->rq_handlers);
|
||||||
ISC_LIST_INIT(disp->rq_events);
|
ISC_LIST_INIT(disp->rq_events);
|
||||||
|
|
||||||
@ -329,7 +572,6 @@ dns_dispatch_create(isc_mem_t *mctx, isc_socket_t *sock, isc_task_t *task,
|
|||||||
res = DNS_R_NOMEMORY;
|
res = DNS_R_NOMEMORY;
|
||||||
goto out4;
|
goto out4;
|
||||||
}
|
}
|
||||||
isc_mempool_setfreemax(disp->bpool, maxbuffers);
|
|
||||||
|
|
||||||
if (isc_mempool_create(mctx, sizeof(dns_dispentry_t),
|
if (isc_mempool_create(mctx, sizeof(dns_dispentry_t),
|
||||||
&disp->rpool) != ISC_R_SUCCESS) {
|
&disp->rpool) != ISC_R_SUCCESS) {
|
||||||
@ -337,9 +579,32 @@ dns_dispatch_create(isc_mem_t *mctx, isc_socket_t *sock, isc_task_t *task,
|
|||||||
goto out5;
|
goto out5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Keep some number of items around. This should be a config
|
||||||
|
* option. For now, keep 8, but later keep at least two even
|
||||||
|
* if the caller wants less. This allows us to ensure certain
|
||||||
|
* things, like an event can be "freed" and the next allocation
|
||||||
|
* will always succeed.
|
||||||
|
*
|
||||||
|
* Note that if limits are placed on anything here, we use one
|
||||||
|
* event internally, so the actual limit should be "wanted + 1."
|
||||||
|
*
|
||||||
|
* XXXMLG
|
||||||
|
*/
|
||||||
|
isc_mempool_setfreemax(disp->epool, 8);
|
||||||
|
isc_mempool_setfreemax(disp->bpool, 8);
|
||||||
|
isc_mempool_setfreemax(disp->rpool, 8);
|
||||||
|
|
||||||
|
disp->failsafe_ev = allocate_event(disp);
|
||||||
|
if (disp->failsafe_ev == NULL) {
|
||||||
|
res = DNS_R_NOMEMORY;
|
||||||
|
goto out6;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* should initialize qid_state here XXXMLG
|
* should initialize qid_state here XXXMLG
|
||||||
*/
|
*/
|
||||||
|
disp->qid_state = (unsigned int)disp;
|
||||||
|
|
||||||
disp->magic = DISPATCH_MAGIC;
|
disp->magic = DISPATCH_MAGIC;
|
||||||
|
|
||||||
@ -353,10 +618,8 @@ dns_dispatch_create(isc_mem_t *mctx, isc_socket_t *sock, isc_task_t *task,
|
|||||||
/*
|
/*
|
||||||
* error returns
|
* error returns
|
||||||
*/
|
*/
|
||||||
#if 0 /* enable when needed */
|
|
||||||
out6:
|
out6:
|
||||||
isc_mempool_destroy(&disp->respool);
|
isc_mempool_destroy(&disp->rpool);
|
||||||
#endif
|
|
||||||
out5:
|
out5:
|
||||||
isc_mempool_destroy(&disp->bpool);
|
isc_mempool_destroy(&disp->bpool);
|
||||||
out4:
|
out4:
|
||||||
@ -382,14 +645,11 @@ dns_dispatch_destroy(dns_dispatch_t **dispp)
|
|||||||
disp = *dispp;
|
disp = *dispp;
|
||||||
*dispp = NULL;
|
*dispp = NULL;
|
||||||
|
|
||||||
killit = ISC_FALSE;
|
|
||||||
|
|
||||||
LOCK(&disp->lock);
|
LOCK(&disp->lock);
|
||||||
|
|
||||||
INSIST(disp->refcount > 0);
|
INSIST(disp->refcount > 0);
|
||||||
disp->refcount--;
|
disp->refcount--;
|
||||||
if (disp->refcount == 0)
|
killit = ok_to_kill(disp);
|
||||||
killit = ISC_TRUE;
|
|
||||||
|
|
||||||
UNLOCK(&disp->lock);
|
UNLOCK(&disp->lock);
|
||||||
|
|
||||||
@ -451,6 +711,7 @@ dns_dispatch_addresponse(dns_dispatch_t *disp, isc_sockaddr_t *dest,
|
|||||||
res->task = task;
|
res->task = task;
|
||||||
res->action = action;
|
res->action = action;
|
||||||
res->arg = arg;
|
res->arg = arg;
|
||||||
|
res->item_out = ISC_FALSE;
|
||||||
ISC_LIST_INIT(res->items);
|
ISC_LIST_INIT(res->items);
|
||||||
ISC_LINK_INIT(res, link);
|
ISC_LINK_INIT(res, link);
|
||||||
ISC_LIST_APPEND(disp->qid_table[bucket], res, link);
|
ISC_LIST_APPEND(disp->qid_table[bucket], res, link);
|
||||||
@ -460,6 +721,8 @@ dns_dispatch_addresponse(dns_dispatch_t *disp, isc_sockaddr_t *dest,
|
|||||||
*idp = id;
|
*idp = id;
|
||||||
*resp = res;
|
*resp = res;
|
||||||
|
|
||||||
|
startrecv(disp);
|
||||||
|
|
||||||
return (DNS_R_SUCCESS);
|
return (DNS_R_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -479,8 +742,6 @@ dns_dispatch_removeresponse(dns_dispatch_t *disp, dns_dispentry_t **resp,
|
|||||||
res = *resp;
|
res = *resp;
|
||||||
*resp = NULL;
|
*resp = NULL;
|
||||||
|
|
||||||
killit = ISC_FALSE;
|
|
||||||
|
|
||||||
if (sockevent != NULL) {
|
if (sockevent != NULL) {
|
||||||
REQUIRE(*sockevent != NULL);
|
REQUIRE(*sockevent != NULL);
|
||||||
ev = *sockevent;
|
ev = *sockevent;
|
||||||
@ -493,8 +754,7 @@ dns_dispatch_removeresponse(dns_dispatch_t *disp, dns_dispentry_t **resp,
|
|||||||
|
|
||||||
INSIST(disp->refcount > 0);
|
INSIST(disp->refcount > 0);
|
||||||
disp->refcount--;
|
disp->refcount--;
|
||||||
if (disp->refcount == 0)
|
killit = ok_to_kill(disp);
|
||||||
killit = ISC_TRUE;
|
|
||||||
|
|
||||||
res->magic = 0;
|
res->magic = 0;
|
||||||
bucket = res->bucket;
|
bucket = res->bucket;
|
||||||
@ -502,6 +762,14 @@ dns_dispatch_removeresponse(dns_dispatch_t *disp, dns_dispentry_t **resp,
|
|||||||
ISC_LIST_UNLINK(disp->qid_table[bucket], res, link);
|
ISC_LIST_UNLINK(disp->qid_table[bucket], res, link);
|
||||||
|
|
||||||
isc_mempool_put(disp->rpool, res);
|
isc_mempool_put(disp->rpool, res);
|
||||||
|
if (ev != NULL) {
|
||||||
|
free_buffer(disp, ev->buffer.base, ev->buffer.length);
|
||||||
|
free_event(disp, ev);
|
||||||
|
}
|
||||||
|
if (disp->shutting_down == 1)
|
||||||
|
do_cancel(disp, NULL);
|
||||||
|
|
||||||
|
startrecv(disp);
|
||||||
|
|
||||||
UNLOCK(&disp->lock);
|
UNLOCK(&disp->lock);
|
||||||
|
|
||||||
@ -533,6 +801,7 @@ dns_dispatch_addrequest(dns_dispatch_t *disp,
|
|||||||
res->task = task;
|
res->task = task;
|
||||||
res->action = action;
|
res->action = action;
|
||||||
res->arg = arg;
|
res->arg = arg;
|
||||||
|
res->item_out = ISC_FALSE;
|
||||||
ISC_LIST_INIT(res->items);
|
ISC_LIST_INIT(res->items);
|
||||||
ISC_LINK_INIT(res, link);
|
ISC_LINK_INIT(res, link);
|
||||||
ISC_LIST_APPEND(disp->rq_handlers, res, link);
|
ISC_LIST_APPEND(disp->rq_handlers, res, link);
|
||||||
@ -541,6 +810,8 @@ dns_dispatch_addrequest(dns_dispatch_t *disp,
|
|||||||
|
|
||||||
*resp = res;
|
*resp = res;
|
||||||
|
|
||||||
|
startrecv(disp);
|
||||||
|
|
||||||
return (DNS_R_SUCCESS);
|
return (DNS_R_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -559,8 +830,6 @@ dns_dispatch_removerequest(dns_dispatch_t *disp, dns_dispentry_t **resp,
|
|||||||
res = *resp;
|
res = *resp;
|
||||||
*resp = NULL;
|
*resp = NULL;
|
||||||
|
|
||||||
killit = ISC_FALSE;
|
|
||||||
|
|
||||||
if (sockevent != NULL) {
|
if (sockevent != NULL) {
|
||||||
REQUIRE(*sockevent != NULL);
|
REQUIRE(*sockevent != NULL);
|
||||||
ev = *sockevent;
|
ev = *sockevent;
|
||||||
@ -573,17 +842,150 @@ dns_dispatch_removerequest(dns_dispatch_t *disp, dns_dispentry_t **resp,
|
|||||||
|
|
||||||
INSIST(disp->refcount > 0);
|
INSIST(disp->refcount > 0);
|
||||||
disp->refcount--;
|
disp->refcount--;
|
||||||
if (disp->refcount == 0)
|
killit = ok_to_kill(disp);
|
||||||
killit = ISC_TRUE;
|
|
||||||
|
|
||||||
res->magic = 0;
|
res->magic = 0;
|
||||||
|
|
||||||
ISC_LIST_UNLINK(disp->rq_handlers, res, link);
|
ISC_LIST_UNLINK(disp->rq_handlers, res, link);
|
||||||
|
|
||||||
isc_mempool_put(disp->rpool, res);
|
isc_mempool_put(disp->rpool, res);
|
||||||
|
if (ev != NULL) {
|
||||||
|
if (ev->buffer.length != 0)
|
||||||
|
free_buffer(disp, ev->buffer.base, ev->buffer.length);
|
||||||
|
free_event(disp, ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
startrecv(disp);
|
||||||
|
|
||||||
UNLOCK(&disp->lock);
|
UNLOCK(&disp->lock);
|
||||||
|
|
||||||
if (killit)
|
if (killit)
|
||||||
destroy(disp);
|
destroy(disp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
dns_dispatch_freeevent(dns_dispatch_t *disp, dns_dispentry_t *resp,
|
||||||
|
dns_dispatchevent_t **sockevent)
|
||||||
|
{
|
||||||
|
dns_dispatchevent_t *ev;
|
||||||
|
isc_boolean_t response;
|
||||||
|
|
||||||
|
REQUIRE(VALID_DISPATCH(disp));
|
||||||
|
REQUIRE(sockevent != NULL && *sockevent != NULL);
|
||||||
|
|
||||||
|
ev = *sockevent;
|
||||||
|
*sockevent = NULL;
|
||||||
|
|
||||||
|
response = ISC_FALSE;
|
||||||
|
if (VALID_RESPONSE(resp)) {
|
||||||
|
response = ISC_TRUE;
|
||||||
|
} else {
|
||||||
|
REQUIRE(VALID_RESPONSE(resp) || VALID_REQUEST(resp));
|
||||||
|
}
|
||||||
|
|
||||||
|
LOCK(&disp->lock);
|
||||||
|
REQUIRE(ev != disp->failsafe_ev);
|
||||||
|
|
||||||
|
free_buffer(disp, ev->buffer.base, ev->buffer.length);
|
||||||
|
free_event(disp, ev);
|
||||||
|
|
||||||
|
if (response)
|
||||||
|
do_next_response(disp, resp);
|
||||||
|
else
|
||||||
|
do_next_request(disp, resp);
|
||||||
|
|
||||||
|
startrecv(disp);
|
||||||
|
|
||||||
|
UNLOCK(&disp->lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
do_next_response(dns_dispatch_t *disp, dns_dispentry_t *resp)
|
||||||
|
{
|
||||||
|
dns_dispatchevent_t *ev;
|
||||||
|
|
||||||
|
INSIST(resp->item_out == ISC_FALSE);
|
||||||
|
|
||||||
|
ev = ISC_LIST_HEAD(resp->items);
|
||||||
|
if (ev == NULL) {
|
||||||
|
if (disp->shutting_down == 1)
|
||||||
|
do_cancel(disp, resp);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ISC_LIST_UNLINK(disp->rq_events, ev, link);
|
||||||
|
|
||||||
|
ev->action = resp->action;
|
||||||
|
ev->arg = resp->arg;
|
||||||
|
ev->sender = resp;
|
||||||
|
resp->item_out = ISC_TRUE;
|
||||||
|
ISC_TASK_SEND(resp->task, (isc_event_t **)&ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
do_next_request(dns_dispatch_t *disp, dns_dispentry_t *resp)
|
||||||
|
{
|
||||||
|
dns_dispatchevent_t *ev;
|
||||||
|
|
||||||
|
INSIST(resp->item_out == ISC_FALSE);
|
||||||
|
|
||||||
|
ev = ISC_LIST_HEAD(disp->rq_events);
|
||||||
|
if (ev == NULL) {
|
||||||
|
if (disp->shutting_down == 1)
|
||||||
|
do_cancel(disp, resp);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ISC_LIST_UNLINK(disp->rq_events, ev, link);
|
||||||
|
|
||||||
|
ev->action = resp->action;
|
||||||
|
ev->arg = resp->arg;
|
||||||
|
ev->sender = resp;
|
||||||
|
resp->item_out = ISC_TRUE;
|
||||||
|
ISC_TASK_SEND(resp->task, (isc_event_t **)&ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
do_cancel(dns_dispatch_t *disp, dns_dispentry_t *resp)
|
||||||
|
{
|
||||||
|
if (disp->shutdown_out == 1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If no target given, find the first request handler. If
|
||||||
|
* there are packets waiting for any handler, however, don't
|
||||||
|
* kill them.
|
||||||
|
*/
|
||||||
|
if (resp == NULL) {
|
||||||
|
resp = ISC_LIST_HEAD(disp->rq_handlers);
|
||||||
|
if (resp != NULL && resp->item_out == ISC_FALSE)
|
||||||
|
resp = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Search for the first responce handler without packets outstanding.
|
||||||
|
*/
|
||||||
|
if (resp == NULL) {
|
||||||
|
resp = linear_first(disp); /* no first item? */
|
||||||
|
if (resp == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
do {
|
||||||
|
if (resp->item_out == ISC_FALSE)
|
||||||
|
break;
|
||||||
|
|
||||||
|
resp = linear_next(disp, resp);
|
||||||
|
} while (resp != NULL);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* No one to send the cancel event to, so nothing to do.
|
||||||
|
*/
|
||||||
|
if (resp == NULL)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Send the shutdown failsafe event to this response critter IFF
|
||||||
|
* the queue is empty. If it is not empty, defer.
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
@ -67,17 +67,11 @@ struct dns_dispatchevent {
|
|||||||
dns_result_t result; /* result code */
|
dns_result_t result; /* result code */
|
||||||
isc_int16_t id; /* message id */
|
isc_int16_t id; /* message id */
|
||||||
isc_sockaddr_t addr; /* address recv'd from */
|
isc_sockaddr_t addr; /* address recv'd from */
|
||||||
unsigned int lattributes; /* some private, some public */
|
|
||||||
isc_buffer_t buffer; /* data buffer */
|
isc_buffer_t buffer; /* data buffer */
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct dns_dispentry dns_dispentry_t;
|
typedef struct dns_dispentry dns_dispentry_t;
|
||||||
|
|
||||||
/*
|
|
||||||
* Private attributes of events
|
|
||||||
*/
|
|
||||||
#define DNS_DISPATCHATTR_MPOOL 0x00010000 /* allocated via mpool */
|
|
||||||
|
|
||||||
dns_result_t
|
dns_result_t
|
||||||
dns_dispatch_create(isc_mem_t *mctx, isc_socket_t *sock, isc_task_t *task,
|
dns_dispatch_create(isc_mem_t *mctx, isc_socket_t *sock, isc_task_t *task,
|
||||||
unsigned int maxbuffersize,
|
unsigned int maxbuffersize,
|
||||||
@ -222,7 +216,8 @@ dns_dispatch_removerequest(dns_dispatch_t *disp, dns_dispentry_t **resp,
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
dns_dispatch_freeevent(dns_dispatch_t *disp, dns_dispatchevent_t **sockevent);
|
dns_dispatch_freeevent(dns_dispatch_t *disp, dns_dispentry_t *resp,
|
||||||
|
dns_dispatchevent_t **sockevent);
|
||||||
/*
|
/*
|
||||||
* Return a dispatchevent and associated buffer to the dispatch. This needs
|
* Return a dispatchevent and associated buffer to the dispatch. This needs
|
||||||
* to be called if more events are desired but a particular event is fully
|
* to be called if more events are desired but a particular event is fully
|
||||||
@ -242,12 +237,30 @@ void
|
|||||||
dns_dispatch_attach(dns_dispatch_t *disp, dns_dispatch_t **dispp);
|
dns_dispatch_attach(dns_dispatch_t *disp, dns_dispatch_t **dispp);
|
||||||
/*
|
/*
|
||||||
* Attach to a dispatch handle.
|
* Attach to a dispatch handle.
|
||||||
|
*
|
||||||
|
* Requires:
|
||||||
|
* < mumble >
|
||||||
|
*
|
||||||
|
* Ensures:
|
||||||
|
* < mumble >
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* < mumble >
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
dns_dispatch_detach(dns_dispatch_t **dispp);
|
dns_dispatch_detach(dns_dispatch_t **dispp);
|
||||||
/*
|
/*
|
||||||
* Detach from a dispatch handle.
|
* Detach from a dispatch handle.
|
||||||
|
*
|
||||||
|
* Requires:
|
||||||
|
* < mumble >
|
||||||
|
*
|
||||||
|
* Ensures:
|
||||||
|
* < mumble >
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* < mumble >
|
||||||
*/
|
*/
|
||||||
|
|
||||||
ISC_LANG_ENDDECLS
|
ISC_LANG_ENDDECLS
|
||||||
|
Loading…
x
Reference in New Issue
Block a user