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

📄 sip_resolve.c

📁 基于sip协议的网络电话源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* $Id: sip_resolve.c 1033 2007-03-02 14:51:03Z bennylp $ *//*  * Copyright (C) 2003-2007 Benny Prijono <benny@prijono.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA  */#include <pjsip/sip_resolve.h>#include <pjsip/sip_transport.h>#include <pjsip/sip_errno.h>#include <pjlib-util/errno.h>#include <pj/array.h>#include <pj/assert.h>#include <pj/ctype.h>#include <pj/log.h>#include <pj/pool.h>#include <pj/rand.h>#include <pj/string.h>#define THIS_FILE   "sip_resolve.c"#define ADDR_MAX_COUNT	    8struct naptr_target{    pj_str_t		    target_name;    /**< NAPTR target name. */    pjsip_transport_type_e  type;	    /**< Transport type.    */    unsigned		    order;	    /**< Order		    */    unsigned		    pref;	    /**< Preference.	    */};struct srv_target{    pjsip_transport_type_e  type;    pj_str_t		    target_name;    char		    target_buf[PJ_MAX_HOSTNAME];    unsigned		    port;    unsigned		    priority;    unsigned		    weight;    unsigned		    sum;    unsigned		    addr_cnt;    pj_in_addr		    addr[ADDR_MAX_COUNT];};struct query{    char		     objname[PJ_MAX_OBJ_NAME];    pjsip_resolver_t	    *resolver;	    /**< Resolver SIP instance.	    */    pj_dns_type		     dns_state;	    /**< DNS type being resolved.   */    void		    *token;    pjsip_resolver_callback *cb;    pj_dns_async_query	    *object;    pj_status_t		     last_error;    /* Original request: */    struct {	pjsip_host_info	     target;    } req;    /* NAPTR records: */    unsigned		     naptr_cnt;    struct naptr_target	     naptr[8];    /* SRV records and their resolved IP addresses: */    unsigned		     srv_cnt;    struct srv_target	     srv[PJSIP_MAX_RESOLVED_ADDRESSES];    /* Number of hosts in SRV records that the IP address has been resolved */    unsigned		     host_resolved;};struct pjsip_resolver_t{    pj_dns_resolver *res;    unsigned	     job_id;};static void dns_callback(void *user_data,			 pj_status_t status,			 pj_dns_parsed_packet *response);/* * Public API to create the resolver. */PJ_DEF(pj_status_t) pjsip_resolver_create( pj_pool_t *pool,					   pjsip_resolver_t **p_res){    pjsip_resolver_t *resolver;    PJ_ASSERT_RETURN(pool && p_res, PJ_EINVAL);    resolver = pj_pool_zalloc(pool, sizeof(*resolver));    *p_res = resolver;    return PJ_SUCCESS;}/* * Public API to set the DNS resolver instance for the SIP resolver. */PJ_DEF(pj_status_t) pjsip_resolver_set_resolver(pjsip_resolver_t *res,						pj_dns_resolver *dns_res){#if PJSIP_HAS_RESOLVER    res->res = dns_res;    return PJ_SUCCESS;#else    PJ_UNUSED_ARG(res);    PJ_UNUSED_ARG(dns_res);    pj_assert(!"Resolver is disabled (PJSIP_HAS_RESOLVER==0)");    return PJ_EINVALIDOP;#endif}/* * Public API to get the internal DNS resolver. */PJ_DEF(pj_dns_resolver*) pjsip_resolver_get_resolver(pjsip_resolver_t *res){    return res->res;}/* * Public API to create destroy the resolver */PJ_DEF(void) pjsip_resolver_destroy(pjsip_resolver_t *resolver){    if (resolver->res) {#if PJSIP_HAS_RESOLVER	pj_dns_resolver_destroy(resolver->res, PJ_FALSE);#endif	resolver->res = NULL;    }}/* * Internal: *  determine if an address is a valid IP address. */static int is_str_ip(const pj_str_t *host){    const char *p = host->ptr;    const char *end = ((const char*)host->ptr) + host->slen;    while (p != end) {	if (pj_isdigit(*p) || *p=='.') {	    ++p;	} else {	    return 0;	}    }    return 1;}/* * This is the main function for performing server resolution. */PJ_DEF(void) pjsip_resolve( pjsip_resolver_t *resolver,			    pj_pool_t *pool,			    const pjsip_host_info *target,			    void *token,			    pjsip_resolver_callback *cb){    pjsip_server_addresses svr_addr;    pj_status_t status = PJ_SUCCESS;    int is_ip_addr;    struct query *query;    pj_str_t srv_name;    pjsip_transport_type_e type = target->type;    /* Is it IP address or hostname?. */    is_ip_addr = is_str_ip(&target->addr.host);    /* Set the transport type if not explicitly specified.      * RFC 3263 section 4.1 specify rules to set up this.     */    if (type == PJSIP_TRANSPORT_UNSPECIFIED) {	if (is_ip_addr || (target->addr.port != 0)) {#if PJ_HAS_TCP	    if (target->flag & PJSIP_TRANSPORT_SECURE) 	    {		type = PJSIP_TRANSPORT_TLS;	    } else if (target->flag & PJSIP_TRANSPORT_RELIABLE) 	    {		type = PJSIP_TRANSPORT_TCP;	    } else #endif	    {		type = PJSIP_TRANSPORT_UDP;	    }	} else {	    /* No type or explicit port is specified, and the address is	     * not IP address.	     * In this case, full resolution must be performed.	     * But we don't support it (yet).	     */	    type = PJSIP_TRANSPORT_UDP;	}    }    /* If target is an IP address, or if resolver is not configured,      * we can just finish the resolution now using pj_gethostbyname()     */    if (is_ip_addr || resolver->res == NULL) {	pj_in_addr ip_addr;	pj_uint16_t srv_port;	if (!is_ip_addr) {	    PJ_LOG(5,(THIS_FILE, 		      "DNS resolver not available, target '%.*s:%d' type=%s "		      "will be resolved with gethostbyname()",		      target->addr.host.slen,		      target->addr.host.ptr,		      target->addr.port,		      pjsip_transport_get_type_name(target->type)));	}	/* Set the port number if not specified. */	if (target->addr.port == 0) {	   srv_port = (pj_uint16_t)		      pjsip_transport_get_default_port_for_type(type);	} else {	   srv_port = (pj_uint16_t)target->addr.port;	}	/* This will eventually call pj_gethostbyname() if the host	 * is not an IP address.	 */	status = pj_sockaddr_in_init((pj_sockaddr_in*)&svr_addr.entry[0].addr,				      &target->addr.host, srv_port);	if (status != PJ_SUCCESS)	    goto on_error;	/* Call the callback. */	ip_addr = ((pj_sockaddr_in*)&svr_addr.entry[0].addr)->sin_addr;	PJ_LOG(5,(THIS_FILE, 		  "Target '%.*s:%d' type=%s resolved to "		  "'%s:%d' type=%s",		  (int)target->addr.host.slen,		  target->addr.host.ptr,		  target->addr.port,		  pjsip_transport_get_type_name(target->type),		  pj_inet_ntoa(ip_addr),		  srv_port,		  pjsip_transport_get_type_name(type)));	svr_addr.count = 1;	svr_addr.entry[0].priority = 0;	svr_addr.entry[0].weight = 0;	svr_addr.entry[0].type = type;	svr_addr.entry[0].addr_len = sizeof(pj_sockaddr_in);	(*cb)(status, token, &svr_addr);	/* Done. */	return;    }    /* Target is not an IP address so we need to resolve it. */#if PJSIP_HAS_RESOLVER    /* Build the query state */    query = pj_pool_zalloc(pool, sizeof(struct query));    pj_ansi_snprintf(query->objname, sizeof(query->objname), "rsvjob%X",		     resolver->job_id++);    query->resolver = resolver;    query->token = token;    query->cb = cb;    query->req.target = *target;    pj_strdup(pool, &query->req.target.addr.host, &target->addr.host);    /* If port is not specified, start with SRV resolution     * (should be with NAPTR, but we'll do that later)     */    PJ_TODO(SUPPORT_DNS_NAPTR);    /* Build dummy NAPTR entry */    query->naptr_cnt = 1;    pj_bzero(&query->naptr[0], sizeof(query->naptr[0]));    query->naptr[0].order = 0;    query->naptr[0].pref = 0;    query->naptr[0].type = type;    query->naptr[0].target_name.ptr = 	pj_pool_alloc(pool, target->addr.host.slen + 12);    if (type == PJSIP_TRANSPORT_TLS)	pj_strcpy2(&query->naptr[0].target_name, "_sips._tcp.");    else if (type == PJSIP_TRANSPORT_TCP)	pj_strcpy2(&query->naptr[0].target_name, "_sip._tcp.");    else if (type == PJSIP_TRANSPORT_UDP)	pj_strcpy2(&query->naptr[0].target_name, "_sip._udp.");    else {	pj_assert(!"Unknown transport type");	pj_strcpy2(&query->naptr[0].target_name, "_sip._udp.");    }    pj_strcat(&query->naptr[0].target_name, &target->addr.host);    /* Start DNS SRV or A resolution, depending on whether port is specified */    if (target->addr.port == 0) {	query->dns_state = PJ_DNS_TYPE_SRV;	srv_name = query->naptr[0].target_name;    } else {	/* Otherwise if port is specified, start with A (or AAAA) host 	 * resolution 	 */	query->dns_state = PJ_DNS_TYPE_A;	/* Since we don't perform SRV resolution, pretend that we'ee already	 * done so by inserting a dummy SRV record.	 */	query->srv_cnt = 1;	pj_bzero(&query->srv[0], sizeof(query->srv[0]));	query->srv[0].target_name = query->req.target.addr.host;	query->srv[0].type = type;	query->srv[0].port = query->req.target.addr.port;	query->srv[0].priority = 0;	query->srv[0].weight = 0;	srv_name = query->srv[0].target_name;    }    /* Start the asynchronous query */    PJ_LOG(5, (query->objname, 	       "Starting async DNS %s query: target=%.*s, transport=%s, "	       "port=%d",	       pj_dns_get_type_name(query->dns_state),	       (int)srv_name.slen, srv_name.ptr,	       pjsip_transport_get_type_name(target->type),	       target->addr.port));    status = pj_dns_resolver_start_query(resolver->res, &srv_name, 				         query->dns_state, 0, &dns_callback,    					 query, &query->object);    if (status != PJ_SUCCESS)	goto on_error;    return;#else /* PJSIP_HAS_RESOLVER */    PJ_UNUSED_ARG(pool);    PJ_UNUSED_ARG(query);    PJ_UNUSED_ARG(srv_name);#endif /* PJSIP_HAS_RESOLVER */on_error:    if (status != PJ_SUCCESS) {	char errmsg[PJ_ERR_MSG_SIZE];	PJ_LOG(4,(THIS_FILE, "Failed to resolve '%.*s'. Err=%d (%s)",			     (int)target->addr.host.slen,			     target->addr.host.ptr,			     status,			     pj_strerror(status,errmsg,sizeof(errmsg)).ptr));	(*cb)(status, token, NULL);	return;    }}/* * The rest of the code should only get compiled when resolver is enabled */#if PJSIP_HAS_RESOLVER#define SWAP(type,ptr1,ptr2)	if (ptr1 != ptr2) { \				  type tmp; \				  pj_memcpy(&tmp, ptr1, sizeof(type)); \				  pj_memcpy(ptr1, ptr2, sizeof(type)); \				  (ptr1)->target_name.ptr = (ptr1)->target_buf; \				  pj_memcpy(ptr2, &tmp, sizeof(type)); \				  (ptr2)->target_name.ptr = (ptr2)->target_buf; \				} else {}/* Build server entries in the query based on received SRV response */static void build_server_entries(struct query *query, 				 pj_dns_parsed_packet *response){    unsigned i;    unsigned naptr_id;    /* Find NAPTR target which corresponds to this SRV target */    for (naptr_id=0; naptr_id < query->naptr_cnt; ++naptr_id) {	if (pj_stricmp(&query->naptr[naptr_id].target_name,		       &response->ans[0].name)==0)	    break;    }    if (naptr_id == query->naptr_cnt) {	PJ_LOG(4,(query->objname, 		  "Unable to find NAPTR record for SRV name %.*s!",		  (int)response->ans[0].name.slen, 		  response->ans[0].name.ptr));	return;    }    /* Save the Resource Records in DNS answer into SRV targets. */    query->srv_cnt = 0;    for (i=0; i<response->hdr.anscount && 	      query->srv_cnt < PJSIP_MAX_RESOLVED_ADDRESSES; ++i)     {	pj_dns_parsed_rr *rr = &response->ans[i];	struct srv_target *srv = &query->srv[query->srv_cnt];	if (rr->type != PJ_DNS_TYPE_SRV) {	    PJ_LOG(4,(query->objname, 		      "Received non SRV answer for SRV query!"));	    continue;	}	if (rr->rdata.srv.target.slen > PJ_MAX_HOSTNAME) {	    PJ_LOG(4,(query->objname, "Hostname is too long!"));	    continue;	}	/* Build the SRV entry for RR */	pj_bzero(srv, sizeof(*srv));	pj_memcpy(srv->target_buf, rr->rdata.srv.target.ptr, 		  rr->rdata.srv.target.slen);	srv->target_name.ptr = srv->target_buf;	srv->target_name.slen = rr->rdata.srv.target.slen;	srv->type = query->naptr[naptr_id].type;	srv->port = rr->rdata.srv.port;	srv->priority = rr->rdata.srv.prio;	srv->weight = rr->rdata.srv.weight;		++query->srv_cnt;    }    /* First pass:      *	order the entries based on priority.     */    for (i=0; i<query->srv_cnt-1; ++i) {	unsigned min = i, j;	for (j=i+1; j<query->srv_cnt; ++j) {

⌨️ 快捷键说明

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