1 /*
2   This file is part of FreeSDP
3   Copyright (C) 2001,2002,2003 Federico Montesino Pouzols <fedemp@altern.org>
4 
5   FreeSDP is free software; you can redistribute it and/or modify it
6   under the terms of the GNU General Public License as published by
7   the Free Software Foundation; either version 2 of the License, or
8   (at your option) any later version.
9 
10   This program is distributed in the hope that it will be useful,
11   but WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   GNU General Public License for more details.
14 
15   You should have received a copy of the GNU General Public License
16   along with this program; if not, write to the Free Software
17   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18 
19   Benjamin Zores, (C) 2006
20     added support in parser for the a=control: lines.
21     added support in parser for the a=range: lines.
22 */
23 
24 /**
25  * @file
26  *
27  * @short Parsing module implementation.
28  *
29  * This file implements the parsing routine <code>fsdp_parse</code>
30  * and the <code>fsdp_get_xxxx</code> routines that allow to get the
31  * session properties from a session description object build through
32  * the application of <code>fsdp_parse</code> to a textual SDP session
33  * description.
34  **/
35 
36 #include "parserpriv.h"
37 
38 /**
39  * \brief find the start of the next line
40  * \param c pointer to current position in string
41  * \return pointer to start of next line or NULL if illegal (i.e.
42  *         a '\r' is not followed by a '\n'
43  */
next_line(const char * c)44 static const char *next_line(const char *c) {
45   c += strcspn(c, "\n\r");
46   if (*c == 0) return c;
47   if (*c == '\r') c++;
48   if (*c == '\n')
49     return c + 1;
50   return NULL;
51 }
52 
53 /**
54  * Moves the <code>c<code> pointer up to the beginning of the next
55  * line.
56  *
57  * @param c char pointer to pointer
58  * @retval FSDPE_ILLEGAL_CHARACTER, when an illegal '\r' character
59  * (not followed by a '\n') is found, returns
60  */
61 #define NEXT_LINE(c) do { if (!(c = next_line(c))) return FSDPE_ILLEGAL_CHARACTER; } while (0);
62 
63 fsdp_error_t
fsdp_parse(const char * text_description,fsdp_description_t * dsc)64 fsdp_parse (const char *text_description, fsdp_description_t * dsc)
65 {
66   fsdp_error_t result;
67   const char *p = text_description, *p2;
68   unsigned int j;
69   /* temps for sscanf */
70 #define TEMPCHARS 6
71   char fsdp_buf[TEMPCHARS][MAXSHORTFIELDLEN];
72   char longfsdp_buf[MAXLONGFIELDLEN];
73 #define TEMPINTS 2
74   unsigned long int wuint[TEMPINTS];
75 
76   if ((NULL == text_description) || (NULL == dsc))
77     return FSDPE_INVALID_PARAMETER;
78 
79   /***************************************************************************/
80   /* A) parse session-level description                                      */
81   /***************************************************************************/
82 
83   /* `v=' line (protocol version) */
84   /* according to the RFC, only `v=0' is valid */
85   if (sscanf (p, "v=%1lu", &wuint[0]))
86   {
87     if (wuint[0] != 0)
88       return FSDPE_INVALID_VERSION;
89   }
90   else
91   {
92     return FSDPE_MISSING_VERSION;
93   }
94   NEXT_LINE (p);
95 
96   /* `o=' line (owner/creator and session identifier) */
97   /* o=<username> <session id> <version> <network type> <address type>
98      <address> */
99   if (!strncmp (p, "o=", 2))
100   {
101     p += 2;
102     /* note that the following max lengths may vary in the future and
103        are quite arbitary */
104     if (sscanf
105         (p,
106          "%" MSFLENS "[\x21-\xFF] %" MSFLENS "[0-9] %" MSFLENS
107          "[0-9] %2s %3s %" MSFLENS "s", fsdp_buf[0], fsdp_buf[1],
108          fsdp_buf[2], fsdp_buf[3], fsdp_buf[4], fsdp_buf[5]) != 6)
109       return FSDPE_INVALID_OWNER;
110     dsc->o_username = strdup (fsdp_buf[0]);
111     dsc->o_session_id = strdup (fsdp_buf[1]);
112     dsc->o_announcement_version = strdup (fsdp_buf[2]);
113     if (!strncmp (fsdp_buf[3], "IN", 2))
114     {
115       dsc->o_network_type = FSDP_NETWORK_TYPE_INET;
116       if (!strncmp (fsdp_buf[4], "IP4", 3))
117         dsc->o_address_type = FSDP_ADDRESS_TYPE_IPV4;
118       else if (!strncmp (fsdp_buf[4], "IP6", 3))
119         dsc->o_address_type = FSDP_ADDRESS_TYPE_IPV6;
120       else
121         return FSDPE_INVALID_OWNER;
122     }
123     else
124     {
125       return FSDPE_INVALID_OWNER;
126     }
127     /* TODO? check valid unicast address/FQDN */
128     dsc->o_address = strdup (fsdp_buf[5]);
129   }
130   else
131   {
132     return FSDPE_MISSING_OWNER;
133   }
134   NEXT_LINE (p);
135 
136   /* `s=' line (session name) -note that the name string cannot be empty */
137   /* s=<session name> */
138   if (!strncmp (p, "s=", 2))
139   {
140     if (sscanf (p, "s=%" MLFLENS "[^\r\n]", longfsdp_buf) < 1)
141       return FSDPE_EMPTY_NAME;
142     dsc->s_name = strdup (longfsdp_buf);
143   }
144   else
145   {
146     return FSDPE_MISSING_NAME;
147   }
148   NEXT_LINE (p);
149 
150   /* `i=' line (session information) [optional] */
151   /* i=<session description> */
152   if (!strncmp (p, "i=", 2)
153       && sscanf (p, "i=%" MLFLENS "[^\r\n]", longfsdp_buf))
154   {
155     dsc->i_information = strdup (longfsdp_buf);
156     NEXT_LINE (p);
157   }
158   else
159   {
160     /* (optional) information absent */
161   }
162 
163   /* `u=' line (URI of description)  [optional] */
164   /* u=<URI> */
165   if (!strncmp (p, "u=", 2)
166       && sscanf (p, "u=%" MLFLENS "[^\r\n]", longfsdp_buf))
167   {
168     /* TODO? check valid uri */
169     dsc->u_uri = strdup (longfsdp_buf);
170     NEXT_LINE (p);
171   }
172   else
173   {
174     /* (optional) uri absent */
175   }
176 
177   /* `e=' lines (email address) [zero or more] */
178   /* e=<email address> */
179   p2 = p;
180   j = 0;
181   while (!strncmp (p2, "e=", 2))
182   {
183     /* First, count how many emails are there */
184     j++;
185     NEXT_LINE (p2);
186   }
187   dsc->emails_count = j;
188   if (dsc->emails_count > 0)
189   {
190     /* Then, build the array of emails */
191     dsc->emails = calloc (j, sizeof (const char *));
192     for (j = 0; j < dsc->emails_count; j++)
193     {
194       sscanf (p, "e=%" MLFLENS "[^\r\n]", longfsdp_buf);
195       /* TODO? check valid email-address. */
196       dsc->emails[j] = strdup (longfsdp_buf);
197       NEXT_LINE (p);
198     }
199   }
200 
201   /* `p=' lines (phone number) [zero or more] */
202   /*  p=<phone number> */
203   j = 0;
204   /* assert ( p2 == p ); */
205   while (!strncmp (p2, "p=", 2))
206   {
207     j++;
208     NEXT_LINE (p2);
209   }
210   dsc->phones_count = j;
211   if (dsc->phones_count > 0)
212   {
213     dsc->phones = calloc (j, sizeof (const char *));
214     for (j = 0; j < dsc->phones_count; j++)
215     {
216       sscanf (p, "p=%" MLFLENS "[^\r\n]", longfsdp_buf);
217       /* TODO? check valid phone-number. */
218       dsc->phones[j] = strdup (longfsdp_buf);
219       NEXT_LINE (p);
220     }
221   }
222 
223   /* `c=' line (connection information - not required if included in all media) [optional] */
224   /* c=<network type> <address type> <connection address> */
225   result = fsdp_parse_c (&p, &(dsc->c_network_type), &(dsc->c_address_type),
226 			 &(dsc->c_address));
227   if (FSDPE_OK != result)
228     return result;
229 
230   /* `b=' lines (bandwidth information) [optional] */
231   /* b=<modifier>:<bandwidth-value> */
232   result =
233     fsdp_parse_b (&p, &(dsc->bw_modifiers), &(dsc->bw_modifiers_count));
234   if (FSDPE_OK != result)
235     return result;
236 
237   /* A.1) Time descriptions: */
238 
239   /* `t=' lines (time the session is active) [1 or more] */
240   /* t=<start time>  <stop time> */
241   j = 0;
242   p2 = p;
243   while (!strncmp (p2, "t=", 2))
244   {
245     j++;
246     NEXT_LINE (p2);
247     while (!strncmp (p2, "r=", 2))
248       NEXT_LINE (p2);
249   }
250   dsc->time_periods_count = j;
251   if (dsc->time_periods_count == 0)
252     return FSDPE_MISSING_TIME;
253   dsc->time_periods = calloc (dsc->time_periods_count,
254 			      sizeof (fsdp_time_period_t *));
255   for (j = 0; j < dsc->time_periods_count; j++)
256   {
257     unsigned int h = 0;
258     if (sscanf (p, "t=%10lu %10lu", &wuint[0], &wuint[1]) != 2)
259     {
260       /* not all periods have been successfully parsed */
261       dsc->time_periods_count = j;
262       return FSDPE_INVALID_TIME;
263     }
264     dsc->time_periods[j] = calloc (1, sizeof (fsdp_time_period_t));
265 
266     /* convert from NTP to time_t time */
267     if (wuint[0] != 0)
268       wuint[0] -= NTP_EPOCH_OFFSET;
269     if (wuint[1] != 0)
270       wuint[1] -= NTP_EPOCH_OFFSET;
271     dsc->time_periods[j]->start = wuint[0];
272     dsc->time_periods[j]->stop = wuint[1];
273     NEXT_LINE (p);
274 
275     /* `r' lines [zero or more repeat times for each t=] */
276     /*r=<repeat interval> <active duration> <list of offsets from
277       start-time> */
278     p2 = p;
279     while (!strncmp (p2, "r=", 2))
280     {
281       h++;
282       NEXT_LINE (p2);
283     }
284     dsc->time_periods[j]->repeats_count = h;
285     if (h > 0)
286     {
287       unsigned int index2 = 0;
288       dsc->time_periods[j]->repeats =
289         calloc (h, sizeof (fsdp_repeat_t *));
290       for (h = 0; h < dsc->time_periods[j]->repeats_count; h++)
291       {
292         /*
293           get_repeat_values(p,&(dsc->time_periods[index].repeats[index2]));
294           fsdp_error_t get_repeat_values (const char *r, fsdp_repeat_t
295           *repeat);
296           */
297         if (sscanf (p, "r=%10s %10s %" MLFLENS "[^\r\n]",
298                     fsdp_buf[0], fsdp_buf[1], longfsdp_buf) == 3)
299         {
300           fsdp_repeat_t *repeat;
301           dsc->time_periods[j]->repeats[h] =
302             calloc (1, sizeof (fsdp_repeat_t));
303           repeat = dsc->time_periods[j]->repeats[h];
304           /* get interval, duration and list of offsets */
305           result =
306             fsdp_repeat_time_to_uint (fsdp_buf[0],
307                                       &(repeat->interval));
308           if (result == FSDPE_OK)
309           {
310             result =
311               fsdp_repeat_time_to_uint (fsdp_buf[1],
312                                         &(repeat->duration));
313             if (result == FSDPE_OK)
314             {
315               unsigned int k = 1;
316               const char *i = longfsdp_buf;
317               while (NULL != (i = strchr (i, ' ')))
318               {
319                 k++;
320                 if (NULL != i)
321                   i++;
322               }
323               repeat->offsets_count = k;
324               repeat->offsets = calloc (k, sizeof (time_t));
325               i = longfsdp_buf;
326               for (k = 0;
327                    (k < repeat->offsets_count)
328                      && (result == FSDPE_OK) && i; k++)
329               {
330                 result =
331                   fsdp_repeat_time_to_uint (i,
332                                             &(repeat->
333                                               offsets[k]));
334                 i = strchr (i, ' ');
335                 if (NULL != i)
336                   i++;
337               }
338               if (k < repeat->offsets_count)
339               {
340                 /* there where invalid repeat offsets */
341                 dsc->time_periods[j]->repeats_count = k;
342                 return FSDPE_INVALID_REPEAT;
343               }
344             }
345           }
346           if (result != FSDPE_OK)
347           {
348             /* not all repeats have been succesfully parsed */
349             dsc->time_periods[j]->repeats_count = h;
350             return FSDPE_INVALID_REPEAT;
351           }
352           NEXT_LINE (p);
353         }
354         else
355         {
356           /* not all repeats have been succesfully parsed */
357           dsc->time_periods[j]->repeats_count = h;
358           return FSDPE_INVALID_REPEAT;
359         }
360         index2++;
361       }
362     }
363   }
364 
365   /* `z=' line (time zone adjustments) [zero or more] */
366   /* z=<adjustment time> <offset> <adjustment time> <offset> .... */
367   if (!strncmp (p, "z=", 2))
368   {
369     if (sscanf (p, "z=%" MLFLENS "[^\r\n]", longfsdp_buf))
370     {
371       /* TODO: guess how many pairs are there and process them */
372       dsc->timezone_adj = strdup (longfsdp_buf);
373       NEXT_LINE (p);
374     }
375     else
376     {
377       return FSDPE_INVALID_TIMEZONE;
378     }
379   }
380 
381   /* `k=' line (encryption key) [optional] */
382   /* k=<method>
383      k=<method>:<encryption key> */
384   result = fsdp_parse_k (&p, &(dsc->k_encryption_method),
385 			 &(dsc->k_encryption_content));
386   if (result != FSDPE_OK)
387     return result;
388 
389   /* A.2) Attributes */
390   /* `a=' lines (session attribute) [0 or more] */
391   /* a=<attribute>
392      a=<attribute>:<value> */
393   while (!strncmp (p, "a=", 2))
394   {
395     /* The "9" length specifier of the first string is subject to
396        changes */
397     if (sscanf
398         (p, "a=%9[^:\r\n]:%" MSFLENS "[^\r\n]", fsdp_buf[0],
399          fsdp_buf[1]) == 2)
400     {
401       /* session-level value attributes */
402       if (!strncmp (fsdp_buf[0], "cat", 3))
403         dsc->a_category = strdup (fsdp_buf[1]);
404       else if (!strncmp (fsdp_buf[0], "keywds", 6))
405         dsc->a_keywords = strdup (fsdp_buf[1]);
406       else if (!strncmp (fsdp_buf[0], "tool", 4))
407         dsc->a_keywords = strdup (fsdp_buf[1]);
408       else if (!strncmp (fsdp_buf[0], "rtpmap", 6))
409         fsdp_parse_rtpmap (&(dsc->a_rtpmaps),
410                            &(dsc->a_rtpmaps_count), fsdp_buf[1]);
411       else if (!strncmp (fsdp_buf[0], "type", 4))
412       {
413         if (!strncmp (fsdp_buf[1], "broadcast", 9))
414           dsc->a_type = FSDP_SESSION_TYPE_BROADCAST;
415         else if (!strncmp (fsdp_buf[1], "meeting", 7))
416           dsc->a_type = FSDP_SESSION_TYPE_MEETING;
417         else if (!strncmp (fsdp_buf[1], "moderated", 9))
418           dsc->a_type = FSDP_SESSION_TYPE_MODERATED;
419         else if (!strncmp (fsdp_buf[1], "test", 4))
420           dsc->a_type = FSDP_SESSION_TYPE_TEST;
421         else if (!strncmp (fsdp_buf[1], "H332", 4))
422           dsc->a_type = FSDP_SESSION_TYPE_H332;
423         else
424           return FSDPE_INVALID_SESSION_TYPE;
425       }
426       else if (!strncmp (fsdp_buf[0], "charset", 7))
427         dsc->a_charset = strdup (fsdp_buf[1]);
428       else if (!strncmp (fsdp_buf[0], "sdplang", 7))
429       {
430         if (NULL == dsc->a_sdplangs)
431         {
432           dsc->a_sdplangs_count = 0;
433           dsc->a_sdplangs =
434             calloc (SDPLANGS_MAX_COUNT, sizeof (char *));
435         }
436         if (dsc->a_sdplangs_count < SDPLANGS_MAX_COUNT)
437         {
438           dsc->a_sdplangs[dsc->a_sdplangs_count] =
439             strdup (fsdp_buf[1]);
440           dsc->a_sdplangs_count++;
441         }
442       }
443       else if (!strncmp (fsdp_buf[0], "lang", 4))
444       {
445         if (NULL == dsc->a_langs)
446         {
447           dsc->a_langs_count = 0;
448           dsc->a_langs = calloc (SDPLANGS_MAX_COUNT, sizeof (char *));
449         }
450         if (dsc->a_langs_count < SDPLANGS_MAX_COUNT)
451         {
452           dsc->a_langs[dsc->a_langs_count] = strdup (fsdp_buf[1]);
453           dsc->a_langs_count++;
454         }
455       }
456       else if (!strncmp (fsdp_buf[0], "control", 7))
457       {
458         if (NULL == dsc->a_controls)
459         {
460           dsc->a_controls_count = 0;
461           dsc->a_controls =
462             calloc (SDPCONTROLS_MAX_COUNT, sizeof (char *));
463         }
464         if (dsc->a_controls_count < SDPCONTROLS_MAX_COUNT)
465         {
466           dsc->a_controls[dsc->a_controls_count] =
467             strdup (fsdp_buf[1]);
468           dsc->a_controls_count++;
469         }
470       }
471       else if (!strncmp (fsdp_buf[0], "range", 5))
472       {
473         free (dsc->a_range);
474         dsc->a_range = strdup (fsdp_buf[1]);
475       }
476       else
477       {
478         /* ignore unknown attributes, but provide access to them */
479         *longfsdp_buf = '\0';
480         strncat (longfsdp_buf, fsdp_buf[0], MAXLONGFIELDLEN-1);
481         strncat (longfsdp_buf, ":", MAXLONGFIELDLEN-strlen(longfsdp_buf)-1);
482         strncat (longfsdp_buf, fsdp_buf[1], MAXLONGFIELDLEN-strlen(longfsdp_buf)-1);
483         if (NULL == dsc->unidentified_attributes)
484         {
485           dsc->unidentified_attributes_count = 0;
486           dsc->unidentified_attributes =
487             calloc (UNIDENTIFIED_ATTRIBUTES_MAX_COUNT,
488                     sizeof (char *));
489         }
490         if (dsc->unidentified_attributes_count <
491             UNIDENTIFIED_ATTRIBUTES_MAX_COUNT)
492         {
493           dsc->unidentified_attributes
494             [dsc->unidentified_attributes_count] =
495             strdup (longfsdp_buf);
496           dsc->unidentified_attributes_count++;
497         }
498       }
499       NEXT_LINE (p);
500     }
501     else if (sscanf (p, "a=%20s", fsdp_buf[0]) == 1)
502     {
503       /* session-level property attributes */
504       if (!strncmp (fsdp_buf[0], "recvonly", 8))
505         dsc->a_sendrecv_mode = FSDP_SENDRECV_RECVONLY;
506       else if (!strncmp (fsdp_buf[0], "sendonly", 8))
507         dsc->a_sendrecv_mode = FSDP_SENDRECV_SENDONLY;
508       else if (!strncmp (fsdp_buf[0], "inactive", 8))
509         dsc->a_sendrecv_mode = FSDP_SENDRECV_INACTIVE;
510       else if (!strncmp (fsdp_buf[0], "sendrecv", 8))
511         dsc->a_sendrecv_mode = FSDP_SENDRECV_SENDRECV;
512       else
513       {
514         /* ignore unknown attributes, but provide access to them */
515         *longfsdp_buf = '\0';
516         strncat (longfsdp_buf, fsdp_buf[0], MAXLONGFIELDLEN-1);
517         if (NULL == dsc->unidentified_attributes)
518         {
519           dsc->unidentified_attributes_count = 0;
520           dsc->unidentified_attributes =
521             calloc (UNIDENTIFIED_ATTRIBUTES_MAX_COUNT,
522                     sizeof (char *));
523         }
524         if (dsc->unidentified_attributes_count <
525             UNIDENTIFIED_ATTRIBUTES_MAX_COUNT)
526         {
527           dsc->unidentified_attributes
528             [dsc->unidentified_attributes_count] =
529             strdup (longfsdp_buf);
530           dsc->unidentified_attributes_count++;
531         }
532       }
533       NEXT_LINE (p);
534     }
535     else
536       return FSDPE_INVALID_ATTRIBUTE;
537   }
538 
539   /***************************************************************************/
540   /* B) parse media-level descriptions                                       */
541   /***************************************************************************/
542   p2 = p;
543   j = 0;
544   while ((*p2 != '\0') && !strncmp (p2, "m=", 2))
545   {
546     char c;
547     j++;
548     NEXT_LINE (p2);
549     while (sscanf (p2, "%c=", &c) == 1)
550     {
551       if (c == 'i' || c == 'c' || c == 'b' || c == 'k' || c == 'a')
552       {
553         NEXT_LINE (p2);
554       }
555       else if (c == 'm')
556       {
557         break;
558       }
559       else
560       {
561         return FSDPE_INVALID_LINE;
562       }
563     }
564   }
565   dsc->media_announcements_count = j;
566   if (dsc->media_announcements_count == 0)
567   {
568     ;
569     /*return FSDPE_MISSING_MEDIA; */
570   }
571   else
572   {				/* dsc->media_announcements_count > 0 */
573     dsc->media_announcements =
574       calloc (j, sizeof (fsdp_media_announcement_t *));
575     for (j = 0; j < dsc->media_announcements_count; j++)
576     {
577       fsdp_media_announcement_t *media = NULL;
578       /* `m=' line (media name, transport address and format list) */
579       /* m=<media>  <port>  <transport> <fmt list> */
580       /* The max. string lengths are subject to change */
581       if (sscanf (p, "m=%11s %8s %7s %" MLFLENS "[^\r\n]",
582                   fsdp_buf[0], fsdp_buf[1], fsdp_buf[2],
583                   longfsdp_buf) != 4)
584       {
585         return FSDPE_INVALID_MEDIA;
586       }
587       else
588       {
589         dsc->media_announcements[j] =
590           calloc (1, sizeof (fsdp_media_announcement_t));
591         media = dsc->media_announcements[j];
592         if (!strncmp (fsdp_buf[0], "audio", 5))
593           media->media_type = FSDP_MEDIA_AUDIO;
594         else if (!strncmp (fsdp_buf[0], "video", 5))
595           media->media_type = FSDP_MEDIA_VIDEO;
596         else if (!strncmp (fsdp_buf[0], "application", 11))
597           media->media_type = FSDP_MEDIA_APPLICATION;
598         else if (!strncmp (fsdp_buf[0], "data", 4))
599           media->media_type = FSDP_MEDIA_DATA;
600         else if (!strncmp (fsdp_buf[0], "control", 7))
601           media->media_type = FSDP_MEDIA_CONTROL;
602         else
603           return FSDPE_UNKNOWN_MEDIA_TYPE;
604         {			/* try to get port specification as port/number */
605           char *slash;
606           if ((slash = strchr (fsdp_buf[1], '/')))
607           {
608             *slash = '\0';
609             slash++;
610             media->port = strtol (fsdp_buf[1], NULL, 10);
611             media->port_count = strtol (slash, NULL, 10);
612           }
613           else
614           {
615             media->port = strtol (fsdp_buf[1], NULL, 10);
616             media->port_count = 0;
617           }
618         }
619         if (!strncmp (fsdp_buf[2], "RTP/AVP", 7))
620           media->transport = FSDP_TP_RTP_AVP;
621         else if (!strncmp (fsdp_buf[2], "udp", 3))
622           media->transport = FSDP_TP_UDP;
623         else if (!strncmp (fsdp_buf[2], "TCP", 3))
624           media->transport = FSDP_TP_TCP;
625         else if (!strncmp (fsdp_buf[2], "UDPTL", 5))
626           media->transport = FSDP_TP_UDPTL;
627         else if (!strncmp (fsdp_buf[2], "vat", 3))
628           media->transport = FSDP_TP_VAT;
629         else if (!strncmp (fsdp_buf[2], "rtp", 3))
630           media->transport = FSDP_TP_OLD_RTP;
631         else
632           return FSDPE_UNKNOWN_MEDIA_TRANSPORT;
633         {
634           unsigned int k = 0;
635           char *s = longfsdp_buf;
636           while (NULL != (s = strchr (s, ' ')))
637           {
638             k++;
639             if (NULL != s)
640               s++;
641           }
642           k++;		/* when there is no space left, count the last format */
643           media->formats_count = k;
644           media->formats = calloc (k, sizeof (char *));
645           s = longfsdp_buf;
646           for (k = 0; k < media->formats_count; k++)
647           {
648             char *space = strchr (s, ' ');
649             if (NULL != space)
650               *space = '\0';
651             media->formats[k] = strdup (s);
652             s = space + 1;
653           }
654         }
655         NEXT_LINE (p);
656       }
657 
658       /* `i=' line (media title) [optional] */
659       /* i=<media title> */
660       if (!strncmp (p, "i=", 2)
661           && sscanf (p, "i=%" MLFLENS "[^\r\n]", longfsdp_buf))
662       {
663         media->i_title = strdup (longfsdp_buf);
664         NEXT_LINE (p);
665       }
666       else
667       {
668         /* (optional) information absent */
669       }
670 
671       /* `c=' line (connection information - overrides session-level
672          line) [optional if provided at session-level] */
673       /* c=<network type> <address type> <connection address> */
674       result = fsdp_parse_c (&p, &(media->c_network_type),
675                              &(media->c_address_type),
676                              &(media->c_address));
677       if (result != FSDPE_OK)
678         return result;
679 
680       /* `b=' lines (bandwidth information) [optional] */
681       /* b=<modifier>:<bandwidth-value> */
682       result = fsdp_parse_b (&p, &(media->bw_modifiers),
683                              &(media->bw_modifiers_count));
684       if (FSDPE_OK != result)
685         return result;
686 
687       /* `k=' line (encryption key) [optional] */
688       /* k=<method>
689          k=<method>:<encryption key> */
690       result = fsdp_parse_k (&p, &(media->k_encryption_method),
691                              &(media->k_encryption_content));
692       if (result != FSDPE_OK)
693         return result;
694 
695       /* B.1) Attributes */
696 
697       /* `a=' lines (zero or more media attribute lines) [optional] */
698       /* a=<attribute>
699          a=<attribute>:<value> */
700       while (!strncmp (p, "a=", 2))
701       {
702         if (sscanf
703             (p, "a=%9[^:\r\n]:%" MLFLENS "[^\r\n]", fsdp_buf[0],
704              longfsdp_buf) == 2)
705         {
706           /* media-level value attributes */
707           if (!strncmp (fsdp_buf[0], "ptime", 5))
708             media->a_ptime = strtoul (longfsdp_buf, NULL, 10);
709           else if (!strncmp (fsdp_buf[0], "maxptime", 8))
710             media->a_maxptime = strtoul (longfsdp_buf, NULL, 10);
711           else if (!strncmp (fsdp_buf[0], "rtpmap", 6))
712             fsdp_parse_rtpmap (&(media->a_rtpmaps),
713                                &(media->a_rtpmaps_count),
714                                longfsdp_buf);
715           else if (!strncmp (fsdp_buf[0], "orient", 6))
716           {
717             if (!strncmp (longfsdp_buf, "portrait", 8))
718               media->a_orient = FSDP_ORIENT_PORTRAIT;
719             else if (!strncmp (longfsdp_buf, "landscape", 9))
720               media->a_orient = FSDP_ORIENT_LANDSCAPE;
721             else if (!strncmp (longfsdp_buf, "seascape", 9))
722               media->a_orient = FSDP_ORIENT_SEASCAPE;
723           }
724           else if (!strncmp (fsdp_buf[0], "sdplang", 7))
725           {
726             if (NULL == dsc->a_sdplangs)
727             {
728               media->a_sdplangs_count = 0;
729               media->a_sdplangs =
730                 calloc (SDPLANGS_MAX_COUNT, sizeof (char *));
731             }
732             if (media->a_sdplangs_count < SDPLANGS_MAX_COUNT)
733             {
734               media->a_sdplangs[dsc->a_sdplangs_count] =
735                 strdup (longfsdp_buf);
736               media->a_sdplangs_count++;
737             }
738           }
739           else if (!strncmp (fsdp_buf[0], "lang", 4))
740           {
741             if (NULL == dsc->a_langs)
742             {
743               media->a_langs_count = 0;
744               media->a_langs =
745                 calloc (SDPLANGS_MAX_COUNT, sizeof (char *));
746             }
747             if (media->a_langs_count < SDPLANGS_MAX_COUNT)
748             {
749               media->a_langs[dsc->a_langs_count] =
750                 strdup (longfsdp_buf);
751               media->a_langs_count++;
752             }
753           }
754           else if (!strncmp (fsdp_buf[0], "control", 7))
755           {
756             if (NULL == media->a_controls)
757             {
758               media->a_controls_count = 0;
759               media->a_controls =
760                 calloc (SDPCONTROLS_MAX_COUNT, sizeof (char *));
761             }
762             if (media->a_controls_count < SDPCONTROLS_MAX_COUNT)
763             {
764               media->a_controls[media->a_controls_count] =
765                 strdup (longfsdp_buf);
766               media->a_controls_count++;
767             }
768           }
769           else if (!strncmp (fsdp_buf[0], "range", 5))
770           {
771             free (media->a_range);
772             media->a_range = strdup (fsdp_buf[1]);
773           }
774           else if (!strncmp (fsdp_buf[0], "framerate", 9))
775             media->a_framerate = strtod (longfsdp_buf, NULL);
776           else if (!strncmp (fsdp_buf[0], "fmtp", 4))
777           {
778             if (NULL == media->a_fmtps)
779             {
780               media->a_fmtps_count = 0;
781               media->a_fmtps =
782                 calloc (SDPLANGS_MAX_COUNT, sizeof (char *));
783             }
784             if (media->a_fmtps_count < SDPLANGS_MAX_COUNT)
785             {
786               media->a_fmtps[media->a_fmtps_count] =
787                 strdup (longfsdp_buf);
788               media->a_fmtps_count++;
789             }
790           }
791           else if (!strncmp (fsdp_buf[0], "rtcp", 4))
792           {
793             int opts = 0;
794             /* rtcp attribute: a=rtcp:<port> <nettype> <addrtype> <address> */
795             opts =
796               sscanf (longfsdp_buf, "%lu %2s %3s %" MSFLENS "s",
797                       &wuint[0], fsdp_buf[0], fsdp_buf[1],
798                       fsdp_buf[2]);
799             if (opts >= 1)
800             {
801               media->a_rtcp_port = wuint[0];
802               if (opts >= 2)
803               {
804                 if (!strncmp (fsdp_buf[0], "IN", 2))
805                 {
806                   media->a_rtcp_network_type =
807                     FSDP_NETWORK_TYPE_INET;
808                 }	/* else
809                            ; TODO: define error code? */
810                 if (opts >= 3)
811                 {
812                   if (!strncmp (fsdp_buf[1], "IP4", 3))
813                     media->a_rtcp_address_type =
814                       FSDP_ADDRESS_TYPE_IPV4;
815                   else if (!strncmp (fsdp_buf[1], "IP6", 3))
816                     media->a_rtcp_address_type =
817                       FSDP_ADDRESS_TYPE_IPV6;
818                   else
819                     return FSDPE_INVALID_CONNECTION_NETTYPE;
820                   /*add specific code? */
821                   if (opts >= 4)
822                     media->a_rtcp_address =
823                       strdup (fsdp_buf[2]);
824                 }
825               }
826             }
827           }
828           else
829           {
830             /* ignore unknown attributes, but provide access to them */
831             *fsdp_buf[1] = '\0';
832             strncat (fsdp_buf[1], fsdp_buf[0], MAXSHORTFIELDLEN-1);
833             strncat (fsdp_buf[1], ":", MAXSHORTFIELDLEN-strlen(fsdp_buf[1])-1);
834             strncat (fsdp_buf[1], longfsdp_buf, MAXSHORTFIELDLEN-strlen(fsdp_buf[1])-1);
835             if (NULL == media->unidentified_attributes)
836             {
837               media->unidentified_attributes_count = 0;
838               media->unidentified_attributes =
839                 calloc (UNIDENTIFIED_ATTRIBUTES_MAX_COUNT,
840                         sizeof (char *));
841             }
842             if (media->unidentified_attributes_count <
843                 UNIDENTIFIED_ATTRIBUTES_MAX_COUNT)
844             {
845               media->unidentified_attributes
846                 [media->unidentified_attributes_count] =
847                 strdup (fsdp_buf[1]);
848               media->unidentified_attributes_count++;
849             }
850           }
851           NEXT_LINE (p);
852         }
853         else if (sscanf (p, "a=%8s", fsdp_buf[0]) == 1)
854         {
855           /* media-level property attributes */
856           if (!strncmp (fsdp_buf[0], "recvonly", 8))
857             media->a_sendrecv_mode = FSDP_SENDRECV_RECVONLY;
858           else if (!strncmp (fsdp_buf[0], "sendonly", 8))
859             media->a_sendrecv_mode = FSDP_SENDRECV_SENDONLY;
860           else if (!strncmp (fsdp_buf[0], "inactive", 8))
861             media->a_sendrecv_mode = FSDP_SENDRECV_INACTIVE;
862           else if (!strncmp (fsdp_buf[0], "sendrecv", 8))
863             media->a_sendrecv_mode = FSDP_SENDRECV_SENDRECV;
864           else
865           {
866             /* ignore unknown attributes, but provide access to them */
867             *longfsdp_buf = '\0';
868             strncat (longfsdp_buf, fsdp_buf[0], MAXLONGFIELDLEN-1);
869             if (NULL == media->unidentified_attributes)
870             {
871               media->unidentified_attributes_count = 0;
872               media->unidentified_attributes =
873                 calloc (UNIDENTIFIED_ATTRIBUTES_MAX_COUNT,
874                         sizeof (char *));
875             }
876             if (media->unidentified_attributes_count <
877                 UNIDENTIFIED_ATTRIBUTES_MAX_COUNT)
878             {
879               media->unidentified_attributes
880                 [media->unidentified_attributes_count] =
881                 strdup (longfsdp_buf);
882               media->unidentified_attributes_count++;
883             }
884           }
885           NEXT_LINE (p);
886         }
887         else
888           return FSDPE_INVALID_ATTRIBUTE;
889       }
890     }			/* end of for */
891   }
892 
893   /* Check c= has been given at session level or at media level for
894      all media */
895   if (NULL == dsc->c_address.address)
896   {
897     unsigned int c;
898     for (c = 0; c < dsc->media_announcements_count; c++)
899       if (NULL == dsc->media_announcements[c]->c_address.address)
900         return FSDPE_MISSING_CONNECTION_INFO;
901   }
902 
903   /* finish */
904   if (*p == '\0')
905     return FSDPE_OK;
906   else
907     return FSDPE_OVERFILLED;
908 }
909 
910 static fsdp_error_t
fsdp_parse_c(const char ** p,fsdp_network_type_t * ntype,fsdp_address_type_t * atype,fsdp_connection_address_t * address)911 fsdp_parse_c (const char **p, fsdp_network_type_t * ntype,
912 	      fsdp_address_type_t * atype,
913 	      fsdp_connection_address_t * address)
914 {
915 #undef TEMPCHARS
916 #define TEMPCHARS 3
917   char fsdp_buf[TEMPCHARS][MAXSHORTFIELDLEN];
918 
919   if (!strncmp (*p, "c=", 2))
920   {
921     if (sscanf (*p, "c=%2s %3s %" MSFLENS "s",
922                 fsdp_buf[0], fsdp_buf[1], fsdp_buf[2]))
923     {
924       if (!strncmp (fsdp_buf[0], "IN", 2))
925       {
926         *ntype = FSDP_NETWORK_TYPE_INET;
927         if (!strncmp (fsdp_buf[1], "IP4", 3))
928           *atype = FSDP_ADDRESS_TYPE_IPV4;
929         else if (!strncmp (fsdp_buf[1], "IP6", 3))
930           *atype = FSDP_ADDRESS_TYPE_IPV6;
931         else
932           return FSDPE_INVALID_CONNECTION_NETTYPE;
933       }
934       else
935       {
936         return FSDPE_INVALID_CONNECTION_ADDRTYPE;
937       }
938       {
939         char *slash = strchr (fsdp_buf[2], '/');
940         if (NULL == slash)
941         {
942           address->address = strdup (fsdp_buf[2]);
943           address->address_ttl = 0;
944           address->address_count = 0;
945         }
946         else
947         {
948           /* address is IP4 multicast */
949           char *slash2;
950           *slash = '\0';
951           slash++;
952           address->address = strdup (fsdp_buf[2]);
953           slash2 = strchr (slash + 1, '/');
954           if (NULL == slash2)
955           {
956             address->address_ttl = strtol (slash, NULL, 10);
957             address->address_count = 0;
958           }
959           else
960           {
961             *slash2 = '\0';
962             slash2++;
963             address->address_ttl = strtol (slash, NULL, 10);
964             address->address_count = strtol (slash2, NULL, 10);
965           }
966         }
967       }
968       NEXT_LINE (*p);
969     }
970     else
971     {
972       return FSDPE_INVALID_CONNECTION;
973     }
974   }
975   return FSDPE_OK;
976 }
977 
978 static fsdp_error_t
fsdp_parse_b(const char ** p,fsdp_bw_modifier_t ** bw_modifiers,unsigned int * bw_modifiers_count)979 fsdp_parse_b (const char **p, fsdp_bw_modifier_t ** bw_modifiers,
980 	      unsigned int *bw_modifiers_count)
981 {
982   char fsdp_buf[MAXSHORTFIELDLEN];
983   unsigned long int wuint;
984   unsigned int i = 0;
985   const char *lp = *p;
986 
987   /* count b= lines */
988   while (!strncmp (lp, "b=", 2))
989   {
990     NEXT_LINE (lp);
991     i++;
992   }
993   *bw_modifiers = calloc (i, sizeof (fsdp_bw_modifier_t));
994   *bw_modifiers_count = i;
995 
996   while (i > 0)
997   {
998     unsigned int index = *bw_modifiers_count - i;
999     if (2 == sscanf (*p, "b=%20[^:\r\n]:%lu", fsdp_buf, &wuint))
1000     {
1001       if (!strncmp (fsdp_buf, "CT", 2))
1002         (*bw_modifiers)[index].b_mod_type =
1003           FSDP_BW_MOD_TYPE_CONFERENCE_TOTAL;
1004       else if (!strncmp (fsdp_buf, "AS", 2))
1005         (*bw_modifiers)[index].b_mod_type =
1006           FSDP_BW_MOD_TYPE_APPLICATION_SPECIFIC;
1007       else if (!strncmp (fsdp_buf, "RS", 2))
1008         (*bw_modifiers)[index].b_mod_type = FSDP_BW_MOD_TYPE_RTCP_SENDERS;
1009       else if (!strncmp (fsdp_buf, "RR", 2))
1010         (*bw_modifiers)[index].b_mod_type =
1011           FSDP_BW_MOD_TYPE_RTCP_RECEIVERS;
1012       else
1013       {
1014         (*bw_modifiers)[index].b_mod_type = FSDP_BW_MOD_TYPE_UNKNOWN;
1015         (*bw_modifiers)[index].b_unknown_bw_modt =
1016           (char *) strdup (fsdp_buf);
1017       }
1018       (*bw_modifiers)[index].b_value = wuint;
1019       NEXT_LINE (*p);
1020     }
1021     else
1022     {
1023       *bw_modifiers_count -= i;
1024       return FSDPE_INVALID_BANDWIDTH;
1025     }
1026     i--;
1027   }
1028   return FSDPE_OK;
1029 }
1030 
1031 static fsdp_error_t
fsdp_parse_k(const char ** p,fsdp_encryption_method_t * method,char ** content)1032 fsdp_parse_k (const char **p, fsdp_encryption_method_t * method,
1033 	      char **content)
1034 {
1035   char fsdp_buf[MAXSHORTFIELDLEN];
1036   char longfsdp_buf[MAXLONGFIELDLEN];
1037 
1038   if (!strncmp (*p, "k=", 2))
1039   {
1040     if (sscanf (*p, "k=prompt"))
1041     {
1042       *method = FSDP_ENCRYPTION_METHOD_PROMPT;
1043       *content = NULL;
1044       NEXT_LINE (*p);
1045     }
1046     else
1047     {
1048       if (sscanf
1049           (*p, "k=%6[^:\r\n]:%" MLFLENS "s", fsdp_buf, longfsdp_buf))
1050       {
1051         if (!strncmp (fsdp_buf, "clear", 5))
1052           *method = FSDP_ENCRYPTION_METHOD_CLEAR;
1053         else if (!strncmp (fsdp_buf, "base64", 6))
1054           *method = FSDP_ENCRYPTION_METHOD_BASE64;
1055         else if (!strncmp (fsdp_buf, "uri", 3))
1056           *method = FSDP_ENCRYPTION_METHOD_URI;
1057         else
1058           return FSDPE_INVALID_ENCRYPTION_METHOD;
1059         *content = strdup (longfsdp_buf);
1060         NEXT_LINE (*p);
1061       }
1062     }
1063   }
1064   return FSDPE_OK;
1065 }
1066 
1067 static fsdp_error_t
fsdp_parse_rtpmap(fsdp_rtpmap_t *** rtpmap,unsigned int * counter,const char * value)1068 fsdp_parse_rtpmap (fsdp_rtpmap_t *** rtpmap, unsigned int *counter,
1069 		   const char *value)
1070 {
1071   fsdp_error_t result = FSDPE_OK;
1072 
1073   if (0 == *counter)
1074   {
1075     *counter = 0;
1076     *rtpmap = calloc (MEDIA_RTPMAPS_MAX_COUNT, sizeof (fsdp_rtpmap_t *));
1077   }
1078   if (*counter < MEDIA_RTPMAPS_MAX_COUNT)
1079   {
1080     unsigned int c = *counter;
1081     fsdp_rtpmap_t **map = *rtpmap;
1082     char fsdp_buf[MAXSHORTFIELDLEN];
1083     char longfsdp_buf[MAXLONGFIELDLEN];
1084     map[c] = calloc (1, sizeof (fsdp_rtpmap_t));
1085 
1086     /* a=rtpmap:<payload type> <encoding name>/<clock rate>[/<encoding
1087        parameters]> */
1088     if (2 == sscanf (value, "%s %s", fsdp_buf, longfsdp_buf))
1089     {
1090       char *slash1;
1091       map[c]->pt = strdup (fsdp_buf);
1092       /* parse <encoding name>/<clock rate>[/<encoding parameters>] */
1093       slash1 = strchr (longfsdp_buf, '/');
1094       if (NULL == slash1)
1095       {
1096         result = FSDPE_INVALID_ATTRIBUTE_RTPMAP;
1097       }
1098       else
1099       {
1100         char *slash2;
1101         *slash1 = '\0';
1102         slash1++;
1103         map[c]->encoding_name = strdup (longfsdp_buf);
1104         slash2 = strchr (slash1, '/');
1105         if (NULL != slash2)
1106         {
1107           *slash2 = '\0';
1108           slash2++;
1109           map[c]->parameters = strdup (slash2);
1110         }
1111         map[c]->clock_rate = strtol (slash1, NULL, 10);
1112       }
1113       (*counter)++;
1114     }
1115   }
1116   return result;
1117 }
1118 
1119 static fsdp_error_t
fsdp_repeat_time_to_uint(const char * time,unsigned long int * seconds)1120 fsdp_repeat_time_to_uint (const char *time, unsigned long int *seconds)
1121 {
1122   const unsigned long SECONDS_PER_DAY = 86400;
1123   const unsigned long SECONDS_PER_HOUR = 3600;
1124   const unsigned long SECONDS_PER_MINUTE = 60;
1125   char c;
1126   unsigned long int wuint;
1127 
1128   if (sscanf (time, "%lu%c", &wuint, &c) == 2)
1129   {
1130     /* time with unit specification character */
1131     switch (c)
1132     {
1133     case 'd':
1134       *seconds = wuint * SECONDS_PER_DAY;
1135       break;
1136     case 'h':
1137       *seconds = wuint * SECONDS_PER_HOUR;
1138       break;
1139     case 'm':
1140       *seconds = wuint * SECONDS_PER_MINUTE;
1141       break;
1142     case 's':
1143       *seconds = wuint;
1144       break;
1145     default:
1146       return FSDPE_INVALID_REPEAT;
1147       break;
1148     }
1149   }
1150   else if (sscanf (time, "%lu", &wuint) == 1)
1151   {
1152     /* time without unit specification character */
1153     *seconds = wuint;
1154   }
1155   else
1156   {
1157     return FSDPE_INVALID_REPEAT;
1158   }
1159   return FSDPE_OK;
1160 }
1161 
1162 unsigned int
fsdp_get_version(const fsdp_description_t * dsc)1163 fsdp_get_version (const fsdp_description_t * dsc)
1164 {
1165   if (!dsc)
1166     return 0;
1167   return dsc->version;
1168 }
1169 
1170 const char *
fsdp_get_owner_username(const fsdp_description_t * dsc)1171 fsdp_get_owner_username (const fsdp_description_t * dsc)
1172 {
1173   if (!dsc)
1174     return NULL;
1175   return dsc->o_username;
1176 }
1177 
1178 const char *
fsdp_get_session_id(const fsdp_description_t * dsc)1179 fsdp_get_session_id (const fsdp_description_t * dsc)
1180 {
1181   if (!dsc)
1182     return NULL;
1183   return dsc->o_session_id;
1184 }
1185 
1186 const char *
fsdp_get_announcement_version(const fsdp_description_t * dsc)1187 fsdp_get_announcement_version (const fsdp_description_t * dsc)
1188 {
1189   if (!dsc)
1190     return NULL;
1191   return dsc->o_announcement_version;
1192 }
1193 
1194 fsdp_network_type_t
fsdp_get_owner_network_type(const fsdp_description_t * dsc)1195 fsdp_get_owner_network_type (const fsdp_description_t * dsc)
1196 {
1197   if (!dsc)
1198     return FSDP_NETWORK_TYPE_UNDEFINED;
1199   return dsc->o_network_type;
1200 }
1201 
1202 fsdp_address_type_t
fsdp_get_owner_address_type(const fsdp_description_t * dsc)1203 fsdp_get_owner_address_type (const fsdp_description_t * dsc)
1204 {
1205   if (!dsc)
1206     return FSDP_ADDRESS_TYPE_UNDEFINED;
1207   return dsc->o_address_type;
1208 }
1209 
1210 const char *
fsdp_get_owner_address(const fsdp_description_t * dsc)1211 fsdp_get_owner_address (const fsdp_description_t * dsc)
1212 {
1213   if (!dsc)
1214     return NULL;
1215   return dsc->o_address;
1216 }
1217 
1218 const char *
fsdp_get_name(const fsdp_description_t * dsc)1219 fsdp_get_name (const fsdp_description_t * dsc)
1220 {
1221   if (!dsc)
1222     return NULL;
1223   return dsc->s_name;
1224 }
1225 
1226 const char *
fsdp_get_information(const fsdp_description_t * dsc)1227 fsdp_get_information (const fsdp_description_t * dsc)
1228 {
1229   if (!dsc)
1230     return NULL;
1231   return dsc->i_information;
1232 }
1233 
1234 const char *
fsdp_get_uri(const fsdp_description_t * dsc)1235 fsdp_get_uri (const fsdp_description_t * dsc)
1236 {
1237   if (!dsc)
1238     return NULL;
1239   return dsc->u_uri;
1240 }
1241 
1242 unsigned int
fsdp_get_emails_count(const fsdp_description_t * dsc)1243 fsdp_get_emails_count (const fsdp_description_t * dsc)
1244 {
1245   if (!dsc)
1246     return 0;
1247   return dsc->emails_count;
1248 }
1249 
1250 const char *
fsdp_get_email(const fsdp_description_t * dsc,unsigned int index)1251 fsdp_get_email (const fsdp_description_t * dsc, unsigned int index)
1252 {
1253   if ((!dsc) || (index >= dsc->emails_count))
1254     return NULL;
1255   return dsc->emails[index];
1256 }
1257 
1258 unsigned int
fsdp_get_phones_count(const fsdp_description_t * dsc)1259 fsdp_get_phones_count (const fsdp_description_t * dsc)
1260 {
1261   if (!dsc)
1262     return 0;
1263   return dsc->phones_count;
1264 }
1265 
1266 const char *
fsdp_get_phone(const fsdp_description_t * dsc,unsigned int index)1267 fsdp_get_phone (const fsdp_description_t * dsc, unsigned int index)
1268 {
1269   if ((!dsc) || (index >= dsc->phones_count))
1270     return NULL;
1271   return dsc->phones[index];
1272 }
1273 
1274 fsdp_network_type_t
fsdp_get_global_conn_network_type(const fsdp_description_t * dsc)1275 fsdp_get_global_conn_network_type (const fsdp_description_t * dsc)
1276 {
1277   if (!dsc)
1278     return FSDP_NETWORK_TYPE_UNDEFINED;
1279   return dsc->c_network_type;
1280 }
1281 
1282 fsdp_address_type_t
fsdp_get_global_conn_address_type(const fsdp_description_t * dsc)1283 fsdp_get_global_conn_address_type (const fsdp_description_t * dsc)
1284 {
1285   if (!dsc)
1286     return FSDP_ADDRESS_TYPE_UNDEFINED;
1287   return dsc->c_address_type;
1288 }
1289 
1290 const char *
fsdp_get_global_conn_address(const fsdp_description_t * dsc)1291 fsdp_get_global_conn_address (const fsdp_description_t * dsc)
1292 {
1293   if (!dsc)
1294     return NULL;
1295   return dsc->c_address.address;
1296 }
1297 
1298 unsigned int
fsdp_get_global_conn_address_ttl(const fsdp_description_t * dsc)1299 fsdp_get_global_conn_address_ttl (const fsdp_description_t * dsc)
1300 {
1301   if (!dsc)
1302     return 0;
1303   return dsc->c_address.address_ttl;
1304 }
1305 
1306 unsigned int
fsdp_get_global_conn_address_count(const fsdp_description_t * dsc)1307 fsdp_get_global_conn_address_count (const fsdp_description_t * dsc)
1308 {
1309   if (!dsc)
1310     return 0;
1311   return dsc->c_address.address_count;
1312 }
1313 
1314 unsigned int
fsdp_get_bw_modifier_count(const fsdp_description_t * dsc)1315 fsdp_get_bw_modifier_count (const fsdp_description_t * dsc)
1316 {
1317   if (!dsc)
1318     return 0;
1319   return dsc->bw_modifiers_count;
1320 }
1321 
1322 fsdp_bw_modifier_type_t
fsdp_get_bw_modifier_type(const fsdp_description_t * dsc,unsigned int index)1323 fsdp_get_bw_modifier_type (const fsdp_description_t * dsc, unsigned int index)
1324 {
1325   if ((!dsc) || (index >= dsc->bw_modifiers_count))
1326     return FSDP_BW_MOD_TYPE_UNDEFINED;
1327   return dsc->bw_modifiers[index].b_mod_type;
1328 }
1329 
1330 const char *
fsdp_get_bw_modifier_type_unknown(const fsdp_description_t * dsc,unsigned int index)1331 fsdp_get_bw_modifier_type_unknown (const fsdp_description_t * dsc,
1332 				   unsigned int index)
1333 {
1334   if ((!dsc) || (index >= dsc->bw_modifiers_count) ||
1335       (dsc->bw_modifiers[index].b_mod_type != FSDP_BW_MOD_TYPE_UNKNOWN))
1336     return NULL;
1337   return dsc->bw_modifiers[index].b_unknown_bw_modt;
1338 }
1339 
1340 unsigned long int
fsdp_get_bw_value(const fsdp_description_t * dsc,unsigned int index)1341 fsdp_get_bw_value (const fsdp_description_t * dsc, unsigned int index)
1342 {
1343   if ((!dsc) || (index >= dsc->bw_modifiers_count))
1344     return 0;
1345   return dsc->bw_modifiers[index].b_value;
1346 }
1347 
1348 time_t
fsdp_get_period_start(const fsdp_description_t * dsc,unsigned int index)1349 fsdp_get_period_start (const fsdp_description_t * dsc, unsigned int index)
1350 {
1351   if ((!dsc) || (index >= dsc->time_periods_count))
1352     return 0;
1353   return dsc->time_periods[index]->start;
1354 }
1355 
1356 time_t
fsdp_get_period_stop(const fsdp_description_t * dsc,unsigned int index)1357 fsdp_get_period_stop (const fsdp_description_t * dsc, unsigned int index)
1358 {
1359   if ((!dsc) || (index >= dsc->time_periods_count))
1360     return 0;
1361   return dsc->time_periods[index]->stop;
1362 }
1363 
1364 unsigned int
fsdp_get_period_repeats_count(const fsdp_description_t * dsc,unsigned int index)1365 fsdp_get_period_repeats_count (const fsdp_description_t * dsc,
1366 			       unsigned int index)
1367 {
1368   if ((!dsc) || (index >= dsc->time_periods_count))
1369     return 0;
1370   return dsc->time_periods[index]->repeats_count;
1371 }
1372 
1373 unsigned long int
fsdp_get_period_repeat_interval(const fsdp_description_t * dsc,unsigned int index,unsigned int rindex)1374 fsdp_get_period_repeat_interval (const fsdp_description_t * dsc,
1375 				 unsigned int index, unsigned int rindex)
1376 {
1377   if ((!dsc) || (index >= dsc->time_periods_count))
1378     return 0;
1379   return dsc->time_periods[index]->repeats[rindex]->interval;
1380 }
1381 
1382 unsigned long int
fsdp_get_period_repeat_duration(const fsdp_description_t * dsc,unsigned int index,unsigned int rindex)1383 fsdp_get_period_repeat_duration (const fsdp_description_t * dsc,
1384 				 unsigned int index, unsigned int rindex)
1385 {
1386   if ((!dsc) || (index >= dsc->time_periods_count))
1387     return 0;
1388   return dsc->time_periods[index]->repeats[rindex]->duration;
1389 }
1390 
1391 const unsigned long int *
fsdp_get_period_repeat_offsets(const fsdp_description_t * dsc,unsigned int index,unsigned int rindex)1392 fsdp_get_period_repeat_offsets (const fsdp_description_t * dsc,
1393 				unsigned int index, unsigned int rindex)
1394 {
1395   if ((!dsc) || (index >= dsc->time_periods_count))
1396     return NULL;
1397   return dsc->time_periods[index]->repeats[rindex]->offsets;
1398 }
1399 
1400 const char *
fsdp_get_timezone_adj(const fsdp_description_t * dsc)1401 fsdp_get_timezone_adj (const fsdp_description_t * dsc)
1402 {
1403   if (!dsc)
1404     return NULL;
1405   return dsc->timezone_adj;
1406 }
1407 
1408 unsigned int
fsdp_get_unidentified_attribute_count(const fsdp_description_t * dsc)1409 fsdp_get_unidentified_attribute_count (const fsdp_description_t * dsc)
1410 {
1411   if (!dsc)
1412     return 0;
1413   return dsc->unidentified_attributes_count;
1414 }
1415 
1416 const char *
fsdp_get_unidentified_attribute(const fsdp_description_t * dsc,unsigned int index)1417 fsdp_get_unidentified_attribute (const fsdp_description_t * dsc,
1418 				 unsigned int index)
1419 {
1420   if (!dsc || (index < dsc->unidentified_attributes_count))
1421     return NULL;
1422   return dsc->unidentified_attributes[index];
1423 }
1424 
1425 fsdp_encryption_method_t
fsdp_get_encryption_method(const fsdp_description_t * dsc)1426 fsdp_get_encryption_method (const fsdp_description_t * dsc)
1427 {
1428   if (!dsc)
1429     return FSDP_ENCRYPTION_METHOD_UNDEFINED;
1430   return dsc->k_encryption_method;
1431 }
1432 
1433 const char *
fsdp_get_encryption_content(const fsdp_description_t * dsc)1434 fsdp_get_encryption_content (const fsdp_description_t * dsc)
1435 {
1436   if (!dsc || (dsc->k_encryption_method == FSDP_ENCRYPTION_METHOD_UNDEFINED))
1437     return NULL;
1438   return dsc->k_encryption_content;
1439 }
1440 
1441 const char *
fsdp_get_str_att(const fsdp_description_t * dsc,fsdp_session_str_att_t att)1442 fsdp_get_str_att (const fsdp_description_t * dsc, fsdp_session_str_att_t att)
1443 {
1444   /*TODO: change these individual attributes with a table, thus
1445     avoiding this slow switch */
1446   char *result;
1447 
1448   if (!dsc)
1449     return NULL;
1450 
1451   switch (att)
1452   {
1453   case FSDP_SESSION_STR_ATT_CATEGORY:
1454     result = dsc->a_category;
1455     break;
1456   case FSDP_SESSION_STR_ATT_KEYWORDS:
1457     result = dsc->a_keywords;
1458     break;
1459   case FSDP_SESSION_STR_ATT_TOOL:
1460     result = dsc->a_tool;
1461     break;
1462   case FSDP_SESSION_STR_ATT_CHARSET:
1463     result = dsc->a_charset;
1464     break;
1465   default:
1466     result = NULL;
1467   }
1468   return result;
1469 }
1470 
1471 unsigned int
fsdp_get_sdplang_count(const fsdp_description_t * dsc)1472 fsdp_get_sdplang_count (const fsdp_description_t * dsc)
1473 {
1474   if (!dsc)
1475     return 0;
1476   return dsc->a_sdplangs_count;
1477 }
1478 
1479 const char *
fsdp_get_sdplang(const fsdp_description_t * dsc,unsigned int index)1480 fsdp_get_sdplang (const fsdp_description_t * dsc, unsigned int index)
1481 {
1482   if ((!dsc) || (index >= dsc->a_sdplangs_count))
1483     return NULL;
1484   return dsc->a_sdplangs[index];
1485 }
1486 
1487 unsigned int
fsdp_get_control_count(const fsdp_description_t * dsc)1488 fsdp_get_control_count (const fsdp_description_t * dsc)
1489 {
1490   if (!dsc)
1491     return 0;
1492   return dsc->a_controls_count;
1493 }
1494 
1495 const char *
fsdp_get_control(const fsdp_description_t * dsc,unsigned int index)1496 fsdp_get_control (const fsdp_description_t * dsc, unsigned int index)
1497 {
1498   if ((!dsc) || (index >= dsc->a_controls_count))
1499     return NULL;
1500   return dsc->a_controls[index];
1501 }
1502 
1503 const char *
fsdp_get_range(const fsdp_description_t * dsc)1504 fsdp_get_range (const fsdp_description_t * dsc)
1505 {
1506   return dsc->a_range;
1507 }
1508 
1509 fsdp_sendrecv_mode_t
fsdp_get_sendrecv_mode(const fsdp_description_t * dsc)1510 fsdp_get_sendrecv_mode (const fsdp_description_t * dsc)
1511 {
1512   if (!dsc)
1513     return FSDP_SENDRECV_UNDEFINED;
1514   return dsc->a_sendrecv_mode;
1515 }
1516 
1517 fsdp_session_type_t
fsdp_get_session_type(const fsdp_description_t * dsc)1518 fsdp_get_session_type (const fsdp_description_t * dsc)
1519 {
1520   if (!dsc)
1521     return FSDP_SESSION_TYPE_UNDEFINED;
1522   return dsc->a_type;
1523 }
1524 
1525 unsigned int
fsdp_get_media_count(const fsdp_description_t * dsc)1526 fsdp_get_media_count (const fsdp_description_t * dsc)
1527 {
1528   if (!dsc)
1529     return 0;
1530   return dsc->media_announcements_count;
1531 }
1532 
1533 const fsdp_media_description_t *
fsdp_get_media(const fsdp_description_t * dsc,unsigned int index)1534 fsdp_get_media (const fsdp_description_t * dsc, unsigned int index)
1535 {
1536   if ((index >= dsc->media_announcements_count))
1537     return NULL;
1538   return dsc->media_announcements[index];
1539 }
1540 
1541 fsdp_media_t
fsdp_get_media_type(const fsdp_media_description_t * dsc)1542 fsdp_get_media_type (const fsdp_media_description_t * dsc)
1543 {
1544   if (!dsc)
1545     return FSDP_MEDIA_UNDEFINED;
1546   return dsc->media_type;
1547 }
1548 
1549 unsigned int
fsdp_get_media_port(const fsdp_media_description_t * dsc)1550 fsdp_get_media_port (const fsdp_media_description_t * dsc)
1551 {
1552   if (!dsc)
1553     return 0;
1554   return dsc->port;
1555 }
1556 
1557 unsigned int
fsdp_get_media_port_count(const fsdp_media_description_t * dsc)1558 fsdp_get_media_port_count (const fsdp_media_description_t * dsc)
1559 {
1560   if (!dsc)
1561     return 0;
1562   return dsc->port_count;
1563 }
1564 
1565 fsdp_transport_protocol_t
fsdp_get_media_transport_protocol(const fsdp_media_description_t * dsc)1566 fsdp_get_media_transport_protocol (const fsdp_media_description_t * dsc)
1567 {
1568   if (!dsc)
1569     return FSDP_TP_UNDEFINED;
1570   return dsc->transport;
1571 }
1572 
1573 unsigned int
fsdp_get_media_formats_count(const fsdp_media_description_t * dsc)1574 fsdp_get_media_formats_count (const fsdp_media_description_t * dsc)
1575 {
1576   if (!dsc)
1577     return 0;
1578   return dsc->formats_count;
1579 }
1580 
1581 const char *
fsdp_get_media_format(const fsdp_media_description_t * dsc,unsigned int index)1582 fsdp_get_media_format (const fsdp_media_description_t * dsc,
1583 		       unsigned int index)
1584 {
1585   if (!dsc || (index < dsc->formats_count - 1))
1586     return NULL;
1587   return dsc->formats[index];
1588 }
1589 
1590 const char *
fsdp_get_media_title(const fsdp_media_description_t * dsc)1591 fsdp_get_media_title (const fsdp_media_description_t * dsc)
1592 {
1593   if (!dsc)
1594     return NULL;
1595   return dsc->i_title;
1596 }
1597 
1598 fsdp_network_type_t
fsdp_get_media_network_type(const fsdp_media_description_t * dsc)1599 fsdp_get_media_network_type (const fsdp_media_description_t * dsc)
1600 {
1601   if (!dsc)
1602     return FSDP_NETWORK_TYPE_UNDEFINED;
1603   return dsc->c_network_type;
1604 }
1605 
1606 fsdp_address_type_t
fsdp_get_media_address_type(const fsdp_media_description_t * dsc)1607 fsdp_get_media_address_type (const fsdp_media_description_t * dsc)
1608 {
1609   if (!dsc)
1610     return FSDP_ADDRESS_TYPE_UNDEFINED;
1611   return dsc->c_address_type;
1612 }
1613 
1614 const char *
fsdp_get_media_address(const fsdp_media_description_t * dsc)1615 fsdp_get_media_address (const fsdp_media_description_t * dsc)
1616 {
1617   if (!dsc)
1618     return NULL;
1619   return dsc->c_address.address;
1620 }
1621 
1622 unsigned int
fsdp_get_media_address_ttl(const fsdp_media_description_t * mdsc)1623 fsdp_get_media_address_ttl (const fsdp_media_description_t * mdsc)
1624 {
1625   if (!mdsc)
1626     return 0;
1627   return mdsc->c_address.address_ttl;
1628 }
1629 
1630 unsigned int
fsdp_get_media_address_count(const fsdp_media_description_t * mdsc)1631 fsdp_get_media_address_count (const fsdp_media_description_t * mdsc)
1632 {
1633   if (!mdsc)
1634     return 0;
1635   return mdsc->c_address.address_count;
1636 }
1637 
1638 fsdp_bw_modifier_type_t
fsdp_get_media_bw_modifier_type(const fsdp_media_description_t * dsc,unsigned int index)1639 fsdp_get_media_bw_modifier_type (const fsdp_media_description_t * dsc,
1640 				 unsigned int index)
1641 {
1642   if (!dsc || (index >= dsc->bw_modifiers_count))
1643     return FSDP_BW_MOD_TYPE_UNDEFINED;
1644   return dsc->bw_modifiers[index].b_mod_type;
1645 }
1646 
1647 const char *
fsdp_get_media_bw_modifier_type_unknown(const fsdp_media_description_t * dsc,unsigned int index)1648 fsdp_get_media_bw_modifier_type_unknown (const fsdp_media_description_t * dsc,
1649 					 unsigned int index)
1650 {
1651   if (!dsc || (index >= dsc->bw_modifiers_count) ||
1652       (FSDP_BW_MOD_TYPE_UNKNOWN != dsc->bw_modifiers[index].b_mod_type))
1653     return NULL;
1654   return dsc->bw_modifiers[index].b_unknown_bw_modt;
1655 }
1656 
1657 unsigned long int
fsdp_get_media_bw_value(const fsdp_media_description_t * dsc,unsigned int index)1658 fsdp_get_media_bw_value (const fsdp_media_description_t * dsc,
1659 			 unsigned int index)
1660 {
1661   if (!dsc || (index >= dsc->bw_modifiers_count))
1662     return 0;
1663   return dsc->bw_modifiers[index].b_value;
1664 }
1665 
1666 fsdp_encryption_method_t
fsdp_get_media_encryption_method(const fsdp_media_description_t * dsc)1667 fsdp_get_media_encryption_method (const fsdp_media_description_t * dsc)
1668 {
1669   if (!dsc)
1670     return FSDP_ENCRYPTION_METHOD_UNDEFINED;
1671   return dsc->k_encryption_method;
1672 }
1673 
1674 const char *
fsdp_get_media_encryption_content(const fsdp_media_description_t * dsc)1675 fsdp_get_media_encryption_content (const fsdp_media_description_t * dsc)
1676 {
1677   if (!dsc)
1678     return NULL;
1679   return dsc->k_encryption_content;
1680 }
1681 
1682 unsigned int
fsdp_get_media_ptime(const fsdp_media_description_t * dsc)1683 fsdp_get_media_ptime (const fsdp_media_description_t * dsc)
1684 {
1685   if (!dsc)
1686     return 0;
1687   return dsc->a_ptime;
1688 }
1689 
1690 unsigned int
fsdp_get_media_maxptime(const fsdp_media_description_t * dsc)1691 fsdp_get_media_maxptime (const fsdp_media_description_t * dsc)
1692 {
1693   if (!dsc)
1694     return 0;
1695   return dsc->a_maxptime;
1696 }
1697 
1698 unsigned int
fsdp_get_media_rtpmap_count(const fsdp_media_description_t * mdsc)1699 fsdp_get_media_rtpmap_count (const fsdp_media_description_t * mdsc)
1700 {
1701   if (!mdsc)
1702     return 0;
1703   return mdsc->a_rtpmaps_count;
1704 }
1705 
1706 const char *
fsdp_get_media_rtpmap_payload_type(const fsdp_media_description_t * mdsc,unsigned int index)1707 fsdp_get_media_rtpmap_payload_type (const fsdp_media_description_t * mdsc,
1708 				    unsigned int index)
1709 {
1710   if (!mdsc || (index >= mdsc->a_rtpmaps_count))
1711     return NULL;
1712   return mdsc->a_rtpmaps[index]->pt;
1713 }
1714 
1715 const char *
fsdp_get_media_rtpmap_encoding_name(const fsdp_media_description_t * mdsc,unsigned int index)1716 fsdp_get_media_rtpmap_encoding_name (const fsdp_media_description_t * mdsc,
1717 				     unsigned int index)
1718 {
1719   if (!mdsc || (index >= mdsc->a_rtpmaps_count))
1720     return NULL;
1721   return mdsc->a_rtpmaps[index]->encoding_name;
1722 }
1723 
1724 unsigned int
fsdp_get_media_rtpmap_clock_rate(const fsdp_media_description_t * mdsc,unsigned int index)1725 fsdp_get_media_rtpmap_clock_rate (const fsdp_media_description_t * mdsc,
1726 				  unsigned int index)
1727 {
1728   if (!mdsc || (index >= mdsc->a_rtpmaps_count))
1729     return 0;
1730   return mdsc->a_rtpmaps[index]->clock_rate;
1731 }
1732 
1733 const char *
fsdp_get_media_rtpmap_encoding_parameters(const fsdp_description_t * mdsc,unsigned int index)1734 fsdp_get_media_rtpmap_encoding_parameters (const fsdp_description_t * mdsc,
1735 					   unsigned int index)
1736 {
1737   if (!mdsc || (index >= mdsc->a_rtpmaps_count))
1738     return NULL;
1739   return mdsc->a_rtpmaps[index]->parameters;
1740 }
1741 
1742 unsigned int
fsdp_get_media_sdplang_count(const fsdp_media_description_t * mdsc)1743 fsdp_get_media_sdplang_count (const fsdp_media_description_t * mdsc)
1744 {
1745   if (!mdsc)
1746     return 0;
1747   return mdsc->a_sdplangs_count;
1748 }
1749 
1750 const char *
fsdp_get_media_sdplang(const fsdp_media_description_t * mdsc,unsigned int index)1751 fsdp_get_media_sdplang (const fsdp_media_description_t * mdsc,
1752 			unsigned int index)
1753 {
1754   if (!mdsc || (index >= mdsc->a_sdplangs_count))
1755     return NULL;
1756   return mdsc->a_sdplangs[index];
1757 }
1758 
1759 unsigned int
fsdp_get_media_lang_count(const fsdp_media_description_t * mdsc)1760 fsdp_get_media_lang_count (const fsdp_media_description_t * mdsc)
1761 {
1762   if (!mdsc)
1763     return 0;
1764   return mdsc->a_langs_count;
1765 }
1766 
1767 const char *
fsdp_get_media_lang(const fsdp_media_description_t * mdsc,unsigned int index)1768 fsdp_get_media_lang (const fsdp_media_description_t * mdsc,
1769 		     unsigned int index)
1770 {
1771   if (!mdsc || (index >= mdsc->a_langs_count))
1772     return NULL;
1773   return mdsc->a_langs[index];
1774 }
1775 
1776 unsigned int
fsdp_get_media_control_count(const fsdp_media_description_t * mdsc)1777 fsdp_get_media_control_count (const fsdp_media_description_t * mdsc)
1778 {
1779   if (!mdsc)
1780     return 0;
1781   return mdsc->a_controls_count;
1782 }
1783 
1784 char *
fsdp_get_media_control(const fsdp_media_description_t * mdsc,unsigned int index)1785 fsdp_get_media_control (const fsdp_media_description_t * mdsc,
1786 			unsigned int index)
1787 {
1788   if (!mdsc || (index >= mdsc->a_controls_count))
1789     return NULL;
1790   return mdsc->a_controls[index];
1791 }
1792 
1793 char *
fsdp_get_media_range(const fsdp_media_description_t * mdsc)1794 fsdp_get_media_range (const fsdp_media_description_t * mdsc)
1795 {
1796   return mdsc->a_range;
1797 }
1798 
1799 unsigned int
fsdp_get_media_fmtp_count(const fsdp_media_description_t * mdsc)1800 fsdp_get_media_fmtp_count (const fsdp_media_description_t * mdsc)
1801 {
1802   if (!mdsc)
1803     return 0;
1804   return mdsc->a_fmtps_count;
1805 }
1806 
1807 const char *
fsdp_get_media_fmtp(const fsdp_media_description_t * mdsc,unsigned int index)1808 fsdp_get_media_fmtp (const fsdp_media_description_t * mdsc,
1809 		     unsigned int index)
1810 {
1811   if (!mdsc || (index >= mdsc->a_fmtps_count))
1812     return NULL;
1813   return mdsc->a_fmtps[index];
1814 }
1815 
1816 fsdp_orient_t
fsdp_get_media_orient(const fsdp_media_description_t * dsc)1817 fsdp_get_media_orient (const fsdp_media_description_t * dsc)
1818 {
1819   if (!dsc)
1820     return FSDP_ORIENT_UNDEFINED;
1821   return dsc->a_orient;
1822 }
1823 
1824 fsdp_sendrecv_mode_t
fsdp_get_media_sendrecv(const fsdp_media_description_t * dsc)1825 fsdp_get_media_sendrecv (const fsdp_media_description_t * dsc)
1826 {
1827   if (!dsc)
1828     return FSDP_SENDRECV_UNDEFINED;
1829   return dsc->a_sendrecv_mode;
1830 }
1831 
1832 float
fsdp_get_media_framerate(const fsdp_media_description_t * dsc)1833 fsdp_get_media_framerate (const fsdp_media_description_t * dsc)
1834 {
1835   if (!dsc)
1836     return 0;
1837   return dsc->a_framerate;
1838 }
1839 
1840 unsigned int
fsdp_get_media_quality(const fsdp_media_description_t * dsc)1841 fsdp_get_media_quality (const fsdp_media_description_t * dsc)
1842 {
1843   if (!dsc)
1844     return 0;
1845   return dsc->a_quality;
1846 }
1847 
1848 unsigned int
fsdp_get_media_rtcp_port(const fsdp_media_description_t * dsc)1849 fsdp_get_media_rtcp_port (const fsdp_media_description_t * dsc)
1850 {
1851   if (!dsc)
1852     return 0;
1853   return dsc->a_rtcp_port;
1854 }
1855 
1856 fsdp_network_type_t
fsdp_get_media_rtcp_network_type(const fsdp_media_description_t * dsc)1857 fsdp_get_media_rtcp_network_type (const fsdp_media_description_t * dsc)
1858 {
1859   if (!dsc)
1860     return FSDP_NETWORK_TYPE_UNDEFINED;
1861   return dsc->a_rtcp_network_type;
1862 }
1863 
1864 fsdp_address_type_t
fsdp_get_media_rtcp_address_type(const fsdp_media_description_t * dsc)1865 fsdp_get_media_rtcp_address_type (const fsdp_media_description_t * dsc)
1866 {
1867   if (!dsc)
1868     return FSDP_ADDRESS_TYPE_UNDEFINED;
1869   return dsc->a_rtcp_address_type;
1870 }
1871 
1872 const char *
fsdp_get_media_rtcp_address(const fsdp_media_description_t * dsc)1873 fsdp_get_media_rtcp_address (const fsdp_media_description_t * dsc)
1874 {
1875   if (!dsc)
1876     return NULL;
1877   return dsc->a_rtcp_address;
1878 }
1879 
1880 unsigned int
fsdp_get_media_unidentified_attribute_count(const fsdp_media_description_t * mdsc)1881 fsdp_get_media_unidentified_attribute_count (const fsdp_media_description_t
1882 					     * mdsc)
1883 {
1884   if (!mdsc)
1885     return 0;
1886   return mdsc->unidentified_attributes_count;
1887 }
1888 
1889 const char *
fsdp_get_media_unidentified_attribute(const fsdp_media_description_t * mdsc,unsigned int index)1890 fsdp_get_media_unidentified_attribute (const fsdp_media_description_t * mdsc,
1891 				       unsigned int index)
1892 {
1893   if (!mdsc || (index < mdsc->unidentified_attributes_count))
1894     return NULL;
1895   return mdsc->unidentified_attributes[index];
1896 }
1897