Get the async getaddress going

This commit is contained in:
Neel Goyal 2013-08-15 17:51:26 -04:00
parent 0c5d8b2c32
commit ff83b43081
8 changed files with 181 additions and 36 deletions

View File

@ -30,6 +30,7 @@
#include <string.h>
#include "context.h"
#include "util-internal.h"
#include <ldns/ldns.h>
/* stuff to make it compile pedantically */
@ -60,13 +61,9 @@ static struct getdns_dict* create_ipaddr_dict_from_rdf(ldns_rdf* rdf) {
getdns_dict *result = getdns_dict_create();
/* set type */
if (rt == LDNS_RDF_TYPE_A) {
getdns_bindata type_bin = { (size_t) strlen(GETDNS_STR_IPV4),
(uint8_t*) GETDNS_STR_IPV4 };
getdns_dict_set_bindata(result, GETDNS_STR_ADDRESS_TYPE, &type_bin);
getdns_dict_util_set_string(result, GETDNS_STR_ADDRESS_TYPE, GETDNS_STR_IPV4);
} else {
getdns_bindata type_bin = { (size_t) strlen(GETDNS_STR_IPV6),
(uint8_t*) GETDNS_STR_IPV6 };
getdns_dict_set_bindata(result, GETDNS_STR_ADDRESS_TYPE, &type_bin);
getdns_dict_util_set_string(result, GETDNS_STR_ADDRESS_TYPE, GETDNS_STR_IPV6);
}
/* set data */
getdns_bindata data_bin = { sz, ldns_rdf_data(rdf) };

View File

@ -508,7 +508,7 @@ getdns_dict_set_bindata(struct getdns_dict *dict, char *name, struct getdns_bind
item->data.bindata = (struct getdns_bindata *) malloc(sizeof(struct getdns_bindata));
if(item->data.bindata != NULL)
{
item->data.bindata->data = (void *) malloc(item->data.bindata->size);
item->data.bindata->data = (void *) malloc(child_bindata->size);
if(item->data.bindata->data != NULL)
{
item->data.bindata->size = child_bindata->size;

View File

@ -64,25 +64,83 @@
/* stuff to make it compile pedantically */
#define UNUSED_PARAM(x) ((void)(x))
/* libevent callback for a network request */
static void dns_req_callback(int fd, short events, void *arg) {
getdns_dns_req *request = (getdns_dns_req*) arg;
uint8_t data[1500];
if (events & EV_READ) {
while (1) {
ssize_t r = recv(fd, data, sizeof(data), MSG_DONTWAIT);
if (r < 0) {
if (errno == EAGAIN) return;
/* otherwise failed */
request->user_callback(request->context,
GETDNS_CALLBACK_ERROR,
NULL, request->user_pointer,
request->trans_id);
}
/* parse a packet */
ldns_pkt* pkt = NULL;
ldns_wire2pkt(&pkt, data, r);
if (pkt == NULL) {
/* otherwise failed */
request->user_callback(request->context,
GETDNS_CALLBACK_ERROR,
NULL, request->user_pointer,
request->trans_id);
} else {
/* success */
getdns_dict* response = create_getdns_response(pkt);
ldns_pkt_free(pkt);
request->user_callback(request->context, GETDNS_CALLBACK_COMPLETE,
response, request->user_pointer,
request->trans_id);
}
}
} else if (events & EV_TIMEOUT) {
request->user_callback(request->context, GETDNS_CALLBACK_TIMEOUT,
NULL, request->user_pointer, request->trans_id);
}
/* clean up ns since right now it's 1:1 with the request */
nameserver_free(request->current_req->ns);
/* cleanup the request */
dns_req_free(request);
}
/* submit a new request to the event loop */
static getdns_return_t submit_new_dns_req(getdns_dns_req *request) {
getdns_dict *nameserver = NULL;
getdns_dict *ip_dict = NULL;
getdns_context_t context = request->context;
struct sockaddr_storage sockdata;
uint8_t* data = NULL;
size_t data_len = 0;
struct timeval timeout = { 5, 0 };
/* get first upstream server */
getdns_list_get_dict(context->upstream_list, 0, &nameserver);
if (!nameserver) {
getdns_list_get_dict(context->upstream_list, 0, &ip_dict);
if (!ip_dict) {
return GETDNS_RETURN_GENERIC_ERROR;
}
/* setup socket */
if (dict_to_sockaddr(nameserver, &sockdata) != GETDNS_RETURN_GOOD) {
/* get the nameserver */
getdns_nameserver *ns = nameserver_new_from_ip_dict(context, ip_dict);
if (!ns) {
return GETDNS_RETURN_GENERIC_ERROR;
}
evutil_socket_t sock = socket(sockdata.ss_family, SOCK_DGRAM, 0);
evutil_make_socket_closeonexec(sock);
evutil_make_socket_nonblocking(sock);
request->current_req->ns = ns;
/* schedule on the loop */
ns->event = event_new(context->event_base, request->current_req->ns->socket,
EV_READ | EV_TIMEOUT,
dns_req_callback, request);
event_add(ns->event, &timeout);
/* send data */
ldns_pkt *pkt = request->current_req->pkt;
ldns_pkt2wire(&data, pkt, &data_len);
send(ns->socket, data, data_len, MSG_DONTWAIT);
free(data);
return GETDNS_RETURN_GOOD;
}

View File

@ -28,4 +28,70 @@
* THE SOFTWARE.
*/
#include "types-internal.h"
#include "util-internal.h"
/* useful macros */
#define gd_malloc(sz) context->memory_allocator(sz)
#define gd_free(ptr) context->memory_deallocator(ptr)
getdns_nameserver* nameserver_new_from_ip_dict(getdns_context_t context,
getdns_dict* ip_dict) {
if (!context || !ip_dict) {
return NULL;
}
struct sockaddr_storage sockdata;
/* setup socket */
if (dict_to_sockaddr(ip_dict, &sockdata) != GETDNS_RETURN_GOOD) {
return NULL;
}
getdns_nameserver *result = gd_malloc(sizeof(getdns_nameserver));
if (!result) {
return NULL;
}
memset(result, 0, sizeof(getdns_nameserver));
result->context = context;
/* create socket */
evutil_socket_t sock = socket(sockdata.ss_family, SOCK_DGRAM, 0);
evutil_make_socket_closeonexec(sock);
evutil_make_socket_nonblocking(sock);
result->address = sockdata;
result->socket = sock;
int connected = -1;
if (sockdata.ss_family == AF_INET) {
connected = connect(sock, (struct sockaddr *) &sockdata, sizeof(struct sockaddr_in));
} else if (sockdata.ss_family == AF_INET6) {
connected = connect(sock, (struct sockaddr *) &sockdata, sizeof(struct sockaddr_in6));
}
if (connected != 0) {
// sad
nameserver_free(result);
result= NULL;
}
return result;
}
void nameserver_free(getdns_nameserver* nameserver) {
if (!nameserver) {
return;
}
if (nameserver->event) {
event_del(nameserver->event);
event_free(nameserver->event);
}
getdns_context_t context = nameserver->context;
evutil_closesocket(nameserver->socket);
gd_free(nameserver);
}
/* TODO */
getdns_dict* nameserver_to_dict(getdns_nameserver* nameserver) {
return NULL;
}

View File

@ -49,8 +49,7 @@ void network_req_free(getdns_network_req* net_req) {
getdns_network_req* network_req_new(getdns_context_t context,
const char* name,
uint16_t request_type,
struct getdns_dict* extensions,
getdns_transaction_t *transaction_id) {
struct getdns_dict* extensions) {
getdns_network_req *net_req = NULL;
ldns_pkt *pkt = NULL;
net_req = gd_malloc(sizeof(getdns_network_req));
@ -70,10 +69,6 @@ getdns_network_req* network_req_new(getdns_context_t context,
return NULL;
}
net_req->pkt = pkt;
net_req->trans_id = ldns_pkt_id(pkt);
if (transaction_id) {
*transaction_id = net_req->trans_id;
}
return net_req;
}
@ -106,12 +101,17 @@ getdns_dns_req* dns_req_new(getdns_context_t context,
/* create the initial network request */
net_req = network_req_new(context, name, request_type,
extensions, transaction_id);
extensions);
if (!net_req) {
dns_req_free(result);
result = NULL;
}
result->trans_id = ldns_pkt_id(net_req->pkt);
if (transaction_id) {
*transaction_id = result->trans_id;
}
result->current_req = net_req;
net_req->owner = result;

View File

@ -46,9 +46,9 @@ typedef struct getdns_nameserver {
int failed_times; /* number of times which we have given this server a chance */
int timedout; /* number of times in a row a request has timed out */
struct event event;
struct event* event;
struct event timeout_event; /* used to keep the timeout for */
/* when we next probe this server. */
/* Valid if state == 0 */
/* Outstanding probe request for this nameserver, if any */
@ -76,12 +76,7 @@ typedef struct getdns_network_req {
int tx_count; /* the number of times that this packet has been sent */
/* not owned */
struct nameserver *ns; /* the server which we last sent it (unused) */
getdns_dict *upstream_server;
struct event timeout_event;
getdns_transaction_t trans_id; /* the transaction id */
getdns_nameserver *ns; /* the server which we sent to */
unsigned transmit_me :1; /* needs to be transmitted */
@ -102,6 +97,8 @@ typedef struct getdns_dns_req {
/* callback data */
getdns_callback_t user_callback;
void *user_pointer;
getdns_transaction_t trans_id; /* the transaction id */
int pending_cb; /* Waiting for its callback to be invoked; not
@ -119,8 +116,7 @@ void network_req_free(getdns_network_req* net_req);
getdns_network_req* network_req_new(getdns_context_t context,
const char* name,
uint16_t request_type,
struct getdns_dict* extensions,
getdns_transaction_t *transaction_id);
struct getdns_dict* extensions);
/* dns request utils */
@ -134,9 +130,12 @@ getdns_dns_req* dns_req_new(getdns_context_t context,
void dns_req_free(getdns_dns_req* req);
/* nameserver utils */
getdns_nameserver* nameserver_new_from_ip_dict(getdns_dict* ip_dict);
getdns_nameserver* nameserver_new_from_ip_dict(getdns_context_t context,
getdns_dict* ip_dict);
void nameserver_free(getdns_nameserver* nameserver);
getdns_dict* nameserver_to_dict(getdns_nameserver* nameserver);
#endif

View File

@ -30,6 +30,15 @@
#include "util-internal.h"
getdns_return_t getdns_dict_util_set_string(getdns_dict* dict, char* name,
char* value) {
char data[strlen(value) + 1];
data[strlen(value)] = 0;
memcpy(data, value, strlen(value));
getdns_bindata type_bin = { strlen(value) + 1, (uint8_t*) data };
return getdns_dict_set_bindata(dict, name, &type_bin);
}
getdns_return_t dict_to_sockaddr(getdns_dict* ns, struct sockaddr_storage* output) {
struct getdns_bindata *address_type = NULL;
struct getdns_bindata *address_data = NULL;
@ -42,7 +51,7 @@ getdns_return_t dict_to_sockaddr(getdns_dict* ns, struct sockaddr_storage* outpu
if (!address_type || !address_data) {
return GETDNS_RETURN_GENERIC_ERROR;
}
if (strcmp((char*) address_type->data, GETDNS_STR_IPV4)) {
if (strcmp((char*) address_type->data, GETDNS_STR_IPV4) == 0) {
/* data is an in_addr_t */
struct sockaddr_in* addr = (struct sockaddr_in*) output;
addr->sin_family = AF_INET;
@ -75,5 +84,14 @@ ldns_pkt *create_new_pkt(getdns_context_t context,
return pkt;
}
getdns_dict *create_getdns_response(ldns_pkt* pkt) {
char* data = ldns_pkt2str(pkt);
getdns_dict* result = getdns_dict_create();
getdns_bindata bindata = {
strlen(data), (uint8_t*) data
};
getdns_dict_set_bindata(result, "pkt", &bindata);
free(data);
return result;
}

View File

@ -38,3 +38,10 @@ ldns_pkt *create_new_pkt(getdns_context_t context,
const char* name,
uint16_t request_type,
struct getdns_dict* extensions);
getdns_dict *create_getdns_response(ldns_pkt* pkt);
/* dict util */
getdns_return_t getdns_dict_util_set_string(getdns_dict* dict, char* name,
char* value);