1 /*
2 * FILE: sdp.c
3 * AUTHOR: Ivan R. Judson <judson@mcs.anl.gov>
4 *
5 * The routines in this file implement parsing and construction of data
6 * that's compliant with the Session Description Protocol, as specified
7 * in RFC draft-ietf-mmusic-sdp-new-08.
8 *
9 * $Revision: 1.2 $
10 * $Date: 2003/05/28 11:36:50 $
11 *
12 * Copyright (c) 2002 Argonne National Laboratory/University of Chicago
13 * All rights reserved.
14 *
15 * Redistribution and use in source and binary forms, with or without
16 * modification, is permitted provided that the following conditions
17 * are met:
18 * 1. Redistributions of source code must retain the above copyright
19 * notice, this list of conditions and the following disclaimer.
20 * 2. Redistributions in binary form must reproduce the above copyright
21 * notice, this list of conditions and the following disclaimer in the
22 * documentation and/or other materials provided with the distribution.
23 * 3. All advertising materials mentioning features or use of this software
24 * must display the following acknowledgement:
25 * This product includes software developed by the Mathematics and
26 * Computer Science Division of Argonne National Laboratory.
27 * 4. Neither the name of the University nor of the Department may be used
28 * to endorse or promote products derived from this software without
29 * specific prior written permission.
30 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
31 * ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
32 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
34 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
35 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
36 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
37 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
38 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
39 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
40 * SUCH DAMAGE.
41 *
42 */
43
44 #include "config_unix.h"
45 #include "config_win32.h"
46 #include "debug.h"
47 #include "memory.h"
48 #include "sdp.h"
49
50 int
sdp_check_key(char keylist[],char * currentkey,char key)51 sdp_check_key(char keylist[], char *currentkey, char key)
52 {
53 char *tempkey = keylist;
54
55 while(*tempkey != key)
56 if(*tempkey != keylist[strlen(keylist)])
57 tempkey++;
58 else
59 return 0;
60
61 if(tempkey >= currentkey) {
62 currentkey = tempkey;
63 return 1;
64 } else {
65 return 0;
66 }
67 }
68
69
70 sdp_media *
sdp_handle_session_key(sdp * session,char key,char * value)71 sdp_handle_session_key(sdp *session, char key, char *value)
72 {
73 sdp_media *media = NULL, *curr_media = NULL;
74 sdp_repeat *repeat = NULL, *curr_repeat = NULL;
75 sdp_timezone *timezone = NULL;
76 sdp_network *network = NULL;
77 sdp_bandwidth_modifier *bwm;
78 sdp_attribute *attr, *curr_attr;
79 sdp_encryption *encrypt;
80 unsigned int n_char;
81
82 switch (key) {
83 case 'v':
84 session->protocol_version = atoi(value);
85 break;
86 case 'o':
87 network = xmalloc(sizeof(sdp_network));
88 memset (network, 0, sizeof(sdp_network));
89
90 sscanf(value, "%as %as %ld %as %as %as\n",
91 &(session->username),&(session->session_id), &(session->version),
92 &(network->network_type), &(network->address_type),
93 &(network->address));
94
95 network->number_of_addresses = 1;
96 session->network = network;
97
98 break;
99 case 's':
100 session->name = xstrdup(value);
101 break;
102 case 'i':
103 session->information = xstrdup(value);
104 break;
105 case 'u':
106 session->uri = xstrdup(value);
107 break;
108 case 'e':
109 session->email = xstrdup(value);
110 break;
111 case 'p':
112 session->phone = xstrdup(value);
113 break;
114 case 'c':
115 network = xmalloc(sizeof(sdp_network));
116 memset (network, 0, sizeof(sdp_network));
117
118 sscanf(value, "%as %as %as\n", &(network->network_type),
119 &(network->address_type), &(network->address));
120
121 network->number_of_addresses = 1;
122
123 if(session->network != NULL)
124 session->network = network;
125 else
126 xfree(network);
127
128 break;
129 case 'b':
130 bwm = xmalloc(sizeof(sdp_bandwidth_modifier));
131 memset (bwm, 0, sizeof(sdp_bandwidth_modifier));
132
133 sscanf(value, "%a[^:]:%a[^\n]", &(bwm->modifier), &(bwm->value));
134
135 if(session->bandwidth_modifier == NULL)
136 session->bandwidth_modifier = bwm;
137 else
138 xfree(bwm);
139
140 break;
141 case 't':
142 sscanf(value, "%ld %ld\n", &(session->start_time), &(session->stop_time));
143
144 break;
145 case 'r':
146 repeat = xmalloc(sizeof(sdp_repeat));
147 memset (repeat, 0, sizeof(sdp_repeat));
148
149 sscanf(value, "%as %as %as\n", &(repeat->interval), &(repeat->duration),
150 &(repeat->offsets));
151
152 if(session->repeats == NULL)
153 session->repeats = repeat;
154 else {
155 curr_repeat = session->repeats;
156 while(curr_repeat != NULL)
157 curr_repeat = curr_repeat->next;
158 curr_repeat->next = repeat;
159 }
160 break;
161 case 'z':
162 /* This is icky but for now... */
163 timezone = xmalloc(sizeof(sdp_timezone));
164 memset(timezone, 0, sizeof(sdp_timezone));
165
166 sscanf(value, "%ld %ld", &(timezone->adjustment), &(timezone->offset));
167
168 session->timezones = timezone;
169 break;
170 case 'k':
171 encrypt = xmalloc(sizeof(sdp_encryption));
172 memset(encrypt, 0, sizeof(sdp_encryption));
173
174 sscanf(value, "%a[^:]:%a[^\n]", &(encrypt->method), &(encrypt->key));
175
176 if(session->encryption == NULL)
177 session->encryption = encrypt;
178 else
179 xfree(encrypt);
180
181 break;
182 case 'a':
183 attr = xmalloc(sizeof(sdp_attribute));
184 memset(attr, 0, sizeof(sdp_attribute));
185
186 n_char = strcspn(value, ":");
187
188 attr->key = xmalloc(n_char+1);
189 memset(attr->key, '\0', n_char+1);
190 strncpy(attr->key, value, n_char);
191
192 if(strlen(value) == n_char)
193 attr->value = NULL;
194 else {
195 attr->value = xmalloc(strlen(value) - n_char + 1);
196 memset(attr->value, '\0', strlen(value) - n_char + 1);
197 strncpy(attr->value, value+n_char+1, strlen(value) - n_char);
198 }
199
200 if(session->attributes == NULL)
201 session->attributes = attr;
202 else {
203 curr_attr = session->attributes;
204 while(curr_attr->next != NULL)
205 curr_attr = curr_attr->next;
206
207 curr_attr->next = attr;
208 }
209 break;
210 case 'm':
211 media = xmalloc(sizeof(sdp_media));
212 memset(media, 0, sizeof(sdp_media));
213 sscanf(value, "%as %d %as %as\n", &(media->name),
214 &(media->port), &(media->transport),
215 &(media->format_list));
216 media->number_of_ports = 1;
217
218 if(session->media == NULL)
219 session->media = media;
220 else {
221 curr_media = session->media;
222 while(curr_media->next != NULL)
223 curr_media = curr_media->next;
224
225 curr_media->next = media;
226 }
227 break;
228 }
229
230 return media;
231 }
232
233 sdp_media *
sdp_handle_media_key(sdp_media * media,char key,char * value)234 sdp_handle_media_key(sdp_media *media, char key, char *value)
235 {
236 sdp_media *new_media;
237 sdp_network *network;
238 sdp_bandwidth_modifier *bwm;
239 sdp_attribute *attr, *curr_attr;
240 sdp_encryption *encrypt;
241 unsigned int n_char;
242
243 switch (key) {
244 case 'i':
245 media->information = xstrdup(value);
246 break;
247 case 'c':
248 network = xmalloc(sizeof(sdp_network));
249 memset (network, 0, sizeof(sdp_network));
250
251 sscanf(value, "%as %as %as\n", &(network->network_type),
252 &(network->address_type), &(network->address));
253
254 network->number_of_addresses = 1;
255
256 if(media->network == NULL)
257 media->network = network;
258 else
259 xfree(network);
260
261 break;
262 case 'b':
263 bwm = xmalloc(sizeof(sdp_bandwidth_modifier));
264 memset (bwm, 0, sizeof(sdp_bandwidth_modifier));
265
266 sscanf(value, "%as:%as\n", &(bwm->modifier), &(bwm->value));
267
268 if(media->bandwidth_modifier == NULL)
269 media->bandwidth_modifier = bwm;
270 else
271 xfree(bwm);
272
273 break;
274 case 'k':
275 encrypt = xmalloc(sizeof(sdp_encryption));
276 memset(encrypt, 0, sizeof(sdp_encryption));
277
278 sscanf(value, "%as:%as\n", &(encrypt->method), &(encrypt->key));
279
280 if(media->encryption == NULL)
281 media->encryption = encrypt;
282 else
283 xfree(encrypt);
284
285 break;
286 case 'a':
287 attr = xmalloc(sizeof(sdp_attribute));
288 memset(attr, 0, sizeof(sdp_attribute));
289
290 n_char = strcspn(value, ":");
291
292 attr->key = xmalloc(n_char+1);
293 memset(attr->key, '\0', n_char+1);
294 strncpy(attr->key, value, n_char);
295
296 if(strlen(value) == n_char)
297 attr->value = NULL;
298 else {
299 attr->value = xmalloc(strlen(value) - n_char + 1);
300 memset(attr->value, '\0', strlen(value) - n_char + 1);
301 strncpy(attr->value, value+n_char+1, strlen(value) - n_char);
302 }
303
304 if(media->attributes == NULL)
305 media->attributes = attr;
306 else {
307 curr_attr = media->attributes;
308 while(curr_attr->next != NULL)
309 curr_attr = curr_attr->next;
310
311 curr_attr->next = attr;
312 }
313 break;
314 case 'm':
315 new_media = xmalloc(sizeof(sdp_media));
316 memset(new_media, 0, sizeof(sdp_media));
317 sscanf(value, "%as %d %as %as\n", &(new_media->name),
318 &(new_media->port), &(new_media->transport),
319 &(new_media->format_list));
320 new_media->number_of_ports = 1;
321
322 media->next = new_media;
323 media = media->next;
324 break;
325 }
326
327 return media;
328 }
329
sdp_parse(char * sdp_string)330 sdp *sdp_parse(char *sdp_string)
331 {
332 static char sessionkeys[] = "vosiuepcbtrzkam";
333 static char mediakeys[] = "micbka";
334 static char *current_key;
335 int goodkey = 0;
336 sdp_media *media = NULL;
337 char *line = NULL, key, *value = NULL;
338 static char *pos;
339 sdp *session = NULL;
340 int n_char;
341
342 if(sdp_string != NULL) {
343 current_key = sessionkeys;
344 session = xmalloc(sizeof(sdp));
345 memset (session, 0, sizeof(sdp));
346
347 session->original = xstrdup(sdp_string);
348
349 pos = sdp_string;
350
351 do {
352 n_char = strcspn(pos, "\n");
353
354 line = xmalloc(n_char+1);
355 memset(line, '\0', n_char+1);
356 strncpy(line, pos, n_char);
357 pos += n_char + 1;
358
359 if(strchr(line, '=') != NULL) {
360 key = line[0];
361 value = &(line[2]);
362
363 if(media == NULL) {
364 if((goodkey = sdp_check_key(sessionkeys, current_key, key)) == 1)
365 media = sdp_handle_session_key(session, key, value);
366 else
367 printf("Bad Session Key!\n");
368 } else {
369 if((goodkey = sdp_check_key(mediakeys, current_key, key)) == 1)
370 media = sdp_handle_media_key(media, key, value);
371 else
372 printf("Bad Media Key!\n");
373 }
374 }
375 xfree(line);
376 } while (n_char != 0);
377 }
378
379 return session;
380 }
381
sdp_print(sdp * session)382 void sdp_print(sdp *session)
383 {
384 if(session != NULL) {
385 sdp_media *current_media = session->media;
386 sdp_attribute *current_attribute = session->attributes;
387
388 printf("Protocol Version: %d\n", session->protocol_version);
389 printf("Username: %s\n", session->username);
390 printf("Session ID: %s\n", session->session_id);
391 printf("Version: %ld\n", session->version);
392 printf("Name: %s\n", session->name);
393 printf("Information: %s\n", session->information);
394 printf("URI: %s\n", session->uri);
395 printf("Email: %s\n", session->email);
396 printf("Phone: %s\n", session->phone);
397 printf("Start Time: %ld\n", session->start_time);
398 printf("Stop Time: %ld\n", session->stop_time);
399
400 if(session->network != NULL) {
401 sdp_print_network(session->network);
402 }
403
404 if(session->bandwidth_modifier != NULL) {
405 printf("Bandwidth Modifier\n");
406 printf("\tModifier: %s\n", session->bandwidth_modifier->modifier);
407 printf("\tValue: %s\n", session->bandwidth_modifier->value);
408 }
409
410 printf("Session Attributes:\n");
411 while(current_attribute != NULL) {
412 printf("\tAttribute: %s Value: %s\n",
413 current_attribute->key, current_attribute->value);
414 current_attribute = current_attribute->next;
415 }
416
417 current_media = session->media;
418 while(current_media != NULL) {
419 sdp_print_media(current_media);
420 current_media = current_media->next;
421 }
422 }
423 }
424
425 void
sdp_print_network(sdp_network * network)426 sdp_print_network(sdp_network *network)
427 {
428 printf("Network Information:\n");
429 printf("\tNetwork Type: %s\n", network->network_type);
430 printf("\tAddress Type: %s\n", network->address_type);
431 printf("\tAddress: %s\n", network->address);
432 printf("\t# of Addresses: %d\n", network->number_of_addresses);
433 }
434
435 void
sdp_print_media(sdp_media * media)436 sdp_print_media(sdp_media *media)
437 {
438 sdp_attribute *curr_attr = media->attributes;
439
440 printf("Media Configuration:\n");
441 printf("\tName: %s\n", media->name);
442 printf("\tPort: %d Number of Ports: %d\n", media->port,
443 media->number_of_ports);
444 if(media->network != NULL) {
445 sdp_print_network(media->network);
446 }
447 printf("\tTransport: %s\n", media->transport);
448 printf("\tInformation: %s\n", media->information);
449
450 if(media->attributes != NULL) {
451 printf("\tMedia Attributes:\n");
452 while(curr_attr != NULL) {
453 printf("\t\tAttribute: %s Value: %s\n", curr_attr->key,
454 curr_attr->value);
455 curr_attr = curr_attr->next;
456 }
457 }
458 }
459
460 char *
sdp_make(sdp * session)461 sdp_make(sdp *session)
462 {
463 sdp_timezone *tz;
464 sdp_attribute *attr;
465 sdp_media *media;
466 char *sdp_string;
467
468 sdp_string = xmalloc(4096);
469
470 sprintf(sdp_string, "v=%d\n", session->protocol_version);
471 sprintf(sdp_string, "%so=%s %s %ld", sdp_string,
472 session->username, session->session_id, session->version);
473 if(session->network != NULL) {
474 sprintf(sdp_string, "%s %s %s %s\n", sdp_string,
475 session->network->network_type,
476 session->network->address_type,
477 session->network->address);
478 }
479 sprintf(sdp_string, "%ss=%s\n", sdp_string, session->name);
480
481 if(session->information != NULL)
482 sprintf(sdp_string, "%si=%s\n", sdp_string, session->information);
483
484 if(session->uri != NULL)
485 sprintf(sdp_string, "%su=%s\n", sdp_string, session->uri);
486
487 if(session->email != NULL)
488 sprintf(sdp_string, "%se=%s\n", sdp_string, session->email);
489
490 if(session->phone != NULL)
491 sprintf(sdp_string, "%sp=%s\n", sdp_string, session->phone);
492
493 if(session->network != NULL)
494 sprintf(sdp_string, "%sc=%s %s %s\n", sdp_string,
495 session->network->network_type,
496 session->network->address_type,
497 session->network->address);
498
499 if(session->bandwidth_modifier != NULL)
500 sprintf(sdp_string, "%sb=%s:%s\n", sdp_string,
501 session->bandwidth_modifier->modifier,
502 session->bandwidth_modifier->value);
503
504 sprintf(sdp_string, "%st=%ld %ld\n", sdp_string,
505 session->start_time, session->stop_time);
506
507 if(session->timezones != NULL) {
508 tz = session->timezones;
509 sprintf(sdp_string, "%sz=%ld %ld", sdp_string, tz->adjustment, tz->offset);
510
511 while(tz->next != NULL) {
512 sprintf(sdp_string, "%s %ld %ld", sdp_string,
513 tz->next->adjustment, tz->next->offset);
514 tz = tz->next;
515 }
516 sprintf(sdp_string, "%s\n", sdp_string);
517 }
518
519 if(session->encryption != NULL) {
520 if(session->encryption->key == NULL)
521 sprintf(sdp_string, "%sk=%s\n", sdp_string,
522 session->encryption->method);
523 else
524 sprintf(sdp_string, "%sk=%s:%s\n", sdp_string,
525 session->encryption->method,
526 session->encryption->key);
527 }
528
529 attr = session->attributes;
530 while(attr != NULL) {
531 sprintf(sdp_string, "%sa=%s:%s\n", sdp_string,
532 attr->key, attr->value);
533 attr = attr->next;
534 }
535
536 media = session->media;
537 while(media != NULL) {
538 if(media->number_of_ports > 1)
539 sprintf(sdp_string, "%sm=%s %d/%d %s %s\n", sdp_string,
540 media->name, media->port, media->number_of_ports,
541 media->transport, media->format_list);
542 else
543 sprintf(sdp_string, "%sm=%s %d %s %s\n", sdp_string,
544 media->name, media->port, media->transport,
545 media->format_list);
546 if(media->information != NULL)
547 sprintf(sdp_string, "%si=%s\n", sdp_string, media->information);
548
549 if(media->network != NULL)
550 sprintf(sdp_string, "%sc=%s %s %s\n", sdp_string,
551 media->network->network_type,
552 media->network->address_type,
553 media->network->address);
554
555 if(media->bandwidth_modifier != NULL)
556 sprintf(sdp_string, "%sb=%s:%s\n", sdp_string,
557 media->bandwidth_modifier->modifier,
558 media->bandwidth_modifier->value);
559
560 if(media->encryption != NULL) {
561 if(media->encryption->key == NULL)
562 sprintf(sdp_string, "%sk=%s\n", sdp_string,
563 media->encryption->method);
564 else
565 sprintf(sdp_string, "%sk=%s:%s\n", sdp_string,
566 media->encryption->method,
567 media->encryption->key);
568 }
569
570 attr = media->attributes;
571 while(attr != NULL) {
572 sprintf(sdp_string, "%sa=%s:%s\n", sdp_string,
573 attr->key, attr->value);
574 attr = attr->next;
575 }
576 media = media->next;
577 }
578
579 return sdp_string;
580 }
581
582 void
sdp_free(sdp * session)583 sdp_free(sdp *session)
584 {
585 sdp_media *media, *cmedia;
586 sdp_attribute *attr, *cattr;
587 sdp_repeat *repeat, *crepeat;
588
589 if(session->username != NULL)
590 xfree(session->username);
591
592 if(session->session_id != NULL)
593 xfree(session->session_id);
594
595 if(session->network != NULL)
596 sdp_free_network(session->network);
597
598 if(session->name != NULL)
599 xfree(session->name);
600
601 if(session->information != NULL)
602 xfree(session->information);
603
604 if(session->uri != NULL)
605 xfree(session->uri);
606
607 if(session->email != NULL)
608 xfree(session->email);
609
610 if(session->phone != NULL)
611 xfree(session->phone);
612
613 if(session->bandwidth_modifier != NULL)
614 sdp_free_bandwidth_modifier(session->bandwidth_modifier);
615
616 if(session->timezones != NULL)
617 xfree(session->timezones);
618
619 if(session->encryption != NULL)
620 sdp_free_encryption(session->encryption);
621
622 repeat = session->repeats;
623 while(repeat != NULL) {
624 crepeat = repeat;
625 repeat = repeat->next;
626 sdp_free_repeat(crepeat);
627 }
628
629 attr = session->attributes;
630 while(attr != NULL) {
631 cattr = attr;
632 attr = attr->next;
633 sdp_free_attribute(cattr);
634 }
635
636 media = session->media;
637 while(media != NULL) {
638 cmedia = media;
639 media = media->next;
640 sdp_free_media(cmedia);
641 }
642
643 if(session->original != NULL)
644 xfree(session->original);
645
646 xfree(session);
647 }
648
649 void
sdp_free_network(sdp_network * network)650 sdp_free_network(sdp_network *network)
651 {
652 xfree(network->network_type);
653 xfree(network->address_type);
654 xfree(network->address);
655 xfree(network);
656 }
657
658 void
sdp_free_attribute(sdp_attribute * attr)659 sdp_free_attribute(sdp_attribute *attr)
660 {
661 xfree(attr->key);
662 if(attr->value != NULL)
663 xfree(attr->value);
664 xfree(attr);
665 }
666
667 void
sdp_free_encryption(sdp_encryption * encr)668 sdp_free_encryption(sdp_encryption *encr)
669 {
670 xfree(encr->method);
671 xfree(encr->key);
672 xfree(encr);
673 }
674
675 void
sdp_free_bandwidth_modifier(sdp_bandwidth_modifier * bwm)676 sdp_free_bandwidth_modifier(sdp_bandwidth_modifier *bwm)
677 {
678 xfree(bwm->modifier);
679 xfree(bwm->value);
680 xfree(bwm);
681 }
682
683 void
sdp_free_repeat(sdp_repeat * repeat)684 sdp_free_repeat(sdp_repeat *repeat)
685 {
686 xfree(repeat->interval);
687 xfree(repeat->duration);
688 xfree(repeat->offsets);
689 xfree(repeat);
690 }
691
692 void
sdp_free_media(sdp_media * media)693 sdp_free_media(sdp_media *media)
694 {
695 sdp_attribute *attr, *cattr;
696
697 xfree(media->name);
698
699 if(media->network != NULL)
700 sdp_free_network(media->network);
701
702 xfree(media->transport);
703 xfree(media->format_list);
704
705 if(media->information != NULL)
706 xfree(media->information);
707
708 if(media->bandwidth_modifier != NULL)
709 sdp_free_bandwidth_modifier(media->bandwidth_modifier);
710
711 if(media->encryption != NULL)
712 sdp_free_encryption(media->encryption);
713
714 attr = media->attributes;
715 while(attr != NULL) {
716 cattr = attr;
717 attr = attr->next;
718 sdp_free_attribute(cattr);
719 }
720
721 xfree(media);
722 }
723
724