Bug Summary

File:libs/sofia-sip/libsofia-sip-ua/sdp/sdp_parse.c
Location:line 1539, column 21
Description:Value stored to 'result' is never read

Annotated Source Code

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
65struct 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') ((c) >= '1' && (c) <= '9')
87#define is_digit(c)((c) >= '0' && (c) <= '9') ((c) >= '0' && (c) <= '9')
88#define is_space(c)((c) == ' ') ((c) == ' ')
89#define is_tab(c)((c) == '\t') ((c) == '\t')
90
91#define pr_errorpr_output.pru_error pr_output.pru_error
92#define pr_sessionpr_output.pru_session pr_output.pru_session
93
94#ifdef _MSC_VER
95#undef STRICT
96#endif
97#define STRICT(pr)(pr->pr_strict) (pr->pr_strict)
98
99/* Static parser object used when running out of memory */
100static const struct sdp_parser_s no_mem_error =
101{
102 { SU_HOME_INIT(no_mem_error){ 0, ((void*)0), ((void*)0) } },
103 { "sdp: not enough memory" }
104};
105
106/* Internal prototypes */
107static void parse_message(sdp_parser_t *p);
108static 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 */
143sdp_parser_t *
144sdp_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((void*)0)) {
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_MAX2147483647)
165 len = ISSIZE_MAX2147483647;
166
167 p = su_home_clone(home, sizeof(*p) + len + 1);
168
169 if (p) {
170 b = strncpy((void *)(p + 1), msg, len)__builtin_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 */
197su_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((void*)0);
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. */
216sdp_session_t *
217sdp_session(sdp_parser_t *p)
218{
219 return p && p->pr_ok ? p->pr_sessionpr_output.pru_session : NULL((void*)0);
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 */
233char const *sdp_parsing_error(sdp_parser_t *p)
234{
235 return !p->pr_ok ? p->pr_errorpr_output.pru_error : NULL((void*)0);
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 */
245void 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" "\011"
260#define CRLF"\015\012" "\015\012"
261#define ALPHA"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
262#define DIGIT"0123456789" "0123456789"
263#define TOKEN"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" "0123456789"
"-!#$%&'*+.^_`{|}~"
ALPHA"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" DIGIT"0123456789" "-!#$%&'*+.^_`{|}~"
264
265/* ========================================================================= */
266/* Parsing functions */
267
268static void post_session(sdp_parser_t *p, sdp_session_t *sdp);
269static void parse_origin(sdp_parser_t *p, char *r, sdp_origin_t **result);
270static void parse_subject(sdp_parser_t *p, char *r, sdp_text_t **result);
271static void parse_information(sdp_parser_t *p, char *r, sdp_text_t **result);
272static void parse_uri(sdp_parser_t *p, char *r, sdp_text_t **result);
273static void parse_email(sdp_parser_t *p, char *r, sdp_list_t **result);
274static void parse_phone(sdp_parser_t *p, char *r, sdp_list_t **result);
275static void parse_connection(sdp_parser_t *p, char *r, sdp_connection_t **result);
276static void parse_bandwidth(sdp_parser_t *p, char *r, sdp_bandwidth_t **result);
277static void parse_time(sdp_parser_t *p, char *r, sdp_time_t **result);
278static void parse_repeat(sdp_parser_t *p, char *r, sdp_repeat_t **result);
279static void parse_zone(sdp_parser_t *p, char *r, sdp_zone_t **result);
280static void parse_key(sdp_parser_t *p, char *r, sdp_key_t **result);
281static void parse_session_attr(sdp_parser_t *p, char *r, sdp_attribute_t **result);
282static void parse_media(sdp_parser_t *p, char *r, sdp_media_t **result);
283static void parse_payload(sdp_parser_t *p, char *r, sdp_rtpmap_t **result);
284static void parse_media_attr(sdp_parser_t *p, char *r, sdp_media_t *m,
285 sdp_attribute_t **result);
286static int parse_rtpmap(sdp_parser_t *p, char *r, sdp_media_t *m);
287static int parse_fmtp(sdp_parser_t *p, char *r, sdp_media_t *m);
288static void parse_text_list(sdp_parser_t *p, char *r, sdp_list_t **result);
289
290static void parse_descs(sdp_parser_t *p, char *r, char *m, sdp_media_t **result);
291
292static int parse_ul(sdp_parser_t *p, char **r, unsigned long *result,
293 unsigned long max_value);
294static int parse_ull(sdp_parser_t *p, char **r, uint64_t *result,
295 uint64_t max_value);
296static void parse_alloc_error(sdp_parser_t *p, const char *typename);
297static char *next(char **message, const char *sep, const char *strip);
298static char *token(char **message, const char *sep, const char *legal,
299 const char *strip);
300#if 0
301static 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)t *v = su_salloc(p->pr_home, sizeof(*v)); if (!v &&
(parse_alloc_error(p, "t"), 1)) return;
\
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)if (*s && (parsing_error(p, "extra data after %s (\"%.04s\")"
, n, s), 1)) return
\
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 */
337static 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_sessionpr_output.pru_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((void*)0);
365 sdp_zone_t **zones = NULL((void*)0);
366 sdp_attribute_t **attributes = &sdp->sdp_attributes;
367
368 if (!STRICT(p)(p->pr_strict))
369 strip = SPACE" " TAB"\011"; /* skip initial whitespace */
370 else
371 strip = "";
372
373 p->pr_ok = 1;
374 p->pr_sessionpr_output.pru_session->sdp_size = sizeof(p->pr_sessionpr_output.pru_session);
375
376 /* Require that version comes first */
377 record = next(&message, CRLF"\015\012", 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"\015\012", 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"\015\012", strip)) {
397 field = record[0];
398
399 rest = record + 2; rest += strspn(rest, strip)__extension__ ({ char __a0, __a1, __a2; (__builtin_constant_p
(strip) && ((size_t)(const void *)((strip) + 1) - (size_t
)(const void *)(strip) == 1) ? ((__builtin_constant_p (rest) &&
((size_t)(const void *)((rest) + 1) - (size_t)(const void *)
(rest) == 1)) ? __builtin_strspn (rest, strip) : ((__a0 = ((const
char *) (strip))[0], __a0 == '\0') ? ((void) (rest), (size_t
) 0) : ((__a1 = ((const char *) (strip))[1], __a1 == '\0') ? __strspn_c1
(rest, __a0) : ((__a2 = ((const char *) (strip))[2], __a2 ==
'\0') ? __strspn_c2 (rest, __a0, __a1) : (((const char *) (strip
))[3] == '\0' ? __strspn_c3 (rest, __a0, __a1, __a2) : __builtin_strspn
(rest, strip)))))) : __builtin_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((void*)0);
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
487int 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 */
502static 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 */
561int sdp_sanity_check(sdp_parser_t *p)
562{
563 sdp_session_t *sdp = p->pr_sessionpr_output.pru_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 */
601static 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 */
625static 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)sdp_origin_t *o = su_salloc(p->pr_home, sizeof(*o)); if (!
o && (parse_alloc_error(p, "sdp_origin_t"), 1)) return
;
;
645
646 *result = o;
647
648 o->o_username = token(&r, SPACE" " TAB"\011", NULL((void*)0), SPACE" " TAB"\011");
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 */
677static 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 */
697static 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 */
716static 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 */
738static 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 */
761static 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 */
787static 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)sdp_connection_t *c = su_salloc(p->pr_home, sizeof(*c)); if
(!c && (parse_alloc_error(p, "sdp_connection_t"), 1)
) return;
;
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"\011", NULL((void*)0), NULL((void*)0));
837
838 /* addrtype */
839 s = token(&r, SPACE" " TAB"\011", NULL((void*)0), NULL((void*)0));
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"\011", SPACE" " TAB"\011");
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, '/')(__extension__ (__builtin_constant_p ('/') && !__builtin_constant_p
(s) && ('/') == '\0' ? (char *) __rawmemchr (s, '/')
: __builtin_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 */
904static 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"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" "0123456789"
"-!#$%&'*+.^_`{|}~"
, SPACE" " TAB"\011");
917
918 if (name == NULL((void*)0) || 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 = NULL((void*)0);
925 else if (su_casematch(name, "AS") == 0)
926 modifier = sdp_bw_as, name = NULL((void*)0);
927 else
928 modifier = sdp_bw_x;
929
930 if (STRICT(p)(p->pr_strict))
931 PARSE_CHECK_REST(p, r, "b")if (*r && (parsing_error(p, "extra data after %s (\"%.04s\")"
, "b", r), 1)) return
;
932
933 {
934 PARSE_ALLOC(p, sdp_bandwidth_t, b)sdp_bandwidth_t *b = su_salloc(p->pr_home, sizeof(*b)); if
(!b && (parse_alloc_error(p, "sdp_bandwidth_t"), 1))
return;
;
935 *result = b;
936 b->b_modifier = modifier;
937 b->b_modifier_name = name;
938 b->b_value = value;
939 }
940}
941
942/* -------------------------------------------------------------------------
943 * Function parse_time() - parse an "t=" field
944 *
945 * Description:
946 * This function parses an SDP time field.
947 *
948 * Parameters:
949 * p - pointer to SDP parser object
950 * r - pointer to record data
951 * result - pointer to which parsed record is assigned
952 */
953static void parse_time(sdp_parser_t *p, char *r, sdp_time_t **result)
954{
955 /*
956 time-fields = 1*( "t=" start-time SP stop-time
957 *(CRLF repeat-fields) CRLF)
958 [zone-adjustments CRLF]
959
960 start-time = time / "0"
961
962 stop-time = time / "0"
963
964 time = POS-DIGIT 9*DIGIT
965 ; Decimal representation of NTP time in
966 ; seconds since 1900. The representation
967 ; of NTP time is an unbounded length field
968 ; containing at least 10 digits. Unlike the
969 ; 64-bit representation used elsewhere, time
970 ; in SDP does not wrap in the year 2036.
971 */
972 PARSE_ALLOC(p, sdp_time_t, t)sdp_time_t *t = su_salloc(p->pr_home, sizeof(*t)); if (!t &&
(parse_alloc_error(p, "sdp_time_t"), 1)) return;
;
973 *result = t;
974 if (parse_ul(p, &r, &t->t_start, 0) ||
975 parse_ul(p, &r, &t->t_stop, 0))
976 parsing_error(p, "invalid time");
977 else if (STRICT(p)(p->pr_strict)) {
978 PARSE_CHECK_REST(p, r, "t")if (*r && (parsing_error(p, "extra data after %s (\"%.04s\")"
, "t", r), 1)) return
;
979 }
980}
981
982/**
983 * Parse an "r=" field
984 *
985 * The function parse_repeat() parses an SDP repeat field.
986 *
987 * @param p pointer to SDP parser object
988 * @param r pointer to record data
989 * @param result pointer to which parsed record is assigned
990 *
991 */
992static void parse_repeat(sdp_parser_t *p, char *d, sdp_repeat_t **result)
993{
994 /*
995 repeat-fields = %x72 "=" repeat-interval 2*(SP typed-time)
996
997 repeat-interval = POS-DIGIT *DIGIT [fixed-len-time-unit]
998
999 typed-time = 1*DIGIT [fixed-len-time-unit]
1000
1001 fixed-len-time-unit = %x64 / %x68 / %x6d / %x73 ; "d" | "h" | "m" | "s"
1002 */
1003
1004 unsigned long tt, *interval;
1005 size_t i;
1006 int n, N;
1007 char *s;
1008 sdp_repeat_t *r;
1009 int strict = STRICT(p)(p->pr_strict);
1010
1011 /** Count number of intervals */
1012 for (N = 0, s = d; *s; ) {
1013 if (!(is_posdigit(*s)((*s) >= '1' && (*s) <= '9') || (!strict && (*s) == '0')))
1014 break;
1015 do { s++; } while (is_digit(*s)((*s) >= '0' && (*s) <= '9'));
1016 if (*s && strchr(strict ? "dhms" : "dhmsDHMS", *s)(__extension__ (__builtin_constant_p (*s) && !__builtin_constant_p
(strict ? "dhms" : "dhmsDHMS") && (*s) == '\0' ? (char
*) __rawmemchr (strict ? "dhms" : "dhmsDHMS", *s) : __builtin_strchr
(strict ? "dhms" : "dhmsDHMS", *s)))
)
1017 s++;
1018 N++;
1019 if (!(i = strict ? is_space(*s)((*s) == ' ') : strspn(s, SPACE TAB)__extension__ ({ char __a0, __a1, __a2; (__builtin_constant_p
(" " "\011") && ((size_t)(const void *)((" " "\011")
+ 1) - (size_t)(const void *)(" " "\011") == 1) ? ((__builtin_constant_p
(s) && ((size_t)(const void *)((s) + 1) - (size_t)(const
void *)(s) == 1)) ? __builtin_strspn (s, " " "\011") : ((__a0
= ((const char *) (" " "\011"))[0], __a0 == '\0') ? ((void) (
s), (size_t) 0) : ((__a1 = ((const char *) (" " "\011"))[1], __a1
== '\0') ? __strspn_c1 (s, __a0) : ((__a2 = ((const char *) (
" " "\011"))[2], __a2 == '\0') ? __strspn_c2 (s, __a0, __a1) :
(((const char *) (" " "\011"))[3] == '\0' ? __strspn_c3 (s, __a0
, __a1, __a2) : __builtin_strspn (s, " " "\011")))))) : __builtin_strspn
(s, " " "\011")); })
))
1020 break;
1021 s += i;
1022 }
1023
1024 PARSE_CHECK_REST(p, s, "r")if (*s && (parsing_error(p, "extra data after %s (\"%.04s\")"
, "r", s), 1)) return
;
1025 if (N < 2) {
1026 parsing_error(p, "invalid repeat");
1027 return;
1028 }
1029 if (!(r = su_salloc(p->pr_home, offsetof(sdp_repeat_t, r_offsets[N - 1])__builtin_offsetof(sdp_repeat_t, r_offsets[N - 1])))) {
1030 parse_alloc_error(p, "sdp_repeat_t");
1031 return;
1032 }
1033
1034 r->r_number_of_offsets = N - 2;
1035 r->r_offsets[N - 2] = 0;
1036
1037 for (n = 0, interval = &r->r_interval; n < N; n++) {
1038 tt = strtoul(d, &d, 10);
1039
1040 switch (*d) {
1041 case 'd': case 'D': tt *= 24;
1042 case 'h': case 'H': tt *= 60;
1043 case 'm': case 'M': tt *= 60;
1044 case 's': case 'S': d++;
1045 break;
1046 }
1047
1048 interval[n] = tt;
1049
1050 while (is_space(*d)((*d) == ' '))
1051 d++;
1052 }
1053
1054 *result = r;
1055}
1056
1057/* -------------------------------------------------------------------------
1058 * Function parse_zone() - parse an "z=" field
1059 *
1060 * Description:
1061 * This function parses an SDP time zone field.
1062 *
1063 * Parameters:
1064 * p - pointer to SDP parser object
1065 * r - pointer to record data
1066 * result - pointer to which parsed record is assigned
1067 *
1068 */
1069static void parse_zone(sdp_parser_t *p, char *r, sdp_zone_t **result)
1070{
1071 char *s;
1072 size_t i;
1073 int n, N;
1074 sdp_zone_t *z;
1075
1076 /*
1077 zone-adjustments = time space ["-"] typed-time
1078 *(space time space ["-"] typed-time)
1079 */
1080
1081 /** Count number of timezones, check syntax */
1082 for (N = 0, s = r; *s;) {
1083 if (!(is_posdigit(*s)((*s) >= '1' && (*s) <= '9') || (!STRICT(p)(p->pr_strict) && (*s) == '0')))
1084 break;
1085 do { s++; } while (is_digit(*s)((*s) >= '0' && (*s) <= '9'));
1086 if (!(i = STRICT(p)(p->pr_strict) ? is_space(*s)((*s) == ' ') : strspn(s, SPACE TAB)__extension__ ({ char __a0, __a1, __a2; (__builtin_constant_p
(" " "\011") && ((size_t)(const void *)((" " "\011")
+ 1) - (size_t)(const void *)(" " "\011") == 1) ? ((__builtin_constant_p
(s) && ((size_t)(const void *)((s) + 1) - (size_t)(const
void *)(s) == 1)) ? __builtin_strspn (s, " " "\011") : ((__a0
= ((const char *) (" " "\011"))[0], __a0 == '\0') ? ((void) (
s), (size_t) 0) : ((__a1 = ((const char *) (" " "\011"))[1], __a1
== '\0') ? __strspn_c1 (s, __a0) : ((__a2 = ((const char *) (
" " "\011"))[2], __a2 == '\0') ? __strspn_c2 (s, __a0, __a1) :
(((const char *) (" " "\011"))[3] == '\0' ? __strspn_c3 (s, __a0
, __a1, __a2) : __builtin_strspn (s, " " "\011")))))) : __builtin_strspn
(s, " " "\011")); })
))
1087 break;
1088 s += i;
1089 if (!(*s == '-' || is_posdigit(*s)((*s) >= '1' && (*s) <= '9') || (!STRICT(p)(p->pr_strict) && (*s) == '0')))
1090 break;
1091 do { s++; } while (is_digit(*s)((*s) >= '0' && (*s) <= '9'));
1092 if (*s && strchr("dhms", *s)(__extension__ (__builtin_constant_p (*s) && !__builtin_constant_p
("dhms") && (*s) == '\0' ? (char *) __rawmemchr ("dhms"
, *s) : __builtin_strchr ("dhms", *s)))
)
1093 s++;
1094 N++;
1095 if (!(i = STRICT(p)(p->pr_strict) ? is_space(*s)((*s) == ' ') : strspn(s, SPACE TAB)__extension__ ({ char __a0, __a1, __a2; (__builtin_constant_p
(" " "\011") && ((size_t)(const void *)((" " "\011")
+ 1) - (size_t)(const void *)(" " "\011") == 1) ? ((__builtin_constant_p
(s) && ((size_t)(const void *)((s) + 1) - (size_t)(const
void *)(s) == 1)) ? __builtin_strspn (s, " " "\011") : ((__a0
= ((const char *) (" " "\011"))[0], __a0 == '\0') ? ((void) (
s), (size_t) 0) : ((__a1 = ((const char *) (" " "\011"))[1], __a1
== '\0') ? __strspn_c1 (s, __a0) : ((__a2 = ((const char *) (
" " "\011"))[2], __a2 == '\0') ? __strspn_c2 (s, __a0, __a1) :
(((const char *) (" " "\011"))[3] == '\0' ? __strspn_c3 (s, __a0
, __a1, __a2) : __builtin_strspn (s, " " "\011")))))) : __builtin_strspn
(s, " " "\011")); })
))
1096 break;
1097 s += i;
1098 }
1099
1100 PARSE_CHECK_REST(p, s, "z")if (*s && (parsing_error(p, "extra data after %s (\"%.04s\")"
, "z", s), 1)) return
;
1101
1102 if (N < 1) {
1103 parsing_error(p, "invalid timezone");
1104 return;
1105 }
1106 if (!(z = su_salloc(p->pr_home, offsetof(sdp_zone_t, z_adjustments[N])__builtin_offsetof(sdp_zone_t, z_adjustments[N])))) {
1107 parse_alloc_error(p, "sdp_zone_t");
1108 return;
1109 }
1110
1111 z->z_number_of_adjustments = N;
1112
1113 for (n = 0; n < N; n++) {
1114 unsigned long at = strtoul(r, &r, 10);
1115 long offset = strtol(r, &r, 10);
1116 switch (*r) {
1117 case 'd': offset *= 24;
1118 case 'h': offset *= 60;
1119 case 'm': offset *= 60;
1120 case 's': r++;
1121 break;
1122 }
1123
1124 z->z_adjustments[n].z_at = at;
1125 z->z_adjustments[n].z_offset = offset;
1126 }
1127
1128 *result = z;
1129}
1130
1131/* -------------------------------------------------------------------------
1132 * Function parse_key() - parse an "k=" field
1133 *
1134 * Description:
1135 * This function parses an SDP key field.
1136 *
1137 * Parameters:
1138 * p - pointer to SDP parser object
1139 * r - pointer to record data
1140 * result - pointer to which parsed record is assigned
1141 *
1142 */
1143static void parse_key(sdp_parser_t *p, char *r, sdp_key_t **result)
1144{
1145 char *s;
1146 /*
1147 key-field = ["k=" key-type CRLF]
1148
1149 key-type = "prompt" |
1150 "clear:" key-data |
1151 "base64:" key-data |
1152 "uri:" uri
1153
1154 key-data = email-safe | "~" | "
1155 */
1156
1157 s = token(&r, ":", TOKEN"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" "0123456789"
"-!#$%&'*+.^_`{|}~"
, SPACE" " TAB"\011");
1158 if (!s) {
1159 parsing_error(p, "invalid key method");
1160 return;
1161 }
1162
1163 {
1164 PARSE_ALLOC(p, sdp_key_t, k)sdp_key_t *k = su_salloc(p->pr_home, sizeof(*k)); if (!k &&
(parse_alloc_error(p, "sdp_key_t"), 1)) return;
;
1165 *result = k;
1166
1167 /* These are defined as key-sensitive in RFC 4566 */
1168#define MATCH(s, tok)((p->pr_strict) ? su_strmatch((s), (tok)) : su_casematch((
s), (tok)))
\
1169 (STRICT(p)(p->pr_strict) ? su_strmatch((s), (tok)) : su_casematch((s), (tok)))
1170
1171 if (MATCH(s, "clear")((p->pr_strict) ? su_strmatch((s), ("clear")) : su_casematch
((s), ("clear")))
)
1172 k->k_method = sdp_key_clear, k->k_method_name = "clear";
1173 else if (MATCH(s, "base64")((p->pr_strict) ? su_strmatch((s), ("base64")) : su_casematch
((s), ("base64")))
)
1174 k->k_method = sdp_key_base64, k->k_method_name = "base64";
1175 else if (MATCH(s, "uri")((p->pr_strict) ? su_strmatch((s), ("uri")) : su_casematch
((s), ("uri")))
)
1176 k->k_method = sdp_key_uri, k->k_method_name = "uri";
1177 else if (MATCH(s, "prompt")((p->pr_strict) ? su_strmatch((s), ("prompt")) : su_casematch
((s), ("prompt")))
)
1178 k->k_method = sdp_key_prompt, k->k_method_name = "prompt";
1179 else if (!STRICT(p)(p->pr_strict))
1180 k->k_method = sdp_key_x, k->k_method_name = s;
1181 else {
1182 parsing_error(p, "invalid key method");
1183 return;
1184 }
1185
1186 k->k_material = r;
1187 }
1188}
1189
1190/* -------------------------------------------------------------------------
1191 * Function parse_session_attr() - parse a session "a=" field
1192 *
1193 * Description:
1194 * This function parses an SDP attribute field regarding whole session.
1195 *
1196 * Parameters:
1197 * p - pointer to SDP parser object
1198 * r - pointer to record data
1199 * result - pointer to which parsed record is assigned
1200 */
1201static void parse_session_attr(sdp_parser_t *p, char *r, sdp_attribute_t **result)
1202{
1203 /*
1204 attribute-fields = *("a=" attribute CRLF)
1205
1206 attribute = (att-field ":" att-value) / att-field
1207
1208 att-field = token
1209
1210 att-value = byte-string
1211 */
1212
1213 char *name = NULL((void*)0), *value = NULL((void*)0);
1214
1215 if (!(name = token(&r, ":", TOKEN"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" "0123456789"
"-!#$%&'*+.^_`{|}~"
, SPACE" " TAB"\011"))) {
1216 parsing_error(p,"invalid attribute name");
1217 return;
1218 }
1219
1220 if (*r)
1221 value = r;
1222 else
1223 PARSE_CHECK_REST(p, r, "a")if (*r && (parsing_error(p, "extra data after %s (\"%.04s\")"
, "a", r), 1)) return
;
1224
1225 if (su_casematch(name, "charset")) {
1226 p->pr_sessionpr_output.pru_session->sdp_charset = value;
1227 return;
1228 }
1229
1230 if (p->pr_mode_manual)
1231 ;
1232 else if (su_casematch(name, "inactive"))
1233 p->pr_session_mode = sdp_inactive;
1234 else if (su_casematch(name, "sendonly"))
1235 p->pr_session_mode = sdp_sendonly;
1236 else if (su_casematch(name, "recvonly"))
1237 p->pr_session_mode = sdp_recvonly;
1238 else if (su_casematch(name, "sendrecv"))
1239 p->pr_session_mode = sdp_sendrecv;
1240
1241 {
1242 PARSE_ALLOC(p, sdp_attribute_t, a)sdp_attribute_t *a = su_salloc(p->pr_home, sizeof(*a)); if
(!a && (parse_alloc_error(p, "sdp_attribute_t"), 1))
return;
;
1243 *result = a;
1244
1245 a->a_name = name;
1246 a->a_value = value;
1247 }
1248}
1249
1250/* -------------------------------------------------------------------------
1251 * Function parse_media() - parse an "m=" field
1252 *
1253 * Description:
1254 * This function parses an SDP media field.
1255 *
1256 * Parameters:
1257 * p - pointer to SDP parser object
1258 * r - pointer to record data
1259 * result - pointer to which parsed record is assigned
1260 */
1261static void parse_media(sdp_parser_t *p, char *r, sdp_media_t **result)
1262{
1263 /*
1264 media-descriptions = *( media-field
1265 information-field
1266 *(connection-field)
1267 bandwidth-fields
1268 key-field
1269 attribute-fields )
1270
1271 media-field = "m=" media space port ["/" integer]
1272 space proto 1*(space fmt) CRLF
1273
1274 media = token
1275 ;typically "audio", "video", "application"
1276 ;or "data"
1277
1278 fmt = token
1279 ;typically an RTP payload type for audio
1280 ;and video media
1281
1282 proto = token *("/" token)
1283 ;typically "RTP/AVP" or "udp" for IP4
1284
1285 port = 1*(DIGIT)
1286 ;should in the range "1024" to "65535" inclusive
1287 */
1288 char *s;
1289 unsigned long value;
1290 PARSE_ALLOC(p, sdp_media_t, m)sdp_media_t *m = su_salloc(p->pr_home, sizeof(*m)); if (!m
&& (parse_alloc_error(p, "sdp_media_t"), 1)) return;
;
1291
1292 *result = m;
1293
1294 m->m_mode = sdp_sendrecv;
1295
1296 s = token(&r, SPACE" ", TOKEN"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" "0123456789"
"-!#$%&'*+.^_`{|}~"
, NULL((void*)0));
1297 if (!s) {
1298 parsing_error(p, "m= invalid media field");
1299 return;
1300 }
1301
1302 sdp_media_type(m, s);
1303
1304 /* Accept m=* in configuration file */
1305 if (p->pr_config && m->m_type == sdp_media_any) {
1306 r += strspn(r, SPACE TAB)__extension__ ({ char __a0, __a1, __a2; (__builtin_constant_p
(" " "\011") && ((size_t)(const void *)((" " "\011")
+ 1) - (size_t)(const void *)(" " "\011") == 1) ? ((__builtin_constant_p
(r) && ((size_t)(const void *)((r) + 1) - (size_t)(const
void *)(r) == 1)) ? __builtin_strspn (r, " " "\011") : ((__a0
= ((const char *) (" " "\011"))[0], __a0 == '\0') ? ((void) (
r), (size_t) 0) : ((__a1 = ((const char *) (" " "\011"))[1], __a1
== '\0') ? __strspn_c1 (r, __a0) : ((__a2 = ((const char *) (
" " "\011"))[2], __a2 == '\0') ? __strspn_c2 (r, __a0, __a1) :
(((const char *) (" " "\011"))[3] == '\0' ? __strspn_c3 (r, __a0
, __a1, __a2) : __builtin_strspn (r, " " "\011")))))) : __builtin_strspn
(r, " " "\011")); })
;
1307 if (r[0] == '\0') {
1308 m->m_proto = sdp_proto_any, m->m_proto_name = "*";
1309 return;
1310 }
1311 }
1312
1313 if (parse_ul(p, &r, &value, 0)) {
1314 parsing_error(p, "m= invalid port number");
1315 return;
1316 }
1317 m->m_port = value;
1318
1319 if (*r == '/') {
1320 r++;
1321 if (parse_ul(p, &r, &value, 0)) {
1322 parsing_error(p, "m= invalid port specification");
1323 return;
1324 }
1325 m->m_number_of_ports = value;
1326 }
1327
1328 s = token(&r, SPACE" ", "/" TOKEN"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" "0123456789"
"-!#$%&'*+.^_`{|}~"
, SPACE" ");
1329 if (s == NULL((void*)0)) {
1330 parsing_error(p, "m= missing protocol");
1331 return;
1332 }
1333
1334 if (!STRICT(p)(p->pr_strict) && su_casematch(s, "RTP"))
1335 m->m_proto = sdp_proto_rtp, m->m_proto_name = "RTP/AVP";
1336 else
1337 sdp_media_transport(m, s);
1338
1339 /* RTP format list */
1340 if (*r && sdp_media_has_rtp(m)) {
1341 parse_payload(p, r, &m->m_rtpmaps);
1342 return;
1343 }
1344
1345 /* "normal" format list */
1346 if (*r) {
1347 sdp_list_t **fmt = &m->m_format;
1348
1349 while (r && *r) {
1350 PARSE_ALLOC(p, sdp_list_t, l)sdp_list_t *l = su_salloc(p->pr_home, sizeof(*l)); if (!l &&
(parse_alloc_error(p, "sdp_list_t"), 1)) return;
;
1351 *fmt = l;
1352 l->l_text = token(&r, SPACE" " TAB"\011", TOKEN"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" "0123456789"
"-!#$%&'*+.^_`{|}~"
, SPACE" " TAB"\011");
1353 fmt = &l->l_next;
1354 }
1355 }
1356}
1357
1358/** Set media type */
1359void sdp_media_type(sdp_media_t *m, char const *s)
1360{
1361 if (su_strmatch(s, "*"))
1362 m->m_type = sdp_media_any, m->m_type_name = "*";
1363 else if (su_casematch(s, "audio"))
1364 m->m_type = sdp_media_audio, m->m_type_name = "audio";
1365 else if (su_casematch(s, "video"))
1366 m->m_type = sdp_media_video, m->m_type_name = "video";
1367 else if (su_casematch(s, "application"))
1368 m->m_type = sdp_media_application, m->m_type_name = "application";
1369 else if (su_casematch(s, "data"))
1370 m->m_type = sdp_media_data, m->m_type_name = "data";
1371 else if (su_casematch(s, "control"))
1372 m->m_type = sdp_media_control, m->m_type_name = "control";
1373 else if (su_casematch(s, "message"))
1374 m->m_type = sdp_media_message, m->m_type_name = "message";
1375 else if (su_casematch(s, "image"))
1376 m->m_type = sdp_media_image, m->m_type_name = "image";
1377 else if (su_casematch(s, "red"))
1378 m->m_type = sdp_media_red, m->m_type_name = "red";
1379 else
1380 m->m_type = sdp_media_x, m->m_type_name = s;
1381}
1382
1383/** Set transport protocol.
1384 *
1385 * Set the @m->m_proto to a well-known protocol type as
1386 * well as canonize case of @a m_proto_name.
1387 */
1388void sdp_media_transport(sdp_media_t *m, char const *s)
1389{
1390 if (m == NULL((void*)0) || s == NULL((void*)0))
1391 ;
1392 else if (su_strmatch(s, "*"))
1393 m->m_proto = sdp_proto_any, m->m_proto_name = "*";
1394 else if (su_casematch(s, "RTP/AVP"))
1395 m->m_proto = sdp_proto_rtp, m->m_proto_name = "RTP/AVP";
1396 else if (su_casematch(s, "RTP/SAVP"))
1397 m->m_proto = sdp_proto_srtp, m->m_proto_name = "RTP/SAVP";
1398 else if (su_casematch(s, "RTP/SAVPF"))
1399 m->m_proto = sdp_proto_extended_srtp, m->m_proto_name = "RTP/SAVPF";
1400 else if (su_casematch(s, "UDP/TLS/RTP/SAVPF"))
1401 m->m_proto = sdp_proto_extended_srtp, m->m_proto_name = "UDP/TLS/RTP/SAVPF";
1402 else if (su_casematch(s, "udptl"))
1403 /* Lower case - be compatible with people living by T.38 examples */
1404 m->m_proto = sdp_proto_udptl, m->m_proto_name = "udptl";
1405 else if (su_casematch(s, "TCP/MSRP"))
1406 m->m_proto = sdp_proto_msrp, m->m_proto_name = "TCP/MSRP";
1407 else if (su_casematch(s, "TCP/TLS/MSRP"))
1408 m->m_proto = sdp_proto_msrps, m->m_proto_name = "TCP/TLS/MSRP";
1409 else if (su_casematch(s, "UDP"))
1410 m->m_proto = sdp_proto_udp, m->m_proto_name = "UDP";
1411 else if (su_casematch(s, "TCP"))
1412 m->m_proto = sdp_proto_tcp, m->m_proto_name = "TCP";
1413 else if (su_casematch(s, "TLS"))
1414 m->m_proto = sdp_proto_tls, m->m_proto_name = "TLS";
1415 else
1416 m->m_proto = sdp_proto_x, m->m_proto_name = s;
1417}
1418
1419/** Check if media uses RTP as its transport protocol. */
1420int sdp_media_has_rtp(sdp_media_t const *m)
1421{
1422 return m && (m->m_proto == sdp_proto_rtp || m->m_proto == sdp_proto_srtp || m->m_proto == sdp_proto_extended_srtp);
1423}
1424
1425#define RTPMAP(pt, encoding, rate, params){ sizeof(sdp_rtpmap_t), ((void*)0), encoding, rate, (char *)params
, ((void*)0), 1, pt, 0 }
\
1426 { sizeof(sdp_rtpmap_t), NULL((void*)0), encoding, rate, (char *)params, NULL((void*)0), 1, pt, 0 }
1427
1428/* rtpmaps for well-known codecs */
1429static sdp_rtpmap_t const
1430 sdp_rtpmap_pcmu = RTPMAP(0, "PCMU", 8000, 0){ sizeof(sdp_rtpmap_t), ((void*)0), "PCMU", 8000, (char *)0, (
(void*)0), 1, 0, 0 }
,
1431 sdp_rtpmap_1016 = RTPMAP(1, "1016", 8000, 0){ sizeof(sdp_rtpmap_t), ((void*)0), "1016", 8000, (char *)0, (
(void*)0), 1, 1, 0 }
,
1432 sdp_rtpmap_g721 = RTPMAP(2, "G721", 8000, 0){ sizeof(sdp_rtpmap_t), ((void*)0), "G721", 8000, (char *)0, (
(void*)0), 1, 2, 0 }
,
1433 sdp_rtpmap_gsm = RTPMAP(3, "GSM", 8000, 0){ sizeof(sdp_rtpmap_t), ((void*)0), "GSM", 8000, (char *)0, (
(void*)0), 1, 3, 0 }
,
1434 sdp_rtpmap_g723 = RTPMAP(4, "G723", 8000, 0){ sizeof(sdp_rtpmap_t), ((void*)0), "G723", 8000, (char *)0, (
(void*)0), 1, 4, 0 }
,
1435 sdp_rtpmap_dvi4_8000 = RTPMAP(5, "DVI4", 8000, 0){ sizeof(sdp_rtpmap_t), ((void*)0), "DVI4", 8000, (char *)0, (
(void*)0), 1, 5, 0 }
,
1436 sdp_rtpmap_dvi4_16000 = RTPMAP(6, "DVI4", 16000, 0){ sizeof(sdp_rtpmap_t), ((void*)0), "DVI4", 16000, (char *)0,
((void*)0), 1, 6, 0 }
,
1437 sdp_rtpmap_lpc = RTPMAP(7, "LPC", 8000, 0){ sizeof(sdp_rtpmap_t), ((void*)0), "LPC", 8000, (char *)0, (
(void*)0), 1, 7, 0 }
,
1438 sdp_rtpmap_pcma = RTPMAP(8, "PCMA", 8000, 0){ sizeof(sdp_rtpmap_t), ((void*)0), "PCMA", 8000, (char *)0, (
(void*)0), 1, 8, 0 }
,
1439 sdp_rtpmap_g722 = RTPMAP(9, "G722", 8000, 0){ sizeof(sdp_rtpmap_t), ((void*)0), "G722", 8000, (char *)0, (
(void*)0), 1, 9, 0 }
,
1440 sdp_rtpmap_l16_2 = RTPMAP(10, "L16", 44100, "2"){ sizeof(sdp_rtpmap_t), ((void*)0), "L16", 44100, (char *)"2"
, ((void*)0), 1, 10, 0 }
,
1441 sdp_rtpmap_l16 = RTPMAP(11, "L16", 44100, 0){ sizeof(sdp_rtpmap_t), ((void*)0), "L16", 44100, (char *)0, (
(void*)0), 1, 11, 0 }
,
1442 sdp_rtpmap_qcelp = RTPMAP(12, "QCELP", 8000, 0){ sizeof(sdp_rtpmap_t), ((void*)0), "QCELP", 8000, (char *)0,
((void*)0), 1, 12, 0 }
,
1443 sdp_rtpmap_cn = RTPMAP(13, "CN", 8000, 0){ sizeof(sdp_rtpmap_t), ((void*)0), "CN", 8000, (char *)0, ((
void*)0), 1, 13, 0 }
,
1444 sdp_rtpmap_mpa = RTPMAP(14, "MPA", 90000, 0){ sizeof(sdp_rtpmap_t), ((void*)0), "MPA", 90000, (char *)0, (
(void*)0), 1, 14, 0 }
,
1445 sdp_rtpmap_g728 = RTPMAP(15, "G728", 8000, 0){ sizeof(sdp_rtpmap_t), ((void*)0), "G728", 8000, (char *)0, (
(void*)0), 1, 15, 0 }
,
1446 sdp_rtpmap_dvi4_11025 = RTPMAP(16, "DVI4", 11025, 0){ sizeof(sdp_rtpmap_t), ((void*)0), "DVI4", 11025, (char *)0,
((void*)0), 1, 16, 0 }
,
1447 sdp_rtpmap_dvi4_22050 = RTPMAP(17, "DVI4", 22050, 0){ sizeof(sdp_rtpmap_t), ((void*)0), "DVI4", 22050, (char *)0,
((void*)0), 1, 17, 0 }
,
1448 sdp_rtpmap_g729 = RTPMAP(18, "G729", 8000, 0){ sizeof(sdp_rtpmap_t), ((void*)0), "G729", 8000, (char *)0, (
(void*)0), 1, 18, 0 }
,
1449 sdp_rtpmap_reserved_cn = RTPMAP(19, "CN", 8000, 0){ sizeof(sdp_rtpmap_t), ((void*)0), "CN", 8000, (char *)0, ((
void*)0), 1, 19, 0 }
,
1450 /* video codecs */
1451 sdp_rtpmap_celb = RTPMAP(25, "CelB", 90000, 0){ sizeof(sdp_rtpmap_t), ((void*)0), "CelB", 90000, (char *)0,
((void*)0), 1, 25, 0 }
,
1452 sdp_rtpmap_jpeg = RTPMAP(26, "JPEG", 90000, 0){ sizeof(sdp_rtpmap_t), ((void*)0), "JPEG", 90000, (char *)0,
((void*)0), 1, 26, 0 }
,
1453 sdp_rtpmap_nv = RTPMAP(28, "nv", 90000, 0){ sizeof(sdp_rtpmap_t), ((void*)0), "nv", 90000, (char *)0, (
(void*)0), 1, 28, 0 }
,
1454 sdp_rtpmap_h261 = RTPMAP(31, "H261", 90000, 0){ sizeof(sdp_rtpmap_t), ((void*)0), "H261", 90000, (char *)0,
((void*)0), 1, 31, 0 }
,
1455 sdp_rtpmap_mpv = RTPMAP(32, "MPV", 90000, 0){ sizeof(sdp_rtpmap_t), ((void*)0), "MPV", 90000, (char *)0, (
(void*)0), 1, 32, 0 }
,
1456 sdp_rtpmap_mp2t = RTPMAP(33, "MP2T", 90000, 0){ sizeof(sdp_rtpmap_t), ((void*)0), "MP2T", 90000, (char *)0,
((void*)0), 1, 33, 0 }
,
1457 sdp_rtpmap_h263 = RTPMAP(34, "H263", 90000, 0){ sizeof(sdp_rtpmap_t), ((void*)0), "H263", 90000, (char *)0,
((void*)0), 1, 34, 0 }
;
1458
1459/** Table of rtpmap structures by payload type numbers.
1460 *
1461 * The table of reserved payload numbers is constructed from @RFC3551
1462 * and @RFC1890. Note the clock rate of G722.
1463 *
1464 * Use sdp_rtpmap_dup() to copy these structures.
1465 */
1466sdp_rtpmap_t const * const sdp_rtpmap_well_known[128] =
1467{
1468 &sdp_rtpmap_pcmu, /* 0 */
1469 &sdp_rtpmap_1016, /* 1 */
1470 &sdp_rtpmap_g721, /* 2 */
1471 &sdp_rtpmap_gsm, /* 3 */
1472 &sdp_rtpmap_g723, /* 4 */
1473 &sdp_rtpmap_dvi4_8000, /* 5 */
1474 &sdp_rtpmap_dvi4_16000, /* 6 */
1475 &sdp_rtpmap_lpc, /* 7 */
1476 &sdp_rtpmap_pcma, /* 8 */
1477 &sdp_rtpmap_g722, /* 9 */
1478 &sdp_rtpmap_l16_2, /* 10 */
1479 &sdp_rtpmap_l16, /* 11 */
1480 &sdp_rtpmap_qcelp, /* 12 */
1481 &sdp_rtpmap_cn, /* 13 */
1482 &sdp_rtpmap_mpa, /* 14 */
1483 &sdp_rtpmap_g728, /* 15 */
1484 &sdp_rtpmap_dvi4_11025, /* 16 */
1485 &sdp_rtpmap_dvi4_22050, /* 17 */
1486 &sdp_rtpmap_g729, /* 18 */
1487 &sdp_rtpmap_reserved_cn, /* 19 */
1488 NULL((void*)0), /* 20 */
1489 NULL((void*)0), /* 21 */
1490 NULL((void*)0), /* 22 */
1491 NULL((void*)0), /* 23 */
1492 NULL((void*)0), /* 24 */
1493 &sdp_rtpmap_celb, /* 25 */
1494 &sdp_rtpmap_jpeg, /* 26 */
1495 NULL((void*)0), /* 27 */
1496 &sdp_rtpmap_nv, /* 28 */
1497 NULL((void*)0), /* 29 */
1498 NULL((void*)0), /* 30 */
1499 &sdp_rtpmap_h261, /* 31 */
1500 &sdp_rtpmap_mpv, /* 32 */
1501 &sdp_rtpmap_mp2t, /* 33 */
1502 &sdp_rtpmap_h263, /* 34 */
1503 NULL((void*)0),
1504};
1505
1506/**
1507 * The function parse_payload() parses an RTP payload type list, and
1508 * creates an rtpmap structure for each payload type.
1509 *
1510 * @param p pointer to SDP parser object
1511 * @param r pointer to record data
1512 * @param result pointer to which parsed record is assigned
1513 */
1514static void parse_payload(sdp_parser_t *p, char *r, sdp_rtpmap_t **result)
1515{
1516 while (*r) {
1517 unsigned long value;
1518
1519 if (parse_ul(p, &r, &value, 128) == 0) {
1520 PARSE_ALLOC(p, sdp_rtpmap_t, rm)sdp_rtpmap_t *rm = su_salloc(p->pr_home, sizeof(*rm)); if (
!rm && (parse_alloc_error(p, "sdp_rtpmap_t"), 1)) return
;
;
1521
1522 assert(0 <= value && value < 128)((0 <= value && value < 128) ? (void) (0) : __assert_fail
("0 <= value && value < 128", "sdp_parse.c", 1522
, __PRETTY_FUNCTION__))
;
1523
1524 *result = rm; result = &rm->rm_next;
1525
1526 if (sdp_rtpmap_well_known[value]) {
1527 *rm = *sdp_rtpmap_well_known[value];
1528 }
1529 else {
1530 rm->rm_predef = 1;
1531 rm->rm_pt = value;
1532 rm->rm_encoding = "";
1533 rm->rm_rate = 0;
1534 }
1535 }
1536 else if (p->pr_config && r[0] == '*' && (r[1] == ' ' || r[1] == '\0')) {
1537 PARSE_ALLOC(p, sdp_rtpmap_t, rm)sdp_rtpmap_t *rm = su_salloc(p->pr_home, sizeof(*rm)); if (
!rm && (parse_alloc_error(p, "sdp_rtpmap_t"), 1)) return
;
;
1538
1539 *result = rm; result = &rm->rm_next;
Value stored to 'result' is never read
1540
1541 rm->rm_predef = 1;
1542 rm->rm_any = 1;
1543 rm->rm_encoding = "*";
1544 rm->rm_rate = 0;
1545
1546 return;
1547 }
1548 else {
1549 parsing_error(p, "m= invalid format for RTP/AVT");
1550
1551 return;
1552 }
1553 }
1554}
1555
1556/* -------------------------------------------------------------------------
1557 * Function parse_media_attr() - parse a media-specific "a=" field
1558 *
1559 * Description:
1560 * This function parses a media-specific attribute field.
1561 *
1562 * Parameters:
1563 * p - pointer to SDP parser object
1564 * r - pointer to record data
1565 * result - pointer to which parsed record is assigned
1566 */
1567static void parse_media_attr(sdp_parser_t *p, char *r, sdp_media_t *m,
1568 sdp_attribute_t **result)
1569{
1570 /*
1571 attribute-fields = *("a=" attribute CRLF)
1572
1573 attribute = (att-field ":" att-value) / att-field
1574
1575 att-field = token
1576
1577 att-value = byte-string
1578
1579 a=rtpmap:<payload type> <encoding name>/<clock rate>[/<encoding parameters>]
1580 a=fmtp:<payload type> <parameters>
1581 */
1582 int rtp = sdp_media_has_rtp(m);
1583 char *name = NULL((void*)0), *value = NULL((void*)0);
1584 int n;
1585
1586 if (!(name = token(&r, ":", TOKEN"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" "0123456789"
"-!#$%&'*+.^_`{|}~"
, SPACE" " TAB"\011"))) {
1587 parsing_error(p,"invalid attribute name");
1588 return;
1589 }
1590
1591 if (*r)
1592 value = r;
1593 else
1594 PARSE_CHECK_REST(p, r, "a")if (*r && (parsing_error(p, "extra data after %s (\"%.04s\")"
, "a", r), 1)) return
;
1595
1596 if (p->pr_mode_manual)
1597 ;
1598 else if (m->m_port == 0 || su_casematch(name, "inactive")) {
1599 m->m_mode = sdp_inactive;
1600 return;
1601 }
1602 else if (su_casematch(name, "sendonly")) {
1603 m->m_mode = sdp_sendonly;
1604 return;
1605 }
1606 else if (su_casematch(name, "recvonly")) {
1607 m->m_mode = sdp_recvonly;
1608 return;
1609 }
1610 else if (su_casematch(name, "sendrecv")) {
1611 m->m_mode = sdp_sendrecv;
1612 return;
1613 }
1614
1615 if (rtp && su_casematch(name, "rtpmap")) {
1616 if ((n = parse_rtpmap(p, r, m)) == 0 || n < -1)
1617 return;
1618 }
1619 else if (rtp && su_casematch(name, "fmtp")) {
1620 if ((n = parse_fmtp(p, r, m)) == 0 || n < -1)
1621 return;
1622 }
1623 else {
1624 PARSE_ALLOC(p, sdp_attribute_t, a)sdp_attribute_t *a = su_salloc(p->pr_home, sizeof(*a)); if
(!a && (parse_alloc_error(p, "sdp_attribute_t"), 1))
return;
;
1625 *result = a;
1626
1627 a->a_name = name;
1628 a->a_value = value;
1629 }
1630}
1631
1632/** Parse rtpmap attribute.
1633 *
1634 * a=rtpmap:<payload type> <encoding name>/<clock rate>[/<encoding parameters>]
1635 */
1636static int parse_rtpmap(sdp_parser_t *p, char *r, sdp_media_t *m)
1637{
1638 unsigned long pt, rate;
1639 char *encoding, *params;
1640 sdp_rtpmap_t *rm;
1641
1642 int strict = STRICT(p)(p->pr_strict);
1643
1644 if (parse_ul(p, &r, &pt, 128)) {
1645 if (strict)
1646 parsing_error(p, "a=rtpmap: invalid payload type");
1647 return -1;
1648 }
1649
1650 for (rm = m->m_rtpmaps; rm; rm = rm->rm_next)
1651 if (rm->rm_pt == pt)
1652 break;
1653
1654 if (!rm) {
1655 if (strict)
1656 parsing_error(p, "a=rtpmap:%lu: unknown payload type", pt);
1657 return -1;
1658 }
1659
1660 encoding = token(&r, "/", TOKEN"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" "0123456789"
"-!#$%&'*+.^_`{|}~"
, NULL((void*)0));
1661 if (!r) {
1662 parsing_error(p, "a=rtpmap:%lu: missing <clock rate>", pt);
1663 return -2;
1664 }
1665 if (parse_ul(p, &r, &rate, 0)) {
1666 parsing_error(p, "a=rtpmap:%lu %s: invalid <clock rate>", pt, encoding);
1667 return -2;
1668 }
1669
1670 if (*r == '/')
1671 params = ++r;
1672 else
1673 params = 0;
1674
1675 rm->rm_predef = 0;
1676 rm->rm_encoding = encoding;
1677 rm->rm_rate = rate;
1678 rm->rm_params = params;
1679
1680 return 0;
1681}
1682
1683/** Parse fmtp attribute.
1684 *
1685 * a=fmtp:<payload type> <parameters>
1686 */
1687static int parse_fmtp(sdp_parser_t *p, char *r, sdp_media_t *m)
1688{
1689 unsigned long pt;
1690 sdp_rtpmap_t *rm;
1691
1692 int strict = STRICT(p)(p->pr_strict);
1693
1694 if (parse_ul(p, &r, &pt, 128)) {
1695 if (strict)
1696 parsing_error(p, "a=rtpmap: invalid payload type");
1697 return -1;
1698 }
1699
1700 for (rm = m->m_rtpmaps; rm; rm = rm->rm_next)
1701 if (rm->rm_pt == pt)
1702 break;
1703
1704 if (!rm) {
1705 if (strict)
1706 parsing_error(p, "a=fmtp:%lu: unknown payload type", pt);
1707 return -1;
1708 }
1709
1710 rm->rm_fmtp = r;
1711 return 0;
1712}
1713
1714/* -------------------------------------------------------------------------
1715 * Function parse_descs() - parse media descriptors
1716 *
1717 * Description:
1718 * This function parses media descriptors at the end of SDP message.
1719 *
1720 * Parameters:
1721 * p - pointer to SDP parser object
1722 * record - pointer to first media field
1723 * message - pointer to rest
1724 * medias - pointer to which parsed media structures are assigned
1725 */
1726static void parse_descs(sdp_parser_t *p,
1727 char *record,
1728 char *message,
1729 sdp_media_t **medias)
1730{
1731 char *rest;
1732 const char *strip;
1733 sdp_media_t *m = NULL((void*)0);
1734 sdp_connection_t **connections = NULL((void*)0);
1735 sdp_bandwidth_t **bandwidths = NULL((void*)0);
1736 sdp_attribute_t **attributes = NULL((void*)0);
1737
1738 if (!STRICT(p)(p->pr_strict))
1739 strip = SPACE" " TAB"\011"; /* skip initial whitespace */
1740 else
1741 strip = "";
1742
1743 for (;
1744 record && p->pr_ok;
1745 record = next(&message, CRLF"\015\012", strip)) {
1746 char field = record[0];
1747
1748 rest = record + 2; rest += strspn(rest, strip)__extension__ ({ char __a0, __a1, __a2; (__builtin_constant_p
(strip) && ((size_t)(const void *)((strip) + 1) - (size_t
)(const void *)(strip) == 1) ? ((__builtin_constant_p (rest) &&
((size_t)(const void *)((rest) + 1) - (size_t)(const void *)
(rest) == 1)) ? __builtin_strspn (rest, strip) : ((__a0 = ((const
char *) (strip))[0], __a0 == '\0') ? ((void) (rest), (size_t
) 0) : ((__a1 = ((const char *) (strip))[1], __a1 == '\0') ? __strspn_c1
(rest, __a0) : ((__a2 = ((const char *) (strip))[2], __a2 ==
'\0') ? __strspn_c2 (rest, __a0, __a1) : (((const char *) (strip
))[3] == '\0' ? __strspn_c3 (rest, __a0, __a1, __a2) : __builtin_strspn
(rest, strip)))))) : __builtin_strspn (rest, strip)); })
;
1749
1750 if (record[1] == '=') switch (field) {
1751 case 'c':
1752 assert(connections)((connections) ? (void) (0) : __assert_fail ("connections", "sdp_parse.c"
, 1752, __PRETTY_FUNCTION__))
;
1753 parse_connection(p, rest, connections);
1754 connections = &(*connections)->c_next;
1755 break;
1756
1757 case 'b':
1758 assert(bandwidths)((bandwidths) ? (void) (0) : __assert_fail ("bandwidths", "sdp_parse.c"
, 1758, __PRETTY_FUNCTION__))
;
1759 parse_bandwidth(p, rest, bandwidths);
1760 bandwidths = &(*bandwidths)->b_next;
1761 break;
1762
1763 case 'k':
1764 parse_key(p, rest, &m->m_key);
1765 break;
1766
1767 case 'a':
1768 assert(attributes)((attributes) ? (void) (0) : __assert_fail ("attributes", "sdp_parse.c"
, 1768, __PRETTY_FUNCTION__))
;
1769 parse_media_attr(p, rest, m, attributes);
1770 if (*attributes)
1771 attributes = &(*attributes)->a_next;
1772 break;
1773
1774 case 'm':
1775 parse_media(p, rest, medias);
1776 m = *medias;
1777 if (m) {
1778 m->m_mode = p->pr_session_mode;
1779 medias = &m->m_next;
1780 connections = &m->m_connections;
1781 bandwidths = &m->m_bandwidths;
1782 attributes = &m->m_attributes;
1783 }
1784 }
1785 }
1786}
1787
1788static void parse_text_list(sdp_parser_t *p, char *r, sdp_list_t **result)
1789{
1790 PARSE_ALLOC(p, sdp_list_t, l)sdp_list_t *l = su_salloc(p->pr_home, sizeof(*l)); if (!l &&
(parse_alloc_error(p, "sdp_list_t"), 1)) return;
;
1791
1792 *result = l;
1793
1794 l->l_text = r;
1795}
1796
1797/*
1798 * parse_ul: parse an unsigned long
1799 */
1800static int parse_ul(sdp_parser_t *p, char **r,
1801 unsigned long *result, unsigned long max)
1802{
1803 char *ul = *r;
1804
1805 ul += strspn(ul, SPACE TAB)__extension__ ({ char __a0, __a1, __a2; (__builtin_constant_p
(" " "\011") && ((size_t)(const void *)((" " "\011")
+ 1) - (size_t)(const void *)(" " "\011") == 1) ? ((__builtin_constant_p
(ul) && ((size_t)(const void *)((ul) + 1) - (size_t)
(const void *)(ul) == 1)) ? __builtin_strspn (ul, " " "\011")
: ((__a0 = ((const char *) (" " "\011"))[0], __a0 == '\0') ?
((void) (ul), (size_t) 0) : ((__a1 = ((const char *) (" " "\011"
))[1], __a1 == '\0') ? __strspn_c1 (ul, __a0) : ((__a2 = ((const
char *) (" " "\011"))[2], __a2 == '\0') ? __strspn_c2 (ul, __a0
, __a1) : (((const char *) (" " "\011"))[3] == '\0' ? __strspn_c3
(ul, __a0, __a1, __a2) : __builtin_strspn (ul, " " "\011")))
))) : __builtin_strspn (ul, " " "\011")); })
;
1806
1807 *result = strtoul(ul, r, 10);
1808 if (ul != *r && !(max && max <= *result)) {
1809 *r += strspn(*r, SPACE TAB)__extension__ ({ char __a0, __a1, __a2; (__builtin_constant_p
(" " "\011") && ((size_t)(const void *)((" " "\011")
+ 1) - (size_t)(const void *)(" " "\011") == 1) ? ((__builtin_constant_p
(*r) && ((size_t)(const void *)((*r) + 1) - (size_t)
(const void *)(*r) == 1)) ? __builtin_strspn (*r, " " "\011")
: ((__a0 = ((const char *) (" " "\011"))[0], __a0 == '\0') ?
((void) (*r), (size_t) 0) : ((__a1 = ((const char *) (" " "\011"
))[1], __a1 == '\0') ? __strspn_c1 (*r, __a0) : ((__a2 = ((const
char *) (" " "\011"))[2], __a2 == '\0') ? __strspn_c2 (*r, __a0
, __a1) : (((const char *) (" " "\011"))[3] == '\0' ? __strspn_c3
(*r, __a0, __a1, __a2) : __builtin_strspn (*r, " " "\011")))
))) : __builtin_strspn (*r, " " "\011")); })
;
1810 return 0;
1811 }
1812
1813 return -1;
1814}
1815
1816#if !HAVE_STRTOULL1
1817#if !((defined(WIN32) || defined(_WIN32)) && (_MSC_VER >= 1800))
1818unsigned long long strtoull(char const *string, char **return_end, int base);
1819#endif
1820#endif
1821
1822/*
1823 * parse_ull: parse an unsigned long long
1824 */
1825static int parse_ull(sdp_parser_t *p, char **r,
1826 uint64_t *result, uint64_t max)
1827{
1828 unsigned long long ull;
1829
1830 char *s = *r;
1831
1832 s += strspn(s, SPACE TAB)__extension__ ({ char __a0, __a1, __a2; (__builtin_constant_p
(" " "\011") && ((size_t)(const void *)((" " "\011")
+ 1) - (size_t)(const void *)(" " "\011") == 1) ? ((__builtin_constant_p
(s) && ((size_t)(const void *)((s) + 1) - (size_t)(const
void *)(s) == 1)) ? __builtin_strspn (s, " " "\011") : ((__a0
= ((const char *) (" " "\011"))[0], __a0 == '\0') ? ((void) (
s), (size_t) 0) : ((__a1 = ((const char *) (" " "\011"))[1], __a1
== '\0') ? __strspn_c1 (s, __a0) : ((__a2 = ((const char *) (
" " "\011"))[2], __a2 == '\0') ? __strspn_c2 (s, __a0, __a1) :
(((const char *) (" " "\011"))[3] == '\0' ? __strspn_c3 (s, __a0
, __a1, __a2) : __builtin_strspn (s, " " "\011")))))) : __builtin_strspn
(s, " " "\011")); })
;
1833
1834 ull = strtoull(s, r, 10);
1835
1836 if (s != *r && !(max && max <= ull)) {
1837 *result = (uint64_t)ull;
1838 *r += strspn(*r, SPACE TAB)__extension__ ({ char __a0, __a1, __a2; (__builtin_constant_p
(" " "\011") && ((size_t)(const void *)((" " "\011")
+ 1) - (size_t)(const void *)(" " "\011") == 1) ? ((__builtin_constant_p
(*r) && ((size_t)(const void *)((*r) + 1) - (size_t)
(const void *)(*r) == 1)) ? __builtin_strspn (*r, " " "\011")
: ((__a0 = ((const char *) (" " "\011"))[0], __a0 == '\0') ?
((void) (*r), (size_t) 0) : ((__a1 = ((const char *) (" " "\011"
))[1], __a1 == '\0') ? __strspn_c1 (*r, __a0) : ((__a2 = ((const
char *) (" " "\011"))[2], __a2 == '\0') ? __strspn_c2 (*r, __a0
, __a1) : (((const char *) (" " "\011"))[3] == '\0' ? __strspn_c3
(*r, __a0, __a1, __a2) : __builtin_strspn (*r, " " "\011")))
))) : __builtin_strspn (*r, " " "\011")); })
;
1839 return 0;
1840 }
1841
1842 return -1;
1843}
1844
1845static char *token(char **message,
1846 const char *sep,
1847 const char *legal,
1848 const char *strip)
1849{
1850 size_t n;
1851 char *retval = *message;
1852
1853 if (strip)
1854 retval += strspn(retval, strip)__extension__ ({ char __a0, __a1, __a2; (__builtin_constant_p
(strip) && ((size_t)(const void *)((strip) + 1) - (size_t
)(const void *)(strip) == 1) ? ((__builtin_constant_p (retval
) && ((size_t)(const void *)((retval) + 1) - (size_t)
(const void *)(retval) == 1)) ? __builtin_strspn (retval, strip
) : ((__a0 = ((const char *) (strip))[0], __a0 == '\0') ? ((void
) (retval), (size_t) 0) : ((__a1 = ((const char *) (strip))[1
], __a1 == '\0') ? __strspn_c1 (retval, __a0) : ((__a2 = ((const
char *) (strip))[2], __a2 == '\0') ? __strspn_c2 (retval, __a0
, __a1) : (((const char *) (strip))[3] == '\0' ? __strspn_c3 (
retval, __a0, __a1, __a2) : __builtin_strspn (retval, strip))
)))) : __builtin_strspn (retval, strip)); })
;
1855
1856 if (legal)
1857 n = strspn(retval, legal)__extension__ ({ char __a0, __a1, __a2; (__builtin_constant_p
(legal) && ((size_t)(const void *)((legal) + 1) - (size_t
)(const void *)(legal) == 1) ? ((__builtin_constant_p (retval
) && ((size_t)(const void *)((retval) + 1) - (size_t)
(const void *)(retval) == 1)) ? __builtin_strspn (retval, legal
) : ((__a0 = ((const char *) (legal))[0], __a0 == '\0') ? ((void
) (retval), (size_t) 0) : ((__a1 = ((const char *) (legal))[1
], __a1 == '\0') ? __strspn_c1 (retval, __a0) : ((__a2 = ((const
char *) (legal))[2], __a2 == '\0') ? __strspn_c2 (retval, __a0
, __a1) : (((const char *) (legal))[3] == '\0' ? __strspn_c3 (
retval, __a0, __a1, __a2) : __builtin_strspn (retval, legal))
)))) : __builtin_strspn (retval, legal)); })
;
1858 else
1859 n = strcspn(retval, sep)__extension__ ({ char __r0, __r1, __r2; (__builtin_constant_p
(sep) && ((size_t)(const void *)((sep) + 1) - (size_t
)(const void *)(sep) == 1) ? ((__builtin_constant_p (retval) &&
((size_t)(const void *)((retval) + 1) - (size_t)(const void *
)(retval) == 1)) ? __builtin_strcspn (retval, sep) : ((__r0 =
((const char *) (sep))[0], __r0 == '\0') ? strlen (retval) :
((__r1 = ((const char *) (sep))[1], __r1 == '\0') ? __strcspn_c1
(retval, __r0) : ((__r2 = ((const char *) (sep))[2], __r2 ==
'\0') ? __strcspn_c2 (retval, __r0, __r1) : (((const char *)
(sep))[3] == '\0' ? __strcspn_c3 (retval, __r0, __r1, __r2) :
__builtin_strcspn (retval, sep)))))) : __builtin_strcspn (retval
, sep)); })
;
1860
1861 if (n == 0)
1862 return NULL((void*)0);
1863
1864 if (retval[n]) {
1865 retval[n++] = '\0';
1866 n += strspn(retval + n, sep)__extension__ ({ char __a0, __a1, __a2; (__builtin_constant_p
(sep) && ((size_t)(const void *)((sep) + 1) - (size_t
)(const void *)(sep) == 1) ? ((__builtin_constant_p (retval +
n) && ((size_t)(const void *)((retval + n) + 1) - (size_t
)(const void *)(retval + n) == 1)) ? __builtin_strspn (retval
+ n, sep) : ((__a0 = ((const char *) (sep))[0], __a0 == '\0'
) ? ((void) (retval + n), (size_t) 0) : ((__a1 = ((const char
*) (sep))[1], __a1 == '\0') ? __strspn_c1 (retval + n, __a0)
: ((__a2 = ((const char *) (sep))[2], __a2 == '\0') ? __strspn_c2
(retval + n, __a0, __a1) : (((const char *) (sep))[3] == '\0'
? __strspn_c3 (retval + n, __a0, __a1, __a2) : __builtin_strspn
(retval + n, sep)))))) : __builtin_strspn (retval + n, sep))
; })
;
1867 }
1868
1869 *message = retval + n;
1870
1871 if (*retval == '\0')
1872 return NULL((void*)0);
1873
1874 return retval;
1875}
1876
1877static char *next(char **message, const char *sep, const char *strip)
1878{
1879 size_t n;
1880 char *retval = *message;
1881
1882 if (strip[0])
1883 retval += strspn(retval, strip)__extension__ ({ char __a0, __a1, __a2; (__builtin_constant_p
(strip) && ((size_t)(const void *)((strip) + 1) - (size_t
)(const void *)(strip) == 1) ? ((__builtin_constant_p (retval
) && ((size_t)(const void *)((retval) + 1) - (size_t)
(const void *)(retval) == 1)) ? __builtin_strspn (retval, strip
) : ((__a0 = ((const char *) (strip))[0], __a0 == '\0') ? ((void
) (retval), (size_t) 0) : ((__a1 = ((const char *) (strip))[1
], __a1 == '\0') ? __strspn_c1 (retval, __a0) : ((__a2 = ((const
char *) (strip))[2], __a2 == '\0') ? __strspn_c2 (retval, __a0
, __a1) : (((const char *) (strip))[3] == '\0' ? __strspn_c3 (
retval, __a0, __a1, __a2) : __builtin_strspn (retval, strip))
)))) : __builtin_strspn (retval, strip)); })
;
1884
1885 n = strcspn(retval, sep)__extension__ ({ char __r0, __r1, __r2; (__builtin_constant_p
(sep) && ((size_t)(const void *)((sep) + 1) - (size_t
)(const void *)(sep) == 1) ? ((__builtin_constant_p (retval) &&
((size_t)(const void *)((retval) + 1) - (size_t)(const void *
)(retval) == 1)) ? __builtin_strcspn (retval, sep) : ((__r0 =
((const char *) (sep))[0], __r0 == '\0') ? strlen (retval) :
((__r1 = ((const char *) (sep))[1], __r1 == '\0') ? __strcspn_c1
(retval, __r0) : ((__r2 = ((const char *) (sep))[2], __r2 ==
'\0') ? __strcspn_c2 (retval, __r0, __r1) : (((const char *)
(sep))[3] == '\0' ? __strcspn_c3 (retval, __r0, __r1, __r2) :
__builtin_strcspn (retval, sep)))))) : __builtin_strcspn (retval
, sep)); })
;
1886
1887 if (n == 0)
1888 return NULL((void*)0);
1889
1890 if (retval[n]) {
1891 retval[n++] = '\0';
1892 n += strspn(retval + n, sep)__extension__ ({ char __a0, __a1, __a2; (__builtin_constant_p
(sep) && ((size_t)(const void *)((sep) + 1) - (size_t
)(const void *)(sep) == 1) ? ((__builtin_constant_p (retval +
n) && ((size_t)(const void *)((retval + n) + 1) - (size_t
)(const void *)(retval + n) == 1)) ? __builtin_strspn (retval
+ n, sep) : ((__a0 = ((const char *) (sep))[0], __a0 == '\0'
) ? ((void) (retval + n), (size_t) 0) : ((__a1 = ((const char
*) (sep))[1], __a1 == '\0') ? __strspn_c1 (retval + n, __a0)
: ((__a2 = ((const char *) (sep))[2], __a2 == '\0') ? __strspn_c2
(retval + n, __a0, __a1) : (((const char *) (sep))[3] == '\0'
? __strspn_c3 (retval + n, __a0, __a1, __a2) : __builtin_strspn
(retval + n, sep)))))) : __builtin_strspn (retval + n, sep))
; })
;
1893 }
1894
1895 *message = retval + n;
1896
1897 if (*retval == '\0')
1898 return NULL((void*)0);
1899
1900 return retval;
1901}
1902
1903static int parsing_error(sdp_parser_t *p, char const *fmt, ...)
1904{
1905 va_list ap;
1906 va_start(ap, fmt)__builtin_va_start(ap, fmt);
1907
1908 memset(p->pr_errorpr_output.pru_error, 0, sizeof(p->pr_errorpr_output.pru_error));
1909 vsnprintf(p->pr_errorpr_output.pru_error, sizeof(p->pr_errorpr_output.pru_error), fmt, ap);
1910 va_end(ap)__builtin_va_end(ap);
1911
1912 p->pr_ok = 0;
1913
1914 return -1;
1915}
1916
1917static void parse_alloc_error(sdp_parser_t *p, const char *typename)
1918{
1919 parsing_error(p, "memory exhausted (while allocating memory for %s)",
1920 typename);
1921}