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