Changeset 64 for pjproject/trunk/pjsip/src/pjsip/sip_uri.c
- Timestamp:
- Nov 20, 2005 7:58:10 PM (18 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
pjproject/trunk/pjsip/src/pjsip/sip_uri.c
r51 r64 19 19 #include <pjsip/sip_uri.h> 20 20 #include <pjsip/sip_msg.h> 21 #include <pjsip/sip_parser.h> 21 22 #include <pjsip/print_util.h> 23 #include <pjsip/sip_errno.h> 24 #include <pjlib-util/string.h> 22 25 #include <pj/string.h> 23 26 #include <pj/pool.h> 24 27 #include <pj/assert.h> 25 28 29 /* 30 * Generic parameter manipulation. 31 */ 32 PJ_DEF(pjsip_param*) pjsip_param_find( pjsip_param *param_list, 33 const pj_str_t *name ) 34 { 35 pjsip_param *p = param_list->next; 36 while (p != param_list) { 37 if (pj_stricmp(&p->name, name)==0) 38 return p; 39 p = p->next; 40 } 41 return NULL; 42 } 43 44 PJ_DEF(const pjsip_param*) pjsip_param_cfind( const pjsip_param *param_list, 45 const pj_str_t *name ) 46 { 47 const pjsip_param *p = param_list->next; 48 while (p != param_list) { 49 if (pj_stricmp(&p->name, name)==0) 50 return p; 51 p = p->next; 52 } 53 return NULL; 54 } 55 56 PJ_DEF(void) pjsip_param_clone( pj_pool_t *pool, pjsip_param *dst_list, 57 const pjsip_param *src_list) 58 { 59 const pjsip_param *p = src_list->next; 60 61 pj_list_init(dst_list); 62 while (p != src_list) { 63 pjsip_param *new_param = pj_pool_alloc(pool, sizeof(pjsip_param)); 64 pj_strdup(pool, &new_param->name, &p->name); 65 pj_strdup(pool, &new_param->value, &p->value); 66 pj_list_insert_before(dst_list, new_param); 67 p = p->next; 68 } 69 } 70 71 /* 72 * URI stuffs 73 */ 26 74 #define IS_SIPS(url) ((url)->vptr==&sips_url_vptr) 27 75 … … 110 158 url->ttl_param = -1; 111 159 url->vptr = secure ? &sips_url_vptr : &sip_url_vptr; 160 pj_list_init(&url->other_param); 161 pj_list_init(&url->header_param); 112 162 } 113 163 … … 124 174 { 125 175 int printed; 126 pj_size_t size_required;127 176 char *startbuf = buf; 177 char *endbuf = buf+size; 128 178 const pj_str_t *scheme; 179 pjsip_param *param; 180 char hparam_char = '?'; 181 129 182 *buf = '\0'; 130 131 /* Check the buffer length. */132 size_required = 6 + url->host.slen + 10 +133 url->user.slen + url->passwd.slen + 2 +134 url->user_param.slen + 6 +135 url->method_param.slen + 8 +136 url->transport_param.slen + 11 +137 9 + 5 +138 url->maddr_param.slen + 7 +139 3 +140 url->other_param.slen +141 url->header_param.slen;142 if (size < size_required) {143 return -1;144 }145 183 146 184 /* Print scheme ("sip:" or "sips:") */ 147 185 scheme = pjsip_uri_get_scheme(url); 148 copy_advance_ no_check(buf, *scheme);186 copy_advance_check(buf, *scheme); 149 187 *buf++ = ':'; 150 188 151 189 /* Print "user:password@", if any. */ 152 190 if (url->user.slen) { 153 copy_advance_ no_check(buf, url->user);191 copy_advance_escape(buf, url->user, pjsip_USER_SPEC); 154 192 if (url->passwd.slen) { 155 193 *buf++ = ':'; 156 copy_advance_ no_check(buf, url->passwd);194 copy_advance_escape(buf, url->passwd, pjsip_PASSWD_SPEC); 157 195 } 158 196 … … 162 200 /* Print host. */ 163 201 pj_assert(url->host.slen != 0); 164 copy_advance_ no_check(buf, url->host);202 copy_advance_check(buf, url->host); 165 203 166 204 /* Only print port if it is explicitly specified. … … 171 209 * UA has sent us port, so we'll just send the port indiscrimately 172 210 */ 173 PJ_TODO(SHOULD_DISALLOW_URI_PORT_IN_FROM_TO_HEADER)174 if (url->port /*&& context != PJSIP_URI_IN_FROMTO_HDR*/) {211 //PJ_TODO(SHOULD_DISALLOW_URI_PORT_IN_FROM_TO_HEADER) 212 if (url->port && context != PJSIP_URI_IN_FROMTO_HDR) { 175 213 *buf++ = ':'; 176 214 printed = pj_utoa(url->port, buf); … … 179 217 180 218 /* User param is allowed in all contexes */ 181 copy_advance_pair_ no_check(buf, ";user=", 6, url->user_param);219 copy_advance_pair_check(buf, ";user=", 6, url->user_param); 182 220 183 221 /* Method param is only allowed in external/other context. */ 184 222 if (context == PJSIP_URI_IN_OTHER) { 185 copy_advance_pair_no_check(buf, ";method=", 8, url->method_param); 223 copy_advance_pair_escape(buf, ";method=", 8, url->method_param, 224 pjsip_PARAM_CHAR_SPEC); 186 225 } 187 226 188 227 /* Transport is not allowed in From/To header. */ 189 228 if (context != PJSIP_URI_IN_FROMTO_HDR) { 190 copy_advance_pair_no_check(buf, ";transport=", 11, url->transport_param); 229 copy_advance_pair_escape(buf, ";transport=", 11, url->transport_param, 230 pjsip_PARAM_CHAR_SPEC); 191 231 } 192 232 193 233 /* TTL param is not allowed in From, To, Route, and Record-Route header. */ 194 234 if (url->ttl_param >= 0 && context != PJSIP_URI_IN_FROMTO_HDR && 195 context != PJSIP_URI_IN_ROUTING_HDR )235 context != PJSIP_URI_IN_ROUTING_HDR && (endbuf-buf) > 15) 196 236 { 197 237 pj_memcpy(buf, ";ttl=", 5); … … 202 242 /* maddr param is not allowed in From and To header. */ 203 243 if (context != PJSIP_URI_IN_FROMTO_HDR) { 204 copy_advance_pair_no_check(buf, ";maddr=", 7, url->maddr_param); 244 copy_advance_pair_escape(buf, ";maddr=", 7, url->maddr_param, 245 pjsip_PARAM_CHAR_SPEC); 205 246 } 206 247 … … 210 251 { 211 252 pj_str_t lr = { ";lr", 3 }; 212 copy_advance_ no_check(buf, lr);253 copy_advance_check(buf, lr); 213 254 } 214 255 215 256 /* Other param. */ 216 if (url->other_param.slen) { 217 copy_advance_no_check(buf, url->other_param); 257 param = url->other_param.next; 258 while (param != &url->other_param) { 259 *buf++ = ';'; 260 copy_advance_escape(buf, param->name, pjsip_PARAM_CHAR_SPEC); 261 if (param->value.slen) { 262 *buf++ = '='; 263 copy_advance_escape(buf, param->value, pjsip_PARAM_CHAR_SPEC); 264 } 265 param = param->next; 218 266 } 219 267 220 268 /* Header param. */ 221 if (url->header_param.slen) { 222 copy_advance_no_check(buf, url->header_param); 269 param = url->header_param.next; 270 while (param != &url->header_param) { 271 *buf++ = hparam_char; 272 copy_advance_escape(buf, param->name, pjsip_HDR_CHAR_SPEC); 273 if (param->value.slen) { 274 *buf++ = '='; 275 copy_advance_escape(buf, param->value, pjsip_HDR_CHAR_SPEC); 276 } 277 param = param->next; 278 hparam_char = '&'; 223 279 } 224 280 … … 227 283 } 228 284 229 static int pjsip_url_compare( pjsip_uri_context_e context, 230 const pjsip_url *url1, const pjsip_url *url2) 231 { 232 /* The easiest (and probably the most efficient) way to compare two URLs 233 are to print them, and compare them bytes per bytes. This technique 234 works quite well with RFC3261, as the RFC (unlike RFC2543) defines that 235 components specified in one URL does NOT match its default value if 236 it is not specified in the second URL. For example, parameter "user=ip" 237 does NOT match if it is omited in second URL. 238 239 HOWEVER, THE SAME CAN NOT BE APPLIED FOR other-param NOR header-param. 240 For these, each of the parameters must be compared one by one. Parameter 241 that exists in one URL will match the comparison. But parameter that 242 exists in both URLs and doesn't match wont match the URL comparison. 243 244 The solution for this is to compare 'standard' URL components with 245 bytes-to-bytes comparison, and compare other-param and header-param with 246 more intelligent comparison. 247 */ 248 char str_url1[PJSIP_MAX_URL_SIZE]; 249 char str_url2[PJSIP_MAX_URL_SIZE]; 250 int len1, len2; 251 252 /* Must compare scheme first, as the second URI may not be SIP URL. */ 253 if (pj_stricmp(pjsip_uri_get_scheme(url1), pjsip_uri_get_scheme(url2))) 254 return -1; 255 256 len1 = pjsip_url_print(context, url1, str_url1, sizeof(str_url1)); 257 if (len1 < 1) { 258 pj_assert(0); 259 return -1; 260 } 261 len2 = pjsip_url_print(context, url2, str_url2, sizeof(str_url2)); 262 if (len2 < 1) { 263 pj_assert(0); 264 return -1; 265 } 266 267 if (len1 != len2) { 268 /* Not equal. */ 269 return -1; 270 } 271 272 if (pj_native_strcmp(str_url1, str_url2)) { 273 /* Not equal */ 274 return -1; 275 } 276 277 /* TODO: compare other-param and header-param in more intelligent manner. */ 278 PJ_TODO(HPARAM_AND_OTHER_PARAM_COMPARISON_IN_URL_COMPARISON) 279 280 if (pj_strcmp(&url1->other_param, &url2->other_param)) { 281 /* Not equal. */ 282 return -1; 283 } 284 if (pj_strcmp(&url1->header_param, &url2->header_param)) { 285 /* Not equal. */ 286 return -1; 287 } 288 289 /* Seems to be equal, isn't it. */ 290 return 0; 285 static pj_status_t pjsip_url_compare( pjsip_uri_context_e context, 286 const pjsip_url *url1, 287 const pjsip_url *url2) 288 { 289 const pjsip_param *p1; 290 291 /* 292 * Compare two SIP URL's according to Section 19.1.4 of RFC 3261. 293 */ 294 295 /* SIP and SIPS URI are never equivalent. 296 * Note: just compare the vptr to avoid string comparison. 297 * Pretty neat huh!! 298 */ 299 if (url1->vptr != url2->vptr) 300 return PJSIP_ECMPSCHEME; 301 302 /* Comparison of the userinfo of SIP and SIPS URIs is case-sensitive. 303 * This includes userinfo containing passwords or formatted as 304 * telephone-subscribers. 305 */ 306 if (pj_strcmp(&url1->user, &url2->user) != 0) 307 return PJSIP_ECMPUSER; 308 if (pj_strcmp(&url1->passwd, &url2->passwd) != 0) 309 return PJSIP_ECMPPASSWD; 291 310 311 /* Comparison of all other components of the URI is 312 * case-insensitive unless explicitly defined otherwise. 313 */ 314 315 /* The ordering of parameters and header fields is not significant 316 * in comparing SIP and SIPS URIs. 317 */ 318 319 /* Characters other than those in the reserved set (see RFC 2396 [5]) 320 * are equivalent to their encoding. 321 */ 322 323 /* An IP address that is the result of a DNS lookup of a host name 324 * does not match that host name. 325 */ 326 if (pj_stricmp(&url1->host, &url2->host) != 0) 327 return PJSIP_ECMPHOST; 328 329 /* A URI omitting any component with a default value will not match a URI 330 * explicitly containing that component with its default value. 331 * For instance, a URI omitting the optional port component will not match 332 * a URI explicitly declaring port 5060. 333 * The same is true for the transport-parameter, ttl-parameter, 334 * user-parameter, and method components. 335 */ 336 337 /* Port is not allowed in To and From header. 338 */ 339 if (context != PJSIP_URI_IN_FROMTO_HDR) { 340 if (url1->port != url2->port) 341 return PJSIP_ECMPPORT; 342 } 343 /* Transport is not allowed in From/To header. */ 344 if (context != PJSIP_URI_IN_FROMTO_HDR) { 345 if (pj_stricmp(&url1->transport_param, &url2->transport_param) != 0) 346 return PJSIP_ECMPTRANSPORTPRM; 347 } 348 /* TTL param is not allowed in From, To, Route, and Record-Route header. */ 349 if (context != PJSIP_URI_IN_FROMTO_HDR && 350 context != PJSIP_URI_IN_ROUTING_HDR) 351 { 352 if (url1->ttl_param != url2->ttl_param) 353 return PJSIP_ECMPTTLPARAM; 354 } 355 /* User param is allowed in all contexes */ 356 if (pj_stricmp(&url1->user_param, &url2->user_param) != 0) 357 return PJSIP_ECMPUSERPARAM; 358 /* Method param is only allowed in external/other context. */ 359 if (context == PJSIP_URI_IN_OTHER) { 360 if (pj_stricmp(&url1->method_param, &url2->method_param) != 0) 361 return PJSIP_ECMPMETHODPARAM; 362 } 363 /* maddr param is not allowed in From and To header. */ 364 if (context != PJSIP_URI_IN_FROMTO_HDR) { 365 if (pj_stricmp(&url1->maddr_param, &url2->maddr_param) != 0) 366 return PJSIP_ECMPMADDRPARAM; 367 } 368 369 /* lr parameter is ignored (?) */ 370 /* lr param is not allowed in From, To, and Contact header. */ 371 372 373 /* All other uri-parameters appearing in only one URI are ignored when 374 * comparing the URIs. 375 */ 376 p1 = url1->other_param.next; 377 while (p1 != &url1->other_param) { 378 const pjsip_param *p2; 379 p2 = pjsip_param_cfind(&url2->other_param, &p1->name); 380 if (p2 ) { 381 if (pj_stricmp(&p1->value, &p2->value) != 0) 382 return PJSIP_ECMPOTHERPARAM; 383 } 384 385 p1 = p1->next; 386 } 387 388 /* URI header components are never ignored. Any present header component 389 * MUST be present in both URIs and match for the URIs to match. 390 * The matching rules are defined for each header field in Section 20. 391 */ 392 p1 = url1->header_param.next; 393 while (p1 != &url1->header_param) { 394 const pjsip_param *p2; 395 p2 = pjsip_param_cfind(&url2->header_param, &p1->name); 396 if (p2) { 397 /* It seems too much to compare two header params according to 398 * the rule of each header. We'll just compare them string to 399 * string.. 400 */ 401 PJ_TODO(MORE_COMPLIANT_HEADER_PARAM_COMPARISON_IN_URL); 402 403 if (pj_stricmp(&p1->value, &p2->value) != 0) 404 return PJSIP_ECMPHEADERPARAM; 405 } else { 406 return PJSIP_ECMPHEADERPARAM; 407 } 408 p1 = p1->next; 409 } 410 411 /* Equal!! Pheuww.. */ 412 return PJ_SUCCESS; 292 413 } 293 414 … … 305 426 url->ttl_param = rhs->ttl_param; 306 427 pj_strdup( pool, &url->maddr_param, &rhs->maddr_param); 307 pj _strdup(pool, &url->other_param, &rhs->other_param);308 pj _strdup(pool, &url->header_param, &rhs->header_param);428 pjsip_param_clone(pool, &url->other_param, &rhs->other_param); 429 pjsip_param_clone(pool, &url->header_param, &rhs->header_param); 309 430 url->lr_param = rhs->lr_param; 310 431 }
Note: See TracChangeset
for help on using the changeset viewer.