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