blob: 97571612507763f74a2dd0834b911f7eedc65944 [file] [log] [blame]
Tristan Matthews0a329cc2013-07-17 13:20:14 -04001/* $Id$ */
2/*
3 * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
4 * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20#include <pjlib-util/resolver.h>
21#include <pjlib-util/errno.h>
22#include <pj/assert.h>
23#include <pj/ctype.h>
24#include <pj/except.h>
25#include <pj/hash.h>
26#include <pj/ioqueue.h>
27#include <pj/log.h>
28#include <pj/os.h>
29#include <pj/pool.h>
30#include <pj/pool_buf.h>
31#include <pj/rand.h>
32#include <pj/string.h>
33#include <pj/sock.h>
34#include <pj/timer.h>
35
36
37#define THIS_FILE "resolver.c"
38
39
40/* Check that maximum DNS nameservers is not too large.
41 * This has got todo with the datatype to index the nameserver in the query.
42 */
43#if PJ_DNS_RESOLVER_MAX_NS > 256
44# error "PJ_DNS_RESOLVER_MAX_NS is too large (max=256)"
45#endif
46
47
48#define RES_HASH_TABLE_SIZE 127 /**< Hash table size (must be 2^n-1 */
49#define PORT 53 /**< Default NS port. */
50#define Q_HASH_TABLE_SIZE 127 /**< Query hash table size */
51#define TIMER_SIZE 127 /**< Initial number of timers. */
52#define MAX_FD 3 /**< Maximum internal sockets. */
53
54#define RES_BUF_SZ PJ_DNS_RESOLVER_RES_BUF_SIZE
55#define UDPSZ PJ_DNS_RESOLVER_MAX_UDP_SIZE
56#define TMP_SZ PJ_DNS_RESOLVER_TMP_BUF_SIZE
57
58
59/* Nameserver state */
60enum ns_state
61{
62 STATE_PROBING,
63 STATE_ACTIVE,
64 STATE_BAD,
65};
66
67static const char *state_names[3] =
68{
69 "Probing",
70 "Active",
71 "Bad"
72};
73
74
75/*
76 * Each nameserver entry.
77 * A name server is identified by its socket address (IP and port).
78 * Each NS will have a flag to indicate whether it's properly functioning.
79 */
80struct nameserver
81{
82 pj_sockaddr_in addr; /**< Server address. */
83
84 enum ns_state state; /**< Nameserver state. */
85 pj_time_val state_expiry; /**< Time set next state. */
86 pj_time_val rt_delay; /**< Response time. */
87
88
89 /* For calculating rt_delay: */
90 pj_uint16_t q_id; /**< Query ID. */
91 pj_time_val sent_time; /**< Time this query is sent. */
92};
93
94
95/* Child query list head
96 * See comments on pj_dns_async_query below.
97 */
98struct query_head
99{
100 PJ_DECL_LIST_MEMBER(pj_dns_async_query);
101};
102
103
104/* Key to look for outstanding query and/or cached response */
105struct res_key
106{
107 pj_uint16_t qtype; /**< Query type. */
108 char name[PJ_MAX_HOSTNAME]; /**< Name being queried */
109};
110
111
112/*
113 * This represents each asynchronous query entry.
114 * This entry will be put in two hash tables, the first one keyed on the DNS
115 * transaction ID to match response with the query, and the second one keyed
116 * on "res_key" structure above to match a new request against outstanding
117 * requests.
118 *
119 * An asynchronous entry may have child entries; child entries are subsequent
120 * queries to the same resource while there is pending query on the same
121 * DNS resource name and type. When a query has child entries, once the
122 * response is received (or error occurs), the response will trigger callback
123 * invocations for all childs entries.
124 *
125 * Note: when application cancels the query, the callback member will be
126 * set to NULL, but for simplicity, the query will be let running.
127 */
128struct pj_dns_async_query
129{
130 PJ_DECL_LIST_MEMBER(pj_dns_async_query); /**< List member. */
131
132 pj_dns_resolver *resolver; /**< The resolver instance. */
133 pj_uint16_t id; /**< Transaction ID. */
134
135 unsigned transmit_cnt; /**< Number of transmissions. */
136
137 struct res_key key; /**< Key to index this query. */
138 pj_hash_entry_buf hbufid; /**< Hash buffer 1 */
139 pj_hash_entry_buf hbufkey; /**< Hash buffer 2 */
140 pj_timer_entry timer_entry; /**< Timer to manage timeouts */
141 unsigned options; /**< Query options. */
142 void *user_data; /**< Application data. */
143 pj_dns_callback *cb; /**< Callback to be called. */
144 struct query_head child_head; /**< Child queries list head. */
145};
146
147
148/* This structure is used to keep cached response entry.
149 * The cache is a hash table keyed on "res_key" structure above.
150 */
151struct cached_res
152{
153 PJ_DECL_LIST_MEMBER(struct cached_res);
154
155 pj_pool_t *pool; /**< Cache's pool. */
156 struct res_key key; /**< Resource key. */
157 pj_hash_entry_buf hbuf; /**< Hash buffer */
158 pj_time_val expiry_time; /**< Expiration time. */
159 pj_dns_parsed_packet *pkt; /**< The response packet. */
160 unsigned ref_cnt; /**< Reference counter. */
161};
162
163
164/* Resolver entry */
165struct pj_dns_resolver
166{
167 pj_str_t name; /**< Resolver instance name for id. */
168
169 /* Internals */
170 pj_pool_t *pool; /**< Internal pool. */
171 pj_mutex_t *mutex; /**< Mutex protection. */
172 pj_bool_t own_timer; /**< Do we own timer? */
173 pj_timer_heap_t *timer; /**< Timer instance. */
174 pj_bool_t own_ioqueue; /**< Do we own ioqueue? */
175 pj_ioqueue_t *ioqueue; /**< Ioqueue instance. */
176 char tmp_pool[TMP_SZ];/**< Temporary pool buffer. */
177
178 /* Socket */
179 pj_sock_t udp_sock; /**< UDP socket. */
180 pj_ioqueue_key_t *udp_key; /**< UDP socket ioqueue key. */
181 unsigned char udp_rx_pkt[UDPSZ];/**< UDP receive buffer. */
182 unsigned char udp_tx_pkt[UDPSZ];/**< UDP receive buffer. */
183 pj_ssize_t udp_len; /**< Length of received packet. */
184 pj_ioqueue_op_key_t udp_op_rx_key; /**< UDP read operation key. */
185 pj_ioqueue_op_key_t udp_op_tx_key; /**< UDP write operation key. */
186 pj_sockaddr_in udp_src_addr; /**< Source address of packet */
187 int udp_addr_len; /**< Source address length. */
188
189 /* Settings */
190 pj_dns_settings settings; /**< Resolver settings. */
191
192 /* Nameservers */
193 unsigned ns_count; /**< Number of name servers. */
194 struct nameserver ns[PJ_DNS_RESOLVER_MAX_NS]; /**< Array of NS. */
195
196 /* Last DNS transaction ID used. */
197 pj_uint16_t last_id;
198
199 /* Hash table for cached response */
200 pj_hash_table_t *hrescache; /**< Cached response in hash table */
201
202 /* Pending asynchronous query, hashed by transaction ID. */
203 pj_hash_table_t *hquerybyid;
204
205 /* Pending asynchronous query, hashed by "res_key" */
206 pj_hash_table_t *hquerybyres;
207
208 /* Query entries free list */
209 struct query_head query_free_nodes;
210};
211
212
213/* Callback from ioqueue when packet is received */
214static void on_read_complete(pj_ioqueue_key_t *key,
215 pj_ioqueue_op_key_t *op_key,
216 pj_ssize_t bytes_read);
217
218/* Callback to be called when query has timed out */
219static void on_timeout( pj_timer_heap_t *timer_heap,
220 struct pj_timer_entry *entry);
221
222/* Select which nameserver to use */
223static pj_status_t select_nameservers(pj_dns_resolver *resolver,
224 unsigned *count,
225 unsigned servers[]);
226
227
228/* Close UDP socket */
229static void close_sock(pj_dns_resolver *resv)
230{
231 /* Close existing socket */
232 if (resv->udp_key != NULL) {
233 pj_ioqueue_unregister(resv->udp_key);
234 resv->udp_key = NULL;
235 resv->udp_sock = PJ_INVALID_SOCKET;
236 } else if (resv->udp_sock != PJ_INVALID_SOCKET) {
237 pj_sock_close(resv->udp_sock);
238 resv->udp_sock = PJ_INVALID_SOCKET;
239 }
240}
241
242
243/* Initialize UDP socket */
244static pj_status_t init_sock(pj_dns_resolver *resv)
245{
246 pj_ioqueue_callback socket_cb;
247 pj_status_t status;
248
249 /* Create the UDP socket */
250 status = pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, &resv->udp_sock);
251 if (status != PJ_SUCCESS)
252 return status;
253
254 /* Bind to any address/port */
255 status = pj_sock_bind_in(resv->udp_sock, 0, 0);
256 if (status != PJ_SUCCESS)
257 return status;
258
259 /* Register to ioqueue */
260 pj_bzero(&socket_cb, sizeof(socket_cb));
261 socket_cb.on_read_complete = &on_read_complete;
262 status = pj_ioqueue_register_sock(resv->pool, resv->ioqueue,
263 resv->udp_sock, resv, &socket_cb,
264 &resv->udp_key);
265 if (status != PJ_SUCCESS)
266 return status;
267
268 pj_ioqueue_op_key_init(&resv->udp_op_rx_key, sizeof(resv->udp_op_rx_key));
269 pj_ioqueue_op_key_init(&resv->udp_op_tx_key, sizeof(resv->udp_op_tx_key));
270
271 /* Start asynchronous read to the UDP socket */
272 resv->udp_len = sizeof(resv->udp_rx_pkt);
273 resv->udp_addr_len = sizeof(resv->udp_src_addr);
274 status = pj_ioqueue_recvfrom(resv->udp_key, &resv->udp_op_rx_key,
275 resv->udp_rx_pkt, &resv->udp_len,
276 PJ_IOQUEUE_ALWAYS_ASYNC,
277 &resv->udp_src_addr, &resv->udp_addr_len);
278 if (status != PJ_EPENDING)
279 return status;
280
281 return PJ_SUCCESS;
282}
283
284
285/* Initialize DNS settings with default values */
286PJ_DEF(void) pj_dns_settings_default(pj_dns_settings *s)
287{
288 pj_bzero(s, sizeof(pj_dns_settings));
289 s->qretr_delay = PJ_DNS_RESOLVER_QUERY_RETRANSMIT_DELAY;
290 s->qretr_count = PJ_DNS_RESOLVER_QUERY_RETRANSMIT_COUNT;
291 s->cache_max_ttl = PJ_DNS_RESOLVER_MAX_TTL;
292 s->good_ns_ttl = PJ_DNS_RESOLVER_GOOD_NS_TTL;
293 s->bad_ns_ttl = PJ_DNS_RESOLVER_BAD_NS_TTL;
294}
295
296
297/*
298 * Create the resolver.
299 */
300PJ_DEF(pj_status_t) pj_dns_resolver_create( pj_pool_factory *pf,
301 const char *name,
302 unsigned options,
303 pj_timer_heap_t *timer,
304 pj_ioqueue_t *ioqueue,
305 pj_dns_resolver **p_resolver)
306{
307 pj_pool_t *pool;
308 pj_dns_resolver *resv;
309 pj_status_t status;
310
311 /* Sanity check */
312 PJ_ASSERT_RETURN(pf && p_resolver, PJ_EINVAL);
313
314 if (name == NULL)
315 name = THIS_FILE;
316
317 /* Create and initialize resolver instance */
318 pool = pj_pool_create(pf, name, 4000, 4000, NULL);
319 if (!pool)
320 return PJ_ENOMEM;
321
322 /* Create pool and name */
323 resv = PJ_POOL_ZALLOC_T(pool, struct pj_dns_resolver);
324 resv->pool = pool;
325 resv->udp_sock = PJ_INVALID_SOCKET;
326 pj_strdup2_with_null(pool, &resv->name, name);
327
328 /* Create the mutex */
329 status = pj_mutex_create_recursive(pool, name, &resv->mutex);
330 if (status != PJ_SUCCESS)
331 goto on_error;
332
333 /* Timer, ioqueue, and settings */
334 resv->timer = timer;
335 resv->ioqueue = ioqueue;
336 resv->last_id = 1;
337
338 pj_dns_settings_default(&resv->settings);
339 resv->settings.options = options;
340
341 /* Create the timer heap if one is not specified */
342 if (resv->timer == NULL) {
343 status = pj_timer_heap_create(pool, TIMER_SIZE, &resv->timer);
344 if (status != PJ_SUCCESS)
345 goto on_error;
346 }
347
348 /* Create the ioqueue if one is not specified */
349 if (resv->ioqueue == NULL) {
350 status = pj_ioqueue_create(pool, MAX_FD, &resv->ioqueue);
351 if (status != PJ_SUCCESS)
352 goto on_error;
353 }
354
355 /* Response cache hash table */
356 resv->hrescache = pj_hash_create(pool, RES_HASH_TABLE_SIZE);
357
358 /* Query hash table and free list. */
359 resv->hquerybyid = pj_hash_create(pool, Q_HASH_TABLE_SIZE);
360 resv->hquerybyres = pj_hash_create(pool, Q_HASH_TABLE_SIZE);
361 pj_list_init(&resv->query_free_nodes);
362
363 /* Initialize the UDP socket */
364 status = init_sock(resv);
365 if (status != PJ_SUCCESS)
366 goto on_error;
367
368 /* Looks like everything is okay */
369 *p_resolver = resv;
370 return PJ_SUCCESS;
371
372on_error:
373 pj_dns_resolver_destroy(resv, PJ_FALSE);
374 return status;
375}
376
377
378/*
379 * Destroy DNS resolver instance.
380 */
381PJ_DEF(pj_status_t) pj_dns_resolver_destroy( pj_dns_resolver *resolver,
382 pj_bool_t notify)
383{
384 pj_hash_iterator_t it_buf, *it;
385 PJ_ASSERT_RETURN(resolver, PJ_EINVAL);
386
387 if (notify) {
388 /*
389 * Notify pending queries if requested.
390 */
391 it = pj_hash_first(resolver->hquerybyid, &it_buf);
392 while (it) {
393 pj_dns_async_query *q = (pj_dns_async_query *)
394 pj_hash_this(resolver->hquerybyid, it);
395 pj_dns_async_query *cq;
396 if (q->cb)
397 (*q->cb)(q->user_data, PJ_ECANCELLED, NULL);
398
399 cq = q->child_head.next;
400 while (cq != (pj_dns_async_query*)&q->child_head) {
401 if (cq->cb)
402 (*cq->cb)(cq->user_data, PJ_ECANCELLED, NULL);
403 cq = cq->next;
404 }
405 it = pj_hash_next(resolver->hquerybyid, it);
406 }
407 }
408
409 /* Destroy cached entries */
410 it = pj_hash_first(resolver->hrescache, &it_buf);
411 while (it) {
412 struct cached_res *cache;
413
414 cache = (struct cached_res*) pj_hash_this(resolver->hrescache, it);
415 pj_hash_set(NULL, resolver->hrescache, &cache->key,
416 sizeof(cache->key), 0, NULL);
417 pj_pool_release(cache->pool);
418
419 it = pj_hash_first(resolver->hrescache, &it_buf);
420 }
421
422 if (resolver->own_timer && resolver->timer) {
423 pj_timer_heap_destroy(resolver->timer);
424 resolver->timer = NULL;
425 }
426
427 close_sock(resolver);
428
429 if (resolver->own_ioqueue && resolver->ioqueue) {
430 pj_ioqueue_destroy(resolver->ioqueue);
431 resolver->ioqueue = NULL;
432 }
433
434 if (resolver->mutex) {
435 pj_mutex_destroy(resolver->mutex);
436 resolver->mutex = NULL;
437 }
438
439 if (resolver->pool) {
440 pj_pool_t *pool = resolver->pool;
441 resolver->pool = NULL;
442 pj_pool_release(pool);
443 }
444 return PJ_SUCCESS;
445}
446
447
448
449/*
450 * Configure name servers for the DNS resolver.
451 */
452PJ_DEF(pj_status_t) pj_dns_resolver_set_ns( pj_dns_resolver *resolver,
453 unsigned count,
454 const pj_str_t servers[],
455 const pj_uint16_t ports[])
456{
457 unsigned i;
458 pj_time_val now;
459 pj_status_t status;
460
461 PJ_ASSERT_RETURN(resolver && count && servers, PJ_EINVAL);
462 PJ_ASSERT_RETURN(count < PJ_DNS_RESOLVER_MAX_NS, PJ_EINVAL);
463
464 pj_mutex_lock(resolver->mutex);
465
466 if (count > PJ_DNS_RESOLVER_MAX_NS)
467 count = PJ_DNS_RESOLVER_MAX_NS;
468
469 resolver->ns_count = 0;
470 pj_bzero(resolver->ns, sizeof(resolver->ns));
471
472 pj_gettimeofday(&now);
473
474 for (i=0; i<count; ++i) {
475 struct nameserver *ns = &resolver->ns[i];
476
477 status = pj_sockaddr_in_init(&ns->addr, &servers[i],
478 (pj_uint16_t)(ports ? ports[i] : PORT));
479 if (status != PJ_SUCCESS) {
480 pj_mutex_unlock(resolver->mutex);
481 return PJLIB_UTIL_EDNSINNSADDR;
482 }
483
484 ns->state = STATE_ACTIVE;
485 ns->state_expiry = now;
486 ns->rt_delay.sec = 10;
487 }
488
489 resolver->ns_count = count;
490
491 pj_mutex_unlock(resolver->mutex);
492 return PJ_SUCCESS;
493}
494
495
496
497/*
498 * Modify the resolver settings.
499 */
500PJ_DEF(pj_status_t) pj_dns_resolver_set_settings(pj_dns_resolver *resolver,
501 const pj_dns_settings *st)
502{
503 PJ_ASSERT_RETURN(resolver && st, PJ_EINVAL);
504
505 pj_mutex_lock(resolver->mutex);
506 pj_memcpy(&resolver->settings, st, sizeof(*st));
507 pj_mutex_unlock(resolver->mutex);
508 return PJ_SUCCESS;
509}
510
511
512/*
513 * Get the resolver current settings.
514 */
515PJ_DEF(pj_status_t) pj_dns_resolver_get_settings( pj_dns_resolver *resolver,
516 pj_dns_settings *st)
517{
518 PJ_ASSERT_RETURN(resolver && st, PJ_EINVAL);
519
520 pj_mutex_lock(resolver->mutex);
521 pj_memcpy(st, &resolver->settings, sizeof(*st));
522 pj_mutex_unlock(resolver->mutex);
523 return PJ_SUCCESS;
524}
525
526
527/*
528 * Poll for events from the resolver.
529 */
530PJ_DEF(void) pj_dns_resolver_handle_events(pj_dns_resolver *resolver,
531 const pj_time_val *timeout)
532{
533 PJ_ASSERT_ON_FAIL(resolver, return);
534
535 pj_mutex_lock(resolver->mutex);
536 pj_timer_heap_poll(resolver->timer, NULL);
537 pj_mutex_unlock(resolver->mutex);
538
539 pj_ioqueue_poll(resolver->ioqueue, timeout);
540}
541
542
543/* Get one query node from the free node, if any, or allocate
544 * a new one.
545 */
546static pj_dns_async_query *alloc_qnode(pj_dns_resolver *resolver,
547 unsigned options,
548 void *user_data,
549 pj_dns_callback *cb)
550{
551 pj_dns_async_query *q;
552
553 /* Merge query options with resolver options */
554 options |= resolver->settings.options;
555
556 if (!pj_list_empty(&resolver->query_free_nodes)) {
557 q = resolver->query_free_nodes.next;
558 pj_list_erase(q);
559 pj_bzero(q, sizeof(*q));
560 } else {
561 q = PJ_POOL_ZALLOC_T(resolver->pool, pj_dns_async_query);
562 }
563
564 /* Init query */
565 q->resolver = resolver;
566 q->options = options;
567 q->user_data = user_data;
568 q->cb = cb;
569 pj_list_init(&q->child_head);
570
571 return q;
572}
573
574
575/*
576 * Transmit query.
577 */
578static pj_status_t transmit_query(pj_dns_resolver *resolver,
579 pj_dns_async_query *q)
580{
581 unsigned pkt_size;
582 unsigned i, server_cnt;
583 unsigned servers[PJ_DNS_RESOLVER_MAX_NS];
584 pj_time_val now;
585 pj_str_t name;
586 pj_time_val delay;
587 pj_status_t status;
588
589 /* Select which nameserver(s) to send requests to. */
590 server_cnt = PJ_ARRAY_SIZE(servers);
591 status = select_nameservers(resolver, &server_cnt, servers);
592 if (status != PJ_SUCCESS) {
593 return status;
594 }
595
596 if (server_cnt == 0) {
597 return PJLIB_UTIL_EDNSNOWORKINGNS;
598 }
599
600 /* Start retransmit/timeout timer for the query */
601 pj_assert(q->timer_entry.id == 0);
602 q->timer_entry.id = 1;
603 q->timer_entry.user_data = q;
604 q->timer_entry.cb = &on_timeout;
605
606 delay.sec = 0;
607 delay.msec = resolver->settings.qretr_delay;
608 pj_time_val_normalize(&delay);
609 status = pj_timer_heap_schedule(resolver->timer, &q->timer_entry, &delay);
610 if (status != PJ_SUCCESS) {
611 return status;
612 }
613
614 /* Check if the socket is available for sending */
615 if (pj_ioqueue_is_pending(resolver->udp_key, &resolver->udp_op_tx_key)) {
616 ++q->transmit_cnt;
617 PJ_LOG(4,(resolver->name.ptr,
618 "Socket busy in transmitting DNS %s query for %s%s",
619 pj_dns_get_type_name(q->key.qtype),
620 q->key.name,
621 (q->transmit_cnt < resolver->settings.qretr_count?
622 ", will try again later":"")));
623 return PJ_SUCCESS;
624 }
625
626 /* Create DNS query packet */
627 pkt_size = sizeof(resolver->udp_tx_pkt);
628 name = pj_str(q->key.name);
629 status = pj_dns_make_query(resolver->udp_tx_pkt, &pkt_size,
630 q->id, q->key.qtype, &name);
631 if (status != PJ_SUCCESS) {
632 pj_timer_heap_cancel(resolver->timer, &q->timer_entry);
633 return status;
634 }
635
636 /* Get current time. */
637 pj_gettimeofday(&now);
638
639 /* Send the packet to name servers */
640 for (i=0; i<server_cnt; ++i) {
641 pj_ssize_t sent = (pj_ssize_t) pkt_size;
642 struct nameserver *ns = &resolver->ns[servers[i]];
643
644 status = pj_ioqueue_sendto(resolver->udp_key,
645 &resolver->udp_op_tx_key,
646 resolver->udp_tx_pkt, &sent, 0,
647 &resolver->ns[servers[i]].addr,
648 sizeof(pj_sockaddr_in));
649
650 PJ_PERROR(4,(resolver->name.ptr, status,
651 "%s %d bytes to NS %d (%s:%d): DNS %s query for %s",
652 (q->transmit_cnt==0? "Transmitting":"Re-transmitting"),
653 (int)pkt_size, servers[i],
654 pj_inet_ntoa(ns->addr.sin_addr),
655 (int)pj_ntohs(ns->addr.sin_port),
656 pj_dns_get_type_name(q->key.qtype),
657 q->key.name));
658
659 if (ns->q_id == 0) {
660 ns->q_id = q->id;
661 ns->sent_time = now;
662 }
663 }
664
665 ++q->transmit_cnt;
666
667 return PJ_SUCCESS;
668}
669
670
671/*
672 * Initialize resource key for hash table lookup.
673 */
674static void init_res_key(struct res_key *key, int type, const pj_str_t *name)
675{
676 unsigned i;
677 pj_size_t len;
678 char *dst = key->name;
679 const char *src = name->ptr;
680
681 pj_bzero(key, sizeof(struct res_key));
682 key->qtype = (pj_uint16_t)type;
683
684 len = name->slen;
685 if (len > PJ_MAX_HOSTNAME) len = PJ_MAX_HOSTNAME;
686
687 /* Copy key, in lowercase */
688 for (i=0; i<len; ++i) {
689 *dst++ = (char)pj_tolower(*src++);
690 }
691}
692
693
694/* Allocate new cache entry */
695static struct cached_res *alloc_entry(pj_dns_resolver *resolver)
696{
697 pj_pool_t *pool;
698 struct cached_res *cache;
699
700 pool = pj_pool_create(resolver->pool->factory, "dnscache",
701 RES_BUF_SZ, 256, NULL);
702 cache = PJ_POOL_ZALLOC_T(pool, struct cached_res);
703 cache->pool = pool;
704 cache->ref_cnt = 1;
705
706 return cache;
707}
708
709/* Re-allocate cache entry, to free cached packet */
710static void reset_entry(struct cached_res **p_cached)
711{
712 pj_pool_t *pool;
713 struct cached_res *cache = *p_cached;
714 unsigned ref_cnt;
715
716 pool = cache->pool;
717 ref_cnt = cache->ref_cnt;
718
719 pj_pool_reset(pool);
720
721 cache = PJ_POOL_ZALLOC_T(pool, struct cached_res);
722 cache->pool = pool;
723 cache->ref_cnt = ref_cnt;
724 *p_cached = cache;
725}
726
727/* Put unused/expired cached entry to the free list */
728static void free_entry(pj_dns_resolver *resolver, struct cached_res *cache)
729{
730 PJ_UNUSED_ARG(resolver);
731 pj_pool_release(cache->pool);
732}
733
734
735/*
736 * Create and start asynchronous DNS query for a single resource.
737 */
738PJ_DEF(pj_status_t) pj_dns_resolver_start_query( pj_dns_resolver *resolver,
739 const pj_str_t *name,
740 int type,
741 unsigned options,
742 pj_dns_callback *cb,
743 void *user_data,
744 pj_dns_async_query **p_query)
745{
746 pj_time_val now;
747 struct res_key key;
748 struct cached_res *cache;
749 pj_dns_async_query *q;
750 pj_uint32_t hval;
751 pj_status_t status = PJ_SUCCESS;
752
753 /* Validate arguments */
754 PJ_ASSERT_RETURN(resolver && name && type, PJ_EINVAL);
755
756 /* Check name is not too long. */
757 PJ_ASSERT_RETURN(name->slen>0 && name->slen < PJ_MAX_HOSTNAME,
758 PJ_ENAMETOOLONG);
759
760 /* Check type */
761 PJ_ASSERT_RETURN(type > 0 && type < 0xFFFF, PJ_EINVAL);
762
763 if (p_query)
764 *p_query = NULL;
765
766 /* Build resource key for looking up hash tables */
767 init_res_key(&key, type, name);
768
769 /* Start working with the resolver */
770 pj_mutex_lock(resolver->mutex);
771
772 /* Get current time. */
773 pj_gettimeofday(&now);
774
775 /* First, check if we have cached response for the specified name/type,
776 * and the cached entry has not expired.
777 */
778 hval = 0;
779 cache = (struct cached_res *) pj_hash_get(resolver->hrescache, &key,
780 sizeof(key), &hval);
781 if (cache) {
782 /* We've found a cached entry. */
783
784 /* Check for expiration */
785 if (PJ_TIME_VAL_GT(cache->expiry_time, now)) {
786
787 /* Log */
788 PJ_LOG(5,(resolver->name.ptr,
789 "Picked up DNS %s record for %.*s from cache, ttl=%d",
790 pj_dns_get_type_name(type),
791 (int)name->slen, name->ptr,
792 (int)(cache->expiry_time.sec - now.sec)));
793
794 /* Map DNS Rcode in the response into PJLIB status name space */
795 status = PJ_DNS_GET_RCODE(cache->pkt->hdr.flags);
796 status = PJ_STATUS_FROM_DNS_RCODE(status);
797
798 /* Workaround for deadlock problem. Need to increment the cache's
799 * ref counter first before releasing mutex, so the cache won't be
800 * destroyed by other thread while in callback.
801 */
802 cache->ref_cnt++;
803 pj_mutex_unlock(resolver->mutex);
804
805 /* This cached response is still valid. Just return this
806 * response to caller.
807 */
808 if (cb) {
809 (*cb)(user_data, status, cache->pkt);
810 }
811
812 /* Done. No host resolution is necessary */
813 pj_mutex_lock(resolver->mutex);
814
815 /* Decrement the ref counter. Also check if it is time to free
816 * the cache (as it has been expired).
817 */
818 cache->ref_cnt--;
819 if (cache->ref_cnt <= 0)
820 free_entry(resolver, cache);
821
822 /* Must return PJ_SUCCESS */
823 status = PJ_SUCCESS;
824
825 goto on_return;
826 }
827
828 /* At this point, we have a cached entry, but this entry has expired.
829 * Remove this entry from the cached list.
830 */
831 pj_hash_set(NULL, resolver->hrescache, &key, sizeof(key), 0, NULL);
832
833 /* Also free the cache, if it is not being used (by callback). */
834 cache->ref_cnt--;
835 if (cache->ref_cnt <= 0)
836 free_entry(resolver, cache);
837
838 /* Must continue with creating a query now */
839 }
840
841 /* Next, check if we have pending query on the same resource */
842 q = (pj_dns_async_query *) pj_hash_get(resolver->hquerybyres, &key,
843 sizeof(key), NULL);
844 if (q) {
845 /* Yes, there's another pending query to the same key.
846 * Just create a new child query and add this query to
847 * pending query's child queries.
848 */
849 pj_dns_async_query *nq;
850
851 nq = alloc_qnode(resolver, options, user_data, cb);
852 pj_list_push_back(&q->child_head, nq);
853
854 /* Done. This child query will be notified once the "parent"
855 * query completes.
856 */
857 status = PJ_SUCCESS;
858 goto on_return;
859 }
860
861 /* There's no pending query to the same key, initiate a new one. */
862 q = alloc_qnode(resolver, options, user_data, cb);
863
864 /* Save the ID and key */
865 /* TODO: dnsext-forgery-resilient: randomize id for security */
866 q->id = resolver->last_id++;
867 if (resolver->last_id == 0)
868 resolver->last_id = 1;
869 pj_memcpy(&q->key, &key, sizeof(struct res_key));
870
871 /* Send the query */
872 status = transmit_query(resolver, q);
873 if (status != PJ_SUCCESS) {
874 pj_list_push_back(&resolver->query_free_nodes, q);
875 goto on_return;
876 }
877
878 /* Add query entry to the hash tables */
879 pj_hash_set_np(resolver->hquerybyid, &q->id, sizeof(q->id),
880 0, q->hbufid, q);
881 pj_hash_set_np(resolver->hquerybyres, &q->key, sizeof(q->key),
882 0, q->hbufkey, q);
883
884 if (p_query)
885 *p_query = q;
886
887on_return:
888 pj_mutex_unlock(resolver->mutex);
889 return status;
890}
891
892
893/*
894 * Cancel a pending query.
895 */
896PJ_DEF(pj_status_t) pj_dns_resolver_cancel_query(pj_dns_async_query *query,
897 pj_bool_t notify)
898{
899 pj_dns_callback *cb;
900
901 PJ_ASSERT_RETURN(query, PJ_EINVAL);
902
903 pj_mutex_lock(query->resolver->mutex);
904
905 cb = query->cb;
906 query->cb = NULL;
907
908 if (notify)
909 (*cb)(query->user_data, PJ_ECANCELLED, NULL);
910
911 pj_mutex_unlock(query->resolver->mutex);
912 return PJ_SUCCESS;
913}
914
915
916/*
917 * DNS response containing A packet.
918 */
919PJ_DEF(pj_status_t) pj_dns_parse_a_response(const pj_dns_parsed_packet *pkt,
920 pj_dns_a_record *rec)
921{
922 enum { MAX_SEARCH = 20 };
923 pj_str_t hostname, alias = {NULL, 0}, *resname;
924 pj_size_t bufstart = 0;
925 pj_size_t bufleft = sizeof(rec->buf_);
926 unsigned i, ansidx, search_cnt=0;
927
928 PJ_ASSERT_RETURN(pkt && rec, PJ_EINVAL);
929
930 /* Init the record */
931 pj_bzero(rec, sizeof(pj_dns_a_record));
932
933 /* Return error if there's error in the packet. */
934 if (PJ_DNS_GET_RCODE(pkt->hdr.flags))
935 return PJ_STATUS_FROM_DNS_RCODE(PJ_DNS_GET_RCODE(pkt->hdr.flags));
936
937 /* Return error if there's no query section */
938 if (pkt->hdr.qdcount == 0)
939 return PJLIB_UTIL_EDNSINANSWER;
940
941 /* Return error if there's no answer */
942 if (pkt->hdr.anscount == 0)
943 return PJLIB_UTIL_EDNSNOANSWERREC;
944
945 /* Get the hostname from the query. */
946 hostname = pkt->q[0].name;
947
948 /* Copy hostname to the record */
949 if (hostname.slen > (int)bufleft) {
950 return PJ_ENAMETOOLONG;
951 }
952
953 pj_memcpy(&rec->buf_[bufstart], hostname.ptr, hostname.slen);
954 rec->name.ptr = &rec->buf_[bufstart];
955 rec->name.slen = hostname.slen;
956
957 bufstart += hostname.slen;
958 bufleft -= hostname.slen;
959
960 /* Find the first RR which name matches the hostname */
961 for (ansidx=0; ansidx < pkt->hdr.anscount; ++ansidx) {
962 if (pj_stricmp(&pkt->ans[ansidx].name, &hostname)==0)
963 break;
964 }
965
966 if (ansidx == pkt->hdr.anscount)
967 return PJLIB_UTIL_EDNSNOANSWERREC;
968
969 resname = &hostname;
970
971 /* Keep following CNAME records. */
972 while (pkt->ans[ansidx].type == PJ_DNS_TYPE_CNAME &&
973 search_cnt++ < MAX_SEARCH)
974 {
975 resname = &pkt->ans[ansidx].rdata.cname.name;
976
977 if (!alias.slen)
978 alias = *resname;
979
980 for (i=0; i < pkt->hdr.anscount; ++i) {
981 if (pj_stricmp(resname, &pkt->ans[i].name)==0) {
982 break;
983 }
984 }
985
986 if (i==pkt->hdr.anscount)
987 return PJLIB_UTIL_EDNSNOANSWERREC;
988
989 ansidx = i;
990 }
991
992 if (search_cnt >= MAX_SEARCH)
993 return PJLIB_UTIL_EDNSINANSWER;
994
995 if (pkt->ans[ansidx].type != PJ_DNS_TYPE_A)
996 return PJLIB_UTIL_EDNSINANSWER;
997
998 /* Copy alias to the record, if present. */
999 if (alias.slen) {
1000 if (alias.slen > (int)bufleft)
1001 return PJ_ENAMETOOLONG;
1002
1003 pj_memcpy(&rec->buf_[bufstart], alias.ptr, alias.slen);
1004 rec->alias.ptr = &rec->buf_[bufstart];
1005 rec->alias.slen = alias.slen;
1006
1007 bufstart += alias.slen;
1008 bufleft -= alias.slen;
1009 }
1010
1011 /* Get the IP addresses. */
1012 for (i=0; i < pkt->hdr.anscount; ++i) {
1013 if (pkt->ans[i].type == PJ_DNS_TYPE_A &&
1014 pj_stricmp(&pkt->ans[i].name, resname)==0 &&
1015 rec->addr_count < PJ_DNS_MAX_IP_IN_A_REC)
1016 {
1017 rec->addr[rec->addr_count++].s_addr =
1018 pkt->ans[i].rdata.a.ip_addr.s_addr;
1019 }
1020 }
1021
1022 if (rec->addr_count == 0)
1023 return PJLIB_UTIL_EDNSNOANSWERREC;
1024
1025 return PJ_SUCCESS;
1026}
1027
1028
1029/* Set nameserver state */
1030static void set_nameserver_state(pj_dns_resolver *resolver,
1031 unsigned index,
1032 enum ns_state state,
1033 const pj_time_val *now)
1034{
1035 struct nameserver *ns = &resolver->ns[index];
1036 enum ns_state old_state = ns->state;
1037
1038 ns->state = state;
1039 ns->state_expiry = *now;
1040
1041 if (state == STATE_PROBING)
1042 ns->state_expiry.sec += ((resolver->settings.qretr_count + 2) *
1043 resolver->settings.qretr_delay) / 1000;
1044 else if (state == STATE_ACTIVE)
1045 ns->state_expiry.sec += resolver->settings.good_ns_ttl;
1046 else
1047 ns->state_expiry.sec += resolver->settings.bad_ns_ttl;
1048
1049 PJ_LOG(5, (resolver->name.ptr, "Nameserver %s:%d state changed %s --> %s",
1050 pj_inet_ntoa(ns->addr.sin_addr),
1051 (int)pj_ntohs(ns->addr.sin_port),
1052 state_names[old_state], state_names[state]));
1053}
1054
1055
1056/* Select which nameserver(s) to use. Note this may return multiple
1057 * name servers. The algorithm to select which nameservers to be
1058 * sent the request to is as follows:
1059 * - select the first nameserver that is known to be good for the
1060 * last PJ_DNS_RESOLVER_GOOD_NS_TTL interval.
1061 * - for all NSes, if last_known_good >= PJ_DNS_RESOLVER_GOOD_NS_TTL,
1062 * include the NS to re-check again that the server is still good,
1063 * unless the NS is known to be bad in the last PJ_DNS_RESOLVER_BAD_NS_TTL
1064 * interval.
1065 * - for all NSes, if last_known_bad >= PJ_DNS_RESOLVER_BAD_NS_TTL,
1066 * also include the NS to re-check again that the server is still bad.
1067 */
1068static pj_status_t select_nameservers(pj_dns_resolver *resolver,
1069 unsigned *count,
1070 unsigned servers[])
1071{
1072 unsigned i, max_count=*count;
1073 int min;
1074 pj_time_val now;
1075
1076 pj_assert(max_count > 0);
1077
1078 *count = 0;
1079 servers[0] = 0xFFFF;
1080
1081 /* Check that nameservers are configured. */
1082 if (resolver->ns_count == 0)
1083 return PJLIB_UTIL_EDNSNONS;
1084
1085 pj_gettimeofday(&now);
1086
1087 /* Select one Active nameserver with best response time. */
1088 for (min=-1, i=0; i<resolver->ns_count; ++i) {
1089 struct nameserver *ns = &resolver->ns[i];
1090
1091 if (ns->state != STATE_ACTIVE)
1092 continue;
1093
1094 if (min == -1)
1095 min = i;
1096 else if (PJ_TIME_VAL_LT(ns->rt_delay, resolver->ns[min].rt_delay))
1097 min = i;
1098 }
1099 if (min != -1) {
1100 servers[0] = min;
1101 ++(*count);
1102 }
1103
1104 /* Scan nameservers. */
1105 for (i=0; i<resolver->ns_count && *count < max_count; ++i) {
1106 struct nameserver *ns = &resolver->ns[i];
1107
1108 if (PJ_TIME_VAL_LTE(ns->state_expiry, now)) {
1109 if (ns->state == STATE_PROBING) {
1110 set_nameserver_state(resolver, i, STATE_BAD, &now);
1111 } else {
1112 set_nameserver_state(resolver, i, STATE_PROBING, &now);
1113 if ((int)i != min) {
1114 servers[*count] = i;
1115 ++(*count);
1116 }
1117 }
1118 } else if (ns->state == STATE_PROBING && (int)i != min) {
1119 servers[*count] = i;
1120 ++(*count);
1121 }
1122 }
1123
1124 return PJ_SUCCESS;
1125}
1126
1127
1128/* Update name server status */
1129static void report_nameserver_status(pj_dns_resolver *resolver,
1130 const pj_sockaddr_in *ns_addr,
1131 const pj_dns_parsed_packet *pkt)
1132{
1133 unsigned i;
1134 int rcode;
1135 pj_uint32_t q_id;
1136 pj_time_val now;
1137 pj_bool_t is_good;
1138
1139 /* Only mark nameserver as "bad" if it returned non-parseable response or
1140 * it returned the following status codes
1141 */
1142 if (pkt) {
1143 rcode = PJ_DNS_GET_RCODE(pkt->hdr.flags);
1144 q_id = pkt->hdr.id;
1145 } else {
1146 rcode = 0;
1147 q_id = (pj_uint32_t)-1;
1148 }
1149
1150 if (!pkt || rcode == PJ_DNS_RCODE_SERVFAIL ||
1151 rcode == PJ_DNS_RCODE_REFUSED ||
1152 rcode == PJ_DNS_RCODE_NOTAUTH)
1153 {
1154 is_good = PJ_FALSE;
1155 } else {
1156 is_good = PJ_TRUE;
1157 }
1158
1159
1160 /* Mark time */
1161 pj_gettimeofday(&now);
1162
1163 /* Recheck all nameservers. */
1164 for (i=0; i<resolver->ns_count; ++i) {
1165 struct nameserver *ns = &resolver->ns[i];
1166
1167 if (ns->addr.sin_addr.s_addr == ns_addr->sin_addr.s_addr &&
1168 ns->addr.sin_port == ns_addr->sin_port &&
1169 ns->addr.sin_family == ns_addr->sin_family)
1170 {
1171 if (q_id == ns->q_id) {
1172 /* Calculate response time */
1173 pj_time_val rt = now;
1174 PJ_TIME_VAL_SUB(rt, ns->sent_time);
1175 ns->rt_delay = rt;
1176 ns->q_id = 0;
1177 }
1178 set_nameserver_state(resolver, i,
1179 (is_good ? STATE_ACTIVE : STATE_BAD), &now);
1180 break;
1181 }
1182 }
1183}
1184
1185
1186/* Update response cache */
1187static void update_res_cache(pj_dns_resolver *resolver,
1188 const struct res_key *key,
1189 pj_status_t status,
1190 pj_bool_t set_expiry,
1191 const pj_dns_parsed_packet *pkt)
1192{
1193 struct cached_res *cache;
1194 pj_uint32_t hval=0, ttl;
1195
1196 /* If status is unsuccessful, clear the same entry from the cache */
1197 if (status != PJ_SUCCESS) {
1198 cache = (struct cached_res *) pj_hash_get(resolver->hrescache, key,
1199 sizeof(*key), &hval);
1200 if (cache && --cache->ref_cnt <= 0)
1201 free_entry(resolver, cache);
1202 pj_hash_set(NULL, resolver->hrescache, key, sizeof(*key), hval, NULL);
1203 }
1204
1205
1206 /* Calculate expiration time. */
1207 if (set_expiry) {
1208 if (pkt->hdr.anscount == 0 || status != PJ_SUCCESS) {
1209 /* If we don't have answers for the name, then give a different
1210 * ttl value (note: PJ_DNS_RESOLVER_INVALID_TTL may be zero,
1211 * which means that invalid names won't be kept in the cache)
1212 */
1213 ttl = PJ_DNS_RESOLVER_INVALID_TTL;
1214
1215 } else {
1216 /* Otherwise get the minimum TTL from the answers */
1217 unsigned i;
1218 ttl = 0xFFFFFFFF;
1219 for (i=0; i<pkt->hdr.anscount; ++i) {
1220 if (pkt->ans[i].ttl < ttl)
1221 ttl = pkt->ans[i].ttl;
1222 }
1223 }
1224 } else {
1225 ttl = 0xFFFFFFFF;
1226 }
1227
1228 /* Apply maximum TTL */
1229 if (ttl > resolver->settings.cache_max_ttl)
1230 ttl = resolver->settings.cache_max_ttl;
1231
1232 /* If TTL is zero, clear the same entry in the hash table */
1233 if (ttl == 0) {
1234 cache = (struct cached_res *) pj_hash_get(resolver->hrescache, key,
1235 sizeof(*key), &hval);
1236 if (cache && --cache->ref_cnt <= 0)
1237 free_entry(resolver, cache);
1238 pj_hash_set(NULL, resolver->hrescache, key, sizeof(*key), hval, NULL);
1239 return;
1240 }
1241
1242 /* Get a cache response entry */
1243 cache = (struct cached_res *) pj_hash_get(resolver->hrescache, key,
1244 sizeof(*key), &hval);
1245 if (cache == NULL) {
1246 cache = alloc_entry(resolver);
1247 } else if (cache->ref_cnt > 1) {
1248 /* When cache entry is being used by callback (to app), just decrement
1249 * ref_cnt so it will be freed after the callback returns and allocate
1250 * new entry.
1251 */
1252 cache->ref_cnt--;
1253 cache = alloc_entry(resolver);
1254 } else {
1255 /* Reset cache to avoid bloated cache pool */
1256 reset_entry(&cache);
1257 }
1258
1259 /* Duplicate the packet.
1260 * We don't need to keep the NS and AR sections from the packet,
1261 * so exclude from duplication. We do need to keep the Query
1262 * section since DNS A parser needs the query section to know
1263 * the name being requested.
1264 */
1265 pj_dns_packet_dup(cache->pool, pkt,
1266 PJ_DNS_NO_NS | PJ_DNS_NO_AR,
1267 &cache->pkt);
1268
1269 /* Calculate expiration time */
1270 if (set_expiry) {
1271 pj_gettimeofday(&cache->expiry_time);
1272 cache->expiry_time.sec += ttl;
1273 } else {
1274 cache->expiry_time.sec = 0x7FFFFFFFL;
1275 cache->expiry_time.msec = 0;
1276 }
1277
1278 /* Copy key to the cached response */
1279 pj_memcpy(&cache->key, key, sizeof(*key));
1280
1281 /* Update the hash table */
1282 pj_hash_set_np(resolver->hrescache, &cache->key, sizeof(*key), hval,
1283 cache->hbuf, cache);
1284
1285}
1286
1287
1288/* Callback to be called when query has timed out */
1289static void on_timeout( pj_timer_heap_t *timer_heap,
1290 struct pj_timer_entry *entry)
1291{
1292 pj_dns_resolver *resolver;
1293 pj_dns_async_query *q, *cq;
1294 pj_status_t status;
1295
1296 PJ_UNUSED_ARG(timer_heap);
1297
1298 q = (pj_dns_async_query *) entry->user_data;
1299 resolver = q->resolver;
1300
1301 pj_mutex_lock(resolver->mutex);
1302
1303 /* Recheck that this query is still pending, since there is a slight
1304 * possibility of race condition (timer elapsed while at the same time
1305 * response arrives)
1306 */
1307 if (pj_hash_get(resolver->hquerybyid, &q->id, sizeof(q->id), NULL)==NULL) {
1308 /* Yeah, this query is done. */
1309 pj_mutex_unlock(resolver->mutex);
1310 return;
1311 }
1312
1313 /* Invalidate id. */
1314 q->timer_entry.id = 0;
1315
1316 /* Check to see if we should retransmit instead of time out */
1317 if (q->transmit_cnt < resolver->settings.qretr_count) {
1318 status = transmit_query(resolver, q);
1319 if (status == PJ_SUCCESS) {
1320 pj_mutex_unlock(resolver->mutex);
1321 return;
1322 } else {
1323 /* Error occurs */
1324 char errmsg[PJ_ERR_MSG_SIZE];
1325
1326 pj_strerror(status, errmsg, sizeof(errmsg));
1327 PJ_LOG(4,(resolver->name.ptr,
1328 "Error transmitting request: %s", errmsg));
1329
1330 /* Let it fallback to timeout section below */
1331 }
1332 }
1333
1334 /* Clear hash table entries */
1335 pj_hash_set(NULL, resolver->hquerybyid, &q->id, sizeof(q->id), 0, NULL);
1336 pj_hash_set(NULL, resolver->hquerybyres, &q->key, sizeof(q->key), 0, NULL);
1337
1338 /* Workaround for deadlock problem in #1565 (similar to #1108) */
1339 pj_mutex_unlock(resolver->mutex);
1340
1341 /* Call application callback, if any. */
1342 if (q->cb)
1343 (*q->cb)(q->user_data, PJ_ETIMEDOUT, NULL);
1344
1345 /* Call application callback for child queries. */
1346 cq = q->child_head.next;
1347 while (cq != (void*)&q->child_head) {
1348 if (cq->cb)
1349 (*cq->cb)(cq->user_data, PJ_ETIMEDOUT, NULL);
1350 cq = cq->next;
1351 }
1352
1353 /* Workaround for deadlock problem in #1565 (similar to #1108) */
1354 pj_mutex_lock(resolver->mutex);
1355
1356 /* Clear data */
1357 q->timer_entry.id = 0;
1358 q->user_data = NULL;
1359
1360 /* Put child entries into recycle list */
1361 cq = q->child_head.next;
1362 while (cq != (void*)&q->child_head) {
1363 pj_dns_async_query *next = cq->next;
1364 pj_list_push_back(&resolver->query_free_nodes, cq);
1365 cq = next;
1366 }
1367
1368 /* Put query entry into recycle list */
1369 pj_list_push_back(&resolver->query_free_nodes, q);
1370
1371 pj_mutex_unlock(resolver->mutex);
1372}
1373
1374
1375/* Callback from ioqueue when packet is received */
1376static void on_read_complete(pj_ioqueue_key_t *key,
1377 pj_ioqueue_op_key_t *op_key,
1378 pj_ssize_t bytes_read)
1379{
1380 pj_dns_resolver *resolver;
1381 pj_pool_t *pool = NULL;
1382 pj_dns_parsed_packet *dns_pkt;
1383 pj_dns_async_query *q;
1384 pj_status_t status;
1385 PJ_USE_EXCEPTION;
1386
1387
1388 resolver = (pj_dns_resolver *) pj_ioqueue_get_user_data(key);
1389 pj_mutex_lock(resolver->mutex);
1390
1391
1392 /* Check for errors */
1393 if (bytes_read < 0) {
1394 char errmsg[PJ_ERR_MSG_SIZE];
1395
1396 status = (pj_status_t)-bytes_read;
1397 pj_strerror(status, errmsg, sizeof(errmsg));
1398 PJ_LOG(4,(resolver->name.ptr,
1399 "DNS resolver read error from %s:%d: %s",
1400 pj_inet_ntoa(resolver->udp_src_addr.sin_addr),
1401 pj_ntohs(resolver->udp_src_addr.sin_port),
1402 errmsg));
1403
1404 goto read_next_packet;
1405 }
1406
1407 PJ_LOG(5,(resolver->name.ptr,
1408 "Received %d bytes DNS response from %s:%d",
1409 (int)bytes_read,
1410 pj_inet_ntoa(resolver->udp_src_addr.sin_addr),
1411 pj_ntohs(resolver->udp_src_addr.sin_port)));
1412
1413
1414 /* Check for zero packet */
1415 if (bytes_read == 0)
1416 goto read_next_packet;
1417
1418 /* Create temporary pool from a fixed buffer */
1419 pool = pj_pool_create_on_buf("restmp", resolver->tmp_pool,
1420 sizeof(resolver->tmp_pool));
1421
1422 /* Parse DNS response */
1423 status = -1;
1424 dns_pkt = NULL;
1425 PJ_TRY {
1426 status = pj_dns_parse_packet(pool, resolver->udp_rx_pkt,
1427 (unsigned)bytes_read, &dns_pkt);
1428 }
1429 PJ_CATCH_ANY {
1430 status = PJ_ENOMEM;
1431 }
1432 PJ_END;
1433
1434 /* Update nameserver status */
1435 report_nameserver_status(resolver, &resolver->udp_src_addr, dns_pkt);
1436
1437 /* Handle parse error */
1438 if (status != PJ_SUCCESS) {
1439 char errmsg[PJ_ERR_MSG_SIZE];
1440
1441 pj_strerror(status, errmsg, sizeof(errmsg));
1442 PJ_LOG(3,(resolver->name.ptr,
1443 "Error parsing DNS response from %s:%d: %s",
1444 pj_inet_ntoa(resolver->udp_src_addr.sin_addr),
1445 pj_ntohs(resolver->udp_src_addr.sin_port),
1446 errmsg));
1447 goto read_next_packet;
1448 }
1449
1450 /* Find the query based on the transaction ID */
1451 q = (pj_dns_async_query*)
1452 pj_hash_get(resolver->hquerybyid, &dns_pkt->hdr.id,
1453 sizeof(dns_pkt->hdr.id), NULL);
1454 if (!q) {
1455 PJ_LOG(5,(resolver->name.ptr,
1456 "DNS response from %s:%d id=%d discarded",
1457 pj_inet_ntoa(resolver->udp_src_addr.sin_addr),
1458 pj_ntohs(resolver->udp_src_addr.sin_port),
1459 (unsigned)dns_pkt->hdr.id));
1460 goto read_next_packet;
1461 }
1462
1463 /* Map DNS Rcode in the response into PJLIB status name space */
1464 status = PJ_STATUS_FROM_DNS_RCODE(PJ_DNS_GET_RCODE(dns_pkt->hdr.flags));
1465
1466 /* Cancel query timeout timer. */
1467 pj_assert(q->timer_entry.id != 0);
1468 pj_timer_heap_cancel(resolver->timer, &q->timer_entry);
1469 q->timer_entry.id = 0;
1470
1471 /* Clear hash table entries */
1472 pj_hash_set(NULL, resolver->hquerybyid, &q->id, sizeof(q->id), 0, NULL);
1473 pj_hash_set(NULL, resolver->hquerybyres, &q->key, sizeof(q->key), 0, NULL);
1474
1475 /* Workaround for deadlock problem in #1108 */
1476 pj_mutex_unlock(resolver->mutex);
1477
1478 /* Notify applications first, to allow application to modify the
1479 * record before it is saved to the hash table.
1480 */
1481 if (q->cb)
1482 (*q->cb)(q->user_data, status, dns_pkt);
1483
1484 /* If query has subqueries, notify subqueries's application callback */
1485 if (!pj_list_empty(&q->child_head)) {
1486 pj_dns_async_query *child_q;
1487
1488 child_q = q->child_head.next;
1489 while (child_q != (pj_dns_async_query*)&q->child_head) {
1490 if (child_q->cb)
1491 (*child_q->cb)(child_q->user_data, status, dns_pkt);
1492 child_q = child_q->next;
1493 }
1494 }
1495
1496 /* Workaround for deadlock problem in #1108 */
1497 pj_mutex_lock(resolver->mutex);
1498
1499 /* Save/update response cache. */
1500 update_res_cache(resolver, &q->key, status, PJ_TRUE, dns_pkt);
1501
1502 /* Recycle query objects, starting with the child queries */
1503 if (!pj_list_empty(&q->child_head)) {
1504 pj_dns_async_query *child_q;
1505
1506 child_q = q->child_head.next;
1507 while (child_q != (pj_dns_async_query*)&q->child_head) {
1508 pj_dns_async_query *next = child_q->next;
1509 pj_list_erase(child_q);
1510 pj_list_push_back(&resolver->query_free_nodes, child_q);
1511 child_q = next;
1512 }
1513 }
1514 pj_list_push_back(&resolver->query_free_nodes, q);
1515
1516read_next_packet:
1517 if (pool) {
1518 /* needed just in case PJ_HAS_POOL_ALT_API is set */
1519 pj_pool_release(pool);
1520 }
1521 bytes_read = sizeof(resolver->udp_rx_pkt);
1522 resolver->udp_addr_len = sizeof(resolver->udp_src_addr);
1523 status = pj_ioqueue_recvfrom(resolver->udp_key, op_key,
1524 resolver->udp_rx_pkt,
1525 &bytes_read, PJ_IOQUEUE_ALWAYS_ASYNC,
1526 &resolver->udp_src_addr,
1527 &resolver->udp_addr_len);
1528 if (status != PJ_EPENDING) {
1529 char errmsg[PJ_ERR_MSG_SIZE];
1530
1531 pj_strerror(status, errmsg, sizeof(errmsg));
1532 PJ_LOG(4,(resolver->name.ptr, "DNS resolver ioqueue read error: %s",
1533 errmsg));
1534
1535 pj_assert(!"Unhandled error");
1536 }
1537
1538 pj_mutex_unlock(resolver->mutex);
1539}
1540
1541
1542/*
1543 * Put the specified DNS packet into DNS cache. This function is mainly used
1544 * for testing the resolver, however it can also be used to inject entries
1545 * into the resolver.
1546 */
1547PJ_DEF(pj_status_t) pj_dns_resolver_add_entry( pj_dns_resolver *resolver,
1548 const pj_dns_parsed_packet *pkt,
1549 pj_bool_t set_ttl)
1550{
1551 struct res_key key;
1552
1553 /* Sanity check */
1554 PJ_ASSERT_RETURN(resolver && pkt, PJ_EINVAL);
1555
1556 /* Packet must be a DNS response */
1557 PJ_ASSERT_RETURN(PJ_DNS_GET_QR(pkt->hdr.flags) & 1, PJ_EINVAL);
1558
1559 /* Make sure there are answers in the packet */
1560 PJ_ASSERT_RETURN((pkt->hdr.anscount && pkt->ans) ||
1561 (pkt->hdr.qdcount && pkt->q),
1562 PJLIB_UTIL_EDNSNOANSWERREC);
1563
1564 pj_mutex_lock(resolver->mutex);
1565
1566 /* Build resource key for looking up hash tables */
1567 pj_bzero(&key, sizeof(struct res_key));
1568 if (pkt->hdr.anscount) {
1569 /* Make sure name is not too long. */
1570 PJ_ASSERT_RETURN(pkt->ans[0].name.slen < PJ_MAX_HOSTNAME,
1571 PJ_ENAMETOOLONG);
1572
1573 init_res_key(&key, pkt->ans[0].type, &pkt->ans[0].name);
1574
1575 } else {
1576 /* Make sure name is not too long. */
1577 PJ_ASSERT_RETURN(pkt->q[0].name.slen < PJ_MAX_HOSTNAME,
1578 PJ_ENAMETOOLONG);
1579
1580 init_res_key(&key, pkt->q[0].type, &pkt->q[0].name);
1581 }
1582
1583 /* Insert entry. */
1584 update_res_cache(resolver, &key, PJ_SUCCESS, set_ttl, pkt);
1585
1586 pj_mutex_unlock(resolver->mutex);
1587
1588 return PJ_SUCCESS;
1589}
1590
1591
1592/*
1593 * Get the total number of response in the response cache.
1594 */
1595PJ_DEF(unsigned) pj_dns_resolver_get_cached_count(pj_dns_resolver *resolver)
1596{
1597 unsigned count;
1598
1599 PJ_ASSERT_RETURN(resolver, 0);
1600
1601 pj_mutex_lock(resolver->mutex);
1602 count = pj_hash_count(resolver->hrescache);
1603 pj_mutex_unlock(resolver->mutex);
1604
1605 return count;
1606}
1607
1608
1609/*
1610 * Dump resolver state to the log.
1611 */
1612PJ_DEF(void) pj_dns_resolver_dump(pj_dns_resolver *resolver,
1613 pj_bool_t detail)
1614{
1615#if PJ_LOG_MAX_LEVEL >= 3
1616 unsigned i;
1617 pj_time_val now;
1618
1619 pj_mutex_lock(resolver->mutex);
1620
1621 pj_gettimeofday(&now);
1622
1623 PJ_LOG(3,(resolver->name.ptr, " Dumping resolver state:"));
1624
1625 PJ_LOG(3,(resolver->name.ptr, " Name servers:"));
1626 for (i=0; i<resolver->ns_count; ++i) {
1627 const char *state_names[] = { "probing", "active", "bad"};
1628 struct nameserver *ns = &resolver->ns[i];
1629
1630 PJ_LOG(3,(resolver->name.ptr,
1631 " NS %d: %s:%d (state=%s until %ds, rtt=%d ms)",
1632 i, pj_inet_ntoa(ns->addr.sin_addr),
1633 pj_ntohs(ns->addr.sin_port),
1634 state_names[ns->state],
1635 ns->state_expiry.sec - now.sec,
1636 PJ_TIME_VAL_MSEC(ns->rt_delay)));
1637 }
1638
1639 PJ_LOG(3,(resolver->name.ptr, " Nb. of cached responses: %u",
1640 pj_hash_count(resolver->hrescache)));
1641 if (detail) {
1642 pj_hash_iterator_t itbuf, *it;
1643 it = pj_hash_first(resolver->hrescache, &itbuf);
1644 while (it) {
1645 struct cached_res *cache;
1646 cache = (struct cached_res*)pj_hash_this(resolver->hrescache, it);
1647 PJ_LOG(3,(resolver->name.ptr,
1648 " Type %s: %s",
1649 pj_dns_get_type_name(cache->key.qtype),
1650 cache->key.name));
1651 it = pj_hash_next(resolver->hrescache, it);
1652 }
1653 }
1654 PJ_LOG(3,(resolver->name.ptr, " Nb. of pending queries: %u (%u)",
1655 pj_hash_count(resolver->hquerybyid),
1656 pj_hash_count(resolver->hquerybyres)));
1657 if (detail) {
1658 pj_hash_iterator_t itbuf, *it;
1659 it = pj_hash_first(resolver->hquerybyid, &itbuf);
1660 while (it) {
1661 struct pj_dns_async_query *q;
1662 q = (pj_dns_async_query*) pj_hash_this(resolver->hquerybyid, it);
1663 PJ_LOG(3,(resolver->name.ptr,
1664 " Type %s: %s",
1665 pj_dns_get_type_name(q->key.qtype),
1666 q->key.name));
1667 it = pj_hash_next(resolver->hquerybyid, it);
1668 }
1669 }
1670 PJ_LOG(3,(resolver->name.ptr, " Nb. of pending query free nodes: %u",
1671 pj_list_size(&resolver->query_free_nodes)));
1672 PJ_LOG(3,(resolver->name.ptr, " Nb. of timer entries: %u",
1673 pj_timer_heap_count(resolver->timer)));
1674 PJ_LOG(3,(resolver->name.ptr, " Pool capacity: %d, used size: %d",
1675 pj_pool_get_capacity(resolver->pool),
1676 pj_pool_get_used_size(resolver->pool)));
1677
1678 pj_mutex_unlock(resolver->mutex);
1679#endif
1680}
1681