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