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

Reply via email to