1 /*
2  * This file is part of the Sofia-SIP package
3  *
4  * Copyright (C) 2005 Nokia Corporation.
5  *
6  * Contact: Pekka Pessi <pekka.pessi@nokia.com>
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public License
10  * as published by the Free Software Foundation; either version 2.1 of
11  * the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
21  * 02110-1301 USA
22  *
23  */
24 
25 /**@ingroup sdp_parser
26  * @CFILE sdp_parse.c
27  * @brief Simple SDP parser interface.
28  *
29  * @author Pekka Pessi <Pekka.Pessi@nokia.com>
30  * @author Kai Vehmanen <kai.vehmanen@nokia.com>
31  *
32  * @date  Created: Fri Feb 18 10:25:08 2000 ppessi
33  *
34  * @sa @RFC4566, @RFC2327.
35  */
36 
37 #include "config.h"
38 
39 #include <sofia-sip/su_alloc.h>
40 #include <sofia-sip/su_string.h>
41 
42 #include "sofia-sip/sdp.h"
43 
44 #include <stddef.h>
45 #include <stdlib.h>
46 #include <string.h>
47 #include <stdarg.h>
48 #include <stdio.h>
49 #include <limits.h>
50 #include <assert.h>
51 
52 /** @typedef struct sdp_parser_s sdp_parser_t;
53  *
54  * SDP parser handle.
55  *
56  * The SDP parser handle returned by sdp_parse() contains either
57  * a successfully parsed SDP session #sdp_session_t or an error message.
58  * If sdp_session() returns non-NULL, parsing was successful.
59  *
60  * @sa #sdp_session_t, sdp_parse(), sdp_session(), sdp_parsing_error(),
61  * sdp_sanity_check(), sdp_parser_home(), sdp_parser_free(), @RFC4566,
62  * @RFC2327.
63  */
64 
65 struct sdp_parser_s {
66   su_home_t       pr_home[1];
67   union {
68     char          pru_error[128];
69     sdp_session_t pru_session[1];
70   } pr_output;
71   char      *pr_message;
72 
73   sdp_mode_t pr_session_mode;
74 
75   unsigned   pr_ok : 1;
76 
77   unsigned   pr_strict : 1;
78   unsigned   pr_anynet : 1;
79   unsigned   pr_mode_0000 : 1;
80   unsigned   pr_mode_manual : 1;
81   unsigned   pr_insane : 1;
82   unsigned   pr_c_missing : 1;
83   unsigned   pr_config : 1;
84 };
85 
86 #define is_posdigit(c) ((c) >= '1' && (c) <= '9')
87 #define is_digit(c) ((c) >= '0' && (c) <= '9')
88 #define is_space(c) ((c) == ' ')
89 #define is_tab(c) ((c) == '\t')
90 
91 #define pr_error   pr_output.pru_error
92 #define pr_session pr_output.pru_session
93 
94 #ifdef _MSC_VER
95 #undef STRICT
96 #endif
97 #define STRICT(pr) (pr->pr_strict)
98 
99 /* Static parser object used when running out of memory */
100 static const struct sdp_parser_s no_mem_error =
101 {
102   { SU_HOME_INIT(no_mem_error) },
103   { "sdp: not enough memory" }
104 };
105 
106 /* Internal prototypes */
107 static void parse_message(sdp_parser_t *p);
108 static int parsing_error(sdp_parser_t *p, char const *fmt, ...);
109 
110 /** Parse an SDP message.
111  *
112  * The function sdp_parse() parses an SDP message @a msg of size @a
113  * msgsize. Parsing is done according to the given @a flags. The SDP message
114  * may not contain a NUL.
115  *
116  * The parsing result is stored to an #sdp_session_t structure.
117  *
118  * @param home    memory home
119  * @param msg     pointer to message
120  * @param msgsize size of the message (excluding final NUL, if any)
121  * @param flags   flags affecting the parsing.
122  *
123  * The following flags are used by parser:
124  *
125  * @li #sdp_f_strict Parser should accept only messages conforming strictly
126  *                   to the specification.
127  * @li #sdp_f_anynet Parser accepts unknown network or address types.
128  * @li #sdp_f_insane Do not run sanity check.
129  * @li #sdp_f_c_missing  Sanity check does not require c= for each m= line
130  * @li #sdp_f_mode_0000 Parser regards "c=IN IP4 0.0.0.0" as "a=inactive"
131  *                      (likewise with c=IN IP6 ::)
132  * @li #sdp_f_mode_manual Do not generate or parse SDP mode
133  * @li #sdp_f_config   Parse config files (any line can be missing)
134  *
135  * @return
136  * Always a valid parser handle.
137  *
138  * @todo Parser accepts some non-conforming SDP even with #sdp_f_strict.
139  *
140  * @sa sdp_session(), sdp_parsing_error(), sdp_sanity_check(),
141  * sdp_parser_home(), sdp_parser_free(), @RFC4566, @RFC2327.
142  */
143 sdp_parser_t *
sdp_parse(su_home_t * home,char const msg[],issize_t msgsize,int flags)144 sdp_parse(su_home_t *home, char const msg[], issize_t msgsize, int flags)
145 {
146   sdp_parser_t *p;
147   char *b;
148   size_t len;
149 
150   if (msgsize == -1 || msg == NULL) {
151     p = su_home_clone(home, sizeof(*p));
152     if (p)
153       parsing_error(p, "invalid input message");
154     else
155       p = (sdp_parser_t*)&no_mem_error;
156     return p;
157   }
158 
159   if (msgsize == -1 && msg)
160     len = strlen(msg);
161   else
162     len = msgsize;
163 
164   if (len > ISSIZE_MAX)
165     len = ISSIZE_MAX;
166 
167   p = su_home_clone(home, sizeof(*p) + len + 1);
168 
169   if (p) {
170     b = strncpy((void *)(p + 1), msg, len);
171     b[len] = 0;
172 
173     p->pr_message = b;
174     p->pr_strict = (flags & sdp_f_strict) != 0;
175     p->pr_anynet = (flags & sdp_f_anynet) != 0;
176     p->pr_mode_0000 = (flags & sdp_f_mode_0000) != 0;
177     p->pr_insane = (flags & sdp_f_insane) != 0;
178     p->pr_c_missing = (flags & sdp_f_c_missing) != 0;
179     if (flags & sdp_f_config)
180       p->pr_c_missing = 1, p->pr_config = 1;
181     p->pr_mode_manual = (flags & sdp_f_mode_manual) != 0;
182     p->pr_session_mode = sdp_sendrecv;
183 
184     parse_message(p);
185 
186     return p;
187   }
188 
189   if (p)
190     sdp_parser_free(p);
191 
192   return (sdp_parser_t*)&no_mem_error;
193 }
194 
195 
196 /** Obtain memory home used by parser */
sdp_parser_home(sdp_parser_t * parser)197 su_home_t *sdp_parser_home(sdp_parser_t *parser)
198 {
199   if (parser != &no_mem_error)
200     return parser->pr_home;
201   else
202     return NULL;
203 }
204 
205 /** Retrieve an SDP session structure.
206  *
207  * The function sdp_session() returns a pointer to the SDP session
208  * structure associated with the SDP parser @a p. The pointer and all the
209  * data in the structure are valid until sdp_parser_free() is called.
210  *
211  * @param p SDP parser
212  *
213  * @return
214  *   The function sdp_session() returns a pointer to an parsed SDP message
215  *   or NULL, if an error has occurred.  */
216 sdp_session_t *
sdp_session(sdp_parser_t * p)217 sdp_session(sdp_parser_t *p)
218 {
219   return p && p->pr_ok ? p->pr_session : NULL;
220 }
221 
222 /** Get a parsing error message.
223  *
224  * The function sdp_parsing_error() returns the error message associated
225  * with an SDP parser @a p.
226  *
227  * @param p SDP parser
228  *
229  * @return
230  * The function sdp_parsing_error() returns a C string describing parsing
231  * error, or NULL if no error occurred.
232  */
sdp_parsing_error(sdp_parser_t * p)233 char const *sdp_parsing_error(sdp_parser_t *p)
234 {
235   return !p->pr_ok ? p->pr_error : NULL;
236 }
237 
238 /** Free an SDP parser.
239  *
240  * The function sdp_parser_free() frees an SDP parser object along with
241  * the memory blocks associated with it.
242  *
243  * @param p pointer to the SDP parser to be freed
244  */
sdp_parser_free(sdp_parser_t * p)245 void sdp_parser_free(sdp_parser_t *p)
246 {
247   if (p && p != &no_mem_error)
248     su_home_unref(p->pr_home);
249 }
250 
251 /* ========================================================================= */
252 
253 /* =========================================================================
254  * Private part
255  */
256 
257 /* Parsing tokens */
258 #define SPACE " "
259 #define TAB   "\011"
260 #define CRLF  "\015\012"
261 #define ALPHA "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
262 #define DIGIT "0123456789"
263 #define TOKEN ALPHA DIGIT "-!#$%&'*+.^_`{|}~"
264 
265 /* ========================================================================= */
266 /* Parsing functions */
267 
268 static void post_session(sdp_parser_t *p, sdp_session_t *sdp);
269 static void parse_origin(sdp_parser_t *p, char *r, sdp_origin_t **result);
270 static void parse_subject(sdp_parser_t *p, char *r, sdp_text_t **result);
271 static void parse_information(sdp_parser_t *p, char *r, sdp_text_t **result);
272 static void parse_uri(sdp_parser_t *p, char *r, sdp_text_t **result);
273 static void parse_email(sdp_parser_t *p, char *r, sdp_list_t **result);
274 static void parse_phone(sdp_parser_t *p, char *r, sdp_list_t **result);
275 static void parse_connection(sdp_parser_t *p, char *r, sdp_connection_t **result);
276 static void parse_bandwidth(sdp_parser_t *p, char *r, sdp_bandwidth_t **result);
277 static void parse_time(sdp_parser_t *p, char *r, sdp_time_t **result);
278 static void parse_repeat(sdp_parser_t *p, char *r, sdp_repeat_t **result);
279 static void parse_zone(sdp_parser_t *p, char *r, sdp_zone_t **result);
280 static void parse_key(sdp_parser_t *p, char *r, sdp_key_t **result);
281 static void parse_session_attr(sdp_parser_t *p, char *r, sdp_attribute_t **result);
282 static void parse_media(sdp_parser_t *p, char *r, sdp_media_t **result);
283 static void parse_payload(sdp_parser_t *p, char *r, sdp_rtpmap_t **result);
284 static void parse_media_attr(sdp_parser_t *p, char *r, sdp_media_t *m,
285 			     sdp_attribute_t **result);
286 static int parse_rtpmap(sdp_parser_t *p, char *r, sdp_media_t *m);
287 static int parse_fmtp(sdp_parser_t *p, char *r, sdp_media_t *m);
288 static void parse_text_list(sdp_parser_t *p, char *r, sdp_list_t **result);
289 
290 static void parse_descs(sdp_parser_t *p, char *r, char *m, sdp_media_t **result);
291 
292 static int parse_ul(sdp_parser_t *p, char **r, unsigned long *result,
293 		    unsigned long max_value);
294 static int parse_ull(sdp_parser_t *p, char **r, uint64_t *result,
295 		     uint64_t max_value);
296 static void parse_alloc_error(sdp_parser_t *p, const char *typename);
297 static char *next(char **message, const char *sep, const char *strip);
298 static char *token(char **message, const char *sep, const char *legal,
299 		   const char *strip);
300 #if 0
301 static void check_mandatory(sdp_parser_t *p, sdp_session_t *sdp);
302 #endif
303 
304 /* -------------------------------------------------------------------------
305  * Macro PARSE_ALLOC
306  *
307  * Description:
308  *   This macro declares a pointer (v) of given type (t). It then allocates
309  *   an structure of given type (t). If allocation was succesful, it assigns
310  *   the XX_size member with appropriate value.
311  */
312 #define PARSE_ALLOC(p, t, v) \
313  t *v = su_salloc(p->pr_home, sizeof(*v)); \
314  if (!v && (parse_alloc_error(p, #t), 1)) return;
315 
316 /* -------------------------------------------------------------------------
317  * Macro PARSE_CHECK_REST
318  *
319  * Description:
320  *   This macro check if there is extra data at the end of field.
321  */
322 #define PARSE_CHECK_REST(p, s, n)\
323  if (*s && (parsing_error(p, "extra data after %s (\"%.04s\")", n, s), 1)) \
324     return
325 
326 /* -------------------------------------------------------------------------
327  * Function parse_message() - parse an SDP message
328  *
329  * Description:
330  *   This function parses an SDP message, which is copied into the
331  *   p->pr_message. The p->pr_message is modified during the parsing,
332  *   and parts of it are returned in p->pr_session.
333  *
334  * Parameters:
335  *   p - pointer to SDP parser object
336  */
parse_message(sdp_parser_t * p)337 static void parse_message(sdp_parser_t *p)
338 {
339 /*
340    announcement =        proto-version
341                          origin-field
342                          session-name-field
343                          information-field
344                          uri-field
345                          email-fields
346                          phone-fields
347                          connection-field
348                          bandwidth-fields
349                          time-fields
350                          key-field
351                          attribute-fields
352                          media-descriptions
353 */
354 
355   sdp_session_t *sdp = p->pr_session;
356   char *record, *rest;
357   char const *strip;
358   char *message = p->pr_message;
359   char field = '\0';
360   sdp_list_t **emails = &sdp->sdp_emails;
361   sdp_list_t **phones = &sdp->sdp_phones;
362   sdp_bandwidth_t **bandwidths = &sdp->sdp_bandwidths;
363   sdp_time_t **times = &sdp->sdp_time;
364   sdp_repeat_t **repeats = NULL;
365   sdp_zone_t **zones = NULL;
366   sdp_attribute_t **attributes = &sdp->sdp_attributes;
367 
368   if (!STRICT(p))
369     strip = SPACE TAB;		/* skip initial whitespace */
370   else
371     strip = "";
372 
373   p->pr_ok = 1;
374   p->pr_session->sdp_size = sizeof(p->pr_session);
375 
376   /* Require that version comes first */
377   record = next(&message, CRLF, strip);
378 
379   if (!su_strmatch(record, "v=0")) {
380     if (!p->pr_config || !record || record[1] != '=') {
381       parsing_error(p, "bad SDP message");
382       return;
383     }
384   }
385   else {
386     record = next(&message, CRLF, strip);
387   }
388 
389   /*
390     XXX - the lines in SDP are in certain order, which we don't check here.
391      For stricter parsing we might want to parse o= and s= next.
392   */
393 
394   for (;
395        record && p->pr_ok;
396        record = next(&message, CRLF, strip)) {
397     field = record[0];
398 
399     rest = record + 2; rest += strspn(rest, strip);
400 
401     if (record[1] != '=') {
402       parsing_error(p, "bad line \"%s\"", record);
403       return;
404     }
405 
406     switch (field) {
407     case 'o':
408       parse_origin(p, rest, &sdp->sdp_origin);
409       break;
410 
411     case 's':
412       parse_subject(p, rest, &sdp->sdp_subject);
413       break;
414 
415     case 'i':
416       parse_information(p, rest, &sdp->sdp_information);
417       break;
418 
419     case 'u':
420       parse_uri(p, rest, &sdp->sdp_uri);
421       break;
422 
423     case 'e':
424       parse_email(p, rest, emails);
425       emails = &(*emails)->l_next;
426       break;
427 
428     case 'p':
429       parse_phone(p, rest, phones);
430       phones = &(*phones)->l_next;
431       break;
432 
433     case 'c':
434       parse_connection(p, rest, &sdp->sdp_connection);
435       break;
436 
437     case 'b':
438       parse_bandwidth(p, rest, bandwidths);
439       bandwidths = &(*bandwidths)->b_next;
440       break;
441 
442     case 't':
443       parse_time(p, rest, times);
444       repeats = &(*times)->t_repeat;
445       zones = &(*times)->t_zone;
446       times = &(*times)->t_next;
447       break;
448 
449     case 'r':
450       if (repeats)
451 	parse_repeat(p, rest, repeats);
452       else
453 	parsing_error(p, "repeat field without time field");
454       break;
455 
456     case 'z':
457       if (zones)
458 	parse_zone(p, rest, zones), zones = NULL;
459       else
460 	parsing_error(p, "zone field without time field");
461       break;
462 
463     case 'k':
464       parse_key(p, rest, &sdp->sdp_key);
465       break;
466 
467     case 'a':
468       parse_session_attr(p, rest, attributes);
469       if (*attributes)
470 	attributes = &(*attributes)->a_next;
471       break;
472 
473     case 'm':
474       parse_descs(p, record, message, &sdp->sdp_media);
475       post_session(p, sdp);
476       return;
477 
478     default:
479       parsing_error(p, "unknown field \"%s\"", record);
480       return;
481     }
482   }
483 
484   post_session(p, sdp);
485 }
486 #ifdef SOFIA_AUTO_CORRECT_INADDR_ANY
sdp_connection_is_inaddr_any(sdp_connection_t const * c)487 int sdp_connection_is_inaddr_any(sdp_connection_t const *c)
488 {
489   return
490     c &&
491     c->c_nettype == sdp_net_in &&
492     ((c->c_addrtype == sdp_addr_ip4 && su_strmatch(c->c_address, "0.0.0.0")) ||
493      (c->c_addrtype == sdp_addr_ip6 && su_strmatch(c->c_address, "::")));
494 }
495 #endif
496 
497 /**Postprocess session description.
498  *
499  * Postprocessing includes setting the session backpointer for each media,
500  * doing sanity checks and setting rejected and mode flags.
501  */
post_session(sdp_parser_t * p,sdp_session_t * sdp)502 static void post_session(sdp_parser_t *p, sdp_session_t *sdp)
503 {
504   sdp_media_t *m;
505 #ifdef SOFIA_AUTO_CORRECT_INADDR_ANY
506   sdp_connection_t const *c;
507 #endif
508 
509   if (!p->pr_ok)
510     return;
511 
512   /* Set session back-pointer */
513   for (m = sdp->sdp_media; m; m = m->m_next) {
514     m->m_session = sdp;
515   }
516 
517   if (p->pr_config) {
518     if (sdp->sdp_version[0] != 0)
519       parsing_error(p, "Incorrect version");
520     return;
521   }
522 
523   /* Go through all media and set mode */
524   for (m = sdp->sdp_media; m; m = m->m_next) {
525     if (m->m_port == 0) {
526       m->m_mode = sdp_inactive;
527       m->m_rejected = 1;
528       continue;
529     }
530 
531 #ifdef SOFIA_AUTO_CORRECT_INADDR_ANY
532     c = sdp_media_connections(m);
533 
534 
535     if (p->pr_mode_0000 && sdp_connection_is_inaddr_any(c)) {
536       /* Reset recvonly flag */
537       m->m_mode &= ~sdp_recvonly;
538     }
539 #endif
540   }
541 
542   if (p->pr_insane)
543     return;
544 
545   /* Verify that all mandatory fields are present */
546   if (sdp_sanity_check(p) < 0)
547     return;
548 }
549 
550 /** Validates that all mandatory fields exist
551  *
552  * Checks that all necessary fields (v=, o=) exists in the parsed sdp. If
553  * strict, check that all mandatory fields (c=, o=, s=, t=) are present.
554  * This function also goes through all media, marks rejected media as such,
555  * and updates the mode accordingly.
556  *
557  * @retval 0 if parsed SDP description is valid
558  * @retval -1 if some SDP line is missing
559  * @retval -2 if c= line is missing
560  */
sdp_sanity_check(sdp_parser_t * p)561 int sdp_sanity_check(sdp_parser_t *p)
562 {
563   sdp_session_t *sdp = p->pr_session;
564   sdp_media_t *m;
565 
566   if (!p || !p->pr_ok)
567     return -1;
568   else if (sdp->sdp_version[0] != 0)
569     return parsing_error(p, "Incorrect version");
570   else if (!sdp->sdp_origin)
571     return parsing_error(p, "No o= present");
572   else if (p->pr_strict && !sdp->sdp_subject)
573     return parsing_error(p, "No s= present");
574   else if (p->pr_strict && !sdp->sdp_time)
575     return parsing_error(p, "No t= present");
576 
577   /* If there is no session level c= check that one exists for all media */
578   /* c= line may be missing if this is a RTSP description */
579   if (!p->pr_c_missing && !sdp->sdp_connection) {
580     for (m = sdp->sdp_media ; m ; m = m->m_next) {
581       if (!m->m_connections && !m->m_rejected) {
582 	parsing_error(p, "No c= on either session level or all mediums");
583 	return -2;
584       }
585     }
586   }
587 
588   return 0;
589 }
590 
591 #if 0
592 /**
593  * Parse a "v=" field
594  *
595  * The function parser_version() parses the SDP version field.
596  *
597  * @param p      pointer to SDP parser object
598  * @param r      pointer to record data
599  * @param result pointer to which parsed record is assigned
600  */
601 static void parse_version(sdp_parser_t *p, char *r, sdp_version_t *result)
602 {
603   /*
604    proto-version =       "v=" 1*DIGIT CRLF
605                          ;[RFC2327] describes version 0
606    */
607   if (parse_ul(p, &r, result, 0))
608     parsing_error(p, "version \"%s\" is invalid", r);
609   else if (*result > 0)
610     parsing_error(p, "unknown version v=%s", r);
611 }
612 #endif
613 
614 /* -------------------------------------------------------------------------
615  * Function parse_origin() - parse an "o=" field
616  *
617  * Description:
618  *   This function parses an SDP origin field.
619  *
620  * Parameters:
621  *   p      - pointer to SDP parser object
622  *   r      - pointer to record data
623  *   result - pointer to which parsed record is assigned
624  */
parse_origin(sdp_parser_t * p,char * r,sdp_origin_t ** result)625 static void parse_origin(sdp_parser_t *p, char *r, sdp_origin_t **result)
626 {
627   /*
628    origin-field =        "o=" username space
629                          sess-id space sess-version space
630                          nettype space addrtype space
631                          addr CRLF
632 
633    username =            safe
634                          ;pretty wide definition, but doesn't include space
635 
636    sess-id =             1*(DIGIT)
637                          ;should be unique for this originating username/host
638 
639    sess-version =        1*(DIGIT)
640                          ;0 is a new session
641 
642 
643    */
644   PARSE_ALLOC(p, sdp_origin_t, o);
645 
646   *result = o;
647 
648   o->o_username = token(&r, SPACE TAB, NULL, SPACE TAB);
649   if (!o->o_username) {
650     parsing_error(p, "invalid username");
651     return;
652   }
653   if (parse_ull(p, &r, &o->o_id, 0)) {
654     parsing_error(p, "invalid session id");
655     return;
656   }
657 
658   if (parse_ull(p, &r, &o->o_version, 0)) {
659     parsing_error(p, "invalid session version");
660     return;
661   }
662 
663   parse_connection(p, r, &o->o_address);
664 }
665 
666 /* -------------------------------------------------------------------------
667  * Function parse_subject() - parse an "s=" field
668  *
669  * Description:
670  *   This function parses an SDP subject field.
671  *
672  * Parameters:
673  *   p      - pointer to SDP parser object
674  *   r      - pointer to record data
675  *   result - pointer to which parsed record is assigned
676  */
parse_subject(sdp_parser_t * p,char * r,sdp_text_t ** result)677 static void parse_subject(sdp_parser_t *p, char *r, sdp_text_t **result)
678 {
679   /*
680    session-name-field =  "s=" text CRLF
681    text =                byte-string
682    */
683   *result = r;
684 }
685 
686 /* -------------------------------------------------------------------------
687  * Function parse_information() - parse an "i=" field
688  *
689  * Description:
690  *   This function parses an SDP information field.
691  *
692  * Parameters:
693  *   p      - pointer to SDP parser object
694  *   r      - pointer to record data
695  *   result - pointer to which parsed record is assigned
696  */
parse_information(sdp_parser_t * p,char * r,sdp_text_t ** result)697 static void parse_information(sdp_parser_t *p, char *r, sdp_text_t **result)
698 {
699   /*
700    information-field =   ["i=" text CRLF]
701    */
702   *result = r;
703 }
704 
705 /* -------------------------------------------------------------------------
706  * Function parse_uri() - parse an "u=" field
707  *
708  * Description:
709  *   This function parses an SDP URI field.
710  *
711  * Parameters:
712  *   p      - pointer to SDP parser object
713  *   r      - pointer to record data
714  *   result - pointer to which parsed record is assigned
715  */
parse_uri(sdp_parser_t * p,char * r,sdp_text_t ** result)716 static void parse_uri(sdp_parser_t *p, char *r, sdp_text_t **result)
717 {
718   /*
719     uri-field =           ["u=" uri CRLF]
720 
721     uri=                  ;defined in RFC1630
722   */
723   /* XXX - no syntax checking here */
724   *result = r;
725 }
726 
727 /* -------------------------------------------------------------------------
728  * Function parse_email() - parse an "e=" field
729  *
730  * Description:
731  *   This function parses an SDP email field.
732  *
733  * Parameters:
734  *   p      - pointer to SDP parser object
735  *   r      - pointer to record data
736  *   result - pointer to which parsed record is assigned
737  */
parse_email(sdp_parser_t * p,char * r,sdp_list_t ** result)738 static void parse_email(sdp_parser_t *p, char *r, sdp_list_t **result)
739 {
740   /*
741    email-fields =        *("e=" email-address CRLF)
742 
743    email-address =       email | email "(" email-safe ")" |
744                          email-safe "<" email ">"
745 
746    email =               ;defined in RFC822  */
747   parse_text_list(p, r, result);
748 }
749 
750 /* -------------------------------------------------------------------------
751  * Function parse_phone() - parse an "p=" field
752  *
753  * Description:
754  *   This function parses an SDP phone field.
755  *
756  * Parameters:
757  *   p      - pointer to SDP parser object
758  *   r      - pointer to record data
759  *   result - pointer to which parsed record is assigned
760  */
parse_phone(sdp_parser_t * p,char * r,sdp_list_t ** result)761 static void parse_phone(sdp_parser_t *p, char *r, sdp_list_t **result)
762 {
763   /*
764    phone-fields =        *("p=" phone-number CRLF)
765 
766    phone-number =        phone | phone "(" email-safe ")" |
767                          email-safe "<" phone ">"
768 
769    phone =               "+" POS-DIGIT 1*(space | "-" | DIGIT)
770                          ;there must be a space or hyphen between the
771                          ;international code and the rest of the number.
772   */
773   parse_text_list(p, r, result);
774 }
775 
776 /* -------------------------------------------------------------------------
777  * Function parse_connection() - parse an "c=" field
778  *
779  * Description:
780  *   This function parses an SDP connection field.
781  *
782  * Parameters:
783  *   p      - pointer to SDP parser object
784  *   r      - pointer to record data
785  *   result - pointer to which parsed record is assigned
786  */
parse_connection(sdp_parser_t * p,char * r,sdp_connection_t ** result)787 static void parse_connection(sdp_parser_t *p, char *r, sdp_connection_t **result)
788 {
789   /*
790    connection-field =    ["c=" nettype space addrtype space
791                          connection-address CRLF]
792                          ;a connection field must be present
793                          ;in every media description or at the
794                          ;session-level
795 
796    nettype =             "IN"
797                          ;list to be extended
798 
799    addrtype =            "IP4" | "IP6"
800                          ;list to be extended
801 
802    connection-address =  multicast-address
803                          | addr
804 
805    multicast-address =   3*(decimal-uchar ".") decimal-uchar "/" ttl
806                          [ "/" integer ]
807                          ;multicast addresses may be in the range
808                          ;224.0.0.0 to 239.255.255.255
809 
810    ttl =                 decimal-uchar
811 
812    addr =                FQDN | unicast-address
813 
814    FQDN =                4*(alpha-numeric|"-"|".")
815                          ;fully qualified domain name as specified in RFC1035
816 
817    unicast-address =     IP4-address | IP6-address
818 
819    IP4-address =         b1 "." decimal-uchar "." decimal-uchar "." b4
820    b1 =                  decimal-uchar
821                          ;less than "224"; not "0" or "127"
822    b4 =                  decimal-uchar
823                          ;not "0"
824 
825    IP6-address =         ;to be defined
826    */
827   PARSE_ALLOC(p, sdp_connection_t, c);
828 
829   *result = c;
830 
831   if (su_casenmatch(r, "IN", 2)) {
832     char *s;
833 
834     /* nettype is internet */
835     c->c_nettype = sdp_net_in;
836     s = token(&r, SPACE TAB, NULL, NULL);
837 
838     /* addrtype */
839     s = token(&r, SPACE TAB, NULL, NULL);
840     if (su_casematch(s, "IP4"))
841       c->c_addrtype = sdp_addr_ip4;
842     else if (su_casematch(s, "IP6"))
843       c->c_addrtype = sdp_addr_ip6;
844     else {
845       parsing_error(p, "unknown IN address type: %s", s);
846       return;
847     }
848 
849     /* address */
850     s = next(&r, SPACE TAB, SPACE TAB);
851     c->c_address = s;
852     if (!s || !*s) {
853       parsing_error(p, "invalid address");
854       return;
855     }
856 
857     /* ttl */
858     s = strchr(s, '/');
859     if (s) {
860       unsigned long value;
861       *s++ = 0;
862       if (parse_ul(p, &s, &value, 256) ||
863 	  (*s && *s != '/')) {
864 	parsing_error(p, "invalid ttl");
865 	return;
866       }
867       c->c_ttl = value;
868       c->c_mcast = 1;
869 
870       /* multiple groups */
871       value = 1;
872       if (*s++ == '/')
873 	if (parse_ul(p, &s, &value, 0) || *s) {
874 	  parsing_error(p, "invalid number of multicast groups");
875 	  return;
876 	}
877       c->c_groups = value;
878     }
879     else
880       c->c_groups = 1;
881   }
882   else if (p->pr_anynet) {
883     c->c_nettype = sdp_net_x;
884     c->c_addrtype = sdp_addr_x;
885     c->c_address = r;
886     c->c_ttl = 0;
887     c->c_groups = 1;
888   }
889   else
890     parsing_error(p, "invalid address");
891 }
892 
893 /* -------------------------------------------------------------------------
894  * Function parse_bandwidth() - parse an "b=" field
895  *
896  * Description:
897  *   This function parses an SDP bandwidth field.
898  *
899  * Parameters:
900  *   p      - pointer to SDP parser object
901  *   r      - pointer to record data
902  *   result - pointer to which parsed record is assigned
903  */
parse_bandwidth(sdp_parser_t * p,char * r,sdp_bandwidth_t ** result)904 static void parse_bandwidth(sdp_parser_t *p, char *r, sdp_bandwidth_t **result)
905 {
906   /*
907    bandwidth-fields =    *("b=" bwtype ":" bandwidth CRLF)
908    bwtype =              token
909    bandwidth =           1*(DIGIT)
910    */
911   /* NOTE: bwtype can also be like X-barf */
912   sdp_bandwidth_e modifier;
913   char *name;
914   unsigned long value;
915 
916   name = token(&r, ":", TOKEN, SPACE TAB);
917 
918   if (name == NULL || parse_ul(p, &r, &value, 0)) {
919     parsing_error(p, "invalid bandwidth");
920     return;
921   }
922 
923   if (su_casematch(name, "CT"))
924     modifier = sdp_bw_ct, name = "CT";
925   else if (su_casematch(name, "TIAS") == 1)
926     modifier = sdp_bw_tias, name = "TIAS";
927   else if (su_casematch(name, "AS") == 1)
928     modifier = sdp_bw_as, name = "AS";
929   else
930 	modifier = sdp_bw_x, name = "BW-X";
931 
932   if (STRICT(p))
933     PARSE_CHECK_REST(p, r, "b");
934 
935   {
936     PARSE_ALLOC(p, sdp_bandwidth_t, b);
937     *result = b;
938     b->b_modifier = modifier;
939     b->b_modifier_name = name;
940     b->b_value = value;
941   }
942 }
943 
944 /* -------------------------------------------------------------------------
945  * Function parse_time() - parse an "t=" field
946  *
947  * Description:
948  *   This function parses an SDP time field.
949  *
950  * Parameters:
951  *   p      - pointer to SDP parser object
952  *   r      - pointer to record data
953  *   result - pointer to which parsed record is assigned
954  */
parse_time(sdp_parser_t * p,char * r,sdp_time_t ** result)955 static void parse_time(sdp_parser_t *p, char *r, sdp_time_t **result)
956 {
957   /*
958    time-fields =         1*( "t=" start-time SP stop-time
959                          *(CRLF repeat-fields) CRLF)
960                          [zone-adjustments CRLF]
961 
962    start-time =          time / "0"
963 
964    stop-time =           time / "0"
965 
966    time =                POS-DIGIT 9*DIGIT
967                          ; Decimal representation of NTP time in
968                          ; seconds since 1900.  The representation
969                          ; of NTP time is an unbounded length field
970                          ; containing at least 10 digits.  Unlike the
971                          ; 64-bit representation used elsewhere, time
972                          ; in SDP does not wrap in the year 2036.
973    */
974   PARSE_ALLOC(p, sdp_time_t, t);
975   *result = t;
976   if (parse_ul(p, &r, &t->t_start, 0) ||
977       parse_ul(p, &r, &t->t_stop, 0))
978     parsing_error(p, "invalid time");
979   else if (STRICT(p)) {
980     PARSE_CHECK_REST(p, r, "t");
981   }
982 }
983 
984 /**
985  * Parse an "r=" field
986  *
987  * The function parse_repeat() parses an SDP repeat field.
988  *
989  * @param p      pointer to SDP parser object
990  * @param r      pointer to record data
991  * @param result pointer to which parsed record is assigned
992  *
993  */
parse_repeat(sdp_parser_t * p,char * d,sdp_repeat_t ** result)994 static void parse_repeat(sdp_parser_t *p, char *d, sdp_repeat_t **result)
995 {
996   /*
997    repeat-fields =       %x72 "=" repeat-interval 2*(SP typed-time)
998 
999    repeat-interval =     POS-DIGIT *DIGIT [fixed-len-time-unit]
1000 
1001    typed-time =          1*DIGIT [fixed-len-time-unit]
1002 
1003    fixed-len-time-unit = %x64 / %x68 / %x6d / %x73 ; "d" | "h" | "m" | "s"
1004    */
1005 
1006   unsigned long tt, *interval;
1007   size_t i;
1008   int n, N;
1009   char *s;
1010   sdp_repeat_t *r;
1011   int strict = STRICT(p);
1012 
1013   /** Count number of intervals */
1014   for (N = 0, s = d; *s; ) {
1015     if (!(is_posdigit(*s) || (!strict && (*s) == '0')))
1016       break;
1017     do { s++; } while (is_digit(*s));
1018     if (*s && strchr(strict ? "dhms" : "dhmsDHMS", *s))
1019       s++;
1020     N++;
1021     if (!(i = strict ? is_space(*s) : strspn(s, SPACE TAB)))
1022       break;
1023     s += i;
1024   }
1025 
1026   PARSE_CHECK_REST(p, s, "r");
1027   if (N < 2) {
1028     parsing_error(p, "invalid repeat");
1029     return;
1030   }
1031   if (!(r = su_salloc(p->pr_home, offsetof(sdp_repeat_t, r_offsets[N - 1])))) {
1032     parse_alloc_error(p, "sdp_repeat_t");
1033     return;
1034   }
1035 
1036   r->r_number_of_offsets = N - 2;
1037   r->r_offsets[N - 2] = 0;
1038 
1039   for (n = 0, interval = &r->r_interval; n < N; n++) {
1040     tt = strtoul(d, &d, 10);
1041 
1042     switch (*d) {
1043     case 'd': case 'D': tt *= 24;
1044     case 'h': case 'H': tt *= 60;
1045     case 'm': case 'M': tt *= 60;
1046     case 's': case 'S': d++;
1047       break;
1048     }
1049 
1050     interval[n] = tt;
1051 
1052     while (is_space(*d))
1053       d++;
1054   }
1055 
1056   *result = r;
1057 }
1058 
1059 /* -------------------------------------------------------------------------
1060  * Function parse_zone() - parse an "z=" field
1061  *
1062  * Description:
1063  *   This function parses an SDP time zone field.
1064  *
1065  * Parameters:
1066  *   p      - pointer to SDP parser object
1067  *   r      - pointer to record data
1068  *   result - pointer to which parsed record is assigned
1069  *
1070  */
parse_zone(sdp_parser_t * p,char * r,sdp_zone_t ** result)1071 static void parse_zone(sdp_parser_t *p, char *r, sdp_zone_t **result)
1072 {
1073   char *s;
1074   size_t i;
1075   int n, N;
1076   sdp_zone_t *z;
1077 
1078   /*
1079    zone-adjustments =    time space ["-"] typed-time
1080                          *(space time space ["-"] typed-time)
1081    */
1082 
1083   /** Count number of timezones, check syntax */
1084   for (N = 0, s = r; *s;) {
1085     if (!(is_posdigit(*s) || (!STRICT(p) && (*s) == '0')))
1086       break;
1087     do { s++; } while (is_digit(*s));
1088     if (!(i = STRICT(p) ? is_space(*s) : strspn(s, SPACE TAB)))
1089       break;
1090     s += i;
1091     if (!(*s == '-' || is_posdigit(*s) || (!STRICT(p) && (*s) == '0')))
1092       break;
1093     do { s++; } while (is_digit(*s));
1094     if (*s && strchr("dhms", *s))
1095       s++;
1096     N++;
1097     if (!(i = STRICT(p) ? is_space(*s) : strspn(s, SPACE TAB)))
1098       break;
1099     s += i;
1100   }
1101 
1102   PARSE_CHECK_REST(p, s, "z");
1103 
1104   if (N < 1) {
1105     parsing_error(p, "invalid timezone");
1106     return;
1107   }
1108   if (!(z = su_salloc(p->pr_home, offsetof(sdp_zone_t, z_adjustments[N])))) {
1109     parse_alloc_error(p, "sdp_zone_t");
1110     return;
1111   }
1112 
1113   z->z_number_of_adjustments = N;
1114 
1115   for (n = 0; n < N; n++) {
1116     unsigned long at = strtoul(r, &r, 10);
1117     long offset = strtol(r, &r, 10);
1118     switch (*r) {
1119     case 'd': offset *= 24;
1120     case 'h': offset *= 60;
1121     case 'm': offset *= 60;
1122     case 's': r++;
1123       break;
1124     }
1125 
1126     z->z_adjustments[n].z_at = at;
1127     z->z_adjustments[n].z_offset = offset;
1128   }
1129 
1130   *result = z;
1131 }
1132 
1133 /* -------------------------------------------------------------------------
1134  * Function parse_key() - parse an "k=" field
1135  *
1136  * Description:
1137  *   This function parses an SDP key field.
1138  *
1139  * Parameters:
1140  *   p      - pointer to SDP parser object
1141  *   r      - pointer to record data
1142  *   result - pointer to which parsed record is assigned
1143  *
1144  */
parse_key(sdp_parser_t * p,char * r,sdp_key_t ** result)1145 static void parse_key(sdp_parser_t *p, char *r, sdp_key_t **result)
1146 {
1147   char *s;
1148   /*
1149    key-field =           ["k=" key-type CRLF]
1150 
1151    key-type =            "prompt" |
1152                          "clear:" key-data |
1153                          "base64:" key-data |
1154                          "uri:" uri
1155 
1156    key-data =            email-safe | "~" | "
1157    */
1158 
1159   s = token(&r, ":", TOKEN, SPACE TAB);
1160   if (!s) {
1161     parsing_error(p, "invalid key method");
1162     return;
1163   }
1164 
1165   {
1166     PARSE_ALLOC(p, sdp_key_t, k);
1167     *result = k;
1168 
1169     /* These are defined as key-sensitive in RFC 4566 */
1170 #define MATCH(s, tok) \
1171     (STRICT(p) ? su_strmatch((s), (tok)) : su_casematch((s), (tok)))
1172 
1173     if (MATCH(s, "clear"))
1174       k->k_method = sdp_key_clear, k->k_method_name = "clear";
1175     else if (MATCH(s, "base64"))
1176       k->k_method = sdp_key_base64, k->k_method_name = "base64";
1177     else if (MATCH(s, "uri"))
1178       k->k_method = sdp_key_uri, k->k_method_name = "uri";
1179     else if (MATCH(s, "prompt"))
1180       k->k_method = sdp_key_prompt, k->k_method_name = "prompt";
1181     else if (!STRICT(p))
1182       k->k_method = sdp_key_x, k->k_method_name = s;
1183     else {
1184       parsing_error(p, "invalid key method");
1185       return;
1186     }
1187 
1188     k->k_material = r;
1189   }
1190 }
1191 
1192 /* -------------------------------------------------------------------------
1193  * Function parse_session_attr() - parse a session "a=" field
1194  *
1195  * Description:
1196  *   This function parses an SDP attribute field regarding whole session.
1197  *
1198  * Parameters:
1199  *   p      - pointer to SDP parser object
1200  *   r      - pointer to record data
1201  *   result - pointer to which parsed record is assigned
1202  */
parse_session_attr(sdp_parser_t * p,char * r,sdp_attribute_t ** result)1203 static void parse_session_attr(sdp_parser_t *p, char *r, sdp_attribute_t **result)
1204 {
1205   /*
1206    attribute-fields =    *("a=" attribute CRLF)
1207 
1208    attribute =           (att-field ":" att-value) / att-field
1209 
1210    att-field =           token
1211 
1212    att-value =           byte-string
1213    */
1214 
1215   char *name = NULL, *value = NULL;
1216 
1217   if (!(name = token(&r, ":", TOKEN, SPACE TAB))) {
1218     parsing_error(p,"invalid attribute name");
1219     return;
1220   }
1221 
1222   if (*r)
1223     value = r;
1224   else
1225     PARSE_CHECK_REST(p, r, "a");
1226 
1227   if (su_casematch(name, "charset")) {
1228     p->pr_session->sdp_charset = value;
1229     return;
1230   }
1231 
1232   if (p->pr_mode_manual)
1233     ;
1234   else if (su_casematch(name, "inactive"))
1235     p->pr_session_mode = sdp_inactive;
1236   else if (su_casematch(name, "sendonly"))
1237     p->pr_session_mode = sdp_sendonly;
1238   else if (su_casematch(name, "recvonly"))
1239     p->pr_session_mode = sdp_recvonly;
1240   else if (su_casematch(name, "sendrecv"))
1241     p->pr_session_mode = sdp_sendrecv;
1242 
1243   {
1244     PARSE_ALLOC(p, sdp_attribute_t, a);
1245     *result = a;
1246 
1247     a->a_name  = name;
1248     a->a_value = value;
1249   }
1250 }
1251 
1252 /* -------------------------------------------------------------------------
1253  * Function parse_media() - parse an "m=" field
1254  *
1255  * Description:
1256  *   This function parses an SDP media field.
1257  *
1258  * Parameters:
1259  *   p      - pointer to SDP parser object
1260  *   r      - pointer to record data
1261  *   result - pointer to which parsed record is assigned
1262  */
parse_media(sdp_parser_t * p,char * r,sdp_media_t ** result)1263 static void parse_media(sdp_parser_t *p, char *r, sdp_media_t **result)
1264 {
1265   /*
1266    media-descriptions =  *( media-field
1267                          information-field
1268                          *(connection-field)
1269                          bandwidth-fields
1270                          key-field
1271                          attribute-fields )
1272 
1273    media-field =         "m=" media space port ["/" integer]
1274                          space proto 1*(space fmt) CRLF
1275 
1276    media =               token
1277                          ;typically "audio", "video", "application"
1278                          ;or "data" or "text"
1279 
1280    fmt =                 token
1281                          ;typically an RTP payload type for audio
1282                          ;and video media
1283 
1284    proto =               token *("/" token)
1285                          ;typically "RTP/AVP" or "udp" for IP4
1286 
1287    port =                1*(DIGIT)
1288                          ;should in the range "1024" to "65535" inclusive
1289    */
1290   char *s;
1291   unsigned long value;
1292   PARSE_ALLOC(p, sdp_media_t, m);
1293 
1294   *result = m;
1295 
1296   m->m_mode = sdp_sendrecv;
1297 
1298   s = token(&r, SPACE, TOKEN, NULL);
1299   if (!s) {
1300     parsing_error(p, "m= invalid media field");
1301     return;
1302   }
1303 
1304   sdp_media_type(m, s);
1305 
1306   /* Accept m=* in configuration file */
1307   if (p->pr_config && m->m_type == sdp_media_any) {
1308     r += strspn(r, SPACE TAB);
1309     if (r[0] == '\0') {
1310       m->m_proto = sdp_proto_any, m->m_proto_name = "*";
1311       return;
1312     }
1313   }
1314 
1315   if (parse_ul(p, &r, &value, 0)) {
1316     parsing_error(p, "m= invalid port number");
1317     return;
1318   }
1319   m->m_port = value;
1320 
1321   if (*r == '/') {
1322     r++;
1323     if (parse_ul(p, &r, &value, 0)) {
1324       parsing_error(p, "m= invalid port specification");
1325       return;
1326     }
1327     m->m_number_of_ports = value;
1328   }
1329 
1330   s = token(&r, SPACE, "/" TOKEN, SPACE);
1331   if (s == NULL) {
1332     parsing_error(p, "m= missing protocol");
1333     return;
1334   }
1335 
1336   if (!STRICT(p) && su_casematch(s, "RTP"))
1337     m->m_proto = sdp_proto_rtp, m->m_proto_name = "RTP/AVP";
1338   else
1339     sdp_media_transport(m, s);
1340 
1341   /* RTP format list */
1342   if (*r && sdp_media_has_rtp(m)) {
1343 	  parse_payload(p, r, &m->m_rtpmaps);
1344 	  return;
1345   }
1346 
1347   /* "normal" format list */
1348   if (*r) {
1349     sdp_list_t **fmt = &m->m_format;
1350 
1351     while (r && *r) {
1352       PARSE_ALLOC(p, sdp_list_t, l);
1353       *fmt = l;
1354       l->l_text = token(&r, SPACE TAB, TOKEN, SPACE TAB);
1355       fmt = &l->l_next;
1356     }
1357   }
1358 }
1359 
1360 /** Set media type */
sdp_media_type(sdp_media_t * m,char const * s)1361 void sdp_media_type(sdp_media_t *m, char const *s)
1362 {
1363   if (su_strmatch(s, "*"))
1364     m->m_type = sdp_media_any, m->m_type_name = "*";
1365   else if (su_casematch(s, "audio"))
1366     m->m_type = sdp_media_audio, m->m_type_name = "audio";
1367   else if (su_casematch(s, "video"))
1368     m->m_type = sdp_media_video, m->m_type_name = "video";
1369   else if (su_casematch(s, "application"))
1370     m->m_type = sdp_media_application, m->m_type_name = "application";
1371   else if (su_casematch(s, "data"))
1372     m->m_type = sdp_media_data, m->m_type_name = "data";
1373   else if (su_casematch(s, "control"))
1374     m->m_type = sdp_media_control, m->m_type_name = "control";
1375   else if (su_casematch(s, "message"))
1376     m->m_type = sdp_media_message, m->m_type_name = "message";
1377   else if (su_casematch(s, "image"))
1378     m->m_type = sdp_media_image, m->m_type_name = "image";
1379   else if (su_casematch(s, "red"))
1380     m->m_type = sdp_media_red, m->m_type_name = "red";
1381   else if (su_casematch(s, "text"))
1382     m->m_type = sdp_media_text, m->m_type_name = "text";
1383   else
1384     m->m_type = sdp_media_x, m->m_type_name = s;
1385 }
1386 
1387 /** Set transport protocol.
1388  *
1389  * Set the @m->m_proto to a well-known protocol type as
1390  * well as canonize case of @a m_proto_name.
1391  */
sdp_media_transport(sdp_media_t * m,char const * s)1392 void sdp_media_transport(sdp_media_t *m, char const *s)
1393 {
1394   if (m == NULL || s == NULL)
1395     ;
1396   else if (su_strmatch(s, "*"))
1397     m->m_proto = sdp_proto_any, m->m_proto_name = "*";
1398   else if (su_casematch(s, "RTP/AVP"))
1399     m->m_proto = sdp_proto_rtp, m->m_proto_name = "RTP/AVP";
1400   else if (su_casematch(s, "RTP/SAVP"))
1401     m->m_proto = sdp_proto_srtp, m->m_proto_name = "RTP/SAVP";
1402   else if (su_casematch(s, "UDP/TLS/RTP/SAVP"))
1403     m->m_proto = sdp_proto_srtp, m->m_proto_name = "RTP/SAVP";
1404   else if (su_casematch(s, "RTP/SAVPF"))
1405 	  m->m_proto = sdp_proto_extended_srtp, m->m_proto_name = "RTP/SAVPF";
1406   else if (su_casematch(s, "UDP/TLS/RTP/SAVPF"))
1407     m->m_proto = sdp_proto_extended_srtp, m->m_proto_name = "UDP/TLS/RTP/SAVPF";
1408   else if (su_casematch(s, "RTP/AVPF"))
1409 	  m->m_proto = sdp_proto_extended_rtp, m->m_proto_name = "RTP/AVPF";
1410   else if (su_casematch(s, "UDP/RTP/AVPF"))
1411     m->m_proto = sdp_proto_extended_rtp, m->m_proto_name = "UDP/RTP/AVPF";
1412   else if (su_casematch(s, "udptl"))
1413     /* Lower case - be compatible with people living by T.38 examples */
1414     m->m_proto = sdp_proto_udptl, m->m_proto_name = "udptl";
1415   else if (su_casematch(s, "TCP/MSRP"))
1416     m->m_proto = sdp_proto_msrp, m->m_proto_name = "TCP/MSRP";
1417   else if (su_casematch(s, "TCP/TLS/MSRP"))
1418     m->m_proto = sdp_proto_msrps, m->m_proto_name = "TCP/TLS/MSRP";
1419   else if (su_casematch(s, "UDP"))
1420     m->m_proto = sdp_proto_udp, m->m_proto_name = "UDP";
1421   else if (su_casematch(s, "TCP"))
1422     m->m_proto = sdp_proto_tcp, m->m_proto_name = "TCP";
1423   else if (su_casematch(s, "TLS"))
1424     m->m_proto = sdp_proto_tls, m->m_proto_name = "TLS";
1425   else
1426     m->m_proto = sdp_proto_x, m->m_proto_name = s;
1427 }
1428 
1429 /** Check if media uses RTP as its transport protocol.  */
sdp_media_has_rtp(sdp_media_t const * m)1430 int sdp_media_has_rtp(sdp_media_t const *m)
1431 {
1432 	return m && (m->m_proto == sdp_proto_rtp || m->m_proto == sdp_proto_srtp || m->m_proto == sdp_proto_extended_srtp || m->m_proto == sdp_proto_extended_rtp);
1433 }
1434 
1435 #define RTPMAP(pt, encoding, rate, params) \
1436   { sizeof(sdp_rtpmap_t), NULL, encoding, rate, (char *)params, NULL, 1, pt, 0 }
1437 
1438 /* rtpmaps for well-known codecs */
1439 static sdp_rtpmap_t const
1440   sdp_rtpmap_pcmu = RTPMAP(0, "PCMU", 8000, 0),
1441   sdp_rtpmap_1016 = RTPMAP(1, "1016", 8000, 0),
1442   sdp_rtpmap_g721 = RTPMAP(2, "G721", 8000, 0),
1443   sdp_rtpmap_gsm =  RTPMAP(3, "GSM",  8000, 0),
1444   sdp_rtpmap_g723 = RTPMAP(4, "G723", 8000, 0),
1445   sdp_rtpmap_dvi4_8000 = RTPMAP(5, "DVI4", 8000, 0),
1446   sdp_rtpmap_dvi4_16000 = RTPMAP(6, "DVI4", 16000, 0),
1447   sdp_rtpmap_lpc = RTPMAP(7, "LPC",  8000, 0),
1448   sdp_rtpmap_pcma = RTPMAP(8, "PCMA", 8000, 0),
1449   sdp_rtpmap_g722 = RTPMAP(9, "G722", 8000, 0),
1450   sdp_rtpmap_l16_2 = RTPMAP(10, "L16", 44100, "2"),
1451   sdp_rtpmap_l16 = RTPMAP(11, "L16", 44100, 0),
1452   sdp_rtpmap_qcelp = RTPMAP(12, "QCELP", 8000, 0),
1453   sdp_rtpmap_cn = RTPMAP(13, "CN", 8000, 0),
1454   sdp_rtpmap_mpa = RTPMAP(14, "MPA", 90000, 0),
1455   sdp_rtpmap_g728 = RTPMAP(15, "G728", 8000, 0),
1456   sdp_rtpmap_dvi4_11025 = RTPMAP(16, "DVI4", 11025, 0),
1457   sdp_rtpmap_dvi4_22050 = RTPMAP(17, "DVI4", 22050, 0),
1458   sdp_rtpmap_g729 = RTPMAP(18, "G729", 8000, 0),
1459   sdp_rtpmap_reserved_cn = RTPMAP(19, "CN", 8000, 0),
1460   /* video codecs */
1461   sdp_rtpmap_celb = RTPMAP(25, "CelB", 90000, 0),
1462   sdp_rtpmap_jpeg = RTPMAP(26, "JPEG", 90000, 0),
1463   sdp_rtpmap_nv = RTPMAP(28, "nv",   90000, 0),
1464   sdp_rtpmap_h261 = RTPMAP(31, "H261", 90000, 0),
1465   sdp_rtpmap_mpv = RTPMAP(32, "MPV",  90000, 0),
1466   sdp_rtpmap_mp2t = RTPMAP(33, "MP2T", 90000, 0),
1467   sdp_rtpmap_h263 = RTPMAP(34, "H263", 90000, 0);
1468 
1469 /** Table of rtpmap structures by payload type numbers.
1470  *
1471  * The table of reserved payload numbers is constructed from @RFC3551
1472  * and @RFC1890. Note the clock rate of G722.
1473  *
1474  * Use sdp_rtpmap_dup() to copy these structures.
1475  */
1476 sdp_rtpmap_t const * const sdp_rtpmap_well_known[128] =
1477 {
1478   &sdp_rtpmap_pcmu,		/* 0 */
1479   &sdp_rtpmap_1016,		/* 1 */
1480   &sdp_rtpmap_g721,		/* 2 */
1481   &sdp_rtpmap_gsm,		/* 3 */
1482   &sdp_rtpmap_g723,		/* 4 */
1483   &sdp_rtpmap_dvi4_8000,	/* 5 */
1484   &sdp_rtpmap_dvi4_16000,	/* 6 */
1485   &sdp_rtpmap_lpc,		/* 7 */
1486   &sdp_rtpmap_pcma,		/* 8 */
1487   &sdp_rtpmap_g722,		/* 9 */
1488   &sdp_rtpmap_l16_2,		/* 10 */
1489   &sdp_rtpmap_l16,		/* 11 */
1490   &sdp_rtpmap_qcelp,		/* 12 */
1491   &sdp_rtpmap_cn,		/* 13 */
1492   &sdp_rtpmap_mpa,		/* 14 */
1493   &sdp_rtpmap_g728,		/* 15 */
1494   &sdp_rtpmap_dvi4_11025,	/* 16 */
1495   &sdp_rtpmap_dvi4_22050,	/* 17 */
1496   &sdp_rtpmap_g729,		/* 18 */
1497   &sdp_rtpmap_reserved_cn,	/* 19 */
1498   NULL,				/* 20 */
1499   NULL,				/* 21 */
1500   NULL,				/* 22 */
1501   NULL,				/* 23 */
1502   NULL,				/* 24 */
1503   &sdp_rtpmap_celb,		/* 25 */
1504   &sdp_rtpmap_jpeg,		/* 26 */
1505   NULL,				/* 27 */
1506   &sdp_rtpmap_nv,		/* 28 */
1507   NULL,				/* 29 */
1508   NULL,				/* 30 */
1509   &sdp_rtpmap_h261,		/* 31 */
1510   &sdp_rtpmap_mpv,		/* 32 */
1511   &sdp_rtpmap_mp2t,		/* 33 */
1512   &sdp_rtpmap_h263,		/* 34 */
1513   NULL,
1514 };
1515 
1516 /**
1517  * The function parse_payload() parses an RTP payload type list, and
1518  * creates an rtpmap structure for each payload type.
1519  *
1520  * @param p       pointer to SDP parser object
1521  * @param r       pointer to record data
1522  * @param result  pointer to which parsed record is assigned
1523  */
parse_payload(sdp_parser_t * p,char * r,sdp_rtpmap_t ** result)1524 static void parse_payload(sdp_parser_t *p, char *r, sdp_rtpmap_t **result)
1525 {
1526   while (*r) {
1527     unsigned long value;
1528 
1529     if (parse_ul(p, &r, &value, 128) == 0) {
1530       PARSE_ALLOC(p, sdp_rtpmap_t, rm);
1531 
1532       assert(0 <= value && value < 128);
1533 
1534       *result = rm; result = &rm->rm_next;
1535 
1536       if (sdp_rtpmap_well_known[value]) {
1537 	*rm = *sdp_rtpmap_well_known[value];
1538       }
1539       else {
1540 	rm->rm_predef = 1;
1541 	rm->rm_pt = value;
1542 	rm->rm_encoding = "";
1543 	rm->rm_rate = 0;
1544       }
1545     }
1546     else if (p->pr_config && r[0] == '*' && (r[1] == ' ' || r[1] == '\0')) {
1547       PARSE_ALLOC(p, sdp_rtpmap_t, rm);
1548 
1549       *result = rm;
1550 
1551       rm->rm_predef = 1;
1552       rm->rm_any = 1;
1553       rm->rm_encoding = "*";
1554       rm->rm_rate = 0;
1555 
1556       return;
1557     }
1558     else {
1559       parsing_error(p, "m= invalid format for RTP/AVT");
1560 
1561       return;
1562     }
1563   }
1564 }
1565 
1566 /* -------------------------------------------------------------------------
1567  * Function parse_media_attr() - parse a media-specific "a=" field
1568  *
1569  * Description:
1570  *   This function parses a media-specific attribute field.
1571  *
1572  * Parameters:
1573  *   p      - pointer to SDP parser object
1574  *   r      - pointer to record data
1575  *   result - pointer to which parsed record is assigned
1576  */
parse_media_attr(sdp_parser_t * p,char * r,sdp_media_t * m,sdp_attribute_t ** result)1577 static void parse_media_attr(sdp_parser_t *p, char *r, sdp_media_t *m,
1578 			     sdp_attribute_t **result)
1579 {
1580   /*
1581    attribute-fields =    *("a=" attribute CRLF)
1582 
1583    attribute =           (att-field ":" att-value) / att-field
1584 
1585    att-field =           token
1586 
1587    att-value =           byte-string
1588 
1589    a=rtpmap:<payload type> <encoding name>/<clock rate>[/<encoding parameters>]
1590    a=fmtp:<payload type> <parameters>
1591    */
1592   int rtp = sdp_media_has_rtp(m);
1593   char *name = NULL, *value = NULL;
1594   int n;
1595 
1596   if (!(name = token(&r, ":", TOKEN, SPACE TAB))) {
1597     parsing_error(p,"invalid attribute name");
1598     return;
1599   }
1600 
1601   if (*r)
1602     value = r;
1603   else
1604     PARSE_CHECK_REST(p, r, "a");
1605 
1606   if (p->pr_mode_manual)
1607     ;
1608   else if (m->m_port == 0 || su_casematch(name, "inactive")) {
1609     m->m_mode = sdp_inactive;
1610     return;
1611   }
1612   else if (su_casematch(name, "sendonly")) {
1613     m->m_mode = sdp_sendonly;
1614     return;
1615   }
1616   else if (su_casematch(name, "recvonly")) {
1617     m->m_mode = sdp_recvonly;
1618     return;
1619   }
1620   else if (su_casematch(name, "sendrecv")) {
1621     m->m_mode = sdp_sendrecv;
1622     return;
1623   }
1624 
1625   if (rtp && su_casematch(name, "rtpmap")) {
1626 	  if ((n = parse_rtpmap(p, r, m)) == 0 || n < -1)
1627 		  return;
1628   }
1629   else if (rtp && su_casematch(name, "fmtp")) {
1630     if ((n = parse_fmtp(p, r, m)) == 0 || n < -1)
1631       return;
1632   }
1633   else {
1634     PARSE_ALLOC(p, sdp_attribute_t, a);
1635     *result = a;
1636 
1637     a->a_name  = name;
1638     a->a_value = value;
1639   }
1640 }
1641 
1642 /** Parse rtpmap attribute.
1643  *
1644  * a=rtpmap:<payload type> <encoding name>/<clock rate>[/<encoding parameters>]
1645  */
parse_rtpmap(sdp_parser_t * p,char * r,sdp_media_t * m)1646 static int parse_rtpmap(sdp_parser_t *p, char *r, sdp_media_t *m)
1647 {
1648   unsigned long pt, rate;
1649   char *encoding, *params;
1650   sdp_rtpmap_t *rm;
1651 
1652   int strict = STRICT(p);
1653 
1654   if (parse_ul(p, &r, &pt, 128)) {
1655     if (strict)
1656       parsing_error(p, "a=rtpmap: invalid payload type");
1657     return -1;
1658   }
1659 
1660   for (rm = m->m_rtpmaps; rm; rm = rm->rm_next)
1661     if (rm->rm_pt == pt)
1662       break;
1663 
1664   if (!rm) {
1665     if (strict)
1666       parsing_error(p, "a=rtpmap:%lu: unknown payload type", pt);
1667     return -1;
1668   }
1669 
1670   encoding = token(&r, "/", TOKEN, NULL);
1671   if (!r) {
1672     parsing_error(p, "a=rtpmap:%lu: missing <clock rate>", pt);
1673     return -2;
1674   }
1675   if (parse_ul(p, &r, &rate, 0)) {
1676     parsing_error(p, "a=rtpmap:%lu %s: invalid <clock rate>", pt, encoding);
1677     return -2;
1678   }
1679 
1680   if (*r == '/')
1681     params = ++r;
1682   else
1683     params = 0;
1684 
1685   rm->rm_predef = 0;
1686   rm->rm_encoding = encoding;
1687   rm->rm_rate = rate;
1688   rm->rm_params = params;
1689 
1690   return 0;
1691 }
1692 
1693 /** Parse fmtp attribute.
1694  *
1695  * a=fmtp:<payload type> <parameters>
1696  */
parse_fmtp(sdp_parser_t * p,char * r,sdp_media_t * m)1697 static int parse_fmtp(sdp_parser_t *p, char *r, sdp_media_t *m)
1698 {
1699   unsigned long pt;
1700   sdp_rtpmap_t *rm;
1701 
1702   int strict = STRICT(p);
1703 
1704   if (parse_ul(p, &r, &pt, 128)) {
1705     if (strict)
1706       parsing_error(p, "a=rtpmap: invalid payload type");
1707     return -1;
1708   }
1709 
1710   for (rm = m->m_rtpmaps; rm; rm = rm->rm_next)
1711     if (rm->rm_pt == pt)
1712       break;
1713 
1714   if (!rm) {
1715     if (strict)
1716       parsing_error(p, "a=fmtp:%lu: unknown payload type", pt);
1717     return -1;
1718   }
1719 
1720   rm->rm_fmtp = r;
1721   return 0;
1722 }
1723 
1724 /* -------------------------------------------------------------------------
1725  * Function parse_descs() - parse media descriptors
1726  *
1727  * Description:
1728  *   This function parses media descriptors at the end of SDP message.
1729  *
1730  * Parameters:
1731  *   p      - pointer to SDP parser object
1732  *   record - pointer to first media field
1733  *   message - pointer to rest
1734  *   medias - pointer to which parsed media structures are assigned
1735  */
parse_descs(sdp_parser_t * p,char * record,char * message,sdp_media_t ** medias)1736 static void parse_descs(sdp_parser_t *p,
1737 			char *record,
1738 			char *message,
1739 			sdp_media_t **medias)
1740 {
1741   char *rest;
1742   const char *strip;
1743   sdp_media_t *m = NULL;
1744   sdp_connection_t **connections = NULL;
1745   sdp_bandwidth_t **bandwidths = NULL;
1746   sdp_attribute_t **attributes = NULL;
1747 
1748   if (!STRICT(p))
1749     strip = SPACE TAB;		/* skip initial whitespace */
1750   else
1751     strip = "";
1752 
1753   for (;
1754        record && p->pr_ok;
1755        record = next(&message, CRLF, strip)) {
1756     char field = record[0];
1757 
1758     rest = record + 2; rest += strspn(rest, strip);
1759 
1760     if (record[1] == '=') switch (field) {
1761     case 'c':
1762       assert(connections);
1763       parse_connection(p, rest, connections);
1764       connections = &(*connections)->c_next;
1765       break;
1766 
1767     case 'b':
1768       assert(bandwidths);
1769       parse_bandwidth(p, rest, bandwidths);
1770       bandwidths = &(*bandwidths)->b_next;
1771       break;
1772 
1773     case 'k':
1774       parse_key(p, rest, &m->m_key);
1775       break;
1776 
1777     case 'a':
1778       assert(attributes);
1779       parse_media_attr(p, rest, m, attributes);
1780       if (*attributes)
1781 	attributes = &(*attributes)->a_next;
1782       break;
1783 
1784     case 'm':
1785       parse_media(p, rest, medias);
1786       m = *medias;
1787       if (m) {
1788 	m->m_mode = p->pr_session_mode;
1789 	medias = &m->m_next;
1790 	connections = &m->m_connections;
1791 	bandwidths = &m->m_bandwidths;
1792 	attributes = &m->m_attributes;
1793       }
1794     }
1795   }
1796 }
1797 
parse_text_list(sdp_parser_t * p,char * r,sdp_list_t ** result)1798 static void parse_text_list(sdp_parser_t *p, char *r, sdp_list_t **result)
1799 {
1800   PARSE_ALLOC(p, sdp_list_t, l);
1801 
1802   *result = l;
1803 
1804   l->l_text = r;
1805 }
1806 
1807 /*
1808  * parse_ul: parse an unsigned long
1809  */
parse_ul(sdp_parser_t * p,char ** r,unsigned long * result,unsigned long max)1810 static int parse_ul(sdp_parser_t *p, char **r,
1811 		    unsigned long *result, unsigned long max)
1812 {
1813   char *ul = *r;
1814 
1815   ul += strspn(ul, SPACE TAB);
1816 
1817   *result = strtoul(ul, r, 10);
1818   if (ul != *r && !(max && max <= *result)) {
1819     *r += strspn(*r, SPACE TAB);
1820     return 0;
1821   }
1822 
1823   return -1;
1824 }
1825 
1826 #if !HAVE_STRTOULL
1827 #if !((defined(WIN32) || defined(_WIN32)) && (_MSC_VER >= 1800))
1828 unsigned long long strtoull(char const *string, char **return_end, int base);
1829 #endif
1830 #endif
1831 
1832 /*
1833  * parse_ull: parse an unsigned long long
1834  */
parse_ull(sdp_parser_t * p,char ** r,uint64_t * result,uint64_t max)1835 static int parse_ull(sdp_parser_t *p, char **r,
1836 		     uint64_t *result, uint64_t max)
1837 {
1838   unsigned long long ull;
1839 
1840   char *s = *r;
1841 
1842   s += strspn(s, SPACE TAB);
1843 
1844   ull = strtoull(s, r, 10);
1845 
1846   if (s != *r && !(max && max <= ull)) {
1847     *result = (uint64_t)ull;
1848     *r += strspn(*r, SPACE TAB);
1849     return 0;
1850   }
1851 
1852   return -1;
1853 }
1854 
token(char ** message,const char * sep,const char * legal,const char * strip)1855 static char *token(char **message,
1856 		   const char *sep,
1857 		   const char *legal,
1858 		   const char *strip)
1859 {
1860   size_t n;
1861   char *retval = *message;
1862 
1863   if (strip)
1864     retval += strspn(retval, strip);
1865 
1866   if (legal)
1867     n = strspn(retval, legal);
1868   else
1869     n = strcspn(retval, sep);
1870 
1871   if (n == 0)
1872     return NULL;
1873 
1874   if (retval[n]) {
1875     retval[n++] = '\0';
1876     n += strspn(retval + n, sep);
1877   }
1878 
1879   *message = retval + n;
1880 
1881   if (*retval == '\0')
1882     return NULL;
1883 
1884   return retval;
1885 }
1886 
next(char ** message,const char * sep,const char * strip)1887 static char *next(char **message, const char *sep, const char *strip)
1888 {
1889   size_t n;
1890   char *retval = *message;
1891 
1892   if (strip[0])
1893     retval += strspn(retval, strip);
1894 
1895   n = strcspn(retval, sep);
1896 
1897   if (n == 0)
1898     return NULL;
1899 
1900   if (retval[n]) {
1901     retval[n++] = '\0';
1902     n += strspn(retval + n, sep);
1903   }
1904 
1905   *message = retval + n;
1906 
1907   if (*retval == '\0')
1908     return NULL;
1909 
1910   return retval;
1911 }
1912 
parsing_error(sdp_parser_t * p,char const * fmt,...)1913 static int parsing_error(sdp_parser_t *p, char const *fmt, ...)
1914 {
1915   va_list ap;
1916   va_start(ap, fmt);
1917 
1918   memset(p->pr_error, 0, sizeof(p->pr_error));
1919   vsnprintf(p->pr_error, sizeof(p->pr_error), fmt, ap);
1920   va_end(ap);
1921 
1922   p->pr_ok = 0;
1923 
1924   return -1;
1925 }
1926 
parse_alloc_error(sdp_parser_t * p,const char * typename)1927 static void parse_alloc_error(sdp_parser_t *p, const char *typename)
1928 {
1929   parsing_error(p, "memory exhausted (while allocating memory for %s)",
1930 		typename);
1931 }
1932