Adding cancel and reply formatting

This commit is contained in:
Neel Goyal 2013-10-17 19:45:25 -04:00
parent da8dad5913
commit 9c75239aaa
9 changed files with 491 additions and 55 deletions

View File

@ -822,6 +822,23 @@ getdns_extension_set_libevent_base(
return GETDNS_RETURN_GOOD;
} /* getdns_extension_set_libevent_base */
/* cancel the request */
static void cancel_dns_req(getdns_dns_req* req) {
getdns_network_req* netreq = req->first_req;
while (netreq) {
if (netreq->state == NET_REQ_IN_FLIGHT) {
/* for ev based ub, this should always prevent
* the callback from firing */
ub_cancel(req->unbound, netreq->unbound_id);
netreq->state = NET_REQ_CANCELED;
} else if (netreq->state == NET_REQ_NOT_SENT) {
netreq->state = NET_REQ_CANCELED;
}
netreq = netreq->next;
}
req->canceled = 1;
}
/*
* getdns_cancel_callback
*
@ -832,8 +849,35 @@ getdns_cancel_callback(
getdns_transaction_t transaction_id
)
{
UNUSED_PARAM(context);
UNUSED_PARAM(transaction_id);
getdns_dns_req *req = NULL;
getdns_callback_t cb = NULL;
void* user_pointer = NULL;
/* delete the node from the tree */
ldns_rbnode_t* node = ldns_rbtree_delete(context->outbound_requests,
&transaction_id);
if (!node) {
return GETDNS_RETURN_UNKNOWN_TRANSACTION;
}
req = (getdns_dns_req*) node->data;
/* do the cancel */
cancel_dns_req(req);
cb = req->user_callback;
user_pointer = req->user_pointer;
/* clean up */
context->memory_deallocator(node);
dns_req_free(req);
/* fire callback */
cb(context,
GETDNS_CALLBACK_CANCEL,
NULL,
user_pointer,
transaction_id);
return GETDNS_RETURN_GOOD;
} /* getdns_cancel_callback */

View File

@ -1,7 +1,7 @@
/**
*
* /brief getdns core functions
*
*
* This is the meat of the API
* Originally taken from the getdns API description pseudo implementation.
*
@ -15,10 +15,10 @@
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@ -30,6 +30,8 @@
#include <getdns/getdns.h>
#include <stdio.h>
#include <arpa/inet.h>
#include <util-internal.h>
/* stuff to make it compile pedantically */
#define UNUSED_PARAM(x) ((void)(x))
@ -62,7 +64,32 @@ char *
getdns_display_ip_address(
struct getdns_bindata *bindata_of_ipv4_or_ipv6_address
)
{ UNUSED_PARAM(bindata_of_ipv4_or_ipv6_address); return NULL; }
{
char buff[256];
if (!bindata_of_ipv4_or_ipv6_address ||
bindata_of_ipv4_or_ipv6_address->size == 0 ||
!bindata_of_ipv4_or_ipv6_address->data) {
return NULL;
}
if (bindata_of_ipv4_or_ipv6_address->size == 4) {
const char* ipStr = inet_ntop(AF_INET,
bindata_of_ipv4_or_ipv6_address->data,
buff,
256);
if (ipStr) {
return strdup(ipStr);
}
} else if (bindata_of_ipv4_or_ipv6_address->size == 16) {
const char* ipStr = inet_ntop(AF_INET6,
bindata_of_ipv4_or_ipv6_address->data,
buff,
256);
if (ipStr) {
return strdup(ipStr);
}
}
return NULL;
}
getdns_return_t
getdns_strerror(getdns_return_t err, char *buf, size_t buflen)

View File

@ -106,28 +106,41 @@ static void handle_dns_request_complete(getdns_dns_req* dns_req) {
/* clean up the request */
getdns_context_clear_outbound_request(dns_req);
dns_req_free(dns_req);
if (response) {
cb(context,
GETDNS_CALLBACK_COMPLETE,
response,
user_arg,
trans_id);
} else {
cb(context,
GETDNS_CALLBACK_ERROR,
NULL,
user_arg,
trans_id);
}
cb(context,
GETDNS_CALLBACK_COMPLETE,
response,
user_arg,
trans_id);
}
static int submit_network_request(getdns_network_req* netreq) {
getdns_dns_req *dns_req = netreq->owner;
netreq->state = NET_REQ_IN_FLIGHT;
return ub_resolve_event(dns_req->unbound,
int r = ub_resolve_event(dns_req->unbound,
dns_req->name,
netreq->request_type,
netreq->request_class,
netreq,
ub_resolve_callback,
&(netreq->unbound_id));
netreq->state = NET_REQ_IN_FLIGHT;
return r;
}
static void ub_resolve_callback(void* arg, int err, ldns_buffer* result, int sec, char* bogus) {
getdns_network_req* netreq = (getdns_network_req*) arg;
/* if netreq->state == NET_REQ_NOT_SENT here, that implies
* that ub called us back immediately - probably from a local file.
* This most likely means that getdns_general has not returned
*/
netreq->state = NET_REQ_FINISHED;
if (err) {
handle_network_request_error(netreq, err);
@ -153,13 +166,13 @@ static void ub_resolve_callback(void* arg, int err, ldns_buffer* result, int sec
getdns_return_t
getdns_general_ub(struct ub_ctx* unbound,
getdns_context_t context,
const char *name,
uint16_t request_type,
struct getdns_dict *extensions,
void *userarg,
getdns_transaction_t *transaction_id,
getdns_callback_t callbackfn) {
getdns_context_t context,
const char *name,
uint16_t request_type,
struct getdns_dict *extensions,
void *userarg,
getdns_transaction_t *transaction_id,
getdns_callback_t callbackfn) {
getdns_return_t gr;
int r;
@ -182,10 +195,6 @@ getdns_general_ub(struct ub_ctx* unbound,
req->user_pointer = userarg;
req->user_callback = callbackfn;
/* TODO:
handle immediate callback
*/
if (transaction_id) {
*transaction_id = req->trans_id;
}
@ -221,7 +230,7 @@ getdns_general_ub(struct ub_ctx* unbound,
/* Can't do async without an event loop
* or callback
*/
return GETDNS_RETURN_BAD_CONTEXT;
return GETDNS_RETURN_BAD_CONTEXT;
}
return getdns_general_ub(context->unbound_async,

View File

@ -252,6 +252,38 @@ struct event_base;
#define GETDNS_STR_PORT "port"
#define GETDNS_STR_EXTENSION_RETURN_BOTH_V4_AND_V6 "return_both_v4_and_v6"
#define GETDNS_STR_KEY_STATUS "status"
#define GETDNS_STR_KEY_REPLIES_TREE "replies_tree"
#define GETDNS_STR_KEY_REPLIES_FULL "replies_full"
#define GETDNS_STR_KEY_JUST_ADDRS "just_address_answers"
#define GETDNS_STR_KEY_CANONICAL_NM "canonical_name"
#define GETDNS_STR_KEY_ANSWER_TYPE "answer_type"
#define GETDNS_STR_KEY_INTERM_ALIASES "intermediate_aliases"
#define GETDNS_STR_KEY_NAME "name"
#define GETDNS_STR_KEY_HEADER "header"
#define GETDNS_STR_KEY_QUESTION "question"
#define GETDNS_STR_KEY_ANSWER "answer"
#define GETDNS_STR_KEY_ID "id"
#define GETDNS_STR_KEY_QR "qr"
#define GETDNS_STR_KEY_OPC "opcode"
#define GETDNS_STR_KEY_TYPE "type"
#define GETDNS_STR_KEY_CLASS "class"
#define GETDNS_STR_KEY_TTL "ttl"
#define GETDNS_STR_KEY_RDATA "rdata"
#define GETDNS_STR_KEY_V4_ADDR "ipv4_address"
#define GETDNS_STR_KEY_V6_ADDR "ipv6_address"
#define GETDNS_STR_KEY_RDATA_RAW "rdata_raw"
#define GETDNS_STR_KEY_AUTHORITY "authority"
#define GETDNS_STR_KEY_ADDITIONAL "additional"
#define GETDNS_STR_KEY_QTYPE "qtype"
#define GETDNS_STR_KEY_QCLASS "qclass"
#define GETDNS_STR_KEY_QNAME "qname"
/** @}
*/

View File

@ -30,6 +30,7 @@
#include "types-internal.h"
#include "util-internal.h"
#include <unbound.h>
/* useful macros */
#define gd_malloc(sz) context->memory_allocator(sz)
@ -111,6 +112,7 @@ getdns_dns_req* dns_req_new(getdns_context_t context,
result->name = strdup(name);
result->context = context;
result->unbound = unbound;
result->canceled = 0;
result->current_req = NULL;
result->first_req = NULL;
result->trans_id = ldns_get_random();

View File

@ -1,7 +1,7 @@
/**
*
* /brief getdns core functions for synchronous use
*
*
* Originally taken from the getdns API description pseudo implementation.
*
*/
@ -14,10 +14,10 @@
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@ -58,7 +58,7 @@ static void sync_callback_func(getdns_context_t context,
static void * request_thread_start(void *arg) {
struct sync_request_data *req_data = arg;
req_data->response_status = getdns_general_ub(req_data->context->unbound_sync,
req_data->context,
req_data->name,
@ -67,7 +67,7 @@ static void * request_thread_start(void *arg) {
req_data,
NULL,
sync_callback_func);
event_base_dispatch(req_data->context->event_base_sync);
return NULL;
}
@ -94,7 +94,7 @@ getdns_general_sync(
GETDNS_RETURN_GOOD,
response
};
/* create the thread */
int ret = pthread_attr_init(&attr);
if (ret != 0) {
@ -133,7 +133,7 @@ getdns_address_sync(
getdns_dict_set_int(extensions,
GETDNS_STR_EXTENSION_RETURN_BOTH_V4_AND_V6,
GETDNS_EXTENSION_TRUE);
getdns_return_t result =
getdns_general_sync(context, name, GETDNS_RRTYPE_A,
extensions, response_length, response);
@ -163,7 +163,7 @@ getdns_service_sync(
struct getdns_dict **response
)
{
return getdns_general_sync(context, name, GETDNS_RRTYPE_SRV, extensions,
response_length, response);

View File

@ -42,14 +42,10 @@ void this_callbackfn(struct getdns_context_t *this_context,
{
if (this_callback_type == GETDNS_CALLBACK_COMPLETE) /* This is a callback with data */
{
getdns_bindata* bindata = NULL;
getdns_dict_get_bindata(this_response, "pkt", &bindata);
if (bindata) {
char* data = (char*) bindata->data;
data[bindata->size] = 0;
memcpy(data, bindata->data, bindata->size);
fprintf(stdout, "The packet %s\n", data);
}
char* res = getdns_pretty_print_dict(this_response);
fprintf(stdout, "%s", res);
getdns_dict_destroy(this_response);
}
else if (this_callback_type == GETDNS_CALLBACK_CANCEL)
fprintf(stderr, "The callback with ID %lld was cancelled. Exiting.", this_transaction_id);
@ -82,7 +78,7 @@ main()
const char * this_name = "www.google.com";
char* this_userarg = "somestring"; // Could add things here to help identify this call
getdns_transaction_t this_transaction_id = 0;
/* Make the call */
getdns_return_t dns_request_return = getdns_address(this_context, this_name,
NULL, this_userarg, &this_transaction_id, this_callbackfn);

View File

@ -42,7 +42,8 @@ struct ub_ctx;
typedef enum network_req_state_enum {
NET_REQ_NOT_SENT,
NET_REQ_IN_FLIGHT,
NET_REQ_FINISHED
NET_REQ_FINISHED,
NET_REQ_CANCELED
} network_req_state;
/**
@ -77,6 +78,9 @@ typedef struct getdns_dns_req {
/* name */
char *name;
/* canceled flag */
int canceled;
/* current network request */
struct getdns_network_req *current_req;
@ -96,7 +100,8 @@ typedef struct getdns_dns_req {
getdns_callback_t user_callback;
void *user_pointer;
getdns_transaction_t trans_id; /* the transaction id */
/* the transaction id */
getdns_transaction_t trans_id;
} getdns_dns_req;
@ -121,7 +126,4 @@ getdns_dns_req* dns_req_new(getdns_context_t context,
void dns_req_free(getdns_dns_req* req);
/* cancel the request */
getdns_return_t dns_req_cancel(getdns_dns_req* req);
#endif

View File

@ -34,6 +34,9 @@
getdns_return_t getdns_dict_util_set_string(getdns_dict* dict, char* name,
const char* value) {
/* account for the null term */
if (value == NULL) {
return GETDNS_RETURN_WRONG_TYPE_REQUESTED;
}
getdns_bindata type_bin = { strlen(value) + 1, (uint8_t*) value };
return getdns_dict_set_bindata(dict, name, &type_bin);
}
@ -114,15 +117,336 @@ getdns_return_t sockaddr_to_dict(struct sockaddr_storage* address, getdns_dict**
return GETDNS_RETURN_GOOD;
}
getdns_dict *create_getdns_response(struct getdns_dns_req* completed_request) {
ldns_pkt* pkt = completed_request->first_req->result;
char* data = ldns_pkt2str(pkt);
/* result must be freed */
static char* convert_rdf_to_str(ldns_rdf* rdf) {
if (ldns_rdf_get_type(rdf) == LDNS_RDF_TYPE_DNAME) {
ldns_dname2canonical(rdf);
}
return ldns_rdf2str(rdf);
}
/* create the header dict */
static getdns_dict *create_reply_header_dict(ldns_pkt* reply) {
/* { "id": 23456, "qr": 1, "opcode": 0, ... }, */
int r = 0;
getdns_dict* result = getdns_dict_create();
getdns_bindata bindata = {
strlen(data), (uint8_t*) data
};
getdns_dict_set_bindata(result, "pkt", &bindata);
free(data);
if (!result) {
return NULL;
}
/* cheat since we know GETDNS_RETURN_GOOD == 0 */
r |= getdns_dict_set_int(result, GETDNS_STR_KEY_ID, ldns_pkt_id(reply));
r |= getdns_dict_set_int(result, GETDNS_STR_KEY_QR, ldns_pkt_qr(reply));
r |= getdns_dict_set_int(result, GETDNS_STR_KEY_OPC, (int) ldns_pkt_get_opcode(reply));
if (r != 0) {
getdns_dict_destroy(result);
result = NULL;
}
return result;
}
static getdns_dict *create_reply_question_dict(ldns_pkt* reply) {
/* { "qname": <bindata for "www.example.com">, "qtype": 1, "qclass": 1 } */
int r = 0;
ldns_rr *question = NULL;
char* qname;
getdns_dict* result = getdns_dict_create();
if (!result) {
return NULL;
}
question = ldns_rr_list_rr(ldns_pkt_question(reply), 0);
r |= getdns_dict_set_int(result, GETDNS_STR_KEY_QTYPE, (int) ldns_rr_get_type(question));
r |= getdns_dict_set_int(result, GETDNS_STR_KEY_QCLASS, (int) ldns_rr_get_class(question));
qname = convert_rdf_to_str(ldns_rr_owner(question));
if (qname) {
r |= getdns_dict_util_set_string(result, GETDNS_STR_KEY_QNAME, qname);
free(qname);
} else {
r = 1;
}
if (r != 0) {
getdns_dict_destroy(result);
result = NULL;
}
return result;
}
static getdns_dict *create_dict_from_rdf(ldns_rdf* rdf) {
/*
create a dict w/ rdata_raw and special fields if needed
i.e.
{
"ipv4_address": <bindata of 0x0a0b0c01>
"rdata_raw": <bindata of 0x0a0b0c01>
}
*/
int r = 0;
getdns_bindata rbin = { ldns_rdf_size(rdf), ldns_rdf_data(rdf) };
getdns_dict* result = getdns_dict_create();
r |= getdns_dict_set_bindata(result, GETDNS_STR_KEY_RDATA_RAW, &rbin);
if (ldns_rdf_get_type(rdf) == LDNS_RDF_TYPE_AAAA) {
r |= getdns_dict_set_bindata(result, GETDNS_STR_KEY_V6_ADDR, &rbin);
} else if (ldns_rdf_get_type(rdf) == LDNS_RDF_TYPE_A) {
r |= getdns_dict_set_bindata(result, GETDNS_STR_KEY_V4_ADDR, &rbin);
}
if (r != 0) {
getdns_dict_destroy(result);
result = NULL;
}
return result;
}
static getdns_dict *create_dict_from_rr(ldns_rr* rr) {
/*
{
"name": <bindata for "www.example.com">,
"type": 1,
"class": 1,
"ttl": 33000,
"rdata":
{
"ipv4_address": <bindata of 0x0a0b0c01>
"rdata_raw": <bindata of 0x0a0b0c01>
}
}
*/
int r = 0;
char * name = NULL;
getdns_dict *result = getdns_dict_create();
size_t rd_count = ldns_rr_rd_count(rr);
ldns_rdf* owner = ldns_rr_owner(rr);
r |= getdns_dict_set_int(result, GETDNS_STR_KEY_TYPE, (int) ldns_rr_get_type(rr));
r |= getdns_dict_set_int(result, GETDNS_STR_KEY_CLASS, (int) ldns_rr_get_class(rr));
r |= getdns_dict_set_int(result, GETDNS_STR_KEY_TTL, ldns_rr_ttl(rr));
if (owner) {
name = convert_rdf_to_str(owner);
if (name) {
r |= getdns_dict_util_set_string(result, GETDNS_STR_KEY_NAME, name);
free(name);
} else {
r = 1;
}
}
/* create rdatas */
if (rd_count >= 1) {
getdns_dict* rdata = create_dict_from_rdf(ldns_rr_rdf(rr, 0));
r |= getdns_dict_set_dict(result, GETDNS_STR_KEY_RDATA, rdata);
}
/* TODO - if more than one, is rdata a list? */
if (r != 0) {
getdns_dict_destroy(result);
result = NULL;
}
return result;
}
/* helper to convert an rr_list to getdns_list.
returns a list of objects where each object
is a result from create_dict_from_rr */
static getdns_list *create_list_from_rr_list(ldns_rr_list* rr_list) {
size_t i = 0;
size_t idx = 0;
int r = 0;
getdns_list *result = getdns_list_create();
for (i = 0; i < ldns_rr_list_rr_count(rr_list); ++i) {
ldns_rr *rr = ldns_rr_list_rr(rr_list, i);
r |= getdns_list_add_item(result, &idx);
r |= getdns_list_set_dict(result, idx, create_dict_from_rr(rr));
}
if (r != 0) {
getdns_list_destroy(result);
result = NULL;
}
return result;
}
/* helper to add the ipv4 or ipv6 bin data to the list of addrs */
static getdns_return_t add_only_addresses(getdns_list* addrs, ldns_rr_list* rr_list) {
int r = 0;
size_t i = 0;
for (i = 0; i < ldns_rr_list_rr_count(rr_list); ++i) {
ldns_rr *rr = ldns_rr_list_rr(rr_list, i);
size_t j = 0;
size_t rd_count = ldns_rr_rd_count(rr);
for (j = 0; j < rd_count; ++j) {
size_t item_idx = 0;
ldns_rdf* rdf = ldns_rr_rdf(rr, j);
getdns_bindata rbin = { ldns_rdf_size(rdf), ldns_rdf_data(rdf) };
r |= getdns_list_add_item(addrs, &item_idx);
r |= getdns_list_set_bindata(addrs, item_idx, &rbin);
}
}
return r;
}
static getdns_dict *create_reply_dict(getdns_network_req* req,
getdns_list *just_addrs) {
/* turn a packet into this glorious structure
{ # This is the first reply
"header": { "id": 23456, "qr": 1, "opcode": 0, ... },
"question": { "qname": <bindata for "www.example.com">, "qtype": 1, "qclass": 1 },
"answer":
[
{
"name": <bindata for "www.example.com">,
"type": 1,
"class": 1,
"ttl": 33000,
"rdata":
{
"ipv4_address": <bindata of 0x0a0b0c01>
"rdata_raw": <bindata of 0x0a0b0c01>
}
}
],
"authority":
[
{
"name": <bindata for "ns1.example.com">,
"type": 1,
"class": 1,
"ttl": 600,
"rdata":
{
"ipv4_address": <bindata of 0x65439876>
"rdata_raw": <bindata of 0x65439876>
}
}
]
"additional": [],
"canonical_name": <bindata for "www.example.com">,
"answer_type": GETDNS_NAMETYPE_DNS
}
*/
int r = 0;
ldns_pkt *reply = req->result;
ldns_rr_list *rr_list = NULL;
ldns_rr* question = NULL;
getdns_dict *subdict = NULL;
getdns_list *sublist = NULL;
char* name = NULL;
getdns_dict *result = getdns_dict_create();
if (!result) {
return NULL;
}
/* header */
subdict = create_reply_header_dict(reply);
r |= getdns_dict_set_dict(result, GETDNS_STR_KEY_HEADER, subdict);
getdns_dict_destroy(subdict);
/* question */
subdict = create_reply_question_dict(reply);
r |= getdns_dict_set_dict(result, GETDNS_STR_KEY_QUESTION, subdict);
getdns_dict_destroy(subdict);
/* answers */
rr_list = ldns_pkt_answer(reply);
sublist = create_list_from_rr_list(rr_list);
r |= getdns_dict_set_list(result, GETDNS_STR_KEY_ANSWER, sublist);
getdns_list_destroy(sublist);
if ((req->request_type == GETDNS_RRTYPE_A ||
req->request_type == GETDNS_RRTYPE_AAAA) &&
just_addrs != NULL) {
/* add to just addrs */
r |= add_only_addresses(just_addrs, rr_list);
}
/* authority */
rr_list = ldns_pkt_authority(reply);
sublist = create_list_from_rr_list(rr_list);
r |= getdns_dict_set_list(result, GETDNS_STR_KEY_AUTHORITY, sublist);
getdns_list_destroy(sublist);
/* additional */
rr_list = ldns_pkt_additional(reply);
sublist = create_list_from_rr_list(rr_list);
r |= getdns_dict_set_list(result, GETDNS_STR_KEY_ADDITIONAL, sublist);
getdns_list_destroy(sublist);
/* other stuff */
r |= getdns_dict_set_int(result, GETDNS_STR_KEY_ANSWER_TYPE, GETDNS_NAMETYPE_DNS);
question = ldns_rr_list_rr(ldns_pkt_question(reply), 0);
name = convert_rdf_to_str(ldns_rr_owner(question));
if (name) {
r |= getdns_dict_util_set_string(result, GETDNS_STR_KEY_CANONICAL_NM, name);
free(name);
} else {
r |= 1;
}
if (r != 0) {
getdns_dict_destroy(result);
result = NULL;
}
return result;
}
static char* get_canonical_name(const char* name) {
ldns_rdf* rdf = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, name);
if (!rdf) {
return NULL;
}
char* result = convert_rdf_to_str(rdf);
ldns_rdf_free(rdf);
return result;
}
getdns_dict *create_getdns_response(struct getdns_dns_req* completed_request) {
getdns_dict* result = getdns_dict_create();
getdns_list* replies_full = getdns_list_create();
getdns_list* just_addrs = NULL;
getdns_list* replies_tree = getdns_list_create();
getdns_network_req *netreq = completed_request->first_req;
int r = 0;
if (completed_request->first_req->request_class == GETDNS_RRTYPE_A ||
completed_request->first_req->request_class == GETDNS_RRTYPE_AAAA) {
just_addrs = getdns_list_create();
}
r |= getdns_dict_set_int(result, GETDNS_STR_KEY_STATUS, GETDNS_RESPSTATUS_GOOD);
r |= getdns_dict_util_set_string(result, GETDNS_STR_KEY_CANONICAL_NM, get_canonical_name(completed_request->name));
r |= getdns_dict_set_int(result, GETDNS_STR_KEY_ANSWER_TYPE, GETDNS_NAMETYPE_DNS);
while (netreq) {
getdns_bindata full_data;
full_data.data = NULL;
full_data.size = 0;
ldns_pkt *pkt = netreq->result;
ldns_status s = ldns_pkt2wire(&(full_data.data), pkt, &(full_data.size));
size_t idx = 0;
/* reply tree */
getdns_dict *reply = create_reply_dict(netreq, just_addrs);
r |= getdns_list_add_item(replies_tree, &idx);
r |= getdns_list_set_dict(replies_tree, idx, reply);
/* buffer */
if (s == LDNS_STATUS_OK) {
r |= getdns_list_add_item(replies_full, &idx);
r |= getdns_list_set_bindata(replies_full, idx, &full_data);
free(full_data.data);
} else {
r = 1;
break;
}
netreq = netreq->next;
}
r |= getdns_dict_set_list(result, GETDNS_STR_KEY_REPLIES_TREE, replies_tree);
r |= getdns_dict_set_list(result, GETDNS_STR_KEY_REPLIES_FULL, replies_full);
if (just_addrs) {
r |= getdns_dict_set_list(result, GETDNS_STR_KEY_JUST_ADDRS, just_addrs);
}
if (r != 0) {
getdns_dict_destroy(result);
result = NULL;
}
return result;
}