Author: file Date: Mon Mar 23 07:23:20 2015 New Revision: 433297 URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=433297 Log: Add SRV recording parsing and sorting.
Modified: team/group/dns_srv/include/asterisk/dns_internal.h team/group/dns_srv/main/dns_core.c team/group/dns_srv/main/dns_srv.c Modified: team/group/dns_srv/include/asterisk/dns_internal.h URL: http://svnview.digium.com/svn/asterisk/team/group/dns_srv/include/asterisk/dns_internal.h?view=diff&rev=433297&r1=433296&r2=433297 ============================================================================== --- team/group/dns_srv/include/asterisk/dns_internal.h (original) +++ team/group/dns_srv/include/asterisk/dns_internal.h Mon Mar 23 07:23:20 2015 @@ -44,14 +44,14 @@ struct ast_dns_srv_record { /*! \brief Generic DNS record information */ struct ast_dns_record generic; - /*! \brief The hostname in the SRV record */ - const char *host; /*! \brief The priority of the SRV record */ unsigned short priority; /*! \brief The weight of the SRV record */ unsigned short weight; /*! \brief The port in the SRV record */ unsigned short port; + /*! \brief The hostname in the SRV record */ + char host[0]; }; /*! \brief A NAPTR record */ @@ -82,7 +82,7 @@ /*! \brief Optional rcode, set if an error occurred */ unsigned int rcode; /*! \brief Records returned */ - AST_LIST_HEAD_NOLOCK(, ast_dns_record) records; + AST_LIST_HEAD_NOLOCK(dns_records, ast_dns_record) records; /*! \brief The canonical name */ const char *canonical; /*! \brief The raw DNS answer */ @@ -147,3 +147,22 @@ * \return scheduler context */ struct ast_sched_context *ast_dns_get_sched(void); + +/*! + * \brief Allocate and parse a DNS SRV record + * + * \param query The DNS query + * \param data This specific SRV record + * \param size The size of the SRV record + * + * \retval non-NULL success + * \retval NULL failure + */ +struct ast_dns_record *ast_dns_srv_alloc(struct ast_dns_query *query, const char *data, const size_t size); + +/*! + * \brief Sort the SRV records on a result + * + * \param result The DNS result + */ +void ast_dns_srv_sort(struct ast_dns_result *result); Modified: team/group/dns_srv/main/dns_core.c URL: http://svnview.digium.com/svn/asterisk/team/group/dns_srv/main/dns_core.c?view=diff&rev=433297&r1=433296&r2=433297 ============================================================================== --- team/group/dns_srv/main/dns_core.c (original) +++ team/group/dns_srv/main/dns_core.c Mon Mar 23 07:23:20 2015 @@ -583,6 +583,8 @@ if (rr_type == ns_t_naptr) { record = naptr_record_alloc(query, data, size); + } else if (rr_type == ns_t_srv) { + record = ast_dns_srv_alloc(query, data, size); } else { record = generic_record_alloc(query, data, size); } @@ -604,6 +606,10 @@ void ast_dns_resolver_completed(struct ast_dns_query *query) { + if (ast_dns_query_get_rr_type(query) == ns_t_srv) { + ast_dns_srv_sort(query->result); + } + query->callback(query); } Modified: team/group/dns_srv/main/dns_srv.c URL: http://svnview.digium.com/svn/asterisk/team/group/dns_srv/main/dns_srv.c?view=diff&rev=433297&r1=433296&r2=433297 ============================================================================== --- team/group/dns_srv/main/dns_srv.c (original) +++ team/group/dns_srv/main/dns_srv.c Mon Mar 23 07:23:20 2015 @@ -31,25 +31,158 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") +#include <netinet/in.h> +#include <arpa/nameser.h> +#include <resolv.h> + #include "asterisk/dns_core.h" #include "asterisk/dns_srv.h" +#include "asterisk/linkedlists.h" +#include "asterisk/dns_internal.h" +#include "asterisk/utils.h" + +struct ast_dns_record *ast_dns_srv_alloc(struct ast_dns_query *query, const char *data, const size_t size) +{ + const char *ptr = data; + size_t remaining = size; + struct ast_dns_srv_record *srv; + unsigned short priority; + unsigned short weight; + unsigned short port; + int host_size; + char host[256] = ""; + + if (remaining < 2) { + return NULL; + } + priority = (ptr[1] << 0) | (ptr[0] << 8); + ptr += 2; + remaining -= 2; + + if (remaining < 2) { + return NULL; + } + weight = (ptr[1] << 0) | (ptr[0] << 8); + ptr += 2; + remaining -= 2; + + if (remaining < 2) { + return NULL; + } + port = (ptr[1] << 0) | (ptr[0] << 8); + ptr += 2; + + /* This currently assumes that the DNS core will provide a record within the full answer, which I'm going to talk to + * Mark about in a few hours + */ + host_size = dn_expand((unsigned char *)query->result->answer, (unsigned char *) data, (unsigned char *) ptr, host, sizeof(host) - 1); + if (host_size < 0) { + ast_log(LOG_ERROR, "Failed to expand domain name: %s\n", strerror(errno)); + return NULL; + } + + if (!strcmp(host, ".")) { + return NULL; + } + + srv = ast_calloc(1, sizeof(*srv) + host_size + 1); + if (!srv) { + return NULL; + } + + srv->priority = ntohs(priority); + srv->weight = ntohs(weight); + srv->port = ntohs(port); + strcpy(srv->host, host); /* SAFE */ + + return (struct ast_dns_record *)srv; +} + +/* This implementation was taken from the existing srv.c which, after reading the RFC, implements it + * as it should. + */ +void ast_dns_srv_sort(struct ast_dns_result *result) +{ + struct ast_dns_record *current; + struct dns_records newlist = AST_LIST_HEAD_NOLOCK_INIT_VALUE; + + while (AST_LIST_FIRST(&result->records)) { + unsigned int random_weight; + unsigned int weight_sum; + unsigned short cur_priority = ((struct ast_dns_srv_record *)AST_LIST_FIRST(&result->records))->priority; + struct dns_records temp_list = AST_LIST_HEAD_NOLOCK_INIT_VALUE; + weight_sum = 0; + + AST_LIST_TRAVERSE_SAFE_BEGIN(&result->records, current, list) { + if (((struct ast_dns_srv_record *)current)->priority != cur_priority) + break; + + AST_LIST_MOVE_CURRENT(&temp_list, list); + } + AST_LIST_TRAVERSE_SAFE_END; + + while (AST_LIST_FIRST(&temp_list)) { + weight_sum = 0; + + AST_LIST_TRAVERSE(&temp_list, current, list) { + weight_sum += ((struct ast_dns_srv_record *)current)->weight; + } + + /* if all the remaining entries have weight == 0, + then just append them to the result list and quit */ + if (weight_sum == 0) { + AST_LIST_APPEND_LIST(&newlist, &temp_list, list); + break; + } + + random_weight = 1 + (unsigned int) ((float) weight_sum * (ast_random() / ((float) RAND_MAX + 1.0))); + + AST_LIST_TRAVERSE_SAFE_BEGIN(&temp_list, current, list) { + if (((struct ast_dns_srv_record *)current)->weight < random_weight) + continue; + + AST_LIST_MOVE_CURRENT(&newlist, list); + break; + } + AST_LIST_TRAVERSE_SAFE_END; + } + + } + + /* now that the new list has been ordered, + put it in place */ + + AST_LIST_APPEND_LIST(&result->records, &newlist, list); +} const char *ast_dns_srv_get_host(const struct ast_dns_record *record) { - return NULL; + struct ast_dns_srv_record *srv = (struct ast_dns_srv_record *) record; + + ast_assert(ast_dns_record_get_rr_type(record) == ns_t_srv); + return srv->host; } unsigned short ast_dns_srv_get_priority(const struct ast_dns_record *record) { - return 0; + struct ast_dns_srv_record *srv = (struct ast_dns_srv_record *) record; + + ast_assert(ast_dns_record_get_rr_type(record) == ns_t_srv); + return srv->priority; } unsigned short ast_dns_srv_get_weight(const struct ast_dns_record *record) { - return 0; + struct ast_dns_srv_record *srv = (struct ast_dns_srv_record *) record; + + ast_assert(ast_dns_record_get_rr_type(record) == ns_t_srv); + return srv->weight; } unsigned short ast_dns_srv_get_port(const struct ast_dns_record *record) { - return 0; -} + struct ast_dns_srv_record *srv = (struct ast_dns_srv_record *) record; + + ast_assert(ast_dns_record_get_rr_type(record) == ns_t_srv); + return srv->port; +} -- _____________________________________________________________________ -- Bandwidth and Colocation Provided by http://www.api-digital.com -- svn-commits mailing list To UNSUBSCRIBE or update options visit: http://lists.digium.com/mailman/listinfo/svn-commits