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