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, (char)NULL); 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, 650 (char)NULL); 651 return (ret); 652 } 653 654 /* 655 * Content-Language = "Content-Language" HCOLON 656 * language-tag *(COMMA language-tag) 657 * language-tag = primary-tag *( "-" subtag ) 658 * primary-tag = 1*8ALPHA 659 * subtag = 1*8ALPHA 660 */ 661 int 662 sip_add_content_lang(sip_msg_t sip_msg, char *lang) 663 { 664 int ret; 665 666 if (lang == NULL) 667 return (EINVAL); 668 ret = sip_add_str_to_msg(sip_msg, SIP_CONTENT_LANG, lang, NULL, 669 (char)NULL); 670 return (ret); 671 } 672 673 /* 674 * Date = "Date" HCOLON SIP-date 675 * SIP-date = rfc1123-date 676 * rfc1123-date = wkday "," SP date1 SP time SP "GMT" 677 * date1 = 2DIGIT SP month SP 4DIGIT 678 * ; day month year (e.g., 02 Jun 1982) 679 * time = 2DIGIT ":" 2DIGIT ":" 2DIGIT 680 * ; 00:00:00 - 23:59:59 681 * wkday = "Mon" / "Tue" / "Wed" 682 * / "Thu" / "Fri" / "Sat" / "Sun" 683 * month = "Jan" / "Feb" / "Mar" / "Apr" 684 * / "May" / "Jun" / "Jul" / "Aug" 685 * / "Sep" / "Oct" / "Nov" / "Dec" 686 */ 687 int 688 sip_add_date(sip_msg_t sip_msg, char *date) 689 { 690 int ret; 691 692 if (date == NULL) 693 return (EINVAL); 694 ret = sip_add_str_to_msg(sip_msg, SIP_DATE, date, NULL, (char)NULL); 695 return (ret); 696 } 697 698 /* 699 * Error-Info = "Error-Info" HCOLON error-uri *(COMMA error-uri) 700 * error-uri = LAQUOT absoluteURI RAQUOT *( SEMI generic-param ) 701 */ 702 int 703 sip_add_error_info(sip_msg_t sip_msg, char *uri, char *plist) 704 { 705 char *tmp; 706 boolean_t alloc; 707 int r; 708 709 if (uri == NULL) 710 return (EINVAL); 711 tmp = sip_add_aquot_to_str(uri, &alloc); 712 if (tmp == NULL) 713 return (EINVAL); 714 715 r = sip_add_str_to_msg(sip_msg, SIP_ERROR_INFO, tmp, plist, SIP_SEMI); 716 if (alloc) 717 free(tmp); 718 return (r); 719 } 720 721 /* 722 * Expires = "Expires" HCOLON delta-seconds 723 * delta-seconds = 1*DIGIT 724 */ 725 int 726 sip_add_expires(sip_msg_t sip_msg, int secs) 727 { 728 int ret; 729 730 if (sip_msg == NULL || (int)secs < 0) 731 return (EINVAL); 732 733 ret = sip_add_int_to_msg(sip_msg, SIP_EXPIRE, secs, NULL); 734 return (ret); 735 } 736 737 /* 738 * In-Reply-To = "In-Reply-To" HCOLON callid *(COMMA callid) 739 * callid = word [ "@" word ] 740 */ 741 int 742 sip_add_in_reply_to(sip_msg_t sip_msg, char *reply_id) 743 { 744 int r; 745 746 if (reply_id == NULL) 747 return (EINVAL); 748 r = sip_add_str_to_msg(sip_msg, SIP_IN_REPLY_TO, reply_id, NULL, 749 (char)NULL); 750 return (r); 751 } 752 753 /* 754 * RSeq = "RSeq" HCOLON response-num 755 */ 756 int 757 sip_add_rseq(sip_msg_t sip_msg, int resp_num) 758 { 759 int ret; 760 761 if (sip_msg == NULL || resp_num <= 0) 762 return (EINVAL); 763 ret = sip_add_int_to_msg(sip_msg, SIP_RSEQ, resp_num, NULL); 764 return (ret); 765 } 766 767 /* 768 * Min-Expires = "Min-Expires" HCOLON delta-seconds 769 */ 770 int 771 sip_add_min_expires(sip_msg_t sip_msg, int secs) 772 { 773 int ret; 774 775 if (sip_msg == NULL || (int)secs < 0) 776 return (EINVAL); 777 ret = sip_add_int_to_msg(sip_msg, SIP_MIN_EXPIRE, secs, NULL); 778 return (ret); 779 } 780 781 /* 782 * MIME-Version = "MIME-Version" HCOLON 1*DIGIT "." 1*DIGIT 783 */ 784 int 785 sip_add_mime_version(sip_msg_t sip_msg, char *version) 786 { 787 int ret; 788 789 if (version == NULL) 790 return (EINVAL); 791 ret = sip_add_str_to_msg(sip_msg, SIP_MIME_VERSION, version, NULL, 792 (char)NULL); 793 return (ret); 794 } 795 796 /* 797 * Organization = "Organization" HCOLON [TEXT-UTF8-TRIM] 798 */ 799 int 800 sip_add_org(sip_msg_t sip_msg, char *org) 801 { 802 int ret; 803 804 if (org == NULL) { 805 ret = sip_add_empty_hdr(sip_msg, SIP_ORGANIZATION); 806 } else { 807 ret = sip_add_str_to_msg(sip_msg, SIP_ORGANIZATION, org, NULL, 808 (char)NULL); 809 } 810 return (ret); 811 } 812 813 /* 814 * Priority = "Priority" HCOLON priority-value 815 * priority-value = "emergency" / "urgent" / "normal" 816 * / "non-urgent" / other-priority 817 * other-priority = token 818 */ 819 int 820 sip_add_priority(sip_msg_t sip_msg, char *prio) 821 { 822 int ret; 823 824 if (prio == NULL) 825 return (EINVAL); 826 ret = sip_add_str_to_msg(sip_msg, SIP_PRIORITY, prio, NULL, (char)NULL); 827 828 return (ret); 829 } 830 831 /* 832 * Reply-To = "Reply-To" HCOLON rplyto-spec 833 * rplyto-spec = ( name-addr / addr-spec ) 834 * *( SEMI rplyto-param ) 835 * rplyto-param = generic-param 836 */ 837 int 838 sip_add_reply_to(sip_msg_t sip_msg, char *uname, char *addr, char *plist, 839 boolean_t add_aquot) 840 { 841 return (sip_add_name_aspec(sip_msg, uname, addr, NULL, add_aquot, 842 SIP_REPLYTO, plist)); 843 } 844 845 846 /* 847 * Privacy-hdr = "Privacy" HCOLON priv-value *(";" priv-value) 848 * priv-value = "header" / "session" / "user" / "none" / "critical" 849 * / token 850 */ 851 int 852 sip_add_privacy(sip_msg_t sip_msg, char *priv_val) 853 { 854 int ret; 855 856 if (priv_val == NULL) 857 return (EINVAL); 858 ret = sip_add_str_to_msg(sip_msg, SIP_PRIVACY, priv_val, NULL, 859 (char)NULL); 860 return (ret); 861 } 862 863 /* 864 * Require = "Require" HCOLON option-tag *(COMMA option-tag) 865 * option-tag = token 866 */ 867 int 868 sip_add_require(sip_msg_t sip_msg, char *req) 869 { 870 int ret; 871 872 if (req == NULL) 873 return (EINVAL); 874 ret = sip_add_str_to_msg(sip_msg, SIP_REQUIRE, req, NULL, (char)NULL); 875 return (ret); 876 } 877 878 /* 879 * Retry-After = "Retry-After" HCOLON delta-seconds 880 * [ comment ] *( SEMI retry-param ) 881 * retry-param = ("duration" EQUAL delta-seconds) 882 * / generic-param 883 */ 884 int 885 sip_add_retry_after(sip_msg_t sip_msg, int secs, char *cmt, char *plist) 886 { 887 int r; 888 889 if (secs <= 0) 890 return (EINVAL); 891 892 if (cmt == NULL) { 893 r = sip_add_int_to_msg(sip_msg, SIP_RETRY_AFTER, secs, plist); 894 return (r); 895 } 896 897 r = sip_add_intstr_to_msg(sip_msg, SIP_RETRY_AFTER, secs, cmt, plist); 898 return (r); 899 } 900 901 /* 902 * Server = "Server" HCOLON server-val *(LWS server-val) 903 * server-val = product / comment 904 * product = token [SLASH product-version] 905 * product-version = token 906 */ 907 int 908 sip_add_server(sip_msg_t sip_msg, char *svr) 909 { 910 int ret; 911 912 if (svr == NULL) 913 return (EINVAL); 914 ret = sip_add_str_to_msg(sip_msg, SIP_SERVER, svr, NULL, (char)NULL); 915 return (ret); 916 } 917 918 /* 919 * Subject = ( "Subject" / "s" ) HCOLON [TEXT-UTF8-TRIM] 920 */ 921 int 922 sip_add_subject(sip_msg_t sip_msg, char *subject) 923 { 924 int ret; 925 926 if (subject == NULL) { 927 ret = sip_add_empty_hdr(sip_msg, SIP_SUBJECT); 928 } else { 929 ret = sip_add_str_to_msg(sip_msg, SIP_SUBJECT, subject, NULL, 930 (char)NULL); 931 } 932 return (ret); 933 } 934 935 /* 936 * Supported = ( "Supported" / "k" ) HCOLON 937 * [option-tag *(COMMA option-tag)] 938 */ 939 int 940 sip_add_supported(sip_msg_t sip_msg, char *support) 941 { 942 int ret; 943 944 if (support == NULL) { 945 ret = sip_add_empty_hdr(sip_msg, SIP_SUPPORT); 946 } else { 947 ret = sip_add_str_to_msg(sip_msg, SIP_SUPPORT, support, NULL, 948 (char)NULL); 949 } 950 return (ret); 951 } 952 953 /* 954 * Timestamp = "Timestamp" HCOLON 1*(DIGIT) 955 * [ "." *(DIGIT) ] [ LWS delay ] 956 * delay = *(DIGIT) [ "." *(DIGIT) ] 957 */ 958 int 959 sip_add_tstamp(sip_msg_t sip_msg, char *time, char *delay) 960 { 961 int ret; 962 963 if (delay == NULL) { 964 ret = sip_add_str_to_msg(sip_msg, SIP_TIMESTAMP, time, NULL, 965 (char)NULL); 966 } else { 967 ret = sip_add_2strs_to_msg(sip_msg, SIP_TIMESTAMP, time, 968 B_FALSE, delay, NULL, ' '); 969 } 970 return (ret); 971 } 972 973 /* 974 * Unsupported = "Unsupported" HCOLON option-tag *(COMMA option-tag) 975 */ 976 int 977 sip_add_unsupported(sip_msg_t sip_msg, char *unsupport) 978 { 979 int ret; 980 981 if (unsupport == NULL) 982 return (EINVAL); 983 ret = sip_add_str_to_msg(sip_msg, SIP_UNSUPPORT, unsupport, NULL, 984 (char)NULL); 985 return (ret); 986 } 987 988 /* 989 * User-Agent = "User-Agent" HCOLON server-val *(LWS server-val) 990 */ 991 int 992 sip_add_user_agent(sip_msg_t sip_msg, char *usr) 993 { 994 int r; 995 996 if (usr == NULL) 997 return (EINVAL); 998 r = sip_add_str_to_msg(sip_msg, SIP_USER_AGENT, usr, NULL, (char)NULL); 999 return (r); 1000 } 1001 1002 /* 1003 * Warning = "Warning" HCOLON warning-value *(COMMA warning-value) 1004 * warning-value = warn-code SP warn-agent SP warn-text 1005 * warn-code = 3DIGIT 1006 * warn-agent = hostport / pseudonym 1007 * ; the name or pseudonym of the server adding 1008 * ; the Warning header, for use in debugging 1009 * warn-text = quoted-string 1010 * pseudonym = token 1011 */ 1012 int 1013 sip_add_warning(sip_msg_t sip_msg, int code, char *addr, char *msg) 1014 { 1015 _sip_header_t *new_header; 1016 int header_size; 1017 _sip_msg_t *_sip_msg; 1018 char *hdr_name = SIP_WARNING; 1019 1020 if (sip_msg == NULL || addr == NULL || msg == NULL || 1021 addr[0] == '\0' || msg[0] == '\0' || code < 100 || code > 999) { 1022 return (EINVAL); 1023 } 1024 1025 _sip_msg = (_sip_msg_t *)sip_msg; 1026 (void) pthread_mutex_lock(&_sip_msg->sip_msg_mutex); 1027 if (_sip_msg->sip_msg_cannot_be_modified) { 1028 (void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex); 1029 return (ENOTSUP); 1030 } 1031 1032 header_size = strlen(hdr_name) + SIP_SPACE_LEN + sizeof (char) + 1033 SIP_SPACE_LEN + sip_num_of_digits(code) + SIP_SPACE_LEN + 1034 strlen(addr) + SIP_SPACE_LEN + sizeof (char) + strlen(msg) + 1035 sizeof (char) + strlen(SIP_CRLF); 1036 1037 new_header = sip_new_header(header_size); 1038 if (new_header == NULL) { 1039 (void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex); 1040 return (ENOMEM); 1041 } 1042 1043 (void) snprintf(new_header->sip_hdr_start, header_size + 1, 1044 "%s %c %d %s \"%s\"%s", hdr_name, SIP_HCOLON, code, addr, 1045 msg, SIP_CRLF); 1046 _sip_add_header(_sip_msg, new_header, B_TRUE, B_FALSE, NULL); 1047 if (_sip_msg->sip_msg_buf != NULL) 1048 _sip_msg->sip_msg_modified = B_TRUE; 1049 (void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex); 1050 1051 return (0); 1052 } 1053 1054 /* 1055 * RAck = "RAck" HCOLON response-num LWS CSeq-num LWS Method 1056 * response-num = 1*DIGIT 1057 * CSeq-num = 1*DIGIT 1058 */ 1059 int 1060 sip_add_rack(sip_msg_t sip_msg, int resp_num, int cseq, sip_method_t method) 1061 { 1062 _sip_header_t *new_header; 1063 int header_size; 1064 _sip_msg_t *_sip_msg; 1065 char *hdr_name = SIP_RACK; 1066 1067 if (sip_msg == NULL || resp_num <= 0 || cseq < 0 || method <= 0 || 1068 method >= MAX_SIP_METHODS) { 1069 return (EINVAL); 1070 } 1071 1072 _sip_msg = (_sip_msg_t *)sip_msg; 1073 (void) pthread_mutex_lock(&_sip_msg->sip_msg_mutex); 1074 if (_sip_msg->sip_msg_cannot_be_modified) { 1075 (void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex); 1076 return (ENOTSUP); 1077 } 1078 1079 header_size = strlen(hdr_name) + SIP_SPACE_LEN + sizeof (char) + 1080 SIP_SPACE_LEN + sip_num_of_digits(resp_num) + SIP_SPACE_LEN + 1081 sip_num_of_digits(cseq) + SIP_SPACE_LEN + 1082 strlen(sip_methods[method].name) + strlen(SIP_CRLF); 1083 1084 new_header = sip_new_header(header_size); 1085 if (new_header == NULL) { 1086 (void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex); 1087 return (ENOMEM); 1088 } 1089 1090 (void) snprintf(new_header->sip_hdr_start, header_size + 1, 1091 "%s %c %d %d %s%s", hdr_name, SIP_HCOLON, resp_num, cseq, 1092 sip_methods[method].name, SIP_CRLF); 1093 1094 _sip_add_header(_sip_msg, new_header, B_TRUE, B_FALSE, NULL); 1095 if (_sip_msg->sip_msg_buf != NULL) 1096 _sip_msg->sip_msg_modified = B_TRUE; 1097 (void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex); 1098 1099 return (0); 1100 1101 } 1102 1103 /* 1104 * Allow-Events = ( "Allow-Events" / "u" ) HCOLON event-type 1105 * *(COMMA event-type) 1106 */ 1107 int 1108 sip_add_allow_events(sip_msg_t sip_msg, char *t_event) 1109 { 1110 return (sip_add_str_to_msg(sip_msg, SIP_ALLOW_EVENTS, t_event, NULL, 1111 (char)NULL)); 1112 } 1113 1114 /* 1115 * Event = ( "Event" / "o" ) HCOLON event-type 1116 * *( SEMI event-param ) 1117 * event-type = event-package *( "." event-template ) 1118 * event-package = token-nodot 1119 * event-template = token-nodot 1120 * token-nodot = 1*( alphanum / "-" / "!" / "%" / "*" 1121 * / "_" / "+" / "`" / "'" / "~" ) 1122 * event-param = generic-param / ( "id" EQUAL token ) 1123 */ 1124 int 1125 sip_add_event(sip_msg_t sip_msg, char *t_event, char *plist) 1126 { 1127 return (sip_add_str_to_msg(sip_msg, SIP_EVENT, t_event, plist, 1128 SIP_SEMI)); 1129 } 1130 1131 /* 1132 * Subscription-State = "Subscription-State" HCOLON substate-value 1133 * *( SEMI subexp-params ) 1134 * substate-value = "active" / "pending" / "terminated" 1135 * / extension-substate 1136 * extension-substate = token 1137 * subexp-params = ("reason" EQUAL event-reason-value) 1138 * / ("expires" EQUAL delta-seconds)* 1139 * / ("retry-after" EQUAL delta-seconds) 1140 * / generic-param 1141 * event-reason-value = "deactivated" 1142 * / "probation" 1143 * / "rejected" 1144 * / "timeout" 1145 * / "giveup" 1146 * / "noresource" 1147 * / event-reason-extension 1148 * event-reason-extension = token 1149 */ 1150 int 1151 sip_add_substate(sip_msg_t sip_msg, char *sub, char *plist) 1152 { 1153 return (sip_add_str_to_msg(sip_msg, SIP_SUBSCRIPTION_STATE, sub, plist, 1154 SIP_SEMI)); 1155 } 1156 1157 /* 1158 * Authorization = "Authorization" HCOLON credentials 1159 * credentials = ("Digest" LWS digest-response) 1160 * / other-response 1161 * digest-response = dig-resp *(COMMA dig-resp) 1162 * dig-resp = username / realm / nonce / digest-uri 1163 * / dresponse / algorithm / cnonce 1164 * / opaque / message-qop 1165 * / nonce-count / auth-param 1166 * username = "username" EQUAL username-value 1167 * username-value = quoted-string 1168 * digest-uri = "uri" EQUAL LDQUOT digest-uri-value RDQUOT 1169 * digest-uri-value = rquest-uri ; Equal to request-uri as specified 1170 * by HTTP/1.1 1171 * message-qop = "qop" EQUAL qop-value 1172 * cnonce = "cnonce" EQUAL cnonce-value 1173 * cnonce-value = nonce-value 1174 * nonce-count = "nc" EQUAL nc-value 1175 * nc-value = 8LHEX 1176 * dresponse = "response" EQUAL request-digest 1177 * request-digest = LDQUOT 32LHEX RDQUOT 1178 * auth-param = auth-param-name EQUAL 1179 * ( token / quoted-string ) 1180 * auth-param-name = token 1181 * other-response = auth-scheme LWS auth-param 1182 * *(COMMA auth-param) 1183 * auth-scheme = token 1184 */ 1185 int 1186 sip_add_author(sip_msg_t sip_msg, char *scheme, char *param) 1187 { 1188 return (sip_add_str_to_msg(sip_msg, SIP_AUTHOR, scheme, param, SIP_SP)); 1189 } 1190 1191 /* 1192 * Authentication-Info = "Authentication-Info" HCOLON ainfo 1193 * *(COMMA ainfo) 1194 * ainfo = nextnonce / message-qop 1195 * / response-auth / cnonce 1196 * / nonce-count 1197 * nextnonce = "nextnonce" EQUAL nonce-value 1198 * response-auth = "rspauth" EQUAL response-digest 1199 * response-digest = LDQUOT *LHEX RDQUOT 1200 */ 1201 int 1202 sip_add_authen_info(sip_msg_t sip_msg, char *ainfo) 1203 { 1204 return (sip_add_str_to_msg(sip_msg, SIP_AUTHEN_INFO, ainfo, NULL, 1205 (char)NULL)); 1206 } 1207 1208 /* 1209 * Proxy-Authenticate = "Proxy-Authenticate" HCOLON challenge 1210 * challenge = ("Digest" LWS digest-cln *(COMMA digest-cln)) 1211 * / other-challenge 1212 * other-challenge = auth-scheme LWS auth-param 1213 * *(COMMA auth-param) 1214 * digest-cln = realm / domain / nonce 1215 * / opaque / stale / algorithm 1216 * / qop-options / auth-param 1217 * realm = "realm" EQUAL realm-value 1218 * realm-value = quoted-string 1219 * domain = "domain" EQUAL LDQUOT URI 1220 * *( 1*SP URI ) RDQUOT 1221 * URI = absoluteURI / abs-path 1222 * nonce = "nonce" EQUAL nonce-value 1223 * nonce-value = quoted-string 1224 * opaque = "opaque" EQUAL quoted-string 1225 * stale = "stale" EQUAL ( "true" / "false" ) 1226 * algorithm = "algorithm" EQUAL ( "MD5" / "MD5-sess" 1227 * / token ) 1228 * qop-options = "qop" EQUAL LDQUOT qop-value 1229 * *("," qop-value) RDQUOT 1230 * qop-value = "auth" / "auth-int" / token 1231 */ 1232 int 1233 sip_add_proxy_authen(sip_msg_t sip_msg, char *pascheme, char *paparam) 1234 { 1235 return (sip_add_str_to_msg(sip_msg, SIP_PROXY_AUTHEN, pascheme, paparam, 1236 SIP_SP)); 1237 } 1238 1239 /* 1240 * Proxy-Authorization = "Proxy-Authorization" HCOLON credentials 1241 */ 1242 int 1243 sip_add_proxy_author(sip_msg_t sip_msg, char *paschem, char *paparam) 1244 { 1245 return (sip_add_str_to_msg(sip_msg, SIP_PROXY_AUTHOR, paschem, paparam, 1246 SIP_SP)); 1247 } 1248 1249 /* 1250 * Proxy-Require = "Proxy-Require" HCOLON option-tag 1251 * *(COMMA option-tag) 1252 * option-tag = token 1253 */ 1254 int 1255 sip_add_proxy_require(sip_msg_t sip_msg, char *opt) 1256 { 1257 return (sip_add_str_to_msg(sip_msg, SIP_PROXY_REQ, opt, NULL, 1258 (char)NULL)); 1259 } 1260 1261 /* 1262 * WWW-Authenticate = "WWW-Authenticate" HCOLON challenge 1263 * extension-header = header-name HCOLON header-value 1264 * header-name = token 1265 * header-value = *(TEXT-UTF8char / UTF8-CONT / LWS) 1266 * message-body = *OCTET 1267 */ 1268 int 1269 sip_add_www_authen(sip_msg_t sip_msg, char *wascheme, char *waparam) 1270 { 1271 return (sip_add_str_to_msg(sip_msg, SIP_WWW_AUTHEN, wascheme, waparam, 1272 SIP_SP)); 1273 } 1274 1275 /* 1276 * Call-ID = ( "Call-ID" / "i" ) HCOLON callid 1277 */ 1278 int 1279 sip_add_callid(sip_msg_t sip_msg, char *callid) 1280 { 1281 int ret; 1282 boolean_t allocd = B_FALSE; 1283 1284 if (sip_msg == NULL || (callid != NULL && callid[0] == '\0')) 1285 return (EINVAL); 1286 if (callid == NULL) { 1287 callid = (char *)sip_guid(); 1288 if (callid == NULL) 1289 return (ENOMEM); 1290 allocd = B_TRUE; 1291 } 1292 ret = sip_add_str_to_msg(sip_msg, SIP_CALL_ID, callid, NULL, 1293 (char)NULL); 1294 if (allocd) 1295 free(callid); 1296 return (ret); 1297 } 1298 1299 /* 1300 * CSeq = "CSeq" HCOLON 1*DIGIT LWS Method 1301 */ 1302 int 1303 sip_add_cseq(sip_msg_t sip_msg, sip_method_t method, uint32_t cseq) 1304 { 1305 int r; 1306 1307 if (sip_msg == NULL || (int)cseq < 0 || method == 0 || 1308 method >= MAX_SIP_METHODS) { 1309 return (EINVAL); 1310 } 1311 r = sip_add_intstr_to_msg(sip_msg, SIP_CSEQ, cseq, 1312 sip_methods[method].name, NULL); 1313 return (r); 1314 } 1315 1316 /* 1317 * Via = ( "Via" / "v" ) HCOLON via-parm *(COMMA via-parm) 1318 * via-parm = sent-protocol LWS sent-by *( SEMI via-params ) 1319 * via-params = via-ttl / via-maddr 1320 * / via-received / via-branch 1321 * / via-extension 1322 * via-ttl = "ttl" EQUAL ttl 1323 * via-maddr = "maddr" EQUAL host 1324 * via-received = "received" EQUAL (IPv4address / IPv6address) 1325 * via-branch = "branch" EQUAL token 1326 * via-extension = generic-param 1327 * sent-protocol = protocol-name SLASH protocol-version 1328 * SLASH transport 1329 * protocol-name = "SIP" / token 1330 * protocol-version = token 1331 * transport = "UDP" / "TCP" / "TLS" / "SCTP" 1332 * / other-transport 1333 * sent-by = host [ COLON port ] 1334 * ttl = 1*3DIGIT ; 0 to 255 1335 */ 1336 _sip_header_t * 1337 sip_create_via_hdr(char *sent_protocol_transport, char *sent_by_host, 1338 int sent_by_port, char *via_params) 1339 { 1340 _sip_header_t *new_header; 1341 int header_size; 1342 int count; 1343 1344 header_size = strlen(SIP_VIA) + SIP_SPACE_LEN + sizeof (char) + 1345 SIP_SPACE_LEN + strlen(SIP_VERSION) + sizeof (char) + 1346 strlen(sent_protocol_transport) + SIP_SPACE_LEN + 1347 strlen(sent_by_host) + strlen(SIP_CRLF); 1348 1349 if (sent_by_port > 0) { 1350 header_size += SIP_SPACE_LEN + sizeof (char) + SIP_SPACE_LEN + 1351 sip_num_of_digits(sent_by_port); 1352 } 1353 1354 if (via_params != NULL) { 1355 header_size += SIP_SPACE_LEN + sizeof (char) + 1356 strlen(via_params); 1357 } 1358 new_header = sip_new_header(header_size); 1359 if (new_header->sip_hdr_start == NULL) 1360 return (NULL); 1361 count = snprintf(new_header->sip_hdr_current, header_size + 1, 1362 "%s %c %s/%s %s", 1363 SIP_VIA, SIP_HCOLON, SIP_VERSION, sent_protocol_transport, 1364 sent_by_host); 1365 new_header->sip_hdr_current += count; 1366 header_size -= count; 1367 1368 if (sent_by_port > 0) { 1369 count = snprintf(new_header->sip_hdr_current, header_size + 1, 1370 " %c %d", SIP_HCOLON, sent_by_port); 1371 new_header->sip_hdr_current += count; 1372 header_size -= count; 1373 } 1374 1375 if (via_params != NULL) { 1376 count = snprintf(new_header->sip_hdr_current, header_size + 1, 1377 " %c%s", SIP_SEMI, via_params); 1378 new_header->sip_hdr_current += count; 1379 header_size -= count; 1380 } 1381 1382 (void) snprintf(new_header->sip_hdr_current, header_size + 1, 1383 "%s", SIP_CRLF); 1384 return (new_header); 1385 } 1386 1387 /* 1388 * There can be multiple via headers we always append the header. 1389 * We expect the via params to be a semi-colon separated list of parameters. 1390 * We will add a semi-clone, before adding the list to the header. 1391 */ 1392 int 1393 sip_add_via(sip_msg_t sip_msg, char *sent_protocol_transport, 1394 char *sent_by_host, int sent_by_port, char *via_params) 1395 { 1396 _sip_header_t *new_header; 1397 _sip_msg_t *_sip_msg; 1398 1399 if (sip_msg == NULL || sent_protocol_transport == NULL || 1400 sent_by_host == NULL || sent_by_port < 0) { 1401 return (EINVAL); 1402 } 1403 1404 _sip_msg = (_sip_msg_t *)sip_msg; 1405 (void) pthread_mutex_lock(&_sip_msg->sip_msg_mutex); 1406 if (_sip_msg->sip_msg_cannot_be_modified) { 1407 (void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex); 1408 return (ENOTSUP); 1409 } 1410 1411 new_header = sip_create_via_hdr(sent_protocol_transport, sent_by_host, 1412 sent_by_port, via_params); 1413 if (new_header == NULL) { 1414 (void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex); 1415 return (ENOMEM); 1416 } 1417 _sip_add_header(_sip_msg, new_header, B_TRUE, B_FALSE, NULL); 1418 if (_sip_msg->sip_msg_buf != NULL) 1419 _sip_msg->sip_msg_modified = B_TRUE; 1420 (void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex); 1421 return (0); 1422 } 1423 1424 /* 1425 * Max-Forwards = "Max-Forwards" HCOLON 1*DIGIT 1426 */ 1427 int 1428 sip_add_maxforward(sip_msg_t sip_msg, uint_t maxforward) 1429 { 1430 if (sip_msg == NULL || (int)maxforward < 0) 1431 return (EINVAL); 1432 return (sip_add_int_to_msg(sip_msg, SIP_MAX_FORWARDS, maxforward, 1433 NULL)); 1434 } 1435 1436 /* 1437 * Content-Type = ( "Content-Type" / "c" ) HCOLON media-type 1438 * media-type = m-type SLASH m-subtype *(SEMI m-parameter) 1439 * m-type = discrete-type / composite-type 1440 * discrete-type = "text" / "image" / "audio" / "video" 1441 * / "application" / extension-token 1442 * composite-type = "message" / "multipart" / extension-token 1443 * extension-token = ietf-token / x-token 1444 * ietf-token = token 1445 * x-token = "x-" token 1446 * m-subtype = extension-token / iana-token 1447 * iana-token = token 1448 * m-parameter = m-attribute EQUAL m-value 1449 * m-attribute = token 1450 * m-value = token / quoted-string 1451 */ 1452 int 1453 sip_add_content_type(sip_msg_t sip_msg, char *type, char *subtype) 1454 { 1455 if (sip_msg == NULL || type == NULL || subtype == NULL) 1456 return (EINVAL); 1457 return (sip_add_2strs_to_msg(sip_msg, SIP_CONTENT_TYPE, type, B_FALSE, 1458 subtype, NULL, SIP_SLASH)); 1459 } 1460 1461 /* 1462 * Content-Length = ( "Content-Length" / "l" ) HCOLON 1*DIGIT 1463 */ 1464 int 1465 sip_add_content_length(_sip_msg_t *_sip_msg, int length) 1466 { 1467 _sip_header_t *new_header; 1468 int header_size; 1469 1470 if (_sip_msg == NULL || length < 0) 1471 return (EINVAL); 1472 (void) pthread_mutex_lock(&_sip_msg->sip_msg_mutex); 1473 if (_sip_msg->sip_msg_cannot_be_modified) { 1474 (void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex); 1475 return (ENOTSUP); 1476 } 1477 1478 header_size = strlen(SIP_CONTENT_LENGTH) + SIP_SPACE_LEN + 1479 sizeof (char) + SIP_SPACE_LEN + sip_num_of_digits(length) + 1480 strlen(SIP_CRLF) + strlen(SIP_CRLF); 1481 1482 new_header = sip_new_header(header_size); 1483 if (new_header == NULL) { 1484 (void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex); 1485 return (ENOMEM); 1486 } 1487 (void) snprintf(new_header->sip_hdr_start, header_size + 1, 1488 "%s %c %u%s%s", SIP_CONTENT_LENGTH, SIP_HCOLON, length, 1489 SIP_CRLF, SIP_CRLF); 1490 1491 _sip_add_header(_sip_msg, new_header, B_TRUE, B_FALSE, NULL); 1492 if (_sip_msg->sip_msg_buf != NULL) 1493 _sip_msg->sip_msg_modified = B_TRUE; 1494 (void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex); 1495 return (0); 1496 } 1497 1498 1499 /* 1500 * Contact = ("Contact" / "m" ) HCOLON 1501 * ( STAR / (contact-param *(COMMA contact-param))) 1502 * contact-param = (name-addr / addr-spec) *(SEMI contact-params) 1503 * name-addr = [ display-name ] LAQUOT addr-spec RAQUOT 1504 * addr-spec = SIP-URI / SIPS-URI / absoluteURI 1505 * display-name = *(token LWS)/ quoted-string 1506 * contact-params = c-p-q / c-p-expires 1507 * / contact-extension 1508 */ 1509 int 1510 sip_add_contact(sip_msg_t sip_msg, char *display_name, char *contact_uri, 1511 boolean_t add_aquot, char *contact_params) 1512 { 1513 return (sip_add_name_aspec(sip_msg, display_name, contact_uri, NULL, 1514 add_aquot, SIP_CONTACT, contact_params)); 1515 } 1516 1517 /* 1518 * From = ( "From" / "f" ) HCOLON from-spec 1519 * from-spec = ( name-addr / addr-spec ) 1520 * *( SEMI from-param ) 1521 * from-param = tag-param / generic-param 1522 * tag-param = "tag" EQUAL token 1523 * 1524 * Since there can be more than one tags, fromtags is a semi colon separated 1525 * list of tags. 1526 */ 1527 int 1528 sip_add_from(sip_msg_t sip_msg, char *display_name, char *from_uri, 1529 char *fromtags, boolean_t add_aquot, char *from_params) 1530 { 1531 return (sip_add_name_aspec(sip_msg, display_name, from_uri, fromtags, 1532 add_aquot, SIP_FROM, from_params)); 1533 } 1534 1535 /* 1536 * To = ( "To" / "t" ) HCOLON ( name-addr 1537 * / addr-spec ) *( SEMI to-param ) 1538 * to-param = tag-param / generic-param 1539 */ 1540 int 1541 sip_add_to(sip_msg_t sip_msg, char *display_name, char *to_uri, 1542 char *totags, boolean_t add_aquot, char *to_params) 1543 { 1544 return (sip_add_name_aspec(sip_msg, display_name, to_uri, totags, 1545 add_aquot, SIP_TO, to_params)); 1546 } 1547 1548 /* 1549 * Route = "Route" HCOLON route-param *(COMMA route-param) 1550 * route-param = name-addr *( SEMI rr-param ) 1551 */ 1552 int 1553 sip_add_route(sip_msg_t sip_msg, char *display_name, char *uri, 1554 char *route_params) 1555 { 1556 return (sip_add_name_aspec(sip_msg, display_name, uri, NULL, B_TRUE, 1557 SIP_ROUTE, route_params)); 1558 } 1559 1560 /* 1561 * Record-Route = "Record-Route" HCOLON rec-route *(COMMA rec-route) 1562 * rec-route = name-addr *( SEMI rr-param ) 1563 * rr-param = generic-param 1564 */ 1565 int 1566 sip_add_record_route(sip_msg_t sip_msg, char *display_name, char *uri, 1567 char *route_params) 1568 { 1569 return (sip_add_name_aspec(sip_msg, display_name, uri, NULL, B_TRUE, 1570 SIP_RECORD_ROUTE, route_params)); 1571 } 1572 1573 1574 /* 1575 * PAssertedID = "P-Asserted-Identity" HCOLON PAssertedID-value 1576 * *(COMMA PAssertedID-value) 1577 * PAssertedID-value = name-addr / addr-spec 1578 */ 1579 int 1580 sip_add_passertedid(sip_msg_t sip_msg, char *display_name, char *addr, 1581 boolean_t add_aquot) 1582 { 1583 return (sip_add_name_aspec(sip_msg, display_name, addr, NULL, add_aquot, 1584 SIP_PASSERTEDID, NULL)); 1585 } 1586 1587 /* 1588 * PPreferredID = "P-Preferred-Identity" HCOLON PPreferredID-value 1589 * *(COMMA PPreferredID-value) 1590 * PPreferredID-value = name-addr / addr-spec 1591 */ 1592 int 1593 sip_add_ppreferredid(sip_msg_t sip_msg, char *display_name, char *addr, 1594 boolean_t add_aquot) 1595 { 1596 return (sip_add_name_aspec(sip_msg, display_name, addr, NULL, add_aquot, 1597 SIP_PPREFERREDID, NULL)); 1598 } 1599