* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: dispatch.c,v 1.116.18.33 2008/08/05 19:19:58 jinmei Exp $ */
+/* $Id: dispatch.c,v 1.116.18.34 2008/08/15 17:32:55 jinmei Exp $ */
/*! \file */
typedef ISC_LIST(dns_dispentry_t) dns_displist_t;
+typedef struct dispsocket dispsocket_t;
+typedef ISC_LIST(dispsocket_t) dispsocketlist_t;
+
/* ARC4 Random generator state */
typedef struct arc4ctx {
isc_uint8_t i;
unsigned int qid_increment; /*%< id increment on collision */
isc_mutex_t lock;
dns_displist_t *qid_table; /*%< the table itself */
- dns_displist_t *addr_table; /*%< address/port table */
+ dispsocketlist_t *sock_table; /*%< socket table */
} dns_qid_t;
struct dns_dispatchmgr {
#define IS_PRIVATE(d) (((d)->attributes & DNS_DISPATCHATTR_PRIVATE) != 0)
-typedef struct dispsocket dispsocket_t;
-
struct dns_dispentry {
unsigned int magic;
dns_dispatch_t *disp;
dns_messageid_t id;
in_port_t port;
unsigned int bucket;
- unsigned int abucket;
isc_sockaddr_t host;
isc_task_t *task;
isc_taskaction_t action;
dispsocket_t *dispsocket;
ISC_LIST(dns_dispatchevent_t) items;
ISC_LINK(dns_dispentry_t) link;
- ISC_LINK(dns_dispentry_t) alink;
};
/*%
unsigned int magic;
isc_socket_t *socket;
dns_dispatch_t *disp;
+ isc_sockaddr_t host;
+ in_port_t localport;
dns_dispentry_t *resp;
isc_task_t *task;
ISC_LINK(dispsocket_t) link;
+ unsigned int bucket;
+ ISC_LINK(dispsocket_t) blink;
};
#define INVALID_BUCKET (0xffffdead)
/*
* Statics.
*/
-static dns_dispentry_t *bucket_search(dns_qid_t *, dns_displist_t *,
- isc_sockaddr_t *, dns_messageid_t,
- in_port_t, unsigned int, isc_boolean_t);
+static dns_dispentry_t *entry_search(dns_qid_t *, isc_sockaddr_t *,
+ dns_messageid_t, in_port_t, unsigned int);
static isc_boolean_t destroy_disp_ok(dns_dispatch_t *);
static void destroy_disp(isc_task_t *task, isc_event_t *event);
static void destroy_dispsocket(dns_dispatch_t *, dispsocket_t **);
destroy_mgr(&mgr);
}
+/*%
+ * Find a dispsocket for socket address 'dest', and port number 'port'.
+ * Return NULL if no such entry exists.
+ */
+static dispsocket_t *
+socket_search(dns_qid_t *qid, isc_sockaddr_t *dest, in_port_t port,
+ unsigned int bucket)
+{
+ dispsocket_t *dispsock;
+
+ REQUIRE(bucket < qid->qid_nbuckets);
+
+ dispsock = ISC_LIST_HEAD(qid->sock_table[bucket]);
+
+ while (dispsock != NULL) {
+ if (isc_sockaddr_equal(dest, &dispsock->host) &&
+ dispsock->localport == port)
+ return (dispsock);
+ dispsock = ISC_LIST_NEXT(dispsock, blink);
+ }
+
+ return (NULL);
+}
+
/*%
* Make a new socket for a single dispatch with a random port number.
* The caller must hold the disp->lock and qid->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, unsigned int *abucketp,
- in_port_t *portp)
+ dispsocket_t **dispsockp, in_port_t *portp)
{
int i;
isc_uint32_t r;
isc_result_t result = ISC_R_FAILURE;
in_port_t port;
isc_sockaddr_t localaddr;
- unsigned int abucket = 0;
+ unsigned int bucket = 0;
dispsocket_t *dispsock;
unsigned int nports;
in_port_t *ports;
dispsock->task = NULL;
isc_task_attach(disp->task[r % disp->ntasks], &dispsock->task);
ISC_LINK_INIT(dispsock, link);
+ ISC_LINK_INIT(dispsock, blink);
dispsock->magic = DISPSOCK_MAGIC;
}
nports)];
isc_sockaddr_setport(&localaddr, port);
- abucket = dns_hash(qid, dest, 0, port);
- if (bucket_search(qid, qid->addr_table, dest, 0, port, abucket,
- ISC_TRUE) != NULL) {
+ bucket = dns_hash(qid, dest, 0, port);
+ if (socket_search(qid, dest, port, bucket) != NULL)
continue;
- }
result = open_socket(sockmgr, &localaddr, 0, &sock);
if (result == ISC_R_SUCCESS || result != ISC_R_ADDRINUSE)
if (result == ISC_R_SUCCESS) {
dispsock->socket = sock;
+ dispsock->host = *dest;
+ dispsock->localport = port;
+ dispsock->bucket = bucket;
+ ISC_LIST_APPEND(qid->sock_table[bucket], dispsock, blink);
*dispsockp = dispsock;
- *abucketp = abucket;
*portp = port;
} else {
/*
static void
destroy_dispsocket(dns_dispatch_t *disp, dispsocket_t **dispsockp) {
dispsocket_t *dispsock;
+ dns_qid_t *qid;
/*
* The dispatch must be locked.
dispsock->magic = 0;
if (dispsock->socket != NULL)
isc_socket_detach(&dispsock->socket);
+ if (ISC_LINK_LINKED(dispsock, blink)) {
+ qid = DNS_QID(disp);
+ LOCK(&qid->lock);
+ ISC_LIST_UNLINK(qid->sock_table[dispsock->bucket], dispsock,
+ blink);
+ UNLOCK(&qid->lock);
+ }
if (dispsock->task != NULL)
isc_task_detach(&dispsock->task);
isc_mempool_put(disp->mgr->spool, dispsock);
static void
deactivate_dispsocket(dns_dispatch_t *disp, dispsocket_t *dispsock) {
isc_result_t result;
+ dns_qid_t *qid;
/*
* The dispatch must be locked.
destroy_dispsocket(disp, &dispsock);
else {
result = isc_socket_close(dispsock->socket);
+
+ qid = DNS_QID(disp);
+ LOCK(&qid->lock);
+ ISC_LIST_UNLINK(qid->sock_table[dispsock->bucket], dispsock,
+ blink);
+ UNLOCK(&qid->lock);
+
if (result == ISC_R_SUCCESS)
ISC_LIST_APPEND(disp->inactivesockets, dispsock, link);
else {
/*
* Find an entry for query ID 'id', socket address 'dest', and port number
- * 'port' in 'table'.
+ * 'port'.
* Return NULL if no such entry exists.
*/
static dns_dispentry_t *
-bucket_search(dns_qid_t *qid, dns_displist_t *table, isc_sockaddr_t *dest,
- dns_messageid_t id, in_port_t port, unsigned int bucket,
- isc_boolean_t ignoreid)
+entry_search(dns_qid_t *qid, isc_sockaddr_t *dest, dns_messageid_t id,
+ in_port_t port, unsigned int bucket)
{
dns_dispentry_t *res;
REQUIRE(bucket < qid->qid_nbuckets);
- res = ISC_LIST_HEAD(table[bucket]);
+ res = ISC_LIST_HEAD(qid->qid_table[bucket]);
while (res != NULL) {
- if ((ignoreid || res->id == id) &&
- isc_sockaddr_equal(dest, &res->host) &&
+ if (res->id == id && isc_sockaddr_equal(dest, &res->host) &&
res->port == port) {
return (res);
}
bucket = dns_hash(qid, &ev->address, id, disp->localport);
LOCK(&qid->lock);
qidlocked = ISC_TRUE;
- resp = bucket_search(qid, qid->qid_table, &ev->address, id,
- disp->localport, bucket, ISC_FALSE);
+ resp = entry_search(qid, &ev->address, id, disp->localport,
+ bucket);
dispatch_log(disp, LVL(90),
"search for response in bucket %d: %s",
bucket, (resp == NULL ? "not found" : "found"));
*/
bucket = dns_hash(qid, &tcpmsg->address, id, disp->localport);
LOCK(&qid->lock);
- resp = bucket_search(qid, qid->qid_table, &tcpmsg->address, id,
- disp->localport, bucket, ISC_FALSE);
+ resp = entry_search(qid, &tcpmsg->address, id, disp->localport, bucket);
dispatch_log(disp, LVL(90),
"search for response in bucket %d: %s",
bucket, (resp == NULL ? "not found" : "found"));
static isc_result_t
qid_allocate(dns_dispatchmgr_t *mgr, unsigned int buckets,
unsigned int increment, dns_qid_t **qidp,
- isc_boolean_t needaddrtable)
+ isc_boolean_t needsocktable)
{
dns_qid_t *qid;
unsigned int i;
return (ISC_R_NOMEMORY);
}
- qid->addr_table = NULL;
- if (needaddrtable) {
- qid->addr_table = isc_mem_get(mgr->mctx,
- buckets * sizeof(dns_displist_t));
- if (qid->addr_table == NULL) {
+ qid->sock_table = NULL;
+ if (needsocktable) {
+ qid->sock_table = isc_mem_get(mgr->mctx, buckets *
+ sizeof(dispsocketlist_t));
+ if (qid->sock_table == NULL) {
isc_mem_put(mgr->mctx, qid, sizeof(*qid));
isc_mem_put(mgr->mctx, qid->qid_table,
buckets * sizeof(dns_displist_t));
result = isc_mutex_init(&qid->lock);
if (result != ISC_R_SUCCESS) {
- if (qid->addr_table != NULL) {
- isc_mem_put(mgr->mctx, qid->addr_table,
+ if (qid->sock_table != NULL) {
+ isc_mem_put(mgr->mctx, qid->sock_table,
buckets * sizeof(dns_displist_t));
}
isc_mem_put(mgr->mctx, qid->qid_table,
for (i = 0; i < buckets; i++) {
ISC_LIST_INIT(qid->qid_table[i]);
- if (qid->addr_table != NULL)
- ISC_LIST_INIT(qid->addr_table[i]);
+ if (qid->sock_table != NULL)
+ ISC_LIST_INIT(qid->sock_table[i]);
}
qid->qid_nbuckets = buckets;
qid->magic = 0;
isc_mem_put(mctx, qid->qid_table,
qid->qid_nbuckets * sizeof(dns_displist_t));
- if (qid->addr_table != NULL) {
- isc_mem_put(mctx, qid->addr_table,
+ if (qid->sock_table != NULL) {
+ isc_mem_put(mctx, qid->sock_table,
qid->qid_nbuckets * sizeof(dns_displist_t));
}
DESTROYLOCK(&qid->lock);
{
dns_dispentry_t *res;
unsigned int bucket;
- unsigned int abucket;
in_port_t localport = 0;
dns_messageid_t id;
int i;
* Get a separate UDP socket with a random port number.
*/
result = get_dispsocket(disp, dest, sockmgr, qid, &dispsocket,
- &abucket, &localport);
+ &localport);
if (result != ISC_R_SUCCESS) {
UNLOCK(&qid->lock);
UNLOCK(&disp->lock);
return (result);
}
} else {
- abucket = 0; /* meaningless, but set explicitly */
localport = disp->localport;
}
bucket = dns_hash(qid, dest, id, localport);
ok = ISC_FALSE;
for (i = 0; i < 64; i++) {
- if (bucket_search(qid, qid->qid_table, dest, id, localport,
- bucket, ISC_FALSE) == NULL) {
+ if (entry_search(qid, dest, id, localport, bucket) == NULL) {
ok = ISC_TRUE;
break;
}
res->id = id;
res->port = localport;
res->bucket = bucket;
- res->abucket = abucket;
res->host = *dest;
res->action = action;
res->arg = arg;
res->item_out = ISC_FALSE;
ISC_LIST_INIT(res->items);
ISC_LINK_INIT(res, link);
- ISC_LINK_INIT(res, alink);
res->magic = RESPONSE_MAGIC;
ISC_LIST_APPEND(qid->qid_table[bucket], res, link);
- if (dispsocket != NULL)
- ISC_LIST_APPEND(qid->addr_table[abucket], res, alink);
UNLOCK(&qid->lock);
request_log(disp, res, LVL(90),
if (result != ISC_R_SUCCESS) {
LOCK(&qid->lock);
ISC_LIST_UNLINK(qid->qid_table[bucket], res, link);
- if (ISC_LINK_LINKED(res, alink)) {
- ISC_LIST_UNLINK(qid->addr_table[abucket], res,
- alink);
- }
UNLOCK(&qid->lock);
if (dispsocket != NULL)
LOCK(&qid->lock);
ISC_LIST_UNLINK(qid->qid_table[bucket], res, link);
- if (ISC_LINK_LINKED(res, alink))
- ISC_LIST_UNLINK(qid->addr_table[res->abucket], res, alink);
UNLOCK(&qid->lock);
if (ev == NULL && res->item_out) {