implement actual network I/O for lw resolver. All I/O is run through the
context, where the sockets are cached. This means one context per thread.
This commit is contained in:
@@ -65,24 +65,17 @@ hexdump(char *msg, void *base, size_t len)
|
||||
}
|
||||
|
||||
static char *TESTSTRING = "This is a test. This is only a test. !!!";
|
||||
static lwres_context_t *ctx;
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
static void
|
||||
test_noop(void)
|
||||
{
|
||||
int ret;
|
||||
lwres_context_t *ctx;
|
||||
lwres_lwpacket_t pkt, pkt2;
|
||||
lwres_nooprequest_t nooprequest, *nooprequest2;
|
||||
lwres_noopresponse_t noopresponse, *noopresponse2;
|
||||
lwres_buffer_t b;
|
||||
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
|
||||
ctx = NULL;
|
||||
ret = lwres_context_create(&ctx, NULL, NULL, NULL);
|
||||
CHECK(ret, "lwres_context_create");
|
||||
|
||||
pkt.flags = 0;
|
||||
pkt.serial = 0x11223344;
|
||||
pkt.recvlength = 0x55667788;
|
||||
@@ -152,6 +145,36 @@ main(int argc, char *argv[])
|
||||
lwres_context_freemem(ctx, b.base, b.length);
|
||||
b.base = NULL;
|
||||
b.length = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
test_gabn(void)
|
||||
{
|
||||
lwres_gabnresponse_t *res;
|
||||
int ret;
|
||||
|
||||
res = NULL;
|
||||
ret = lwres_getaddrsbyname(ctx, "www.flame.org", LWRES_ADDRTYPE_V4,
|
||||
&res);
|
||||
assert(ret == 0);
|
||||
|
||||
lwres_gabnresponse_free(ctx, &res);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
int ret;
|
||||
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
|
||||
ctx = NULL;
|
||||
ret = lwres_context_create(&ctx, NULL, NULL, NULL);
|
||||
CHECK(ret, "lwres_context_create");
|
||||
|
||||
test_noop();
|
||||
test_gabn();
|
||||
|
||||
lwres_context_destroy(&ctx);
|
||||
|
||||
|
||||
@@ -22,14 +22,22 @@
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include <lwres/context.h>
|
||||
#include <lwres/lwres.h>
|
||||
|
||||
#include "context_p.h"
|
||||
#include "assert_p.h"
|
||||
|
||||
static void *lwres_malloc(void *, size_t);
|
||||
static void lwres_free(void *, void *, size_t);
|
||||
static int context_connect(lwres_context_t *);
|
||||
|
||||
int
|
||||
lwres_context_create(lwres_context_t **contextp, void *arg,
|
||||
@@ -63,10 +71,13 @@ lwres_context_create(lwres_context_t **contextp, void *arg,
|
||||
ctx->malloc = malloc_function;
|
||||
ctx->free = free_function;
|
||||
ctx->arg = arg;
|
||||
ctx->sock = -1;
|
||||
|
||||
ctx->timeout = LWRES_DEFAULT_TIMEOUT;
|
||||
ctx->serial = (isc_uint32_t)ctx; /* XXXMLG */
|
||||
|
||||
(void)context_connect(ctx); /* XXXMLG */
|
||||
|
||||
*contextp = ctx;
|
||||
return (0);
|
||||
}
|
||||
@@ -141,3 +152,58 @@ lwres_free(void *arg, void *mem, size_t len)
|
||||
memset(mem, 0xa9, len);
|
||||
free(mem);
|
||||
}
|
||||
|
||||
static int
|
||||
context_connect(lwres_context_t *ctx)
|
||||
{
|
||||
int s;
|
||||
int ret;
|
||||
struct sockaddr_in localhost;
|
||||
|
||||
memset(&localhost, 0, sizeof(localhost));
|
||||
localhost.sin_family = AF_INET;
|
||||
localhost.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
||||
localhost.sin_port = htons(LWRES_UDP_PORT);
|
||||
|
||||
s = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||
if (s < 0)
|
||||
return (-1);
|
||||
|
||||
ret = connect(s, (struct sockaddr *)&localhost, sizeof(localhost));
|
||||
if (ret != 0) {
|
||||
close(s);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
ctx->sock = s;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
lwres_context_sendrecv(lwres_context_t *ctx,
|
||||
void *sendbase, int sendlen,
|
||||
void *recvbase, int recvlen)
|
||||
{
|
||||
int ret;
|
||||
struct sockaddr_in sin;
|
||||
int fromlen;
|
||||
|
||||
ret = send(ctx->sock, sendbase, sendlen, 0);
|
||||
if (ret < 0)
|
||||
return (ret);
|
||||
if (ret != sendlen)
|
||||
return (-1);
|
||||
|
||||
fromlen = sizeof(sin);
|
||||
ret = recvfrom(ctx->sock, recvbase, recvlen, 0,
|
||||
(struct sockaddr *)&sin, &fromlen);
|
||||
if (ret < 0)
|
||||
return (-1);
|
||||
|
||||
if (sin.sin_addr.s_addr != htonl(INADDR_LOOPBACK)
|
||||
|| sin.sin_port != htons(LWRES_UDP_PORT))
|
||||
return (-1);
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
@@ -35,6 +35,11 @@ struct lwres_context {
|
||||
unsigned int timeout; /* time to wait for reply */
|
||||
isc_uint32_t serial; /* serial number state */
|
||||
|
||||
/*
|
||||
* For network I/O.
|
||||
*/
|
||||
int sock; /* socket to send on */
|
||||
|
||||
/*
|
||||
* Function pointers for allocating memory.
|
||||
*/
|
||||
|
||||
@@ -77,6 +77,11 @@ lwres_context_freemem(lwres_context_t *ctx, void *mem, size_t len);
|
||||
void *
|
||||
lwres_context_allocmem(lwres_context_t *ctx, size_t len);
|
||||
|
||||
int
|
||||
lwres_context_sendrecv(lwres_context_t *ctx,
|
||||
void *sendbase, int sendlen,
|
||||
void *recvbase, int recvlen);
|
||||
|
||||
ISC_LANG_ENDDECLS
|
||||
|
||||
#endif /* LWRES_CONTEXT_H */
|
||||
|
||||
@@ -86,6 +86,9 @@
|
||||
|
||||
#define LWRES_STRING_LENGTH(x) (sizeof(isc_uint16_t) + strlen(x) + 1)
|
||||
|
||||
#define LWRES_UDP_PORT 921 /* XXXMLG */
|
||||
#define LWRES_RECVLENGTH 2048 /* XXXMLG */
|
||||
|
||||
/*
|
||||
* NO-OP
|
||||
*/
|
||||
@@ -116,6 +119,7 @@ typedef struct {
|
||||
|
||||
typedef struct {
|
||||
/* public */
|
||||
isc_uint32_t addrtypes;
|
||||
char *name;
|
||||
} lwres_gabnrequest_t;
|
||||
|
||||
@@ -126,6 +130,9 @@ typedef struct {
|
||||
char *real_name;
|
||||
char **aliases;
|
||||
lwres_addr_t *addrs;
|
||||
/* if base != NULL, it will be freed when this structure is freed. */
|
||||
void *base;
|
||||
size_t baselen;
|
||||
} lwres_gabnresponse_t;
|
||||
|
||||
/*
|
||||
@@ -142,6 +149,9 @@ typedef struct {
|
||||
isc_uint16_t naliases;
|
||||
char *real_name;
|
||||
char **aliases;
|
||||
/* if base != NULL, it will be freed when this structure is freed. */
|
||||
void *base;
|
||||
size_t baselen;
|
||||
} lwres_gnbaresponse_t;
|
||||
|
||||
#define LWRES_ADDRTYPE_V4 0x00000001U /* ipv4 */
|
||||
@@ -336,6 +346,10 @@ lwres_string_parse(lwres_buffer_t *b, char **c, isc_uint16_t *len);
|
||||
int
|
||||
lwres_addr_parse(lwres_buffer_t *b, lwres_addr_t *addr);
|
||||
|
||||
int
|
||||
lwres_getaddrsbyname(lwres_context_t *ctx, const char *name,
|
||||
isc_uint32_t addrtypes, lwres_gabnresponse_t **structp);
|
||||
|
||||
ISC_LANG_ENDDECLS
|
||||
|
||||
#endif /* LWRES_LWRES_H */
|
||||
|
||||
@@ -47,7 +47,7 @@ lwres_gabnrequest_render(lwres_context_t *ctx, lwres_gabnrequest_t *req,
|
||||
|
||||
datalen = strlen(req->name);
|
||||
|
||||
payload_length = LWRES_STRING_LENGTH(req->name);
|
||||
payload_length = LWRES_STRING_LENGTH(req->name) + 4;
|
||||
|
||||
buflen = LWRES_LWPACKET_LENGTH + payload_length;
|
||||
buf = CTXMALLOC(buflen);
|
||||
@@ -74,6 +74,11 @@ lwres_gabnrequest_render(lwres_context_t *ctx, lwres_gabnrequest_t *req,
|
||||
|
||||
INSIST(SPACE_OK(b, payload_length));
|
||||
|
||||
/*
|
||||
* Address types we'll accept.
|
||||
*/
|
||||
lwres_buffer_putuint32(b, req->addrtypes);
|
||||
|
||||
/*
|
||||
* Put the length and the data. We know this will fit because we
|
||||
* just checked for it.
|
||||
@@ -180,6 +185,7 @@ lwres_gabnrequest_parse(lwres_context_t *ctx, lwres_lwpacket_t *pkt,
|
||||
int ret;
|
||||
char *name;
|
||||
lwres_gabnrequest_t *gabn;
|
||||
isc_uint32_t addrtypes;
|
||||
|
||||
REQUIRE(ctx != NULL);
|
||||
REQUIRE(pkt != NULL);
|
||||
@@ -189,6 +195,11 @@ lwres_gabnrequest_parse(lwres_context_t *ctx, lwres_lwpacket_t *pkt,
|
||||
if ((pkt->flags & LWRES_LWPACKETFLAG_RESPONSE) == 0)
|
||||
return (-1);
|
||||
|
||||
if (!SPACE_REMAINING(b, 4))
|
||||
return (-1);
|
||||
|
||||
addrtypes = lwres_buffer_getuint32(b);
|
||||
|
||||
/*
|
||||
* Pull off the name itself
|
||||
*/
|
||||
@@ -203,6 +214,7 @@ lwres_gabnrequest_parse(lwres_context_t *ctx, lwres_lwpacket_t *pkt,
|
||||
if (gabn == NULL)
|
||||
return (-1);
|
||||
|
||||
gabn->addrtypes = addrtypes;
|
||||
gabn->name = name;
|
||||
|
||||
*structp = gabn;
|
||||
@@ -249,6 +261,7 @@ lwres_gabnresponse_parse(lwres_context_t *ctx, lwres_lwpacket_t *pkt,
|
||||
goto out;
|
||||
}
|
||||
gabn->naliases = naliases;
|
||||
gabn->base = NULL;
|
||||
|
||||
gabn->addrs = CTXMALLOC(sizeof(lwres_addr_t) * naddrs);
|
||||
if (gabn->addrs == NULL) {
|
||||
@@ -326,5 +339,7 @@ lwres_gabnresponse_free(lwres_context_t *ctx, lwres_gabnresponse_t **structp)
|
||||
CTXFREE(gabn->aliases, sizeof(char *) * gabn->naliases);
|
||||
if (gabn->naddrs > 0)
|
||||
CTXFREE(gabn->addrs, sizeof(lwres_addr_t *) * gabn->naddrs);
|
||||
if (gabn->base != NULL)
|
||||
CTXFREE(gabn->base, gabn->baselen);
|
||||
CTXFREE(gabn, sizeof(lwres_gabnresponse_t));
|
||||
}
|
||||
|
||||
@@ -224,6 +224,7 @@ lwres_gnbaresponse_parse(lwres_context_t *ctx, lwres_lwpacket_t *pkt,
|
||||
if (gnba == NULL)
|
||||
return (-1);
|
||||
gnba->naliases = 0;
|
||||
gnba->base = NULL;
|
||||
|
||||
gnba->aliases = CTXMALLOC(sizeof(char *) * naliases);
|
||||
if (gnba->aliases == NULL) {
|
||||
@@ -290,5 +291,7 @@ lwres_gnbaresponse_free(lwres_context_t *ctx, lwres_gnbaresponse_t **structp)
|
||||
|
||||
if (gnba->naliases > 0)
|
||||
CTXFREE(gnba->aliases, sizeof(char *) * gnba->naliases);
|
||||
if (gnba->base != NULL)
|
||||
CTXFREE(gnba->base, gnba->baselen);
|
||||
CTXFREE(gnba, sizeof(lwres_gnbaresponse_t));
|
||||
}
|
||||
|
||||
@@ -21,11 +21,18 @@
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include <lwres/lwbuffer.h>
|
||||
#include <lwres/lwres.h>
|
||||
|
||||
#include "assert_p.h"
|
||||
#include "context_p.h"
|
||||
|
||||
/*
|
||||
* Requires:
|
||||
@@ -86,3 +93,99 @@ lwres_addr_parse(lwres_buffer_t *b, lwres_addr_t *addr)
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
lwres_getaddrsbyname(lwres_context_t *ctx, const char *name,
|
||||
isc_uint32_t addrtypes, lwres_gabnresponse_t **structp)
|
||||
{
|
||||
lwres_gabnrequest_t request;
|
||||
lwres_gabnresponse_t *response;
|
||||
int ret;
|
||||
int free_b;
|
||||
lwres_buffer_t b;
|
||||
lwres_lwpacket_t pkt;
|
||||
isc_uint32_t serial;
|
||||
char *buffer;
|
||||
|
||||
REQUIRE(ctx != NULL);
|
||||
REQUIRE(name != NULL);
|
||||
REQUIRE(addrtypes != 0);
|
||||
REQUIRE(structp != NULL && *structp == NULL);
|
||||
|
||||
response = NULL;
|
||||
free_b = 0;
|
||||
buffer = NULL;
|
||||
serial = (isc_uint32_t)name;
|
||||
|
||||
buffer = CTXMALLOC(LWRES_RECVLENGTH);
|
||||
if (buffer == NULL) {
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set up our request and render it to a buffer.
|
||||
*/
|
||||
request.addrtypes = addrtypes;
|
||||
request.name = (char *)name;
|
||||
pkt.flags = 0;
|
||||
pkt.serial = serial;
|
||||
pkt.result = 0;
|
||||
pkt.recvlength = LWRES_RECVLENGTH;
|
||||
|
||||
ret = lwres_gabnrequest_render(ctx, &request, &pkt, &b);
|
||||
if (ret != 0)
|
||||
goto out;
|
||||
free_b = 1;
|
||||
|
||||
ret = lwres_context_sendrecv(ctx, b.base, b.length, buffer,
|
||||
LWRES_RECVLENGTH);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
CTXFREE(b.base, b.length);
|
||||
free_b = 0;
|
||||
|
||||
lwres_buffer_init(&b, buffer, ret);
|
||||
|
||||
/*
|
||||
* Parse the packet header.
|
||||
*/
|
||||
ret = lwres_lwpacket_parseheader(&b, &pkt);
|
||||
if (ret != 0)
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* Sanity check.
|
||||
*/
|
||||
if (pkt.serial != serial) {
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
if (pkt.opcode != LWRES_OPCODE_GETADDRSBYNAME) {
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse the response.
|
||||
*/
|
||||
ret = lwres_gabnresponse_parse(ctx, &pkt, &b, &response);
|
||||
if (ret != 0)
|
||||
goto out;
|
||||
response->base = buffer;
|
||||
response->baselen = LWRES_RECVLENGTH;
|
||||
buffer = NULL; /* don't free this below */
|
||||
|
||||
*structp = response;
|
||||
return (0);
|
||||
|
||||
out:
|
||||
if (free_b != 0)
|
||||
CTXFREE(b.base, b.length);
|
||||
if (buffer != NULL)
|
||||
CTXFREE(buffer, LWRES_RECVLENGTH);
|
||||
if (response != NULL)
|
||||
lwres_gabnresponse_free(ctx, &response);
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user