⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 resolver.c

📁 基于sip协议的网络电话源码
💻 C
📖 第 1 页 / 共 3 页
字号:
    PJ_ASSERT_ON_FAIL(resolver, return);    pj_mutex_lock(resolver->mutex);    pj_timer_heap_poll(resolver->timer, NULL);    pj_mutex_unlock(resolver->mutex);    pj_ioqueue_poll(resolver->ioqueue, timeout);}/* Get one query node from the free node, if any, or allocate  * a new one. */static pj_dns_async_query *alloc_qnode(pj_dns_resolver *resolver,				       unsigned options,				       void *user_data,				       pj_dns_callback *cb){    pj_dns_async_query *q;    /* Merge query options with resolver options */    options |= resolver->settings.options;    if (!pj_list_empty(&resolver->query_free_nodes)) {	q = resolver->query_free_nodes.next;	pj_list_erase(q);	pj_bzero(q, sizeof(*q));    } else {	q = pj_pool_zalloc(resolver->pool, sizeof(*q));    }    /* Init query */    q->resolver = resolver;    q->options = options;    q->user_data = user_data;    q->cb = cb;    pj_list_init(&q->child_head);    return q;}/* * Transmit query. */static pj_status_t transmit_query(pj_dns_resolver *resolver,				  pj_dns_async_query *q){    unsigned pkt_size;    unsigned i, server_cnt;    unsigned servers[PJ_DNS_RESOLVER_MAX_NS];    pj_time_val now;    pj_str_t name;    pj_time_val delay;    pj_status_t status;    /* Create DNS query packet */    pkt_size = sizeof(resolver->udp_tx_pkt);    name = pj_str(q->key.name);    status = pj_dns_make_query(resolver->udp_tx_pkt, &pkt_size, 			       q->id, q->key.qtype, &name);    if (status != PJ_SUCCESS) {	return status;    }    /* Select which nameserver(s) to send requests to. */    server_cnt = PJ_ARRAY_SIZE(servers);    status = select_nameservers(resolver, &server_cnt, servers);    if (status != PJ_SUCCESS) {	return status;    }    if (server_cnt == 0) {	return PJLIB_UTIL_EDNSNOWORKINGNS;    }    /* Start retransmit/timeout timer for the query */    pj_assert(q->timer_entry.id == 0);    q->timer_entry.id = 1;    q->timer_entry.user_data = q;    q->timer_entry.cb = &on_timeout;    delay.sec = 0;    delay.msec = resolver->settings.qretr_delay;    pj_time_val_normalize(&delay);    status = pj_timer_heap_schedule(resolver->timer, &q->timer_entry, &delay);    if (status != PJ_SUCCESS) {	return status;    }    /* Get current time. */    pj_gettimeofday(&now);    /* Send the packet to name servers */    for (i=0; i<server_cnt; ++i) {	pj_ssize_t sent  = (pj_ssize_t) pkt_size;	struct nameserver *ns = &resolver->ns[servers[i]];	pj_sock_sendto(resolver->udp_sock, resolver->udp_tx_pkt, &sent, 0,		       &resolver->ns[servers[i]].addr, sizeof(pj_sockaddr_in));	PJ_LOG(4,(resolver->name.ptr, 		  "%s %d bytes to NS %d (%s:%d): DNS %s query for %s",		  (q->transmit_cnt==0? "Transmitting":"Re-transmitting"),		  (int)sent, servers[i],		  pj_inet_ntoa(ns->addr.sin_addr), 		  (int)pj_ntohs(ns->addr.sin_port),		  pj_dns_get_type_name(q->key.qtype), 		  q->key.name));	if (ns->q_id == 0) {	    ns->q_id = q->id;	    ns->sent_time = now;	}    }    ++q->transmit_cnt;    return PJ_SUCCESS;}/* * Initialize resource key for hash table lookup. */static void init_res_key(struct res_key *key, int type, const pj_str_t *name){    unsigned i, len;    char *dst = key->name;    const char *src = name->ptr;    pj_bzero(key, sizeof(struct res_key));    key->qtype = (pj_uint16_t)type;    len = name->slen;    if (len > PJ_MAX_HOSTNAME) len = PJ_MAX_HOSTNAME;    /* Copy key, in lowercase */    for (i=0; i<len; ++i) {	*dst++ = (char)pj_tolower(*src++);    }}/* * Create and start asynchronous DNS query for a single resource. */PJ_DEF(pj_status_t) pj_dns_resolver_start_query( pj_dns_resolver *resolver,						 const pj_str_t *name,						 int type,						 unsigned options,						 pj_dns_callback *cb,						 void *user_data,						 pj_dns_async_query **p_query){    pj_time_val now;    struct res_key key;    struct cached_res *cache;    pj_dns_async_query *q;    pj_uint32_t hval;    pj_status_t status = PJ_SUCCESS;    /* Validate arguments */    PJ_ASSERT_RETURN(resolver && name && type, PJ_EINVAL);    /* Check name is not too long. */    PJ_ASSERT_RETURN(name->slen>0 && name->slen < PJ_MAX_HOSTNAME,		     PJ_ENAMETOOLONG);    /* Check type */    PJ_ASSERT_RETURN(type > 0 && type < 0xFFFF, PJ_EINVAL);    if (p_query)	*p_query = NULL;    /* Build resource key for looking up hash tables */    init_res_key(&key, type, name);    /* Start working with the resolver */    pj_mutex_lock(resolver->mutex);    /* Get current time. */    pj_gettimeofday(&now);    /* First, check if we have cached response for the specified name/type,     * and the cached entry has not expired.     */    hval = 0;    cache = pj_hash_get(resolver->hrescache, &key, sizeof(key), &hval);    if (cache) {	/* We've found a cached entry. */	/* Check for expiration */	if (PJ_TIME_VAL_GT(cache->expiry_time, now)) {	    /* Log */	    PJ_LOG(5,(resolver->name.ptr, 		      "Picked up DNS %s record for %.*s from cache, ttl=%d",		      pj_dns_get_type_name(type),		      (int)name->slen, name->ptr,		      (int)(cache->expiry_time.sec - now.sec)));	    /* Map DNS Rcode in the response into PJLIB status name space */	    status = PJ_DNS_GET_RCODE(cache->pkt->hdr.flags);	    status = PJ_STATUS_FROM_DNS_RCODE(status);	    /* This cached response is still valid. Just return this	     * response to caller.	     */	    if (cb) {		(*cb)(user_data, status, cache->pkt);	    }	    /* Done. No host resolution is necessary */	    /* Must return PJ_SUCCESS */	    status = PJ_SUCCESS;	    goto on_return;	}	/* At this point, we have a cached entry, but this entry has expired.	 * Remove this entry from the cached list.	 */	pj_hash_set(NULL, resolver->hrescache, &key, sizeof(key), 0, NULL);	/* Store the entry into free nodes */	pj_list_push_back(&resolver->res_free_nodes, cache);	/* Must continue with creating a query now */    }    /* Next, check if we have pending query on the same resource */    q = pj_hash_get(resolver->hquerybyres, &key, sizeof(key), NULL);    if (q) {	/* Yes, there's another pending query to the same key.	 * Just create a new child query and add this query to	 * pending query's child queries.	 */	pj_dns_async_query *nq;	nq = alloc_qnode(resolver, options, user_data, cb);	pj_list_push_back(&q->child_head, nq);	/* Done. This child query will be notified once the "parent"	 * query completes.	 */	status = PJ_SUCCESS;	goto on_return;    }     /* There's no pending query to the same key, initiate a new one. */    q = alloc_qnode(resolver, options, user_data, cb);    /* Save the ID and key */    q->id = resolver->last_id++;    if (resolver->last_id == 0)	resolver->last_id = 1;    pj_memcpy(&q->key, &key, sizeof(struct res_key));    /* Send the query */    status = transmit_query(resolver, q);    if (status != PJ_SUCCESS) {	pj_list_push_back(&resolver->query_free_nodes, q);	goto on_return;    }    /* Add query entry to the hash tables */    pj_hash_set_np(resolver->hquerybyid, &q->id, sizeof(q->id), 		   0, q->hbufid, q);    pj_hash_set_np(resolver->hquerybyres, &q->key, sizeof(q->key),		   0, q->hbufkey, q);    if (p_query)	*p_query = q;on_return:    pj_mutex_unlock(resolver->mutex);    return status;}/* * Cancel a pending query. */PJ_DEF(pj_status_t) pj_dns_resolver_cancel_query(pj_dns_async_query *query,						 pj_bool_t notify){    pj_dns_callback *cb;    PJ_ASSERT_RETURN(query, PJ_EINVAL);    pj_mutex_lock(query->resolver->mutex);    cb = query->cb;    query->cb = NULL;    if (notify)	(*cb)(query->user_data, PJ_ECANCELLED, NULL);    pj_mutex_unlock(query->resolver->mutex);    return PJ_SUCCESS;}/* Set nameserver state */static void set_nameserver_state(pj_dns_resolver *resolver,				 unsigned index,				 enum ns_state state,				 const pj_time_val *now){    struct nameserver *ns = &resolver->ns[index];    ns->state = state;    ns->state_expiry = *now;    if (state == STATE_PROBING)	ns->state_expiry.sec += ((PJ_DNS_RESOLVER_QUERY_RETRANSMIT_COUNT + 2) *				 PJ_DNS_RESOLVER_QUERY_RETRANSMIT_DELAY) / 1000;    else if (state == STATE_ACTIVE)	ns->state_expiry.sec += PJ_DNS_RESOLVER_GOOD_NS_TTL;    else	ns->state_expiry.sec += PJ_DNS_RESOLVER_BAD_NS_TTL;}/* Select which nameserver(s) to use. Note this may return multiple * name servers. The algorithm to select which nameservers to be * sent the request to is as follows: *  - select the first nameserver that is known to be good for the *    last PJ_DNS_RESOLVER_GOOD_NS_TTL interval. *  - for all NSes, if last_known_good >= PJ_DNS_RESOLVER_GOOD_NS_TTL,  *    include the NS to re-check again that the server is still good, *    unless the NS is known to be bad in the last PJ_DNS_RESOLVER_BAD_NS_TTL *    interval. *  - for all NSes, if last_known_bad >= PJ_DNS_RESOLVER_BAD_NS_TTL,  *    also include the NS to re-check again that the server is still bad. */static pj_status_t select_nameservers(pj_dns_resolver *resolver,				      unsigned *count,				      unsigned servers[]){    unsigned i, max_count=*count;    int min;    pj_time_val now;    pj_assert(max_count > 0);    *count = 0;    servers[0] = 0xFFFF;    /* Check that nameservers are configured. */    if (resolver->ns_count == 0)	return PJLIB_UTIL_EDNSNONS;    pj_gettimeofday(&now);    /* Select one Active nameserver with best response time. */    for (min=-1, i=0; i<resolver->ns_count; ++i) {	struct nameserver *ns = &resolver->ns[i];	if (ns->state != STATE_ACTIVE)	    continue;	if (min == -1)	    min = i;	else if (PJ_TIME_VAL_LT(ns->rt_delay, resolver->ns[min].rt_delay))	    min = i;    }    if (min != -1) {	servers[0] = min;	++(*count);    }    /* Scan nameservers. */    for (i=0; i<resolver->ns_count && *count < max_count; ++i) {	struct nameserver *ns = &resolver->ns[i];	if (PJ_TIME_VAL_LTE(ns->state_expiry, now)) {	    if (ns->state == STATE_PROBING) {		set_nameserver_state(resolver, i, STATE_BAD, &now);	    } else {		set_nameserver_state(resolver, i, STATE_PROBING, &now);		if ((int)i != min) {		    servers[*count] = i;		    ++(*count);		}	    }	} else if (ns->state == STATE_PROBING && (int)i != min) {	    servers[*count] = i;	    ++(*count);	}    }    return PJ_SUCCESS;}/* Update name server status */static void report_nameserver_status(pj_dns_resolver *resolver,				     const pj_sockaddr_in *ns_addr,				     const pj_dns_parsed_packet *pkt){    unsigned i;    int rcode;    pj_uint32_t q_id;    pj_time_val now;    pj_bool_t is_good;    /* Only mark nameserver as "bad" if it returned non-parseable response or     * it returned the following status codes     */    if (pkt) {	rcode = PJ_DNS_GET_RCODE(pkt->hdr.flags);	q_id = pkt->hdr.id;    } else {	rcode = 0;	q_id = (pj_uint32_t)-1;    }    if (!pkt || rcode == PJ_DNS_RCODE_SERVFAIL ||	        rcode == PJ_DNS_RCODE_REFUSED ||	        rcode == PJ_DNS_RCODE_NOTAUTH)     {	is_good = PJ_FALSE;    } else {	is_good = PJ_TRUE;    }    /* Mark time */    pj_gettimeofday(&now);    /* Recheck all nameservers. */    for (i=0; i<resolver->ns_count; ++i) {	struct nameserver *ns = &resolver->ns[i];	if (ns->addr.sin_addr.s_addr == ns_addr->sin_addr.s_addr &&	    ns->addr.sin_port == ns_addr->sin_port &&	    ns->addr.sin_family == ns_addr->sin_family)	{	    if (q_id == ns->q_id) {		/* Calculate response time */		pj_time_val rt = now;		PJ_TIME_VAL_SUB(rt, ns->sent_time);		ns->rt_delay = rt;		ns->q_id = 0;	    }	    set_nameserver_state(resolver, i, 				 (is_good ? STATE_ACTIVE : STATE_BAD), &now);	    break;	}    }}/* Update response cache */static void update_res_cache(pj_dns_resolver *resolver,			     const struct res_key *key,			     pj_status_t status,			     pj_bool_t set_expiry,			     const pj_dns_parsed_packet *pkt){    struct cached_res *cache;    pj_pool_t *res_pool;    pj_uint32_t hval=0, ttl;    PJ_USE_EXCEPTION;    /* If status is unsuccessful, clear the same entry from the cache */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -