diff --git a/bin/named/server.c b/bin/named/server.c index 94864342c3..b1242d75bc 100644 --- a/bin/named/server.c +++ b/bin/named/server.c @@ -51,6 +51,46 @@ isc_mem_t *mctx = NULL; +/* + * Process the wire format message given in r, and return a new packet to + * transmit. + * + * Return of DNS_R_SUCCESS means r->base is a newly allocated region of + * memory, and r->length is its length. The actual for-transmit packet + * begins at (r->length + reslen) to reserve (reslen) bytes at the front + * of the packet for transmission specific details. + */ +static dns_result_t +dispatch(isc_mem_t *mctx, isc_region_t *rxr, unsigned int reslen) +{ + isc_region_t txr; + unsigned char *cp; + + /* + * XXX for now, just SERVFAIL everything. + */ + txr.length = rxr->length + reslen; + txr.base = isc_mem_get(mctx, txr.length); + if (txr.base == NULL) + return (DNS_R_NOMEMORY); + + memcpy(txr.base + reslen, rxr->base, rxr->length); + + cp = txr.base + reslen; + cp += 2; + *cp |= 0x80; /* set QR to response */ + *cp++ &= 0xf9; /* clear AA, TC */ + *cp++ = 2; /* SERVFAIL */ + + rxr->base = txr.base; + rxr->length = txr.length; + + isc_mem_stats(mctx, stdout); + + return (DNS_R_SUCCESS); +} + + int main(int argc, char *argv[]) { @@ -95,8 +135,9 @@ main(int argc, char *argv[]) (int)addrlen) == ISC_R_SUCCESS); ludp = udp_listener_allocate(mctx, workers); - RUNTIME_CHECK(udp_listener_start(ludp, so0, manager, workers, - workers, 0) == ISC_R_SUCCESS); + RUNTIME_CHECK(udp_listener_start(ludp, so0, manager, + workers, workers, 0, + dispatch) == ISC_R_SUCCESS); isc_mem_stats(mctx, stdout); @@ -114,8 +155,9 @@ main(int argc, char *argv[]) (int)addrlen) == ISC_R_SUCCESS); ltcp = tcp_listener_allocate(mctx, workers); - RUNTIME_CHECK(tcp_listener_start(ltcp, so1, manager, workers, - workers, 0) == ISC_R_SUCCESS); + RUNTIME_CHECK(tcp_listener_start(ltcp, so1, manager, + workers, workers, 0, + dispatch) == ISC_R_SUCCESS); isc_mem_stats(mctx, stdout); diff --git a/bin/named/tcpclient.c b/bin/named/tcpclient.c index a2652ad644..c4fdcb7477 100644 --- a/bin/named/tcpclient.c +++ b/bin/named/tcpclient.c @@ -202,6 +202,9 @@ tcp_recv_req(isc_task_t *task, isc_event_t *event) isc_socketevent_t *dev; tcp_cctx_t *ctx; isc_region_t region; + unsigned char *cp; + isc_uint16_t len; + dns_result_t result; sock = event->sender; dev = (isc_socketevent_t *)event; @@ -236,18 +239,37 @@ tcp_recv_req(isc_task_t *task, isc_event_t *event) dump_packet(ctx->buf, dev->n); /* - * release memory + * Call the dispatch() function to actually process this packet. + * If it returns ISC_R_SUCCESS, we have a packet to transmit. + * do so. If it returns anything else, drop this connection. */ - isc_mem_put(ctx->mctx, ctx->buf, ctx->buflen); + region.base = ctx->buf; + region.length = dev->n; + result = ctx->parent->dispatch(ctx->mctx, ®ion, 2); + isc_mem_put(ctx->mctx, ctx->buf, ctx->buflen); /* clean up request */ ctx->buf = NULL; /* - * Queue up another receive. + * Failure. Close TCP client. */ - region.base = (unsigned char *)&ctx->buflen; - region.length = 2; - isc_socket_recv(sock, ®ion, ISC_FALSE, - task, tcp_recv_len, event->arg); + if (result != DNS_R_SUCCESS) { + tcp_restart(task, ctx); + + isc_event_free(&event); + + return; + } + + /* + * Success. Send the packet, after filling in the length at the + * front of the packet. + */ + len = region.length - 2; + cp = region.base; + *cp++ = (len & 0xff00) >> 8; + *cp++ = (len & 0x00ff); + + isc_socket_send(sock, ®ion, task, tcp_send, ctx); isc_event_free(&event); } @@ -308,16 +330,43 @@ tcp_send(isc_task_t *task, isc_event_t *event) { isc_socket_t *sock; isc_socketevent_t *dev; + tcp_cctx_t *ctx; + isc_region_t region; sock = event->sender; dev = (isc_socketevent_t *)event; + ctx = (tcp_cctx_t *)(event->arg); - printf("my_send: %s task %p\n\t(sock %p, base %p, length %d, n %d, result %d)\n", - (char *)(event->arg), task, sock, - dev->region.base, dev->region.length, + printf("tcp_send: task %u\n\t(base %p, length %d, n %d, result %d)\n", + ctx->slot, dev->region.base, dev->region.length, dev->n, dev->result); - isc_mem_put(event->mctx, dev->region.base, dev->region.length); + /* + * release memory regardless of outcome. + */ + isc_mem_put(ctx->mctx, dev->region.base, dev->region.length); + + if (dev->result == ISC_R_CANCELED) { + isc_task_shutdown(task); + + isc_event_free(&event); + + return; + } + if (dev->result != ISC_R_SUCCESS) { + tcp_restart(task, ctx); + + isc_event_free(&event); + + return; + } + + /* + * Queue up another receive. + */ + region.base = (unsigned char *)&ctx->buflen; + region.length = 2; + isc_socket_recv(sock, ®ion, ISC_FALSE, task, tcp_recv_len, ctx); isc_event_free(&event); } @@ -353,14 +402,17 @@ tcp_listener_allocate(isc_mem_t *mctx, u_int nwmax) isc_result_t tcp_listener_start(tcp_listener_t *l, isc_socket_t *sock, isc_taskmgr_t *tmgr, - u_int nwstart, u_int nwkeep, u_int nwtimeout) + u_int nwstart, u_int nwkeep, u_int nwtimeout, + dns_result_t (*dispatch)(isc_mem_t *, isc_region_t *, + unsigned int)) { u_int i; - isc_region_t region; LOCK(&l->lock); INSIST(l->nwactive == 0); + INSIST(dispatch != NULL); + l->dispatch = dispatch; l->sock = sock; RUNTIME_CHECK(isc_socket_listen(sock, 0) == ISC_R_SUCCESS); diff --git a/bin/named/tcpclient.h b/bin/named/tcpclient.h index 94d14f8953..53a17e48ca 100644 --- a/bin/named/tcpclient.h +++ b/bin/named/tcpclient.h @@ -21,6 +21,7 @@ struct __tcp_listener { u_int nwkeep; /* workers to keep */ u_int nwmax; /* workers max */ isc_mem_t *mctx; + dns_result_t (*dispatch)(isc_mem_t *, isc_region_t *, unsigned int); isc_mutex_t lock; /* locked */ @@ -33,4 +34,7 @@ tcp_listener_t *tcp_listener_allocate(isc_mem_t *mctx, u_int nwmax); isc_result_t tcp_listener_start(tcp_listener_t *l, isc_socket_t *sock, isc_taskmgr_t *tmgr, - u_int nwstart, u_int nwkeep, u_int nwtimeout); + u_int nwstart, u_int nwkeep, u_int nwtimeout, + dns_result_t (*dispatch)(isc_mem_t *, + isc_region_t *, + unsigned int)); diff --git a/bin/named/udpclient.c b/bin/named/udpclient.c index cf1a4886f8..70a4f2193e 100644 --- a/bin/named/udpclient.c +++ b/bin/named/udpclient.c @@ -21,6 +21,8 @@ #include #include +#include + #define LOCK(lp) \ RUNTIME_CHECK(isc_mutex_lock((lp)) == ISC_R_SUCCESS) #define UNLOCK(lp) \ @@ -74,6 +76,7 @@ udp_shutdown(isc_task_t *task, isc_event_t *event) { udp_cctx_t *ctx; udp_listener_t *l; + isc_socket_t *sock; ctx = (udp_cctx_t *)(event->arg); l = ctx->parent; @@ -91,10 +94,11 @@ udp_shutdown(isc_task_t *task, isc_event_t *event) l->tasks[ctx->slot] = NULL; l->ctxs[ctx->slot] = NULL; - isc_socket_cancel(l->sock, task, ISC_SOCKCANCEL_ALL); - l->nwactive--; + sock = l->sock; + isc_socket_detach(&sock); + UNLOCK(&l->lock); printf("Final shutdown slot %u\n", ctx->slot); @@ -109,6 +113,8 @@ udp_recv(isc_task_t *task, isc_event_t *event) isc_socket_t *sock; isc_socketevent_t *dev; udp_cctx_t *ctx; + dns_result_t result; + isc_region_t region; sock = event->sender; dev = (isc_socketevent_t *)event; @@ -123,14 +129,10 @@ udp_recv(isc_task_t *task, isc_event_t *event) ntohs(dev->address.type.sin.sin_port)); if (dev->result != ISC_R_SUCCESS) { - isc_socket_detach(&sock); - - udp_cctx_free(ctx); + isc_task_shutdown(task); isc_event_free(&event); - isc_task_shutdown(task); - return; } @@ -139,8 +141,14 @@ udp_recv(isc_task_t *task, isc_event_t *event) */ dump_packet(ctx->buf, dev->n); - isc_socket_recv(sock, &dev->region, ISC_FALSE, - task, udp_recv, event->arg); + region.base = ctx->buf; + region.length = dev->n; + result = ctx->parent->dispatch(ctx->mctx, ®ion, 0); + + if (result == DNS_R_SUCCESS) { + isc_socket_sendto(sock, ®ion, task, udp_send, ctx, + &dev->address, dev->addrlength); + } isc_event_free(&event); } @@ -150,16 +158,30 @@ udp_send(isc_task_t *task, isc_event_t *event) { isc_socket_t *sock; isc_socketevent_t *dev; + udp_cctx_t *ctx; + isc_region_t region; sock = event->sender; dev = (isc_socketevent_t *)event; + ctx = (udp_cctx_t *)(event->arg); - printf("my_send: %s task %p\n\t(sock %p, base %p, length %d, n %d, result %d)\n", - (char *)(event->arg), task, sock, - dev->region.base, dev->region.length, + printf("udp_send: task %u\n\t(base %p, length %d, n %d, result %d)\n", + ctx->slot, dev->region.base, dev->region.length, dev->n, dev->result); - isc_mem_put(event->mctx, dev->region.base, dev->region.length); + isc_mem_put(ctx->mctx, dev->region.base, dev->region.length); + + if (dev->result != ISC_R_SUCCESS) { + isc_task_shutdown(task); + + isc_event_free(&event); + + return; + } + + region.base = ctx->buf; + region.length = UDP_INPUT_BUFFER_SIZE; + isc_socket_recv(sock, ®ion, ISC_FALSE, task, udp_recv, ctx); isc_event_free(&event); } @@ -195,14 +217,18 @@ udp_listener_allocate(isc_mem_t *mctx, u_int nwmax) isc_result_t udp_listener_start(udp_listener_t *l, isc_socket_t *sock, isc_taskmgr_t *tmgr, - u_int nwstart, u_int nwkeep, u_int nwtimeout) + u_int nwstart, u_int nwkeep, u_int nwtimeout, + dns_result_t (*dispatch)(isc_mem_t *, isc_region_t *, + unsigned int)) { u_int i; isc_region_t region; LOCK(&l->lock); INSIST(l->nwactive == 0); + INSIST(dispatch != NULL); + l->dispatch = dispatch; l->sock = sock; for (i = 0 ; i < nwstart ; i++) { diff --git a/bin/named/udpclient.h b/bin/named/udpclient.h index abf0ef23f7..60fc89c6c5 100644 --- a/bin/named/udpclient.h +++ b/bin/named/udpclient.h @@ -21,6 +21,7 @@ struct __udp_listener { u_int nwkeep; /* workers to keep */ u_int nwmax; /* workers max */ isc_mem_t *mctx; + dns_result_t (*dispatch)(isc_mem_t *, isc_region_t *, unsigned int); isc_mutex_t lock; /* locked */ @@ -33,4 +34,7 @@ udp_listener_t *udp_listener_allocate(isc_mem_t *mctx, u_int nwmax); isc_result_t udp_listener_start(udp_listener_t *l, isc_socket_t *sock, isc_taskmgr_t *tmgr, - u_int nwstart, u_int nwkeep, u_int nwtimeout); + u_int nwstart, u_int nwkeep, u_int nwtimeout, + dns_result_t (*dispatch)(isc_mem_t *, + isc_region_t *, + unsigned int));