1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include "sip_parse_uri.h" 30 #include "sip_msg.h" 31 #include "sip_miscdefs.h" 32 #include "sip_parse_generic.h" 33 34 /* 35 * Returns number of digits in the given int 36 */ 37 static int 38 sip_num_of_digits(int num) 39 { 40 int num_of_bytes = 0; 41 42 do { 43 num_of_bytes += 1; 44 num = num / 10; 45 } while (num > 0); 46 return (num_of_bytes); 47 } 48 49 /* 50 * Return the int as a string 51 */ 52 static char * 53 sip_int_to_str(int i) 54 { 55 int count; 56 int t; 57 int x; 58 char *str; 59 60 if (i < 0) 61 return (NULL); 62 /* 63 * the following two loops convert int i to str 64 */ 65 count = 1; 66 t = i; 67 while ((t = t / 10) != 0) { 68 count++; 69 } 70 71 str = calloc(1, sizeof (char) * count + 1); 72 if (str == NULL) 73 return (NULL); 74 t = i; 75 for (x = 0; x < count; x++) { 76 int a; 77 a = t % 10; 78 str[count - 1 - x] = a + '0'; 79 t = t / 10; 80 } 81 str[count] = '\0'; 82 return (str); 83 } 84 85 /* 86 * Add quotes to the give str and return the quoted string 87 */ 88 static char * 89 sip_add_aquot_to_str(char *str, boolean_t *alloc) 90 { 91 char *new_str; 92 char *tmp = str; 93 int size; 94 95 while (isspace(*tmp)) 96 tmp++; 97 98 *alloc = B_FALSE; 99 if (*tmp != SIP_LAQUOT) { 100 size = strlen(str) + 2 * sizeof (char); 101 new_str = calloc(1, size + 1); 102 if (new_str == NULL) 103 return (NULL); 104 new_str[0] = SIP_LAQUOT; 105 new_str[1] = '\0'; 106 (void) strncat(new_str, str, strlen(str)); 107 (void) strncat(new_str, ">", 1); 108 new_str[size] = '\0'; 109 *alloc = B_TRUE; 110 return (new_str); 111 } 112 113 return (str); 114 } 115 116 /* 117 * Add an empty header 118 */ 119 static int 120 sip_add_empty_hdr(sip_msg_t sip_msg, char *hdr_name) 121 { 122 _sip_header_t *new_header; 123 int header_size; 124 _sip_msg_t *_sip_msg; 125 int csize = sizeof (char); 126 127 if (sip_msg == NULL || hdr_name == NULL) 128 return (EINVAL); 129 _sip_msg = (_sip_msg_t *)sip_msg; 130 (void) pthread_mutex_lock(&_sip_msg->sip_msg_mutex); 131 if (_sip_msg->sip_msg_cannot_be_modified) { 132 (void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex); 133 return (ENOTSUP); 134 } 135 136 header_size = strlen(hdr_name) + SIP_SPACE_LEN + csize; 137 138 new_header = sip_new_header(header_size); 139 if (new_header == NULL) { 140 (void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex); 141 return (ENOMEM); 142 } 143 144 (void) snprintf(new_header->sip_hdr_start, header_size + 1, 145 "%s %c", hdr_name, SIP_HCOLON); 146 147 _sip_add_header(_sip_msg, new_header, B_TRUE, B_FALSE, hdr_name); 148 if (_sip_msg->sip_msg_buf != NULL) 149 _sip_msg->sip_msg_modified = B_TRUE; 150 (void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex); 151 152 return (0); 153 } 154 155 /* 156 * Generic function to add a header with two strings to message 157 */ 158 static int 159 sip_add_2strs_to_msg(sip_msg_t sip_msg, char *hdr_name, char *str1, 160 boolean_t qstr1, char *str2, char *plist, char sep) 161 { 162 _sip_header_t *new_header; 163 int header_size; 164 _sip_msg_t *_sip_msg; 165 int csize = sizeof (char); 166 167 if (sip_msg == NULL || str1 == NULL || str2 == NULL || 168 (str1 != NULL && str1[0] == '\0') || 169 (str2 != NULL && str2[0] == '\0')) { 170 return (EINVAL); 171 } 172 _sip_msg = (_sip_msg_t *)sip_msg; 173 (void) pthread_mutex_lock(&_sip_msg->sip_msg_mutex); 174 if (_sip_msg->sip_msg_cannot_be_modified) { 175 (void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex); 176 return (ENOTSUP); 177 } 178 179 if (plist == NULL) { 180 header_size = strlen(hdr_name) + SIP_SPACE_LEN + csize + 181 SIP_SPACE_LEN + strlen(str1) + csize + strlen(str2) + 182 strlen(SIP_CRLF); 183 } else { 184 header_size = strlen(hdr_name) + SIP_SPACE_LEN + csize + 185 SIP_SPACE_LEN + strlen(str1) + csize + strlen(str2) + 186 csize + strlen(plist) + strlen(SIP_CRLF); 187 } 188 if (qstr1) 189 header_size += 2 * sizeof (char); 190 191 new_header = sip_new_header(header_size); 192 if (new_header == NULL) { 193 (void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex); 194 return (ENOMEM); 195 } 196 197 if (plist == NULL) { 198 if (qstr1) { 199 (void) snprintf(new_header->sip_hdr_start, 200 header_size + 1, "%s %c \"%s\"%c%s%s", 201 hdr_name, SIP_HCOLON, str1, sep, str2, SIP_CRLF); 202 } else { 203 (void) snprintf(new_header->sip_hdr_start, 204 header_size + 1, "%s %c %s%c%s%s", 205 hdr_name, SIP_HCOLON, str1, sep, str2, SIP_CRLF); 206 } 207 } else { 208 if (qstr1) { 209 (void) snprintf(new_header->sip_hdr_start, 210 header_size + 1, 211 "%s %c \"%s\"%c%s%c%s%s", hdr_name, SIP_HCOLON, 212 str1, sep, str2, SIP_SEMI, plist, SIP_CRLF); 213 } else { 214 (void) snprintf(new_header->sip_hdr_start, 215 header_size + 1, "%s %c %s%c%s%c%s%s", 216 hdr_name, SIP_HCOLON, str1, sep, str2, SIP_SEMI, 217 plist, SIP_CRLF); 218 } 219 } 220 _sip_add_header(_sip_msg, new_header, B_TRUE, B_FALSE, NULL); 221 if (_sip_msg->sip_msg_buf != NULL) 222 _sip_msg->sip_msg_modified = B_TRUE; 223 (void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex); 224 225 return (0); 226 } 227 228 /* 229 * Generic function to add a header with a string to message 230 */ 231 static int 232 sip_add_str_to_msg(sip_msg_t sip_msg, char *hdr_name, char *str, char *plist, 233 char param_sep) 234 { 235 _sip_header_t *new_header; 236 int header_size; 237 _sip_msg_t *_sip_msg; 238 int csize = sizeof (char); 239 240 if (sip_msg == NULL || str == NULL || (str != NULL && str[0] == '\0')) 241 return (EINVAL); 242 _sip_msg = (_sip_msg_t *)sip_msg; 243 (void) pthread_mutex_lock(&_sip_msg->sip_msg_mutex); 244 if (_sip_msg->sip_msg_cannot_be_modified) { 245 (void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex); 246 return (ENOTSUP); 247 } 248 249 if (plist == NULL) { 250 header_size = strlen(hdr_name) + SIP_SPACE_LEN + csize + 251 SIP_SPACE_LEN + + strlen(str) + strlen(SIP_CRLF); 252 } else { 253 header_size = strlen(hdr_name) + SIP_SPACE_LEN + csize + 254 SIP_SPACE_LEN + + strlen(str) + csize + strlen(plist) + 255 strlen(SIP_CRLF); 256 } 257 258 new_header = sip_new_header(header_size); 259 if (new_header == NULL) { 260 (void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex); 261 return (ENOMEM); 262 } 263 if (plist == NULL) { 264 (void) snprintf(new_header->sip_hdr_start, header_size + 1, 265 "%s %c %s%s", hdr_name, SIP_HCOLON, str, SIP_CRLF); 266 } else { 267 (void) snprintf(new_header->sip_hdr_start, header_size + 1, 268 "%s %c %s%c%s%s", hdr_name, SIP_HCOLON, str, param_sep, 269 plist, SIP_CRLF); 270 } 271 _sip_add_header(_sip_msg, new_header, B_TRUE, B_FALSE, NULL); 272 if (_sip_msg->sip_msg_buf != NULL) 273 _sip_msg->sip_msg_modified = B_TRUE; 274 (void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex); 275 276 return (0); 277 } 278 279 /* 280 * Add an header with an int to sip_msg 281 */ 282 static int 283 sip_add_int_to_msg(sip_msg_t sip_msg, char *hdr_name, int i, char *plist) 284 { 285 _sip_header_t *new_header; 286 int header_size; 287 _sip_msg_t *_sip_msg; 288 char *digit_str; 289 int csize = sizeof (char); 290 291 if (sip_msg == NULL || (hdr_name == NULL)) 292 return (EINVAL); 293 _sip_msg = (_sip_msg_t *)sip_msg; 294 (void) pthread_mutex_lock(&_sip_msg->sip_msg_mutex); 295 if (_sip_msg->sip_msg_cannot_be_modified) { 296 (void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex); 297 return (ENOTSUP); 298 } 299 300 /* 301 * the following two loops convert int i to str 302 */ 303 digit_str = sip_int_to_str(i); 304 if (digit_str == NULL) 305 return (EINVAL); 306 307 if (plist == NULL) { 308 header_size = strlen(hdr_name) + SIP_SPACE_LEN + csize + 309 SIP_SPACE_LEN + strlen(digit_str) + strlen(SIP_CRLF); 310 } else { 311 header_size = strlen(hdr_name) + SIP_SPACE_LEN + csize + 312 SIP_SPACE_LEN + strlen(digit_str) + csize + 313 strlen(plist) + strlen(SIP_CRLF); 314 } 315 316 new_header = sip_new_header(header_size); 317 if (new_header == NULL) { 318 (void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex); 319 free(digit_str); 320 return (ENOMEM); 321 } 322 323 if (plist == NULL) { 324 (void) snprintf(new_header->sip_hdr_start, header_size + 1, 325 "%s %c %s%s", hdr_name, SIP_HCOLON, digit_str, SIP_CRLF); 326 } else { 327 (void) snprintf(new_header->sip_hdr_start, header_size + 1, 328 "%s %c %s%c%s%s", hdr_name, SIP_HCOLON, digit_str, 329 SIP_SEMI, plist, SIP_CRLF); 330 } 331 free(digit_str); 332 _sip_add_header(_sip_msg, new_header, B_TRUE, B_FALSE, NULL); 333 if (_sip_msg->sip_msg_buf != NULL) 334 _sip_msg->sip_msg_modified = B_TRUE; 335 (void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex); 336 337 return (0); 338 } 339 340 /* 341 * Add a header with an int and string to sip_msg 342 */ 343 static int 344 sip_add_intstr_to_msg(sip_msg_t sip_msg, char *hdr_name, int i, char *s, 345 char *plist) 346 { 347 _sip_header_t *new_header; 348 int header_size; 349 _sip_msg_t *_sip_msg; 350 char *digit_str; 351 int csize = sizeof (char); 352 353 if (sip_msg == NULL || (hdr_name == NULL)) 354 return (EINVAL); 355 _sip_msg = (_sip_msg_t *)sip_msg; 356 (void) pthread_mutex_lock(&_sip_msg->sip_msg_mutex); 357 if (_sip_msg->sip_msg_cannot_be_modified) { 358 (void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex); 359 return (ENOTSUP); 360 } 361 362 /* 363 * the following two loops convert int i to str 364 */ 365 digit_str = sip_int_to_str(i); 366 if (digit_str == NULL) { 367 (void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex); 368 return (EINVAL); 369 } 370 if (plist == NULL) { 371 header_size = strlen(hdr_name) + SIP_SPACE_LEN + csize + 372 SIP_SPACE_LEN + strlen(digit_str) + csize + strlen(s) + 373 strlen(SIP_CRLF); 374 } else { 375 header_size = strlen(hdr_name) + SIP_SPACE_LEN + csize + 376 SIP_SPACE_LEN + strlen(digit_str) + csize + strlen(s) + 377 csize + strlen(plist) + strlen(SIP_CRLF); 378 } 379 380 new_header = sip_new_header(header_size); 381 if (new_header == NULL) { 382 (void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex); 383 free(digit_str); 384 return (ENOMEM); 385 } 386 387 if (plist == NULL) { 388 (void) snprintf(new_header->sip_hdr_start, header_size + 1, 389 "%s %c %s %s%s", hdr_name, SIP_HCOLON, digit_str, s, 390 SIP_CRLF); 391 } else { 392 (void) snprintf(new_header->sip_hdr_start, header_size + 1, 393 "%s %c %s %s%c%s%s", hdr_name, SIP_HCOLON, digit_str, 394 s, SIP_SEMI, plist, SIP_CRLF); 395 } 396 free(digit_str); 397 _sip_add_header(_sip_msg, new_header, B_TRUE, B_FALSE, NULL); 398 if (_sip_msg->sip_msg_buf != NULL) 399 _sip_msg->sip_msg_modified = B_TRUE; 400 (void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex); 401 402 return (0); 403 } 404 405 /* 406 * Generic function to add Contact, From, To, Route or Record-Route header 407 */ 408 static int 409 sip_add_name_aspec(sip_msg_t sip_msg, char *display_name, char *uri, 410 char *tags, boolean_t add_aquot, char *header_name, char *params) 411 { 412 char *t = uri; 413 boolean_t qalloc = B_FALSE; 414 boolean_t palloc = B_FALSE; 415 int r; 416 417 if (sip_msg == NULL || uri == NULL || header_name == NULL) 418 return (EINVAL); 419 if (display_name != NULL && !add_aquot) 420 return (EINVAL); 421 if (add_aquot) { 422 t = sip_add_aquot_to_str(uri, &qalloc); 423 if (t == NULL) 424 return (ENOMEM); 425 } 426 if (tags != NULL) { 427 int plen; 428 429 if (params != NULL) 430 return (EINVAL); 431 432 plen = strlen(SIP_TAG) + strlen(tags) + 1; 433 params = malloc(plen); 434 if (params == NULL) 435 return (ENOMEM); 436 (void) snprintf(params, plen, "%s%s", SIP_TAG, tags); 437 params[plen - 1] = '\0'; 438 palloc = B_TRUE; 439 } 440 if (display_name == NULL) { 441 r = sip_add_2strs_to_msg(sip_msg, header_name, " ", B_FALSE, 442 t, params, SIP_SP); 443 } else { 444 r = sip_add_2strs_to_msg(sip_msg, header_name, display_name, 445 B_TRUE, t, params, SIP_SP); 446 } 447 if (qalloc) 448 free(t); 449 if (palloc) 450 free(params); 451 return (r); 452 } 453 454 /* 455 * Accept = "Accept" ":" (media-range [ accept-params ]) 456 * media-range = ( "X/X" | (type "/" "*") | (type "/" subtype))*(";" parameter) 457 * accept-params = ";" "q" "=" qvalue *(accept-extension) 458 * accept-extension = ";" token [ "=" (token | quoted-str) 459 * 460 * function take two char ptrs - type and subtype - if any of them is NULL 461 * the corresponding value will be set to "*" in header 462 */ 463 int 464 sip_add_accept(sip_msg_t sip_msg, char *type, char *subtype, char *m_par, 465 char *a_par) 466 { 467 int ret; 468 char *plist; 469 int size; 470 boolean_t alloc = B_FALSE; 471 472 if (type == NULL && subtype == NULL) { 473 ret = sip_add_empty_hdr(sip_msg, SIP_ACCEPT); 474 return (ret); 475 } 476 477 if ((m_par != NULL) && (a_par != NULL)) { 478 size = strlen(m_par) + strlen(a_par) + 2 * sizeof (char); 479 plist = calloc(1, size * sizeof (char)); 480 (void) strncpy(plist, m_par, strlen(m_par)); 481 (void) strncat(plist, ";", 1); 482 (void) strncat(plist, a_par, strlen(a_par)); 483 alloc = B_TRUE; 484 } else if (m_par != NULL) { 485 plist = m_par; 486 } else 487 plist = a_par; 488 489 if ((type != NULL) && (subtype != NULL)) { 490 ret = sip_add_2strs_to_msg(sip_msg, SIP_ACCEPT, type, B_FALSE, 491 subtype, plist, SIP_SLASH); 492 } else if (type != NULL) { 493 ret = sip_add_2strs_to_msg(sip_msg, SIP_ACCEPT, type, B_FALSE, 494 "*", plist, SIP_SLASH); 495 } else { 496 ret = EINVAL; 497 } 498 499 if (alloc == B_TRUE) 500 free(plist); 501 502 return (ret); 503 } 504 505 506 /* 507 * Accept-Encoding = "Accept-Encoding" ":" 1#(codings [ ";" "q" "=" qval]) 508 * codings = ( content-coding | "*" ) 509 * content-coding = token 510 * 511 * function take one char ptr, if NULL value will be set to "*" 512 */ 513 int 514 sip_add_accept_enc(sip_msg_t sip_msg, char *code, char *plist) 515 { 516 int ret; 517 518 if (code == NULL) { 519 ret = sip_add_str_to_msg(sip_msg, SIP_ACCEPT_ENCODE, "*", plist, 520 SIP_SEMI); 521 } else { 522 ret = sip_add_str_to_msg(sip_msg, SIP_ACCEPT_ENCODE, code, 523 plist, SIP_SEMI); 524 } 525 return (ret); 526 } 527 528 /* 529 * Accept-Language = "Accept-Language" ":" 1#( language-range [ ";" "q""=" val]) 530 * language-range = ( ( 1*8ALPHA *("-" 1*8ALPHA))|"*") 531 */ 532 int 533 sip_add_accept_lang(sip_msg_t sip_msg, char *lang, char *plist) 534 { 535 int ret; 536 537 if (lang == NULL) { 538 ret = sip_add_empty_hdr(sip_msg, SIP_ACCEPT_LANG); 539 return (ret); 540 } 541 ret = sip_add_str_to_msg(sip_msg, SIP_ACCEPT_LANG, lang, plist, 542 SIP_SEMI); 543 return (ret); 544 } 545 546 /* 547 * Alert-Info = "Alert-Info" ":" "<" URI ">" 548 */ 549 int 550 sip_add_alert_info(sip_msg_t sip_msg, char *alert, char *plist) 551 { 552 int ret; 553 char *tmp; 554 boolean_t alloc; 555 556 if (alert == NULL) 557 return (EINVAL); 558 tmp = sip_add_aquot_to_str(alert, &alloc); 559 if (tmp == NULL) 560 return (ENOMEM); 561 ret = sip_add_str_to_msg(sip_msg, SIP_ALERT_INFO, tmp, plist, SIP_SEMI); 562 if (alloc) 563 free(tmp); 564 return (ret); 565 } 566 567 /* 568 * Allow = "Allow" ":" method-name1[, method-name2..] 569 * method-name = "INVITE" | "ACK" | "OPTIONS" | "CANCEL" | "BYE" 570 */ 571 int 572 sip_add_allow(sip_msg_t sip_msg, sip_method_t method) 573 { 574 int ret; 575 576 if (method == 0 || method >= MAX_SIP_METHODS) 577 return (EINVAL); 578 ret = sip_add_str_to_msg(sip_msg, SIP_ALLOW, sip_methods[method].name, 579 NULL, (char)NULL); 580 return (ret); 581 } 582 583 /* 584 * Call-Info = "Call-Info" HCOLON info *(COMMA info) 585 * info = LAQUOT absoluteURI RAQUOT *( SEMI info-param) 586 * info-param = ( "purpose" EQUAL ( "icon" / "info" 587 * / "card" / token ) ) / generic-param 588 */ 589 int 590 sip_add_call_info(sip_msg_t sip_msg, char *uri, char *plist) 591 { 592 char *tmp; 593 boolean_t alloc; 594 int r; 595 596 if (uri == NULL) 597 return (EINVAL); 598 tmp = sip_add_aquot_to_str(uri, &alloc); 599 if (tmp == NULL) 600 return (ENOMEM); 601 r = sip_add_str_to_msg(sip_msg, SIP_CALL_INFO, tmp, plist, SIP_SEMI); 602 if (alloc) 603 free(tmp); 604 return (r); 605 } 606 607 /* 608 * Content-Disposition = "Content-Disposition" HCOLON 609 * disp-type *( SEMI disp-param ) 610 * disp-type = "render" / "session" / "icon" / "alert" 611 * / disp-extension-token 612 * disp-param = handling-param / generic-param 613 * handling-param = "handling" EQUAL 614 * ( "optional" / "required" 615 * / other-handling ) 616 * other-handling = token 617 * disp-extension-token = token 618 */ 619 int 620 sip_add_content_disp(sip_msg_t sip_msg, char *dis_type, char *plist) 621 { 622 int ret; 623 624 if (dis_type == NULL) 625 return (EINVAL); 626 627 ret = sip_add_str_to_msg(sip_msg, SIP_CONTENT_DIS, dis_type, plist, 628 SIP_SEMI); 629 return (ret); 630 } 631 632 /* 633 * Content-Encoding = ( "Content-Encoding" / "e" ) HCOLON 634 * content-coding *(COMMA content-coding) 635 * content-coding = token 636 */ 637 int 638 sip_add_content_enc(sip_msg_t sip_msg, char *code) 639 { 640 int ret; 641 642 if (code == NULL) 643 return (EINVAL); 644 645 ret = sip_add_str_to_msg(sip_msg, SIP_CONTENT_ENCODE, code, NULL, 646 (char)NULL); 647 return (ret); 648 } 649 650 /* 651 * Content-Language = "Content-Language" HCOLON 652 * language-tag *(COMMA language-tag) 653 * language-tag = primary-tag *( "-" subtag ) 654 * primary-tag = 1*8ALPHA 655 * subtag = 1*8ALPHA 656 */ 657 int 658 sip_add_content_lang(sip_msg_t sip_msg, char *lang) 659 { 660 int ret; 661 662 if (lang == NULL) 663 return (EINVAL); 664 ret = sip_add_str_to_msg(sip_msg, SIP_CONTENT_LANG, lang, NULL, 665 (char)NULL); 666 return (ret); 667 } 668 669 /* 670 * Date = "Date" HCOLON SIP-date 671 * SIP-date = rfc1123-date 672 * rfc1123-date = wkday "," SP date1 SP time SP "GMT" 673 * date1 = 2DIGIT SP month SP 4DIGIT 674 * ; day month year (e.g., 02 Jun 1982) 675 * time = 2DIGIT ":" 2DIGIT ":" 2DIGIT 676 * ; 00:00:00 - 23:59:59 677 * wkday = "Mon" / "Tue" / "Wed" 678 * / "Thu" / "Fri" / "Sat" / "Sun" 679 * month = "Jan" / "Feb" / "Mar" / "Apr" 680 * / "May" / "Jun" / "Jul" / "Aug" 681 * / "Sep" / "Oct" / "Nov" / "Dec" 682 */ 683 int 684 sip_add_date(sip_msg_t sip_msg, char *date) 685 { 686 int ret; 687 688 if (date == NULL) 689 return (EINVAL); 690 ret = sip_add_str_to_msg(sip_msg, SIP_DATE, date, NULL, (char)NULL); 691 return (ret); 692 } 693 694 /* 695 * Error-Info = "Error-Info" HCOLON error-uri *(COMMA error-uri) 696 * error-uri = LAQUOT absoluteURI RAQUOT *( SEMI generic-param ) 697 */ 698 int 699 sip_add_error_info(sip_msg_t sip_msg, char *uri, char *plist) 700 { 701 char *tmp; 702 boolean_t alloc; 703 int r; 704 705 if (uri == NULL) 706 return (EINVAL); 707 tmp = sip_add_aquot_to_str(uri, &alloc); 708 if (tmp == NULL) 709 return (EINVAL); 710 711 r = sip_add_str_to_msg(sip_msg, SIP_ERROR_INFO, tmp, plist, SIP_SEMI); 712 if (alloc) 713 free(tmp); 714 return (r); 715 } 716 717 /* 718 * Expires = "Expires" HCOLON delta-seconds 719 * delta-seconds = 1*DIGIT 720 */ 721 int 722 sip_add_expires(sip_msg_t sip_msg, int secs) 723 { 724 int ret; 725 726 if (sip_msg == NULL || (int)secs < 0) 727 return (EINVAL); 728 729 ret = sip_add_int_to_msg(sip_msg, SIP_EXPIRE, secs, NULL); 730 return (ret); 731 } 732 733 /* 734 * In-Reply-To = "In-Reply-To" HCOLON callid *(COMMA callid) 735 * callid = word [ "@" word ] 736 */ 737 int 738 sip_add_in_reply_to(sip_msg_t sip_msg, char *reply_id) 739 { 740 int r; 741 742 if (reply_id == NULL) 743 return (EINVAL); 744 r = sip_add_str_to_msg(sip_msg, SIP_IN_REPLY_TO, reply_id, NULL, 745 (char)NULL); 746 return (r); 747 } 748 749 /* 750 * RSeq = "RSeq" HCOLON response-num 751 */ 752 int 753 sip_add_rseq(sip_msg_t sip_msg, int resp_num) 754 { 755 int ret; 756 757 if (sip_msg == NULL || resp_num <= 0) 758 return (EINVAL); 759 ret = sip_add_int_to_msg(sip_msg, SIP_RSEQ, resp_num, NULL); 760 return (ret); 761 } 762 763 /* 764 * Min-Expires = "Min-Expires" HCOLON delta-seconds 765 */ 766 int 767 sip_add_min_expires(sip_msg_t sip_msg, int secs) 768 { 769 int ret; 770 771 if (sip_msg == NULL || (int)secs < 0) 772 return (EINVAL); 773 ret = sip_add_int_to_msg(sip_msg, SIP_MIN_EXPIRE, secs, NULL); 774 return (ret); 775 } 776 777 /* 778 * MIME-Version = "MIME-Version" HCOLON 1*DIGIT "." 1*DIGIT 779 */ 780 int 781 sip_add_mime_version(sip_msg_t sip_msg, char *version) 782 { 783 int ret; 784 785 if (version == NULL) 786 return (EINVAL); 787 ret = sip_add_str_to_msg(sip_msg, SIP_MIME_VERSION, version, NULL, 788 (char)NULL); 789 return (ret); 790 } 791 792 /* 793 * Organization = "Organization" HCOLON [TEXT-UTF8-TRIM] 794 */ 795 int 796 sip_add_org(sip_msg_t sip_msg, char *org) 797 { 798 int ret; 799 800 if (org == NULL) { 801 ret = sip_add_empty_hdr(sip_msg, SIP_ORGANIZATION); 802 } else { 803 ret = sip_add_str_to_msg(sip_msg, SIP_ORGANIZATION, org, NULL, 804 (char)NULL); 805 } 806 return (ret); 807 } 808 809 /* 810 * Priority = "Priority" HCOLON priority-value 811 * priority-value = "emergency" / "urgent" / "normal" 812 * / "non-urgent" / other-priority 813 * other-priority = token 814 */ 815 int 816 sip_add_priority(sip_msg_t sip_msg, char *prio) 817 { 818 int ret; 819 820 if (prio == NULL) 821 return (EINVAL); 822 ret = sip_add_str_to_msg(sip_msg, SIP_PRIORITY, prio, NULL, (char)NULL); 823 824 return (ret); 825 } 826 827 /* 828 * Reply-To = "Reply-To" HCOLON rplyto-spec 829 * rplyto-spec = ( name-addr / addr-spec ) 830 * *( SEMI rplyto-param ) 831 * rplyto-param = generic-param 832 */ 833 int 834 sip_add_reply_to(sip_msg_t sip_msg, char *uname, char *addr, char *plist, 835 boolean_t add_aquot) 836 { 837 return (sip_add_name_aspec(sip_msg, uname, addr, NULL, add_aquot, 838 SIP_REPLYTO, plist)); 839 } 840 841 842 /* 843 * Privacy-hdr = "Privacy" HCOLON priv-value *(";" priv-value) 844 * priv-value = "header" / "session" / "user" / "none" / "critical" 845 * / token 846 */ 847 int 848 sip_add_privacy(sip_msg_t sip_msg, char *priv_val) 849 { 850 int ret; 851 852 if (priv_val == NULL) 853 return (EINVAL); 854 ret = sip_add_str_to_msg(sip_msg, SIP_PRIVACY, priv_val, NULL, 855 (char)NULL); 856 return (ret); 857 } 858 859 /* 860 * Require = "Require" HCOLON option-tag *(COMMA option-tag) 861 * option-tag = token 862 */ 863 int 864 sip_add_require(sip_msg_t sip_msg, char *req) 865 { 866 int ret; 867 868 if (req == NULL) 869 return (EINVAL); 870 ret = sip_add_str_to_msg(sip_msg, SIP_REQUIRE, req, NULL, (char)NULL); 871 return (ret); 872 } 873 874 /* 875 * Retry-After = "Retry-After" HCOLON delta-seconds 876 * [ comment ] *( SEMI retry-param ) 877 * retry-param = ("duration" EQUAL delta-seconds) 878 * / generic-param 879 */ 880 int 881 sip_add_retry_after(sip_msg_t sip_msg, int secs, char *cmt, char *plist) 882 { 883 int r; 884 885 if (secs <= 0) 886 return (EINVAL); 887 888 if (cmt == NULL) { 889 r = sip_add_int_to_msg(sip_msg, SIP_RETRY_AFTER, secs, plist); 890 return (r); 891 } 892 893 r = sip_add_intstr_to_msg(sip_msg, SIP_RETRY_AFTER, secs, cmt, plist); 894 return (r); 895 } 896 897 /* 898 * Server = "Server" HCOLON server-val *(LWS server-val) 899 * server-val = product / comment 900 * product = token [SLASH product-version] 901 * product-version = token 902 */ 903 int 904 sip_add_server(sip_msg_t sip_msg, char *svr) 905 { 906 int ret; 907 908 if (svr == NULL) 909 return (EINVAL); 910 ret = sip_add_str_to_msg(sip_msg, SIP_SERVER, svr, NULL, (char)NULL); 911 return (ret); 912 } 913 914 /* 915 * Subject = ( "Subject" / "s" ) HCOLON [TEXT-UTF8-TRIM] 916 */ 917 int 918 sip_add_subject(sip_msg_t sip_msg, char *subject) 919 { 920 int ret; 921 922 if (subject == NULL) { 923 ret = sip_add_empty_hdr(sip_msg, SIP_SUBJECT); 924 } else { 925 ret = sip_add_str_to_msg(sip_msg, SIP_SUBJECT, subject, NULL, 926 (char)NULL); 927 } 928 return (ret); 929 } 930 931 /* 932 * Supported = ( "Supported" / "k" ) HCOLON 933 * [option-tag *(COMMA option-tag)] 934 */ 935 int 936 sip_add_supported(sip_msg_t sip_msg, char *support) 937 { 938 int ret; 939 940 if (support == NULL) { 941 ret = sip_add_empty_hdr(sip_msg, SIP_SUPPORT); 942 } else { 943 ret = sip_add_str_to_msg(sip_msg, SIP_SUPPORT, support, NULL, 944 (char)NULL); 945 } 946 return (ret); 947 } 948 949 /* 950 * Timestamp = "Timestamp" HCOLON 1*(DIGIT) 951 * [ "." *(DIGIT) ] [ LWS delay ] 952 * delay = *(DIGIT) [ "." *(DIGIT) ] 953 */ 954 int 955 sip_add_tstamp(sip_msg_t sip_msg, char *time, char *delay) 956 { 957 int ret; 958 959 if (delay == NULL) { 960 ret = sip_add_str_to_msg(sip_msg, SIP_TIMESTAMP, time, NULL, 961 (char)NULL); 962 } else { 963 ret = sip_add_2strs_to_msg(sip_msg, SIP_TIMESTAMP, time, 964 B_FALSE, delay, NULL, ' '); 965 } 966 return (ret); 967 } 968 969 /* 970 * Unsupported = "Unsupported" HCOLON option-tag *(COMMA option-tag) 971 */ 972 int 973 sip_add_unsupported(sip_msg_t sip_msg, char *unsupport) 974 { 975 int ret; 976 977 if (unsupport == NULL) 978 return (EINVAL); 979 ret = sip_add_str_to_msg(sip_msg, SIP_UNSUPPORT, unsupport, NULL, 980 (char)NULL); 981 return (ret); 982 } 983 984 /* 985 * User-Agent = "User-Agent" HCOLON server-val *(LWS server-val) 986 */ 987 int 988 sip_add_user_agent(sip_msg_t sip_msg, char *usr) 989 { 990 int r; 991 992 if (usr == NULL) 993 return (EINVAL); 994 r = sip_add_str_to_msg(sip_msg, SIP_USER_AGENT, usr, NULL, (char)NULL); 995 return (r); 996 } 997 998 /* 999 * Warning = "Warning" HCOLON warning-value *(COMMA warning-value) 1000 * warning-value = warn-code SP warn-agent SP warn-text 1001 * warn-code = 3DIGIT 1002 * warn-agent = hostport / pseudonym 1003 * ; the name or pseudonym of the server adding 1004 * ; the Warning header, for use in debugging 1005 * warn-text = quoted-string 1006 * pseudonym = token 1007 */ 1008 int 1009 sip_add_warning(sip_msg_t sip_msg, int code, char *addr, char *msg) 1010 { 1011 _sip_header_t *new_header; 1012 int header_size; 1013 _sip_msg_t *_sip_msg; 1014 char *hdr_name = SIP_WARNING; 1015 1016 if (sip_msg == NULL || addr == NULL || msg == NULL || 1017 addr[0] == '\0' || msg == '\0' || code < 100 || code > 999) { 1018 return (EINVAL); 1019 } 1020 1021 _sip_msg = (_sip_msg_t *)sip_msg; 1022 (void) pthread_mutex_lock(&_sip_msg->sip_msg_mutex); 1023 if (_sip_msg->sip_msg_cannot_be_modified) { 1024 (void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex); 1025 return (ENOTSUP); 1026 } 1027 1028 header_size = strlen(hdr_name) + SIP_SPACE_LEN + sizeof (char) + 1029 SIP_SPACE_LEN + sip_num_of_digits(code) + SIP_SPACE_LEN + 1030 strlen(addr) + SIP_SPACE_LEN + sizeof (char) + strlen(msg) + 1031 sizeof (char) + strlen(SIP_CRLF); 1032 1033 new_header = sip_new_header(header_size); 1034 if (new_header == NULL) { 1035 (void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex); 1036 return (ENOMEM); 1037 } 1038 1039 (void) snprintf(new_header->sip_hdr_start, header_size + 1, 1040 "%s %c %d %s \"%s\"%s", hdr_name, SIP_HCOLON, code, addr, 1041 msg, SIP_CRLF); 1042 _sip_add_header(_sip_msg, new_header, B_TRUE, B_FALSE, NULL); 1043 if (_sip_msg->sip_msg_buf != NULL) 1044 _sip_msg->sip_msg_modified = B_TRUE; 1045 (void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex); 1046 1047 return (0); 1048 } 1049 1050 /* 1051 * RAck = "RAck" HCOLON response-num LWS CSeq-num LWS Method 1052 * response-num = 1*DIGIT 1053 * CSeq-num = 1*DIGIT 1054 */ 1055 int 1056 sip_add_rack(sip_msg_t sip_msg, int resp_num, int cseq, sip_method_t method) 1057 { 1058 _sip_header_t *new_header; 1059 int header_size; 1060 _sip_msg_t *_sip_msg; 1061 char *hdr_name = SIP_RACK; 1062 1063 if (sip_msg == NULL || resp_num <= 0 || cseq < 0 || method <= 0 || 1064 method >= MAX_SIP_METHODS) { 1065 return (EINVAL); 1066 } 1067 1068 _sip_msg = (_sip_msg_t *)sip_msg; 1069 (void) pthread_mutex_lock(&_sip_msg->sip_msg_mutex); 1070 if (_sip_msg->sip_msg_cannot_be_modified) { 1071 (void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex); 1072 return (ENOTSUP); 1073 } 1074 1075 header_size = strlen(hdr_name) + SIP_SPACE_LEN + sizeof (char) + 1076 SIP_SPACE_LEN + sip_num_of_digits(resp_num) + SIP_SPACE_LEN + 1077 sip_num_of_digits(cseq) + SIP_SPACE_LEN + 1078 strlen(sip_methods[method].name) + strlen(SIP_CRLF); 1079 1080 new_header = sip_new_header(header_size); 1081 if (new_header == NULL) { 1082 (void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex); 1083 return (ENOMEM); 1084 } 1085 1086 (void) snprintf(new_header->sip_hdr_start, header_size + 1, 1087 "%s %c %d %d %s%s", hdr_name, SIP_HCOLON, resp_num, cseq, 1088 sip_methods[method].name, SIP_CRLF); 1089 1090 _sip_add_header(_sip_msg, new_header, B_TRUE, B_FALSE, NULL); 1091 if (_sip_msg->sip_msg_buf != NULL) 1092 _sip_msg->sip_msg_modified = B_TRUE; 1093 (void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex); 1094 1095 return (0); 1096 1097 } 1098 1099 /* 1100 * Allow-Events = ( "Allow-Events" / "u" ) HCOLON event-type 1101 * *(COMMA event-type) 1102 */ 1103 int 1104 sip_add_allow_events(sip_msg_t sip_msg, char *t_event) 1105 { 1106 return (sip_add_str_to_msg(sip_msg, SIP_ALLOW_EVENTS, t_event, NULL, 1107 (char)NULL)); 1108 } 1109 1110 /* 1111 * Event = ( "Event" / "o" ) HCOLON event-type 1112 * *( SEMI event-param ) 1113 * event-type = event-package *( "." event-template ) 1114 * event-package = token-nodot 1115 * event-template = token-nodot 1116 * token-nodot = 1*( alphanum / "-" / "!" / "%" / "*" 1117 * / "_" / "+" / "`" / "'" / "~" ) 1118 * event-param = generic-param / ( "id" EQUAL token ) 1119 */ 1120 int 1121 sip_add_event(sip_msg_t sip_msg, char *t_event, char *plist) 1122 { 1123 return (sip_add_str_to_msg(sip_msg, SIP_EVENT, t_event, plist, 1124 SIP_SEMI)); 1125 } 1126 1127 /* 1128 * Subscription-State = "Subscription-State" HCOLON substate-value 1129 * *( SEMI subexp-params ) 1130 * substate-value = "active" / "pending" / "terminated" 1131 * / extension-substate 1132 * extension-substate = token 1133 * subexp-params = ("reason" EQUAL event-reason-value) 1134 * / ("expires" EQUAL delta-seconds)* 1135 * / ("retry-after" EQUAL delta-seconds) 1136 * / generic-param 1137 * event-reason-value = "deactivated" 1138 * / "probation" 1139 * / "rejected" 1140 * / "timeout" 1141 * / "giveup" 1142 * / "noresource" 1143 * / event-reason-extension 1144 * event-reason-extension = token 1145 */ 1146 int 1147 sip_add_substate(sip_msg_t sip_msg, char *sub, char *plist) 1148 { 1149 return (sip_add_str_to_msg(sip_msg, SIP_SUBSCRIPTION_STATE, sub, plist, 1150 SIP_SEMI)); 1151 } 1152 1153 /* 1154 * Authorization = "Authorization" HCOLON credentials 1155 * credentials = ("Digest" LWS digest-response) 1156 * / other-response 1157 * digest-response = dig-resp *(COMMA dig-resp) 1158 * dig-resp = username / realm / nonce / digest-uri 1159 * / dresponse / algorithm / cnonce 1160 * / opaque / message-qop 1161 * / nonce-count / auth-param 1162 * username = "username" EQUAL username-value 1163 * username-value = quoted-string 1164 * digest-uri = "uri" EQUAL LDQUOT digest-uri-value RDQUOT 1165 * digest-uri-value = rquest-uri ; Equal to request-uri as specified 1166 * by HTTP/1.1 1167 * message-qop = "qop" EQUAL qop-value 1168 * cnonce = "cnonce" EQUAL cnonce-value 1169 * cnonce-value = nonce-value 1170 * nonce-count = "nc" EQUAL nc-value 1171 * nc-value = 8LHEX 1172 * dresponse = "response" EQUAL request-digest 1173 * request-digest = LDQUOT 32LHEX RDQUOT 1174 * auth-param = auth-param-name EQUAL 1175 * ( token / quoted-string ) 1176 * auth-param-name = token 1177 * other-response = auth-scheme LWS auth-param 1178 * *(COMMA auth-param) 1179 * auth-scheme = token 1180 */ 1181 int 1182 sip_add_author(sip_msg_t sip_msg, char *scheme, char *param) 1183 { 1184 return (sip_add_str_to_msg(sip_msg, SIP_AUTHOR, scheme, param, SIP_SP)); 1185 } 1186 1187 /* 1188 * Authentication-Info = "Authentication-Info" HCOLON ainfo 1189 * *(COMMA ainfo) 1190 * ainfo = nextnonce / message-qop 1191 * / response-auth / cnonce 1192 * / nonce-count 1193 * nextnonce = "nextnonce" EQUAL nonce-value 1194 * response-auth = "rspauth" EQUAL response-digest 1195 * response-digest = LDQUOT *LHEX RDQUOT 1196 */ 1197 int 1198 sip_add_authen_info(sip_msg_t sip_msg, char *ainfo) 1199 { 1200 return (sip_add_str_to_msg(sip_msg, SIP_AUTHEN_INFO, ainfo, NULL, 1201 (char)NULL)); 1202 } 1203 1204 /* 1205 * Proxy-Authenticate = "Proxy-Authenticate" HCOLON challenge 1206 * challenge = ("Digest" LWS digest-cln *(COMMA digest-cln)) 1207 * / other-challenge 1208 * other-challenge = auth-scheme LWS auth-param 1209 * *(COMMA auth-param) 1210 * digest-cln = realm / domain / nonce 1211 * / opaque / stale / algorithm 1212 * / qop-options / auth-param 1213 * realm = "realm" EQUAL realm-value 1214 * realm-value = quoted-string 1215 * domain = "domain" EQUAL LDQUOT URI 1216 * *( 1*SP URI ) RDQUOT 1217 * URI = absoluteURI / abs-path 1218 * nonce = "nonce" EQUAL nonce-value 1219 * nonce-value = quoted-string 1220 * opaque = "opaque" EQUAL quoted-string 1221 * stale = "stale" EQUAL ( "true" / "false" ) 1222 * algorithm = "algorithm" EQUAL ( "MD5" / "MD5-sess" 1223 * / token ) 1224 * qop-options = "qop" EQUAL LDQUOT qop-value 1225 * *("," qop-value) RDQUOT 1226 * qop-value = "auth" / "auth-int" / token 1227 */ 1228 int 1229 sip_add_proxy_authen(sip_msg_t sip_msg, char *pascheme, char *paparam) 1230 { 1231 return (sip_add_str_to_msg(sip_msg, SIP_PROXY_AUTHEN, pascheme, paparam, 1232 SIP_SP)); 1233 } 1234 1235 /* 1236 * Proxy-Authorization = "Proxy-Authorization" HCOLON credentials 1237 */ 1238 int 1239 sip_add_proxy_author(sip_msg_t sip_msg, char *paschem, char *paparam) 1240 { 1241 return (sip_add_str_to_msg(sip_msg, SIP_PROXY_AUTHOR, paschem, paparam, 1242 SIP_SP)); 1243 } 1244 1245 /* 1246 * Proxy-Require = "Proxy-Require" HCOLON option-tag 1247 * *(COMMA option-tag) 1248 * option-tag = token 1249 */ 1250 int 1251 sip_add_proxy_require(sip_msg_t sip_msg, char *opt) 1252 { 1253 return (sip_add_str_to_msg(sip_msg, SIP_PROXY_REQ, opt, NULL, 1254 (char)NULL)); 1255 } 1256 1257 /* 1258 * WWW-Authenticate = "WWW-Authenticate" HCOLON challenge 1259 * extension-header = header-name HCOLON header-value 1260 * header-name = token 1261 * header-value = *(TEXT-UTF8char / UTF8-CONT / LWS) 1262 * message-body = *OCTET 1263 */ 1264 int 1265 sip_add_www_authen(sip_msg_t sip_msg, char *wascheme, char *waparam) 1266 { 1267 return (sip_add_str_to_msg(sip_msg, SIP_WWW_AUTHEN, wascheme, waparam, 1268 SIP_SP)); 1269 } 1270 1271 /* 1272 * Call-ID = ( "Call-ID" / "i" ) HCOLON callid 1273 */ 1274 int 1275 sip_add_callid(sip_msg_t sip_msg, char *callid) 1276 { 1277 int ret; 1278 boolean_t allocd = B_FALSE; 1279 1280 if (sip_msg == NULL || (callid != NULL && callid[0] == '\0')) 1281 return (EINVAL); 1282 if (callid == NULL) { 1283 callid = (char *)sip_guid(); 1284 if (callid == NULL) 1285 return (ENOMEM); 1286 allocd = B_TRUE; 1287 } 1288 ret = sip_add_str_to_msg(sip_msg, SIP_CALL_ID, callid, NULL, 1289 (char)NULL); 1290 if (allocd) 1291 free(callid); 1292 return (ret); 1293 } 1294 1295 /* 1296 * CSeq = "CSeq" HCOLON 1*DIGIT LWS Method 1297 */ 1298 int 1299 sip_add_cseq(sip_msg_t sip_msg, sip_method_t method, uint32_t cseq) 1300 { 1301 int r; 1302 1303 if (sip_msg == NULL || (int)cseq < 0 || method == 0 || 1304 method >= MAX_SIP_METHODS) { 1305 return (EINVAL); 1306 } 1307 r = sip_add_intstr_to_msg(sip_msg, SIP_CSEQ, cseq, 1308 sip_methods[method].name, NULL); 1309 return (r); 1310 } 1311 1312 /* 1313 * Via = ( "Via" / "v" ) HCOLON via-parm *(COMMA via-parm) 1314 * via-parm = sent-protocol LWS sent-by *( SEMI via-params ) 1315 * via-params = via-ttl / via-maddr 1316 * / via-received / via-branch 1317 * / via-extension 1318 * via-ttl = "ttl" EQUAL ttl 1319 * via-maddr = "maddr" EQUAL host 1320 * via-received = "received" EQUAL (IPv4address / IPv6address) 1321 * via-branch = "branch" EQUAL token 1322 * via-extension = generic-param 1323 * sent-protocol = protocol-name SLASH protocol-version 1324 * SLASH transport 1325 * protocol-name = "SIP" / token 1326 * protocol-version = token 1327 * transport = "UDP" / "TCP" / "TLS" / "SCTP" 1328 * / other-transport 1329 * sent-by = host [ COLON port ] 1330 * ttl = 1*3DIGIT ; 0 to 255 1331 */ 1332 _sip_header_t * 1333 sip_create_via_hdr(char *sent_protocol_transport, char *sent_by_host, 1334 int sent_by_port, char *via_params) 1335 { 1336 _sip_header_t *new_header; 1337 int header_size; 1338 int count; 1339 1340 header_size = strlen(SIP_VIA) + SIP_SPACE_LEN + sizeof (char) + 1341 SIP_SPACE_LEN + strlen(SIP_VERSION) + sizeof (char) + 1342 strlen(sent_protocol_transport) + SIP_SPACE_LEN + 1343 strlen(sent_by_host) + strlen(SIP_CRLF); 1344 1345 if (sent_by_port > 0) { 1346 header_size += SIP_SPACE_LEN + sizeof (char) + SIP_SPACE_LEN + 1347 sip_num_of_digits(sent_by_port); 1348 } 1349 1350 if (via_params != NULL) { 1351 header_size += SIP_SPACE_LEN + sizeof (char) + 1352 strlen(via_params); 1353 } 1354 new_header = sip_new_header(header_size); 1355 if (new_header->sip_hdr_start == NULL) 1356 return (NULL); 1357 count = snprintf(new_header->sip_hdr_current, header_size + 1, 1358 "%s %c %s/%s %s", 1359 SIP_VIA, SIP_HCOLON, SIP_VERSION, sent_protocol_transport, 1360 sent_by_host); 1361 new_header->sip_hdr_current += count; 1362 header_size -= count; 1363 1364 if (sent_by_port > 0) { 1365 count = snprintf(new_header->sip_hdr_current, header_size + 1, 1366 " %c %d", SIP_HCOLON, sent_by_port); 1367 new_header->sip_hdr_current += count; 1368 header_size -= count; 1369 } 1370 1371 if (via_params != NULL) { 1372 count = snprintf(new_header->sip_hdr_current, header_size + 1, 1373 " %c%s", SIP_SEMI, via_params); 1374 new_header->sip_hdr_current += count; 1375 header_size -= count; 1376 } 1377 1378 (void) snprintf(new_header->sip_hdr_current, header_size + 1, 1379 "%s", SIP_CRLF); 1380 return (new_header); 1381 } 1382 1383 /* 1384 * There can be multiple via headers we always append the header. 1385 * We expect the via params to be a semi-colon separated list of parameters. 1386 * We will add a semi-clone, before adding the list to the header. 1387 */ 1388 int 1389 sip_add_via(sip_msg_t sip_msg, char *sent_protocol_transport, 1390 char *sent_by_host, int sent_by_port, char *via_params) 1391 { 1392 _sip_header_t *new_header; 1393 _sip_msg_t *_sip_msg; 1394 1395 if (sip_msg == NULL || sent_protocol_transport == NULL || 1396 sent_by_host == NULL || sent_by_port < 0) { 1397 return (EINVAL); 1398 } 1399 1400 _sip_msg = (_sip_msg_t *)sip_msg; 1401 (void) pthread_mutex_lock(&_sip_msg->sip_msg_mutex); 1402 if (_sip_msg->sip_msg_cannot_be_modified) { 1403 (void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex); 1404 return (ENOTSUP); 1405 } 1406 1407 new_header = sip_create_via_hdr(sent_protocol_transport, sent_by_host, 1408 sent_by_port, via_params); 1409 if (new_header == NULL) { 1410 (void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex); 1411 return (ENOMEM); 1412 } 1413 _sip_add_header(_sip_msg, new_header, B_TRUE, B_FALSE, NULL); 1414 if (_sip_msg->sip_msg_buf != NULL) 1415 _sip_msg->sip_msg_modified = B_TRUE; 1416 (void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex); 1417 return (0); 1418 } 1419 1420 /* 1421 * Max-Forwards = "Max-Forwards" HCOLON 1*DIGIT 1422 */ 1423 int 1424 sip_add_maxforward(sip_msg_t sip_msg, uint_t maxforward) 1425 { 1426 if (sip_msg == NULL || (int)maxforward < 0) 1427 return (EINVAL); 1428 return (sip_add_int_to_msg(sip_msg, SIP_MAX_FORWARDS, maxforward, 1429 NULL)); 1430 } 1431 1432 /* 1433 * Content-Type = ( "Content-Type" / "c" ) HCOLON media-type 1434 * media-type = m-type SLASH m-subtype *(SEMI m-parameter) 1435 * m-type = discrete-type / composite-type 1436 * discrete-type = "text" / "image" / "audio" / "video" 1437 * / "application" / extension-token 1438 * composite-type = "message" / "multipart" / extension-token 1439 * extension-token = ietf-token / x-token 1440 * ietf-token = token 1441 * x-token = "x-" token 1442 * m-subtype = extension-token / iana-token 1443 * iana-token = token 1444 * m-parameter = m-attribute EQUAL m-value 1445 * m-attribute = token 1446 * m-value = token / quoted-string 1447 */ 1448 int 1449 sip_add_content_type(sip_msg_t sip_msg, char *type, char *subtype) 1450 { 1451 if (sip_msg == NULL || type == NULL || subtype == NULL) 1452 return (EINVAL); 1453 return (sip_add_2strs_to_msg(sip_msg, SIP_CONTENT_TYPE, type, B_FALSE, 1454 subtype, NULL, SIP_SLASH)); 1455 } 1456 1457 /* 1458 * Content-Length = ( "Content-Length" / "l" ) HCOLON 1*DIGIT 1459 */ 1460 int 1461 sip_add_content_length(_sip_msg_t *_sip_msg, int length) 1462 { 1463 _sip_header_t *new_header; 1464 int header_size; 1465 1466 if (_sip_msg == NULL || length < 0) 1467 return (EINVAL); 1468 (void) pthread_mutex_lock(&_sip_msg->sip_msg_mutex); 1469 if (_sip_msg->sip_msg_cannot_be_modified) { 1470 (void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex); 1471 return (ENOTSUP); 1472 } 1473 1474 header_size = strlen(SIP_CONTENT_LENGTH) + SIP_SPACE_LEN + 1475 sizeof (char) + SIP_SPACE_LEN + sip_num_of_digits(length) + 1476 strlen(SIP_CRLF) + strlen(SIP_CRLF); 1477 1478 new_header = sip_new_header(header_size); 1479 if (new_header == NULL) { 1480 (void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex); 1481 return (ENOMEM); 1482 } 1483 (void) snprintf(new_header->sip_hdr_start, header_size + 1, 1484 "%s %c %u%s%s", SIP_CONTENT_LENGTH, SIP_HCOLON, length, 1485 SIP_CRLF, SIP_CRLF); 1486 1487 _sip_add_header(_sip_msg, new_header, B_TRUE, B_FALSE, NULL); 1488 if (_sip_msg->sip_msg_buf != NULL) 1489 _sip_msg->sip_msg_modified = B_TRUE; 1490 (void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex); 1491 return (0); 1492 } 1493 1494 1495 /* 1496 * Contact = ("Contact" / "m" ) HCOLON 1497 * ( STAR / (contact-param *(COMMA contact-param))) 1498 * contact-param = (name-addr / addr-spec) *(SEMI contact-params) 1499 * name-addr = [ display-name ] LAQUOT addr-spec RAQUOT 1500 * addr-spec = SIP-URI / SIPS-URI / absoluteURI 1501 * display-name = *(token LWS)/ quoted-string 1502 * contact-params = c-p-q / c-p-expires 1503 * / contact-extension 1504 */ 1505 int 1506 sip_add_contact(sip_msg_t sip_msg, char *display_name, char *contact_uri, 1507 boolean_t add_aquot, char *contact_params) 1508 { 1509 return (sip_add_name_aspec(sip_msg, display_name, contact_uri, NULL, 1510 add_aquot, SIP_CONTACT, contact_params)); 1511 } 1512 1513 /* 1514 * From = ( "From" / "f" ) HCOLON from-spec 1515 * from-spec = ( name-addr / addr-spec ) 1516 * *( SEMI from-param ) 1517 * from-param = tag-param / generic-param 1518 * tag-param = "tag" EQUAL token 1519 * 1520 * Since there can be more than one tags, fromtags is a semi colon separated 1521 * list of tags. 1522 */ 1523 int 1524 sip_add_from(sip_msg_t sip_msg, char *display_name, char *from_uri, 1525 char *fromtags, boolean_t add_aquot, char *from_params) 1526 { 1527 return (sip_add_name_aspec(sip_msg, display_name, from_uri, fromtags, 1528 add_aquot, SIP_FROM, from_params)); 1529 } 1530 1531 /* 1532 * To = ( "To" / "t" ) HCOLON ( name-addr 1533 * / addr-spec ) *( SEMI to-param ) 1534 * to-param = tag-param / generic-param 1535 */ 1536 int 1537 sip_add_to(sip_msg_t sip_msg, char *display_name, char *to_uri, 1538 char *totags, boolean_t add_aquot, char *to_params) 1539 { 1540 return (sip_add_name_aspec(sip_msg, display_name, to_uri, totags, 1541 add_aquot, SIP_TO, to_params)); 1542 } 1543 1544 /* 1545 * Route = "Route" HCOLON route-param *(COMMA route-param) 1546 * route-param = name-addr *( SEMI rr-param ) 1547 */ 1548 int 1549 sip_add_route(sip_msg_t sip_msg, char *display_name, char *uri, 1550 char *route_params) 1551 { 1552 return (sip_add_name_aspec(sip_msg, display_name, uri, NULL, B_TRUE, 1553 SIP_ROUTE, route_params)); 1554 } 1555 1556 /* 1557 * Record-Route = "Record-Route" HCOLON rec-route *(COMMA rec-route) 1558 * rec-route = name-addr *( SEMI rr-param ) 1559 * rr-param = generic-param 1560 */ 1561 int 1562 sip_add_record_route(sip_msg_t sip_msg, char *display_name, char *uri, 1563 char *route_params) 1564 { 1565 return (sip_add_name_aspec(sip_msg, display_name, uri, NULL, B_TRUE, 1566 SIP_RECORD_ROUTE, route_params)); 1567 } 1568 1569 1570 /* 1571 * PAssertedID = "P-Asserted-Identity" HCOLON PAssertedID-value 1572 * *(COMMA PAssertedID-value) 1573 * PAssertedID-value = name-addr / addr-spec 1574 */ 1575 int 1576 sip_add_passertedid(sip_msg_t sip_msg, char *display_name, char *addr, 1577 boolean_t add_aquot) 1578 { 1579 return (sip_add_name_aspec(sip_msg, display_name, addr, NULL, add_aquot, 1580 SIP_PASSERTEDID, NULL)); 1581 } 1582 1583 /* 1584 * PPreferredID = "P-Preferred-Identity" HCOLON PPreferredID-value 1585 * *(COMMA PPreferredID-value) 1586 * PPreferredID-value = name-addr / addr-spec 1587 */ 1588 int 1589 sip_add_ppreferredid(sip_msg_t sip_msg, char *display_name, char *addr, 1590 boolean_t add_aquot) 1591 { 1592 return (sip_add_name_aspec(sip_msg, display_name, addr, NULL, add_aquot, 1593 SIP_PPREFERREDID, NULL)); 1594 } 1595