Bug Summary

File:sdp/sdp_parse.c
Warning:line 1167, column 13
Dereference of null pointer (loaded from variable 'result')

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name sdp_parse.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-eagerly-assume -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -mrelocation-model pic -pic-level 2 -mthread-model posix -mdisable-fp-elim -fmath-errno -masm-verbose -mconstructor-aliases -munwind-tables -fuse-init-array -target-cpu x86-64 -dwarf-column-info -debugger-tuning=gdb -resource-dir /usr/lib/llvm-7/lib/clang/7.0.1 -D HAVE_CONFIG_H -I . -I ../.. -I ../../libsofia-sip-ua/su/sofia-sip -I ./../su -I ../su -D SU_DEBUG=0 -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib/llvm-7/lib/clang/7.0.1/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fdebug-compilation-dir /drone/src/libsofia-sip-ua/sdp -ferror-limit 19 -fmessage-length 0 -fobjc-runtime=gcc -fdiagnostics-show-option -analyzer-output=html -o /drone/src/scan-build/2021-08-31-181429-363-1 -x c sdp_parse.c -faddrsig
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)) {
1
Assuming the condition is false
2
Assuming 'msg' is not equal to NULL
3
Taking false branch
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)
4
Taking false branch
165 len = ISSIZE_MAX2147483647;
166
167 p = su_home_clone(home, sizeof(*p) + len + 1);
168
169 if (p) {
5
Assuming 'p' is non-null
6
Taking true branch
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;
7
Assuming the condition is false
175 p->pr_anynet = (flags & sdp_f_anynet) != 0;
8
Assuming the condition is false
176 p->pr_mode_0000 = (flags & sdp_f_mode_0000) != 0;
9
Assuming the condition is false
177 p->pr_insane = (flags & sdp_f_insane) != 0;
10
Assuming the condition is false
178 p->pr_c_missing = (flags & sdp_f_c_missing) != 0;
11
Assuming the condition is false
179 if (flags & sdp_f_config)
12
Assuming the condition is false
13
Taking false branch
180 p->pr_c_missing = 1, p->pr_config = 1;
181 p->pr_mode_manual = (flags & sdp_f_mode_manual) != 0;
14
Assuming the condition is false
182 p->pr_session_mode = sdp_sendrecv;
183
184 parse_message(p);
15
Calling 'parse_message'
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))
16
Taking true branch
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")) {
17
Assuming the condition is true
18
Taking true branch
380 if (!p->pr_config || !record || record[1] != '=') {
19
Assuming the condition is false
20
Taking false branch
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 (;
21
Loop condition is true. Entering loop body
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);
400
401 if (record[1] != '=') {
22
Taking false branch
402 parsing_error(p, "bad line \"%s\"", record);
403 return;
404 }
405
406 switch (field) {
23
Control jumps to 'case 109:' at line 473
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);
24
Calling 'parse_descs'
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, '/');
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 = "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)(p->pr_strict))
933 PARSE_CHECK_REST(p, r, "b")if (*r && (parsing_error(p, "extra data after %s (\"%.04s\")"
, "b", r), 1)) return
;
934
935 {
936 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;
;
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 */
955static 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)sdp_time_t *t = su_salloc(p->pr_home, sizeof(*t)); if (!t &&
(parse_alloc_error(p, "sdp_time_t"), 1)) return;
;
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)(p->pr_strict)) {
980 PARSE_CHECK_REST(p, r, "t")if (*r && (parsing_error(p, "extra data after %s (\"%.04s\")"
, "t", r), 1)) return
;
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 */
994static 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)(p->pr_strict);
1012
1013 /** Count number of intervals */
1014 for (N = 0, s = d; *s; ) {
1015 if (!(is_posdigit(*s)((*s) >= '1' && (*s) <= '9') || (!strict && (*s) == '0')))
1016 break;
1017 do { s++; } while (is_digit(*s)((*s) >= '0' && (*s) <= '9'));
1018 if (*s && strchr(strict ? "dhms" : "dhmsDHMS", *s))
1019 s++;
1020 N++;
1021 if (!(i = strict ? is_space(*s)((*s) == ' ') : strspn(s, SPACE" " TAB"\011")))
1022 break;
1023 s += i;
1024 }
1025
1026 PARSE_CHECK_REST(p, s, "r")if (*s && (parsing_error(p, "extra data after %s (\"%.04s\")"
, "r", s), 1)) return
;
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])__builtin_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)((*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 */
1071static 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)((*s) >= '1' && (*s) <= '9') || (!STRICT(p)(p->pr_strict) && (*s) == '0')))
1086 break;
1087 do { s++; } while (is_digit(*s)((*s) >= '0' && (*s) <= '9'));
1088 if (!(i = STRICT(p)(p->pr_strict) ? is_space(*s)((*s) == ' ') : strspn(s, SPACE" " TAB"\011")))
1089 break;
1090 s += i;
1091 if (!(*s == '-' || is_posdigit(*s)((*s) >= '1' && (*s) <= '9') || (!STRICT(p)(p->pr_strict) && (*s) == '0')))
1092 break;
1093 do { s++; } while (is_digit(*s)((*s) >= '0' && (*s) <= '9'));
1094 if (*s && strchr("dhms", *s))
1095 s++;
1096 N++;
1097 if (!(i = STRICT(p)(p->pr_strict) ? is_space(*s)((*s) == ' ') : strspn(s, SPACE" " TAB"\011")))
1098 break;
1099 s += i;
1100 }
1101
1102 PARSE_CHECK_REST(p, s, "z")if (*s && (parsing_error(p, "extra data after %s (\"%.04s\")"
, "z", s), 1)) return
;
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])__builtin_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 */
1145static 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"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" "0123456789"
"-!#$%&'*+.^_`{|}~"
, SPACE" " TAB"\011");
1160 if (!s) {
32
Assuming 's' is non-null
33
Taking false branch
1161 parsing_error(p, "invalid key method");
1162 return;
1163 }
1164
1165 {
1166 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;
;
1167 *result = k;
34
Dereference of null pointer (loaded from variable 'result')
1168
1169 /* These are defined as key-sensitive in RFC 4566 */
1170#define MATCH(s, tok)((p->pr_strict) ? su_strmatch((s), (tok)) : su_casematch((
s), (tok)))
\
1171 (STRICT(p)(p->pr_strict) ? su_strmatch((s), (tok)) : su_casematch((s), (tok)))
1172
1173 if (MATCH(s, "clear")((p->pr_strict) ? su_strmatch((s), ("clear")) : su_casematch
((s), ("clear")))
)
1174 k->k_method = sdp_key_clear, k->k_method_name = "clear";
1175 else if (MATCH(s, "base64")((p->pr_strict) ? su_strmatch((s), ("base64")) : su_casematch
((s), ("base64")))
)
1176 k->k_method = sdp_key_base64, k->k_method_name = "base64";
1177 else if (MATCH(s, "uri")((p->pr_strict) ? su_strmatch((s), ("uri")) : su_casematch
((s), ("uri")))
)
1178 k->k_method = sdp_key_uri, k->k_method_name = "uri";
1179 else if (MATCH(s, "prompt")((p->pr_strict) ? su_strmatch((s), ("prompt")) : su_casematch
((s), ("prompt")))
)
1180 k->k_method = sdp_key_prompt, k->k_method_name = "prompt";
1181 else if (!STRICT(p)(p->pr_strict))
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 */
1203static 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((void*)0), *value = NULL((void*)0);
1216
1217 if (!(name = token(&r, ":", TOKEN"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" "0123456789"
"-!#$%&'*+.^_`{|}~"
, SPACE" " TAB"\011"))) {
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")if (*r && (parsing_error(p, "extra data after %s (\"%.04s\")"
, "a", r), 1)) return
;
1226
1227 if (su_casematch(name, "charset")) {
1228 p->pr_sessionpr_output.pru_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)sdp_attribute_t *a = su_salloc(p->pr_home, sizeof(*a)); if
(!a && (parse_alloc_error(p, "sdp_attribute_t"), 1))
return;
;
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 */
1263static 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)sdp_media_t *m = su_salloc(p->pr_home, sizeof(*m)); if (!m
&& (parse_alloc_error(p, "sdp_media_t"), 1)) return;
;
1293
1294 *result = m;
1295
1296 m->m_mode = sdp_sendrecv;
1297
1298 s = token(&r, SPACE" ", TOKEN"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" "0123456789"
"-!#$%&'*+.^_`{|}~"
, NULL((void*)0));
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"\011");
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"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" "0123456789"
"-!#$%&'*+.^_`{|}~"
, SPACE" ");
1331 if (s == NULL((void*)0)) {
1332 parsing_error(p, "m= missing protocol");
1333 return;
1334 }
1335
1336 if (!STRICT(p)(p->pr_strict) && 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)sdp_list_t *l = su_salloc(p->pr_home, sizeof(*l)); if (!l &&
(parse_alloc_error(p, "sdp_list_t"), 1)) return;
;
1353 *fmt = l;
1354 l->l_text = token(&r, SPACE" " TAB"\011", TOKEN"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" "0123456789"
"-!#$%&'*+.^_`{|}~"
, SPACE" " TAB"\011");
1355 fmt = &l->l_next;
1356 }
1357 }
1358}
1359
1360/** Set media type */
1361void 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 */
1392void sdp_media_transport(sdp_media_t *m, char const *s)
1393{
1394 if (m == NULL((void*)0) || s == NULL((void*)0))
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. */
1430int 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){ sizeof(sdp_rtpmap_t), ((void*)0), encoding, rate, (char *)params
, ((void*)0), 1, pt, 0 }
\
1436 { sizeof(sdp_rtpmap_t), NULL((void*)0), encoding, rate, (char *)params, NULL((void*)0), 1, pt, 0 }
1437
1438/* rtpmaps for well-known codecs */
1439static sdp_rtpmap_t const
1440 sdp_rtpmap_pcmu = RTPMAP(0, "PCMU", 8000, 0){ sizeof(sdp_rtpmap_t), ((void*)0), "PCMU", 8000, (char *)0, (
(void*)0), 1, 0, 0 }
,
1441 sdp_rtpmap_1016 = RTPMAP(1, "1016", 8000, 0){ sizeof(sdp_rtpmap_t), ((void*)0), "1016", 8000, (char *)0, (
(void*)0), 1, 1, 0 }
,
1442 sdp_rtpmap_g721 = RTPMAP(2, "G721", 8000, 0){ sizeof(sdp_rtpmap_t), ((void*)0), "G721", 8000, (char *)0, (
(void*)0), 1, 2, 0 }
,
1443 sdp_rtpmap_gsm = RTPMAP(3, "GSM", 8000, 0){ sizeof(sdp_rtpmap_t), ((void*)0), "GSM", 8000, (char *)0, (
(void*)0), 1, 3, 0 }
,
1444 sdp_rtpmap_g723 = RTPMAP(4, "G723", 8000, 0){ sizeof(sdp_rtpmap_t), ((void*)0), "G723", 8000, (char *)0, (
(void*)0), 1, 4, 0 }
,
1445 sdp_rtpmap_dvi4_8000 = RTPMAP(5, "DVI4", 8000, 0){ sizeof(sdp_rtpmap_t), ((void*)0), "DVI4", 8000, (char *)0, (
(void*)0), 1, 5, 0 }
,
1446 sdp_rtpmap_dvi4_16000 = RTPMAP(6, "DVI4", 16000, 0){ sizeof(sdp_rtpmap_t), ((void*)0), "DVI4", 16000, (char *)0,
((void*)0), 1, 6, 0 }
,
1447 sdp_rtpmap_lpc = RTPMAP(7, "LPC", 8000, 0){ sizeof(sdp_rtpmap_t), ((void*)0), "LPC", 8000, (char *)0, (
(void*)0), 1, 7, 0 }
,
1448 sdp_rtpmap_pcma = RTPMAP(8, "PCMA", 8000, 0){ sizeof(sdp_rtpmap_t), ((void*)0), "PCMA", 8000, (char *)0, (
(void*)0), 1, 8, 0 }
,
1449 sdp_rtpmap_g722 = RTPMAP(9, "G722", 8000, 0){ sizeof(sdp_rtpmap_t), ((void*)0), "G722", 8000, (char *)0, (
(void*)0), 1, 9, 0 }
,
1450 sdp_rtpmap_l16_2 = RTPMAP(10, "L16", 44100, "2"){ sizeof(sdp_rtpmap_t), ((void*)0), "L16", 44100, (char *)"2"
, ((void*)0), 1, 10, 0 }
,
1451 sdp_rtpmap_l16 = RTPMAP(11, "L16", 44100, 0){ sizeof(sdp_rtpmap_t), ((void*)0), "L16", 44100, (char *)0, (
(void*)0), 1, 11, 0 }
,
1452 sdp_rtpmap_qcelp = RTPMAP(12, "QCELP", 8000, 0){ sizeof(sdp_rtpmap_t), ((void*)0), "QCELP", 8000, (char *)0,
((void*)0), 1, 12, 0 }
,
1453 sdp_rtpmap_cn = RTPMAP(13, "CN", 8000, 0){ sizeof(sdp_rtpmap_t), ((void*)0), "CN", 8000, (char *)0, ((
void*)0), 1, 13, 0 }
,
1454 sdp_rtpmap_mpa = RTPMAP(14, "MPA", 90000, 0){ sizeof(sdp_rtpmap_t), ((void*)0), "MPA", 90000, (char *)0, (
(void*)0), 1, 14, 0 }
,
1455 sdp_rtpmap_g728 = RTPMAP(15, "G728", 8000, 0){ sizeof(sdp_rtpmap_t), ((void*)0), "G728", 8000, (char *)0, (
(void*)0), 1, 15, 0 }
,
1456 sdp_rtpmap_dvi4_11025 = RTPMAP(16, "DVI4", 11025, 0){ sizeof(sdp_rtpmap_t), ((void*)0), "DVI4", 11025, (char *)0,
((void*)0), 1, 16, 0 }
,
1457 sdp_rtpmap_dvi4_22050 = RTPMAP(17, "DVI4", 22050, 0){ sizeof(sdp_rtpmap_t), ((void*)0), "DVI4", 22050, (char *)0,
((void*)0), 1, 17, 0 }
,
1458 sdp_rtpmap_g729 = RTPMAP(18, "G729", 8000, 0){ sizeof(sdp_rtpmap_t), ((void*)0), "G729", 8000, (char *)0, (
(void*)0), 1, 18, 0 }
,
1459 sdp_rtpmap_reserved_cn = RTPMAP(19, "CN", 8000, 0){ sizeof(sdp_rtpmap_t), ((void*)0), "CN", 8000, (char *)0, ((
void*)0), 1, 19, 0 }
,
1460 /* video codecs */
1461 sdp_rtpmap_celb = RTPMAP(25, "CelB", 90000, 0){ sizeof(sdp_rtpmap_t), ((void*)0), "CelB", 90000, (char *)0,
((void*)0), 1, 25, 0 }
,
1462 sdp_rtpmap_jpeg = RTPMAP(26, "JPEG", 90000, 0){ sizeof(sdp_rtpmap_t), ((void*)0), "JPEG", 90000, (char *)0,
((void*)0), 1, 26, 0 }
,
1463 sdp_rtpmap_nv = RTPMAP(28, "nv", 90000, 0){ sizeof(sdp_rtpmap_t), ((void*)0), "nv", 90000, (char *)0, (
(void*)0), 1, 28, 0 }
,
1464 sdp_rtpmap_h261 = RTPMAP(31, "H261", 90000, 0){ sizeof(sdp_rtpmap_t), ((void*)0), "H261", 90000, (char *)0,
((void*)0), 1, 31, 0 }
,
1465 sdp_rtpmap_mpv = RTPMAP(32, "MPV", 90000, 0){ sizeof(sdp_rtpmap_t), ((void*)0), "MPV", 90000, (char *)0, (
(void*)0), 1, 32, 0 }
,
1466 sdp_rtpmap_mp2t = RTPMAP(33, "MP2T", 90000, 0){ sizeof(sdp_rtpmap_t), ((void*)0), "MP2T", 90000, (char *)0,
((void*)0), 1, 33, 0 }
,
1467 sdp_rtpmap_h263 = RTPMAP(34, "H263", 90000, 0){ sizeof(sdp_rtpmap_t), ((void*)0), "H263", 90000, (char *)0,
((void*)0), 1, 34, 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 */
1476sdp_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((void*)0), /* 20 */
1499 NULL((void*)0), /* 21 */
1500 NULL((void*)0), /* 22 */
1501 NULL((void*)0), /* 23 */
1502 NULL((void*)0), /* 24 */
1503 &sdp_rtpmap_celb, /* 25 */
1504 &sdp_rtpmap_jpeg, /* 26 */
1505 NULL((void*)0), /* 27 */
1506 &sdp_rtpmap_nv, /* 28 */
1507 NULL((void*)0), /* 29 */
1508 NULL((void*)0), /* 30 */
1509 &sdp_rtpmap_h261, /* 31 */
1510 &sdp_rtpmap_mpv, /* 32 */
1511 &sdp_rtpmap_mp2t, /* 33 */
1512 &sdp_rtpmap_h263, /* 34 */
1513 NULL((void*)0),
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 */
1524static 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)sdp_rtpmap_t *rm = su_salloc(p->pr_home, sizeof(*rm)); if (
!rm && (parse_alloc_error(p, "sdp_rtpmap_t"), 1)) return
;
;
1531
1532 assert(0 <= value && value < 128)((void) sizeof ((0 <= value && value < 128) ? 1
: 0), __extension__ ({ if (0 <= value && value <
128) ; else __assert_fail ("0 <= value && value < 128"
, "sdp_parse.c", 1532, __extension__ __PRETTY_FUNCTION__); })
)
;
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)sdp_rtpmap_t *rm = su_salloc(p->pr_home, sizeof(*rm)); if (
!rm && (parse_alloc_error(p, "sdp_rtpmap_t"), 1)) return
;
;
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 */
1577static 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((void*)0), *value = NULL((void*)0);
1594 int n;
1595
1596 if (!(name = token(&r, ":", TOKEN"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" "0123456789"
"-!#$%&'*+.^_`{|}~"
, SPACE" " TAB"\011"))) {
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")if (*r && (parsing_error(p, "extra data after %s (\"%.04s\")"
, "a", r), 1)) return
;
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)sdp_attribute_t *a = su_salloc(p->pr_home, sizeof(*a)); if
(!a && (parse_alloc_error(p, "sdp_attribute_t"), 1))
return;
;
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 */
1646static 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)(p->pr_strict);
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"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" "0123456789"
"-!#$%&'*+.^_`{|}~"
, NULL((void*)0));
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 */
1697static 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)(p->pr_strict);
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 */
1736static 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((void*)0);
25
'm' initialized to a null pointer value
1744 sdp_connection_t **connections = NULL((void*)0);
1745 sdp_bandwidth_t **bandwidths = NULL((void*)0);
1746 sdp_attribute_t **attributes = NULL((void*)0);
1747
1748 if (!STRICT(p)(p->pr_strict))
26
Taking true branch
1749 strip = SPACE" " TAB"\011"; /* skip initial whitespace */
1750 else
1751 strip = "";
1752
1753 for (;
27
Loop condition is true. Entering loop body
1754 record && p->pr_ok;
1755 record = next(&message, CRLF"\015\012", strip)) {
1756 char field = record[0];
1757
1758 rest = record + 2; rest += strspn(rest, strip);
1759
1760 if (record[1] == '=') switch (field) {
28
Taking true branch
29
Control jumps to 'case 107:' at line 1777
1761 case 'c':
1762 assert(connections)((void) sizeof ((connections) ? 1 : 0), __extension__ ({ if (
connections) ; else __assert_fail ("connections", "sdp_parse.c"
, 1762, __extension__ __PRETTY_FUNCTION__); }))
;
1763 parse_connection(p, rest, connections);
1764 connections = &(*connections)->c_next;
1765 break;
1766
1767 case 'b':
1768 assert(bandwidths)((void) sizeof ((bandwidths) ? 1 : 0), __extension__ ({ if (bandwidths
) ; else __assert_fail ("bandwidths", "sdp_parse.c", 1768, __extension__
__PRETTY_FUNCTION__); }))
;
1769 parse_bandwidth(p, rest, bandwidths);
1770 bandwidths = &(*bandwidths)->b_next;
1771 break;
1772
1773 case 'i':
1774 parse_information(p, rest, &m->m_information);
1775 break;
1776
1777 case 'k':
1778 parse_key(p, rest, &m->m_key);
30
Passing null pointer value via 3rd parameter 'result'
31
Calling 'parse_key'
1779 break;
1780
1781 case 'a':
1782 assert(attributes)((void) sizeof ((attributes) ? 1 : 0), __extension__ ({ if (attributes
) ; else __assert_fail ("attributes", "sdp_parse.c", 1782, __extension__
__PRETTY_FUNCTION__); }))
;
1783 parse_media_attr(p, rest, m, attributes);
1784 if (*attributes)
1785 attributes = &(*attributes)->a_next;
1786 break;
1787
1788 case 'm':
1789 parse_media(p, rest, medias);
1790 m = *medias;
1791 if (m) {
1792 m->m_mode = p->pr_session_mode;
1793 medias = &m->m_next;
1794 connections = &m->m_connections;
1795 bandwidths = &m->m_bandwidths;
1796 attributes = &m->m_attributes;
1797 }
1798 }
1799 }
1800}
1801
1802static void parse_text_list(sdp_parser_t *p, char *r, sdp_list_t **result)
1803{
1804 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;
;
1805
1806 *result = l;
1807
1808 l->l_text = r;
1809}
1810
1811/*
1812 * parse_ul: parse an unsigned long
1813 */
1814static int parse_ul(sdp_parser_t *p, char **r,
1815 unsigned long *result, unsigned long max)
1816{
1817 char *ul = *r;
1818
1819 ul += strspn(ul, SPACE" " TAB"\011");
1820
1821 *result = strtoul(ul, r, 10);
1822 if (ul != *r && !(max && max <= *result)) {
1823 *r += strspn(*r, SPACE" " TAB"\011");
1824 return 0;
1825 }
1826
1827 return -1;
1828}
1829
1830#if !HAVE_STRTOULL1
1831#if !((defined(WIN32) || defined(_WIN32)) && (_MSC_VER >= 1800))
1832unsigned long long strtoull(char const *string, char **return_end, int base);
1833#endif
1834#endif
1835
1836/*
1837 * parse_ull: parse an unsigned long long
1838 */
1839static int parse_ull(sdp_parser_t *p, char **r,
1840 uint64_t *result, uint64_t max)
1841{
1842 unsigned long long ull;
1843
1844 char *s = *r;
1845
1846 s += strspn(s, SPACE" " TAB"\011");
1847
1848 ull = strtoull(s, r, 10);
1849
1850 if (s != *r && !(max && max <= ull)) {
1851 *result = (uint64_t)ull;
1852 *r += strspn(*r, SPACE" " TAB"\011");
1853 return 0;
1854 }
1855
1856 return -1;
1857}
1858
1859static char *token(char **message,
1860 const char *sep,
1861 const char *legal,
1862 const char *strip)
1863{
1864 size_t n;
1865 char *retval = *message;
1866
1867 if (strip)
1868 retval += strspn(retval, strip);
1869
1870 if (legal)
1871 n = strspn(retval, legal);
1872 else
1873 n = strcspn(retval, sep);
1874
1875 if (n == 0)
1876 return NULL((void*)0);
1877
1878 if (retval[n]) {
1879 retval[n++] = '\0';
1880 n += strspn(retval + n, sep);
1881 }
1882
1883 *message = retval + n;
1884
1885 if (*retval == '\0')
1886 return NULL((void*)0);
1887
1888 return retval;
1889}
1890
1891static char *next(char **message, const char *sep, const char *strip)
1892{
1893 size_t n;
1894 char *retval = *message;
1895
1896 if (strip[0])
1897 retval += strspn(retval, strip);
1898
1899 n = strcspn(retval, sep);
1900
1901 if (n == 0)
1902 return NULL((void*)0);
1903
1904 if (retval[n]) {
1905 retval[n++] = '\0';
1906 n += strspn(retval + n, sep);
1907 }
1908
1909 *message = retval + n;
1910
1911 if (*retval == '\0')
1912 return NULL((void*)0);
1913
1914 return retval;
1915}
1916
1917static int parsing_error(sdp_parser_t *p, char const *fmt, ...)
1918{
1919 va_list ap;
1920 va_start(ap, fmt)__builtin_va_start(ap, fmt);
1921
1922 memset(p->pr_errorpr_output.pru_error, 0, sizeof(p->pr_errorpr_output.pru_error));
1923 vsnprintf(p->pr_errorpr_output.pru_error, sizeof(p->pr_errorpr_output.pru_error), fmt, ap);
1924 va_end(ap)__builtin_va_end(ap);
1925
1926 p->pr_ok = 0;
1927
1928 return -1;
1929}
1930
1931static void parse_alloc_error(sdp_parser_t *p, const char *typename)
1932{
1933 parsing_error(p, "memory exhausted (while allocating memory for %s)",
1934 typename);
1935}