#include <isc/portset.h>
#include <isc/print.h>
#include <isc/random.h>
+#include <isc/socket.h>
#include <isc/stats.h>
#include <isc/string.h>
#include <isc/task.h>
unsigned int maxbuffers; /*%< max buffers */
/* Locked internally. */
- isc_mutex_t pool_lock;
- isc_mempool_t *epool; /*%< memory pool for events */
- isc_mempool_t *rpool; /*%< memory pool for replies */
+ isc_mutex_t depool_lock;
+ isc_mempool_t *depool; /*%< pool for dispatch events */
+ isc_mutex_t rpool_lock;
+ isc_mempool_t *rpool; /*%< pool for replies */
+ isc_mutex_t dpool_lock;
isc_mempool_t *dpool; /*%< dispatch allocations */
- isc_mempool_t *bpool; /*%< memory pool for buffers */
- isc_mempool_t *spool; /*%< memory pool for dispsocs */
+ isc_mutex_t bpool_lock;
+ isc_mempool_t *bpool; /*%< pool for buffers */
+ isc_mutex_t spool_lock;
+ isc_mempool_t *spool; /*%< pool for dispsocks */
/*%
* Locked by qid->lock if qid exists; otherwise, can be used without
unsigned int maxrequests; /*%< max requests */
isc_event_t *ctlevent;
+ isc_mutex_t sepool_lock;
+ isc_mempool_t *sepool; /*%< pool for socket events */
+
/*% Locked by mgr->lock. */
ISC_LINK(dns_dispatch_t) link;
in_port_t);
static void free_buffer(dns_dispatch_t *disp, void *buf, unsigned int len);
static void *allocate_udp_buffer(dns_dispatch_t *disp);
-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 void free_devent(dns_dispatch_t *disp, dns_dispatchevent_t *ev);
+static inline dns_dispatchevent_t *allocate_devent(dns_dispatch_t *disp);
static void do_cancel(dns_dispatch_t *disp);
static dns_dispentry_t *linear_first(dns_qid_t *disp);
static dns_dispentry_t *linear_next(dns_qid_t *disp,
"shutting down; detaching from sock %p, task %p",
disp->socket, disp->task[0]); /* XXXX */
+ if (disp->sepool != NULL) {
+ isc_mempool_destroy(&disp->sepool);
+ isc_mutex_destroy(&disp->sepool_lock);
+ }
+
if (disp->socket != NULL)
isc_socket_detach(&disp->socket);
while ((dispsocket = ISC_LIST_HEAD(disp->inactivesockets)) != NULL) {
static void
deref_portentry(dns_dispatch_t *disp, dispportentry_t **portentryp) {
dispportentry_t *portentry = *portentryp;
+ isc_boolean_t unlink = ISC_FALSE;
dns_qid_t *qid;
REQUIRE(disp->port_table != NULL);
qid = DNS_QID(disp);
LOCK(&qid->lock);
portentry->refs--;
- if (portentry->refs == 0) {
+ unlink = ISC_TF(portentry->refs == 0);
+ UNLOCK(&qid->lock);
+
+ if (unlink) {
ISC_LIST_UNLINK(disp->port_table[portentry->port %
DNS_DISPATCH_PORTTABLESIZE],
portentry, link);
}
*portentryp = NULL;
- UNLOCK(&qid->lock);
}
/*%
/*%
* Make a new socket for a single dispatch with a random port number.
- * The caller must hold the disp->lock and qid->lock.
+ * The caller must hold the disp->lock
*/
static isc_result_t
get_dispsocket(dns_dispatch_t *disp, isc_sockaddr_t *dest,
- isc_socketmgr_t *sockmgr, dns_qid_t *qid,
- dispsocket_t **dispsockp, in_port_t *portp)
+ isc_socketmgr_t *sockmgr, dispsocket_t **dispsockp,
+ in_port_t *portp)
{
int i;
isc_uint32_t r;
in_port_t *ports;
unsigned int bindoptions;
dispportentry_t *portentry = NULL;
+ dns_qid_t *qid;
if (isc_sockaddr_pf(&disp->local) == AF_INET) {
nports = disp->mgr->nv4ports;
* very likely to fail in bind(2) or connect(2).
*/
localaddr = disp->local;
+ qid = DNS_QID(disp);
+
for (i = 0; i < 64; i++) {
port = ports[dispatch_uniformrandom(DISP_ARC4CTX(disp),
nports)];
isc_sockaddr_setport(&localaddr, port);
+ LOCK(&qid->lock);
bucket = dns_hash(qid, dest, 0, port);
- if (socket_search(qid, dest, port, bucket) != NULL)
+ if (socket_search(qid, dest, port, bucket) != NULL) {
+ UNLOCK(&qid->lock);
continue;
+ }
+ UNLOCK(&qid->lock);
bindoptions = 0;
portentry = port_search(disp, port);
+
if (portentry != NULL)
bindoptions |= ISC_SOCKET_REUSEADDRESS;
result = open_socket(sockmgr, &localaddr, bindoptions, &sock,
dispsock->host = *dest;
dispsock->portentry = portentry;
dispsock->bucket = bucket;
+ LOCK(&qid->lock);
ISC_LIST_APPEND(qid->sock_table[bucket], dispsock, blink);
+ UNLOCK(&qid->lock);
*dispsockp = dispsock;
*portp = port;
} else {
static void
free_buffer(dns_dispatch_t *disp, void *buf, unsigned int len) {
+ isc_mempool_t *bpool;
INSIST(buf != NULL && len != 0);
INSIST(disp->mgr->buffers > 0);
INSIST(len == disp->mgr->buffersize);
disp->mgr->buffers--;
- isc_mempool_put(disp->mgr->bpool, buf);
+ bpool = disp->mgr->bpool;
UNLOCK(&disp->mgr->buffer_lock);
+ isc_mempool_put(bpool, buf);
break;
default:
INSIST(0);
static void *
allocate_udp_buffer(dns_dispatch_t *disp) {
+ isc_mempool_t *bpool;
void *temp;
LOCK(&disp->mgr->buffer_lock);
- temp = isc_mempool_get(disp->mgr->bpool);
-
- if (temp != NULL)
- disp->mgr->buffers++;
+ bpool = disp->mgr->bpool;
+ disp->mgr->buffers++;
UNLOCK(&disp->mgr->buffer_lock);
+ temp = isc_mempool_get(bpool);
+
+ if (temp == NULL) {
+ LOCK(&disp->mgr->buffer_lock);
+ disp->mgr->buffers--;
+ UNLOCK(&disp->mgr->buffer_lock);
+ }
+
return (temp);
}
static inline void
-free_event(dns_dispatch_t *disp, dns_dispatchevent_t *ev) {
+free_sevent(isc_event_t *ev) {
+ isc_mempool_t *pool = ev->ev_destroy_arg;
+ isc_socketevent_t *sev = (isc_socketevent_t *) ev;
+ isc_mempool_put(pool, sev);
+}
+
+static inline isc_socketevent_t *
+allocate_sevent(dns_dispatch_t *disp, isc_socket_t *socket,
+ isc_eventtype_t type, isc_taskaction_t action, const void *arg)
+{
+ isc_socketevent_t *ev;
+ void *deconst_arg;
+
+ ev = isc_mempool_get(disp->sepool);
+ if (ev == NULL)
+ return (NULL);
+ DE_CONST(arg, deconst_arg);
+ ISC_EVENT_INIT(ev, sizeof(*ev), 0, NULL, type,
+ action, deconst_arg, socket,
+ free_sevent, disp->sepool);
+ ev->result = ISC_R_UNSET;
+ ISC_LINK_INIT(ev, ev_link);
+ ISC_LIST_INIT(ev->bufferlist);
+ ev->region.base = NULL;
+ ev->n = 0;
+ ev->offset = 0;
+ ev->attributes = 0;
+
+ return (ev);
+}
+
+
+static inline void
+free_devent(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->mgr->epool, ev);
+ isc_mempool_put(disp->mgr->depool, ev);
}
static inline dns_dispatchevent_t *
-allocate_event(dns_dispatch_t *disp) {
+allocate_devent(dns_dispatch_t *disp) {
dns_dispatchevent_t *ev;
- ev = isc_mempool_get(disp->mgr->epool);
+ ev = isc_mempool_get(disp->mgr->depool);
if (ev == NULL)
return (NULL);
ISC_EVENT_INIT(ev, sizeof(*ev), 0, NULL, 0,
sendresponse:
queue_response = resp->item_out;
- rev = allocate_event(resp->disp);
+ rev = allocate_devent(resp->disp);
if (rev == NULL) {
free_buffer(disp, ev->region.base, ev->region.length);
goto unlock;
if (resp == NULL)
goto unlock;
queue_response = resp->item_out;
- rev = allocate_event(disp);
+ rev = allocate_devent(disp);
if (rev == NULL)
goto unlock;
if (region.base == NULL)
return (ISC_R_NOMEMORY);
if (dispsock != NULL) {
- res = isc_socket_recv(socket, ®ion, 1,
- dispsock->task, udp_exrecv,
- dispsock);
+ isc_task_t *dt = dispsock->task;
+ isc_socketevent_t *sev =
+ allocate_sevent(disp, socket,
+ ISC_SOCKEVENT_RECVDONE,
+ udp_exrecv, dispsock);
+ if (sev == NULL) {
+ free_buffer(disp, region.base, region.length);
+ return (ISC_R_NOMEMORY);
+ }
+
+ res = isc_socket_recv2(socket, ®ion, 1, dt, sev, 0);
if (res != ISC_R_SUCCESS) {
free_buffer(disp, region.base, region.length);
return (res);
}
} else {
- res = isc_socket_recv(socket, ®ion, 1,
- disp->task[0], udp_shrecv, disp);
+ isc_task_t *dt = disp->task[0];
+ isc_socketevent_t *sev =
+ allocate_sevent(disp, socket,
+ ISC_SOCKEVENT_RECVDONE,
+ udp_shrecv, disp);
+ if (sev == NULL) {
+ free_buffer(disp, region.base, region.length);
+ return (ISC_R_NOMEMORY);
+ }
+
+ res = isc_socket_recv2(socket, ®ion, 1, dt, sev, 0);
if (res != ISC_R_SUCCESS) {
free_buffer(disp, region.base, region.length);
disp->shutdown_why = res;
destroy_mgr_ok(dns_dispatchmgr_t *mgr) {
mgr_log(mgr, LVL(90),
"destroy_mgr_ok: shuttingdown=%d, listnonempty=%d, "
- "epool=%d, rpool=%d, dpool=%d",
+ "depool=%d, rpool=%d, dpool=%d",
MGR_IS_SHUTTINGDOWN(mgr), !ISC_LIST_EMPTY(mgr->list),
- isc_mempool_getallocated(mgr->epool),
+ isc_mempool_getallocated(mgr->depool),
isc_mempool_getallocated(mgr->rpool),
isc_mempool_getallocated(mgr->dpool));
if (!MGR_IS_SHUTTINGDOWN(mgr))
return (ISC_FALSE);
if (!ISC_LIST_EMPTY(mgr->list))
return (ISC_FALSE);
- if (isc_mempool_getallocated(mgr->epool) != 0)
+ if (isc_mempool_getallocated(mgr->depool) != 0)
return (ISC_FALSE);
if (isc_mempool_getallocated(mgr->rpool) != 0)
return (ISC_FALSE);
DESTROYLOCK(&mgr->arc4_lock);
- isc_mempool_destroy(&mgr->epool);
+ isc_mempool_destroy(&mgr->depool);
isc_mempool_destroy(&mgr->rpool);
isc_mempool_destroy(&mgr->dpool);
if (mgr->bpool != NULL)
if (mgr->spool != NULL)
isc_mempool_destroy(&mgr->spool);
- DESTROYLOCK(&mgr->pool_lock);
+ DESTROYLOCK(&mgr->spool_lock);
+ DESTROYLOCK(&mgr->bpool_lock);
+ DESTROYLOCK(&mgr->dpool_lock);
+ DESTROYLOCK(&mgr->rpool_lock);
+ DESTROYLOCK(&mgr->depool_lock);
#ifdef BIND9
if (mgr->entropy != NULL)
if (result != ISC_R_SUCCESS)
goto kill_arc4_lock;
- result = isc_mutex_init(&mgr->pool_lock);
+ result = isc_mutex_init(&mgr->depool_lock);
if (result != ISC_R_SUCCESS)
goto kill_buffer_lock;
- mgr->epool = NULL;
+ result = isc_mutex_init(&mgr->rpool_lock);
+ if (result != ISC_R_SUCCESS)
+ goto kill_depool_lock;
+
+ result = isc_mutex_init(&mgr->dpool_lock);
+ if (result != ISC_R_SUCCESS)
+ goto kill_rpool_lock;
+
+ result = isc_mutex_init(&mgr->bpool_lock);
+ if (result != ISC_R_SUCCESS)
+ goto kill_dpool_lock;
+
+ result = isc_mutex_init(&mgr->spool_lock);
+ if (result != ISC_R_SUCCESS)
+ goto kill_bpool_lock;
+
+ mgr->depool = NULL;
if (isc_mempool_create(mgr->mctx, sizeof(dns_dispatchevent_t),
- &mgr->epool) != ISC_R_SUCCESS) {
+ &mgr->depool) != ISC_R_SUCCESS) {
result = ISC_R_NOMEMORY;
- goto kill_pool_lock;
+ goto kill_spool_lock;
}
mgr->rpool = NULL;
if (isc_mempool_create(mgr->mctx, sizeof(dns_dispentry_t),
&mgr->rpool) != ISC_R_SUCCESS) {
result = ISC_R_NOMEMORY;
- goto kill_epool;
+ goto kill_depool;
}
mgr->dpool = NULL;
goto kill_rpool;
}
- isc_mempool_setname(mgr->epool, "dispmgr_epool");
- isc_mempool_setfreemax(mgr->epool, 1024);
- isc_mempool_associatelock(mgr->epool, &mgr->pool_lock);
+ isc_mempool_setname(mgr->depool, "dispmgr_depool");
+ isc_mempool_setmaxalloc(mgr->depool, 32768);
+ isc_mempool_setfreemax(mgr->depool, 32768);
+ isc_mempool_associatelock(mgr->depool, &mgr->depool_lock);
+ isc_mempool_setfillcount(mgr->depool, 32);
isc_mempool_setname(mgr->rpool, "dispmgr_rpool");
- isc_mempool_setfreemax(mgr->rpool, 1024);
- isc_mempool_associatelock(mgr->rpool, &mgr->pool_lock);
+ isc_mempool_setmaxalloc(mgr->rpool, 32768);
+ isc_mempool_setfreemax(mgr->rpool, 32768);
+ isc_mempool_associatelock(mgr->rpool, &mgr->rpool_lock);
+ isc_mempool_setfillcount(mgr->rpool, 32);
isc_mempool_setname(mgr->dpool, "dispmgr_dpool");
- isc_mempool_setfreemax(mgr->dpool, 1024);
- isc_mempool_associatelock(mgr->dpool, &mgr->pool_lock);
+ isc_mempool_setmaxalloc(mgr->dpool, 32768);
+ isc_mempool_setfreemax(mgr->dpool, 32768);
+ isc_mempool_associatelock(mgr->dpool, &mgr->dpool_lock);
+ isc_mempool_setfillcount(mgr->dpool, 32);
mgr->buffers = 0;
mgr->buffersize = 0;
isc_mempool_destroy(&mgr->dpool);
kill_rpool:
isc_mempool_destroy(&mgr->rpool);
- kill_epool:
- isc_mempool_destroy(&mgr->epool);
- kill_pool_lock:
- DESTROYLOCK(&mgr->pool_lock);
+ kill_depool:
+ isc_mempool_destroy(&mgr->depool);
+ kill_spool_lock:
+ DESTROYLOCK(&mgr->spool_lock);
+ kill_bpool_lock:
+ DESTROYLOCK(&mgr->bpool_lock);
+ kill_dpool_lock:
+ DESTROYLOCK(&mgr->dpool_lock);
+ kill_rpool_lock:
+ DESTROYLOCK(&mgr->rpool_lock);
+ kill_depool_lock:
+ DESTROYLOCK(&mgr->depool_lock);
kill_buffer_lock:
DESTROYLOCK(&mgr->buffer_lock);
kill_arc4_lock:
*/
if (maxbuffers > mgr->maxbuffers) {
isc_mempool_setmaxalloc(mgr->bpool, maxbuffers);
+ isc_mempool_setfreemax(mgr->bpool, maxbuffers);
mgr->maxbuffers = maxbuffers;
}
} else {
}
isc_mempool_setname(mgr->bpool, "dispmgr_bpool");
isc_mempool_setmaxalloc(mgr->bpool, maxbuffers);
- isc_mempool_associatelock(mgr->bpool, &mgr->pool_lock);
+ isc_mempool_setfreemax(mgr->bpool, maxbuffers);
+ isc_mempool_associatelock(mgr->bpool, &mgr->bpool_lock);
+ isc_mempool_setfillcount(mgr->bpool, 32);
}
/* Create or adjust socket pool */
if (mgr->spool != NULL) {
- isc_mempool_setmaxalloc(mgr->spool, DNS_DISPATCH_POOLSOCKS * 2);
+ if (maxrequests < DNS_DISPATCH_POOLSOCKS * 2)
+ isc_mempool_setmaxalloc(mgr->spool,
+ DNS_DISPATCH_POOLSOCKS * 2);
+ isc_mempool_setfreemax(mgr->spool,
+ DNS_DISPATCH_POOLSOCKS * 2);
UNLOCK(&mgr->buffer_lock);
return (ISC_R_SUCCESS);
}
}
isc_mempool_setname(mgr->spool, "dispmgr_spool");
isc_mempool_setmaxalloc(mgr->spool, maxrequests);
- isc_mempool_associatelock(mgr->spool, &mgr->pool_lock);
+ isc_mempool_setfreemax(mgr->spool, maxrequests);
+ isc_mempool_associatelock(mgr->spool, &mgr->spool_lock);
+ isc_mempool_setfillcount(mgr->spool, 32);
result = qid_allocate(mgr, buckets, increment, &mgr->qid, ISC_TRUE);
if (result != ISC_R_SUCCESS)
if (result != ISC_R_SUCCESS)
goto deallocate;
- disp->failsafe_ev = allocate_event(disp);
+ disp->failsafe_ev = allocate_devent(disp);
if (disp->failsafe_ev == NULL) {
result = ISC_R_NOMEMORY;
goto kill_lock;
INSIST(ISC_LIST_EMPTY(disp->activesockets));
INSIST(ISC_LIST_EMPTY(disp->inactivesockets));
- isc_mempool_put(mgr->epool, disp->failsafe_ev);
+ isc_mempool_put(mgr->depool, disp->failsafe_ev);
disp->failsafe_ev = NULL;
if (disp->qid != NULL)
disp->socket = NULL;
isc_socket_attach(sock, &disp->socket);
+ disp->sepool = NULL;
+
disp->ntasks = 1;
disp->task[0] = NULL;
result = isc_task_create(taskmgr, 0, &disp->task[0]);
goto kill_task;
}
+ disp->sepool = NULL;
+ if (isc_mempool_create(mgr->mctx, sizeof(isc_socketevent_t),
+ &disp->sepool) != ISC_R_SUCCESS)
+ {
+ result = ISC_R_NOMEMORY;
+ goto kill_ctlevent;
+ }
+
+ result = isc_mutex_init(&disp->sepool_lock);
+ if (result != ISC_R_SUCCESS)
+ goto kill_sepool;
+
+ isc_mempool_setname(disp->sepool, "disp_sepool");
+ isc_mempool_setmaxalloc(disp->sepool, 32768);
+ isc_mempool_setfreemax(disp->sepool, 32768);
+ isc_mempool_associatelock(disp->sepool, &disp->sepool_lock);
+ isc_mempool_setfillcount(disp->sepool, 16);
+
attributes &= ~DNS_DISPATCHATTR_TCP;
attributes |= DNS_DISPATCHATTR_UDP;
disp->attributes = attributes;
/*
* Error returns.
*/
+ kill_sepool:
+ isc_mempool_destroy(&disp->sepool);
+ kill_ctlevent:
+ isc_event_free(&disp->ctlevent);
kill_task:
for (i = 0; i < disp->ntasks; i++)
isc_task_detach(&disp->task[i]);
oldestsocket = ISC_LIST_HEAD(disp->activesockets);
oldestresp = oldestsocket->resp;
if (oldestresp != NULL && !oldestresp->item_out) {
- rev = allocate_event(oldestresp->disp);
+ rev = allocate_devent(oldestresp->disp);
if (rev != NULL) {
rev->buffer.base = NULL;
rev->result = ISC_R_CANCELED;
}
qid = DNS_QID(disp);
- LOCK(&qid->lock);
if ((disp->attributes & DNS_DISPATCHATTR_EXCLUSIVE) != 0) {
/*
* Get a separate UDP socket with a random port number.
*/
- result = get_dispsocket(disp, dest, sockmgr, qid, &dispsocket,
+ result = get_dispsocket(disp, dest, sockmgr, &dispsocket,
&localport);
if (result != ISC_R_SUCCESS) {
- UNLOCK(&qid->lock);
UNLOCK(&disp->lock);
inc_stats(disp->mgr, dns_resstatscounter_dispsockfail);
return (result);
/*
* Try somewhat hard to find an unique ID.
*/
+ LOCK(&qid->lock);
id = (dns_messageid_t)dispatch_random(DISP_ARC4CTX(disp));
bucket = dns_hash(qid, dest, id, localport);
ok = ISC_FALSE;
id &= 0x0000ffff;
bucket = dns_hash(qid, dest, id, localport);
}
+ UNLOCK(&qid->lock);
if (!ok) {
- UNLOCK(&qid->lock);
UNLOCK(&disp->lock);
return (ISC_R_NOMORE);
}
res = isc_mempool_get(disp->mgr->rpool);
if (res == NULL) {
- UNLOCK(&qid->lock);
UNLOCK(&disp->lock);
if (dispsocket != NULL)
destroy_dispsocket(disp, &dispsocket);
ISC_LIST_INIT(res->items);
ISC_LINK_INIT(res, link);
res->magic = RESPONSE_MAGIC;
+
+ LOCK(&qid->lock);
ISC_LIST_APPEND(qid->qid_table[bucket], res, link);
UNLOCK(&qid->lock);
res->item_out = ISC_FALSE;
if (ev->buffer.base != NULL)
free_buffer(disp, ev->buffer.base, ev->buffer.length);
- free_event(disp, ev);
+ free_devent(disp, ev);
}
request_log(disp, res, LVL(90), "detaching from task %p", res->task);
ISC_LIST_UNLINK(res->items, ev, ev_link);
if (ev->buffer.base != NULL)
free_buffer(disp, ev->buffer.base, ev->buffer.length);
- free_event(disp, ev);
+ free_devent(disp, ev);
ev = ISC_LIST_HEAD(res->items);
}
res->magic = 0;