1
/* $Id: resolver.c 4333 2013-01-23 09:53:39Z nanang $ */
3
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
4
* Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
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.
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.
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
20
#include <pjlib-util/resolver.h>
21
#include <pjlib-util/errno.h>
22
#include <pj/assert.h>
24
#include <pj/except.h>
26
#include <pj/ioqueue.h>
30
#include <pj/pool_buf.h>
32
#include <pj/string.h>
37
#define THIS_FILE "resolver.c"
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.
43
#if PJ_DNS_RESOLVER_MAX_NS > 256
44
# error "PJ_DNS_RESOLVER_MAX_NS is too large (max=256)"
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. */
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
59
/* Nameserver state */
67
static const char *state_names[3] =
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.
82
pj_sockaddr_in addr; /**< Server address. */
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. */
89
/* For calculating rt_delay: */
90
pj_uint16_t q_id; /**< Query ID. */
91
pj_time_val sent_time; /**< Time this query is sent. */
95
/* Child query list head
96
* See comments on pj_dns_async_query below.
100
PJ_DECL_LIST_MEMBER(pj_dns_async_query);
104
/* Key to look for outstanding query and/or cached response */
107
pj_uint16_t qtype; /**< Query type. */
108
char name[PJ_MAX_HOSTNAME]; /**< Name being queried */
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
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.
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.
128
struct pj_dns_async_query
130
PJ_DECL_LIST_MEMBER(pj_dns_async_query); /**< List member. */
132
pj_dns_resolver *resolver; /**< The resolver instance. */
133
pj_uint16_t id; /**< Transaction ID. */
135
unsigned transmit_cnt; /**< Number of transmissions. */
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. */
148
/* This structure is used to keep cached response entry.
149
* The cache is a hash table keyed on "res_key" structure above.
153
PJ_DECL_LIST_MEMBER(struct cached_res);
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. */
164
struct pj_dns_resolver
166
pj_str_t name; /**< Resolver instance name for id. */
169
pj_pool_t *pool; /**< Internal pool. */
170
pj_mutex_t *mutex; /**< Mutex protection. */
171
pj_bool_t own_timer; /**< Do we own timer? */
172
pj_timer_heap_t *timer; /**< Timer instance. */
173
pj_bool_t own_ioqueue; /**< Do we own ioqueue? */
174
pj_ioqueue_t *ioqueue; /**< Ioqueue instance. */
175
char tmp_pool[TMP_SZ];/**< Temporary pool buffer. */
178
pj_sock_t udp_sock; /**< UDP socket. */
179
pj_ioqueue_key_t *udp_key; /**< UDP socket ioqueue key. */
180
unsigned char udp_rx_pkt[UDPSZ];/**< UDP receive buffer. */
181
unsigned char udp_tx_pkt[UDPSZ];/**< UDP receive buffer. */
182
pj_ssize_t udp_len; /**< Length of received packet. */
183
pj_ioqueue_op_key_t udp_op_rx_key; /**< UDP read operation key. */
184
pj_ioqueue_op_key_t udp_op_tx_key; /**< UDP write operation key. */
185
pj_sockaddr_in udp_src_addr; /**< Source address of packet */
186
int udp_addr_len; /**< Source address length. */
189
pj_dns_settings settings; /**< Resolver settings. */
192
unsigned ns_count; /**< Number of name servers. */
193
struct nameserver ns[PJ_DNS_RESOLVER_MAX_NS]; /**< Array of NS. */
195
/* Last DNS transaction ID used. */
198
/* Hash table for cached response */
199
pj_hash_table_t *hrescache; /**< Cached response in hash table */
201
/* Pending asynchronous query, hashed by transaction ID. */
202
pj_hash_table_t *hquerybyid;
204
/* Pending asynchronous query, hashed by "res_key" */
205
pj_hash_table_t *hquerybyres;
207
/* Query entries free list */
208
struct query_head query_free_nodes;
212
/* Callback from ioqueue when packet is received */
213
static void on_read_complete(pj_ioqueue_key_t *key,
214
pj_ioqueue_op_key_t *op_key,
215
pj_ssize_t bytes_read);
217
/* Callback to be called when query has timed out */
218
static void on_timeout( pj_timer_heap_t *timer_heap,
219
struct pj_timer_entry *entry);
221
/* Select which nameserver to use */
222
static pj_status_t select_nameservers(pj_dns_resolver *resolver,
227
/* Close UDP socket */
228
static void close_sock(pj_dns_resolver *resv)
230
/* Close existing socket */
231
if (resv->udp_key != NULL) {
232
pj_ioqueue_unregister(resv->udp_key);
233
resv->udp_key = NULL;
234
resv->udp_sock = PJ_INVALID_SOCKET;
235
} else if (resv->udp_sock != PJ_INVALID_SOCKET) {
236
pj_sock_close(resv->udp_sock);
237
resv->udp_sock = PJ_INVALID_SOCKET;
242
/* Initialize UDP socket */
243
static pj_status_t init_sock(pj_dns_resolver *resv)
245
pj_ioqueue_callback socket_cb;
248
/* Create the UDP socket */
249
status = pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, &resv->udp_sock);
250
if (status != PJ_SUCCESS)
253
/* Bind to any address/port */
254
status = pj_sock_bind_in(resv->udp_sock, 0, 0);
255
if (status != PJ_SUCCESS)
258
/* Register to ioqueue */
259
pj_bzero(&socket_cb, sizeof(socket_cb));
260
socket_cb.on_read_complete = &on_read_complete;
261
status = pj_ioqueue_register_sock(resv->pool, resv->ioqueue,
262
resv->udp_sock, resv, &socket_cb,
264
if (status != PJ_SUCCESS)
267
pj_ioqueue_op_key_init(&resv->udp_op_rx_key, sizeof(resv->udp_op_rx_key));
268
pj_ioqueue_op_key_init(&resv->udp_op_tx_key, sizeof(resv->udp_op_tx_key));
270
/* Start asynchronous read to the UDP socket */
271
resv->udp_len = sizeof(resv->udp_rx_pkt);
272
resv->udp_addr_len = sizeof(resv->udp_src_addr);
273
status = pj_ioqueue_recvfrom(resv->udp_key, &resv->udp_op_rx_key,
274
resv->udp_rx_pkt, &resv->udp_len,
275
PJ_IOQUEUE_ALWAYS_ASYNC,
276
&resv->udp_src_addr, &resv->udp_addr_len);
277
if (status != PJ_EPENDING)
284
/* Initialize DNS settings with default values */
285
PJ_DEF(void) pj_dns_settings_default(pj_dns_settings *s)
287
pj_bzero(s, sizeof(pj_dns_settings));
288
s->qretr_delay = PJ_DNS_RESOLVER_QUERY_RETRANSMIT_DELAY;
289
s->qretr_count = PJ_DNS_RESOLVER_QUERY_RETRANSMIT_COUNT;
290
s->cache_max_ttl = PJ_DNS_RESOLVER_MAX_TTL;
291
s->good_ns_ttl = PJ_DNS_RESOLVER_GOOD_NS_TTL;
292
s->bad_ns_ttl = PJ_DNS_RESOLVER_BAD_NS_TTL;
297
* Create the resolver.
299
PJ_DEF(pj_status_t) pj_dns_resolver_create( pj_pool_factory *pf,
302
pj_timer_heap_t *timer,
303
pj_ioqueue_t *ioqueue,
304
pj_dns_resolver **p_resolver)
307
pj_dns_resolver *resv;
311
PJ_ASSERT_RETURN(pf && p_resolver, PJ_EINVAL);
316
/* Create and initialize resolver instance */
317
pool = pj_pool_create(pf, name, 4000, 4000, NULL);
321
/* Create pool and name */
322
resv = PJ_POOL_ZALLOC_T(pool, struct pj_dns_resolver);
324
resv->udp_sock = PJ_INVALID_SOCKET;
325
pj_strdup2_with_null(pool, &resv->name, name);
327
/* Create the mutex */
328
status = pj_mutex_create_recursive(pool, name, &resv->mutex);
329
if (status != PJ_SUCCESS)
332
/* Timer, ioqueue, and settings */
334
resv->ioqueue = ioqueue;
337
pj_dns_settings_default(&resv->settings);
338
resv->settings.options = options;
340
/* Create the timer heap if one is not specified */
341
if (resv->timer == NULL) {
342
status = pj_timer_heap_create(pool, TIMER_SIZE, &resv->timer);
343
if (status != PJ_SUCCESS)
347
/* Create the ioqueue if one is not specified */
348
if (resv->ioqueue == NULL) {
349
status = pj_ioqueue_create(pool, MAX_FD, &resv->ioqueue);
350
if (status != PJ_SUCCESS)
354
/* Response cache hash table */
355
resv->hrescache = pj_hash_create(pool, RES_HASH_TABLE_SIZE);
357
/* Query hash table and free list. */
358
resv->hquerybyid = pj_hash_create(pool, Q_HASH_TABLE_SIZE);
359
resv->hquerybyres = pj_hash_create(pool, Q_HASH_TABLE_SIZE);
360
pj_list_init(&resv->query_free_nodes);
362
/* Initialize the UDP socket */
363
status = init_sock(resv);
364
if (status != PJ_SUCCESS)
367
/* Looks like everything is okay */
372
pj_dns_resolver_destroy(resv, PJ_FALSE);
378
* Destroy DNS resolver instance.
380
PJ_DEF(pj_status_t) pj_dns_resolver_destroy( pj_dns_resolver *resolver,
383
pj_hash_iterator_t it_buf, *it;
384
PJ_ASSERT_RETURN(resolver, PJ_EINVAL);
388
* Notify pending queries if requested.
390
it = pj_hash_first(resolver->hquerybyid, &it_buf);
392
pj_dns_async_query *q = (pj_dns_async_query *)
393
pj_hash_this(resolver->hquerybyid, it);
394
pj_dns_async_query *cq;
396
(*q->cb)(q->user_data, PJ_ECANCELLED, NULL);
398
cq = q->child_head.next;
399
while (cq != (pj_dns_async_query*)&q->child_head) {
401
(*cq->cb)(cq->user_data, PJ_ECANCELLED, NULL);
404
it = pj_hash_next(resolver->hquerybyid, it);
408
/* Destroy cached entries */
409
it = pj_hash_first(resolver->hrescache, &it_buf);
411
struct cached_res *cache;
413
cache = (struct cached_res*) pj_hash_this(resolver->hrescache, it);
414
pj_hash_set(NULL, resolver->hrescache, &cache->key,
415
sizeof(cache->key), 0, NULL);
416
pj_pool_release(cache->pool);
418
it = pj_hash_first(resolver->hrescache, &it_buf);
421
if (resolver->own_timer && resolver->timer) {
422
pj_timer_heap_destroy(resolver->timer);
423
resolver->timer = NULL;
426
close_sock(resolver);
428
if (resolver->own_ioqueue && resolver->ioqueue) {
429
pj_ioqueue_destroy(resolver->ioqueue);
430
resolver->ioqueue = NULL;
433
if (resolver->mutex) {
434
pj_mutex_destroy(resolver->mutex);
435
resolver->mutex = NULL;
438
if (resolver->pool) {
439
pj_pool_t *pool = resolver->pool;
440
resolver->pool = NULL;
441
pj_pool_release(pool);
449
* Configure name servers for the DNS resolver.
451
PJ_DEF(pj_status_t) pj_dns_resolver_set_ns( pj_dns_resolver *resolver,
453
const pj_str_t servers[],
454
const pj_uint16_t ports[])
460
PJ_ASSERT_RETURN(resolver && count && servers, PJ_EINVAL);
461
PJ_ASSERT_RETURN(count < PJ_DNS_RESOLVER_MAX_NS, PJ_EINVAL);
463
pj_mutex_lock(resolver->mutex);
465
if (count > PJ_DNS_RESOLVER_MAX_NS)
466
count = PJ_DNS_RESOLVER_MAX_NS;
468
resolver->ns_count = 0;
469
pj_bzero(resolver->ns, sizeof(resolver->ns));
471
pj_gettimeofday(&now);
473
for (i=0; i<count; ++i) {
474
struct nameserver *ns = &resolver->ns[i];
476
status = pj_sockaddr_in_init(&ns->addr, &servers[i],
477
(pj_uint16_t)(ports ? ports[i] : PORT));
478
if (status != PJ_SUCCESS) {
479
pj_mutex_unlock(resolver->mutex);
480
return PJLIB_UTIL_EDNSINNSADDR;
483
ns->state = STATE_ACTIVE;
484
ns->state_expiry = now;
485
ns->rt_delay.sec = 10;
488
resolver->ns_count = count;
490
pj_mutex_unlock(resolver->mutex);
497
* Modify the resolver settings.
499
PJ_DEF(pj_status_t) pj_dns_resolver_set_settings(pj_dns_resolver *resolver,
500
const pj_dns_settings *st)
502
PJ_ASSERT_RETURN(resolver && st, PJ_EINVAL);
504
pj_mutex_lock(resolver->mutex);
505
pj_memcpy(&resolver->settings, st, sizeof(*st));
506
pj_mutex_unlock(resolver->mutex);
512
* Get the resolver current settings.
514
PJ_DEF(pj_status_t) pj_dns_resolver_get_settings( pj_dns_resolver *resolver,
517
PJ_ASSERT_RETURN(resolver && st, PJ_EINVAL);
519
pj_mutex_lock(resolver->mutex);
520
pj_memcpy(st, &resolver->settings, sizeof(*st));
521
pj_mutex_unlock(resolver->mutex);
527
* Poll for events from the resolver.
529
PJ_DEF(void) pj_dns_resolver_handle_events(pj_dns_resolver *resolver,
530
const pj_time_val *timeout)
532
PJ_ASSERT_ON_FAIL(resolver, return);
534
pj_mutex_lock(resolver->mutex);
535
pj_timer_heap_poll(resolver->timer, NULL);
536
pj_mutex_unlock(resolver->mutex);
538
pj_ioqueue_poll(resolver->ioqueue, timeout);
542
/* Get one query node from the free node, if any, or allocate
545
static pj_dns_async_query *alloc_qnode(pj_dns_resolver *resolver,
550
pj_dns_async_query *q;
552
/* Merge query options with resolver options */
553
options |= resolver->settings.options;
555
if (!pj_list_empty(&resolver->query_free_nodes)) {
556
q = resolver->query_free_nodes.next;
558
pj_bzero(q, sizeof(*q));
560
q = PJ_POOL_ZALLOC_T(resolver->pool, pj_dns_async_query);
564
q->resolver = resolver;
565
q->options = options;
566
q->user_data = user_data;
568
pj_list_init(&q->child_head);
577
static pj_status_t transmit_query(pj_dns_resolver *resolver,
578
pj_dns_async_query *q)
581
unsigned i, server_cnt;
582
unsigned servers[PJ_DNS_RESOLVER_MAX_NS];
588
/* Select which nameserver(s) to send requests to. */
589
server_cnt = PJ_ARRAY_SIZE(servers);
590
status = select_nameservers(resolver, &server_cnt, servers);
591
if (status != PJ_SUCCESS) {
595
if (server_cnt == 0) {
596
return PJLIB_UTIL_EDNSNOWORKINGNS;
599
/* Start retransmit/timeout timer for the query */
600
pj_assert(q->timer_entry.id == 0);
601
q->timer_entry.id = 1;
602
q->timer_entry.user_data = q;
603
q->timer_entry.cb = &on_timeout;
606
delay.msec = resolver->settings.qretr_delay;
607
pj_time_val_normalize(&delay);
608
status = pj_timer_heap_schedule(resolver->timer, &q->timer_entry, &delay);
609
if (status != PJ_SUCCESS) {
613
/* Check if the socket is available for sending */
614
if (pj_ioqueue_is_pending(resolver->udp_key, &resolver->udp_op_tx_key)) {
616
PJ_LOG(4,(resolver->name.ptr,
617
"Socket busy in transmitting DNS %s query for %s%s",
618
pj_dns_get_type_name(q->key.qtype),
620
(q->transmit_cnt < resolver->settings.qretr_count?
621
", will try again later":"")));
625
/* Create DNS query packet */
626
pkt_size = sizeof(resolver->udp_tx_pkt);
627
name = pj_str(q->key.name);
628
status = pj_dns_make_query(resolver->udp_tx_pkt, &pkt_size,
629
q->id, q->key.qtype, &name);
630
if (status != PJ_SUCCESS) {
631
pj_timer_heap_cancel(resolver->timer, &q->timer_entry);
635
/* Get current time. */
636
pj_gettimeofday(&now);
638
/* Send the packet to name servers */
639
for (i=0; i<server_cnt; ++i) {
640
pj_ssize_t sent = (pj_ssize_t) pkt_size;
641
struct nameserver *ns = &resolver->ns[servers[i]];
643
status = pj_ioqueue_sendto(resolver->udp_key,
644
&resolver->udp_op_tx_key,
645
resolver->udp_tx_pkt, &sent, 0,
646
&resolver->ns[servers[i]].addr,
647
sizeof(pj_sockaddr_in));
649
PJ_PERROR(4,(resolver->name.ptr, status,
650
"%s %d bytes to NS %d (%s:%d): DNS %s query for %s",
651
(q->transmit_cnt==0? "Transmitting":"Re-transmitting"),
652
(int)pkt_size, servers[i],
653
pj_inet_ntoa(ns->addr.sin_addr),
654
(int)pj_ntohs(ns->addr.sin_port),
655
pj_dns_get_type_name(q->key.qtype),
671
* Initialize resource key for hash table lookup.
673
static void init_res_key(struct res_key *key, int type, const pj_str_t *name)
676
char *dst = key->name;
677
const char *src = name->ptr;
679
pj_bzero(key, sizeof(struct res_key));
680
key->qtype = (pj_uint16_t)type;
683
if (len > PJ_MAX_HOSTNAME) len = PJ_MAX_HOSTNAME;
685
/* Copy key, in lowercase */
686
for (i=0; i<len; ++i) {
687
*dst++ = (char)pj_tolower(*src++);
692
/* Allocate new cache entry */
693
static struct cached_res *alloc_entry(pj_dns_resolver *resolver)
696
struct cached_res *cache;
698
pool = pj_pool_create(resolver->pool->factory, "dnscache",
699
RES_BUF_SZ, 256, NULL);
700
cache = PJ_POOL_ZALLOC_T(pool, struct cached_res);
706
/* Put unused/expired cached entry to the free list */
707
static void free_entry(pj_dns_resolver *resolver, struct cached_res *cache)
709
PJ_UNUSED_ARG(resolver);
710
pj_pool_release(cache->pool);
715
* Create and start asynchronous DNS query for a single resource.
717
PJ_DEF(pj_status_t) pj_dns_resolver_start_query( pj_dns_resolver *resolver,
718
const pj_str_t *name,
723
pj_dns_async_query **p_query)
727
struct cached_res *cache;
728
pj_dns_async_query *q;
730
pj_status_t status = PJ_SUCCESS;
732
/* Validate arguments */
733
PJ_ASSERT_RETURN(resolver && name && type, PJ_EINVAL);
735
/* Check name is not too long. */
736
PJ_ASSERT_RETURN(name->slen>0 && name->slen < PJ_MAX_HOSTNAME,
740
PJ_ASSERT_RETURN(type > 0 && type < 0xFFFF, PJ_EINVAL);
745
/* Build resource key for looking up hash tables */
746
init_res_key(&key, type, name);
748
/* Start working with the resolver */
749
pj_mutex_lock(resolver->mutex);
751
/* Get current time. */
752
pj_gettimeofday(&now);
754
/* First, check if we have cached response for the specified name/type,
755
* and the cached entry has not expired.
758
cache = (struct cached_res *) pj_hash_get(resolver->hrescache, &key,
761
/* We've found a cached entry. */
763
/* Check for expiration */
764
if (PJ_TIME_VAL_GT(cache->expiry_time, now)) {
767
PJ_LOG(5,(resolver->name.ptr,
768
"Picked up DNS %s record for %.*s from cache, ttl=%d",
769
pj_dns_get_type_name(type),
770
(int)name->slen, name->ptr,
771
(int)(cache->expiry_time.sec - now.sec)));
773
/* Map DNS Rcode in the response into PJLIB status name space */
774
status = PJ_DNS_GET_RCODE(cache->pkt->hdr.flags);
775
status = PJ_STATUS_FROM_DNS_RCODE(status);
777
/* This cached response is still valid. Just return this
778
* response to caller.
781
(*cb)(user_data, status, cache->pkt);
784
/* Done. No host resolution is necessary */
786
/* Must return PJ_SUCCESS */
792
/* At this point, we have a cached entry, but this entry has expired.
793
* Remove this entry from the cached list.
795
pj_hash_set(NULL, resolver->hrescache, &key, sizeof(key), 0, NULL);
797
/* Store the entry into free nodes */
798
free_entry(resolver, cache);
800
/* Must continue with creating a query now */
803
/* Next, check if we have pending query on the same resource */
804
q = (pj_dns_async_query *) pj_hash_get(resolver->hquerybyres, &key,
807
/* Yes, there's another pending query to the same key.
808
* Just create a new child query and add this query to
809
* pending query's child queries.
811
pj_dns_async_query *nq;
813
nq = alloc_qnode(resolver, options, user_data, cb);
814
pj_list_push_back(&q->child_head, nq);
816
/* Done. This child query will be notified once the "parent"
823
/* There's no pending query to the same key, initiate a new one. */
824
q = alloc_qnode(resolver, options, user_data, cb);
826
/* Save the ID and key */
827
/* TODO: dnsext-forgery-resilient: randomize id for security */
828
q->id = resolver->last_id++;
829
if (resolver->last_id == 0)
830
resolver->last_id = 1;
831
pj_memcpy(&q->key, &key, sizeof(struct res_key));
834
status = transmit_query(resolver, q);
835
if (status != PJ_SUCCESS) {
836
pj_list_push_back(&resolver->query_free_nodes, q);
840
/* Add query entry to the hash tables */
841
pj_hash_set_np(resolver->hquerybyid, &q->id, sizeof(q->id),
843
pj_hash_set_np(resolver->hquerybyres, &q->key, sizeof(q->key),
850
pj_mutex_unlock(resolver->mutex);
856
* Cancel a pending query.
858
PJ_DEF(pj_status_t) pj_dns_resolver_cancel_query(pj_dns_async_query *query,
863
PJ_ASSERT_RETURN(query, PJ_EINVAL);
865
pj_mutex_lock(query->resolver->mutex);
871
(*cb)(query->user_data, PJ_ECANCELLED, NULL);
873
pj_mutex_unlock(query->resolver->mutex);
879
* DNS response containing A packet.
881
PJ_DEF(pj_status_t) pj_dns_parse_a_response(const pj_dns_parsed_packet *pkt,
882
pj_dns_a_record *rec)
884
enum { MAX_SEARCH = 20 };
885
pj_str_t hostname, alias = {NULL, 0}, *resname;
886
unsigned bufstart = 0;
887
unsigned bufleft = sizeof(rec->buf_);
888
unsigned i, ansidx, search_cnt=0;
890
PJ_ASSERT_RETURN(pkt && rec, PJ_EINVAL);
892
/* Init the record */
893
pj_bzero(rec, sizeof(pj_dns_a_record));
895
/* Return error if there's error in the packet. */
896
if (PJ_DNS_GET_RCODE(pkt->hdr.flags))
897
return PJ_STATUS_FROM_DNS_RCODE(PJ_DNS_GET_RCODE(pkt->hdr.flags));
899
/* Return error if there's no query section */
900
if (pkt->hdr.qdcount == 0)
901
return PJLIB_UTIL_EDNSINANSWER;
903
/* Return error if there's no answer */
904
if (pkt->hdr.anscount == 0)
905
return PJLIB_UTIL_EDNSNOANSWERREC;
907
/* Get the hostname from the query. */
908
hostname = pkt->q[0].name;
910
/* Copy hostname to the record */
911
if (hostname.slen > (int)bufleft) {
912
return PJ_ENAMETOOLONG;
915
pj_memcpy(&rec->buf_[bufstart], hostname.ptr, hostname.slen);
916
rec->name.ptr = &rec->buf_[bufstart];
917
rec->name.slen = hostname.slen;
919
bufstart += hostname.slen;
920
bufleft -= hostname.slen;
922
/* Find the first RR which name matches the hostname */
923
for (ansidx=0; ansidx < pkt->hdr.anscount; ++ansidx) {
924
if (pj_stricmp(&pkt->ans[ansidx].name, &hostname)==0)
928
if (ansidx == pkt->hdr.anscount)
929
return PJLIB_UTIL_EDNSNOANSWERREC;
933
/* Keep following CNAME records. */
934
while (pkt->ans[ansidx].type == PJ_DNS_TYPE_CNAME &&
935
search_cnt++ < MAX_SEARCH)
937
resname = &pkt->ans[ansidx].rdata.cname.name;
942
for (i=0; i < pkt->hdr.anscount; ++i) {
943
if (pj_stricmp(resname, &pkt->ans[i].name)==0) {
948
if (i==pkt->hdr.anscount)
949
return PJLIB_UTIL_EDNSNOANSWERREC;
954
if (search_cnt >= MAX_SEARCH)
955
return PJLIB_UTIL_EDNSINANSWER;
957
if (pkt->ans[ansidx].type != PJ_DNS_TYPE_A)
958
return PJLIB_UTIL_EDNSINANSWER;
960
/* Copy alias to the record, if present. */
962
if (alias.slen > (int)bufleft)
963
return PJ_ENAMETOOLONG;
965
pj_memcpy(&rec->buf_[bufstart], alias.ptr, alias.slen);
966
rec->alias.ptr = &rec->buf_[bufstart];
967
rec->alias.slen = alias.slen;
969
bufstart += alias.slen;
970
bufleft -= alias.slen;
973
/* Get the IP addresses. */
974
for (i=0; i < pkt->hdr.anscount; ++i) {
975
if (pkt->ans[i].type == PJ_DNS_TYPE_A &&
976
pj_stricmp(&pkt->ans[i].name, resname)==0 &&
977
rec->addr_count < PJ_DNS_MAX_IP_IN_A_REC)
979
rec->addr[rec->addr_count++].s_addr =
980
pkt->ans[i].rdata.a.ip_addr.s_addr;
984
if (rec->addr_count == 0)
985
return PJLIB_UTIL_EDNSNOANSWERREC;
991
/* Set nameserver state */
992
static void set_nameserver_state(pj_dns_resolver *resolver,
995
const pj_time_val *now)
997
struct nameserver *ns = &resolver->ns[index];
998
enum ns_state old_state = ns->state;
1001
ns->state_expiry = *now;
1003
if (state == STATE_PROBING)
1004
ns->state_expiry.sec += ((resolver->settings.qretr_count + 2) *
1005
resolver->settings.qretr_delay) / 1000;
1006
else if (state == STATE_ACTIVE)
1007
ns->state_expiry.sec += resolver->settings.good_ns_ttl;
1009
ns->state_expiry.sec += resolver->settings.bad_ns_ttl;
1011
PJ_LOG(5, (resolver->name.ptr, "Nameserver %s:%d state changed %s --> %s",
1012
pj_inet_ntoa(ns->addr.sin_addr),
1013
(int)pj_ntohs(ns->addr.sin_port),
1014
state_names[old_state], state_names[state]));
1018
/* Select which nameserver(s) to use. Note this may return multiple
1019
* name servers. The algorithm to select which nameservers to be
1020
* sent the request to is as follows:
1021
* - select the first nameserver that is known to be good for the
1022
* last PJ_DNS_RESOLVER_GOOD_NS_TTL interval.
1023
* - for all NSes, if last_known_good >= PJ_DNS_RESOLVER_GOOD_NS_TTL,
1024
* include the NS to re-check again that the server is still good,
1025
* unless the NS is known to be bad in the last PJ_DNS_RESOLVER_BAD_NS_TTL
1027
* - for all NSes, if last_known_bad >= PJ_DNS_RESOLVER_BAD_NS_TTL,
1028
* also include the NS to re-check again that the server is still bad.
1030
static pj_status_t select_nameservers(pj_dns_resolver *resolver,
1034
unsigned i, max_count=*count;
1038
pj_assert(max_count > 0);
1041
servers[0] = 0xFFFF;
1043
/* Check that nameservers are configured. */
1044
if (resolver->ns_count == 0)
1045
return PJLIB_UTIL_EDNSNONS;
1047
pj_gettimeofday(&now);
1049
/* Select one Active nameserver with best response time. */
1050
for (min=-1, i=0; i<resolver->ns_count; ++i) {
1051
struct nameserver *ns = &resolver->ns[i];
1053
if (ns->state != STATE_ACTIVE)
1058
else if (PJ_TIME_VAL_LT(ns->rt_delay, resolver->ns[min].rt_delay))
1066
/* Scan nameservers. */
1067
for (i=0; i<resolver->ns_count && *count < max_count; ++i) {
1068
struct nameserver *ns = &resolver->ns[i];
1070
if (PJ_TIME_VAL_LTE(ns->state_expiry, now)) {
1071
if (ns->state == STATE_PROBING) {
1072
set_nameserver_state(resolver, i, STATE_BAD, &now);
1074
set_nameserver_state(resolver, i, STATE_PROBING, &now);
1075
if ((int)i != min) {
1076
servers[*count] = i;
1080
} else if (ns->state == STATE_PROBING && (int)i != min) {
1081
servers[*count] = i;
1090
/* Update name server status */
1091
static void report_nameserver_status(pj_dns_resolver *resolver,
1092
const pj_sockaddr_in *ns_addr,
1093
const pj_dns_parsed_packet *pkt)
1101
/* Only mark nameserver as "bad" if it returned non-parseable response or
1102
* it returned the following status codes
1105
rcode = PJ_DNS_GET_RCODE(pkt->hdr.flags);
1109
q_id = (pj_uint32_t)-1;
1112
if (!pkt || rcode == PJ_DNS_RCODE_SERVFAIL ||
1113
rcode == PJ_DNS_RCODE_REFUSED ||
1114
rcode == PJ_DNS_RCODE_NOTAUTH)
1123
pj_gettimeofday(&now);
1125
/* Recheck all nameservers. */
1126
for (i=0; i<resolver->ns_count; ++i) {
1127
struct nameserver *ns = &resolver->ns[i];
1129
if (ns->addr.sin_addr.s_addr == ns_addr->sin_addr.s_addr &&
1130
ns->addr.sin_port == ns_addr->sin_port &&
1131
ns->addr.sin_family == ns_addr->sin_family)
1133
if (q_id == ns->q_id) {
1134
/* Calculate response time */
1135
pj_time_val rt = now;
1136
PJ_TIME_VAL_SUB(rt, ns->sent_time);
1140
set_nameserver_state(resolver, i,
1141
(is_good ? STATE_ACTIVE : STATE_BAD), &now);
1148
/* Update response cache */
1149
static void update_res_cache(pj_dns_resolver *resolver,
1150
const struct res_key *key,
1152
pj_bool_t set_expiry,
1153
const pj_dns_parsed_packet *pkt)
1155
struct cached_res *cache;
1156
pj_uint32_t hval=0, ttl;
1158
/* If status is unsuccessful, clear the same entry from the cache */
1159
if (status != PJ_SUCCESS) {
1160
cache = (struct cached_res *) pj_hash_get(resolver->hrescache, key,
1161
sizeof(*key), &hval);
1163
free_entry(resolver, cache);
1164
pj_hash_set(NULL, resolver->hrescache, key, sizeof(*key), hval, NULL);
1168
/* Calculate expiration time. */
1170
if (pkt->hdr.anscount == 0 || status != PJ_SUCCESS) {
1171
/* If we don't have answers for the name, then give a different
1172
* ttl value (note: PJ_DNS_RESOLVER_INVALID_TTL may be zero,
1173
* which means that invalid names won't be kept in the cache)
1175
ttl = PJ_DNS_RESOLVER_INVALID_TTL;
1178
/* Otherwise get the minimum TTL from the answers */
1181
for (i=0; i<pkt->hdr.anscount; ++i) {
1182
if (pkt->ans[i].ttl < ttl)
1183
ttl = pkt->ans[i].ttl;
1190
/* Apply maximum TTL */
1191
if (ttl > resolver->settings.cache_max_ttl)
1192
ttl = resolver->settings.cache_max_ttl;
1194
/* If TTL is zero, clear the same entry in the hash table */
1196
cache = (struct cached_res *) pj_hash_get(resolver->hrescache, key,
1197
sizeof(*key), &hval);
1199
free_entry(resolver, cache);
1200
pj_hash_set(NULL, resolver->hrescache, key, sizeof(*key), hval, NULL);
1204
/* Get a cache response entry */
1205
cache = (struct cached_res *) pj_hash_get(resolver->hrescache, key,
1206
sizeof(*key), &hval);
1207
if (cache == NULL) {
1208
cache = alloc_entry(resolver);
1211
/* Duplicate the packet.
1212
* We don't need to keep the NS and AR sections from the packet,
1213
* so exclude from duplication. We do need to keep the Query
1214
* section since DNS A parser needs the query section to know
1215
* the name being requested.
1218
pj_dns_packet_dup(cache->pool, pkt,
1219
PJ_DNS_NO_NS | PJ_DNS_NO_AR,
1222
/* Calculate expiration time */
1224
pj_gettimeofday(&cache->expiry_time);
1225
cache->expiry_time.sec += ttl;
1227
cache->expiry_time.sec = 0x7FFFFFFFL;
1228
cache->expiry_time.msec = 0;
1231
/* Copy key to the cached response */
1232
pj_memcpy(&cache->key, key, sizeof(*key));
1234
/* Update the hash table */
1235
pj_hash_set_np(resolver->hrescache, &cache->key, sizeof(*key), hval,
1236
cache->hbuf, cache);
1241
/* Callback to be called when query has timed out */
1242
static void on_timeout( pj_timer_heap_t *timer_heap,
1243
struct pj_timer_entry *entry)
1245
pj_dns_resolver *resolver;
1246
pj_dns_async_query *q, *cq;
1249
PJ_UNUSED_ARG(timer_heap);
1251
q = (pj_dns_async_query *) entry->user_data;
1252
resolver = q->resolver;
1254
pj_mutex_lock(resolver->mutex);
1256
/* Recheck that this query is still pending, since there is a slight
1257
* possibility of race condition (timer elapsed while at the same time
1260
if (pj_hash_get(resolver->hquerybyid, &q->id, sizeof(q->id), NULL)==NULL) {
1261
/* Yeah, this query is done. */
1262
pj_mutex_unlock(resolver->mutex);
1266
/* Invalidate id. */
1267
q->timer_entry.id = 0;
1269
/* Check to see if we should retransmit instead of time out */
1270
if (q->transmit_cnt < resolver->settings.qretr_count) {
1271
status = transmit_query(resolver, q);
1272
if (status == PJ_SUCCESS) {
1273
pj_mutex_unlock(resolver->mutex);
1277
char errmsg[PJ_ERR_MSG_SIZE];
1279
pj_strerror(status, errmsg, sizeof(errmsg));
1280
PJ_LOG(4,(resolver->name.ptr,
1281
"Error transmitting request: %s", errmsg));
1283
/* Let it fallback to timeout section below */
1287
/* Clear hash table entries */
1288
pj_hash_set(NULL, resolver->hquerybyid, &q->id, sizeof(q->id), 0, NULL);
1289
pj_hash_set(NULL, resolver->hquerybyres, &q->key, sizeof(q->key), 0, NULL);
1291
/* Workaround for deadlock problem in #1565 (similar to #1108) */
1292
pj_mutex_unlock(resolver->mutex);
1294
/* Call application callback, if any. */
1296
(*q->cb)(q->user_data, PJ_ETIMEDOUT, NULL);
1298
/* Call application callback for child queries. */
1299
cq = q->child_head.next;
1300
while (cq != (void*)&q->child_head) {
1302
(*cq->cb)(cq->user_data, PJ_ETIMEDOUT, NULL);
1306
/* Workaround for deadlock problem in #1565 (similar to #1108) */
1307
pj_mutex_lock(resolver->mutex);
1310
q->timer_entry.id = 0;
1311
q->user_data = NULL;
1313
/* Put child entries into recycle list */
1314
cq = q->child_head.next;
1315
while (cq != (void*)&q->child_head) {
1316
pj_dns_async_query *next = cq->next;
1317
pj_list_push_back(&resolver->query_free_nodes, cq);
1321
/* Put query entry into recycle list */
1322
pj_list_push_back(&resolver->query_free_nodes, q);
1324
pj_mutex_unlock(resolver->mutex);
1328
/* Callback from ioqueue when packet is received */
1329
static void on_read_complete(pj_ioqueue_key_t *key,
1330
pj_ioqueue_op_key_t *op_key,
1331
pj_ssize_t bytes_read)
1333
pj_dns_resolver *resolver;
1334
pj_pool_t *pool = NULL;
1335
pj_dns_parsed_packet *dns_pkt;
1336
pj_dns_async_query *q;
1341
resolver = (pj_dns_resolver *) pj_ioqueue_get_user_data(key);
1342
pj_mutex_lock(resolver->mutex);
1345
/* Check for errors */
1346
if (bytes_read < 0) {
1347
char errmsg[PJ_ERR_MSG_SIZE];
1349
status = -bytes_read;
1350
pj_strerror(status, errmsg, sizeof(errmsg));
1351
PJ_LOG(4,(resolver->name.ptr,
1352
"DNS resolver read error from %s:%d: %s",
1353
pj_inet_ntoa(resolver->udp_src_addr.sin_addr),
1354
pj_ntohs(resolver->udp_src_addr.sin_port),
1357
goto read_next_packet;
1360
PJ_LOG(5,(resolver->name.ptr,
1361
"Received %d bytes DNS response from %s:%d",
1363
pj_inet_ntoa(resolver->udp_src_addr.sin_addr),
1364
pj_ntohs(resolver->udp_src_addr.sin_port)));
1367
/* Check for zero packet */
1368
if (bytes_read == 0)
1369
goto read_next_packet;
1371
/* Create temporary pool from a fixed buffer */
1372
pool = pj_pool_create_on_buf("restmp", resolver->tmp_pool,
1373
sizeof(resolver->tmp_pool));
1375
/* Parse DNS response */
1379
status = pj_dns_parse_packet(pool, resolver->udp_rx_pkt,
1380
(unsigned)bytes_read, &dns_pkt);
1387
/* Update nameserver status */
1388
report_nameserver_status(resolver, &resolver->udp_src_addr, dns_pkt);
1390
/* Handle parse error */
1391
if (status != PJ_SUCCESS) {
1392
char errmsg[PJ_ERR_MSG_SIZE];
1394
pj_strerror(status, errmsg, sizeof(errmsg));
1395
PJ_LOG(3,(resolver->name.ptr,
1396
"Error parsing DNS response from %s:%d: %s",
1397
pj_inet_ntoa(resolver->udp_src_addr.sin_addr),
1398
pj_ntohs(resolver->udp_src_addr.sin_port),
1400
goto read_next_packet;
1403
/* Find the query based on the transaction ID */
1404
q = (pj_dns_async_query*)
1405
pj_hash_get(resolver->hquerybyid, &dns_pkt->hdr.id,
1406
sizeof(dns_pkt->hdr.id), NULL);
1408
PJ_LOG(5,(resolver->name.ptr,
1409
"DNS response from %s:%d id=%d discarded",
1410
pj_inet_ntoa(resolver->udp_src_addr.sin_addr),
1411
pj_ntohs(resolver->udp_src_addr.sin_port),
1412
(unsigned)dns_pkt->hdr.id));
1413
goto read_next_packet;
1416
/* Map DNS Rcode in the response into PJLIB status name space */
1417
status = PJ_STATUS_FROM_DNS_RCODE(PJ_DNS_GET_RCODE(dns_pkt->hdr.flags));
1419
/* Cancel query timeout timer. */
1420
pj_assert(q->timer_entry.id != 0);
1421
pj_timer_heap_cancel(resolver->timer, &q->timer_entry);
1422
q->timer_entry.id = 0;
1424
/* Clear hash table entries */
1425
pj_hash_set(NULL, resolver->hquerybyid, &q->id, sizeof(q->id), 0, NULL);
1426
pj_hash_set(NULL, resolver->hquerybyres, &q->key, sizeof(q->key), 0, NULL);
1428
/* Workaround for deadlock problem in #1108 */
1429
pj_mutex_unlock(resolver->mutex);
1431
/* Notify applications first, to allow application to modify the
1432
* record before it is saved to the hash table.
1435
(*q->cb)(q->user_data, status, dns_pkt);
1437
/* If query has subqueries, notify subqueries's application callback */
1438
if (!pj_list_empty(&q->child_head)) {
1439
pj_dns_async_query *child_q;
1441
child_q = q->child_head.next;
1442
while (child_q != (pj_dns_async_query*)&q->child_head) {
1444
(*child_q->cb)(child_q->user_data, status, dns_pkt);
1445
child_q = child_q->next;
1449
/* Workaround for deadlock problem in #1108 */
1450
pj_mutex_lock(resolver->mutex);
1452
/* Save/update response cache. */
1453
update_res_cache(resolver, &q->key, status, PJ_TRUE, dns_pkt);
1455
/* Recycle query objects, starting with the child queries */
1456
if (!pj_list_empty(&q->child_head)) {
1457
pj_dns_async_query *child_q;
1459
child_q = q->child_head.next;
1460
while (child_q != (pj_dns_async_query*)&q->child_head) {
1461
pj_dns_async_query *next = child_q->next;
1462
pj_list_erase(child_q);
1463
pj_list_push_back(&resolver->query_free_nodes, child_q);
1467
pj_list_push_back(&resolver->query_free_nodes, q);
1471
/* needed just in case PJ_HAS_POOL_ALT_API is set */
1472
pj_pool_release(pool);
1474
bytes_read = sizeof(resolver->udp_rx_pkt);
1475
resolver->udp_addr_len = sizeof(resolver->udp_src_addr);
1476
status = pj_ioqueue_recvfrom(resolver->udp_key, op_key,
1477
resolver->udp_rx_pkt,
1478
&bytes_read, PJ_IOQUEUE_ALWAYS_ASYNC,
1479
&resolver->udp_src_addr,
1480
&resolver->udp_addr_len);
1481
if (status != PJ_EPENDING) {
1482
char errmsg[PJ_ERR_MSG_SIZE];
1484
pj_strerror(status, errmsg, sizeof(errmsg));
1485
PJ_LOG(4,(resolver->name.ptr, "DNS resolver ioqueue read error: %s",
1488
pj_assert(!"Unhandled error");
1491
pj_mutex_unlock(resolver->mutex);
1496
* Put the specified DNS packet into DNS cache. This function is mainly used
1497
* for testing the resolver, however it can also be used to inject entries
1498
* into the resolver.
1500
PJ_DEF(pj_status_t) pj_dns_resolver_add_entry( pj_dns_resolver *resolver,
1501
const pj_dns_parsed_packet *pkt,
1507
PJ_ASSERT_RETURN(resolver && pkt, PJ_EINVAL);
1509
/* Packet must be a DNS response */
1510
PJ_ASSERT_RETURN(PJ_DNS_GET_QR(pkt->hdr.flags) & 1, PJ_EINVAL);
1512
/* Make sure there are answers in the packet */
1513
PJ_ASSERT_RETURN((pkt->hdr.anscount && pkt->ans) ||
1514
(pkt->hdr.qdcount && pkt->q),
1515
PJLIB_UTIL_EDNSNOANSWERREC);
1517
pj_mutex_lock(resolver->mutex);
1519
/* Build resource key for looking up hash tables */
1520
pj_bzero(&key, sizeof(struct res_key));
1521
if (pkt->hdr.anscount) {
1522
/* Make sure name is not too long. */
1523
PJ_ASSERT_RETURN(pkt->ans[0].name.slen < PJ_MAX_HOSTNAME,
1526
init_res_key(&key, pkt->ans[0].type, &pkt->ans[0].name);
1529
/* Make sure name is not too long. */
1530
PJ_ASSERT_RETURN(pkt->q[0].name.slen < PJ_MAX_HOSTNAME,
1533
init_res_key(&key, pkt->q[0].type, &pkt->q[0].name);
1537
update_res_cache(resolver, &key, PJ_SUCCESS, set_ttl, pkt);
1539
pj_mutex_unlock(resolver->mutex);
1546
* Get the total number of response in the response cache.
1548
PJ_DEF(unsigned) pj_dns_resolver_get_cached_count(pj_dns_resolver *resolver)
1552
PJ_ASSERT_RETURN(resolver, 0);
1554
pj_mutex_lock(resolver->mutex);
1555
count = pj_hash_count(resolver->hrescache);
1556
pj_mutex_unlock(resolver->mutex);
1563
* Dump resolver state to the log.
1565
PJ_DEF(void) pj_dns_resolver_dump(pj_dns_resolver *resolver,
1568
#if PJ_LOG_MAX_LEVEL >= 3
1572
pj_mutex_lock(resolver->mutex);
1574
pj_gettimeofday(&now);
1576
PJ_LOG(3,(resolver->name.ptr, " Dumping resolver state:"));
1578
PJ_LOG(3,(resolver->name.ptr, " Name servers:"));
1579
for (i=0; i<resolver->ns_count; ++i) {
1580
const char *state_names[] = { "probing", "active", "bad"};
1581
struct nameserver *ns = &resolver->ns[i];
1583
PJ_LOG(3,(resolver->name.ptr,
1584
" NS %d: %s:%d (state=%s until %ds, rtt=%d ms)",
1585
i, pj_inet_ntoa(ns->addr.sin_addr),
1586
pj_ntohs(ns->addr.sin_port),
1587
state_names[ns->state],
1588
ns->state_expiry.sec - now.sec,
1589
PJ_TIME_VAL_MSEC(ns->rt_delay)));
1592
PJ_LOG(3,(resolver->name.ptr, " Nb. of cached responses: %u",
1593
pj_hash_count(resolver->hrescache)));
1595
pj_hash_iterator_t itbuf, *it;
1596
it = pj_hash_first(resolver->hrescache, &itbuf);
1598
struct cached_res *cache;
1599
cache = (struct cached_res*)pj_hash_this(resolver->hrescache, it);
1600
PJ_LOG(3,(resolver->name.ptr,
1602
pj_dns_get_type_name(cache->key.qtype),
1604
it = pj_hash_next(resolver->hrescache, it);
1607
PJ_LOG(3,(resolver->name.ptr, " Nb. of pending queries: %u (%u)",
1608
pj_hash_count(resolver->hquerybyid),
1609
pj_hash_count(resolver->hquerybyres)));
1611
pj_hash_iterator_t itbuf, *it;
1612
it = pj_hash_first(resolver->hquerybyid, &itbuf);
1614
struct pj_dns_async_query *q;
1615
q = (pj_dns_async_query*) pj_hash_this(resolver->hquerybyid, it);
1616
PJ_LOG(3,(resolver->name.ptr,
1618
pj_dns_get_type_name(q->key.qtype),
1620
it = pj_hash_next(resolver->hquerybyid, it);
1623
PJ_LOG(3,(resolver->name.ptr, " Nb. of pending query free nodes: %u",
1624
pj_list_size(&resolver->query_free_nodes)));
1625
PJ_LOG(3,(resolver->name.ptr, " Nb. of timer entries: %u",
1626
pj_timer_heap_count(resolver->timer)));
1627
PJ_LOG(3,(resolver->name.ptr, " Pool capacity: %d, used size: %d",
1628
pj_pool_get_capacity(resolver->pool),
1629
pj_pool_get_used_size(resolver->pool)));
1631
pj_mutex_unlock(resolver->mutex);