From ab412807973236847a7de09df805432d33b34e90 Mon Sep 17 00:00:00 2001 From: Michael Graff Date: Wed, 26 Jan 2000 01:18:55 +0000 Subject: [PATCH] checkpoint; no memory leaks, finds run --- bin/lwresd/client.c | 80 +++++++++++- bin/lwresd/client.h | 18 ++- bin/lwresd/main.c | 36 +++++- bin/lwresd/process_gabn.c | 262 +++++++++++++++++++++++++++++--------- 4 files changed, 320 insertions(+), 76 deletions(-) diff --git a/bin/lwresd/client.c b/bin/lwresd/client.c index 306eea9c4c..6403d14b9a 100644 --- a/bin/lwresd/client.c +++ b/bin/lwresd/client.c @@ -58,6 +58,18 @@ hexdump(char *msg, void *base, size_t len) printf("\n"); } +void +DP(int level, char *format, ...) +{ + va_list args; + + va_start(args, format); + isc_log_vwrite(dns_lctx, + DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_ADB, + ISC_LOG_DEBUG(level), format, args); + va_end(args); +} + static void clientmgr_can_die(clientmgr_t *cm) { @@ -276,6 +288,8 @@ client_send(isc_task_t *task, isc_event_t *ev) INSIST(CLIENT_ISSEND(client)); INSIST(client->sendbuf == dev->region.base); + printf("Task %p for client %p got send-done event\n", task, client); + if (client->sendbuf != client->buffer) lwres_context_freemem(cm->lwctx, client->sendbuf, client->sendlength); @@ -287,8 +301,6 @@ client_send(isc_task_t *task, isc_event_t *ev) void client_initialize(client_t *client, clientmgr_t *cmgr) { - int i; - client->clientmgr = cmgr; ISC_LINK_INIT(client, link); CLIENT_SETIDLE(client); @@ -299,15 +311,69 @@ client_initialize(client_t *client, clientmgr_t *cmgr) client->sendbuf = NULL; client->sendlength = 0; + client->find = NULL; client->v4find = NULL; client->v6find = NULL; - client->find_pending = 0; client->find_wanted = 0; - for (i = 0 ; i < LWRES_MAX_ALIASES ; i++) - client->aliases[i] = NULL; - client->naliases = 0; - ISC_LIST_APPEND(cmgr->idle, client, link); } + +void +client_init_aliases(client_t *client) +{ + int i; + + for (i = 0 ; i < LWRES_MAX_ALIASES ; i++) { + client->aliases[i] = NULL; + client->aliaslen[i] = 0; + } + for (i = 0 ; i < LWRES_MAX_ADDRS ; i++) { + client->addrs[i].family = 0; + client->addrs[i].length = 0; + client->addrs[i].address = NULL; + } +} + +void +client_init_gabn(client_t *client) +{ + /* + * Initialize the real name and alias arrays in the reply we're + * going to build up. + */ + client_init_aliases(client); + client->gabn.naliases = 0; + client->gabn.naddrs = 0; + client->gabn.realname = NULL; + client->gabn.aliases = client->aliases; + client->gabn.realnamelen = 0; + client->gabn.aliaslen = client->aliaslen; + client->gabn.addrs = client->addrs; + client->gabn.base = NULL; + client->gabn.baselen = NULL; + + /* + * Set up the internal buffer to point to the receive region. + */ + isc_buffer_init(&client->recv_buffer, client->buffer, + LWRES_RECVLENGTH, ISC_BUFFERTYPE_TEXT); +} + +void +client_init_gnba(client_t *client) +{ + /* + * Initialize the real name and alias arrays in the reply we're + * going to build up. + */ + client_init_aliases(client); + client->gnba.naliases = 0; + client->gnba.realname = NULL; + client->gnba.aliases = client->aliases; + client->gnba.realnamelen = 0; + client->gnba.aliaslen = client->aliaslen; + client->gnba.base = NULL; + client->gnba.baselen = NULL; +} diff --git a/bin/lwresd/client.h b/bin/lwresd/client.h index 9a6e874870..e71fee0f8b 100644 --- a/bin/lwresd/client.h +++ b/bin/lwresd/client.h @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -32,6 +33,7 @@ #include #include #include +#include #define LWRD_EVENTCLASS ISC_EVENTCLASS(4242) @@ -64,12 +66,13 @@ struct client_s { /* * gabn (get address by name) state info. */ + dns_adbfind_t *find; dns_adbfind_t *v4find; dns_adbfind_t *v6find; - unsigned int find_pending; /* Addresses remaining */ unsigned int find_wanted; /* Addresses we want */ dns_fixedname_t target_name; lwres_gabnresponse_t gabn; + isc_buffer_t recv_buffer; /* * gnba (get name by address) state info. @@ -77,15 +80,16 @@ struct client_s { lwres_gnbaresponse_t gnba; /* - * Alias info. This is copied up to the gabn/gnba structures - * eventually. + * Alias and address info. This is copied up to the gabn/gnba + * structures eventually. * * XXXMLG We can keep all of this in a client since we only service * three packet types right now. If we started handling more, * we'd need to use "arg" above and allocate/destroy things. */ char *aliases[LWRES_MAX_ALIASES]; - unsigned int naliases; + u_int16_t aliaslen[LWRES_MAX_ALIASES]; + lwres_addr_t addrs[LWRES_MAX_ADDRS]; }; /* @@ -179,4 +183,10 @@ void process_noop(client_t *, lwres_buffer_t *); void error_pkt_send(client_t *, isc_uint32_t); +void client_init_aliases(client_t *); +void client_init_gabn(client_t *); +void client_init_gnba(client_t *); + +void DP(int level, char *format, ...); + #endif /* LWD_CLIENT_H */ diff --git a/bin/lwresd/main.c b/bin/lwresd/main.c index b0f848b21c..2865cf6f28 100644 --- a/bin/lwresd/main.c +++ b/bin/lwresd/main.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -30,6 +31,7 @@ #include #include +#include #include @@ -136,6 +138,8 @@ main(int argc, char **argv) isc_result_t result; unsigned int i, j; client_t *client; + isc_logdestination_t destination; + isc_log_t *lctx; UNUSED(argc); UNUSED(argv); @@ -149,8 +153,31 @@ main(int argc, char **argv) result = isc_mem_create(0, 0, &mem); INSIST(result == ISC_R_SUCCESS); - cmgr = isc_mem_get(mem, sizeof(clientmgr_t) * NTASKS); - INSIST(cmgr != NULL); + /* + * Set up logging. + */ + lctx = NULL; + result = isc_log_create(mem, &lctx); + INSIST(result == ISC_R_SUCCESS); + result = dns_log_init(lctx); + INSIST(result == ISC_R_SUCCESS); + + destination.file.stream = stderr; + destination.file.name = NULL; + destination.file.versions = ISC_LOG_ROLLNEVER; + destination.file.maximum_size = 0; + result = isc_log_createchannel(lctx, "_default", + ISC_LOG_TOFILEDESC, + ISC_LOG_DYNAMIC, + &destination, ISC_LOG_PRINTTIME); + INSIST(result == ISC_R_SUCCESS); + result = isc_log_usechannel(lctx, "_default", NULL, NULL); + INSIST(result == ISC_R_SUCCESS); + + /* + * Set the initial debug level. + */ + isc_log_setdebuglevel(lctx, 99); /* * Create a task manager. @@ -196,6 +223,9 @@ main(int argc, char **argv) result = isc_socket_bind(sock, &localhost); INSIST(result == ISC_R_SUCCESS); + cmgr = isc_mem_get(mem, sizeof(clientmgr_t) * NTASKS); + INSIST(cmgr != NULL); + /* * Create one task for each client manager. */ @@ -308,6 +338,8 @@ main(int argc, char **argv) isc_mem_put(mem, cmgr, sizeof(clientmgr_t) * NTASKS); cmgr = NULL; + isc_log_destroy(&lctx); + /* * Kill the memory system. */ diff --git a/bin/lwresd/process_gabn.c b/bin/lwresd/process_gabn.c index f36f0dce61..c77e19eb14 100644 --- a/bin/lwresd/process_gabn.c +++ b/bin/lwresd/process_gabn.c @@ -28,30 +28,152 @@ #include #include +#include +#include #include #include #include "client.h" +#define NEED_V4(c) ((((c)->find_wanted & LWRES_ADDRTYPE_V4) != 0) \ + && ((c)->v4find == NULL)) +#define NEED_V6(c) ((((c)->find_wanted & LWRES_ADDRTYPE_V6) != 0) \ + && ((c)->v6find == NULL)) + +static void start_find(client_t *); + +/* + * Destroy any finds. This can be used to "start over from scratch" and + * should only be called when events are _not_ being generated by the finds. + */ +static void +cleanup_gabn(client_t *client) +{ + DP(50, "Cleaning up client %p\n"); + + if (client->v4find != NULL) + dns_adb_destroyfind(&client->v4find); + if (client->v6find != NULL) + dns_adb_destroyfind(&client->v6find); +} + +static void +generate_reply(client_t *client) +{ + DP(50, "Generating gabn reply for client %p\n"); + cleanup_gabn(client); + + client_state_idle(client); +} + +/* + * Take the current real name, move it to an alias slot (if any are + * open) then put this new name in as the real name for the target. + * + * Return success if it can be rendered, otherwise failure. Note that + * not having enough alias slots open is NOT a failure. + */ +static isc_result_t +add_alias(client_t *client) +{ + isc_buffer_t b; + isc_result_t result; + isc_uint16_t naliases; + + b = client->recv_buffer; + + /* + * Render the new name to the buffer. + */ + result = dns_name_totext(dns_fixedname_name(&client->target_name), + ISC_TRUE, &client->recv_buffer); + if (result != ISC_R_SUCCESS) + return (result); + + /* + * Are there any open slots? + */ + naliases = client->gabn.naliases; + if (naliases < LWRES_MAX_ALIASES) { + client->gabn.aliases[naliases] = client->gabn.realname; + client->gabn.aliaslen[naliases] = client->gabn.realnamelen; + client->gabn.naliases++; + } + + /* + * Save this name away as the current real name. + */ + client->gabn.realname = b.base + b.used; + client->gabn.realnamelen = client->recv_buffer.used - b.used; + + return (ISC_R_SUCCESS); +} + static void process_gabn_finddone(isc_task_t *task, isc_event_t *ev) { client_t *client = ev->arg; + isc_eventtype_t result; - dns_adb_destroyfind(&client->v4find); + DP(50, "Find done for task %p, client %p", task, client); + result = ev->type; isc_event_free(&ev); + + /* + * No more info to be had? If so, we have all the good stuff + * right now, so we can render things. + */ + if (result == DNS_EVENT_ADBNOMOREADDRESSES) { + if (NEED_V4(client)) { + client->v4find = client->find; + client->find = NULL; + } else if (NEED_V6(client)) { + client->v6find = client->find; + client->find = NULL; + } else { + dns_adb_destroyfind(&client->find); + } + generate_reply(client); + return; + } + + /* + * We probably don't need this find anymore. We're either going to + * reissue it, or an error occurred. Either way, we're done with + * it. + */ + if ((client->find != client->v4find) + && (client->find != client->v6find)) { + dns_adb_destroyfind(&client->find); + } else { + client->find = NULL; + } + + /* + * We have some new information we can gather. Run off and fetch + * it. + */ + if (result == DNS_EVENT_ADBMOREADDRESSES) { + start_find(client); + return; + } + + /* + * An error or other strangeness happened. Drop this query. + */ + cleanup_gabn(client); + error_pkt_send(client, LWRES_R_FAILURE); } -static isc_result_t -start_v4find(client_t *client) +static void +start_find(client_t *client) { unsigned int options; isc_result_t result; - dns_fixedname_t cname; - printf("Starting v4 find for client %p\n", client); + DP(50, "Starting find for client %p", client); /* * Issue a find for the name contained in the request. We won't @@ -60,78 +182,89 @@ start_v4find(client_t *client) */ options = 0; options |= DNS_ADBFIND_WANTEVENT; - options |= DNS_ADBFIND_INET; /* * Set the bits up here to mark that we want this address family * and that we do not currently have a find pending. We will * set that bit again below if it turns out we will get an event. */ - INSIST((client->find_wanted & LWRES_ADDRTYPE_V4) != 0); - client->find_pending &= LWRES_ADDRTYPE_V4; + if (NEED_V4(client)) + options |= DNS_ADBFIND_INET; + if (NEED_V6(client)) + options |= DNS_ADBFIND_INET6; - dns_fixedname_init(&cname); - - if (client->v4find != NULL) - dns_adb_destroyfind(&client->v4find); + INSIST(client->find == NULL); + find_again: result = dns_adb_createfind(client->clientmgr->view->adb, client->clientmgr->task, process_gabn_finddone, client, dns_fixedname_name(&client->target_name), dns_rootname, options, 0, - dns_fixedname_name(&cname), + dns_fixedname_name(&client->target_name), &client->v4find); /* - * If we're going to get an event, set our internal pending flag. + * Did we get an error? */ - if ((client->v4find->options & DNS_ADBFIND_WANTEVENT) != 0) - client->find_pending |= LWRES_ADDRTYPE_V4; - - /* - * If we get here, we either have a find pending, or we have - * data. If we have all the data there is to be had, mark us as done. - * Otherwise, leave us running and let our event callback call - * us again. - * - * Eventually we'll get a valid result, either a list of addresses - * or failure. - */ - switch (result) { + if (result != ISC_R_SUCCESS && result != DNS_R_ALIAS) { + error_pkt_send(client, LWRES_R_FAILURE); + return; } /* - * If there is an event pending, wait for it. The event callback - * will kill this fetch and reissue it. + * Did we get an alias? If so, save it and re-issue the query. */ - return (ISC_R_NOTIMPLEMENTED); -} - -static isc_result_t -start_v6find(client_t *client) -{ - unsigned int options; - isc_result_t result; - - printf("Starting v6 find for client %p\n", client); + if (result == DNS_R_ALIAS) { + DP(50, "Found alias, restarting query."); + dns_adb_destroyfind(&client->find); + cleanup_gabn(client); + result = add_alias(client); + if (result != ISC_R_SUCCESS) { + DP(50, "Out of buffer space adding alias"); + error_pkt_send(client, LWRES_R_FAILURE); + return; + } + goto find_again; + } /* - * Issue a find for the name contained in the request. We won't - * set the bit that says "anything is good enough" -- we want it - * all. + * Did we get our answer to V4 addresses? */ - options = 0; - options |= DNS_ADBFIND_WANTEVENT; - options |= DNS_ADBFIND_INET6; + if (NEED_V4(client) + && ((client->find->query_pending & DNS_ADBFIND_INET) == 0)) + client->v4find = client->find; /* - * If there is an event pending, wait for it. The event callback - * will kill this fetch and reissue it. + * Did we get our answer to V6 addresses? */ - return (ISC_R_NOTIMPLEMENTED); -} + if (NEED_V6(client) + && ((client->find->query_pending & DNS_ADBFIND_INET6) == 0)) + client->v6find = client->find; + /* + * If we're going to get an event, set our internal pending flag + * and return. When we get an event back we'll do the right + * thing, basically by calling this function again, perhaps with a + * new target name. + * + * If we have both v4 and v6, and we are still getting an event, + * we have a programming error, so die hard. + */ + if ((client->v4find->options & DNS_ADBFIND_WANTEVENT) != 0) { + DP(50, "Event will be sent."); + INSIST(client->v4find == NULL || client->v6find == NULL); + return; + } + DP(50, "No event will be sent."); + + /* + * We seem to have everything we asked for, or at least we are + * able to respond with things we've learned. + */ + + generate_reply(client); +} /* * When we are called, we can be assured that: @@ -178,27 +311,30 @@ process_gabn(client_t *client, lwres_buffer_t *b) if (result != ISC_R_SUCCESS) goto out; - client->find_pending = 0; client->find_wanted = req->addrtypes; - if ((req->addrtypes & LWRES_ADDRTYPE_V4) != 0) { - result = start_v4find(client); - if (result != ISC_R_SUCCESS) - goto out; - } - - if ((req->addrtypes & LWRES_ADDRTYPE_V6) != 0) { - result = start_v6find(client); - if (result != ISC_R_SUCCESS) - goto out; - } + /* + * Start the find. + */ + start_find(client); /* - * We no longer need to keep this around. Return success, and - * let the find*() functions drive us from now on. + * We no longer need to keep this around. */ lwres_gabnrequest_free(client->clientmgr->lwctx, &req); + /* + * Initialize the real name and alias arrays in the reply we're + * going to build up. + */ + client_init_gabn(client); + + /* + * Do we have all the bits we need to generate a reply? + */ + if (client->find == NULL) { /* XXXMLG */ + } + return; /*