1
/* $Id: sip_uri.c 4228 2012-08-13 07:26:03Z bennylp $ */
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 <pjsip/sip_uri.h>
21
#include <pjsip/sip_msg.h>
22
#include <pjsip/sip_parser.h>
23
#include <pjsip/print_util.h>
24
#include <pjsip/sip_errno.h>
25
#include <pjlib-util/string.h>
26
#include <pj/string.h>
28
#include <pj/assert.h>
31
* Generic parameter manipulation.
33
PJ_DEF(pjsip_param*) pjsip_param_find( const pjsip_param *param_list,
34
const pj_str_t *name )
36
pjsip_param *p = (pjsip_param*)param_list->next;
37
while (p != param_list) {
38
if (pj_stricmp(&p->name, name)==0)
45
PJ_DEF(int) pjsip_param_cmp( const pjsip_param *param_list1,
46
const pjsip_param *param_list2,
49
const pjsip_param *p1;
51
if ((ig_nf & 1)==0 && pj_list_size(param_list1)!=pj_list_size(param_list2))
54
p1 = param_list1->next;
55
while (p1 != param_list1) {
56
const pjsip_param *p2;
57
p2 = pjsip_param_find(param_list2, &p1->name);
59
int rc = pj_stricmp(&p1->value, &p2->value);
62
} else if ((ig_nf & 1)==0)
71
PJ_DEF(void) pjsip_param_clone( pj_pool_t *pool, pjsip_param *dst_list,
72
const pjsip_param *src_list)
74
const pjsip_param *p = src_list->next;
76
pj_list_init(dst_list);
77
while (p && p != src_list) {
78
pjsip_param *new_param = PJ_POOL_ALLOC_T(pool, pjsip_param);
79
pj_strdup(pool, &new_param->name, &p->name);
80
pj_strdup(pool, &new_param->value, &p->value);
81
pj_list_insert_before(dst_list, new_param);
87
PJ_DEF(void) pjsip_param_shallow_clone( pj_pool_t *pool,
88
pjsip_param *dst_list,
89
const pjsip_param *src_list)
91
const pjsip_param *p = src_list->next;
93
pj_list_init(dst_list);
94
while (p != src_list) {
95
pjsip_param *new_param = PJ_POOL_ALLOC_T(pool, pjsip_param);
96
new_param->name = p->name;
97
new_param->value = p->value;
98
pj_list_insert_before(dst_list, new_param);
103
PJ_DEF(pj_ssize_t) pjsip_param_print_on( const pjsip_param *param_list,
104
char *buf, pj_size_t size,
105
const pj_cis_t *pname_spec,
106
const pj_cis_t *pvalue_spec,
109
const pjsip_param *p;
114
p = param_list->next;
115
if (p == NULL || p == param_list)
121
PJ_UNUSED_ARG(pname_spec);
125
copy_advance_escape(buf, p->name, (*pname_spec));
128
if (*p->value.ptr == '"')
129
copy_advance(buf, p->value);
131
copy_advance_escape(buf, p->value, (*pvalue_spec));
134
if (sep == '?') sep = '&';
135
} while (p != param_list);
144
#define IS_SIPS(url) ((url)->vptr==&sips_url_vptr)
146
static const pj_str_t *pjsip_url_get_scheme( const pjsip_sip_uri* );
147
static const pj_str_t *pjsips_url_get_scheme( const pjsip_sip_uri* );
148
static const pj_str_t *pjsip_name_addr_get_scheme( const pjsip_name_addr * );
149
static void *pjsip_get_uri( pjsip_uri *uri );
150
static void *pjsip_name_addr_get_uri( pjsip_name_addr *name );
152
static pj_str_t sip_str = { "sip", 3 };
153
static pj_str_t sips_str = { "sips", 4 };
155
static pjsip_name_addr* pjsip_name_addr_clone( pj_pool_t *pool,
156
const pjsip_name_addr *rhs);
157
static pj_ssize_t pjsip_name_addr_print(pjsip_uri_context_e context,
158
const pjsip_name_addr *name,
159
char *buf, pj_size_t size);
160
static int pjsip_name_addr_compare( pjsip_uri_context_e context,
161
const pjsip_name_addr *naddr1,
162
const pjsip_name_addr *naddr2);
163
static pj_ssize_t pjsip_url_print( pjsip_uri_context_e context,
164
const pjsip_sip_uri *url,
165
char *buf, pj_size_t size);
166
static int pjsip_url_compare( pjsip_uri_context_e context,
167
const pjsip_sip_uri *url1,
168
const pjsip_sip_uri *url2);
169
static pjsip_sip_uri* pjsip_url_clone(pj_pool_t *pool,
170
const pjsip_sip_uri *rhs);
172
typedef const pj_str_t* (*P_GET_SCHEME)(const void*);
173
typedef void* (*P_GET_URI)(void*);
174
typedef pj_ssize_t (*P_PRINT_URI)(pjsip_uri_context_e,const void *,
176
typedef int (*P_CMP_URI)(pjsip_uri_context_e, const void*,
178
typedef void* (*P_CLONE)(pj_pool_t*, const void*);
181
static pjsip_uri_vptr sip_url_vptr =
183
(P_GET_SCHEME) &pjsip_url_get_scheme,
184
(P_GET_URI) &pjsip_get_uri,
185
(P_PRINT_URI) &pjsip_url_print,
186
(P_CMP_URI) &pjsip_url_compare,
187
(P_CLONE) &pjsip_url_clone
190
static pjsip_uri_vptr sips_url_vptr =
192
(P_GET_SCHEME) &pjsips_url_get_scheme,
193
(P_GET_URI) &pjsip_get_uri,
194
(P_PRINT_URI) &pjsip_url_print,
195
(P_CMP_URI) &pjsip_url_compare,
196
(P_CLONE) &pjsip_url_clone
199
static pjsip_uri_vptr name_addr_vptr =
201
(P_GET_SCHEME) &pjsip_name_addr_get_scheme,
202
(P_GET_URI) &pjsip_name_addr_get_uri,
203
(P_PRINT_URI) &pjsip_name_addr_print,
204
(P_CMP_URI) &pjsip_name_addr_compare,
205
(P_CLONE) &pjsip_name_addr_clone
208
static const pj_str_t *pjsip_url_get_scheme(const pjsip_sip_uri *url)
214
static const pj_str_t *pjsips_url_get_scheme(const pjsip_sip_uri *url)
220
static void *pjsip_get_uri( pjsip_uri *uri )
225
static void *pjsip_name_addr_get_uri( pjsip_name_addr *name )
227
return pjsip_uri_get_uri(name->uri);
230
PJ_DEF(void) pjsip_sip_uri_set_secure( pjsip_sip_uri *url,
233
url->vptr = secure ? &sips_url_vptr : &sip_url_vptr;
236
PJ_DEF(void) pjsip_sip_uri_init(pjsip_sip_uri *url, pj_bool_t secure)
238
pj_bzero(url, sizeof(*url));
240
pjsip_sip_uri_set_secure(url, secure);
241
pj_list_init(&url->other_param);
242
pj_list_init(&url->header_param);
245
PJ_DEF(pjsip_sip_uri*) pjsip_sip_uri_create( pj_pool_t *pool,
248
pjsip_sip_uri *url = PJ_POOL_ALLOC_T(pool, pjsip_sip_uri);
249
pjsip_sip_uri_init(url, secure);
253
static pj_ssize_t pjsip_url_print( pjsip_uri_context_e context,
254
const pjsip_sip_uri *url,
255
char *buf, pj_size_t size)
258
char *startbuf = buf;
259
char *endbuf = buf+size;
260
const pj_str_t *scheme;
261
const pjsip_parser_const_t *pc = pjsip_parser_const();
265
/* Print scheme ("sip:" or "sips:") */
266
scheme = pjsip_uri_get_scheme(url);
267
copy_advance_check(buf, *scheme);
270
/* Print "user:password@", if any. */
271
if (url->user.slen) {
272
const pj_cis_t *spec = pjsip_cfg()->endpt.allow_tx_hash_in_uri ?
273
&pc->pjsip_USER_SPEC_LENIENT :
274
&pc->pjsip_USER_SPEC;
275
copy_advance_escape(buf, url->user, *spec);
276
if (url->passwd.slen) {
278
copy_advance_escape(buf, url->passwd, pc->pjsip_PASSWD_SPEC);
285
pj_assert(url->host.slen != 0);
286
/* Detect IPv6 IP address */
287
if (pj_memchr(url->host.ptr, ':', url->host.slen)) {
288
copy_advance_pair_quote_cond(buf, "", 0, url->host, '[', ']');
290
copy_advance_check(buf, url->host);
293
/* Only print port if it is explicitly specified.
294
* Port is not allowed in To and From header, see Table 1 in
295
* RFC 3261 Section 19.1.1
297
/* Note: ticket #1141 adds run-time setting to allow port number to
298
* appear in From/To header. Default is still false.
301
(context != PJSIP_URI_IN_FROMTO_HDR ||
302
pjsip_cfg()->endpt.allow_port_in_fromto_hdr))
304
if (endbuf - buf < 10)
308
printed = pj_utoa(url->port, buf);
312
/* User param is allowed in all contexes */
313
copy_advance_pair_check(buf, ";user=", 6, url->user_param);
315
/* Method param is only allowed in external/other context. */
316
if (context == PJSIP_URI_IN_OTHER) {
317
copy_advance_pair_escape(buf, ";method=", 8, url->method_param,
318
pc->pjsip_PARAM_CHAR_SPEC);
321
/* Transport is not allowed in From/To header. */
322
if (context != PJSIP_URI_IN_FROMTO_HDR) {
323
copy_advance_pair_escape(buf, ";transport=", 11, url->transport_param,
324
pc->pjsip_PARAM_CHAR_SPEC);
327
/* TTL param is not allowed in From, To, Route, and Record-Route header. */
328
if (url->ttl_param >= 0 && context != PJSIP_URI_IN_FROMTO_HDR &&
329
context != PJSIP_URI_IN_ROUTING_HDR)
331
if (endbuf - buf < 15)
333
pj_memcpy(buf, ";ttl=", 5);
334
printed = pj_utoa(url->ttl_param, buf+5);
338
/* maddr param is not allowed in From and To header. */
339
if (context != PJSIP_URI_IN_FROMTO_HDR && url->maddr_param.slen) {
340
/* Detect IPv6 IP address */
341
if (pj_memchr(url->maddr_param.ptr, ':', url->maddr_param.slen)) {
342
copy_advance_pair_quote_cond(buf, ";maddr=", 7, url->maddr_param,
345
copy_advance_pair_escape(buf, ";maddr=", 7, url->maddr_param,
346
pc->pjsip_PARAM_CHAR_SPEC);
350
/* lr param is not allowed in From, To, and Contact header. */
351
if (url->lr_param && context != PJSIP_URI_IN_FROMTO_HDR &&
352
context != PJSIP_URI_IN_CONTACT_HDR)
354
pj_str_t lr = { ";lr", 3 };
355
if (endbuf - buf < 3)
357
copy_advance_check(buf, lr);
361
printed = pjsip_param_print_on(&url->other_param, buf, endbuf-buf,
362
&pc->pjsip_PARAM_CHAR_SPEC,
363
&pc->pjsip_PARAM_CHAR_SPEC, ';');
369
* Header param is only allowed in these contexts:
370
* - PJSIP_URI_IN_CONTACT_HDR
371
* - PJSIP_URI_IN_OTHER
373
if (context == PJSIP_URI_IN_CONTACT_HDR || context == PJSIP_URI_IN_OTHER) {
374
printed = pjsip_param_print_on(&url->header_param, buf, endbuf-buf,
375
&pc->pjsip_HDR_CHAR_SPEC,
376
&pc->pjsip_HDR_CHAR_SPEC, '?');
386
static pj_status_t pjsip_url_compare( pjsip_uri_context_e context,
387
const pjsip_sip_uri *url1,
388
const pjsip_sip_uri *url2)
390
const pjsip_param *p1;
393
* Compare two SIP URL's according to Section 19.1.4 of RFC 3261.
396
/* SIP and SIPS URI are never equivalent.
397
* Note: just compare the vptr to avoid string comparison.
400
if (url1->vptr != url2->vptr)
401
return PJSIP_ECMPSCHEME;
403
/* Comparison of the userinfo of SIP and SIPS URIs is case-sensitive.
404
* This includes userinfo containing passwords or formatted as
405
* telephone-subscribers.
407
if (pj_strcmp(&url1->user, &url2->user) != 0)
408
return PJSIP_ECMPUSER;
409
if (pj_strcmp(&url1->passwd, &url2->passwd) != 0)
410
return PJSIP_ECMPPASSWD;
412
/* Comparison of all other components of the URI is
413
* case-insensitive unless explicitly defined otherwise.
416
/* The ordering of parameters and header fields is not significant
417
* in comparing SIP and SIPS URIs.
420
/* Characters other than those in the reserved set (see RFC 2396 [5])
421
* are equivalent to their encoding.
424
/* An IP address that is the result of a DNS lookup of a host name
425
* does not match that host name.
427
if (pj_stricmp(&url1->host, &url2->host) != 0)
428
return PJSIP_ECMPHOST;
430
/* A URI omitting any component with a default value will not match a URI
431
* explicitly containing that component with its default value.
432
* For instance, a URI omitting the optional port component will not match
433
* a URI explicitly declaring port 5060.
434
* The same is true for the transport-parameter, ttl-parameter,
435
* user-parameter, and method components.
438
/* Port is not allowed in To and From header.
440
if (context != PJSIP_URI_IN_FROMTO_HDR) {
441
if (url1->port != url2->port)
442
return PJSIP_ECMPPORT;
444
/* Transport is not allowed in From/To header. */
445
if (context != PJSIP_URI_IN_FROMTO_HDR) {
446
if (pj_stricmp(&url1->transport_param, &url2->transport_param) != 0)
447
return PJSIP_ECMPTRANSPORTPRM;
449
/* TTL param is not allowed in From, To, Route, and Record-Route header. */
450
if (context != PJSIP_URI_IN_FROMTO_HDR &&
451
context != PJSIP_URI_IN_ROUTING_HDR)
453
if (url1->ttl_param != url2->ttl_param)
454
return PJSIP_ECMPTTLPARAM;
456
/* User param is allowed in all contexes */
457
if (pj_stricmp(&url1->user_param, &url2->user_param) != 0)
458
return PJSIP_ECMPUSERPARAM;
459
/* Method param is only allowed in external/other context. */
460
if (context == PJSIP_URI_IN_OTHER) {
461
if (pj_stricmp(&url1->method_param, &url2->method_param) != 0)
462
return PJSIP_ECMPMETHODPARAM;
464
/* maddr param is not allowed in From and To header. */
465
if (context != PJSIP_URI_IN_FROMTO_HDR) {
466
if (pj_stricmp(&url1->maddr_param, &url2->maddr_param) != 0)
467
return PJSIP_ECMPMADDRPARAM;
470
/* lr parameter is ignored (?) */
471
/* lr param is not allowed in From, To, and Contact header. */
474
/* All other uri-parameters appearing in only one URI are ignored when
475
* comparing the URIs.
477
if (pjsip_param_cmp(&url1->other_param, &url2->other_param, 1)!=0)
478
return PJSIP_ECMPOTHERPARAM;
480
/* URI header components are never ignored. Any present header component
481
* MUST be present in both URIs and match for the URIs to match.
482
* The matching rules are defined for each header field in Section 20.
484
p1 = url1->header_param.next;
485
while (p1 != &url1->header_param) {
486
const pjsip_param *p2;
487
p2 = pjsip_param_find(&url2->header_param, &p1->name);
489
/* It seems too much to compare two header params according to
490
* the rule of each header. We'll just compare them string to
493
if (pj_stricmp(&p1->value, &p2->value) != 0)
494
return PJSIP_ECMPHEADERPARAM;
496
return PJSIP_ECMPHEADERPARAM;
501
/* Equal!! Pheuww.. */
506
PJ_DEF(void) pjsip_sip_uri_assign(pj_pool_t *pool, pjsip_sip_uri *url,
507
const pjsip_sip_uri *rhs)
509
pj_strdup( pool, &url->user, &rhs->user);
510
pj_strdup( pool, &url->passwd, &rhs->passwd);
511
pj_strdup( pool, &url->host, &rhs->host);
512
url->port = rhs->port;
513
pj_strdup( pool, &url->user_param, &rhs->user_param);
514
pj_strdup( pool, &url->method_param, &rhs->method_param);
515
pj_strdup( pool, &url->transport_param, &rhs->transport_param);
516
url->ttl_param = rhs->ttl_param;
517
pj_strdup( pool, &url->maddr_param, &rhs->maddr_param);
518
pjsip_param_clone(pool, &url->other_param, &rhs->other_param);
519
pjsip_param_clone(pool, &url->header_param, &rhs->header_param);
520
url->lr_param = rhs->lr_param;
523
static pjsip_sip_uri* pjsip_url_clone(pj_pool_t *pool, const pjsip_sip_uri *rhs)
525
pjsip_sip_uri *url = PJ_POOL_ALLOC_T(pool, pjsip_sip_uri);
529
pjsip_sip_uri_init(url, IS_SIPS(rhs));
530
pjsip_sip_uri_assign(pool, url, rhs);
534
static const pj_str_t *pjsip_name_addr_get_scheme(const pjsip_name_addr *name)
536
pj_assert(name->uri != NULL);
537
return pjsip_uri_get_scheme(name->uri);
540
PJ_DEF(void) pjsip_name_addr_init(pjsip_name_addr *name)
542
name->vptr = &name_addr_vptr;
544
name->display.slen = 0;
545
name->display.ptr = NULL;
548
PJ_DEF(pjsip_name_addr*) pjsip_name_addr_create(pj_pool_t *pool)
550
pjsip_name_addr *name_addr = PJ_POOL_ALLOC_T(pool, pjsip_name_addr);
551
pjsip_name_addr_init(name_addr);
555
static pj_ssize_t pjsip_name_addr_print(pjsip_uri_context_e context,
556
const pjsip_name_addr *name,
557
char *buf, pj_size_t size)
560
char *startbuf = buf;
561
char *endbuf = buf + size;
564
uri = (pjsip_uri*) pjsip_uri_get_uri(name->uri);
565
pj_assert(uri != NULL);
567
if (context != PJSIP_URI_IN_REQ_URI) {
568
if (name->display.slen) {
569
if (endbuf-buf < 8) return -1;
571
copy_advance(buf, name->display);
578
printed = pjsip_uri_print(context,uri, buf, size-(buf-startbuf));
583
if (context != PJSIP_URI_IN_REQ_URI) {
591
PJ_DEF(void) pjsip_name_addr_assign(pj_pool_t *pool, pjsip_name_addr *dst,
592
const pjsip_name_addr *src)
594
pj_strdup( pool, &dst->display, &src->display);
595
dst->uri = (pjsip_uri*) pjsip_uri_clone(pool, src->uri);
598
static pjsip_name_addr* pjsip_name_addr_clone( pj_pool_t *pool,
599
const pjsip_name_addr *rhs)
601
pjsip_name_addr *addr = PJ_POOL_ALLOC_T(pool, pjsip_name_addr);
605
pjsip_name_addr_init(addr);
606
pjsip_name_addr_assign(pool, addr, rhs);
610
static int pjsip_name_addr_compare( pjsip_uri_context_e context,
611
const pjsip_name_addr *naddr1,
612
const pjsip_name_addr *naddr2)
616
/* Check that naddr2 is also a name_addr */
617
if (naddr1->vptr != naddr2->vptr)
620
/* I'm not sure whether display name is included in the comparison. */
621
if (pj_strcmp(&naddr1->display, &naddr2->display) != 0) {
625
pj_assert( naddr1->uri != NULL );
626
pj_assert( naddr2->uri != NULL );
628
/* Compare name-addr as URL */
629
d = pjsip_uri_cmp( context, naddr1->uri, naddr2->uri);
636
///////////////////////////////////////////////////////////////////////////////
638
static const pj_str_t *other_uri_get_scheme( const pjsip_other_uri*);
639
static void *other_uri_get_uri( pjsip_other_uri*);
640
static pj_ssize_t other_uri_print( pjsip_uri_context_e context,
641
const pjsip_other_uri *url,
642
char *buf, pj_size_t size);
643
static int other_uri_cmp( pjsip_uri_context_e context,
644
const pjsip_other_uri *url1,
645
const pjsip_other_uri *url2);
646
static pjsip_other_uri* other_uri_clone( pj_pool_t *pool,
647
const pjsip_other_uri *rhs);
649
static pjsip_uri_vptr other_uri_vptr =
651
(P_GET_SCHEME) &other_uri_get_scheme,
652
(P_GET_URI) &other_uri_get_uri,
653
(P_PRINT_URI) &other_uri_print,
654
(P_CMP_URI) &other_uri_cmp,
655
(P_CLONE) &other_uri_clone
659
PJ_DEF(pjsip_other_uri*) pjsip_other_uri_create(pj_pool_t *pool)
661
pjsip_other_uri *uri = PJ_POOL_ZALLOC_T(pool, pjsip_other_uri);
662
uri->vptr = &other_uri_vptr;
666
static const pj_str_t *other_uri_get_scheme( const pjsip_other_uri *uri )
671
static void *other_uri_get_uri( pjsip_other_uri *uri )
676
static pj_ssize_t other_uri_print(pjsip_uri_context_e context,
677
const pjsip_other_uri *uri,
678
char *buf, pj_size_t size)
680
char *startbuf = buf;
681
char *endbuf = buf + size;
683
PJ_UNUSED_ARG(context);
685
if (uri->scheme.slen + uri->content.slen + 1 > (int)size)
689
copy_advance(buf, uri->scheme);
693
copy_advance(buf, uri->content);
695
return (buf - startbuf);
698
static int other_uri_cmp(pjsip_uri_context_e context,
699
const pjsip_other_uri *uri1,
700
const pjsip_other_uri *uri2)
702
PJ_UNUSED_ARG(context);
704
/* Check that uri2 is also an other_uri */
705
if (uri1->vptr != uri2->vptr)
708
/* Scheme must match. */
709
if (pj_stricmp(&uri1->scheme, &uri2->scheme) != 0) {
710
return PJSIP_ECMPSCHEME;
713
/* Content must match. */
714
if(pj_stricmp(&uri1->content, &uri2->content) != 0) {
723
static pjsip_other_uri* other_uri_clone(pj_pool_t *pool,
724
const pjsip_other_uri *rhs)
726
pjsip_other_uri *uri = pjsip_other_uri_create(pool);
727
pj_strdup(pool, &uri->scheme, &rhs->scheme);
728
pj_strdup(pool, &uri->content, &rhs->content);