Intermediate commit of context.h, mdns.[ch]

This commit is contained in:
Christian Huitema 2017-01-20 19:44:05 -08:00
parent abd0244aba
commit 31eee9c7d1
3 changed files with 168 additions and 0 deletions

View File

@ -287,6 +287,22 @@ struct getdns_context {
/* We need to run WSAStartup() to be able to use getaddrinfo() */ /* We need to run WSAStartup() to be able to use getaddrinfo() */
WSADATA wsaData; WSADATA wsaData;
#endif #endif
/* MDNS */
#ifdef HAVE_MDNS_SUPPORT
/*
* If supporting MDNS, context may be instantiated either in basic mode
* or in full mode. If working in extended mode, two multicast sockets are
* left open, for IPv4 and IPv6. Data can be received on either socket.
* The context also keeps a list of open queries, characterized by a
* name and an RR type.
*/
int mdns_extended_support;
int fd_mdns_v4;
int fd_mdns_v6;
_getdns_rbtree_t mdns_continuous_queries_by_name_rrtype;
#endif /* HAVE_MDNS_SUPPORT */
}; /* getdns_context */ }; /* getdns_context */
/** internal functions **/ /** internal functions **/

View File

@ -78,6 +78,131 @@ static uint8_t mdns_suffix_b_e_f_ip6_arpa[] = {
7, 'i', 'p', 'v', '6', 7, 'i', 'p', 'v', '6',
4, 'a', 'r', 'p', 'a', 0 }; 4, 'a', 'r', 'p', 'a', 0 };
/*
* Compare function for the netreq_by_query_id,
* used in the red-black tree of all netreq by continuous query.
*/
static int mdns_cmp_netreq_by_query_id(const void * id1, const void * id2)
{
int ret = 0;
if (id1 != id2)
{
ret = (((intptr_t)id1) < ((intptr_t)id2)) ? -1 : 1;
}
return ret;
}
/*
* Compare function for the getdns_mdns_known_record type,
* used in the red-black tree of known records per query.
*/
static int mdns_cmp_known_records(const void * nkr1, const void * nkr2)
{
int ret = 0;
getdns_mdns_known_record * kr1 = (getdns_mdns_known_record *)nkr1;
getdns_mdns_known_record * kr2 = (getdns_mdns_known_record *)nkr2;
if (kr1->record_length != kr2->record_length)
{
ret = (kr1->record_length < kr2->record_length) ? -1 : 1;
}
else
{
ret = memcmp((const void*)kr1->record_data, (const void*)kr2->record_data, kr1->record_length);
}
return ret;
}
/*
* Compare function for the mdns_continuous_query_by_name_rrtype,
* used in the red-black tree of all ongoing queries.
*/
static int mdns_cmp_continuous_queries_by_name_rrtype(const void * nqnr1, const void * nqnr2)
{
int ret = 0;
getdns_mdns_continuous_query * qnr1 = (getdns_mdns_continuous_query *)nqnr1;
getdns_mdns_continuous_query * qnr2 = (getdns_mdns_continuous_query *)nqnr2;
if (qnr1->request_class != qnr2->request_class)
{
ret = (qnr1->request_class < qnr2->request_class) ? -1 : 1;
}
else if (qnr1->request_type != qnr2->request_type)
{
ret = (qnr1->request_type < qnr2->request_type) ? -1 : 1;
}
else if (qnr1->name_len != qnr2->name_len)
{
ret = (qnr1->name_len < qnr2->name_len) ? -1 : 1;
}
else
{
ret = memcmp((void*)qnr1->name, (void*)qnr2->name, qnr1->name_len);
}
return ret;
}
/*
* Initialize a continuous query from netreq
*/
static int mdns_initialize_continuous_request(getdns_network_req *netreq)
{
int ret = 0;
getdns_mdns_continuous_query temp_query, *continuous_query, *inserted_query;
getdns_dns_req *dnsreq = netreq->owner;
/*
* Fill the target request, but only initialize name and request_type
*/
temp_query.request_class = dnsreq->request_class;
temp_query.request_type = netreq->request_type;
temp_query.name_len = dnsreq->name_len;
/* TODO: check that dnsreq is in canonical form */
memcpy(temp_query.name, dnsreq->name, dnsreq->name_len);
/*
* Check whether the continuous query is already in the RB tree.
* if there is not, create one.
* TODO: should lock the context object when doing that.
*/
continuous_query = (getdns_mdns_continuous_query *)
_getdns_rbtree_search(&dnsreq->context->mdns_continuous_queries_by_name_rrtype, &temp_query);
if (continuous_query == NULL)
{
continuous_query = (getdns_mdns_continuous_query *)
GETDNS_MALLOC(dnsreq->context->mf, getdns_mdns_continuous_query);
if (continuous_query != NULL)
{
continuous_query->request_class = temp_query.request_class;
continuous_query->request_type = temp_query.request_type;
continuous_query->name_len = temp_query.name_len;
memcpy(continuous_query->name, temp_query.name, temp_query.name_len);
_getdns_rbtree_init(&continuous_query->known_records_by_value, mdns_cmp_known_records);
/* Tracking of network requests on this socket */
_getdns_rbtree_init(&continuous_query->netreq_by_query_id, mdns_cmp_netreq_by_query_id);
/* Add the new continuous query to the context */
inserted_query = _getdns_rbtree_insert(&dnsreq->context->mdns_continuous_queries_by_name_rrtype,
continuous_query);
if (inserted_query == NULL)
{
/* Weird. This can only happen in a race condition */
GETDNS_FREE(dnsreq->context->mf, continuous_query);
ret = GETDNS_RETURN_GENERIC_ERROR;
}
}
else
{
ret = GETDNS_RETURN_MEMORY_ERROR;
}
}
/* To do: insert netreq into query list */
/* to do: queue message request to socket */
return ret;
}
/* TODO: actualy delete what is required.. */ /* TODO: actualy delete what is required.. */
static void static void
mdns_cleanup(getdns_network_req *netreq) mdns_cleanup(getdns_network_req *netreq)

View File

@ -30,6 +30,33 @@ _getdns_submit_mdns_request(getdns_network_req *netreq);
getdns_return_t getdns_return_t
_getdns_mdns_namespace_check(getdns_dns_req *dnsreq); _getdns_mdns_namespace_check(getdns_dns_req *dnsreq);
/*
* data structure for continuous queries
*/
typedef struct getdns_mdns_known_record
{
uint32_t ttl; /* todo: should this be an expiration date? */
uint8_t * record_data;
int record_length;
} getdns_mdns_known_record;
typedef struct getdns_mdns_continuous_query
{
uint8_t name[256]; /* binary representation of name being queried */
int name_len;
uint16_t request_class;
uint16_t request_type;
/* list of known records */
_getdns_rbtree_t known_records_by_value;
/* list of user queries */
_getdns_rbtree_t netreq_by_query_id;
/* todo: do we need an expiration date, or a timer? */
/* todo: do we need an update mark for showing last results? */
} getdns_mdns_continuous_query;
#endif /* HAVE_MDNS_SUPPORT */ #endif /* HAVE_MDNS_SUPPORT */
#endif /* MDNS_H */ #endif /* MDNS_H */