Commit 2343e814 authored by Michael Graff's avatar Michael Graff
Browse files

checkpoint

parent 9f27c513
......@@ -36,10 +36,10 @@ LIBS = ${DEPLIBS} \
TARGETS = lwresd
OBJS = main.@O@ client.@O@ \
OBJS = main.@O@ client.@O@ err_pkt.@O@ \
process_gabn.@O@ process_gnba.@O@ process_noop.@O@
SRCS = main.c client.c \
SRCS = main.c client.c err_pkt.c \
process_gabn.c process_gnba.c process_noop.c
@BIND9_MAKE_RULES@
......
......@@ -75,8 +75,6 @@ clientmgr_can_die(clientmgr_t *cm)
static void
process_request(client_t *client)
{
clientmgr_t *cm = client->clientmgr;
lwres_lwpacket_t pkt;
lwres_buffer_t b;
isc_result_t result;
......@@ -85,41 +83,35 @@ process_request(client_t *client)
lwres_buffer_init(&b, client->buffer, client->recvlength);
lwres_buffer_add(&b, client->recvlength);
result = lwres_lwpacket_parseheader(&b, &pkt);
result = lwres_lwpacket_parseheader(&b, &client->pkt);
if (result != ISC_R_SUCCESS) {
printf("Invalid packet header received\n");
goto restart;
}
printf("OPCODE %08x\n", pkt.opcode);
printf("OPCODE %08x\n", client->pkt.opcode);
switch (pkt.opcode) {
switch (client->pkt.opcode) {
case LWRES_OPCODE_GETADDRSBYNAME:
result = process_gabn(client, &b, &pkt);
break;
process_gabn(client, &b);
return;
case LWRES_OPCODE_GETNAMEBYADDR:
result = process_gnba(client, &b, &pkt);
break;
process_gnba(client, &b);
return;
case LWRES_OPCODE_NOOP:
result = process_noop(client, &b, &pkt);
break;
process_noop(client, &b);
return;
default:
printf("Unknown opcode %08x\n", pkt.opcode);
printf("Unknown opcode %08x\n", client->pkt.opcode);
goto restart;
}
/*
* We're working on something, so stay in the run queue.
* Drop the packet.
*/
if (result == ISC_R_SUCCESS)
return;
restart:
printf("restarting client %p...\n", client);
client->state = CLIENT_STATE_IDLE;
ISC_LIST_UNLINK(cm->running, client, link);
ISC_LIST_PREPEND(cm->idle, client, link);
client_start_recv(cm);
client_state_idle(client);
}
void
......@@ -129,7 +121,9 @@ client_recv(isc_task_t *task, isc_event_t *ev)
clientmgr_t *cm = client->clientmgr;
isc_socketevent_t *dev = (isc_socketevent_t *)ev;
INSIST(dev->region.base == client->buffer);
INSIST(CLIENT_ISRECV(client));
CLIENT_SETRECVDONE(client);
INSIST((cm->flags & CLIENTMGR_FLAG_RECVPENDING) != 0);
......@@ -145,17 +139,17 @@ client_recv(isc_task_t *task, isc_event_t *ev)
/*
* Go idle.
*/
CLIENT_SETIDLE(client);
ISC_LIST_UNLINK(cm->running, client, link);
ISC_LIST_APPEND(cm->idle, client, link);
clientmgr_can_die(cm);
client_state_idle(client);
return;
}
/*
* XXXMLG If we wanted to run on ipv6 as well, we'd need the pktinfo
* bits. Right now we don't, so don't remember them.
*/
client->recvlength = dev->n;
client->address = dev->address;
client_start_recv(cm);
process_request(client);
......@@ -173,7 +167,8 @@ client_start_recv(clientmgr_t *cm)
isc_result_t result;
isc_region_t r;
REQUIRE((cm->flags & CLIENTMGR_FLAG_SHUTTINGDOWN) == 0);
if ((cm->flags & CLIENTMGR_FLAG_SHUTTINGDOWN) != 0)
return (ISC_R_SUCCESS);
/*
* If a recv is already running, don't bother.
......@@ -241,3 +236,78 @@ client_shutdown(isc_task_t *task, isc_event_t *ev)
cm->flags |= CLIENTMGR_FLAG_SHUTTINGDOWN;
}
/*
* Do all the crap needed to move a client from the run queue to the idle
* queue.
*/
void
client_state_idle(client_t *client)
{
clientmgr_t *cm;
cm = client->clientmgr;
INSIST(client->sendbuf == NULL);
INSIST(client->sendlength == 0);
INSIST(client->arg == NULL);
INSIST(client->v4find == NULL);
INSIST(client->v6find == NULL);
ISC_LIST_UNLINK(cm->running, client, link);
ISC_LIST_PREPEND(cm->idle, client, link);
CLIENT_SETIDLE(client);
clientmgr_can_die(cm);
client_start_recv(cm);
}
void
client_send(isc_task_t *task, isc_event_t *ev)
{
client_t *client = ev->arg;
clientmgr_t *cm = client->clientmgr;
isc_socketevent_t *dev = (isc_socketevent_t *)ev;
UNUSED(task);
INSIST(CLIENT_ISSEND(client));
INSIST(client->sendbuf == dev->region.base);
if (client->sendbuf != client->buffer) {
lwres_context_freemem(cm->lwctx, client->sendbuf,
client->sendlength);
client->sendbuf = NULL;
}
client_state_idle(client);
}
void
client_initialize(client_t *client, clientmgr_t *cmgr)
{
int i;
client->clientmgr = cmgr;
ISC_LINK_INIT(client, link);
CLIENT_SETIDLE(client);
client->arg = NULL;
client->recvlength = 0;
client->sendbuf = NULL;
client->sendlength = 0;
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);
}
......@@ -30,6 +30,7 @@
#include <dns/cache.h>
#include <dns/db.h>
#include <dns/master.h>
#include <dns/fixedname.h>
#include <dns/name.h>
#define LWRD_EVENTCLASS ISC_EVENTCLASS(4242)
......@@ -40,24 +41,51 @@ typedef struct client_s client_t;
typedef struct clientmgr_s clientmgr_t;
struct client_s {
isc_sockaddr_t sockaddr; /* where to reply */
isc_sockaddr_t address; /* where to reply */
clientmgr_t *clientmgr; /* our parent */
ISC_LINK(client_t) link;
unsigned int state;
void *arg; /* packet processing state */
/*
* Received data info.
*/
unsigned char buffer[LWRES_RECVLENGTH]; /* receive buffer */
isc_uint32_t recvlength; /* length recv'd */
lwres_lwpacket_t pkt;
/*
* Send data state. If sendbuf != buffer (that is, the send buffer
* isn't our receive buffer) it will be freed to the lwres_context_t.
*/
unsigned char *sendbuf;
isc_uint32_t sendlength;
unsigned int state;
/*
* gabn (get address by name) state info.
*/
dns_adbfind_t *v4find;
dns_adbfind_t *v6find;
unsigned int find_done; /* addrs we have */
unsigned int find_wanted;
ISC_LINK(client_t) link;
unsigned int find_pending; /* Addresses remaining */
unsigned int find_wanted; /* Addresses we want */
dns_fixedname_t target_name;
lwres_gabnresponse_t gabn;
/*
* gnba (get name by address) state info.
*/
lwres_gnbaresponse_t gnba;
/*
* Alias 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;
};
/*
......@@ -75,8 +103,6 @@ struct client_s {
* _SEND All data for a response has completed, and a reply was
* sent via a socket send() call.
*
* _SENDDONE The send done event was received.
*
* Badly formatted state table:
*
* IDLE -> RECV when client has a recv() queued.
......@@ -89,7 +115,7 @@ struct client_s {
*
* FINDWAIT -> SEND when enough data was received to reply.
*
* SENDDONE -> IDLE when a senddone event was received.
* SEND -> IDLE when a senddone event was received.
*
* At any time -> IDLE on error. Sometimes this will be -> SEND
* instead, if enough data is on hand to reply with a meaningful
......@@ -109,7 +135,11 @@ struct client_s {
#define CLIENT_ISRECVDONE(c) ((c)->state == CLIENT_STATE_RECVDONE)
#define CLIENT_ISFINDWAIT(c) ((c)->state == CLIENT_STATE_FINDWAIT)
#define CLIENT_ISSEND(c) ((c)->state == CLIENT_STATE_SEND)
#define CLIENT_ISSENDDONE(c) ((c)->state == CLIENT_STATE_SENDDONE)
/*
* Overall magic test that means we're not idle.
*/
#define CLIENT_ISRUNNING(c) (!CLIENT_ISIDLE(c))
#define CLIENT_SETIDLE(c) ((c)->state = CLIENT_STATE_IDLE)
#define CLIENT_SETRECV(c) ((c)->state = CLIENT_STATE_RECV)
......@@ -132,15 +162,21 @@ struct clientmgr_s {
#define CLIENTMGR_FLAG_RECVPENDING 0x00000001
#define CLIENTMGR_FLAG_SHUTTINGDOWN 0x00000002
void client_initialize(client_t *, clientmgr_t *);
isc_result_t client_start_recv(clientmgr_t *);
void client_state_idle(client_t *);
void client_recv(isc_task_t *, isc_event_t *);
void client_shutdown(isc_task_t *, isc_event_t *);
isc_result_t client_start_recv(clientmgr_t *);
void client_send(isc_task_t *, isc_event_t *);
/*
* Processing functions of various types.
*/
isc_result_t process_gabn(client_t *, lwres_buffer_t *, lwres_lwpacket_t *);
isc_result_t process_gnba(client_t *, lwres_buffer_t *, lwres_lwpacket_t *);
isc_result_t process_noop(client_t *, lwres_buffer_t *, lwres_lwpacket_t *);
void process_gabn(client_t *, lwres_buffer_t *);
void process_gnba(client_t *, lwres_buffer_t *);
void process_noop(client_t *, lwres_buffer_t *);
void error_pkt_send(client_t *, isc_uint32_t);
#endif /* LWD_CLIENT_H */
/*
* Copyright (C) 1999 Internet Software Consortium.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
* ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
* CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
* ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
* SOFTWARE.
*/
#include <config.h>
#include <sys/types.h>
#include <isc/assertions.h>
#include <isc/mem.h>
#include <isc/result.h>
#include <isc/sockaddr.h>
#include <isc/socket.h>
#include <isc/task.h>
#include <isc/util.h>
#include <dns/fixedname.h>
#include <lwres/lwres.h>
#include <lwres/result.h>
#include "client.h"
/*
* Generate an error packet for the client, schedule a send, and put us in
* the SEND state.
*
* The client->pkt structure will be modified to form an error return.
* The receiver needs to verify that it is in fact an error, and do the
* right thing with it. The opcode will be unchanged. The result needs
* to be set before calling this function.
*
* The only change this code makes is to set the receive buffer size to the
* size we use, set the reply bit, and recompute any security information.
*/
void
error_pkt_send(client_t *client, isc_uint32_t _result)
{
isc_result_t result;
int lwres;
isc_region_t r;
lwres_buffer_t b;
clientmgr_t *cm;
cm = client->clientmgr;
REQUIRE(CLIENT_ISRUNNING(client));
/*
* Since we are only sending the packet header, we can safely toss
* the receive buffer. This means we won't need to allocate space
* for sending an error reply. This is a Good Thing.
*/
client->pkt.length = LWRES_LWPACKET_LENGTH;
client->pkt.flags |= LWRES_LWPACKETFLAG_RESPONSE;
client->pkt.recvlength = LWRES_RECVLENGTH;
client->pkt.authtype = 0; /* XXXMLG */
client->pkt.authlength = 0;
client->pkt.result = _result;
lwres_buffer_init(&b, client->buffer, LWRES_RECVLENGTH);
lwres = lwres_lwpacket_renderheader(&b, &client->pkt);
if (lwres != LWRES_R_SUCCESS) {
client_state_idle(client);
return;
}
r.base = client->buffer;
r.length = b.used;
client->sendbuf = client->buffer;
result = isc_socket_sendto(cm->sock, &r, cm->task, client_send, client,
&client->address, NULL);
if (result != ISC_R_SUCCESS) {
client_state_idle(client);
return;
}
CLIENT_SETSEND(client);
}
......@@ -38,7 +38,7 @@
/*
* The goal number of clients we can handle will be NTASKS * NRECVS.
*/
#define NTASKS 10 /* tasks to create to handle lwres queries */
#define NTASKS 20 /* tasks to create to handle lwres queries */
#define NRECVS 5 /* max clients per task */
#define NTHREADS 1 /* # threads to create in thread manager */
......@@ -236,16 +236,8 @@ main(int argc, char **argv)
client = isc_mem_get(mem, sizeof(client_t) * ntasks);
if (client == NULL)
break;
for (j = 0 ; j < ntasks ; j++) {
client[j].clientmgr = &cmgr[j];
client[j].recvlength = 0;
client[j].sendbuf = NULL;
client[j].sendlength = 0;
ISC_LINK_INIT(&client[j], link);
CLIENT_SETIDLE(&client[j]);
ISC_LIST_APPEND(cmgr[j].idle, &client[j], link);
}
for (j = 0 ; j < ntasks ; j++)
client_initialize(&client[j], &cmgr[j]);
}
INSIST(i > 0);
......
......@@ -30,6 +30,7 @@
#include <dns/fixedname.h>
#include <lwres/lwres.h>
#include <lwres/result.h>
#include "client.h"
......@@ -39,10 +40,11 @@ process_gabn_finddone(isc_task_t *task, isc_event_t *ev)
}
static isc_result_t
start_v4find(client_t *client, dns_name_t *name)
start_v4find(client_t *client)
{
unsigned int options;
isc_result_t result;
dns_fixedname_t cname;
/*
* Issue a find for the name contained in the request. We won't
......@@ -53,11 +55,44 @@ start_v4find(client_t *client, dns_name_t *name)
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;
dns_fixedname_init(&cname);
if (client->v4find != NULL)
dns_adb_destroyfind(&client->v4find);
result = dns_adb_createfind(client->clientmgr->view->adb,
client->clientmgr->task,
process_gabn_finddone, client,
name, dns_rootname, options,
0, NULL /*XXX*/, &client->v4find);
dns_fixedname_name(&client->target_name),
dns_rootname, options, 0,
dns_fixedname_name(&cname),
&client->v4find);
/*
* If we're going to get an event, set our internal pending flag.
*/
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 there is an event pending, wait for it. The event callback
......@@ -67,7 +102,7 @@ start_v4find(client_t *client, dns_name_t *name)
}
static isc_result_t
start_v6find(client_t *client, dns_name_t *name)
start_v6find(client_t *client)
{
unsigned int options;
isc_result_t result;
......@@ -81,12 +116,6 @@ start_v6find(client_t *client, dns_name_t *name)
options |= DNS_ADBFIND_WANTEVENT;
options |= DNS_ADBFIND_INET6;
result = dns_adb_createfind(client->clientmgr->view->adb,
client->clientmgr->task,
process_gabn_finddone, client,
name, dns_rootname, options,
0, NULL /*XXX*/, &client->v6find);
/*
* If there is an event pending, wait for it. The event callback
* will kill this fetch and reissue it.
......@@ -94,20 +123,39 @@ start_v6find(client_t *client, dns_name_t *name)
return (ISC_R_NOTIMPLEMENTED);
}
isc_result_t
process_gabn(client_t *client, lwres_buffer_t *b, lwres_lwpacket_t *pkt)
/*
* When we are called, we can be assured that:
*
* client->sockaddr contains the address we need to reply to,
*
* client->pkt contains the packet header data,
*
* the packet "checks out" overall -- any MD5 hashes or crypto
* bits have been verified,
*
* "b" points to the remaining data after the packet header
* was parsed off.
*
* We are in a the RECVDONE state.
*
* From this state we will enter the SEND state if we happen to have
* everything we need or we need to return an error packet, or to the
* FINDWAIT state if we need to look things up.
*/
void
process_gabn(client_t *client, lwres_buffer_t *b)
{
isc_result_t result;
lwres_lwpacket_t rpkt;
lwres_gabnrequest_t *req;
lwres_gabnresponse_t resp;
dns_fixedname_t name;
isc_buffer_t namebuf;
REQUIRE(CLIENT_ISRECVDONE(client));
req = NULL;
result = lwres_gabnrequest_parse(client->clientmgr->lwctx,
b, pkt, &req);
b, &client->pkt, &req);
if (result != ISC_R_SUCCESS)
goto out;
......@@ -115,25 +163,43 @@ process_gabn(client_t *client, lwres_buffer_t *b, lwres_lwpacket_t *pkt)
ISC_BUFFERTYPE_TEXT);
isc_buffer_add(&namebuf, req->namelen);
dns_fixedname_init(&name);
result = dns_name_fromtext(dns_fixedname_name(&name), &namebuf,
dns_rootname, ISC_FALSE, NULL);
dns_fixedname_init(&client->target_name);
result = dns_name_fromtext(dns_fixedname_name(&client->target_name),
&namebuf, dns_rootname, ISC_FALSE, NULL);
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, dns_fixedname_name(&name));
INSIST(result == ISC_R_SUCCESS);
result = start_v4find(client);
if (result != ISC_R_SUCCESS)
goto out;
}
if ((req->addrtypes & LWRES_ADDRTYPE_V6) != 0) {
result = start_v6find(client, dns_fixedname_name(&name));
INSIST(result == ISC_R_SUCCESS);
result = start_v6find(client);
if (result != ISC_R_SUCCESS)
goto out;
}
return (ISC_R_SUCCESS);
/*
* We no longer need to keep this around. Return success, and
* let the find*() functions drive us from now on.
*/
lwres_gabnrequest_free(client->clientmgr->lwctx, &req);
return;
/*
* We're screwed. Return an error packet to our caller.
*/
out:
if (req != NULL)
lwres_gabnrequest_free(client->clientmgr->lwctx, &req);
return (result);
error_pkt_send(client, LWRES_R_FAILURE);
return;
}