Asterisk - The Open Source Telephony Project GIT-master-f36a736
Data Structures | Functions
srv.c File Reference

DNS SRV Record Lookup Support for Asterisk. More...

#include "asterisk.h"
#include <netinet/in.h>
#include <arpa/nameser.h>
#include <resolv.h>
#include "asterisk/channel.h"
#include "asterisk/srv.h"
#include "asterisk/dns.h"
#include "asterisk/utils.h"
#include "asterisk/linkedlists.h"
Include dependency graph for srv.c:

Go to the source code of this file.

Data Structures

struct  srv_context
 
struct  srv_context::srv_entries
 
struct  srv_entry
 

Functions

int ast_get_srv (struct ast_channel *chan, char *host, int hostlen, int *port, const char *service)
 Lookup entry in SRV records Returns 1 if found, 0 if not found, -1 on hangup. More...
 
void ast_srv_cleanup (struct srv_context **context)
 Cleanup resources associated with ast_srv_lookup. More...
 
int ast_srv_get_nth_record (struct srv_context *context, int record_num, const char **host, unsigned short *port, unsigned short *priority, unsigned short *weight)
 Retrieve details from a specific SRV record. More...
 
unsigned int ast_srv_get_record_count (struct srv_context *context)
 Get the number of records for a given SRV context. More...
 
int ast_srv_lookup (struct srv_context **context, const char *service, const char **host, unsigned short *port)
 Retrieve set of SRV lookups, in order. More...
 
static int parse_srv (unsigned char *answer, int len, unsigned char *msg, struct srv_entry **result)
 
static void process_weights (struct srv_context *context)
 
static int srv_callback (void *context, unsigned char *answer, int len, unsigned char *fullanswer)
 

Detailed Description

DNS SRV Record Lookup Support for Asterisk.

Author
Mark Spencer marks.nosp@m.ter@.nosp@m.digiu.nosp@m.m.co.nosp@m.m
Note
Funding provided by nic.at

Definition in file srv.c.

Function Documentation

◆ ast_get_srv()

int ast_get_srv ( struct ast_channel chan,
char *  host,
int  hostlen,
int *  port,
const char *  service 
)

Lookup entry in SRV records Returns 1 if found, 0 if not found, -1 on hangup.

Only do SRV record lookup if you get a domain without a port. If you get a port #, it's a DNS host name.

Parameters
chanAst channel
hosthost name (return value)
hostlenLength of string "host"
portPort number (return value)
serviceService tag for SRV lookup (like "_sip._udp" or "_stun._udp"

Definition at line 260 of file srv.c.

261{
263 struct srv_entry *current;
264 int ret;
265
266 if (chan && ast_autoservice_start(chan) < 0) {
267 return -1;
268 }
269
270 ret = ast_search_dns(&context, service, C_IN, T_SRV, srv_callback);
271
272 if (context.have_weights) {
274 }
275
276 if (chan) {
277 ret |= ast_autoservice_stop(chan);
278 }
279
280 /* TODO: there could be a "." entry in the returned list of
281 answers... if so, this requires special handling */
282
283 /* the list of entries will be sorted in the proper selection order
284 already, so we just need the first one (if any) */
285
286 if ((ret > 0) && (current = AST_LIST_REMOVE_HEAD(&context.entries, list))) {
287 ast_copy_string(host, current->host, hostlen);
288 *port = current->port;
290 ast_debug(4, "ast_get_srv: SRV lookup for '%s' mapped to host %s, port %d\n",
291 service, host, *port);
292 } else {
293 host[0] = '\0';
294 *port = -1;
295 }
296
297 while ((current = AST_LIST_REMOVE_HEAD(&context.entries, list))) {
299 }
300
301 return ret;
302}
#define ast_free(a)
Definition: astmm.h:180
enum ast_cc_service_type service
Definition: ccss.c:383
int ast_autoservice_stop(struct ast_channel *chan)
Stop servicing a channel for us...
Definition: autoservice.c:266
int ast_autoservice_start(struct ast_channel *chan)
Automatically service a channel for us...
Definition: autoservice.c:200
int ast_search_dns(void *context, const char *dname, int class, int type, int(*callback)(void *context, unsigned char *answer, int len, unsigned char *fullanswer))
Perform DNS lookup (used by DNS, enum and SRV lookups)
Definition: dns.c:491
#define ast_debug(level,...)
Log a DEBUG message.
#define AST_LIST_HEAD_NOLOCK_INIT_VALUE
Defines initial values for a declaration of AST_LIST_HEAD_NOLOCK.
Definition: linkedlists.h:252
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:833
size_t current
Definition: main/cli.c:113
static void process_weights(struct srv_context *context)
Definition: srv.c:150
static int srv_callback(void *context, unsigned char *answer, int len, unsigned char *fullanswer)
Definition: srv.c:113
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425
Definition: srv.c:56
struct srv_entry::@391 list
char host[1]
Definition: srv.c:62
unsigned short port
Definition: srv.c:59

References ast_autoservice_start(), ast_autoservice_stop(), ast_copy_string(), ast_debug, ast_free, AST_LIST_HEAD_NOLOCK_INIT_VALUE, AST_LIST_REMOVE_HEAD, ast_search_dns(), voicemailpwcheck::context, current, srv_entry::host, srv_entry::list, srv_entry::port, process_weights(), service, and srv_callback().

Referenced by ast_get_ip_or_srv_with_preference().

◆ ast_srv_cleanup()

void ast_srv_cleanup ( struct srv_context **  context)

Cleanup resources associated with ast_srv_lookup.

Parameters
contextPointer passed into ast_srv_lookup

Definition at line 248 of file srv.c.

249{
250 const char *host;
251 unsigned short port;
252
253 if (*context) {
254 /* We have a context to clean up. */
255 while (!(ast_srv_lookup(context, NULL, &host, &port))) {
256 }
257 }
258}
#define NULL
Definition: resample.c:96
int ast_srv_lookup(struct srv_context **context, const char *service, const char **host, unsigned short *port)
Retrieve set of SRV lookups, in order.
Definition: srv.c:202

References ast_srv_lookup(), voicemailpwcheck::context, srv_entry::host, NULL, and srv_entry::port.

Referenced by ip_identify_match_srv_lookup(), launch_ha_netscript(), srds_destroy_cb(), and srv_datastore_setup().

◆ ast_srv_get_nth_record()

int ast_srv_get_nth_record ( struct srv_context context,
int  record_num,
const char **  host,
unsigned short *  port,
unsigned short *  priority,
unsigned short *  weight 
)

Retrieve details from a specific SRV record.

After calling ast_srv_lookup, the srv_context will contain the data from several records. You can retrieve the data of a specific one by asking for a specific record number. The records are sorted based on priority and secondarily based on weight. See RFC 2782 for the exact sorting rules.

Parameters
contextThe context returned by ast_srv_lookup
record_numThe 1-indexed record number to retrieve
[out]hostThe host portion of the record
[out]portThe port portion of the record
[out]priorityThe priority portion of the record
[out]weightThe weight portion of the record
Return values
-1Failed to retrieve information. Likely due to an out of range record_num
0Success

Definition at line 309 of file srv.c.

311{
312 int i = 1;
313 int res = -1;
314 struct srv_entry *entry;
315
316 if (record_num < 1 || record_num > context->num_records) {
317 return res;
318 }
319
320 AST_LIST_TRAVERSE(&context->entries, entry, list) {
321 if (i == record_num) {
322 *host = entry->host;
323 *port = entry->port;
324 *priority = entry->priority;
325 *weight = entry->weight;
326 res = 0;
327 break;
328 }
329 ++i;
330 }
331
332 return res;
333}
char weight
static int priority
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:491
Definition: search.h:40

References AST_LIST_TRAVERSE, voicemailpwcheck::context, srv_entry::host, srv_entry::list, srv_entry::port, priority, and weight.

Referenced by srv_result_read().

◆ ast_srv_get_record_count()

unsigned int ast_srv_get_record_count ( struct srv_context context)

Get the number of records for a given SRV context.

This is meant to be used after calling ast_srv_lookup, so that one may retrieve the number of records returned during a specific SRV lookup.

Parameters
contextThe context returned by ast_srv_lookup
Returns
Number of records in context

Definition at line 304 of file srv.c.

305{
306 return context->num_records;
307}

References voicemailpwcheck::context.

Referenced by srv_result_read().

◆ ast_srv_lookup()

int ast_srv_lookup ( struct srv_context **  context,
const char *  service,
const char **  host,
unsigned short *  port 
)

Retrieve set of SRV lookups, in order.

Parameters
[in]contextA pointer in which to hold the result
[in]serviceThe service name to look up
[out]hostResult host
[out]portAssociated TCP portnum
Return values
-1Query failed
0Result exists in host and port
1No more results

Definition at line 202 of file srv.c.

203{
204 struct srv_entry *cur;
205
206 if (*context == NULL) {
207 if (!(*context = ast_calloc(1, sizeof(struct srv_context)))) {
208 return -1;
209 }
210 AST_LIST_HEAD_INIT_NOLOCK(&(*context)->entries);
211
212 if (((ast_search_dns(*context, service, C_IN, T_SRV, srv_callback)) < 1) ||
213 AST_LIST_EMPTY(&(*context)->entries)) {
215 *context = NULL;
216 return -1;
217 }
218
219 if ((*context)->have_weights) {
221 }
222
223 (*context)->prev = AST_LIST_FIRST(&(*context)->entries);
224 *host = (*context)->prev->host;
225 *port = (*context)->prev->port;
226 AST_LIST_TRAVERSE(&(*context)->entries, cur, list) {
227 ++((*context)->num_records);
228 }
229 return 0;
230 }
231
232 if (((*context)->prev = AST_LIST_NEXT((*context)->prev, list))) {
233 /* Retrieve next item in result */
234 *host = (*context)->prev->host;
235 *port = (*context)->prev->port;
236 return 0;
237 } else {
238 /* No more results */
239 while ((cur = AST_LIST_REMOVE_HEAD(&(*context)->entries, list))) {
240 ast_free(cur);
241 }
243 *context = NULL;
244 return 1;
245 }
246}
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
#define AST_LIST_HEAD_INIT_NOLOCK(head)
Initializes a list head structure.
Definition: linkedlists.h:681
#define AST_LIST_EMPTY(head)
Checks whether the specified list contains any entries.
Definition: linkedlists.h:450
#define AST_LIST_FIRST(head)
Returns the first entry contained in a list.
Definition: linkedlists.h:421
#define AST_LIST_NEXT(elm, field)
Returns the next entry in the list after the given entry.
Definition: linkedlists.h:439

References ast_calloc, ast_free, AST_LIST_EMPTY, AST_LIST_FIRST, AST_LIST_HEAD_INIT_NOLOCK, AST_LIST_NEXT, AST_LIST_REMOVE_HEAD, AST_LIST_TRAVERSE, ast_search_dns(), voicemailpwcheck::context, srv_entry::host, srv_entry::list, NULL, srv_entry::port, process_weights(), service, and srv_callback().

Referenced by ast_srv_cleanup(), ip_identify_match_srv_lookup(), launch_ha_netscript(), and srv_datastore_setup().

◆ parse_srv()

static int parse_srv ( unsigned char *  answer,
int  len,
unsigned char *  msg,
struct srv_entry **  result 
)
static

Definition at line 72 of file srv.c.

73{
74 struct srv {
75 unsigned short priority;
76 unsigned short weight;
77 unsigned short port;
78 } __attribute__((__packed__)) *srv = (struct srv *) answer;
79
80 int res = 0;
81 char repl[256] = "";
82 struct srv_entry *entry;
83
84 if (len < sizeof(*srv))
85 return -1;
86
87 answer += sizeof(*srv);
88 len -= sizeof(*srv);
89
90 if ((res = dn_expand(msg, answer + len, answer, repl, sizeof(repl) - 1)) <= 0) {
91 ast_log(LOG_WARNING, "Failed to expand hostname\n");
92 return -1;
93 }
94
95 /* the magic value "." for the target domain means that this service
96 is *NOT* available at the domain we searched */
97 if (!strcmp(repl, "."))
98 return -1;
99
100 if (!(entry = ast_calloc(1, sizeof(*entry) + strlen(repl))))
101 return -1;
102
103 entry->priority = ntohs(srv->priority);
104 entry->weight = ntohs(srv->weight);
105 entry->port = ntohs(srv->port);
106 strcpy(entry->host, repl);
107
108 *result = entry;
109
110 return 0;
111}
#define ast_log
Definition: astobj2.c:42
static PGresult * result
Definition: cel_pgsql.c:84
static int answer(void *data)
Definition: chan_pjsip.c:687
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
#define LOG_WARNING

References answer(), ast_calloc, ast_log, len(), LOG_WARNING, priority, result, and weight.

Referenced by srv_callback().

◆ process_weights()

static void process_weights ( struct srv_context context)
static

Definition at line 150 of file srv.c.

151{
152 struct srv_entry *current;
153 struct srv_entries newlist = AST_LIST_HEAD_NOLOCK_INIT_VALUE;
154
155 while (AST_LIST_FIRST(&context->entries)) {
156 unsigned int random_weight;
157 unsigned int weight_sum;
158 unsigned short cur_priority = AST_LIST_FIRST(&context->entries)->priority;
159 struct srv_entries temp_list = AST_LIST_HEAD_NOLOCK_INIT_VALUE;
160 weight_sum = 0;
161
163 if (current->priority != cur_priority)
164 break;
165
166 AST_LIST_MOVE_CURRENT(&temp_list, list);
167 }
169
170 while (AST_LIST_FIRST(&temp_list)) {
171 weight_sum = 0;
172 AST_LIST_TRAVERSE(&temp_list, current, list)
173 current->weight_sum = weight_sum += current->weight;
174
175 /* if all the remaining entries have weight == 0,
176 then just append them to the result list and quit */
177 if (weight_sum == 0) {
178 AST_LIST_APPEND_LIST(&newlist, &temp_list, list);
179 break;
180 }
181
182 random_weight = 1 + (unsigned int) ((float) weight_sum * (ast_random() / ((float) RAND_MAX + 1.0)));
183
184 AST_LIST_TRAVERSE_SAFE_BEGIN(&temp_list, current, list) {
185 if (current->weight < random_weight)
186 continue;
187
188 AST_LIST_MOVE_CURRENT(&newlist, list);
189 break;
190 }
192 }
193
194 }
195
196 /* now that the new list has been ordered,
197 put it in place */
198
199 AST_LIST_APPEND_LIST(&context->entries, &newlist, list);
200}
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
Definition: linkedlists.h:615
#define AST_LIST_MOVE_CURRENT(newhead, field)
Move the current list entry to another list.
Definition: linkedlists.h:582
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
Definition: linkedlists.h:529
#define AST_LIST_APPEND_LIST(head, list, field)
Appends a whole list to the tail of a list.
Definition: linkedlists.h:783
long int ast_random(void)
Definition: utils.c:2312

References AST_LIST_APPEND_LIST, AST_LIST_FIRST, AST_LIST_HEAD_NOLOCK_INIT_VALUE, AST_LIST_MOVE_CURRENT, AST_LIST_TRAVERSE, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_random(), voicemailpwcheck::context, and current.

Referenced by ast_get_srv(), and ast_srv_lookup().

◆ srv_callback()

static int srv_callback ( void *  context,
unsigned char *  answer,
int  len,
unsigned char *  fullanswer 
)
static

Definition at line 113 of file srv.c.

114{
115 struct srv_context *c = (struct srv_context *) context;
116 struct srv_entry *entry = NULL;
117 struct srv_entry *current;
118
119 if (parse_srv(answer, len, fullanswer, &entry))
120 return -1;
121
122 if (entry->weight)
123 c->have_weights = 1;
124
126 /* insert this entry just before the first existing
127 entry with a higher priority */
128 if (current->priority <= entry->priority)
129 continue;
130
132 entry = NULL;
133 break;
134 }
136
137 /* if we didn't find a place to insert the entry before an existing
138 entry, then just add it to the end */
139 if (entry)
140 AST_LIST_INSERT_TAIL(&c->entries, entry, list);
141
142 return 0;
143}
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:731
#define AST_LIST_INSERT_BEFORE_CURRENT(elm, field)
Inserts a list entry before the current entry during a traversal.
Definition: linkedlists.h:599
static int parse_srv(unsigned char *answer, int len, unsigned char *msg, struct srv_entry **result)
Definition: srv.c:72
static struct test_val c

References answer(), AST_LIST_INSERT_BEFORE_CURRENT, AST_LIST_INSERT_TAIL, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, c, voicemailpwcheck::context, current, len(), srv_entry::list, NULL, and parse_srv().

Referenced by ast_get_srv(), and ast_srv_lookup().