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 *
sdp_find_media(sdp_media_t * media,const char * name)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 *
sdp_find_attribute(sdp_attr_t * attr,const char * name)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 *
sdp_find_media_rtpmap(sdp_media_t * media,const char * format)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
sdp_add_origin(sdp_session_t * session,const char * name,uint64_t id,uint64_t ver,const char * nettype,const char * addrtype,const char * address)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
sdp_add_name(sdp_session_t * session,const char * name)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
sdp_add_information(char ** information,const char * value)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
sdp_add_uri(sdp_session_t * session,const char * uri)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
sdp_add_email(sdp_session_t * session,const char * email)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
sdp_add_phone(sdp_session_t * session,const char * phone)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
sdp_add_connection(sdp_conn_t ** conn,const char * nettype,const char * addrtype,const char * address,uint8_t ttl,int addrcount)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
sdp_add_bandwidth(sdp_bandwidth_t ** bw,const char * type,uint64_t value)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
sdp_add_time(sdp_session_t * session,uint64_t starttime,uint64_t stoptime,sdp_time_t ** time)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
sdp_add_repeat(sdp_time_t * time,uint64_t interval,uint64_t duration,const char * offset)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
sdp_add_zone(sdp_session_t * session,uint64_t time,const char * offset)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
sdp_add_key(sdp_key_t ** key,const char * method,const char * enckey)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
sdp_add_attribute(sdp_attr_t ** attr,const char * name,const char * value)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
sdp_add_media(sdp_session_t * session,const char * name,uint_t port,int portcount,const char * protocol,const char * fmt,sdp_media_t ** media)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
sdp_get_length(const sdp_session_t * session)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 *
sdp_clone_session(const sdp_session_t * session)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 *
sdp_session_to_str(const sdp_session_t * session,int * error)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
sdp_delete_all_field(sdp_session_t * session,const char field)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
sdp_delete_all_media_field(sdp_media_t * media,const char field)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
sdp_delete_media(sdp_media_t ** l_media,sdp_media_t * media)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
sdp_delete_attribute(sdp_attr_t ** l_attr,sdp_attr_t * attr)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 *
sdp_new_session()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