checkpoint; no memory leaks, finds run
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include <isc/event.h>
|
||||
#include <isc/eventclass.h>
|
||||
#include <isc/list.h>
|
||||
#include <isc/log.h>
|
||||
#include <isc/mem.h>
|
||||
#include <isc/sockaddr.h>
|
||||
#include <isc/socket.h>
|
||||
@@ -32,6 +33,7 @@
|
||||
#include <dns/master.h>
|
||||
#include <dns/fixedname.h>
|
||||
#include <dns/name.h>
|
||||
#include <dns/log.h>
|
||||
|
||||
#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 */
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <isc/assertions.h>
|
||||
#include <isc/event.h>
|
||||
#include <isc/mem.h>
|
||||
#include <isc/log.h>
|
||||
#include <isc/result.h>
|
||||
#include <isc/sockaddr.h>
|
||||
#include <isc/socket.h>
|
||||
@@ -30,6 +31,7 @@
|
||||
#include <isc/util.h>
|
||||
|
||||
#include <dns/rootns.h>
|
||||
#include <dns/log.h>
|
||||
|
||||
#include <lwres/lwres.h>
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -28,30 +28,152 @@
|
||||
#include <isc/util.h>
|
||||
|
||||
#include <dns/fixedname.h>
|
||||
#include <dns/adb.h>
|
||||
#include <dns/events.h>
|
||||
|
||||
#include <lwres/lwres.h>
|
||||
#include <lwres/result.h>
|
||||
|
||||
#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;
|
||||
|
||||
/*
|
||||
|
||||
Reference in New Issue
Block a user