dns_srv.c File Reference

DNS SRV Record Support. More...

#include "asterisk.h"
#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"

Include dependency graph for dns_srv.c:

Go to the source code of this file.

Functions

const char * ast_dns_srv_get_host (const struct ast_dns_record *record)
 Get the hostname from an SRV record.
unsigned short ast_dns_srv_get_port (const struct ast_dns_record *record)
 Get the port from an SRV record.
unsigned short ast_dns_srv_get_priority (const struct ast_dns_record *record)
 Get the priority from an SRV record.
unsigned short ast_dns_srv_get_weight (const struct ast_dns_record *record)
 Get the weight from an SRV record.
struct ast_dns_recorddns_srv_alloc (struct ast_dns_query *query, const char *data, const size_t size)
 Allocate and parse a DNS SRV record.
void dns_srv_sort (struct ast_dns_result *result)
 Sort the SRV records on a result.


Detailed Description

DNS SRV Record Support.

Author:
Joshua Colp <jcolp@digium.com>

Definition in file dns_srv.c.


Function Documentation

const char* ast_dns_srv_get_host ( const struct ast_dns_record record  ) 

Get the hostname from an SRV record.

Parameters:
record The DNS record
Returns:
the hostname

Definition at line 182 of file dns_srv.c.

References ast_assert, ast_dns_record_get_rr_type(), and ast_dns_srv_record::host.

Referenced by AST_TEST_DEFINE(), and nominal_test().

00183 {
00184    struct ast_dns_srv_record *srv = (struct ast_dns_srv_record *) record;
00185 
00186    ast_assert(ast_dns_record_get_rr_type(record) == ns_t_srv);
00187    return srv->host;
00188 }

unsigned short ast_dns_srv_get_port ( const struct ast_dns_record record  ) 

Get the port from an SRV record.

Parameters:
record The DNS record
Returns:
the port

Definition at line 206 of file dns_srv.c.

References ast_assert, ast_dns_record_get_rr_type(), and ast_dns_srv_record::port.

Referenced by AST_TEST_DEFINE(), and nominal_test().

00207 {
00208    struct ast_dns_srv_record *srv = (struct ast_dns_srv_record *) record;
00209 
00210    ast_assert(ast_dns_record_get_rr_type(record) == ns_t_srv);
00211    return srv->port;
00212 }

unsigned short ast_dns_srv_get_priority ( const struct ast_dns_record record  ) 

Get the priority from an SRV record.

Parameters:
record The DNS record
Returns:
the priority

Definition at line 190 of file dns_srv.c.

References ast_assert, ast_dns_record_get_rr_type(), and ast_dns_srv_record::priority.

Referenced by AST_TEST_DEFINE(), and nominal_test().

00191 {
00192    struct ast_dns_srv_record *srv = (struct ast_dns_srv_record *) record;
00193 
00194    ast_assert(ast_dns_record_get_rr_type(record) == ns_t_srv);
00195    return srv->priority;
00196 }

unsigned short ast_dns_srv_get_weight ( const struct ast_dns_record record  ) 

Get the weight from an SRV record.

Parameters:
record The DNS record
Returns:
the weight

Definition at line 198 of file dns_srv.c.

References ast_assert, ast_dns_record_get_rr_type(), and ast_dns_srv_record::weight.

Referenced by AST_TEST_DEFINE(), and nominal_test().

00199 {
00200    struct ast_dns_srv_record *srv = (struct ast_dns_srv_record *) record;
00201 
00202    ast_assert(ast_dns_record_get_rr_type(record) == ns_t_srv);
00203    return srv->weight;
00204 }

struct ast_dns_record* dns_srv_alloc ( struct ast_dns_query query,
const char *  data,
const size_t  size 
) [read]

Allocate and parse a DNS SRV record.

Parameters:
query The DNS query
data This specific SRV record
size The size of the SRV record
Return values:
non-NULL success
NULL failure

Definition at line 44 of file dns_srv.c.

References ast_dns_result::answer, ast_dns_result::answer_size, ast_assert, ast_calloc, ast_log, ast_dns_srv_record::data, ast_dns_record::data_ptr, dns_find_record(), dns_parse_short(), errno, ast_dns_srv_record::generic, ast_dns_srv_record::host, host, LOG_ERROR, NULL, ast_dns_srv_record::port, ast_dns_srv_record::priority, ast_dns_query::result, ast_dns_srv_record::weight, and weight.

00045 {
00046    uint16_t priority;
00047    uint16_t weight;
00048    uint16_t port;
00049    const char *ptr;
00050    const char *end_of_record;
00051    struct ast_dns_srv_record *srv;
00052    int host_size;
00053    char host[NI_MAXHOST] = "";
00054 
00055    ptr = dns_find_record(data, size, query->result->answer, query->result->answer_size);
00056    ast_assert(ptr != NULL);
00057 
00058    end_of_record = ptr + size;
00059 
00060    /* PRIORITY */
00061    ptr += dns_parse_short((unsigned char *) ptr, &priority);
00062    if (ptr >= end_of_record) {
00063       return NULL;
00064    }
00065 
00066    /* WEIGHT */
00067    ptr += dns_parse_short((unsigned char *) ptr, &weight);
00068    if (ptr >= end_of_record) {
00069       return NULL;
00070    }
00071 
00072    /* PORT */
00073    ptr += dns_parse_short((unsigned char *) ptr, &port);
00074    if (ptr >= end_of_record) {
00075       return NULL;
00076    }
00077 
00078    host_size = dn_expand((unsigned char *)query->result->answer, (unsigned char *) end_of_record, (unsigned char *) ptr, host, sizeof(host) - 1);
00079    if (host_size < 0) {
00080       ast_log(LOG_ERROR, "Failed to expand domain name: %s\n", strerror(errno));
00081       return NULL;
00082    }
00083 
00084    if (!strcmp(host, ".")) {
00085       return NULL;
00086    }
00087 
00088    srv = ast_calloc(1, sizeof(*srv) + size + host_size + 1);
00089    if (!srv) {
00090       return NULL;
00091    }
00092 
00093    srv->priority = priority;
00094    srv->weight = weight;
00095    srv->port = port;
00096 
00097    srv->host = srv->data + size;
00098    strcpy((char *)srv->host, host); /* SAFE */
00099    ((char *)srv->host)[host_size] = '\0';
00100 
00101    srv->generic.data_ptr = srv->data;
00102 
00103    return (struct ast_dns_record *)srv;
00104 }

void dns_srv_sort ( struct ast_dns_result result  ) 

Sort the SRV records on a result.

Parameters:
result The DNS result

Definition at line 109 of file dns_srv.c.

References AST_LIST_APPEND_LIST, AST_LIST_FIRST, AST_LIST_HEAD_NOLOCK_INIT_VALUE, AST_LIST_INSERT_HEAD, AST_LIST_INSERT_TAIL, AST_LIST_MOVE_CURRENT, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_random(), ast_dns_srv_record::priority, weight, and ast_dns_srv_record::weight_sum.

00110 {
00111    struct ast_dns_record *current;
00112    struct dns_records newlist = AST_LIST_HEAD_NOLOCK_INIT_VALUE;
00113 
00114    while (AST_LIST_FIRST(&result->records)) {
00115       unsigned short cur_priority = 0;
00116       struct dns_records temp_list = AST_LIST_HEAD_NOLOCK_INIT_VALUE;
00117 
00118       /* Find the lowest current priority to work on */
00119       AST_LIST_TRAVERSE(&result->records, current, list) {
00120          if (!cur_priority || ((struct ast_dns_srv_record *)current)->priority < cur_priority) {
00121             cur_priority = ((struct ast_dns_srv_record *)current)->priority;
00122          }
00123       }
00124 
00125       /* Find all records which match this priority */
00126       AST_LIST_TRAVERSE_SAFE_BEGIN(&result->records, current, list) {
00127          if (((struct ast_dns_srv_record *)current)->priority != cur_priority) {
00128             continue;
00129          }
00130 
00131          AST_LIST_REMOVE_CURRENT(list);
00132 
00133          /* Records with a weight of zero must always be at the head */
00134          if (((struct ast_dns_srv_record *)current)->weight == 0) {
00135             AST_LIST_INSERT_HEAD(&temp_list, current, list);
00136          } else {
00137             AST_LIST_INSERT_TAIL(&temp_list, current, list);
00138          }
00139       }
00140       AST_LIST_TRAVERSE_SAFE_END;
00141 
00142       /* Apply weighting - as each record is passed the sum of all previous weights (plus its own) is stored away, and then a random weight
00143        * is calculated. The first record with a weight sum greater than the random weight is put in the new list and the whole thing starts
00144        * once again.
00145        */
00146       while (AST_LIST_FIRST(&temp_list)) {
00147          unsigned int weight_sum = 0;
00148          unsigned int random_weight;
00149 
00150          AST_LIST_TRAVERSE(&temp_list, current, list) {
00151             ((struct ast_dns_srv_record *)current)->weight_sum = weight_sum += ((struct ast_dns_srv_record *)current)->weight;
00152          }
00153 
00154          /* if all the remaining entries have weight == 0,
00155             then just append them to the result list and quit */
00156          if (weight_sum == 0) {
00157             AST_LIST_APPEND_LIST(&newlist, &temp_list, list);
00158             break;
00159          }
00160 
00161          random_weight = 1 + (unsigned int) ((float) weight_sum * (ast_random() / ((float) RAND_MAX + 1.0)));
00162 
00163          AST_LIST_TRAVERSE_SAFE_BEGIN(&temp_list, current, list) {
00164             if (((struct ast_dns_srv_record *)current)->weight_sum < random_weight) {
00165                continue;
00166             }
00167 
00168             AST_LIST_MOVE_CURRENT(&newlist, list);
00169             break;
00170          }
00171          AST_LIST_TRAVERSE_SAFE_END;
00172       }
00173 
00174    }
00175 
00176    /* now that the new list has been ordered,
00177       put it in place */
00178 
00179    AST_LIST_APPEND_LIST(&result->records, &newlist, list);
00180 }


Generated on Thu Apr 16 06:30:44 2015 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6