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 /* 28 * Contains implementation of various interfaces exported by library 29 */ 30 31 #include <stdio.h> 32 #include <assert.h> 33 #include <errno.h> 34 #include <stdlib.h> 35 #include <string.h> 36 #include <ctype.h> 37 #include <sdp.h> 38 39 #include "sdp_parse.h" 40 #include "commp_util.h" 41 42 #define FIELD_EQUALS_CRLF_LEN 4 /* first two characters and CRLF */ 43 44 #define SDP_ATTR_TO_STR(m_attr) { \ 45 while ((m_attr) != NULL) { \ 46 if ((m_attr)->a_value != NULL) { \ 47 wrote = snprintf(buf, len, "a=%s%c%s%s", \ 48 (m_attr)->a_name, COMMP_COLON, (m_attr)-> \ 49 a_value, COMMP_CRLF); \ 50 } else { \ 51 wrote = snprintf(buf, len, "a=%s%s", (m_attr)-> \ 52 a_name, COMMP_CRLF); \ 53 } \ 54 len = len - wrote; \ 55 buf = buf + wrote; \ 56 (m_attr) = (m_attr)->a_next; \ 57 } \ 58 } 59 60 #define SDP_KEY_TO_STR(m_key) { \ 61 if ((m_key) != NULL) { \ 62 if ((m_key)->k_enckey != NULL) { \ 63 wrote = snprintf(buf, len, "k=%s%c%s%s", \ 64 (m_key)->k_method, COMMP_COLON, (m_key)-> \ 65 k_enckey, COMMP_CRLF); \ 66 } else { \ 67 wrote = snprintf(buf, len, "k=%s%s", (m_key)-> \ 68 k_method, COMMP_CRLF); \ 69 } \ 70 len = len - wrote; \ 71 buf = buf + wrote; \ 72 } \ 73 } 74 75 #define SDP_BANDWIDTH_TO_STR(m_bw) { \ 76 while ((m_bw) != NULL) { \ 77 wrote = snprintf(buf, len, "b=%s%c%llu%s", (m_bw)-> \ 78 b_type, COMMP_COLON, (m_bw)->b_value, COMMP_CRLF); \ 79 len = len - wrote; \ 80 buf = buf + wrote; \ 81 (m_bw) = (m_bw)->b_next; \ 82 } \ 83 } 84 85 #define SDP_INFORMATION_TO_STR(m_info) { \ 86 if ((m_info) != NULL) { \ 87 wrote = snprintf(buf, len, "i=%s%s", (m_info), COMMP_CRLF); \ 88 len = len - wrote; \ 89 buf = buf + wrote; \ 90 } \ 91 } 92 93 #define SDP_CONNECTION_TO_STR(m_conn) { \ 94 while ((m_conn) != NULL) { \ 95 if (strcasecmp((m_conn)->c_addrtype, \ 96 COMMP_ADDRTYPE_IP4) == 0) { \ 97 if ((m_conn)->c_addrcount > 1) { \ 98 wrote = snprintf(buf, len, "c=%s %s %s/%d/%d" \ 99 "%s", (m_conn)->c_nettype, (m_conn)-> \ 100 c_addrtype, (m_conn)->c_address, (m_conn)->\ 101 c_ttl, (m_conn)->c_addrcount, COMMP_CRLF); \ 102 } else if ((m_conn)->c_addrcount == 1) { \ 103 wrote = snprintf(buf, len, "c=%s %s %s/%d%s", \ 104 (m_conn)->c_nettype, (m_conn)->c_addrtype, \ 105 (m_conn)->c_address, (m_conn)->c_ttl, \ 106 COMMP_CRLF); \ 107 } else { \ 108 wrote = snprintf(buf, len, "c=%s %s %s%s", \ 109 (m_conn)->c_nettype, (m_conn)->c_addrtype, \ 110 (m_conn)->c_address, COMMP_CRLF); \ 111 } \ 112 } else if (strcasecmp((m_conn)->c_addrtype, \ 113 COMMP_ADDRTYPE_IP6) == 0) { \ 114 if ((m_conn)->c_addrcount <= 1) { \ 115 wrote = snprintf(buf, len, "c=%s %s %s%s", \ 116 (m_conn)->c_nettype, (m_conn)->c_addrtype, \ 117 (m_conn)->c_address, COMMP_CRLF); \ 118 } else { \ 119 wrote = snprintf(buf, len, "c=%s %s %s/%d%s", \ 120 (m_conn)->c_nettype, (m_conn)->c_addrtype, \ 121 (m_conn)->c_address, (m_conn)->c_addrcount,\ 122 COMMP_CRLF); \ 123 } \ 124 } else { \ 125 wrote = snprintf(buf, len, "c=%s %s %s%s", (m_conn)-> \ 126 c_nettype, (m_conn)->c_addrtype, (m_conn)-> \ 127 c_address, COMMP_CRLF); \ 128 } \ 129 len = len - wrote; \ 130 buf = buf + wrote; \ 131 (m_conn) = (m_conn)->c_next; \ 132 } \ 133 } 134 135 #define SDP_ADD_KEY(d_key, s_key) { \ 136 if ((s_key) != NULL) { \ 137 if (sdp_add_key(&(d_key), (s_key)->k_method, \ 138 (s_key)->k_enckey) != 0) { \ 139 sdp_free_session(new_sess); \ 140 return (NULL); \ 141 } \ 142 } \ 143 } 144 145 #define SDP_ADD_ATTRIBUTE(d_attr, s_attr) { \ 146 while ((s_attr) != NULL) { \ 147 if (sdp_add_attribute(&(d_attr), (s_attr)->a_name, \ 148 (s_attr)->a_value) != 0) { \ 149 sdp_free_session(new_sess); \ 150 return (NULL); \ 151 } \ 152 (s_attr) = (s_attr)->a_next; \ 153 } \ 154 } 155 156 #define SDP_ADD_BANDWIDTH(d_bw, s_bw) { \ 157 while ((s_bw) != NULL) { \ 158 if (sdp_add_bandwidth(&(d_bw), (s_bw)->b_type, \ 159 (s_bw)->b_value) != 0) { \ 160 sdp_free_session(new_sess); \ 161 return (NULL); \ 162 } \ 163 (s_bw) = (s_bw)->b_next; \ 164 } \ 165 } 166 167 #define SDP_ADD_CONNECTION(d_conn, s_conn) { \ 168 while ((s_conn) != NULL) { \ 169 if (sdp_add_connection(&(d_conn), (s_conn)->c_nettype, \ 170 (s_conn)->c_addrtype, (s_conn)->c_address, \ 171 (s_conn)->c_ttl, (s_conn)->c_addrcount) != 0) { \ 172 sdp_free_session(new_sess); \ 173 return (NULL); \ 174 } \ 175 (s_conn) = (s_conn)->c_next; \ 176 } \ 177 } 178 179 #define SDP_LEN_CONNECTION(m_conn) { \ 180 while ((m_conn) != NULL) { \ 181 len += FIELD_EQUALS_CRLF_LEN; \ 182 len += strlen((m_conn)->c_nettype); \ 183 len += strlen((m_conn)->c_addrtype) + 1; \ 184 len += strlen((m_conn)->c_address) + 1; \ 185 len += snprintf(buf, 1, "%u", (m_conn)->c_ttl) + 1; \ 186 len += snprintf(buf, 1, "%d", (m_conn)->c_addrcount) + 1; \ 187 (m_conn) = (m_conn)->c_next; \ 188 } \ 189 } 190 191 #define SDP_LEN_BANDWIDTH(m_bw) { \ 192 while ((m_bw) != NULL) { \ 193 len += FIELD_EQUALS_CRLF_LEN; \ 194 len += strlen((m_bw)->b_type); \ 195 len += snprintf(buf, 1, "%llu", (m_bw)->b_value) + 1; \ 196 (m_bw) = (m_bw)->b_next; \ 197 } \ 198 } 199 200 #define SDP_LEN_KEY(m_key) { \ 201 if ((m_key) != NULL) { \ 202 len += FIELD_EQUALS_CRLF_LEN; \ 203 len += strlen((m_key)->k_method); \ 204 if ((m_key)->k_enckey != NULL) \ 205 len += strlen((m_key)->k_enckey) + 1; \ 206 } \ 207 } 208 209 #define SDP_LEN_ATTRIBUTE(m_attr) { \ 210 while ((m_attr) != NULL) { \ 211 len += FIELD_EQUALS_CRLF_LEN; \ 212 len += strlen((m_attr)->a_name); \ 213 if ((m_attr)->a_value != NULL) \ 214 len += strlen((m_attr)->a_value) + 1; \ 215 (m_attr) = (m_attr)->a_next; \ 216 } \ 217 } 218 219 /* 220 * Given a media list and media name ("audio", "video", et al), it searches 221 * the list for that media. Returns NULL if media not present. 222 */ 223 sdp_media_t * 224 sdp_find_media(sdp_media_t *media, const char *name) 225 { 226 if (media == NULL || name == NULL || (strlen(name) == 0)) { 227 return (NULL); 228 } 229 while (media != NULL) { 230 if (media->m_name != NULL) { 231 if (strcasecmp(name, media->m_name) == 0) 232 return (media); 233 } 234 media = media->m_next; 235 } 236 return (media); 237 } 238 239 /* 240 * Given a attribute list and name of the attribute ("rtpmap", "fmtp", et al), 241 * this API searches the list for that attribute. Returns NULL if not found. 242 */ 243 sdp_attr_t * 244 sdp_find_attribute(sdp_attr_t *attr, const char *name) 245 { 246 if (attr == NULL || name == NULL || (strlen(name) == 0)) { 247 return (NULL); 248 } 249 while (attr != NULL) { 250 if (attr->a_name != NULL) { 251 if (strcasecmp(attr->a_name, name) == 0) 252 return (attr); 253 } 254 attr = attr->a_next; 255 } 256 return (attr); 257 } 258 259 /* 260 * Given a media list and a format number, this API will return the rtpmap 261 * attribute matching the format number. 262 */ 263 sdp_attr_t * 264 sdp_find_media_rtpmap(sdp_media_t *media, const char *format) 265 { 266 sdp_attr_t *attr = NULL; 267 char *tmp = NULL; 268 269 if (media == NULL || format == NULL || (strlen(format) == 0)) { 270 return (NULL); 271 } 272 attr = media->m_attr; 273 while (attr != NULL) { 274 if (attr->a_name != NULL && (strcasecmp(attr->a_name, 275 SDP_RTPMAP) == 0)) { 276 if (attr->a_value != NULL) { 277 tmp = attr->a_value; 278 while (isspace(*tmp)) 279 ++tmp; 280 if (strncasecmp(tmp, format, 281 strlen(format)) == 0) { 282 return (attr); 283 } 284 } 285 } 286 attr = attr->a_next; 287 } 288 return (attr); 289 } 290 291 /* 292 * Adds origin field to the session. 293 * o=<username> <sess-id> <sess-version> <nettype> <addrtype> <unicast-address> 294 */ 295 int 296 sdp_add_origin(sdp_session_t *session, const char *name, uint64_t id, 297 uint64_t ver, const char *nettype, const char *addrtype, 298 const char *address) 299 { 300 sdp_origin_t *origin; 301 int ret = 0; 302 303 if (session == NULL || name == NULL || nettype == NULL || 304 addrtype == NULL || address == NULL) { 305 return (EINVAL); 306 } 307 if (session->s_origin != NULL) 308 return (EPROTO); 309 origin = calloc(1, sizeof (sdp_origin_t)); 310 if (origin == NULL) 311 return (ENOMEM); 312 origin->o_id = id; 313 origin->o_version = ver; 314 if ((ret = commp_add_str(&origin->o_username, name, strlen(name))) != 0) 315 goto err_ret; 316 if ((ret = commp_add_str(&origin->o_nettype, nettype, 317 strlen(nettype))) != 0) { 318 goto err_ret; 319 } 320 if ((ret = commp_add_str(&origin->o_addrtype, addrtype, 321 strlen(addrtype))) != 0) { 322 goto err_ret; 323 } 324 if ((ret = commp_add_str(&origin->o_address, address, 325 strlen(address))) != 0) { 326 goto err_ret; 327 } 328 session->s_origin = origin; 329 return (ret); 330 err_ret: 331 sdp_free_origin(origin); 332 return (ret); 333 } 334 335 /* 336 * Adds session name field to the session. 337 * s=<session name> 338 */ 339 int 340 sdp_add_name(sdp_session_t *session, const char *name) 341 { 342 if (session == NULL || name == NULL) 343 return (EINVAL); 344 if (session->s_name != NULL) 345 return (EPROTO); 346 return (commp_add_str(&session->s_name, name, strlen(name))); 347 } 348 349 /* 350 * Adds session information field to the session or media section of SDP. 351 * i=<session description> 352 */ 353 int 354 sdp_add_information(char **information, const char *value) 355 { 356 if (information == NULL || value == NULL) 357 return (EINVAL); 358 if (*information != NULL) 359 return (EPROTO); 360 return (commp_add_str(information, value, strlen(value))); 361 } 362 363 /* 364 * Adds uri field to the session. 365 * u=<uri> 366 */ 367 int 368 sdp_add_uri(sdp_session_t *session, const char *uri) 369 { 370 if (session == NULL || uri == NULL) 371 return (EINVAL); 372 if (session->s_uri != NULL) 373 return (EPROTO); 374 return (commp_add_str(&session->s_uri, uri, strlen(uri))); 375 } 376 377 /* 378 * Adds email address field to the session. 379 * e=<email-address> 380 */ 381 int 382 sdp_add_email(sdp_session_t *session, const char *email) 383 { 384 if (session == NULL || email == NULL || (strlen(email) == 0)) 385 return (EINVAL); 386 return (add_value_to_list(&session->s_email, email, strlen(email), 387 B_TRUE)); 388 } 389 390 /* 391 * Adds phone number field to the session. 392 * p=<phone-number> 393 */ 394 int 395 sdp_add_phone(sdp_session_t *session, const char *phone) 396 { 397 if (session == NULL || phone == NULL || (strlen(phone) == 0)) 398 return (EINVAL); 399 return (add_value_to_list(&session->s_phone, phone, strlen(phone), 400 B_TRUE)); 401 } 402 403 /* 404 * Adds connection field to the session or media section of SDP 405 * c=<nettype> <addrtype> <connection-address>[/ttl]/<number of addresses> 406 */ 407 int 408 sdp_add_connection(sdp_conn_t **conn, const char *nettype, const char *addrtype, 409 const char *address, uint8_t ttl, int addrcount) 410 { 411 sdp_conn_t *tmp; 412 sdp_conn_t *new_conn; 413 int ret = 0; 414 415 if (conn == NULL || nettype == NULL || addrtype == NULL || 416 address == NULL) { 417 return (EINVAL); 418 } 419 new_conn = calloc(1, sizeof (sdp_conn_t)); 420 if (new_conn == NULL) 421 return (ENOMEM); 422 new_conn->c_ttl = ttl; 423 new_conn->c_addrcount = addrcount; 424 if ((ret = commp_add_str(&new_conn->c_nettype, nettype, 425 strlen(nettype))) != 0) { 426 goto err_ret; 427 } 428 if ((ret = commp_add_str(&new_conn->c_addrtype, addrtype, 429 strlen(addrtype))) != 0) { 430 goto err_ret; 431 } 432 if ((ret = commp_add_str(&new_conn->c_address, address, 433 strlen(address))) != 0) { 434 goto err_ret; 435 } 436 if (*conn == NULL) { 437 *conn = new_conn; 438 } else { 439 tmp = *conn; 440 while (tmp->c_next != NULL) 441 tmp = tmp->c_next; 442 tmp->c_next = new_conn; 443 } 444 return (ret); 445 err_ret: 446 sdp_free_connection(new_conn); 447 return (ret); 448 } 449 450 /* 451 * Adds bandwidth field to the session or media section of SDP. 452 * b=<bwtype>:<bandwidth> 453 */ 454 int 455 sdp_add_bandwidth(sdp_bandwidth_t **bw, const char *type, uint64_t value) 456 { 457 sdp_bandwidth_t *new_bw; 458 sdp_bandwidth_t *tmp; 459 int ret = 0; 460 461 if (bw == NULL || type == NULL) 462 return (EINVAL); 463 new_bw = calloc(1, sizeof (sdp_bandwidth_t)); 464 if (new_bw == NULL) 465 return (ENOMEM); 466 new_bw->b_value = value; 467 if ((ret = commp_add_str(&new_bw->b_type, type, strlen(type))) != 0) { 468 free(new_bw); 469 return (ret); 470 } 471 if (*bw == NULL) { 472 *bw = new_bw; 473 } else { 474 tmp = *bw; 475 while (tmp->b_next != NULL) 476 tmp = tmp->b_next; 477 tmp->b_next = new_bw; 478 } 479 return (ret); 480 } 481 482 /* 483 * Adds time field to the session 484 * t=<start-time> <stop-time> 485 */ 486 int 487 sdp_add_time(sdp_session_t *session, uint64_t starttime, uint64_t stoptime, 488 sdp_time_t **time) 489 { 490 sdp_time_t *new_time; 491 sdp_time_t *tmp; 492 493 if (time != NULL) 494 *time = NULL; 495 if (session == NULL) { 496 return (EINVAL); 497 } 498 new_time = calloc(1, sizeof (sdp_time_t)); 499 if (new_time == NULL) { 500 return (ENOMEM); 501 } 502 new_time->t_start = starttime; 503 new_time->t_stop = stoptime; 504 tmp = session->s_time; 505 if (tmp == NULL) 506 session->s_time = new_time; 507 else { 508 while (tmp->t_next != NULL) 509 tmp = tmp->t_next; 510 tmp->t_next = new_time; 511 } 512 if (time != NULL) 513 *time = new_time; 514 return (0); 515 } 516 517 /* 518 * Adds repeat field to the time structure of session 519 * r=<repeat interval> <active duration> <offsets from start-time> 520 */ 521 int 522 sdp_add_repeat(sdp_time_t *time, uint64_t interval, uint64_t duration, 523 const char *offset) 524 { 525 sdp_repeat_t *tmp; 526 sdp_repeat_t *new_repeat; 527 int ret = 0; 528 529 if (time == NULL || offset == NULL) 530 return (EINVAL); 531 new_repeat = calloc(1, sizeof (sdp_repeat_t)); 532 if (new_repeat == NULL) 533 return (ENOMEM); 534 new_repeat->r_interval = interval; 535 new_repeat->r_duration = duration; 536 if ((ret = sdp_str_to_list(&new_repeat->r_offset, offset, 537 strlen(offset), B_FALSE)) != 0) { 538 goto err_ret; 539 } 540 tmp = time->t_repeat; 541 if (tmp == NULL) { 542 time->t_repeat = new_repeat; 543 } else { 544 while (tmp->r_next != NULL) 545 tmp = tmp->r_next; 546 tmp->r_next = new_repeat; 547 } 548 return (ret); 549 err_ret: 550 sdp_free_repeat(new_repeat); 551 return (ret); 552 } 553 554 /* 555 * Adds time zone field to the session 556 * z=<adjustment time> <offset> <adjustment time> <offset> .... 557 */ 558 int 559 sdp_add_zone(sdp_session_t *session, uint64_t time, const char *offset) 560 { 561 sdp_zone_t *new_zone; 562 sdp_zone_t *tmp; 563 int ret = 0; 564 565 if (session == NULL || offset == NULL) 566 return (EINVAL); 567 new_zone = calloc(1, sizeof (sdp_zone_t)); 568 if (new_zone == NULL) 569 return (ENOMEM); 570 new_zone->z_time = time; 571 if ((ret = commp_add_str(&new_zone->z_offset, offset, 572 strlen(offset))) != 0) { 573 free(new_zone); 574 return (ret); 575 } 576 tmp = session->s_zone; 577 if (tmp == NULL) { 578 session->s_zone = new_zone; 579 } else { 580 while (tmp->z_next != NULL) { 581 tmp = tmp->z_next; 582 } 583 tmp->z_next = new_zone; 584 } 585 return (ret); 586 } 587 588 /* 589 * Adds key field to session or media section of SDP. 590 * k=<method> 591 * k=<method>:<encryption key> 592 */ 593 int 594 sdp_add_key(sdp_key_t **key, const char *method, const char *enckey) 595 { 596 int ret = 0; 597 598 if (key == NULL || method == NULL) 599 return (EINVAL); 600 if (*key != NULL) 601 return (EPROTO); 602 *key = calloc(1, sizeof (sdp_key_t)); 603 if (*key == NULL) 604 return (ENOMEM); 605 if ((ret = commp_add_str(&((*key)->k_method), method, 606 strlen(method))) != 0) { 607 goto err_ret; 608 } 609 if (enckey != NULL) { 610 if ((ret = commp_add_str(&((*key)->k_enckey), enckey, 611 strlen(enckey))) != 0) { 612 goto err_ret; 613 } 614 } 615 return (ret); 616 err_ret: 617 sdp_free_key(*key); 618 *key = NULL; 619 return (ret); 620 } 621 622 /* 623 * Adds attribute field to session or media section of SDP. 624 * a=<attribute> 625 * a=<attribute>:<value> 626 */ 627 int 628 sdp_add_attribute(sdp_attr_t **attr, const char *name, const char *value) 629 { 630 sdp_attr_t *tmp; 631 sdp_attr_t *new_attr; 632 int ret = 0; 633 634 if (attr == NULL || name == NULL) 635 return (EINVAL); 636 new_attr = calloc(1, sizeof (sdp_attr_t)); 637 if (new_attr == NULL) 638 return (ENOMEM); 639 if ((ret = commp_add_str(&new_attr->a_name, name, strlen(name))) != 0) 640 goto err_ret; 641 if (value != NULL) { 642 if ((ret = commp_add_str(&new_attr->a_value, value, 643 strlen(value))) != 0) { 644 goto err_ret; 645 } 646 } 647 tmp = *attr; 648 if (tmp == NULL) { 649 *attr = new_attr; 650 } else { 651 while (tmp->a_next != NULL) 652 tmp = tmp->a_next; 653 tmp->a_next = new_attr; 654 } 655 return (ret); 656 err_ret: 657 sdp_free_attribute(new_attr); 658 return (ret); 659 } 660 661 /* 662 * Adds media field to the session. 663 * m=<media> <port>[/portcount] <proto> <fmt> ... 664 */ 665 int 666 sdp_add_media(sdp_session_t *session, const char *name, uint_t port, 667 int portcount, const char *protocol, const char *fmt, sdp_media_t **media) 668 { 669 sdp_media_t *tmp; 670 sdp_media_t *new_media; 671 int ret = 0; 672 673 if (media != NULL) 674 *media = NULL; 675 if (session == NULL || name == NULL || protocol == NULL || 676 portcount <= 0 || fmt == NULL) { 677 return (EINVAL); 678 } 679 new_media = calloc(1, sizeof (sdp_media_t)); 680 if (new_media == NULL) { 681 return (ENOMEM); 682 } 683 new_media->m_session = session; 684 new_media->m_port = port; 685 new_media->m_portcount = portcount; 686 if ((ret = commp_add_str(&new_media->m_name, name, strlen(name))) != 0) 687 goto err_ret; 688 if ((ret = commp_add_str(&new_media->m_proto, protocol, 689 strlen(protocol))) != 0) { 690 goto err_ret; 691 } 692 if ((ret = sdp_str_to_list(&new_media->m_format, fmt, 693 strlen(fmt), B_TRUE)) != 0) { 694 goto err_ret; 695 } 696 tmp = session->s_media; 697 if (tmp == NULL) { 698 session->s_media = new_media; 699 } else { 700 while (tmp->m_next != NULL) 701 tmp = tmp->m_next; 702 tmp->m_next = new_media; 703 } 704 if (media != NULL) 705 *media = new_media; 706 return (0); 707 err_ret: 708 sdp_free_media(new_media); 709 return (ret); 710 } 711 712 /* 713 * This internal API is required by sdp_session_to_str(). It determines the 714 * length of buffer that is required to hold the session. Since the RFC does 715 * not limit the size of various sub-fields in the field. We need to scan 716 * through the structure to determine the length. 717 */ 718 int 719 sdp_get_length(const sdp_session_t *session) 720 { 721 int len = 0; 722 char buf[1]; 723 sdp_list_t *list; 724 sdp_conn_t *conn; 725 sdp_bandwidth_t *bw; 726 sdp_zone_t *zone; 727 sdp_time_t *time; 728 sdp_repeat_t *repeat; 729 sdp_attr_t *attr; 730 sdp_media_t *media; 731 732 len += FIELD_EQUALS_CRLF_LEN; 733 len += snprintf(buf, 1, "%d", session->s_version); 734 if (session->s_origin != NULL) { 735 len += FIELD_EQUALS_CRLF_LEN; 736 len += strlen(session->s_origin->o_username); 737 len += snprintf(buf, 1, "%llu", session->s_origin->o_id) + 1; 738 len += snprintf(buf, 1, "%llu", session->s_origin->o_version) 739 + 1; 740 len += strlen(session->s_origin->o_nettype) + 1; 741 len += strlen(session->s_origin->o_addrtype) + 1; 742 len += strlen(session->s_origin->o_address) + 1; 743 } 744 if (session->s_name != NULL) 745 len += strlen(session->s_name) + FIELD_EQUALS_CRLF_LEN; 746 if (session->s_info != NULL) 747 len += strlen(session->s_info) + FIELD_EQUALS_CRLF_LEN; 748 if (session->s_uri != NULL) 749 len += strlen(session->s_uri) + FIELD_EQUALS_CRLF_LEN; 750 list = session->s_email; 751 while (list != NULL) { 752 len += strlen((char *)list->value) + FIELD_EQUALS_CRLF_LEN; 753 list = list->next; 754 } 755 list = session->s_phone; 756 while (list != NULL) { 757 len += strlen((char *)list->value) + FIELD_EQUALS_CRLF_LEN; 758 list = list->next; 759 } 760 conn = session->s_conn; 761 SDP_LEN_CONNECTION(conn); 762 bw = session->s_bw; 763 SDP_LEN_BANDWIDTH(bw); 764 time = session->s_time; 765 while (time != NULL) { 766 len += FIELD_EQUALS_CRLF_LEN; 767 len += snprintf(buf, 1, "%llu", time->t_start); 768 len += snprintf(buf, 1, "%llu", time->t_stop) + 1; 769 repeat = time->t_repeat; 770 while (repeat != NULL) { 771 len += FIELD_EQUALS_CRLF_LEN; 772 len += snprintf(buf, 1, "%llu", repeat->r_interval); 773 len += snprintf(buf, 1, "%llu", repeat->r_duration) + 1; 774 list = repeat->r_offset; 775 while (list != NULL) { 776 len += snprintf(buf, 1, "%llu", 777 *(uint64_t *)list->value) + 1; 778 list = list->next; 779 } 780 repeat = repeat->r_next; 781 } 782 time = time->t_next; 783 } 784 if (session->s_zone != NULL) 785 len += FIELD_EQUALS_CRLF_LEN; 786 zone = session->s_zone; 787 while (zone != NULL) { 788 len += snprintf(buf, 1, "%llu", zone->z_time) + 1; 789 len += strlen(zone->z_offset) + 1; 790 zone = zone->z_next; 791 } 792 SDP_LEN_KEY(session->s_key); 793 attr = session->s_attr; 794 SDP_LEN_ATTRIBUTE(attr); 795 media = session->s_media; 796 while (media != NULL) { 797 len += FIELD_EQUALS_CRLF_LEN; 798 len += strlen(media->m_name); 799 len += snprintf(buf, 1, "%u", media->m_port) + 1; 800 len += snprintf(buf, 1, "%d", media->m_portcount) + 1; 801 len += strlen(media->m_proto) + 1; 802 list = media->m_format; 803 while (list != NULL) { 804 len += strlen((char *)list->value) + 1; 805 list = list->next; 806 } 807 if (media->m_info != NULL) 808 len += strlen(media->m_info) + FIELD_EQUALS_CRLF_LEN; 809 conn = media->m_conn; 810 SDP_LEN_CONNECTION(conn); 811 bw = media->m_bw; 812 SDP_LEN_BANDWIDTH(bw); 813 SDP_LEN_KEY(media->m_key); 814 attr = media->m_attr; 815 SDP_LEN_ATTRIBUTE(attr); 816 media = media->m_next; 817 } 818 return (len); 819 } 820 821 /* 822 * Given a session structure it clones (deep copy) and returns the cloned copy 823 */ 824 sdp_session_t * 825 sdp_clone_session(const sdp_session_t *session) 826 { 827 sdp_session_t *new_sess; 828 sdp_origin_t *origin; 829 sdp_list_t *list; 830 sdp_time_t *time; 831 sdp_time_t *new_time; 832 sdp_repeat_t *repeat; 833 sdp_media_t *media; 834 sdp_media_t *new_media; 835 sdp_conn_t *conn; 836 sdp_bandwidth_t *bw; 837 sdp_attr_t *attr; 838 sdp_zone_t *zone; 839 char *offset = NULL; 840 char *format = NULL; 841 842 if (session == NULL) 843 return (NULL); 844 new_sess = calloc(1, sizeof (sdp_session_t)); 845 if (new_sess == NULL) 846 return (NULL); 847 new_sess->sdp_session_version = session->sdp_session_version; 848 new_sess->s_version = session->s_version; 849 origin = session->s_origin; 850 if (origin != NULL && (sdp_add_origin(new_sess, origin->o_username, 851 origin->o_id, origin->o_version, origin->o_nettype, origin-> 852 o_addrtype, origin->o_address) != 0)) { 853 goto err_ret; 854 } 855 if (session->s_name != NULL && sdp_add_name(new_sess, session-> 856 s_name) != 0) { 857 goto err_ret; 858 } 859 if (session->s_info != NULL && sdp_add_information(&new_sess-> 860 s_info, session->s_info) != 0) { 861 goto err_ret; 862 } 863 if (session->s_uri != NULL && sdp_add_uri(new_sess, session-> 864 s_uri) != 0) { 865 goto err_ret; 866 } 867 list = session->s_email; 868 while (list != NULL) { 869 if (sdp_add_email(new_sess, (char *)list->value) != 0) 870 goto err_ret; 871 list = list->next; 872 } 873 list = session->s_phone; 874 while (list != NULL) { 875 if (sdp_add_phone(new_sess, (char *)list->value) != 0) 876 goto err_ret; 877 list = list->next; 878 } 879 conn = session->s_conn; 880 SDP_ADD_CONNECTION(new_sess->s_conn, conn); 881 bw = session->s_bw; 882 SDP_ADD_BANDWIDTH(new_sess->s_bw, bw); 883 time = session->s_time; 884 while (time != NULL) { 885 if (sdp_add_time(new_sess, time->t_start, time->t_stop, 886 &new_time) != 0) { 887 goto err_ret; 888 } 889 repeat = time->t_repeat; 890 while (repeat != NULL) { 891 if (sdp_list_to_str(repeat->r_offset, &offset, 892 B_FALSE) != 0) { 893 goto err_ret; 894 } 895 if (sdp_add_repeat(new_time, repeat->r_interval, 896 repeat->r_duration, offset) != 0) { 897 free(offset); 898 goto err_ret; 899 } 900 free(offset); 901 repeat = repeat->r_next; 902 } 903 time = time->t_next; 904 } 905 zone = session->s_zone; 906 while (zone != NULL) { 907 if (sdp_add_zone(new_sess, zone->z_time, zone->z_offset) != 0) 908 goto err_ret; 909 zone = zone->z_next; 910 } 911 SDP_ADD_KEY(new_sess->s_key, session->s_key); 912 attr = session->s_attr; 913 SDP_ADD_ATTRIBUTE(new_sess->s_attr, attr); 914 media = session->s_media; 915 while (media != NULL) { 916 if (sdp_list_to_str(media->m_format, &format, B_TRUE) != 0) 917 goto err_ret; 918 if (sdp_add_media(new_sess, media->m_name, 919 media->m_port, media->m_portcount, media->m_proto, 920 format, &new_media) != 0) { 921 free(format); 922 goto err_ret; 923 } 924 free(format); 925 if (media->m_info != NULL) { 926 if (sdp_add_information(&new_media->m_info, 927 media->m_info) != 0) { 928 goto err_ret; 929 } 930 } 931 conn = media->m_conn; 932 SDP_ADD_CONNECTION(new_media->m_conn, conn); 933 bw = media->m_bw; 934 SDP_ADD_BANDWIDTH(new_media->m_bw, bw); 935 SDP_ADD_KEY(new_media->m_key, media->m_key); 936 attr = media->m_attr; 937 SDP_ADD_ATTRIBUTE(new_media->m_attr, attr); 938 new_media->m_session = new_sess; 939 media = media->m_next; 940 } 941 return (new_sess); 942 err_ret: 943 sdp_free_session(new_sess); 944 return (NULL); 945 } 946 947 /* 948 * should i check if individual members are NULL, if not snprintf 949 * will core dump. 950 */ 951 /* 952 * Given a session structure, this API converts it into character 953 * buffer, which will be used as a payload later on. 954 */ 955 char * 956 sdp_session_to_str(const sdp_session_t *session, int *error) 957 { 958 char *ret = NULL; 959 char *buf = NULL; 960 int len = 0; 961 int s_len = 0; 962 int wrote = 0; 963 sdp_origin_t *origin; 964 sdp_list_t *list; 965 sdp_conn_t *conn; 966 sdp_attr_t *attr; 967 sdp_bandwidth_t *bw; 968 sdp_time_t *time; 969 sdp_repeat_t *repeat; 970 sdp_zone_t *zone; 971 sdp_media_t *media; 972 973 if (error != NULL) 974 *error = 0; 975 if (session == NULL) { 976 if (error != NULL) 977 *error = EINVAL; 978 return (NULL); 979 } 980 s_len = sdp_get_length(session); 981 ret = malloc(s_len + 1); 982 if (ret == NULL) { 983 if (error != NULL) 984 *error = ENOMEM; 985 return (NULL); 986 } 987 buf = ret; 988 len = s_len + 1; 989 wrote = snprintf(buf, len, "v=%d%s", session->s_version, COMMP_CRLF); 990 len = len - wrote; 991 buf = buf + wrote; 992 origin = session->s_origin; 993 if (origin != NULL) { 994 wrote = snprintf(buf, len, "o=%s %llu %llu %s %s %s%s", 995 origin->o_username, origin->o_id, origin->o_version, 996 origin->o_nettype, origin->o_addrtype, origin->o_address, 997 COMMP_CRLF); 998 len = len - wrote; 999 buf = buf + wrote; 1000 } 1001 if (session->s_name != NULL) { 1002 wrote = snprintf(buf, len, "s=%s%s", session->s_name, 1003 COMMP_CRLF); 1004 len = len - wrote; 1005 buf = buf + wrote; 1006 } 1007 SDP_INFORMATION_TO_STR(session->s_info); 1008 if (session->s_uri != NULL) { 1009 wrote = snprintf(buf, len, "u=%s%s", session->s_uri, 1010 COMMP_CRLF); 1011 len = len - wrote; 1012 buf = buf + wrote; 1013 } 1014 list = session->s_email; 1015 while (list != NULL) { 1016 wrote = snprintf(buf, len, "e=%s%s", (char *)list->value, 1017 COMMP_CRLF); 1018 len = len - wrote; 1019 buf = buf + wrote; 1020 list = list->next; 1021 } 1022 list = session->s_phone; 1023 while (list != NULL) { 1024 wrote = snprintf(buf, len, "p=%s%s", (char *)list->value, 1025 COMMP_CRLF); 1026 len = len - wrote; 1027 buf = buf + wrote; 1028 list = list->next; 1029 } 1030 conn = session->s_conn; 1031 SDP_CONNECTION_TO_STR(conn); 1032 bw = session->s_bw; 1033 SDP_BANDWIDTH_TO_STR(bw); 1034 time = session->s_time; 1035 while (time != NULL) { 1036 wrote = snprintf(buf, len, "t=%llu %llu%s", time->t_start, 1037 time->t_stop, COMMP_CRLF); 1038 len = len - wrote; 1039 buf = buf + wrote; 1040 repeat = time->t_repeat; 1041 while (repeat != NULL) { 1042 wrote = snprintf(buf, len, "r=%llu %llu", repeat-> 1043 r_interval, repeat->r_duration); 1044 len = len - wrote; 1045 buf = buf + wrote; 1046 list = repeat->r_offset; 1047 while (list != NULL) { 1048 wrote = snprintf(buf, len, " %llu", 1049 *(uint64_t *)list->value); 1050 len = len - wrote; 1051 buf = buf + wrote; 1052 list = list->next; 1053 } 1054 wrote = snprintf(buf, len, "%s", COMMP_CRLF); 1055 len = len - wrote; 1056 buf = buf + wrote; 1057 repeat = repeat->r_next; 1058 } 1059 time = time->t_next; 1060 } 1061 zone = session->s_zone; 1062 if (zone != NULL) { 1063 wrote = snprintf(buf, len, "z=%llu %s", zone->z_time, 1064 zone->z_offset); 1065 len = len - wrote; 1066 buf = buf + wrote; 1067 zone = zone->z_next; 1068 while (zone != NULL) { 1069 wrote = snprintf(buf, len, " %llu %s", zone->z_time, 1070 zone->z_offset); 1071 len = len - wrote; 1072 buf = buf + wrote; 1073 zone = zone->z_next; 1074 } 1075 wrote = snprintf(buf, len, "%s", COMMP_CRLF); 1076 len = len - wrote; 1077 buf = buf + wrote; 1078 } 1079 SDP_KEY_TO_STR(session->s_key); 1080 attr = session->s_attr; 1081 SDP_ATTR_TO_STR(attr); 1082 media = session->s_media; 1083 while (media != NULL) { 1084 if (media->m_portcount == 1) { 1085 wrote = snprintf(buf, len, "m=%s %d %s", media->m_name, 1086 media->m_port, media->m_proto); 1087 } else { 1088 wrote = snprintf(buf, len, "m=%s %d/%d %s", media-> 1089 m_name, media->m_port, media->m_portcount, media-> 1090 m_proto); 1091 } 1092 len = len - wrote; 1093 buf = buf + wrote; 1094 list = media->m_format; 1095 while (list != NULL) { 1096 wrote = snprintf(buf, len, " %s", (char *)list->value); 1097 len = len - wrote; 1098 buf = buf + wrote; 1099 list = list->next; 1100 } 1101 wrote = snprintf(buf, len, "%s", COMMP_CRLF); 1102 len = len - wrote; 1103 buf = buf + wrote; 1104 SDP_INFORMATION_TO_STR(media->m_info); 1105 conn = media->m_conn; 1106 SDP_CONNECTION_TO_STR(conn); 1107 bw = media->m_bw; 1108 SDP_BANDWIDTH_TO_STR(bw); 1109 SDP_KEY_TO_STR(media->m_key); 1110 attr = media->m_attr; 1111 SDP_ATTR_TO_STR(attr); 1112 media = media->m_next; 1113 } 1114 assert(len >= 1); 1115 *buf = '\0'; 1116 return (ret); 1117 } 1118 1119 /* 1120 * Given a session structure and the field ('v', 'o', 's', et al), this API 1121 * deletes the corresponding structure element. It frees the memory and sets the 1122 * pointer to NULL 1123 */ 1124 int 1125 sdp_delete_all_field(sdp_session_t *session, const char field) 1126 { 1127 if (session == NULL) 1128 return (EINVAL); 1129 switch (field) { 1130 case SDP_ORIGIN_FIELD: 1131 sdp_free_origin(session->s_origin); 1132 session->s_origin = NULL; 1133 break; 1134 case SDP_NAME_FIELD: 1135 free(session->s_name); 1136 session->s_name = NULL; 1137 break; 1138 case SDP_INFO_FIELD: 1139 free(session->s_info); 1140 session->s_info = NULL; 1141 break; 1142 case SDP_URI_FIELD: 1143 free(session->s_uri); 1144 session->s_uri = NULL; 1145 break; 1146 case SDP_EMAIL_FIELD: 1147 sdp_free_list(session->s_email); 1148 session->s_email = NULL; 1149 break; 1150 case SDP_PHONE_FIELD: 1151 sdp_free_list(session->s_phone); 1152 session->s_phone = NULL; 1153 break; 1154 case SDP_CONNECTION_FIELD: 1155 sdp_free_connection(session->s_conn); 1156 session->s_conn = NULL; 1157 break; 1158 case SDP_BANDWIDTH_FIELD: 1159 sdp_free_bandwidth(session->s_bw); 1160 session->s_bw = NULL; 1161 break; 1162 case SDP_TIME_FIELD: 1163 sdp_free_time(session->s_time); 1164 session->s_time = NULL; 1165 break; 1166 case SDP_ZONE_FIELD: 1167 sdp_free_zone(session->s_zone); 1168 session->s_zone = NULL; 1169 break; 1170 case SDP_KEY_FIELD: 1171 sdp_free_key(session->s_key); 1172 session->s_key = NULL; 1173 break; 1174 case SDP_ATTRIBUTE_FIELD: 1175 sdp_free_attribute(session->s_attr); 1176 session->s_attr = NULL; 1177 break; 1178 case SDP_MEDIA_FIELD: 1179 sdp_free_media(session->s_media); 1180 session->s_media = NULL; 1181 break; 1182 default: 1183 return (EINVAL); 1184 } 1185 return (0); 1186 } 1187 1188 /* 1189 * Given a media structure and the field ('i', 'b', 'c', et al), this API 1190 * deletes the corresponding structure element. It frees the memory and sets 1191 * the pointer to NULL. 1192 */ 1193 int 1194 sdp_delete_all_media_field(sdp_media_t *media, const char field) 1195 { 1196 if (media == NULL) 1197 return (EINVAL); 1198 switch (field) { 1199 case SDP_INFO_FIELD: 1200 free(media->m_info); 1201 media->m_info = NULL; 1202 break; 1203 case SDP_CONNECTION_FIELD: 1204 sdp_free_connection(media->m_conn); 1205 media->m_conn = NULL; 1206 break; 1207 case SDP_BANDWIDTH_FIELD: 1208 sdp_free_bandwidth(media->m_bw); 1209 media->m_bw = NULL; 1210 break; 1211 case SDP_KEY_FIELD: 1212 sdp_free_key(media->m_key); 1213 media->m_key = NULL; 1214 break; 1215 case SDP_ATTRIBUTE_FIELD: 1216 sdp_free_attribute(media->m_attr); 1217 media->m_attr = NULL; 1218 break; 1219 default: 1220 return (EINVAL); 1221 } 1222 return (0); 1223 } 1224 1225 /* 1226 * Given a media list and the media, this API deletes that media from the 1227 * list. It frees the memory corresponding to that media. 1228 */ 1229 int 1230 sdp_delete_media(sdp_media_t **l_media, sdp_media_t *media) 1231 { 1232 sdp_media_t *cur; 1233 sdp_media_t *prev; 1234 1235 if (l_media == NULL || *l_media == NULL || media == NULL) 1236 return (EINVAL); 1237 cur = *l_media; 1238 prev = NULL; 1239 while (cur != NULL && cur != media) { 1240 prev = cur; 1241 cur = cur->m_next; 1242 } 1243 if (cur == NULL) 1244 return (EINVAL); 1245 if (cur == *l_media) 1246 *l_media = cur->m_next; 1247 else 1248 prev->m_next = cur->m_next; 1249 cur->m_next = NULL; 1250 sdp_free_media(cur); 1251 return (0); 1252 } 1253 1254 /* 1255 * Given an attribute list and an attribute, this API deletes that attribue 1256 * from the list. It frees the memory corresponding to that attribute. 1257 */ 1258 int 1259 sdp_delete_attribute(sdp_attr_t **l_attr, sdp_attr_t *attr) 1260 { 1261 sdp_attr_t *cur; 1262 sdp_attr_t *prev; 1263 1264 if (l_attr == NULL || *l_attr == NULL || attr == NULL) 1265 return (EINVAL); 1266 cur = *l_attr; 1267 prev = NULL; 1268 while (cur != NULL && cur != attr) { 1269 prev = cur; 1270 cur = cur->a_next; 1271 } 1272 if (cur == NULL) 1273 return (EINVAL); 1274 if (cur == *l_attr) 1275 *l_attr = cur->a_next; 1276 else 1277 prev->a_next = cur->a_next; 1278 cur->a_next = NULL; 1279 sdp_free_attribute(cur); 1280 return (0); 1281 } 1282 1283 /* 1284 * Allocates a new sdp session structure and assigns a version number to it. 1285 * Currently one version is defined and it is 1. This will be useful in future 1286 * in the unlikely need to change the structure. 1287 */ 1288 sdp_session_t * 1289 sdp_new_session() 1290 { 1291 sdp_session_t *session = NULL; 1292 1293 session = calloc(1, sizeof (sdp_session_t)); 1294 if (session != NULL) 1295 session->sdp_session_version = SDP_SESSION_VERSION_1; 1296 return (session); 1297 } 1298