📄 sip_uri.c
字号:
/* $Id: sip_uri.c 974 2007-02-19 01:13:53Z 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_uri.h>
#include <pjsip/sip_msg.h>
#include <pjsip/sip_parser.h>
#include <pjsip/print_util.h>
#include <pjsip/sip_errno.h>
#include <pjlib-util/string.h>
#include <pj/string.h>
#include <pj/pool.h>
#include <pj/assert.h>
/*
* Generic parameter manipulation.
*/
PJ_DEF(pjsip_param*) pjsip_param_find( pjsip_param *param_list,
const pj_str_t *name )
{
pjsip_param *p = param_list->next;
while (p != param_list) {
if (pj_stricmp(&p->name, name)==0)
return p;
p = p->next;
}
return NULL;
}
PJ_DEF(const pjsip_param*) pjsip_param_cfind( const pjsip_param *param_list,
const pj_str_t *name )
{
const pjsip_param *p = param_list->next;
while (p != param_list) {
if (pj_stricmp_alnum(&p->name, name)==0)
return p;
p = p->next;
}
return NULL;
}
PJ_DEF(void) pjsip_param_clone( pj_pool_t *pool, pjsip_param *dst_list,
const pjsip_param *src_list)
{
const pjsip_param *p = src_list->next;
pj_list_init(dst_list);
while (p != src_list) {
pjsip_param *new_param = pj_pool_alloc(pool, sizeof(pjsip_param));
pj_strdup(pool, &new_param->name, &p->name);
pj_strdup(pool, &new_param->value, &p->value);
pj_list_insert_before(dst_list, new_param);
p = p->next;
}
}
PJ_DEF(void) pjsip_param_shallow_clone( pj_pool_t *pool,
pjsip_param *dst_list,
const pjsip_param *src_list)
{
const pjsip_param *p = src_list->next;
pj_list_init(dst_list);
while (p != src_list) {
pjsip_param *new_param = pj_pool_alloc(pool, sizeof(pjsip_param));
new_param->name = p->name;
new_param->value = p->value;
pj_list_insert_before(dst_list, new_param);
p = p->next;
}
}
PJ_DEF(pj_ssize_t) pjsip_param_print_on( const pjsip_param *param_list,
char *buf, pj_size_t size,
const pj_cis_t *pname_spec,
const pj_cis_t *pvalue_spec,
int sep)
{
const pjsip_param *p;
char *startbuf;
char *endbuf;
int printed;
p = param_list->next;
if (p == param_list)
return 0;
startbuf = buf;
endbuf = buf + size;
PJ_UNUSED_ARG(pname_spec);
do {
*buf++ = (char)sep;
copy_advance_escape(buf, p->name, (*pname_spec));
if (p->value.slen) {
*buf++ = '=';
copy_advance_escape(buf, p->value, (*pvalue_spec));
}
p = p->next;
if (sep == '?') sep = '&';
} while (p != param_list);
return buf-startbuf;
}
/*
* URI stuffs
*/
#define IS_SIPS(url) ((url)->vptr==&sips_url_vptr)
static const pj_str_t *pjsip_url_get_scheme( const pjsip_sip_uri* );
static const pj_str_t *pjsips_url_get_scheme( const pjsip_sip_uri* );
static const pj_str_t *pjsip_name_addr_get_scheme( const pjsip_name_addr * );
static void *pjsip_get_uri( pjsip_uri *uri );
static void *pjsip_name_addr_get_uri( pjsip_name_addr *name );
static pj_str_t sip_str = { "sip", 3 };
static pj_str_t sips_str = { "sips", 4 };
#ifdef __GNUC__
# define HAPPY_FLAG (void*)
#else
# define HAPPY_FLAG
#endif
static pjsip_name_addr* pjsip_name_addr_clone( pj_pool_t *pool,
const pjsip_name_addr *rhs);
static pj_ssize_t pjsip_name_addr_print(pjsip_uri_context_e context,
const pjsip_name_addr *name,
char *buf, pj_size_t size);
static int pjsip_name_addr_compare( pjsip_uri_context_e context,
const pjsip_name_addr *naddr1,
const pjsip_name_addr *naddr2);
static pj_ssize_t pjsip_url_print( pjsip_uri_context_e context,
const pjsip_sip_uri *url,
char *buf, pj_size_t size);
static int pjsip_url_compare( pjsip_uri_context_e context,
const pjsip_sip_uri *url1,
const pjsip_sip_uri *url2);
static pjsip_sip_uri* pjsip_url_clone(pj_pool_t *pool,
const pjsip_sip_uri *rhs);
static pjsip_uri_vptr sip_url_vptr =
{
HAPPY_FLAG &pjsip_url_get_scheme,
HAPPY_FLAG &pjsip_get_uri,
HAPPY_FLAG &pjsip_url_print,
HAPPY_FLAG &pjsip_url_compare,
HAPPY_FLAG &pjsip_url_clone
};
static pjsip_uri_vptr sips_url_vptr =
{
HAPPY_FLAG &pjsips_url_get_scheme,
HAPPY_FLAG &pjsip_get_uri,
HAPPY_FLAG &pjsip_url_print,
HAPPY_FLAG &pjsip_url_compare,
HAPPY_FLAG &pjsip_url_clone
};
static pjsip_uri_vptr name_addr_vptr =
{
HAPPY_FLAG &pjsip_name_addr_get_scheme,
HAPPY_FLAG &pjsip_name_addr_get_uri,
HAPPY_FLAG &pjsip_name_addr_print,
HAPPY_FLAG &pjsip_name_addr_compare,
HAPPY_FLAG &pjsip_name_addr_clone
};
static const pj_str_t *pjsip_url_get_scheme(const pjsip_sip_uri *url)
{
PJ_UNUSED_ARG(url);
return &sip_str;
}
static const pj_str_t *pjsips_url_get_scheme(const pjsip_sip_uri *url)
{
PJ_UNUSED_ARG(url);
return &sips_str;
}
static void *pjsip_get_uri( pjsip_uri *uri )
{
return uri;
}
static void *pjsip_name_addr_get_uri( pjsip_name_addr *name )
{
return pjsip_uri_get_uri(name->uri);
}
PJ_DEF(void) pjsip_sip_uri_set_secure( pjsip_sip_uri *url,
pj_bool_t secure )
{
url->vptr = secure ? &sips_url_vptr : &sip_url_vptr;
}
PJ_DEF(void) pjsip_sip_uri_init(pjsip_sip_uri *url, pj_bool_t secure)
{
pj_bzero(url, sizeof(*url));
url->ttl_param = -1;
pjsip_sip_uri_set_secure(url, secure);
pj_list_init(&url->other_param);
pj_list_init(&url->header_param);
}
PJ_DEF(pjsip_sip_uri*) pjsip_sip_uri_create( pj_pool_t *pool,
pj_bool_t secure )
{
pjsip_sip_uri *url = pj_pool_alloc(pool, sizeof(pjsip_sip_uri));
pjsip_sip_uri_init(url, secure);
return url;
}
static pj_ssize_t pjsip_url_print( pjsip_uri_context_e context,
const pjsip_sip_uri *url,
char *buf, pj_size_t size)
{
int printed;
char *startbuf = buf;
char *endbuf = buf+size;
const pj_str_t *scheme;
*buf = '\0';
/* Print scheme ("sip:" or "sips:") */
scheme = pjsip_uri_get_scheme(url);
copy_advance_check(buf, *scheme);
*buf++ = ':';
/* Print "user:password@", if any. */
if (url->user.slen) {
copy_advance_escape(buf, url->user, pjsip_USER_SPEC);
if (url->passwd.slen) {
*buf++ = ':';
copy_advance_escape(buf, url->passwd, pjsip_PASSWD_SPEC);
}
*buf++ = '@';
}
/* Print host. */
pj_assert(url->host.slen != 0);
copy_advance_check(buf, url->host);
/* Only print port if it is explicitly specified.
* Port is not allowed in To and From header.
*/
/* Unfortunately some UA requires us to send back the port
* number exactly as it was sent. We don't remember whether an
* UA has sent us port, so we'll just send the port indiscrimately
*/
//PJ_TODO(SHOULD_DISALLOW_URI_PORT_IN_FROM_TO_HEADER)
if (url->port && context != PJSIP_URI_IN_FROMTO_HDR) {
if (endbuf - buf < 10)
return -1;
*buf++ = ':';
printed = pj_utoa(url->port, buf);
buf += printed;
}
/* User param is allowed in all contexes */
copy_advance_pair_check(buf, ";user=", 6, url->user_param);
/* Method param is only allowed in external/other context. */
if (context == PJSIP_URI_IN_OTHER) {
copy_advance_pair_escape(buf, ";method=", 8, url->method_param,
pjsip_PARAM_CHAR_SPEC);
}
/* Transport is not allowed in From/To header. */
if (context != PJSIP_URI_IN_FROMTO_HDR) {
copy_advance_pair_escape(buf, ";transport=", 11, url->transport_param,
pjsip_PARAM_CHAR_SPEC);
}
/* TTL param is not allowed in From, To, Route, and Record-Route header. */
if (url->ttl_param >= 0 && context != PJSIP_URI_IN_FROMTO_HDR &&
context != PJSIP_URI_IN_ROUTING_HDR)
{
if (endbuf - buf < 15)
return -1;
pj_memcpy(buf, ";ttl=", 5);
printed = pj_utoa(url->ttl_param, buf+5);
buf += printed + 5;
}
/* maddr param is not allowed in From and To header. */
if (context != PJSIP_URI_IN_FROMTO_HDR) {
copy_advance_pair_escape(buf, ";maddr=", 7, url->maddr_param,
pjsip_PARAM_CHAR_SPEC);
}
/* lr param is not allowed in From, To, and Contact header. */
if (url->lr_param && context != PJSIP_URI_IN_FROMTO_HDR &&
context != PJSIP_URI_IN_CONTACT_HDR)
{
pj_str_t lr = { ";lr", 3 };
if (endbuf - buf < 3)
return -1;
copy_advance_check(buf, lr);
}
/* Other param. */
printed = pjsip_param_print_on(&url->other_param, buf, endbuf-buf,
&pjsip_PARAM_CHAR_SPEC,
&pjsip_PARAM_CHAR_SPEC, ';');
if (printed < 0)
return -1;
buf += printed;
/* Header param.
* Header param is only allowed in these contexts:
* - PJSIP_URI_IN_CONTACT_HDR
* - PJSIP_URI_IN_OTHER
*/
if (context == PJSIP_URI_IN_CONTACT_HDR || context == PJSIP_URI_IN_OTHER) {
printed = pjsip_param_print_on(&url->header_param, buf, endbuf-buf,
&pjsip_HDR_CHAR_SPEC,
&pjsip_HDR_CHAR_SPEC, '?');
if (printed < 0)
return -1;
buf += printed;
}
*buf = '\0';
return buf-startbuf;
}
static pj_status_t pjsip_url_compare( pjsip_uri_context_e context,
const pjsip_sip_uri *url1,
const pjsip_sip_uri *url2)
{
const pjsip_param *p1;
/*
* Compare two SIP URL's according to Section 19.1.4 of RFC 3261.
*/
/* SIP and SIPS URI are never equivalent.
* Note: just compare the vptr to avoid string comparison.
* Pretty neat huh!!
*/
if (url1->vptr != url2->vptr)
return PJSIP_ECMPSCHEME;
/* Comparison of the userinfo of SIP and SIPS URIs is case-sensitive.
* This includes userinfo containing passwords or formatted as
* telephone-subscribers.
*/
if (pj_strcmp(&url1->user, &url2->user) != 0)
return PJSIP_ECMPUSER;
if (pj_strcmp(&url1->passwd, &url2->passwd) != 0)
return PJSIP_ECMPPASSWD;
/* Comparison of all other components of the URI is
* case-insensitive unless explicitly defined otherwise.
*/
/* The ordering of parameters and header fields is not significant
* in comparing SIP and SIPS URIs.
*/
/* Characters other than those in the 搑eserved
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -