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

📄 sip_resolve.c

📁 一个开源SIP协议栈
💻 C
📖 第 1 页 / 共 2 页
字号:
	    if (query->srv[j].priority < query->srv[min].priority)
		min = j;
	}
	SWAP(struct srv_target, &query->srv[i], &query->srv[min]);
    }

    /* Second pass:
     *	pick one host among hosts with the same priority, according
     *	to its weight. The idea is when one server fails, client should
     *	contact the next server with higher priority rather than contacting
     *	server with the same priority as the failed one.
     *
     *  The algorithm for selecting server among servers with the same
     *  priority is described in RFC 2782.
     */
    for (i=0; i<query->srv_cnt; ++i) {
	unsigned j, count=1, sum;

	/* Calculate running sum for servers with the same priority */
	sum = query->srv[i].sum = query->srv[i].weight;
	for (j=i+1; j<query->srv_cnt && 
		    query->srv[j].priority == query->srv[i].priority; ++j)
	{
	    sum += query->srv[j].weight;
	    query->srv[j].sum = sum;
	    ++count;
	}

	if (count > 1) {
	    unsigned r;

	    /* Elect one random number between zero and the total sum of
	     * weight (inclusive).
	     */
	    r = pj_rand() % (sum + 1);

	    /* Select the first server which running sum is greater than or
	     * equal to the random number.
	     */
	    for (j=i; j<i+count; ++j) {
		if (query->srv[j].sum >= r)
		    break;
	    }

	    /* Must have selected one! */
	    pj_assert(j != i+count);

	    /* Put this entry in front (of entries with same priority) */
	    SWAP(struct srv_target, &query->srv[i], &query->srv[j]);

	    /* Remove all other entries (of the same priority) */
	    while (count > 1) {
		pj_array_erase(query->srv, sizeof(struct srv_target), 
			       query->srv_cnt, i+1);
		--count;
		--query->srv_cnt;
	    }
	}
    }

    /* Since we've been moving around SRV entries, update the pointers
     * in target_name.
     */
    for (i=0; i<query->srv_cnt; ++i) {
	query->srv[i].target_name.ptr = query->srv[i].target_buf;
    }

    /* Check for Additional Info section if A records are available, and
     * fill in the IP address (so that we won't need to resolve the A 
     * record with another DNS query). 
     */
    for (i=0; i<response->hdr.arcount; ++i) {
	pj_dns_parsed_rr *rr = &response->arr[i];
	unsigned j;

	if (rr->type != PJ_DNS_TYPE_A)
	    continue;

	/* Yippeaiyee!! There is an "A" record! 
	 * Update the IP address of the corresponding SRV record.
	 */
	for (j=0; j<query->srv_cnt; ++j) {
	    if (pj_stricmp(&rr->name, &query->srv[j].target_name)==0) {
		unsigned cnt = query->srv[j].addr_cnt;
		query->srv[j].addr[cnt].s_addr = rr->rdata.a.ip_addr.s_addr;
		++query->srv[j].addr_cnt;
		++query->host_resolved;
		break;
	    }
	}

	/* Not valid message; SRV entry might have been deleted in
	 * server selection process.
	 */
	/*
	if (j == query->srv_cnt) {
	    PJ_LOG(4,(query->objname, 
		      "Received DNS SRV answer with A record, but "
		      "couldn't find matching name (name=%.*s)",
		      (int)rr->name.slen,
		      rr->name.ptr));
	}
	*/
    }

    /* Rescan again the name specified in the SRV record to see if IP
     * address is specified as the target name (unlikely, but well, who 
     * knows..).
     */
    for (i=0; i<query->srv_cnt; ++i) {
	pj_in_addr addr;

	if (query->srv[i].addr_cnt != 0) {
	    /* IP address already resolved */
	    continue;
	}

	if (pj_inet_aton(&query->srv[i].target_name, &addr) != 0) {
	    query->srv[i].addr[query->srv[i].addr_cnt++] = addr;
	    ++query->host_resolved;
	}
    }

    /* Print resolved entries to the log */
    PJ_LOG(5,(query->objname, 
	      "SRV query for %.*s completed, "
	      "%d of %d total entries selected%c",
	      (int)query->naptr[naptr_id].target_name.slen,
	      query->naptr[naptr_id].target_name.ptr,
	      query->srv_cnt,
	      response->hdr.anscount,
	      (query->srv_cnt ? ':' : ' ')));

    for (i=0; i<query->srv_cnt; ++i) {
	const char *addr;

	if (query->srv[i].addr_cnt != 0)
	    addr = pj_inet_ntoa(query->srv[i].addr[0]);
	else
	    addr = "-";

	PJ_LOG(5,(query->objname, 
		  " %d: SRV %d %d %d %.*s (%s)",
		  i, query->srv[i].priority, 
		  query->srv[i].weight, 
		  query->srv[i].port, 
		  (int)query->srv[i].target_name.slen, 
		  query->srv[i].target_name.ptr,
		  addr));
    }
}


/* Start DNS A record queries for all SRV records in the query structure */
static pj_status_t resolve_hostnames(struct query *query)
{
    unsigned i;
    pj_status_t err=PJ_SUCCESS, status;

    query->dns_state = PJ_DNS_TYPE_A;
    for (i=0; i<query->srv_cnt; ++i) {
	PJ_LOG(5, (query->objname, 
		   "Starting async DNS A query for %.*s",
		   (int)query->srv[i].target_name.slen, 
		   query->srv[i].target_name.ptr));

	status = pj_dns_resolver_start_query(query->resolver->res,
					     &query->srv[i].target_name,
					     PJ_DNS_TYPE_A, 0,
					     &dns_callback,
					     query, NULL);
	if (status != PJ_SUCCESS) {
	    query->host_resolved++;
	    err = status;
	}
    }
    
    return (query->host_resolved == query->srv_cnt) ? err : PJ_SUCCESS;
}

/* 
 * This callback is called by PJLIB-UTIL DNS resolver when asynchronous
 * query has completed (successfully or with error).
 */
static void dns_callback(void *user_data,
			 pj_status_t status,
			 pj_dns_parsed_packet *pkt)
{
    struct query *query = user_data;
    unsigned i;

    /* Proceed to next stage */

    if (query->dns_state == PJ_DNS_TYPE_SRV) {

	/* We are getting SRV response */

	if (status == PJ_SUCCESS && pkt->hdr.anscount != 0) {
	    /* Got SRV response, build server entry. If A records are available
	     * in additional records section of the DNS response, save them too.
	     */
	    build_server_entries(query, pkt);

	} else if (status != PJ_SUCCESS) {
	    char errmsg[PJ_ERR_MSG_SIZE];
	    unsigned naptr_id;

	    /* Update query last error */
	    query->last_error = status;

	    /* Find which NAPTR target has not got SRV records */
	    for (naptr_id=0; naptr_id < query->naptr_cnt; ++naptr_id) {
		for (i=0; i<query->srv_cnt; ++i) {
		    if (query->srv[i].type == query->naptr[naptr_id].type)
			break;
		}
		if (i == query->srv_cnt)
		    break;
	    }
	    if (naptr_id == query->naptr_cnt) {
		/* Strangely all NAPTR records seem to already have SRV
		 * records! This is quite unexpected, by anyway lets set
		 * the naptr_id to zero just in case.
		 */
		pj_assert(!"Strange");
		naptr_id = 0;

	    }

	    pj_strerror(status, errmsg, sizeof(errmsg));
	    PJ_LOG(4,(query->objname, 
		      "DNS SRV resolution failed for %.*s: %s", 
		      (int)query->naptr[naptr_id].target_name.slen, 
		      query->naptr[naptr_id].target_name.ptr,
		      errmsg));
	}

	/* If we can't build SRV record, assume the original target is
	 * an A record.
	 */
	if (query->srv_cnt == 0) {
	    /* Looks like we aren't getting any SRV responses.
	     * Resolve the original target as A record by creating a 
	     * single "dummy" srv record and start the hostname resolution.
	     */
	    unsigned naptr_id;

	    /* Find which NAPTR target has not got SRV records */
	    for (naptr_id=0; naptr_id < query->naptr_cnt; ++naptr_id) {
		for (i=0; i<query->srv_cnt; ++i) {
		    if (query->srv[i].type == query->naptr[naptr_id].type)
			break;
		}
		if (i == query->srv_cnt)
		    break;
	    }
	    if (naptr_id == query->naptr_cnt) {
		/* Strangely all NAPTR records seem to already have SRV
		 * records! This is quite unexpected, by anyway lets set
		 * the naptr_id to zero just in case.
		 */
		pj_assert(!"Strange");
		naptr_id = 0;

	    }

	    PJ_LOG(4, (query->objname, 
		       "DNS SRV resolution failed for %.*s, trying "
		       "resolving A record for %.*s",
		       (int)query->naptr[naptr_id].target_name.slen, 
		       query->naptr[naptr_id].target_name.ptr,
		       (int)query->req.target.addr.host.slen,
		       query->req.target.addr.host.ptr));

	    /* Create a "dummy" srv record using the original target */
	    i = query->srv_cnt++;
	    pj_bzero(&query->srv[i], sizeof(query->srv[i]));
	    query->srv[i].target_name = query->req.target.addr.host;
	    query->srv[i].type = query->naptr[naptr_id].type;
	    query->srv[i].priority = 0;
	    query->srv[i].weight = 0;

	    query->srv[i].port = query->req.target.addr.port;
	    if (query->srv[i].port == 0) {
		query->srv[i].port = (pj_uint16_t)
		 pjsip_transport_get_default_port_for_type(query->srv[i].type);
	    }
	} 
	

	/* Resolve server hostnames (DNS A record) for hosts which don't have
	 * A record yet.
	 */
	if (query->host_resolved != query->srv_cnt) {
	    status = resolve_hostnames(query);
	    if (status != PJ_SUCCESS)
		goto on_error;

	    /* Must return now. Callback may have been called and query
	     * may have been destroyed.
	     */
	    return;
	}

    } else if (query->dns_state == PJ_DNS_TYPE_A) {

	/* Check that we really have answer */
	if (status==PJ_SUCCESS && pkt->hdr.anscount != 0) {

	    /* Update IP address of the corresponding hostname */
	    for (i=0; i<query->srv_cnt; ++i) {
		if (pj_stricmp(&pkt->ans[0].name, 
			       &query->srv[i].target_name)==0) 
		{
		    break;
		}
	    }

	    if (i == query->srv_cnt) {
		PJ_LOG(4,(query->objname, 
			  "Received answer to DNS A request with no matching "
			  "SRV record! The unknown name is %.*s",
			  (int)pkt->ans[0].name.slen, pkt->ans[0].name.ptr));
	    } else {
		unsigned j;

		query->srv[i].addr[query->srv[i].addr_cnt++].s_addr =
		    pkt->ans[0].rdata.a.ip_addr.s_addr;

		PJ_LOG(5,(query->objname, 
			  "DNS A for %.*s: %s",
			  (int)query->srv[i].target_name.slen, 
			  query->srv[i].target_name.ptr,
			  pj_inet_ntoa(pkt->ans[0].rdata.a.ip_addr)));

		/* Check for multiple IP addresses */
		for (j=1; j<pkt->hdr.anscount && 
			    query->srv[i].addr_cnt < ADDR_MAX_COUNT; ++j)
		{
		    query->srv[i].addr[query->srv[i].addr_cnt++].s_addr = 
			pkt->ans[j].rdata.a.ip_addr.s_addr;

		    PJ_LOG(5,(query->objname, 
			      "Additional DNS A for %.*s: %s",
			      (int)query->srv[i].target_name.slen, 
			      query->srv[i].target_name.ptr,
			      pj_inet_ntoa(pkt->ans[j].rdata.a.ip_addr)));
		}
	    }

	} else if (status != PJ_SUCCESS) {
	    char errmsg[PJ_ERR_MSG_SIZE];

	    /* Update last error */
	    query->last_error = status;

	    /* Log error */
	    pj_strerror(status, errmsg, sizeof(errmsg));
	    PJ_LOG(4,(query->objname, "DNS A record resolution failed: %s", 
		      errmsg));
	}

	++query->host_resolved;

    } else {
	pj_assert(!"Unexpected state!");
	query->last_error = status = PJ_EINVALIDOP;
	goto on_error;
    }

    /* Check if all hosts have been resolved */
    if (query->host_resolved == query->srv_cnt) {
	/* Got all answers, build server addresses */
	pjsip_server_addresses svr_addr;

	svr_addr.count = 0;
	for (i=0; i<query->srv_cnt; ++i) {
	    unsigned j;

	    /* Do we have IP address for this server? */
	    /* This log is redundant really.
	    if (query->srv[i].addr_cnt == 0) {
		PJ_LOG(5,(query->objname, 
			  " SRV target %.*s:%d does not have IP address!",
			  (int)query->srv[i].target_name.slen,
			  query->srv[i].target_name.ptr,
			  query->srv[i].port));
		continue;
	    }
	    */

	    for (j=0; j<query->srv[i].addr_cnt; ++j) {
		unsigned idx = svr_addr.count;
		pj_sockaddr_in *addr;

		svr_addr.entry[idx].type = query->srv[i].type;
		svr_addr.entry[idx].priority = query->srv[i].priority;
		svr_addr.entry[idx].weight = query->srv[i].weight;
		svr_addr.entry[idx].addr_len = sizeof(pj_sockaddr_in);
	     
		addr = (pj_sockaddr_in*)&svr_addr.entry[idx].addr;
		pj_bzero(addr, sizeof(pj_sockaddr_in));
		addr->sin_family = PJ_AF_INET;
		addr->sin_addr = query->srv[i].addr[j];
		addr->sin_port = pj_htons((pj_uint16_t)query->srv[i].port);

		++svr_addr.count;
	    }
	}

	PJ_LOG(5,(query->objname, 
		  "Server resolution complete, %d server entry(s) found",
		  svr_addr.count));


	if (svr_addr.count > 0)
	    status = PJ_SUCCESS;
	else {
	    status = query->last_error;
	    if (status == PJ_SUCCESS)
		status = PJLIB_UTIL_EDNSNOANSWERREC;
	}

	/* Call the callback */
	(*query->cb)(status, query->token, &svr_addr);
    }


    return;

on_error:
    /* Check for failure */
    if (status != PJ_SUCCESS) {
	char errmsg[PJ_ERR_MSG_SIZE];
	PJ_LOG(4,(query->objname, 
		  "DNS %s record resolution error for '%.*s'."
		  " Err=%d (%s)",
		  pj_dns_get_type_name(query->dns_state),
		  (int)query->req.target.addr.host.slen,
		  query->req.target.addr.host.ptr,
		  status,
		  pj_strerror(status,errmsg,sizeof(errmsg)).ptr));
	(*query->cb)(status, query->token, NULL);
	return;
    }
}

#endif	/* PJSIP_HAS_RESOLVER */



⌨️ 快捷键说明

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