Line data Source code
1 : /* This Source Code Form is subject to the terms of the Mozilla Public
2 : * License, v. 2.0. If a copy of the MPL was not distributed with this
3 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4 :
5 : #include <errno.h>
6 : #include <limits.h>
7 : #include <stdio.h>
8 :
9 : #include "plstr.h"
10 : #include "sdp_os_defs.h"
11 : #include "sdp.h"
12 : #include "sdp_private.h"
13 : #include "sdp_base64.h"
14 :
15 : #include "CSFLog.h"
16 :
17 : static const char* logTag = "sdp_attr";
18 :
19 : /*
20 : * Macro for sdp_build_attr_fmtp
21 : * Adds name-value pair where value is char*
22 : */
23 : #define FMTP_BUILD_STRING(condition, name, value) \
24 : if ((condition)) { \
25 : sdp_append_name_and_string(fs, (name), (value), semicolon); \
26 : semicolon = TRUE; \
27 : }
28 :
29 : /*
30 : * Macro for sdp_build_attr_fmtp
31 : * Adds name-value pair where value is unsigned
32 : */
33 : #define FMTP_BUILD_UNSIGNED(condition, name, value) \
34 : if ((condition)) { \
35 : sdp_append_name_and_unsigned(fs, (name), (value), semicolon); \
36 : semicolon = TRUE; \
37 : }
38 :
39 : /*
40 : * Macro for sdp_build_attr_fmtp
41 : * Adds flag string on condition
42 : */
43 : #define FMTP_BUILD_FLAG(condition, name) \
44 : if ((condition)) { \
45 : if (semicolon) { \
46 : flex_string_append(fs, ";"); \
47 : } \
48 : flex_string_append(fs, name); \
49 : semicolon = TRUE; \
50 : }
51 :
52 0 : static int find_token_enum(const char *attr_name,
53 : sdp_t *sdp_p,
54 : const char **ptr,
55 : const sdp_namearray_t *types,
56 : int type_count,
57 : int unknown_value)
58 : {
59 0 : sdp_result_e result = SDP_SUCCESS;
60 : char tmp[SDP_MAX_STRING_LEN+1];
61 : int i;
62 :
63 0 : *ptr = sdp_getnextstrtok(*ptr, tmp, sizeof(tmp), " \t", &result);
64 0 : if (result != SDP_SUCCESS) {
65 0 : sdp_parse_error(sdp_p,
66 0 : "%s Warning: problem parsing %s", sdp_p->debug_str, attr_name);
67 0 : sdp_p->conf_p->num_invalid_param++;
68 0 : return -1;
69 : }
70 :
71 0 : for (i=0; i < type_count; i++) {
72 0 : if (!cpr_strncasecmp(tmp, types[i].name, types[i].strlen)) {
73 0 : return i;
74 : }
75 : }
76 0 : return unknown_value;
77 : }
78 :
79 : /*
80 : * Helper function for adding nv-pair where value is string.
81 : */
82 0 : static void sdp_append_name_and_string(flex_string *fs,
83 : const char *name,
84 : const char *value,
85 : tinybool semicolon)
86 : {
87 0 : flex_string_sprintf(fs, "%s%s=%s",
88 : semicolon ? ";" : "",
89 : name,
90 : value);
91 0 : }
92 :
93 : /*
94 : * Helper function for adding nv-pair where value is unsigned.
95 : */
96 0 : static void sdp_append_name_and_unsigned(flex_string *fs,
97 : const char *name,
98 : unsigned int value,
99 : tinybool semicolon)
100 : {
101 0 : flex_string_sprintf(fs, "%s%s=%u",
102 : semicolon ? ";" : "",
103 : name,
104 : value);
105 0 : }
106 :
107 : /* Function: sdp_parse_attribute
108 : * Description: Figure out the type of attribute and call the appropriate
109 : * parsing routine. If parsing errors are encountered,
110 : * warnings will be printed and the attribute will be ignored.
111 : * Unrecognized/invalid attributes do not cause overall parsing
112 : * errors. All errors detected are noted as warnings.
113 : * Parameters: sdp_p The SDP handle returned by sdp_init_description.
114 : * level The level to check for the attribute.
115 : * ptr Pointer to the attribute string to parse.
116 : */
117 0 : sdp_result_e sdp_parse_attribute (sdp_t *sdp_p, uint16_t level, const char *ptr)
118 : {
119 : int i;
120 0 : uint8_t xcpar_flag = FALSE;
121 : sdp_result_e result;
122 0 : sdp_mca_t *mca_p=NULL;
123 : sdp_attr_t *attr_p;
124 : sdp_attr_t *next_attr_p;
125 0 : sdp_attr_t *prev_attr_p = NULL;
126 : char tmp[SDP_MAX_STRING_LEN];
127 :
128 : /* Validate the level */
129 0 : if (level != SDP_SESSION_LEVEL) {
130 0 : mca_p = sdp_find_media_level(sdp_p, level);
131 0 : if (mca_p == NULL) {
132 0 : return (SDP_FAILURE);
133 : }
134 : }
135 :
136 : /* Find the attribute type. */
137 0 : ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), ": \t", &result);
138 0 : if (ptr == NULL) {
139 0 : sdp_parse_error(sdp_p,
140 0 : "%s No attribute type specified, parse failed.", sdp_p->debug_str);
141 0 : sdp_p->conf_p->num_invalid_param++;
142 0 : return (SDP_INVALID_PARAMETER);
143 : }
144 0 : if (ptr[0] == ':') {
145 : /* Skip the ':' char for parsing attribute parameters. */
146 0 : ptr++;
147 : }
148 0 : if (result != SDP_SUCCESS) {
149 0 : sdp_parse_error(sdp_p,
150 0 : "%s No attribute type specified, parse failed.", sdp_p->debug_str);
151 0 : sdp_p->conf_p->num_invalid_param++;
152 0 : return (SDP_INVALID_PARAMETER);
153 : }
154 :
155 0 : attr_p = (sdp_attr_t *)SDP_MALLOC(sizeof(sdp_attr_t));
156 0 : if (attr_p == NULL) {
157 0 : sdp_p->conf_p->num_no_resource++;
158 0 : return (SDP_NO_RESOURCE);
159 : }
160 0 : attr_p->line_number = sdp_p->parse_line;
161 0 : attr_p->type = SDP_ATTR_INVALID;
162 0 : attr_p->next_p = NULL;
163 0 : for (i=0; i < SDP_MAX_ATTR_TYPES; i++) {
164 0 : if (cpr_strncasecmp(tmp, sdp_attr[i].name, sdp_attr[i].strlen) == 0) {
165 0 : attr_p->type = (sdp_attr_e)i;
166 0 : break;
167 : }
168 : }
169 0 : if (attr_p->type == SDP_ATTR_INVALID) {
170 0 : sdp_parse_error(sdp_p,
171 : "%s Warning: Unrecognized attribute (%s) ",
172 0 : sdp_p->debug_str, tmp);
173 0 : sdp_free_attr(attr_p);
174 0 : return (SDP_SUCCESS);
175 : }
176 :
177 : /* If this is an X-cpar or cpar attribute, set the flag. The attribute
178 : * type will be changed by the parse. */
179 0 : if ((attr_p->type == SDP_ATTR_X_CPAR) ||
180 0 : (attr_p->type == SDP_ATTR_CPAR)) {
181 0 : xcpar_flag = TRUE;
182 : }
183 :
184 : /* Parse the attribute. */
185 0 : result = sdp_attr[attr_p->type].parse_func(sdp_p, attr_p, ptr);
186 0 : if (result != SDP_SUCCESS) {
187 0 : sdp_free_attr(attr_p);
188 : /* Return success so the parse won't fail. We don't want to
189 : * fail on errors with attributes but just ignore them.
190 : */
191 0 : return (SDP_SUCCESS);
192 : }
193 :
194 : /* If this was an X-cpar/cpar attribute, it was hooked into the X-cap/cdsc
195 : * structure, so we're finished.
196 : */
197 0 : if (xcpar_flag == TRUE) {
198 0 : return (result);
199 : }
200 :
201 : /* Add the attribute in the appropriate place. */
202 0 : if (level == SDP_SESSION_LEVEL) {
203 0 : for (next_attr_p = sdp_p->sess_attrs_p; next_attr_p != NULL;
204 0 : prev_attr_p = next_attr_p,
205 0 : next_attr_p = next_attr_p->next_p) {
206 : ; /* Empty for */
207 : }
208 0 : if (prev_attr_p == NULL) {
209 0 : sdp_p->sess_attrs_p = attr_p;
210 : } else {
211 0 : prev_attr_p->next_p = attr_p;
212 : }
213 : } else {
214 0 : for (next_attr_p = mca_p->media_attrs_p; next_attr_p != NULL;
215 0 : prev_attr_p = next_attr_p,
216 0 : next_attr_p = next_attr_p->next_p) {
217 : ; /* Empty for */
218 : }
219 0 : if (prev_attr_p == NULL) {
220 0 : mca_p->media_attrs_p = attr_p;
221 : } else {
222 0 : prev_attr_p->next_p = attr_p;
223 : }
224 : }
225 :
226 0 : return (result);
227 : }
228 :
229 : /* Build all of the attributes defined for the specified level. */
230 0 : sdp_result_e sdp_build_attribute (sdp_t *sdp_p, uint16_t level, flex_string *fs)
231 : {
232 : sdp_attr_t *attr_p;
233 0 : sdp_mca_t *mca_p=NULL;
234 : sdp_result_e result;
235 :
236 0 : if (level == SDP_SESSION_LEVEL) {
237 0 : attr_p = sdp_p->sess_attrs_p;
238 : } else {
239 0 : mca_p = sdp_find_media_level(sdp_p, level);
240 0 : if (mca_p == NULL) {
241 0 : return (SDP_FAILURE);
242 : }
243 0 : attr_p = mca_p->media_attrs_p;
244 : }
245 : /* Re-initialize the current capability number for this new level. */
246 0 : sdp_p->cur_cap_num = 1;
247 :
248 : /* Build all of the attributes for this level. Note that if there
249 : * is a problem building an attribute, we don't fail but just ignore it.*/
250 0 : while (attr_p != NULL) {
251 0 : if (attr_p->type >= SDP_MAX_ATTR_TYPES) {
252 0 : if (sdp_p->debug_flag[SDP_DEBUG_WARNINGS]) {
253 0 : CSFLogDebug(logTag, "%s Invalid attribute type to build (%u)",
254 : sdp_p->debug_str, (unsigned)attr_p->type);
255 : }
256 : } else {
257 0 : result = sdp_attr[attr_p->type].build_func(sdp_p, attr_p, fs);
258 :
259 0 : if (result != SDP_SUCCESS) {
260 0 : CSFLogError(logTag, "%s error building attribute %d", __FUNCTION__, result);
261 0 : return result;
262 : }
263 :
264 0 : if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
265 0 : SDP_PRINT("%s Built a=%s attribute line", sdp_p->debug_str,
266 : sdp_get_attr_name(attr_p->type));
267 : }
268 : }
269 0 : attr_p = attr_p->next_p;
270 : }
271 :
272 0 : return SDP_SUCCESS;
273 : }
274 :
275 0 : sdp_result_e sdp_parse_attr_simple_string (sdp_t *sdp_p, sdp_attr_t *attr_p,
276 : const char *ptr)
277 : {
278 : sdp_result_e result;
279 :
280 0 : ptr = sdp_getnextstrtok(ptr, attr_p->attr.string_val,
281 : sizeof(attr_p->attr.string_val), " \t", &result);
282 :
283 0 : if (result != SDP_SUCCESS) {
284 0 : sdp_parse_error(sdp_p,
285 : "%s Warning: No string token found for %s attribute",
286 0 : sdp_p->debug_str, sdp_get_attr_name(attr_p->type));
287 0 : sdp_p->conf_p->num_invalid_param++;
288 0 : return (SDP_INVALID_PARAMETER);
289 : } else {
290 0 : if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
291 0 : SDP_PRINT("%s Parsed a=%s, %s", sdp_p->debug_str,
292 : sdp_get_attr_name(attr_p->type),
293 : attr_p->attr.string_val);
294 : }
295 0 : return (SDP_SUCCESS);
296 : }
297 : }
298 :
299 0 : sdp_result_e sdp_build_attr_simple_string (sdp_t *sdp_p, sdp_attr_t *attr_p,
300 : flex_string *fs)
301 : {
302 0 : flex_string_sprintf(fs, "a=%s:%s\r\n", sdp_attr[attr_p->type].name,
303 0 : attr_p->attr.string_val);
304 :
305 0 : return SDP_SUCCESS;
306 : }
307 :
308 0 : sdp_result_e sdp_parse_attr_simple_u32 (sdp_t *sdp_p, sdp_attr_t *attr_p,
309 : const char *ptr)
310 : {
311 : sdp_result_e result;
312 :
313 0 : attr_p->attr.u32_val = sdp_getnextnumtok(ptr, &ptr, " \t", &result);
314 :
315 0 : if (result != SDP_SUCCESS) {
316 0 : sdp_parse_error(sdp_p,
317 : "%s Warning: Numeric token for %s attribute not found",
318 0 : sdp_p->debug_str, sdp_get_attr_name(attr_p->type));
319 0 : sdp_p->conf_p->num_invalid_param++;
320 0 : return (SDP_INVALID_PARAMETER);
321 : } else {
322 0 : if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
323 0 : SDP_PRINT("%s Parsed a=%s, %u", sdp_p->debug_str,
324 : sdp_get_attr_name(attr_p->type), attr_p->attr.u32_val);
325 : }
326 0 : return (SDP_SUCCESS);
327 : }
328 : }
329 :
330 0 : sdp_result_e sdp_build_attr_simple_u32 (sdp_t *sdp_p, sdp_attr_t *attr_p,
331 : flex_string *fs)
332 : {
333 0 : flex_string_sprintf(fs, "a=%s:%u\r\n", sdp_attr[attr_p->type].name,
334 : attr_p->attr.u32_val);
335 :
336 0 : return SDP_SUCCESS;
337 : }
338 :
339 0 : sdp_result_e sdp_parse_attr_simple_bool (sdp_t *sdp_p, sdp_attr_t *attr_p,
340 : const char *ptr)
341 : {
342 : sdp_result_e result;
343 :
344 0 : if (sdp_getnextnumtok(ptr, &ptr, " \t", &result) == 0) {
345 0 : attr_p->attr.boolean_val = FALSE;
346 : } else {
347 0 : attr_p->attr.boolean_val= TRUE;
348 : }
349 :
350 0 : if (result != SDP_SUCCESS) {
351 0 : sdp_parse_error(sdp_p,
352 : "%s Warning: Boolean token for %s attribute not found",
353 0 : sdp_p->debug_str, sdp_get_attr_name(attr_p->type));
354 0 : sdp_p->conf_p->num_invalid_param++;
355 0 : return (SDP_INVALID_PARAMETER);
356 : } else {
357 0 : if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
358 0 : if (attr_p->attr.boolean_val) {
359 0 : SDP_PRINT("%s Parsed a=%s, boolean is TRUE", sdp_p->debug_str,
360 : sdp_get_attr_name(attr_p->type));
361 : } else {
362 0 : SDP_PRINT("%s Parsed a=%s, boolean is FALSE", sdp_p->debug_str,
363 : sdp_get_attr_name(attr_p->type));
364 : }
365 : }
366 0 : return (SDP_SUCCESS);
367 : }
368 : }
369 :
370 0 : sdp_result_e sdp_build_attr_simple_bool (sdp_t *sdp_p, sdp_attr_t *attr_p,
371 : flex_string *fs)
372 : {
373 0 : flex_string_sprintf(fs, "a=%s:%s\r\n", sdp_attr[attr_p->type].name,
374 0 : attr_p->attr.boolean_val ? "1" : "0");
375 :
376 0 : return SDP_SUCCESS;
377 : }
378 :
379 : /*
380 : * sdp_parse_attr_maxprate
381 : *
382 : * This function parses maxprate attribute lines. The ABNF for this a=
383 : * line is:
384 : * max-p-rate-def = "a" "=" "maxprate" ":" packet-rate CRLF
385 : * packet-rate = 1*DIGIT ["." 1*DIGIT]
386 : *
387 : * Returns:
388 : * SDP_INVALID_PARAMETER - If we are unable to parse the string OR if
389 : * packet-rate is not in the right format as per
390 : * the ABNF.
391 : *
392 : * SDP_SUCCESS - If we are able to successfully parse the a= line.
393 : */
394 0 : sdp_result_e sdp_parse_attr_maxprate (sdp_t *sdp_p, sdp_attr_t *attr_p,
395 : const char *ptr)
396 : {
397 : sdp_result_e result;
398 :
399 0 : ptr = sdp_getnextstrtok(ptr, attr_p->attr.string_val,
400 : sizeof(attr_p->attr.string_val), " \t", &result);
401 :
402 0 : if (result != SDP_SUCCESS) {
403 0 : sdp_parse_error(sdp_p,
404 : "%s Warning: No string token found for %s attribute",
405 0 : sdp_p->debug_str, sdp_get_attr_name(attr_p->type));
406 0 : sdp_p->conf_p->num_invalid_param++;
407 0 : return (SDP_INVALID_PARAMETER);
408 : } else {
409 0 : if (!sdp_validate_maxprate(attr_p->attr.string_val)) {
410 0 : sdp_parse_error(sdp_p,
411 : "%s is not a valid maxprate value.",
412 0 : attr_p->attr.string_val);
413 0 : sdp_p->conf_p->num_invalid_param++;
414 0 : return (SDP_INVALID_PARAMETER);
415 : }
416 :
417 0 : if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
418 0 : SDP_PRINT("%s Parsed a=%s, %s", sdp_p->debug_str,
419 : sdp_get_attr_name(attr_p->type),
420 : attr_p->attr.string_val);
421 : }
422 0 : return (SDP_SUCCESS);
423 : }
424 : }
425 :
426 : /*
427 : * sdp_attr_fmtp_no_value
428 : * Helper function for sending the warning when a parameter value is
429 : * missing.
430 : *
431 : */
432 0 : static void sdp_attr_fmtp_no_value(sdp_t *sdp, const char *param_name)
433 : {
434 0 : sdp_parse_error(sdp,
435 : "%s Warning: No %s value specified for fmtp attribute",
436 0 : sdp->debug_str, param_name);
437 0 : sdp->conf_p->num_invalid_param++;
438 0 : }
439 :
440 : /*
441 : * sdp_attr_fmtp_invalid_value
442 : * Helper function for sending the warning when a parameter value is
443 : * incorrect.
444 : *
445 : */
446 0 : static void sdp_attr_fmtp_invalid_value(sdp_t *sdp, const char *param_name,
447 : const char* param_value)
448 : {
449 0 : sdp_parse_error(sdp,
450 : "%s Warning: Invalid %s: %s specified for fmtp attribute",
451 0 : sdp->debug_str, param_name, param_value);
452 0 : sdp->conf_p->num_invalid_param++;
453 0 : }
454 :
455 : /*
456 : * sdp_verify_attr_fmtp_telephone_event
457 : * Helper function for verifying the telephone-event fmtp format
458 : */
459 0 : static sdp_result_e sdp_verify_attr_fmtp_telephone_event(char *fmtpVal)
460 : {
461 0 : size_t len = fmtpVal ? strlen(fmtpVal) : 0;
462 :
463 : // make sure the basics are good:
464 : // - at least 1 character
465 : // - no illegal chars
466 : // - first char is a number
467 0 : if (len < 1
468 0 : || strspn(fmtpVal, "0123456789,-") != len
469 0 : || PL_strstr(fmtpVal, ",,")
470 0 : || fmtpVal[len-1] == ','
471 0 : || !('0' <= fmtpVal[0] && fmtpVal[0] <= '9')) {
472 0 : return SDP_INVALID_PARAMETER;
473 : }
474 :
475 : // Now that we've passed the basic sanity test, copy the string so we
476 : // can tokenize and check the format of the tokens without disturbing
477 : // the input string.
478 : char dtmf_tones[SDP_MAX_STRING_LEN+1];
479 0 : PL_strncpyz(dtmf_tones, fmtpVal, sizeof(dtmf_tones));
480 :
481 : char *strtok_state;
482 0 : char *temp = PL_strtok_r(dtmf_tones, ",", &strtok_state);
483 :
484 0 : while (temp != NULL) {
485 0 : len = strlen(temp);
486 0 : if (len > 5) {
487 : // an example of a max size token is "11-15", so if the
488 : // token is longer than 5 it is bad
489 0 : return SDP_INVALID_PARAMETER;
490 : }
491 :
492 : // case where we have 1 or 2 characters, example 4 or 23
493 0 : if (len < 3 && strspn(temp, "0123456789") != len) {
494 0 : return SDP_INVALID_PARAMETER;
495 0 : } else if (len >= 3) {
496 : // case where we have 3-5 characters, ex 3-5, 2-33, or 10-20
497 0 : sdp_result_e result1 = SDP_SUCCESS;
498 0 : sdp_result_e result2 = SDP_SUCCESS;
499 : uint8_t low_val;
500 : uint8_t high_val;
501 0 : low_val = (uint8_t)sdp_getnextnumtok(temp, (const char **)&temp,
502 : "-", &result1);
503 0 : high_val = (uint8_t)sdp_getnextnumtok(temp, (const char **)&temp,
504 : "-", &result2);
505 0 : if (temp[0] // we don't want to find a second hyphen
506 0 : || result1 != SDP_SUCCESS
507 0 : || result2 != SDP_SUCCESS) {
508 0 : return SDP_INVALID_PARAMETER;
509 : }
510 :
511 0 : if (low_val > 99
512 0 : || high_val > 99
513 0 : || high_val <= low_val) {
514 0 : return SDP_INVALID_PARAMETER;
515 : }
516 : }
517 :
518 0 : temp=PL_strtok_r(NULL, ",", &strtok_state);
519 : }
520 :
521 0 : return SDP_SUCCESS;
522 : }
523 :
524 : /* Note: The fmtp attribute formats currently handled are:
525 : * fmtp:<payload type> <event>,<event>...
526 : * fmtp:<payload_type> [annexa=yes/no] [annexb=yes/no] [bitrate=<value>]
527 : * [QCIF =<value>] [CIF =<value>] [MaxBR = <value>] one or more
528 : * Other FMTP params as per H.263, H.263+, H.264 codec support.
529 : * Note -"value" is a numeric value > 0 and each event is a
530 : * single number or a range separated by a '-'.
531 : * Example: fmtp:101 1,3-15,20
532 : * Video codecs have annexes that can be listed in the following legal formats:
533 : * a) a=fmtp:34 param1=token;D;I;J;K=1;N=2;P=1,3
534 : * b) a=fmtp:34 param1=token;D;I;J;K=1;N=2;P=1,3;T
535 : * c) a=fmtp:34 param1=token;D;I;J
536 : *
537 : */
538 0 : sdp_result_e sdp_get_fmtp_tok(sdp_t *sdp_p,
539 : const char** fmtp_ptr,
540 : const char* fmtp_name,
541 : char* buf,
542 : size_t buf_size,
543 : char** tok)
544 : {
545 0 : sdp_result_e result1 = SDP_SUCCESS;
546 :
547 0 : *fmtp_ptr = sdp_getnextstrtok(*fmtp_ptr, buf, buf_size, "; \t", &result1);
548 0 : if (result1 != SDP_SUCCESS) {
549 0 : *fmtp_ptr = sdp_getnextstrtok(*fmtp_ptr, buf, buf_size, " \t", &result1);
550 0 : if (result1 != SDP_SUCCESS) {
551 0 : sdp_attr_fmtp_no_value(sdp_p, fmtp_name);
552 0 : return SDP_INVALID_PARAMETER;
553 : }
554 : }
555 0 : *tok = buf;
556 0 : (*tok)++;
557 :
558 0 : return SDP_SUCCESS;
559 : }
560 :
561 0 : sdp_result_e sdp_get_fmtp_tok_val(sdp_t *sdp_p,
562 : const char** fmtp_ptr,
563 : const char* fmtp_name,
564 : char* buf,
565 : size_t buf_size,
566 : char** tok,
567 : unsigned long* strtoul_result,
568 : unsigned long illegal_value,
569 : unsigned long min_limit,
570 : unsigned long max_limit)
571 : {
572 0 : sdp_result_e result1 = SDP_SUCCESS;
573 : unsigned long value;
574 : char* strtoul_end;
575 :
576 0 : result1 = sdp_get_fmtp_tok(sdp_p, fmtp_ptr, fmtp_name, buf, buf_size, tok);
577 0 : if (result1 != SDP_SUCCESS) return result1;
578 :
579 0 : errno = 0;
580 0 : value = strtoul(*tok, &strtoul_end, 10);
581 :
582 0 : if (errno
583 0 : || (*tok == strtoul_end)
584 0 : || (illegal_value != ULONG_MAX && value == illegal_value)
585 0 : || (min_limit != ULONG_MAX && value < min_limit)
586 0 : || (max_limit != ULONG_MAX && value > max_limit)) {
587 0 : sdp_attr_fmtp_invalid_value(sdp_p, fmtp_name, *tok);
588 0 : return SDP_INVALID_PARAMETER;
589 : }
590 0 : *strtoul_result = value;
591 :
592 0 : return SDP_SUCCESS;
593 : }
594 :
595 0 : sdp_result_e sdp_parse_attr_fmtp (sdp_t *sdp_p, sdp_attr_t *attr_p,
596 : const char *ptr)
597 : {
598 : uint16_t i;
599 : uint32_t mapword;
600 : uint32_t bmap;
601 : uint8_t low_val;
602 : uint8_t high_val;
603 : const char *ptr2;
604 : const char *fmtp_ptr;
605 0 : sdp_result_e result1 = SDP_SUCCESS;
606 0 : sdp_result_e result2 = SDP_SUCCESS;
607 0 : tinybool done = FALSE;
608 0 : tinybool codec_info_found = FALSE;
609 : sdp_fmtp_t *fmtp_p;
610 : char tmp[SDP_MAX_STRING_LEN];
611 : char *src_ptr;
612 0 : char *temp_ptr = NULL;
613 0 : char *tok=NULL;
614 0 : char *temp=NULL;
615 0 : uint16_t custom_x=0;
616 0 : uint16_t custom_y=0;
617 0 : uint16_t custom_mpi=0;
618 0 : uint16_t par_height=0;
619 0 : uint16_t par_width=0;
620 0 : uint16_t cpcf=0;
621 0 : uint16_t iter=0;
622 :
623 0 : ulong l_val = 0;
624 : char* strtok_state;
625 : unsigned long strtoul_result;
626 : char* strtoul_end;
627 :
628 : /* Find the payload type number. */
629 0 : attr_p->attr.fmtp.payload_num = (uint16_t)sdp_getnextnumtok(ptr, &ptr,
630 : " \t", &result1);
631 0 : if (result1 != SDP_SUCCESS) {
632 0 : sdp_attr_fmtp_no_value(sdp_p, "payload type");
633 0 : return SDP_INVALID_PARAMETER;
634 : }
635 0 : fmtp_p = &(attr_p->attr.fmtp);
636 0 : fmtp_p->fmtp_format = SDP_FMTP_UNKNOWN_TYPE;
637 0 : fmtp_p->parameter_add = 1;
638 0 : fmtp_p->flag = 0;
639 :
640 : /*
641 : * set default value of packetization mode and level-asymmetry-allowed. If
642 : * remote sdp does not specify any value for these two parameters, then the
643 : * default value will be assumed for remote sdp. If remote sdp does specify
644 : * any value for these parameters, then default value will be overridden.
645 : */
646 0 : fmtp_p->packetization_mode = SDP_DEFAULT_PACKETIZATION_MODE_VALUE;
647 0 : fmtp_p->level_asymmetry_allowed = SDP_DEFAULT_LEVEL_ASYMMETRY_ALLOWED_VALUE;
648 :
649 0 : temp_ptr = cpr_strdup(ptr);
650 0 : if (temp_ptr == NULL) {
651 0 : return (SDP_FAILURE);
652 : }
653 0 : fmtp_ptr = src_ptr = temp_ptr;
654 :
655 0 : src_ptr = temp_ptr;
656 0 : while (!done) {
657 0 : fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "= \t", &result1);
658 0 : if (result1 == SDP_SUCCESS) {
659 0 : if (cpr_strncasecmp(tmp, sdp_fmtp_codec_param[1].name,
660 0 : sdp_fmtp_codec_param[1].strlen) == 0) {
661 0 : result1 = sdp_get_fmtp_tok(sdp_p, &fmtp_ptr, "annexb", tmp, sizeof(tmp), &tok);
662 0 : if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
663 :
664 0 : if (cpr_strncasecmp(tok,sdp_fmtp_codec_param_val[0].name,
665 0 : sdp_fmtp_codec_param_val[0].strlen) == 0) {
666 0 : fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
667 0 : fmtp_p->annexb_required = TRUE;
668 0 : fmtp_p->annexb = TRUE;
669 0 : } else if (cpr_strncasecmp(tok,sdp_fmtp_codec_param_val[1].name,
670 0 : sdp_fmtp_codec_param_val[1].strlen) == 0) {
671 0 : fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
672 0 : fmtp_p->annexb_required = TRUE;
673 0 : fmtp_p->annexb = FALSE;
674 : } else {
675 0 : sdp_attr_fmtp_invalid_value(sdp_p, "annexb", tok);
676 0 : SDP_FREE(temp_ptr);
677 0 : return SDP_INVALID_PARAMETER;
678 : }
679 0 : codec_info_found = TRUE;
680 :
681 0 : } else if (cpr_strncasecmp(tmp, sdp_fmtp_codec_param[0].name,
682 0 : sdp_fmtp_codec_param[0].strlen) == 0) {
683 0 : result1 = sdp_get_fmtp_tok(sdp_p, &fmtp_ptr, "annexa", tmp, sizeof(tmp), &tok);
684 0 : if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
685 :
686 0 : if (cpr_strncasecmp(tok,sdp_fmtp_codec_param_val[0].name,
687 0 : sdp_fmtp_codec_param_val[0].strlen) == 0) {
688 0 : fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
689 0 : fmtp_p->annexa = TRUE;
690 0 : fmtp_p->annexa_required = TRUE;
691 0 : } else if (cpr_strncasecmp(tok,sdp_fmtp_codec_param_val[1].name,
692 0 : sdp_fmtp_codec_param_val[1].strlen) == 0) {
693 0 : fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
694 0 : fmtp_p->annexa = FALSE;
695 0 : fmtp_p->annexa_required = TRUE;
696 : } else {
697 0 : sdp_attr_fmtp_invalid_value(sdp_p, "annexa", tok);
698 0 : SDP_FREE(temp_ptr);
699 0 : return SDP_INVALID_PARAMETER;
700 : }
701 0 : codec_info_found = TRUE;
702 :
703 0 : } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[2].name,
704 0 : sdp_fmtp_codec_param[2].strlen) == 0) {
705 0 : result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "bitrate", tmp, sizeof(tmp),
706 : &tok, &strtoul_result, 0, -1, UINT_MAX);
707 0 : if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
708 :
709 0 : fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
710 0 : fmtp_p->bitrate = (uint32_t) strtoul_result;
711 0 : codec_info_found = TRUE;
712 :
713 0 : } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[41].name,
714 0 : sdp_fmtp_codec_param[41].strlen) == 0) {
715 0 : result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "mode", tmp, sizeof(tmp),
716 : &tok, &strtoul_result, -1, -1, UINT_MAX);
717 0 : if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
718 :
719 0 : fmtp_p->fmtp_format = SDP_FMTP_MODE;
720 0 : fmtp_p->mode = (uint32_t) strtoul_result;
721 0 : codec_info_found = TRUE;
722 :
723 0 : } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[3].name,
724 0 : sdp_fmtp_codec_param[3].strlen) == 0) {
725 0 : result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "qcif", tmp, sizeof(tmp),
726 : &tok, &strtoul_result, -1, SDP_MIN_CIF_VALUE, SDP_MAX_CIF_VALUE);
727 0 : if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
728 :
729 0 : fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
730 0 : fmtp_p->qcif = (uint16_t) strtoul_result;
731 0 : codec_info_found = TRUE;
732 :
733 0 : } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[4].name,
734 0 : sdp_fmtp_codec_param[4].strlen) == 0) {
735 0 : result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "cif", tmp, sizeof(tmp),
736 : &tok, &strtoul_result, -1, SDP_MIN_CIF_VALUE, SDP_MAX_CIF_VALUE);
737 0 : if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
738 :
739 0 : fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
740 0 : fmtp_p->cif = (uint16_t) strtoul_result;
741 0 : codec_info_found = TRUE;
742 :
743 0 : } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[5].name,
744 0 : sdp_fmtp_codec_param[5].strlen) == 0) {
745 0 : result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "maxbr", tmp, sizeof(tmp),
746 : &tok, &strtoul_result, 0, -1, USHRT_MAX);
747 0 : if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
748 :
749 0 : fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
750 0 : fmtp_p->maxbr = (uint16_t) strtoul_result;
751 0 : codec_info_found = TRUE;
752 :
753 0 : } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[6].name,
754 0 : sdp_fmtp_codec_param[6].strlen) == 0) {
755 0 : result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "sqcif", tmp, sizeof(tmp),
756 : &tok, &strtoul_result, -1, SDP_MIN_CIF_VALUE, SDP_MAX_CIF_VALUE);
757 0 : if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
758 :
759 0 : fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
760 0 : fmtp_p->sqcif = (uint16_t) strtoul_result;
761 0 : codec_info_found = TRUE;
762 :
763 0 : } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[7].name,
764 0 : sdp_fmtp_codec_param[7].strlen) == 0) {
765 0 : result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "cif4", tmp, sizeof(tmp),
766 : &tok, &strtoul_result, -1, SDP_MIN_CIF_VALUE, SDP_MAX_CIF_VALUE);
767 0 : if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
768 :
769 0 : fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
770 0 : fmtp_p->cif4 = (uint16_t) strtoul_result;
771 0 : codec_info_found = TRUE;
772 :
773 0 : } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[8].name,
774 0 : sdp_fmtp_codec_param[8].strlen) == 0) {
775 0 : result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "cif16", tmp, sizeof(tmp),
776 : &tok, &strtoul_result, -1, SDP_MIN_CIF_VALUE, SDP_MAX_CIF_VALUE);
777 0 : if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
778 :
779 0 : fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
780 0 : fmtp_p->cif16 = (uint16_t) strtoul_result;
781 0 : codec_info_found = TRUE;
782 :
783 0 : } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[9].name,
784 0 : sdp_fmtp_codec_param[9].strlen) == 0) {
785 0 : result1 = sdp_get_fmtp_tok(sdp_p, &fmtp_ptr, "custom", tmp, sizeof(tmp), &tok);
786 0 : if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
787 :
788 0 : temp=PL_strtok_r(tok, ",", &strtok_state);
789 0 : iter++;
790 0 : if (temp) {
791 0 : iter=1;
792 0 : while (temp != NULL) {
793 0 : errno = 0;
794 0 : strtoul_result = strtoul(temp, &strtoul_end, 10);
795 :
796 0 : if (errno || temp == strtoul_end || strtoul_result > USHRT_MAX){
797 0 : custom_x = custom_y = custom_mpi = 0;
798 0 : break;
799 : }
800 :
801 0 : if (iter == 1)
802 0 : custom_x = (uint16_t) strtoul_result;
803 0 : if (iter == 2)
804 0 : custom_y = (uint16_t) strtoul_result;
805 0 : if (iter == 3)
806 0 : custom_mpi = (uint16_t) strtoul_result;
807 :
808 0 : temp=PL_strtok_r(NULL, ",", &strtok_state);
809 0 : iter++;
810 : }
811 : }
812 :
813 : /* custom x,y and mpi values from tmp */
814 0 : if (!custom_x || !custom_y || !custom_mpi) {
815 0 : sdp_attr_fmtp_invalid_value(sdp_p, "x/y/MPI", temp);
816 0 : SDP_FREE(temp_ptr);
817 0 : return SDP_INVALID_PARAMETER;
818 : }
819 0 : fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
820 0 : fmtp_p->custom_x = custom_x;
821 0 : fmtp_p->custom_y = custom_y;
822 0 : fmtp_p->custom_mpi = custom_mpi;
823 0 : codec_info_found = TRUE;
824 :
825 0 : } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[10].name,
826 0 : sdp_fmtp_codec_param[10].strlen) == 0) {
827 0 : result1 = sdp_get_fmtp_tok(sdp_p, &fmtp_ptr, "par", tmp, sizeof(tmp), &tok);
828 0 : if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
829 :
830 0 : temp=PL_strtok_r(tok, ":", &strtok_state);
831 0 : if (temp) {
832 0 : iter=1;
833 : /* get par width and par height for the aspect ratio */
834 0 : while (temp != NULL) {
835 0 : errno = 0;
836 0 : strtoul_result = strtoul(temp, &strtoul_end, 10);
837 :
838 0 : if (errno || temp == strtoul_end || strtoul_result > USHRT_MAX) {
839 0 : par_width = par_height = 0;
840 0 : break;
841 : }
842 :
843 0 : if (iter == 1)
844 0 : par_width = (uint16_t) strtoul_result;
845 : else
846 0 : par_height = (uint16_t) strtoul_result;
847 :
848 0 : temp=PL_strtok_r(NULL, ",", &strtok_state);
849 0 : iter++;
850 : }
851 : }
852 0 : if (!par_width || !par_height) {
853 0 : sdp_attr_fmtp_invalid_value(sdp_p, "par_width or par_height", temp);
854 0 : SDP_FREE(temp_ptr);
855 0 : return SDP_INVALID_PARAMETER;
856 : }
857 0 : fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
858 0 : fmtp_p->par_width = par_width;
859 0 : fmtp_p->par_height = par_height;
860 0 : codec_info_found = TRUE;
861 :
862 0 : } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[11].name,
863 0 : sdp_fmtp_codec_param[11].strlen) == 0) {
864 0 : result1 = sdp_get_fmtp_tok(sdp_p, &fmtp_ptr, "cpcf", tmp, sizeof(tmp), &tok);
865 0 : if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
866 :
867 0 : temp=PL_strtok_r(tok, ".", &strtok_state);
868 0 : if ( temp != NULL ) {
869 0 : errno = 0;
870 0 : strtoul_result = strtoul(temp, &strtoul_end, 10);
871 :
872 0 : if (errno || temp == strtoul_end || strtoul_result > USHRT_MAX) {
873 0 : cpcf = 0;
874 : } else {
875 0 : cpcf = (uint16_t) strtoul_result;
876 : }
877 : }
878 :
879 0 : if (!cpcf) {
880 0 : sdp_attr_fmtp_invalid_value(sdp_p, "cpcf", tok);
881 0 : SDP_FREE(temp_ptr);
882 0 : return SDP_INVALID_PARAMETER;
883 : }
884 0 : fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
885 0 : fmtp_p->cpcf = cpcf;
886 0 : codec_info_found = TRUE;
887 :
888 0 : } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[12].name,
889 0 : sdp_fmtp_codec_param[12].strlen) == 0) {
890 0 : result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "bpp", tmp, sizeof(tmp),
891 : &tok, &strtoul_result, 0, -1, USHRT_MAX);
892 0 : if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
893 :
894 0 : fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
895 0 : fmtp_p->bpp = (uint16_t) strtoul_result;
896 0 : codec_info_found = TRUE;
897 :
898 0 : } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[13].name,
899 0 : sdp_fmtp_codec_param[13].strlen) == 0) {
900 0 : result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "hrd", tmp, sizeof(tmp),
901 : &tok, &strtoul_result, 0, -1, USHRT_MAX);
902 0 : if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
903 :
904 0 : fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
905 0 : fmtp_p->hrd = (uint16_t) strtoul_result;
906 0 : codec_info_found = TRUE;
907 :
908 0 : } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[14].name,
909 0 : sdp_fmtp_codec_param[14].strlen) == 0) {
910 0 : result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "profile", tmp, sizeof(tmp),
911 : &tok, &strtoul_result, -1, -1, SDP_MAX_PROFILE_VALUE);
912 0 : if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
913 :
914 0 : fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
915 0 : fmtp_p->profile = (short) strtoul_result;
916 0 : codec_info_found = TRUE;
917 :
918 0 : } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[15].name,
919 0 : sdp_fmtp_codec_param[15].strlen) == 0) {
920 0 : result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "level", tmp, sizeof(tmp),
921 : &tok, &strtoul_result, -1, -1, SDP_MAX_LEVEL_VALUE);
922 0 : if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
923 :
924 0 : fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
925 0 : fmtp_p->level = (short) strtoul_result;
926 0 : codec_info_found = TRUE;
927 :
928 0 : } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[16].name,
929 0 : sdp_fmtp_codec_param[16].strlen) == 0) {
930 0 : fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
931 0 : fmtp_p->is_interlace = TRUE;
932 0 : codec_info_found = TRUE;
933 :
934 0 : } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[17].name,
935 0 : sdp_fmtp_codec_param[17].strlen) == 0) {
936 0 : result1 = sdp_get_fmtp_tok(sdp_p, &fmtp_ptr, "profile_level_id", tmp, sizeof(tmp), &tok);
937 0 : if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
938 :
939 0 : fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
940 0 : sstrncpy(fmtp_p->profile_level_id , tok, sizeof(fmtp_p->profile_level_id));
941 0 : codec_info_found = TRUE;
942 :
943 0 : } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[18].name,
944 0 : sdp_fmtp_codec_param[18].strlen) == 0) {
945 0 : result1 = sdp_get_fmtp_tok(sdp_p, &fmtp_ptr, "parameter_sets", tmp, sizeof(tmp), &tok);
946 0 : if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
947 :
948 0 : fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
949 0 : sstrncpy(fmtp_p->parameter_sets , tok, sizeof(fmtp_p->parameter_sets));
950 0 : codec_info_found = TRUE;
951 :
952 0 : } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[19].name,
953 0 : sdp_fmtp_codec_param[19].strlen) == 0) {
954 0 : result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "packetization_mode", tmp, sizeof(tmp),
955 : &tok, &strtoul_result, -1, -1, 2);
956 : // this one is different for some reason. Most others don't increment
957 : // the num_invalid_param field. (mjf)
958 0 : if (result1 == SDP_INVALID_PARAMETER) { sdp_p->conf_p->num_invalid_param++; }
959 0 : if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
960 :
961 0 : fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
962 0 : fmtp_p->packetization_mode = (int16_t) strtoul_result;
963 0 : codec_info_found = TRUE;
964 :
965 0 : } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[20].name,
966 0 : sdp_fmtp_codec_param[20].strlen) == 0) {
967 0 : result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "interleaving_depth", tmp, sizeof(tmp),
968 : &tok, &strtoul_result, 0, -1, USHRT_MAX);
969 0 : if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
970 :
971 0 : fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
972 0 : fmtp_p->interleaving_depth = (uint16_t) strtoul_result;
973 0 : codec_info_found = TRUE;
974 :
975 0 : } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[21].name,
976 0 : sdp_fmtp_codec_param[21].strlen) == 0) {
977 0 : result1 = sdp_get_fmtp_tok(sdp_p, &fmtp_ptr, "deint_buf", tmp, sizeof(tmp), &tok);
978 0 : if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
979 :
980 0 : if (sdp_checkrange(sdp_p, tok, &l_val) == TRUE) {
981 0 : fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
982 0 : fmtp_p->deint_buf_req = (uint32_t) l_val;
983 0 : fmtp_p->flag |= SDP_DEINT_BUF_REQ_FLAG;
984 0 : codec_info_found = TRUE;
985 : } else {
986 0 : sdp_attr_fmtp_invalid_value(sdp_p, "deint_buf_req", tok);
987 0 : SDP_FREE(temp_ptr);
988 0 : return SDP_INVALID_PARAMETER;
989 : }
990 :
991 0 : } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[22].name,
992 0 : sdp_fmtp_codec_param[22].strlen) == 0) {
993 0 : result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "max_don_diff", tmp, sizeof(tmp),
994 : &tok, &strtoul_result, 0, -1, UINT_MAX);
995 0 : if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
996 :
997 0 : fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
998 0 : fmtp_p->max_don_diff = (uint32_t) strtoul_result;
999 0 : codec_info_found = TRUE;
1000 :
1001 0 : } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[23].name,
1002 0 : sdp_fmtp_codec_param[23].strlen) == 0) {
1003 0 : result1 = sdp_get_fmtp_tok(sdp_p, &fmtp_ptr, "init_buf_time", tmp, sizeof(tmp), &tok);
1004 0 : if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
1005 :
1006 0 : if (sdp_checkrange(sdp_p, tok, &l_val) == TRUE) {
1007 0 : fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
1008 0 : fmtp_p->init_buf_time = (uint32_t) l_val;
1009 0 : fmtp_p->flag |= SDP_INIT_BUF_TIME_FLAG;
1010 0 : codec_info_found = TRUE;
1011 : } else {
1012 0 : sdp_attr_fmtp_invalid_value(sdp_p, "init_buf_time", tok);
1013 0 : SDP_FREE(temp_ptr);
1014 0 : return SDP_INVALID_PARAMETER;
1015 : }
1016 :
1017 0 : } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[24].name,
1018 0 : sdp_fmtp_codec_param[24].strlen) == 0) {
1019 0 : result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "max_mbps", tmp, sizeof(tmp),
1020 : &tok, &strtoul_result, 0, -1, UINT_MAX);
1021 0 : if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
1022 :
1023 0 : fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
1024 0 : fmtp_p->max_mbps = (uint32_t) strtoul_result;
1025 0 : codec_info_found = TRUE;
1026 :
1027 0 : } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[25].name,
1028 0 : sdp_fmtp_codec_param[25].strlen) == 0) {
1029 0 : result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "max-fs", tmp, sizeof(tmp),
1030 : &tok, &strtoul_result, 0, -1, UINT_MAX);
1031 0 : if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
1032 :
1033 0 : fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
1034 0 : fmtp_p->max_fs = (uint32_t) strtoul_result;
1035 0 : codec_info_found = TRUE;
1036 :
1037 0 : } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[26].name,
1038 0 : sdp_fmtp_codec_param[26].strlen) == 0) {
1039 0 : result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "max_cbp", tmp, sizeof(tmp),
1040 : &tok, &strtoul_result, 0, -1, UINT_MAX);
1041 0 : if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
1042 :
1043 0 : fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
1044 0 : fmtp_p->max_cpb = (uint32_t) strtoul_result;
1045 0 : codec_info_found = TRUE;
1046 :
1047 0 : } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[27].name,
1048 0 : sdp_fmtp_codec_param[27].strlen) == 0) {
1049 0 : result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "max_dpb", tmp, sizeof(tmp),
1050 : &tok, &strtoul_result, 0, -1, UINT_MAX);
1051 0 : if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
1052 :
1053 0 : fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
1054 0 : fmtp_p->max_dpb = (uint32_t) strtoul_result;
1055 0 : codec_info_found = TRUE;
1056 :
1057 0 : } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[28].name,
1058 0 : sdp_fmtp_codec_param[28].strlen) == 0) {
1059 0 : result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "max_br", tmp, sizeof(tmp),
1060 : &tok, &strtoul_result, 0, -1, UINT_MAX);
1061 0 : if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
1062 :
1063 0 : fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
1064 0 : fmtp_p->max_br = (uint32_t) strtoul_result;
1065 0 : codec_info_found = TRUE;
1066 :
1067 0 : } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[29].name,
1068 0 : sdp_fmtp_codec_param[29].strlen) == 0) {
1069 0 : result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "redundant_pic_cap", tmp, sizeof(tmp),
1070 : &tok, &strtoul_result, 0, -1, 1);
1071 0 : fmtp_p->redundant_pic_cap = (result1 == SDP_SUCCESS);
1072 0 : codec_info_found = TRUE;
1073 :
1074 0 : } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[30].name,
1075 0 : sdp_fmtp_codec_param[30].strlen) == 0) {
1076 0 : result1 = sdp_get_fmtp_tok(sdp_p, &fmtp_ptr, "deint_buf_cap", tmp, sizeof(tmp), &tok);
1077 0 : if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
1078 :
1079 0 : if (sdp_checkrange(sdp_p, tok, &l_val) == TRUE) {
1080 0 : fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
1081 0 : fmtp_p->deint_buf_cap = (uint32_t) l_val;
1082 0 : fmtp_p->flag |= SDP_DEINT_BUF_CAP_FLAG;
1083 0 : codec_info_found = TRUE;
1084 : } else {
1085 0 : sdp_attr_fmtp_invalid_value(sdp_p, "deint_buf_cap", tok);
1086 0 : SDP_FREE(temp_ptr);
1087 0 : return SDP_INVALID_PARAMETER;
1088 : }
1089 :
1090 0 : } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[31].name,
1091 0 : sdp_fmtp_codec_param[31].strlen) == 0) {
1092 0 : result1 = sdp_get_fmtp_tok(sdp_p, &fmtp_ptr, "max_rcmd_nalu_size", tmp, sizeof(tmp), &tok);
1093 0 : if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
1094 :
1095 0 : if (sdp_checkrange(sdp_p, tok, &l_val) == TRUE) {
1096 0 : fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
1097 0 : fmtp_p->max_rcmd_nalu_size = (uint32_t) l_val;
1098 0 : fmtp_p->flag |= SDP_MAX_RCMD_NALU_SIZE_FLAG;
1099 0 : codec_info_found = TRUE;
1100 : } else {
1101 0 : sdp_attr_fmtp_invalid_value(sdp_p, "max_rcmd_nalu_size", tok);
1102 0 : SDP_FREE(temp_ptr);
1103 0 : return SDP_INVALID_PARAMETER;
1104 : }
1105 :
1106 0 : } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[32].name,
1107 0 : sdp_fmtp_codec_param[32].strlen) == 0) {
1108 0 : result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "parameter_add", tmp, sizeof(tmp),
1109 : &tok, &strtoul_result, 0, -1, 1);
1110 0 : if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
1111 :
1112 0 : fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
1113 0 : fmtp_p->parameter_add = (uint16_t) strtoul_result;
1114 0 : codec_info_found = TRUE;
1115 :
1116 0 : } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[33].name,
1117 0 : sdp_fmtp_codec_param[33].strlen) == 0) {
1118 0 : fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
1119 0 : fmtp_p->annex_d = TRUE;
1120 0 : codec_info_found = TRUE;
1121 :
1122 0 : } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[34].name,
1123 0 : sdp_fmtp_codec_param[34].strlen) == 0) {
1124 0 : fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
1125 0 : fmtp_p->annex_f = TRUE;
1126 0 : codec_info_found = TRUE;
1127 :
1128 0 : } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[35].name,
1129 0 : sdp_fmtp_codec_param[35].strlen) == 0) {
1130 0 : fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
1131 0 : fmtp_p->annex_i = TRUE;
1132 0 : codec_info_found = TRUE;
1133 :
1134 0 : } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[36].name,
1135 0 : sdp_fmtp_codec_param[36].strlen) == 0) {
1136 0 : fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
1137 0 : fmtp_p->annex_j = TRUE;
1138 0 : codec_info_found = TRUE;
1139 :
1140 0 : } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[37].name,
1141 0 : sdp_fmtp_codec_param[36].strlen) == 0) {
1142 0 : fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
1143 0 : fmtp_p->annex_t = TRUE;
1144 0 : codec_info_found = TRUE;
1145 :
1146 0 : } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[38].name,
1147 0 : sdp_fmtp_codec_param[38].strlen) == 0) {
1148 0 : result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "annex_k", tmp, sizeof(tmp),
1149 : &tok, &strtoul_result, 0, -1, USHRT_MAX);
1150 0 : if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
1151 :
1152 0 : fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
1153 0 : fmtp_p->annex_k_val = (uint16_t) strtoul_result;
1154 0 : codec_info_found = TRUE;
1155 :
1156 0 : } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[39].name,
1157 0 : sdp_fmtp_codec_param[39].strlen) == 0) {
1158 0 : result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "annex_n", tmp, sizeof(tmp),
1159 : &tok, &strtoul_result, 0, -1, USHRT_MAX);
1160 0 : if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
1161 :
1162 0 : fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
1163 0 : fmtp_p->annex_n_val = (uint16_t) strtoul_result;
1164 0 : codec_info_found = TRUE;
1165 :
1166 0 : } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[40].name,
1167 0 : sdp_fmtp_codec_param[40].strlen) == 0) {
1168 0 : result1 = sdp_get_fmtp_tok(sdp_p, &fmtp_ptr, "annex_p", tmp, sizeof(tmp), &tok);
1169 0 : if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
1170 :
1171 0 : fmtp_p->annex_p_val_picture_resize = 0;
1172 0 : fmtp_p->annex_p_val_warp = 0;
1173 0 : temp = PL_strtok_r(tok, ",", &strtok_state);
1174 0 : if (temp) {
1175 0 : iter=1;
1176 0 : while (temp != NULL) {
1177 0 : errno = 0;
1178 0 : strtoul_result = strtoul(temp, &strtoul_end, 10);
1179 :
1180 0 : if (errno || temp == strtoul_end || strtoul_result > USHRT_MAX) {
1181 : break;
1182 : }
1183 :
1184 0 : if (iter == 1)
1185 0 : fmtp_p->annex_p_val_picture_resize = (uint16_t) strtoul_result;
1186 0 : else if (iter == 2)
1187 0 : fmtp_p->annex_p_val_warp = (uint16_t) strtoul_result;
1188 :
1189 0 : temp = PL_strtok_r(NULL, ",", &strtok_state);
1190 0 : iter++;
1191 : }
1192 : }
1193 :
1194 0 : fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
1195 0 : codec_info_found = TRUE;
1196 :
1197 0 : } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[42].name,
1198 0 : sdp_fmtp_codec_param[42].strlen) == 0) {
1199 0 : result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "level_asymmetry_allowed", tmp, sizeof(tmp),
1200 : &tok, &strtoul_result, -1, -1, SDP_MAX_LEVEL_ASYMMETRY_ALLOWED_VALUE);
1201 0 : if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
1202 :
1203 0 : fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
1204 0 : fmtp_p->level_asymmetry_allowed = (int) strtoul_result;
1205 0 : codec_info_found = TRUE;
1206 :
1207 0 : } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[43].name,
1208 0 : sdp_fmtp_codec_param[43].strlen) == 0) {
1209 0 : result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "maxaveragebitrate", tmp, sizeof(tmp),
1210 : &tok, &strtoul_result, 0, -1, UINT_MAX);
1211 0 : if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
1212 :
1213 0 : fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
1214 0 : fmtp_p->maxaveragebitrate = (uint32_t) strtoul_result;
1215 0 : codec_info_found = TRUE;
1216 :
1217 0 : } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[44].name,
1218 0 : sdp_fmtp_codec_param[44].strlen) == 0) {
1219 0 : result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "usedtx", tmp, sizeof(tmp),
1220 : &tok, &strtoul_result, -1, -1, 1);
1221 0 : if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
1222 :
1223 0 : fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
1224 0 : fmtp_p->usedtx = (uint16_t) strtoul_result;
1225 0 : codec_info_found = TRUE;
1226 :
1227 0 : } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[45].name,
1228 0 : sdp_fmtp_codec_param[45].strlen) == 0) {
1229 0 : result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "stereo", tmp, sizeof(tmp),
1230 : &tok, &strtoul_result, -1, -1, 1);
1231 0 : if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
1232 :
1233 0 : fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
1234 0 : fmtp_p->stereo = (uint16_t) strtoul_result;
1235 0 : codec_info_found = TRUE;
1236 :
1237 0 : } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[46].name,
1238 0 : sdp_fmtp_codec_param[46].strlen) == 0) {
1239 0 : result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "useinbandfec", tmp, sizeof(tmp),
1240 : &tok, &strtoul_result, -1, -1, 1);
1241 0 : if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
1242 :
1243 0 : fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
1244 0 : fmtp_p->useinbandfec = (uint16_t) strtoul_result;
1245 0 : codec_info_found = TRUE;
1246 :
1247 0 : } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[47].name,
1248 0 : sdp_fmtp_codec_param[47].strlen) == 0) {
1249 0 : result1 = sdp_get_fmtp_tok(sdp_p, &fmtp_ptr, "maxcodedaudiobandwidth", tmp, sizeof(tmp), &tok);
1250 : // this one is different for some reason. Most others don't increment
1251 : // the num_invalid_param field. (mjf)
1252 0 : if (result1 == SDP_INVALID_PARAMETER) { sdp_p->conf_p->num_invalid_param++; }
1253 0 : if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
1254 :
1255 0 : fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
1256 0 : sstrncpy(fmtp_p->maxcodedaudiobandwidth , tok, sizeof(fmtp_p->maxcodedaudiobandwidth));
1257 0 : codec_info_found = TRUE;
1258 :
1259 0 : } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[48].name,
1260 0 : sdp_fmtp_codec_param[48].strlen) == 0) {
1261 0 : result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "cbr", tmp, sizeof(tmp),
1262 : &tok, &strtoul_result, -1, -1, 1);
1263 0 : if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
1264 :
1265 0 : fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
1266 0 : fmtp_p->cbr = (uint16_t) strtoul_result;
1267 0 : codec_info_found = TRUE;
1268 :
1269 0 : } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[49].name,
1270 0 : sdp_fmtp_codec_param[49].strlen) == 0) {
1271 0 : result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "max-fr", tmp, sizeof(tmp),
1272 : &tok, &strtoul_result, 0, -1, UINT_MAX);
1273 0 : if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
1274 :
1275 0 : fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
1276 0 : fmtp_p->max_fr = (uint32_t) strtoul_result;
1277 0 : codec_info_found = TRUE;
1278 :
1279 0 : } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[50].name,
1280 0 : sdp_fmtp_codec_param[50].strlen) == 0) {
1281 0 : result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "maxplaybackrate", tmp, sizeof(tmp),
1282 : &tok, &strtoul_result, 0, -1, UINT_MAX);
1283 0 : if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
1284 :
1285 0 : fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO;
1286 0 : fmtp_p->maxplaybackrate = (uint32_t) strtoul_result;
1287 0 : codec_info_found = TRUE;
1288 :
1289 0 : } else if (fmtp_ptr != NULL && *fmtp_ptr == '\n') {
1290 0 : temp=PL_strtok_r(tmp, ";", &strtok_state);
1291 0 : if (temp) {
1292 0 : if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
1293 0 : SDP_PRINT("%s Annexes are possibly there for this fmtp %s tmp: %s line\n",
1294 : sdp_p->debug_str, fmtp_ptr, tmp);
1295 : }
1296 0 : while (temp != NULL) {
1297 0 : if (strchr(temp, 'D') !=NULL) {
1298 0 : attr_p->attr.fmtp.annex_d = TRUE;
1299 : }
1300 0 : if (strchr(temp, 'F') !=NULL) {
1301 0 : attr_p->attr.fmtp.annex_f = TRUE;
1302 : }
1303 0 : if (strchr(temp, 'I') !=NULL) {
1304 0 : attr_p->attr.fmtp.annex_i = TRUE;
1305 : }
1306 0 : if (strchr(temp, 'J') !=NULL) {
1307 0 : attr_p->attr.fmtp.annex_j = TRUE;
1308 : }
1309 0 : if (strchr(temp, 'T') !=NULL) {
1310 0 : attr_p->attr.fmtp.annex_t = TRUE;
1311 : }
1312 0 : temp=PL_strtok_r(NULL, ";", &strtok_state);
1313 : }
1314 : } /* if (temp) */
1315 0 : done = TRUE;
1316 0 : } else if (strchr(tmp, '/')) {
1317 : // XXX Note that because RFC 5109 so conveniently specified
1318 : // this fmtp with no param names, we hope that nothing else
1319 : // has a slash in the string because otherwise we won't know
1320 : // how to differentiate.
1321 0 : temp=PL_strtok_r(tmp, "/", &strtok_state);
1322 0 : if (temp) {
1323 0 : iter = 0;
1324 0 : while (temp != NULL) {
1325 0 : errno = 0;
1326 0 : strtoul_result = strtoul(temp, &strtoul_end, 10);
1327 :
1328 0 : if (errno ||
1329 0 : temp == strtoul_end || strtoul_result > USHRT_MAX) {
1330 0 : temp = NULL;
1331 0 : continue;
1332 : }
1333 0 : fmtp_p->redundant_encodings[iter++] =
1334 0 : (uint8_t)strtoul_result;
1335 0 : temp=PL_strtok_r(NULL, "/", &strtok_state);
1336 : }
1337 : } /* if (temp) */
1338 0 : } else if (SDP_SUCCESS == sdp_verify_attr_fmtp_telephone_event(tmp)) {
1339 : // XXX Note that DTMF fmtp will fall into here:
1340 : // a=fmtp:101 0-15 (or 0-15,NN,NN etc)
1341 0 : sstrncpy(fmtp_p->dtmf_tones , tmp, sizeof(fmtp_p->dtmf_tones));
1342 0 : codec_info_found = TRUE;
1343 : } else {
1344 : // unknown parameter - eat chars until ';'
1345 0 : CSFLogDebug(logTag, "%s Unknown fmtp type (%s) - ignoring", __FUNCTION__,
1346 : tmp);
1347 0 : fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "; \t",
1348 : &result1);
1349 0 : if (result1 != SDP_SUCCESS) {
1350 0 : fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), " \t", &result1);
1351 0 : if (result1 != SDP_SUCCESS) {
1352 : // hmmm, no ; or spaces or tabs; continue on
1353 : }
1354 : }
1355 : }
1356 0 : fmtp_ptr++;
1357 : } else {
1358 0 : done = TRUE;
1359 : }
1360 : } /* while - done loop*/
1361 :
1362 0 : if (codec_info_found) {
1363 :
1364 0 : if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
1365 0 : SDP_PRINT("%s Parsed a=%s, payload type %u, bitrate %u, mode %u QCIF = %u, CIF = %u, MAXBR= %u, SQCIF=%u, CIF4= %u, CIF16=%u, CUSTOM=%u,%u,%u , PAR=%u:%u,CPCF=%u, BPP=%u, HRD=%u \n",
1366 : sdp_p->debug_str,
1367 : sdp_get_attr_name(attr_p->type),
1368 : attr_p->attr.fmtp.payload_num,
1369 : attr_p->attr.fmtp.bitrate,
1370 : attr_p->attr.fmtp.mode,
1371 : attr_p->attr.fmtp.qcif,
1372 : attr_p->attr.fmtp.cif,
1373 : attr_p->attr.fmtp.maxbr,
1374 : attr_p->attr.fmtp.sqcif,
1375 : attr_p->attr.fmtp.cif4,
1376 : attr_p->attr.fmtp.cif16,
1377 : attr_p->attr.fmtp.custom_x,attr_p->attr.fmtp.custom_y,
1378 : attr_p->attr.fmtp.custom_mpi,
1379 : attr_p->attr.fmtp.par_width,
1380 : attr_p->attr.fmtp.par_height,
1381 : attr_p->attr.fmtp.cpcf,
1382 : attr_p->attr.fmtp.bpp,
1383 : attr_p->attr.fmtp.hrd
1384 : );
1385 : }
1386 :
1387 0 : if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
1388 0 : SDP_PRINT("%s Parsed a=%s, payload type %u,PROFILE=%u,LEVEL=%u, INTERLACE - %s",
1389 : sdp_p->debug_str,
1390 : sdp_get_attr_name(attr_p->type),
1391 : attr_p->attr.fmtp.payload_num,
1392 : attr_p->attr.fmtp.profile,
1393 : attr_p->attr.fmtp.level,
1394 : attr_p->attr.fmtp.is_interlace ? "YES":"NO");
1395 : }
1396 :
1397 0 : if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
1398 0 : SDP_PRINT("%s Parsed H.264 attributes: profile-level-id=%s, parameter-sets=%s, packetization-mode=%d level-asymmetry-allowed=%d interleaving-depth=%d deint-buf-req=%u max-don-diff=%u, init_buf-time=%u\n",
1399 : sdp_p->debug_str,
1400 : attr_p->attr.fmtp.profile_level_id,
1401 : attr_p->attr.fmtp.parameter_sets,
1402 : attr_p->attr.fmtp.packetization_mode,
1403 : attr_p->attr.fmtp.level_asymmetry_allowed,
1404 : attr_p->attr.fmtp.interleaving_depth,
1405 : attr_p->attr.fmtp.deint_buf_req,
1406 : attr_p->attr.fmtp.max_don_diff,
1407 : attr_p->attr.fmtp.init_buf_time
1408 : );
1409 : }
1410 :
1411 0 : if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
1412 0 : SDP_PRINT("\n%s Parsed H.264 opt attributes: max-mbps=%u, max-fs=%u, max-cpb=%u max-dpb=%u max-br=%u redundant-pic-cap=%d, deint-buf-cap=%u, max-rcmd-nalu-size=%u , parameter-add=%d\n",
1413 : sdp_p->debug_str,
1414 : attr_p->attr.fmtp.max_mbps,
1415 : attr_p->attr.fmtp.max_fs,
1416 : attr_p->attr.fmtp.max_cpb,
1417 : attr_p->attr.fmtp.max_dpb,
1418 : attr_p->attr.fmtp.max_br,
1419 : attr_p->attr.fmtp.redundant_pic_cap,
1420 : attr_p->attr.fmtp.deint_buf_cap,
1421 : attr_p->attr.fmtp.max_rcmd_nalu_size,
1422 : attr_p->attr.fmtp.parameter_add);
1423 :
1424 : }
1425 0 : if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
1426 0 : SDP_PRINT("%s Parsed annexes are : D=%d F=%d I=%d J=%d T=%d, K=%d N=%d P=%d,%d\n",
1427 : sdp_p->debug_str,
1428 : attr_p->attr.fmtp.annex_d,
1429 : attr_p->attr.fmtp.annex_f, attr_p->attr.fmtp.annex_i,
1430 : attr_p->attr.fmtp.annex_j, attr_p->attr.fmtp.annex_t,
1431 : attr_p->attr.fmtp.annex_k_val,
1432 : attr_p->attr.fmtp.annex_n_val,
1433 : attr_p->attr.fmtp.annex_p_val_picture_resize,
1434 : attr_p->attr.fmtp.annex_p_val_warp);
1435 :
1436 : }
1437 0 : SDP_FREE(temp_ptr);
1438 0 : return (SDP_SUCCESS);
1439 : } else {
1440 0 : done = FALSE;
1441 0 : fmtp_ptr = src_ptr;
1442 0 : tmp[0] = '\0';
1443 : }
1444 :
1445 0 : for (i=0; !done; i++) {
1446 0 : fmtp_p->fmtp_format = SDP_FMTP_NTE;
1447 : /* Look for comma separated events */
1448 0 : fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), ", \t", &result1);
1449 0 : if (result1 != SDP_SUCCESS) {
1450 0 : done = TRUE;
1451 0 : continue;
1452 : }
1453 : /* Now look for '-' separated range */
1454 0 : ptr2 = tmp;
1455 0 : low_val = (uint8_t)sdp_getnextnumtok(ptr2, (const char **)&ptr2,
1456 : "- \t", &result1);
1457 0 : if (*ptr2 == '-') {
1458 0 : high_val = (uint8_t)sdp_getnextnumtok(ptr2, (const char **)&ptr2,
1459 : "- \t", &result2);
1460 : } else {
1461 0 : high_val = low_val;
1462 : }
1463 :
1464 0 : if ((result1 != SDP_SUCCESS) || (result2 != SDP_SUCCESS)) {
1465 0 : sdp_parse_error(sdp_p,
1466 : "%s Warning: Invalid named events specified for fmtp attribute.",
1467 0 : sdp_p->debug_str);
1468 0 : sdp_p->conf_p->num_invalid_param++;
1469 0 : SDP_FREE(temp_ptr);
1470 0 : return (SDP_INVALID_PARAMETER);
1471 : }
1472 :
1473 0 : for (i = low_val; i <= high_val; i++) {
1474 0 : mapword = i/SDP_NE_BITS_PER_WORD;
1475 0 : bmap = SDP_NE_BIT_0 << (i%32);
1476 0 : fmtp_p->bmap[mapword] |= bmap;
1477 : }
1478 0 : if (high_val > fmtp_p->maxval) {
1479 0 : fmtp_p->maxval = high_val;
1480 : }
1481 : }
1482 :
1483 0 : if (fmtp_p->maxval == 0) {
1484 0 : sdp_parse_error(sdp_p,
1485 : "%s Warning: No named events specified for fmtp attribute.",
1486 0 : sdp_p->debug_str);
1487 0 : sdp_p->conf_p->num_invalid_param++;
1488 0 : SDP_FREE(temp_ptr);
1489 0 : return (SDP_INVALID_PARAMETER);
1490 : }
1491 :
1492 0 : if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
1493 0 : SDP_PRINT("%s Parsed a=%s, payload type %u, ", sdp_p->debug_str,
1494 : sdp_get_attr_name(attr_p->type),
1495 : attr_p->attr.fmtp.payload_num);
1496 : }
1497 0 : SDP_FREE(temp_ptr);
1498 0 : return (SDP_SUCCESS);
1499 : }
1500 :
1501 : sdp_result_e
1502 0 : sdp_build_attr_fmtp_params (sdp_t *sdp_p, sdp_fmtp_t *fmtp_p, flex_string *fs)
1503 : {
1504 : uint16_t event_id;
1505 : uint32_t mask;
1506 : uint32_t mapword;
1507 0 : uint8_t min = 0;
1508 0 : uint8_t max = 0;
1509 0 : tinybool range_start = FALSE;
1510 0 : tinybool range_end = FALSE;
1511 0 : tinybool semicolon = FALSE;
1512 :
1513 0 : switch (fmtp_p->fmtp_format) {
1514 : case SDP_FMTP_MODE:
1515 0 : sdp_append_name_and_unsigned(fs, "mode", fmtp_p->mode, FALSE);
1516 0 : break;
1517 :
1518 : case SDP_FMTP_CODEC_INFO:
1519 0 : FMTP_BUILD_UNSIGNED(fmtp_p->bitrate > 0, "bitrate", fmtp_p->bitrate)
1520 :
1521 0 : FMTP_BUILD_STRING(fmtp_p->annexa_required,
1522 : "annexa", (fmtp_p->annexa ? "yes" : "no"))
1523 :
1524 0 : FMTP_BUILD_STRING(fmtp_p->annexb_required,
1525 : "annexb", (fmtp_p->annexa ? "yes" : "no"))
1526 :
1527 0 : FMTP_BUILD_UNSIGNED(fmtp_p->qcif > 0, "QCIF", fmtp_p->qcif)
1528 :
1529 0 : FMTP_BUILD_UNSIGNED(fmtp_p->cif > 0, "CIF", fmtp_p->cif)
1530 :
1531 0 : FMTP_BUILD_UNSIGNED(fmtp_p->maxbr > 0, "MAXBR", fmtp_p->maxbr)
1532 :
1533 0 : FMTP_BUILD_UNSIGNED(fmtp_p->sqcif > 0, "SQCIF", fmtp_p->sqcif)
1534 :
1535 0 : FMTP_BUILD_UNSIGNED(fmtp_p->cif4 > 0, "CIF4", fmtp_p->cif4)
1536 :
1537 0 : FMTP_BUILD_UNSIGNED(fmtp_p->cif16 > 0, "CIF16", fmtp_p->cif16)
1538 :
1539 0 : if ((fmtp_p->custom_x > 0) && (fmtp_p->custom_y > 0) &&
1540 0 : (fmtp_p->custom_mpi > 0)) {
1541 0 : flex_string_sprintf(fs, "%sCUSTOM=%u,%u,%u",
1542 : semicolon ? ";" : "",
1543 0 : fmtp_p->custom_x,
1544 0 : fmtp_p->custom_y,
1545 0 : fmtp_p->custom_mpi);
1546 :
1547 0 : semicolon = TRUE;
1548 : }
1549 :
1550 0 : if ((fmtp_p->par_height > 0) && (fmtp_p->par_width > 0)) {
1551 0 : flex_string_sprintf(fs, "%sPAR=%u:%u",
1552 : semicolon ? ";" : "",
1553 0 : fmtp_p->par_width,
1554 0 : fmtp_p->par_width);
1555 :
1556 0 : semicolon = TRUE;
1557 : }
1558 :
1559 0 : FMTP_BUILD_UNSIGNED(fmtp_p->cpcf > 0, "CPCF", fmtp_p->cpcf)
1560 :
1561 0 : FMTP_BUILD_UNSIGNED(fmtp_p->bpp > 0, "BPP", fmtp_p->bpp)
1562 :
1563 0 : FMTP_BUILD_UNSIGNED(fmtp_p->hrd > 0, "HRD", fmtp_p->hrd)
1564 :
1565 0 : FMTP_BUILD_UNSIGNED(fmtp_p->profile >= 0, "PROFILE", fmtp_p->profile)
1566 :
1567 0 : FMTP_BUILD_UNSIGNED(fmtp_p->level >= 0, "LEVEL", fmtp_p->level)
1568 :
1569 0 : FMTP_BUILD_FLAG(fmtp_p->is_interlace, "INTERLACE")
1570 :
1571 0 : FMTP_BUILD_FLAG(fmtp_p->annex_d, "D")
1572 :
1573 0 : FMTP_BUILD_FLAG(fmtp_p->annex_f, "F")
1574 :
1575 0 : FMTP_BUILD_FLAG(fmtp_p->annex_i, "I")
1576 :
1577 0 : FMTP_BUILD_FLAG(fmtp_p->annex_j, "J")
1578 :
1579 0 : FMTP_BUILD_FLAG(fmtp_p->annex_t, "T")
1580 :
1581 0 : FMTP_BUILD_UNSIGNED(fmtp_p->annex_k_val > 0,
1582 : "K", fmtp_p->annex_k_val)
1583 :
1584 0 : FMTP_BUILD_UNSIGNED(fmtp_p->annex_n_val > 0,
1585 : "N", fmtp_p->annex_n_val)
1586 :
1587 0 : if ((fmtp_p->annex_p_val_picture_resize > 0) &&
1588 0 : (fmtp_p->annex_p_val_warp > 0)) {
1589 0 : flex_string_sprintf(fs, "%sP=%d:%d",
1590 : semicolon ? ";" : "",
1591 0 : fmtp_p->annex_p_val_picture_resize,
1592 0 : fmtp_p->annex_p_val_warp);
1593 :
1594 0 : semicolon = TRUE;
1595 : }
1596 :
1597 0 : FMTP_BUILD_STRING(strlen(fmtp_p->profile_level_id) > 0,
1598 : "profile-level-id", fmtp_p->profile_level_id)
1599 :
1600 0 : FMTP_BUILD_STRING(strlen(fmtp_p->parameter_sets) > 0,
1601 : "sprop-parameter-sets", fmtp_p->parameter_sets)
1602 :
1603 0 : FMTP_BUILD_UNSIGNED(
1604 : fmtp_p->packetization_mode < SDP_MAX_PACKETIZATION_MODE_VALUE,
1605 : "packetization-mode", fmtp_p->packetization_mode)
1606 :
1607 0 : FMTP_BUILD_UNSIGNED(
1608 : fmtp_p->level_asymmetry_allowed <=
1609 : SDP_MAX_LEVEL_ASYMMETRY_ALLOWED_VALUE,
1610 : "level-asymmetry-allowed", fmtp_p->level_asymmetry_allowed)
1611 :
1612 0 : FMTP_BUILD_UNSIGNED(fmtp_p->interleaving_depth > 0,
1613 : "sprop-interleaving-depth", fmtp_p->interleaving_depth)
1614 :
1615 0 : FMTP_BUILD_UNSIGNED(fmtp_p->flag & SDP_DEINT_BUF_REQ_FLAG,
1616 : "sprop-deint-buf-req", fmtp_p->deint_buf_req)
1617 :
1618 0 : FMTP_BUILD_UNSIGNED(fmtp_p->max_don_diff > 0,
1619 : "sprop-max-don-diff", fmtp_p->max_don_diff)
1620 :
1621 0 : FMTP_BUILD_UNSIGNED(fmtp_p->flag & SDP_INIT_BUF_TIME_FLAG,
1622 : "sprop-init-buf-time", fmtp_p->init_buf_time)
1623 :
1624 0 : FMTP_BUILD_UNSIGNED(fmtp_p->max_mbps > 0,
1625 : "max-mbps", fmtp_p->max_mbps)
1626 :
1627 0 : FMTP_BUILD_UNSIGNED(fmtp_p->max_fs > 0, "max-fs", fmtp_p->max_fs)
1628 :
1629 0 : FMTP_BUILD_UNSIGNED(fmtp_p->max_fr > 0, "max-fr", fmtp_p->max_fr)
1630 :
1631 0 : FMTP_BUILD_UNSIGNED(fmtp_p->max_cpb > 0, "max-cpb", fmtp_p->max_cpb)
1632 :
1633 0 : FMTP_BUILD_UNSIGNED(fmtp_p->max_dpb > 0, "max-dpb", fmtp_p->max_dpb)
1634 :
1635 0 : FMTP_BUILD_UNSIGNED(fmtp_p->max_br > 0, "max-br", fmtp_p->max_br)
1636 :
1637 0 : FMTP_BUILD_UNSIGNED(fmtp_p->redundant_pic_cap > 0,
1638 : "redundant-pic-cap", fmtp_p->redundant_pic_cap)
1639 :
1640 0 : FMTP_BUILD_UNSIGNED(fmtp_p->flag & SDP_DEINT_BUF_CAP_FLAG,
1641 : "deint-buf-cap", fmtp_p->deint_buf_cap)
1642 :
1643 0 : FMTP_BUILD_UNSIGNED(fmtp_p->flag & SDP_MAX_RCMD_NALU_SIZE_FLAG,
1644 : "max-rcmd-naFMTP_BUILD_FLlu-size", fmtp_p->max_rcmd_nalu_size)
1645 :
1646 0 : FMTP_BUILD_UNSIGNED(fmtp_p->parameter_add <= 1, "parameter-add",
1647 : fmtp_p->parameter_add)
1648 :
1649 0 : FMTP_BUILD_UNSIGNED(fmtp_p->maxaveragebitrate > 0,
1650 : "maxaveragebitrate", fmtp_p->maxaveragebitrate)
1651 :
1652 0 : FMTP_BUILD_UNSIGNED(fmtp_p->usedtx <= 1, "usedtx", fmtp_p->usedtx)
1653 :
1654 0 : FMTP_BUILD_UNSIGNED(fmtp_p->stereo <= 1, "stereo", fmtp_p->stereo)
1655 :
1656 0 : FMTP_BUILD_UNSIGNED(fmtp_p->useinbandfec <= 1,
1657 : "useinbandfec", fmtp_p->useinbandfec)
1658 :
1659 0 : FMTP_BUILD_STRING(strlen(fmtp_p->maxcodedaudiobandwidth) > 0,
1660 : "maxcodedaudiobandwidth", fmtp_p->maxcodedaudiobandwidth)
1661 :
1662 0 : FMTP_BUILD_UNSIGNED(fmtp_p->cbr <= 1, "cbr", fmtp_p->cbr)
1663 :
1664 0 : break;
1665 :
1666 : case SDP_FMTP_NTE:
1667 : default:
1668 0 : break;
1669 : }
1670 :
1671 0 : for(event_id = 0, mapword = 0, mask = SDP_NE_BIT_0;
1672 0 : event_id <= fmtp_p->maxval;
1673 0 : event_id++, mapword = event_id/SDP_NE_BITS_PER_WORD ) {
1674 :
1675 0 : if (event_id % SDP_NE_BITS_PER_WORD) {
1676 0 : mask <<= 1;
1677 : } else {
1678 : /* crossed a bitmap word boundary */
1679 0 : mask = SDP_NE_BIT_0;
1680 0 : if (!range_start && !range_end && !fmtp_p->bmap[mapword]) {
1681 : /* no events in this word, skip to the last event id
1682 : * in this bitmap word. */
1683 0 : event_id += SDP_NE_BITS_PER_WORD - 1;
1684 0 : continue;
1685 : }
1686 : }
1687 :
1688 0 : if (fmtp_p->bmap[mapword] & mask) {
1689 0 : if (!range_start) {
1690 0 : range_start = TRUE;
1691 0 : min = max = (uint8_t)event_id;
1692 : } else {
1693 0 : max = (uint8_t)event_id;
1694 : }
1695 0 : range_end = (max == fmtp_p->maxval);
1696 : } else {
1697 : /* If we were in the middle of a range, then we've hit the
1698 : * end. If we weren't, there is no end to hit. */
1699 0 : range_end = range_start;
1700 : }
1701 :
1702 : /* If this is the end of the range, print it to the string. */
1703 0 : if (range_end) {
1704 0 : range_start = range_end = FALSE;
1705 :
1706 0 : flex_string_sprintf(fs, "%u", min);
1707 :
1708 0 : if (min != max) {
1709 0 : flex_string_sprintf(fs, "-%u", max);
1710 : }
1711 :
1712 0 : if (max != fmtp_p->maxval) {
1713 0 : flex_string_append(fs, ",");
1714 : }
1715 : }
1716 : }
1717 0 : return SDP_SUCCESS;
1718 : }
1719 :
1720 0 : sdp_result_e sdp_build_attr_fmtp (sdp_t *sdp_p, sdp_attr_t *attr_p, flex_string *fs)
1721 : {
1722 : sdp_fmtp_t *fmtp_p;
1723 : sdp_result_e result;
1724 :
1725 0 : flex_string_sprintf(fs, "a=%s:%u ",
1726 0 : sdp_attr[attr_p->type].name,
1727 0 : attr_p->attr.fmtp.payload_num);
1728 :
1729 0 : fmtp_p = &(attr_p->attr.fmtp);
1730 :
1731 0 : result = sdp_build_attr_fmtp_params(sdp_p, fmtp_p, fs);
1732 :
1733 0 : if (result != SDP_SUCCESS) {
1734 0 : return result;
1735 : }
1736 :
1737 0 : flex_string_append(fs, "\r\n");
1738 :
1739 0 : return SDP_SUCCESS;
1740 : }
1741 :
1742 0 : sdp_result_e sdp_parse_attr_sctpmap(sdp_t *sdp_p, sdp_attr_t *attr_p,
1743 : const char *ptr)
1744 : {
1745 0 : sdp_result_e result = SDP_SUCCESS;
1746 : char tmp[SDP_MAX_STRING_LEN];
1747 : uint32_t streams;
1748 :
1749 : /* Find the payload type number. */
1750 0 : attr_p->attr.sctpmap.port = (uint16_t)sdp_getnextnumtok(ptr, &ptr,
1751 : " \t", &result);
1752 0 : if (result != SDP_SUCCESS) {
1753 0 : sdp_parse_error(sdp_p,
1754 : "%s Warning: no sctpmap port number",
1755 0 : sdp_p->debug_str);
1756 0 : return SDP_INVALID_PARAMETER;
1757 : }
1758 :
1759 0 : ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
1760 0 : if (result != SDP_SUCCESS) {
1761 0 : sdp_parse_error(sdp_p,
1762 : "%s Warning: No sctpmap protocol specified.",
1763 0 : sdp_p->debug_str);
1764 0 : sdp_p->conf_p->num_invalid_param++;
1765 0 : return SDP_INVALID_PARAMETER;
1766 : }
1767 0 : sstrncpy(attr_p->attr.sctpmap.protocol, tmp,
1768 : sizeof (attr_p->attr.sctpmap.protocol));
1769 :
1770 0 : streams = sdp_getnextnumtok(ptr, &ptr, " \t", &result);
1771 0 : if (result != SDP_SUCCESS) {
1772 0 : sdp_parse_error(sdp_p,
1773 : "%s Warning: No sctpmap streams specified.",
1774 0 : sdp_p->debug_str);
1775 0 : sdp_p->conf_p->num_invalid_param++;
1776 0 : return SDP_INVALID_PARAMETER;
1777 : }
1778 :
1779 0 : attr_p->attr.sctpmap.streams = streams;
1780 :
1781 0 : return SDP_SUCCESS;
1782 : }
1783 :
1784 0 : sdp_result_e sdp_build_attr_sctpmap(sdp_t *sdp_p, sdp_attr_t *attr_p,
1785 : flex_string *fs)
1786 : {
1787 0 : flex_string_sprintf(fs, "a=%s:%u %s %u\r\n",
1788 0 : sdp_attr[attr_p->type].name,
1789 0 : attr_p->attr.sctpmap.port,
1790 0 : attr_p->attr.sctpmap.protocol,
1791 : attr_p->attr.sctpmap.streams);
1792 :
1793 0 : return SDP_SUCCESS;
1794 : }
1795 :
1796 0 : sdp_result_e sdp_parse_attr_direction (sdp_t *sdp_p, sdp_attr_t *attr_p,
1797 : const char *ptr)
1798 : {
1799 : /* No parameters to parse. */
1800 0 : if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
1801 0 : SDP_PRINT("%s Parsed a=%s", sdp_p->debug_str,
1802 : sdp_get_attr_name(attr_p->type));
1803 : }
1804 :
1805 0 : return (SDP_SUCCESS);
1806 : }
1807 :
1808 0 : sdp_result_e sdp_build_attr_direction (sdp_t *sdp_p, sdp_attr_t *attr_p, flex_string *fs)
1809 : {
1810 0 : flex_string_sprintf(fs, "a=%s\r\n", sdp_get_attr_name(attr_p->type));
1811 :
1812 0 : return SDP_SUCCESS;
1813 : }
1814 :
1815 0 : sdp_result_e sdp_parse_attr_qos (sdp_t *sdp_p, sdp_attr_t *attr_p,
1816 : const char *ptr)
1817 : {
1818 : int i;
1819 : sdp_result_e result;
1820 : char tmp[SDP_MAX_STRING_LEN];
1821 :
1822 : /* Find the strength tag. */
1823 0 : ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
1824 0 : if (result != SDP_SUCCESS) {
1825 0 : sdp_parse_error(sdp_p,
1826 : "%s Warning: No qos strength tag specified.",
1827 0 : sdp_p->debug_str);
1828 0 : sdp_p->conf_p->num_invalid_param++;
1829 0 : return (SDP_INVALID_PARAMETER);
1830 : }
1831 0 : attr_p->attr.qos.strength = SDP_QOS_STRENGTH_UNKNOWN;
1832 0 : for (i=0; i < SDP_MAX_QOS_STRENGTH; i++) {
1833 0 : if (cpr_strncasecmp(tmp, sdp_qos_strength[i].name,
1834 0 : sdp_qos_strength[i].strlen) == 0) {
1835 0 : attr_p->attr.qos.strength = (sdp_qos_strength_e)i;
1836 : }
1837 : }
1838 0 : if (attr_p->attr.qos.strength == SDP_QOS_STRENGTH_UNKNOWN) {
1839 0 : sdp_parse_error(sdp_p,
1840 : "%s Warning: QOS strength tag unrecognized (%s)",
1841 0 : sdp_p->debug_str, tmp);
1842 0 : sdp_p->conf_p->num_invalid_param++;
1843 0 : return (SDP_INVALID_PARAMETER);
1844 : }
1845 :
1846 : /* Find the qos direction. */
1847 0 : ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
1848 0 : if (result != SDP_SUCCESS) {
1849 0 : sdp_parse_error(sdp_p,
1850 : "%s Warning: No qos direction specified.",
1851 0 : sdp_p->debug_str);
1852 0 : sdp_p->conf_p->num_invalid_param++;
1853 0 : return (SDP_INVALID_PARAMETER);
1854 : }
1855 0 : attr_p->attr.qos.direction = SDP_QOS_DIR_UNKNOWN;
1856 0 : for (i=0; i < SDP_MAX_QOS_DIR; i++) {
1857 0 : if (cpr_strncasecmp(tmp, sdp_qos_direction[i].name,
1858 0 : sdp_qos_direction[i].strlen) == 0) {
1859 0 : attr_p->attr.qos.direction = (sdp_qos_dir_e)i;
1860 : }
1861 : }
1862 0 : if (attr_p->attr.qos.direction == SDP_QOS_DIR_UNKNOWN) {
1863 0 : sdp_parse_error(sdp_p,
1864 : "%s Warning: QOS direction unrecognized (%s)",
1865 0 : sdp_p->debug_str, tmp);
1866 0 : sdp_p->conf_p->num_invalid_param++;
1867 0 : return (SDP_INVALID_PARAMETER);
1868 : }
1869 :
1870 : /* See if confirm was specified. Defaults to FALSE. */
1871 0 : attr_p->attr.qos.confirm = FALSE;
1872 0 : ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
1873 0 : if (result == SDP_SUCCESS) {
1874 0 : if (cpr_strncasecmp(tmp, "confirm", sizeof("confirm")) == 0) {
1875 0 : attr_p->attr.qos.confirm = TRUE;
1876 : }
1877 0 : if (attr_p->attr.qos.confirm == FALSE) {
1878 0 : sdp_parse_error(sdp_p,
1879 : "%s Warning: QOS confirm parameter invalid (%s)",
1880 0 : sdp_p->debug_str, tmp);
1881 0 : sdp_p->conf_p->num_invalid_param++;
1882 0 : return (SDP_INVALID_PARAMETER);
1883 : }
1884 : }
1885 :
1886 0 : if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
1887 0 : SDP_PRINT("%s Parsed a=%s, strength %s, direction %s, confirm %s",
1888 : sdp_p->debug_str, sdp_get_attr_name(attr_p->type),
1889 : sdp_get_qos_strength_name(attr_p->attr.qos.strength),
1890 : sdp_get_qos_direction_name(attr_p->attr.qos.direction),
1891 : (attr_p->attr.qos.confirm ? "set" : "not set"));
1892 : }
1893 :
1894 0 : return (SDP_SUCCESS);
1895 : }
1896 :
1897 0 : sdp_result_e sdp_build_attr_qos (sdp_t *sdp_p, sdp_attr_t *attr_p, flex_string *fs)
1898 : {
1899 0 : flex_string_sprintf(fs, "a=%s:%s %s%s\r\n", sdp_attr[attr_p->type].name,
1900 : sdp_get_qos_strength_name(attr_p->attr.qos.strength),
1901 : sdp_get_qos_direction_name(attr_p->attr.qos.direction),
1902 0 : attr_p->attr.qos.confirm ? " confirm" : "");
1903 :
1904 0 : return SDP_SUCCESS;
1905 : }
1906 :
1907 0 : sdp_result_e sdp_parse_attr_curr (sdp_t *sdp_p, sdp_attr_t *attr_p,
1908 : const char *ptr)
1909 : {
1910 : int i;
1911 : sdp_result_e result;
1912 : char tmp[SDP_MAX_STRING_LEN];
1913 :
1914 : /* Find the curr type tag. */
1915 0 : ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
1916 0 : if (result != SDP_SUCCESS) {
1917 0 : sdp_parse_error(sdp_p,
1918 : "%s Warning: No curr attr type specified.",
1919 0 : sdp_p->debug_str);
1920 0 : sdp_p->conf_p->num_invalid_param++;
1921 0 : return (SDP_INVALID_PARAMETER);
1922 : }
1923 0 : attr_p->attr.curr.type = SDP_CURR_UNKNOWN_TYPE;
1924 0 : for (i=0; i < SDP_MAX_CURR_TYPES; i++) {
1925 0 : if (cpr_strncasecmp(tmp, sdp_curr_type[i].name,
1926 0 : sdp_curr_type[i].strlen) == 0) {
1927 0 : attr_p->attr.curr.type = (sdp_curr_type_e)i;
1928 : }
1929 : }
1930 :
1931 0 : if (attr_p->attr.curr.type != SDP_CURR_QOS_TYPE) {
1932 0 : sdp_parse_error(sdp_p,
1933 : "%s Warning: Unknown curr type.",
1934 0 : sdp_p->debug_str);
1935 0 : sdp_p->conf_p->num_invalid_param++;
1936 0 : return (SDP_INVALID_PARAMETER);
1937 : }
1938 :
1939 : /* Check qos status type */
1940 0 : ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
1941 0 : if (result != SDP_SUCCESS) {
1942 0 : sdp_parse_error(sdp_p,
1943 : "%s Warning: No curr attr type specified.",
1944 0 : sdp_p->debug_str);
1945 0 : sdp_p->conf_p->num_invalid_param++;
1946 0 : return (SDP_INVALID_PARAMETER);
1947 : }
1948 0 : attr_p->attr.curr.status_type = SDP_QOS_STATUS_TYPE_UNKNOWN;
1949 0 : for (i=0; i < SDP_MAX_QOS_STATUS_TYPES; i++) {
1950 0 : if (cpr_strncasecmp(tmp, sdp_qos_status_type[i].name,
1951 0 : sdp_qos_status_type[i].strlen) == 0) {
1952 0 : attr_p->attr.curr.status_type = (sdp_qos_status_types_e)i;
1953 : }
1954 : }
1955 :
1956 :
1957 : /* Find the qos direction. */
1958 0 : ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
1959 0 : if (result != SDP_SUCCESS) {
1960 0 : sdp_parse_error(sdp_p,
1961 : "%s Warning: No qos direction specified.",
1962 0 : sdp_p->debug_str);
1963 0 : sdp_p->conf_p->num_invalid_param++;
1964 0 : return (SDP_INVALID_PARAMETER);
1965 : }
1966 0 : attr_p->attr.curr.direction = SDP_QOS_DIR_UNKNOWN;
1967 0 : for (i=0; i < SDP_MAX_QOS_DIR; i++) {
1968 0 : if (cpr_strncasecmp(tmp, sdp_qos_direction[i].name,
1969 0 : sdp_qos_direction[i].strlen) == 0) {
1970 0 : attr_p->attr.curr.direction = (sdp_qos_dir_e)i;
1971 : }
1972 : }
1973 0 : if (attr_p->attr.curr.direction == SDP_QOS_DIR_UNKNOWN) {
1974 0 : sdp_parse_error(sdp_p,
1975 : "%s Warning: QOS direction unrecognized (%s)",
1976 0 : sdp_p->debug_str, tmp);
1977 0 : sdp_p->conf_p->num_invalid_param++;
1978 0 : return (SDP_INVALID_PARAMETER);
1979 : }
1980 :
1981 0 : if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
1982 0 : SDP_PRINT("%s Parsed a=%s, type %s status type %s, direction %s",
1983 : sdp_p->debug_str, sdp_get_attr_name(attr_p->type),
1984 : sdp_get_curr_type_name(attr_p->attr.curr.type),
1985 : sdp_get_qos_status_type_name(attr_p->attr.curr.status_type),
1986 : sdp_get_qos_direction_name(attr_p->attr.curr.direction));
1987 : }
1988 :
1989 0 : return (SDP_SUCCESS);
1990 : }
1991 :
1992 0 : sdp_result_e sdp_build_attr_curr (sdp_t *sdp_p, sdp_attr_t *attr_p, flex_string *fs)
1993 : {
1994 0 : flex_string_sprintf(fs, "a=%s:%s %s %s\r\n",
1995 0 : sdp_attr[attr_p->type].name,
1996 : sdp_get_curr_type_name(attr_p->attr.curr.type),
1997 : sdp_get_qos_status_type_name(attr_p->attr.curr.status_type),
1998 : sdp_get_qos_direction_name(attr_p->attr.curr.direction));
1999 :
2000 0 : return SDP_SUCCESS;
2001 : }
2002 :
2003 0 : sdp_result_e sdp_parse_attr_des (sdp_t *sdp_p, sdp_attr_t *attr_p,
2004 : const char *ptr)
2005 : {
2006 : int i;
2007 : sdp_result_e result;
2008 : char tmp[SDP_MAX_STRING_LEN];
2009 :
2010 : /* Find the curr type tag. */
2011 0 : ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
2012 0 : if (result != SDP_SUCCESS) {
2013 0 : sdp_parse_error(sdp_p,
2014 : "%s Warning: No des attr type specified.",
2015 0 : sdp_p->debug_str);
2016 0 : sdp_p->conf_p->num_invalid_param++;
2017 0 : return (SDP_INVALID_PARAMETER);
2018 : }
2019 0 : attr_p->attr.des.type = SDP_DES_UNKNOWN_TYPE;
2020 0 : for (i=0; i < SDP_MAX_CURR_TYPES; i++) {
2021 0 : if (cpr_strncasecmp(tmp, sdp_des_type[i].name,
2022 0 : sdp_des_type[i].strlen) == 0) {
2023 0 : attr_p->attr.des.type = (sdp_des_type_e)i;
2024 : }
2025 : }
2026 :
2027 0 : if (attr_p->attr.des.type != SDP_DES_QOS_TYPE) {
2028 0 : sdp_parse_error(sdp_p,
2029 : "%s Warning: Unknown conf type.",
2030 0 : sdp_p->debug_str);
2031 0 : sdp_p->conf_p->num_invalid_param++;
2032 0 : return (SDP_INVALID_PARAMETER);
2033 : }
2034 :
2035 : /* Find the strength tag. */
2036 0 : ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
2037 0 : if (result != SDP_SUCCESS) {
2038 0 : sdp_parse_error(sdp_p,
2039 : "%s Warning: No qos strength tag specified.",
2040 0 : sdp_p->debug_str);
2041 0 : sdp_p->conf_p->num_invalid_param++;
2042 0 : return (SDP_INVALID_PARAMETER);
2043 : }
2044 0 : attr_p->attr.des.strength = SDP_QOS_STRENGTH_UNKNOWN;
2045 0 : for (i=0; i < SDP_MAX_QOS_STRENGTH; i++) {
2046 0 : if (cpr_strncasecmp(tmp, sdp_qos_strength[i].name,
2047 0 : sdp_qos_strength[i].strlen) == 0) {
2048 0 : attr_p->attr.des.strength = (sdp_qos_strength_e)i;
2049 : }
2050 : }
2051 0 : if (attr_p->attr.des.strength == SDP_QOS_STRENGTH_UNKNOWN) {
2052 0 : sdp_parse_error(sdp_p,
2053 : "%s Warning: QOS strength tag unrecognized (%s)",
2054 0 : sdp_p->debug_str, tmp);
2055 0 : sdp_p->conf_p->num_invalid_param++;
2056 0 : return (SDP_INVALID_PARAMETER);
2057 : }
2058 :
2059 : /* Check qos status type */
2060 0 : ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
2061 0 : if (result != SDP_SUCCESS) {
2062 0 : sdp_parse_error(sdp_p,
2063 : "%s Warning: No des attr type specified.",
2064 0 : sdp_p->debug_str);
2065 0 : sdp_p->conf_p->num_invalid_param++;
2066 0 : return (SDP_INVALID_PARAMETER);
2067 : }
2068 0 : attr_p->attr.des.status_type = SDP_QOS_STATUS_TYPE_UNKNOWN;
2069 0 : for (i=0; i < SDP_MAX_QOS_STATUS_TYPES; i++) {
2070 0 : if (cpr_strncasecmp(tmp, sdp_qos_status_type[i].name,
2071 0 : sdp_qos_status_type[i].strlen) == 0) {
2072 0 : attr_p->attr.des.status_type = (sdp_qos_status_types_e)i;
2073 : }
2074 : }
2075 :
2076 :
2077 : /* Find the qos direction. */
2078 0 : ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
2079 0 : if (result != SDP_SUCCESS) {
2080 0 : sdp_parse_error(sdp_p,
2081 : "%s Warning: No qos direction specified.",
2082 0 : sdp_p->debug_str);
2083 0 : sdp_p->conf_p->num_invalid_param++;
2084 0 : return (SDP_INVALID_PARAMETER);
2085 : }
2086 0 : attr_p->attr.des.direction = SDP_QOS_DIR_UNKNOWN;
2087 0 : for (i=0; i < SDP_MAX_QOS_DIR; i++) {
2088 0 : if (cpr_strncasecmp(tmp, sdp_qos_direction[i].name,
2089 0 : sdp_qos_direction[i].strlen) == 0) {
2090 0 : attr_p->attr.des.direction = (sdp_qos_dir_e)i;
2091 : }
2092 : }
2093 0 : if (attr_p->attr.des.direction == SDP_QOS_DIR_UNKNOWN) {
2094 0 : sdp_parse_error(sdp_p,
2095 : "%s Warning: QOS direction unrecognized (%s)",
2096 0 : sdp_p->debug_str, tmp);
2097 0 : sdp_p->conf_p->num_invalid_param++;
2098 0 : return (SDP_INVALID_PARAMETER);
2099 : }
2100 :
2101 0 : if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
2102 0 : SDP_PRINT("%s Parsed a=%s, type %s strength %s status type %s, direction %s",
2103 : sdp_p->debug_str, sdp_get_attr_name(attr_p->type),
2104 : sdp_get_des_type_name(attr_p->attr.des.type),
2105 : sdp_get_qos_strength_name(attr_p->attr.qos.strength),
2106 : sdp_get_qos_status_type_name(attr_p->attr.des.status_type),
2107 : sdp_get_qos_direction_name(attr_p->attr.des.direction));
2108 : }
2109 :
2110 0 : return (SDP_SUCCESS);
2111 : }
2112 :
2113 :
2114 0 : sdp_result_e sdp_build_attr_des (sdp_t *sdp_p, sdp_attr_t *attr_p, flex_string *fs)
2115 : {
2116 0 : flex_string_sprintf(fs, "a=%s:%s %s %s %s\r\n",
2117 0 : sdp_attr[attr_p->type].name,
2118 0 : sdp_get_curr_type_name((sdp_curr_type_e)attr_p->attr.des.type),
2119 : sdp_get_qos_strength_name(attr_p->attr.des.strength),
2120 : sdp_get_qos_status_type_name(attr_p->attr.des.status_type),
2121 : sdp_get_qos_direction_name(attr_p->attr.des.direction));
2122 :
2123 0 : return SDP_SUCCESS;
2124 : }
2125 :
2126 0 : sdp_result_e sdp_parse_attr_conf (sdp_t *sdp_p, sdp_attr_t *attr_p,
2127 : const char *ptr)
2128 : {
2129 : int i;
2130 : sdp_result_e result;
2131 : char tmp[SDP_MAX_STRING_LEN];
2132 :
2133 : /* Find the curr type tag. */
2134 0 : ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
2135 0 : if (result != SDP_SUCCESS) {
2136 0 : sdp_parse_error(sdp_p,
2137 : "%s Warning: No conf attr type specified.",
2138 0 : sdp_p->debug_str);
2139 0 : sdp_p->conf_p->num_invalid_param++;
2140 0 : return (SDP_INVALID_PARAMETER);
2141 : }
2142 0 : attr_p->attr.conf.type = SDP_CONF_UNKNOWN_TYPE;
2143 0 : for (i=0; i < SDP_MAX_CURR_TYPES; i++) {
2144 0 : if (cpr_strncasecmp(tmp, sdp_conf_type[i].name,
2145 0 : sdp_conf_type[i].strlen) == 0) {
2146 0 : attr_p->attr.conf.type = (sdp_conf_type_e)i;
2147 : }
2148 : }
2149 :
2150 0 : if (attr_p->attr.conf.type != SDP_CONF_QOS_TYPE) {
2151 0 : sdp_parse_error(sdp_p,
2152 : "%s Warning: Unknown conf type.",
2153 0 : sdp_p->debug_str);
2154 0 : sdp_p->conf_p->num_invalid_param++;
2155 0 : return (SDP_INVALID_PARAMETER);
2156 : }
2157 :
2158 : /* Check qos status type */
2159 0 : ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
2160 0 : if (result != SDP_SUCCESS) {
2161 0 : sdp_parse_error(sdp_p,
2162 : "%s Warning: No conf attr type specified.",
2163 0 : sdp_p->debug_str);
2164 0 : sdp_p->conf_p->num_invalid_param++;
2165 0 : return (SDP_INVALID_PARAMETER);
2166 : }
2167 0 : attr_p->attr.conf.status_type = SDP_QOS_STATUS_TYPE_UNKNOWN;
2168 0 : for (i=0; i < SDP_MAX_QOS_STATUS_TYPES; i++) {
2169 0 : if (cpr_strncasecmp(tmp, sdp_qos_status_type[i].name,
2170 0 : sdp_qos_status_type[i].strlen) == 0) {
2171 0 : attr_p->attr.conf.status_type = (sdp_qos_status_types_e)i;
2172 : }
2173 : }
2174 :
2175 :
2176 : /* Find the qos direction. */
2177 0 : ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
2178 0 : if (result != SDP_SUCCESS) {
2179 0 : sdp_parse_error(sdp_p,
2180 : "%s Warning: No qos direction specified.",
2181 0 : sdp_p->debug_str);
2182 0 : sdp_p->conf_p->num_invalid_param++;
2183 0 : return (SDP_INVALID_PARAMETER);
2184 : }
2185 0 : attr_p->attr.conf.direction = SDP_QOS_DIR_UNKNOWN;
2186 0 : for (i=0; i < SDP_MAX_QOS_DIR; i++) {
2187 0 : if (cpr_strncasecmp(tmp, sdp_qos_direction[i].name,
2188 0 : sdp_qos_direction[i].strlen) == 0) {
2189 0 : attr_p->attr.conf.direction = (sdp_qos_dir_e)i;
2190 : }
2191 : }
2192 0 : if (attr_p->attr.conf.direction == SDP_QOS_DIR_UNKNOWN) {
2193 0 : sdp_parse_error(sdp_p,
2194 : "%s Warning: QOS direction unrecognized (%s)",
2195 0 : sdp_p->debug_str, tmp);
2196 0 : sdp_p->conf_p->num_invalid_param++;
2197 0 : return (SDP_INVALID_PARAMETER);
2198 : }
2199 :
2200 0 : if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
2201 0 : SDP_PRINT("%s Parsed a=%s, type %s status type %s, direction %s",
2202 : sdp_p->debug_str, sdp_get_attr_name(attr_p->type),
2203 : sdp_get_conf_type_name(attr_p->attr.conf.type),
2204 : sdp_get_qos_status_type_name(attr_p->attr.conf.status_type),
2205 : sdp_get_qos_direction_name(attr_p->attr.conf.direction));
2206 : }
2207 :
2208 0 : return (SDP_SUCCESS);
2209 : }
2210 :
2211 0 : sdp_result_e sdp_build_attr_conf (sdp_t *sdp_p, sdp_attr_t *attr_p, flex_string *fs)
2212 : {
2213 0 : flex_string_sprintf(fs, "a=%s:%s %s %s\r\n",
2214 0 : sdp_attr[attr_p->type].name,
2215 : sdp_get_conf_type_name(attr_p->attr.conf.type),
2216 : sdp_get_qos_status_type_name(attr_p->attr.conf.status_type),
2217 : sdp_get_qos_direction_name(attr_p->attr.conf.direction));
2218 :
2219 0 : return SDP_SUCCESS;
2220 : }
2221 :
2222 : /*
2223 : * Parse a rtpmap or a sprtmap. Both formats use the same structure
2224 : * the only difference being the keyword "rtpmap" vs "sprtmap". The
2225 : * rtpmap field in the sdp_attr_t is used to store both mappings.
2226 : */
2227 0 : sdp_result_e sdp_parse_attr_transport_map (sdp_t *sdp_p, sdp_attr_t *attr_p,
2228 : const char *ptr)
2229 : {
2230 : sdp_result_e result;
2231 :
2232 0 : attr_p->attr.transport_map.payload_num = 0;
2233 0 : attr_p->attr.transport_map.encname[0] = '\0';
2234 0 : attr_p->attr.transport_map.clockrate = 0;
2235 0 : attr_p->attr.transport_map.num_chan = 1;
2236 :
2237 : /* Find the payload type number. */
2238 0 : attr_p->attr.transport_map.payload_num =
2239 0 : (uint16_t)sdp_getnextnumtok(ptr, &ptr, " \t", &result);
2240 0 : if (result != SDP_SUCCESS) {
2241 0 : sdp_parse_error(sdp_p,
2242 : "%s Warning: Invalid payload type specified for %s attribute.",
2243 0 : sdp_p->debug_str, sdp_get_attr_name(attr_p->type));
2244 0 : sdp_p->conf_p->num_invalid_param++;
2245 0 : return (SDP_INVALID_PARAMETER);
2246 : }
2247 :
2248 : /* Find the encoding name. */
2249 0 : ptr = sdp_getnextstrtok(ptr, attr_p->attr.transport_map.encname,
2250 : sizeof(attr_p->attr.transport_map.encname), "/ \t", &result);
2251 0 : if (result != SDP_SUCCESS) {
2252 0 : sdp_parse_error(sdp_p,
2253 : "%s Warning: No encoding name specified in %s attribute.",
2254 0 : sdp_p->debug_str, sdp_get_attr_name(attr_p->type));
2255 0 : sdp_p->conf_p->num_invalid_param++;
2256 0 : return (SDP_INVALID_PARAMETER);
2257 : }
2258 :
2259 : /* Find the clockrate. */
2260 0 : attr_p->attr.transport_map.clockrate =
2261 0 : sdp_getnextnumtok(ptr, &ptr, "/ \t", &result);
2262 0 : if (result != SDP_SUCCESS) {
2263 0 : sdp_parse_error(sdp_p,
2264 : "%s Warning: No clockrate specified for "
2265 : "%s attribute, set to default of 8000.",
2266 0 : sdp_p->debug_str, sdp_get_attr_name(attr_p->type));
2267 0 : attr_p->attr.transport_map.clockrate = 8000;
2268 : }
2269 :
2270 : /* Find the number of channels, if specified. This is optional. */
2271 0 : if (*ptr == '/') {
2272 : /* If a '/' exists, expect something valid beyond it. */
2273 0 : attr_p->attr.transport_map.num_chan =
2274 0 : (uint16_t)sdp_getnextnumtok(ptr, &ptr, "/ \t", &result);
2275 0 : if (result != SDP_SUCCESS) {
2276 0 : sdp_parse_error(sdp_p,
2277 : "%s Warning: Invalid number of channels parameter"
2278 0 : " for rtpmap attribute.", sdp_p->debug_str);
2279 0 : sdp_p->conf_p->num_invalid_param++;
2280 0 : return (SDP_INVALID_PARAMETER);
2281 : }
2282 : }
2283 :
2284 0 : if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
2285 0 : SDP_PRINT("%s Parsed a=%s, payload type %u, encoding name %s, "
2286 : "clockrate %u", sdp_p->debug_str,
2287 : sdp_get_attr_name(attr_p->type),
2288 : attr_p->attr.transport_map.payload_num,
2289 : attr_p->attr.transport_map.encname,
2290 : attr_p->attr.transport_map.clockrate);
2291 0 : if (attr_p->attr.transport_map.num_chan != 1) {
2292 0 : SDP_PRINT("/%u", attr_p->attr.transport_map.num_chan);
2293 : }
2294 : }
2295 :
2296 0 : return (SDP_SUCCESS);
2297 : }
2298 :
2299 : /*
2300 : * Build a rtpmap or a sprtmap. Both formats use the same structure
2301 : * the only difference being the keyword "rtpmap" vs "sprtmap". The
2302 : * rtpmap field in the sdp_attr_t is used for both mappings.
2303 : */
2304 0 : sdp_result_e sdp_build_attr_transport_map (sdp_t *sdp_p, sdp_attr_t *attr_p,
2305 : flex_string *fs)
2306 : {
2307 0 : if (attr_p->attr.transport_map.num_chan == 1) {
2308 0 : flex_string_sprintf(fs, "a=%s:%u %s/%u\r\n",
2309 0 : sdp_attr[attr_p->type].name,
2310 0 : attr_p->attr.transport_map.payload_num,
2311 0 : attr_p->attr.transport_map.encname,
2312 : attr_p->attr.transport_map.clockrate);
2313 : } else {
2314 0 : flex_string_sprintf(fs, "a=%s:%u %s/%u/%u\r\n",
2315 0 : sdp_attr[attr_p->type].name,
2316 0 : attr_p->attr.transport_map.payload_num,
2317 0 : attr_p->attr.transport_map.encname,
2318 : attr_p->attr.transport_map.clockrate,
2319 0 : attr_p->attr.transport_map.num_chan);
2320 : }
2321 :
2322 0 : return SDP_SUCCESS;
2323 : }
2324 :
2325 0 : sdp_result_e sdp_parse_attr_subnet (sdp_t *sdp_p, sdp_attr_t *attr_p,
2326 : const char *ptr)
2327 : {
2328 : int i;
2329 : char *slash_ptr;
2330 : sdp_result_e result;
2331 0 : tinybool type_found = FALSE;
2332 : char tmp[SDP_MAX_STRING_LEN];
2333 :
2334 : /* Find the subnet network type. */
2335 0 : ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
2336 0 : if (result != SDP_SUCCESS) {
2337 0 : sdp_parse_error(sdp_p,
2338 : "%s Warning: No network type specified in subnet attribute.",
2339 0 : sdp_p->debug_str);
2340 0 : sdp_p->conf_p->num_invalid_param++;
2341 0 : return (SDP_INVALID_PARAMETER);
2342 : }
2343 0 : attr_p->attr.subnet.nettype = SDP_NT_UNSUPPORTED;
2344 0 : for (i=0; i < SDP_MAX_NETWORK_TYPES; i++) {
2345 0 : if (cpr_strncasecmp(tmp, sdp_nettype[i].name,
2346 0 : sdp_nettype[i].strlen) == 0) {
2347 0 : type_found = TRUE;
2348 : }
2349 0 : if (type_found == TRUE) {
2350 0 : if (sdp_p->conf_p->nettype_supported[i] == TRUE) {
2351 0 : attr_p->attr.subnet.nettype = (sdp_nettype_e)i;
2352 : }
2353 0 : type_found = FALSE;
2354 : }
2355 : }
2356 0 : if (attr_p->attr.subnet.nettype == SDP_NT_UNSUPPORTED) {
2357 0 : sdp_parse_error(sdp_p,
2358 : "%s Warning: Subnet network type unsupported (%s).",
2359 0 : sdp_p->debug_str, tmp);
2360 0 : sdp_p->conf_p->num_invalid_param++;
2361 0 : return (SDP_INVALID_PARAMETER);
2362 : }
2363 :
2364 : /* Find the subnet address type. */
2365 0 : ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
2366 0 : if (result != SDP_SUCCESS) {
2367 0 : sdp_parse_error(sdp_p,
2368 : "%s Warning: No address type specified in subnet attribute.",
2369 0 : sdp_p->debug_str);
2370 0 : sdp_p->conf_p->num_invalid_param++;
2371 0 : return (SDP_INVALID_PARAMETER);
2372 : }
2373 0 : attr_p->attr.subnet.addrtype = SDP_AT_UNSUPPORTED;
2374 0 : for (i=0; i < SDP_MAX_ADDR_TYPES; i++) {
2375 0 : if (cpr_strncasecmp(tmp, sdp_addrtype[i].name,
2376 0 : sdp_addrtype[i].strlen) == 0) {
2377 0 : type_found = TRUE;
2378 : }
2379 0 : if (type_found == TRUE) {
2380 0 : if (sdp_p->conf_p->addrtype_supported[i] == TRUE) {
2381 0 : attr_p->attr.subnet.addrtype = (sdp_addrtype_e)i;
2382 : }
2383 0 : type_found = FALSE;
2384 : }
2385 : }
2386 0 : if (attr_p->attr.subnet.addrtype == SDP_AT_UNSUPPORTED) {
2387 0 : sdp_parse_error(sdp_p,
2388 : "%s Warning: Subnet address type unsupported (%s).",
2389 0 : sdp_p->debug_str, tmp);
2390 0 : sdp_p->conf_p->num_invalid_param++;
2391 0 : return (SDP_INVALID_PARAMETER);
2392 : }
2393 :
2394 : /* Find the subnet address. */
2395 0 : ptr = sdp_getnextstrtok(ptr, attr_p->attr.subnet.addr,
2396 : sizeof(attr_p->attr.subnet.addr), " \t", &result);
2397 0 : if (result != SDP_SUCCESS) {
2398 0 : sdp_parse_error(sdp_p,
2399 : "%s Warning: No subnet address specified in "
2400 0 : "subnet attribute.", sdp_p->debug_str);
2401 0 : sdp_p->conf_p->num_invalid_param++;
2402 0 : return (SDP_INVALID_PARAMETER);
2403 : }
2404 0 : slash_ptr = sdp_findchar(attr_p->attr.subnet.addr, "/");
2405 0 : if (*slash_ptr == '/') {
2406 0 : *slash_ptr++ = '\0';
2407 : /* If the '/' exists, expect a valid prefix to follow. */
2408 0 : attr_p->attr.subnet.prefix = sdp_getnextnumtok(slash_ptr,
2409 : (const char **)&slash_ptr,
2410 : " \t", &result);
2411 0 : if (result != SDP_SUCCESS) {
2412 0 : sdp_parse_error(sdp_p,
2413 : "%s Warning: Invalid subnet prefix specified in "
2414 0 : "subnet attribute.", sdp_p->debug_str);
2415 0 : sdp_p->conf_p->num_invalid_param++;
2416 0 : return (SDP_INVALID_PARAMETER);
2417 : }
2418 : } else {
2419 0 : attr_p->attr.subnet.prefix = SDP_INVALID_VALUE;
2420 : }
2421 :
2422 0 : if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
2423 0 : SDP_PRINT("%s Parsed a=%s, network %s, addr type %s, address %s ",
2424 : sdp_p->debug_str, sdp_get_attr_name(attr_p->type),
2425 : sdp_get_network_name(attr_p->attr.subnet.nettype),
2426 : sdp_get_address_name(attr_p->attr.subnet.addrtype),
2427 : attr_p->attr.subnet.addr);
2428 0 : if (attr_p->attr.subnet.prefix != SDP_INVALID_VALUE) {
2429 0 : SDP_PRINT("/%u", (ushort)attr_p->attr.subnet.prefix);
2430 : }
2431 : }
2432 :
2433 0 : return (SDP_SUCCESS);
2434 : }
2435 :
2436 0 : sdp_result_e sdp_build_attr_subnet (sdp_t *sdp_p, sdp_attr_t *attr_p,
2437 : flex_string *fs)
2438 : {
2439 0 : if (attr_p->attr.subnet.prefix == SDP_INVALID_VALUE) {
2440 0 : flex_string_sprintf(fs, "a=%s:%s %s %s\r\n",
2441 0 : sdp_attr[attr_p->type].name,
2442 : sdp_get_network_name(attr_p->attr.subnet.nettype),
2443 : sdp_get_address_name(attr_p->attr.subnet.addrtype),
2444 0 : attr_p->attr.subnet.addr);
2445 : } else {
2446 0 : flex_string_sprintf(fs, "a=%s:%s %s %s/%u\r\n",
2447 0 : sdp_attr[attr_p->type].name,
2448 : sdp_get_network_name(attr_p->attr.subnet.nettype),
2449 : sdp_get_address_name(attr_p->attr.subnet.addrtype),
2450 0 : attr_p->attr.subnet.addr,
2451 0 : (ushort)attr_p->attr.subnet.prefix);
2452 : }
2453 :
2454 0 : return SDP_SUCCESS;
2455 : }
2456 :
2457 0 : sdp_result_e sdp_parse_attr_t38_ratemgmt (sdp_t *sdp_p, sdp_attr_t *attr_p,
2458 : const char *ptr)
2459 : {
2460 : int i;
2461 : sdp_result_e result;
2462 : char tmp[SDP_MAX_STRING_LEN];
2463 :
2464 : /* Find the rate mgmt. */
2465 0 : ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
2466 0 : if (result != SDP_SUCCESS) {
2467 0 : sdp_parse_error(sdp_p,
2468 : "%s Warning: No t38 rate management specified.",
2469 0 : sdp_p->debug_str);
2470 0 : sdp_p->conf_p->num_invalid_param++;
2471 0 : return (SDP_INVALID_PARAMETER);
2472 : }
2473 0 : attr_p->attr.t38ratemgmt = SDP_T38_UNKNOWN_RATE;
2474 0 : for (i=0; i < SDP_T38_MAX_RATES; i++) {
2475 0 : if (cpr_strncasecmp(tmp, sdp_t38_rate[i].name,
2476 0 : sdp_t38_rate[i].strlen) == 0) {
2477 0 : attr_p->attr.t38ratemgmt = (sdp_t38_ratemgmt_e)i;
2478 : }
2479 : }
2480 :
2481 0 : if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
2482 0 : SDP_PRINT("%s Parsed a=%s, rate %s", sdp_p->debug_str,
2483 : sdp_get_attr_name(attr_p->type),
2484 : sdp_get_t38_ratemgmt_name(attr_p->attr.t38ratemgmt));
2485 : }
2486 :
2487 0 : return (SDP_SUCCESS);
2488 : }
2489 :
2490 0 : sdp_result_e sdp_build_attr_t38_ratemgmt (sdp_t *sdp_p, sdp_attr_t *attr_p,
2491 : flex_string *fs)
2492 : {
2493 0 : flex_string_sprintf(fs, "a=%s:%s\r\n",
2494 0 : sdp_attr[attr_p->type].name,
2495 : sdp_get_t38_ratemgmt_name(attr_p->attr.t38ratemgmt));
2496 :
2497 0 : return SDP_SUCCESS;
2498 : }
2499 :
2500 0 : sdp_result_e sdp_parse_attr_t38_udpec (sdp_t *sdp_p, sdp_attr_t *attr_p,
2501 : const char *ptr)
2502 : {
2503 : int i;
2504 : sdp_result_e result;
2505 : char tmp[SDP_MAX_STRING_LEN];
2506 :
2507 : /* Find the udpec. */
2508 0 : ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
2509 0 : if (result != SDP_SUCCESS) {
2510 0 : sdp_parse_error(sdp_p,
2511 : "%s Warning: No t38 udpEC specified.",
2512 0 : sdp_p->debug_str);
2513 0 : sdp_p->conf_p->num_invalid_param++;
2514 0 : return (SDP_INVALID_PARAMETER);
2515 : }
2516 0 : attr_p->attr.t38udpec = SDP_T38_UDPEC_UNKNOWN;
2517 0 : for (i=0; i < SDP_T38_MAX_UDPEC; i++) {
2518 0 : if (cpr_strncasecmp(tmp, sdp_t38_udpec[i].name,
2519 0 : sdp_t38_udpec[i].strlen) == 0) {
2520 0 : attr_p->attr.t38udpec = (sdp_t38_udpec_e)i;
2521 : }
2522 : }
2523 :
2524 0 : if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
2525 0 : SDP_PRINT("%s Parsed a=%s, udpec %s", sdp_p->debug_str,
2526 : sdp_get_attr_name(attr_p->type),
2527 : sdp_get_t38_udpec_name(attr_p->attr.t38udpec));
2528 : }
2529 :
2530 0 : return (SDP_SUCCESS);
2531 : }
2532 :
2533 0 : sdp_result_e sdp_build_attr_t38_udpec (sdp_t *sdp_p, sdp_attr_t *attr_p,
2534 : flex_string *fs)
2535 : {
2536 0 : flex_string_sprintf(fs, "a=%s:%s\r\n",
2537 0 : sdp_attr[attr_p->type].name,
2538 : sdp_get_t38_udpec_name(attr_p->attr.t38udpec));
2539 :
2540 0 : return SDP_SUCCESS;
2541 : }
2542 :
2543 0 : sdp_result_e sdp_parse_attr_pc_codec (sdp_t *sdp_p, sdp_attr_t *attr_p,
2544 : const char *ptr)
2545 : {
2546 : uint16_t i;
2547 : sdp_result_e result;
2548 :
2549 0 : for (i=0; i < SDP_MAX_PAYLOAD_TYPES; i++) {
2550 0 : attr_p->attr.pccodec.payload_type[i] = (ushort)sdp_getnextnumtok(ptr, &ptr,
2551 : " \t", &result);
2552 0 : if (result != SDP_SUCCESS) {
2553 0 : break;
2554 : }
2555 0 : attr_p->attr.pccodec.num_payloads++;
2556 : }
2557 :
2558 0 : if (attr_p->attr.pccodec.num_payloads == 0) {
2559 0 : sdp_parse_error(sdp_p,
2560 : "%s Warning: No payloads specified for %s attr.",
2561 0 : sdp_p->debug_str, sdp_attr[attr_p->type].name);
2562 0 : sdp_p->conf_p->num_invalid_param++;
2563 0 : return (SDP_INVALID_PARAMETER);
2564 : }
2565 :
2566 0 : if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
2567 0 : SDP_PRINT("%s Parsed a=%s, num payloads %u, payloads: ",
2568 : sdp_p->debug_str, sdp_get_attr_name(attr_p->type),
2569 : attr_p->attr.pccodec.num_payloads);
2570 0 : for (i=0; i < attr_p->attr.pccodec.num_payloads; i++) {
2571 0 : SDP_PRINT("%u ", attr_p->attr.pccodec.payload_type[i]);
2572 : }
2573 : }
2574 :
2575 0 : return (SDP_SUCCESS);
2576 : }
2577 :
2578 0 : sdp_result_e sdp_build_attr_pc_codec (sdp_t *sdp_p, sdp_attr_t *attr_p,
2579 : flex_string *fs)
2580 : {
2581 : int i;
2582 :
2583 0 : flex_string_sprintf(fs, "a=%s: ", sdp_attr[attr_p->type].name);
2584 :
2585 0 : for (i=0; i < attr_p->attr.pccodec.num_payloads; i++) {
2586 0 : flex_string_sprintf(fs, "%u ", attr_p->attr.pccodec.payload_type[i]);
2587 : }
2588 :
2589 0 : flex_string_append(fs, "\r\n");
2590 :
2591 0 : return SDP_SUCCESS;
2592 : }
2593 :
2594 :
2595 0 : sdp_result_e sdp_parse_attr_cap (sdp_t *sdp_p, sdp_attr_t *attr_p,
2596 : const char *ptr)
2597 : {
2598 : uint16_t i;
2599 : sdp_result_e result;
2600 : sdp_mca_t *cap_p;
2601 : char tmp[SDP_MAX_STRING_LEN];
2602 :
2603 : /* Set the capability pointer to NULL for now in case we encounter
2604 : * an error in parsing.
2605 : */
2606 0 : attr_p->attr.cap_p = NULL;
2607 : /* Set the capability valid flag to FALSE in case we encounter an
2608 : * error. If we do, we don't want to process any X-cpar/cpar attributes
2609 : * from this point until we process the next valid X-cap/cdsc attr. */
2610 0 : sdp_p->cap_valid = FALSE;
2611 :
2612 : /* Allocate resource for new capability. Note that the capability
2613 : * uses the same structure used for media lines.
2614 : */
2615 0 : cap_p = sdp_alloc_mca(sdp_p->parse_line);
2616 0 : if (cap_p == NULL) {
2617 0 : sdp_p->conf_p->num_no_resource++;
2618 0 : return (SDP_NO_RESOURCE);
2619 : }
2620 :
2621 : /* Find the capability number. We don't need to store this since we
2622 : * calculate it for ourselves as we need to. But it must be specified. */
2623 0 : (void)sdp_getnextnumtok(ptr, &ptr, "/ \t", &result);
2624 0 : if (result != SDP_SUCCESS) {
2625 0 : sdp_parse_error(sdp_p,
2626 : "%s Warning: Capability not specified for %s, "
2627 0 : "unable to parse.", sdp_p->debug_str,
2628 : sdp_get_attr_name(attr_p->type));
2629 0 : SDP_FREE(cap_p);
2630 0 : sdp_p->conf_p->num_invalid_param++;
2631 0 : return (SDP_INVALID_PARAMETER);
2632 : }
2633 :
2634 : /* Find the media type. */
2635 0 : ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
2636 0 : if (result != SDP_SUCCESS) {
2637 0 : sdp_parse_error(sdp_p,
2638 : "%s No media type specified for %s attribute, "
2639 : "unable to parse.",
2640 0 : sdp_p->debug_str, sdp_get_attr_name(attr_p->type));
2641 0 : SDP_FREE(cap_p);
2642 0 : sdp_p->conf_p->num_invalid_param++;
2643 0 : return (SDP_INVALID_PARAMETER);
2644 : }
2645 0 : cap_p->media = SDP_MEDIA_UNSUPPORTED;
2646 0 : for (i=0; i < SDP_MAX_MEDIA_TYPES; i++) {
2647 0 : if (cpr_strncasecmp(tmp, sdp_media[i].name, sdp_media[i].strlen) == 0) {
2648 0 : cap_p->media = (sdp_media_e)i;
2649 0 : break;
2650 : }
2651 : }
2652 0 : if (cap_p->media == SDP_MEDIA_UNSUPPORTED) {
2653 0 : sdp_parse_error(sdp_p,
2654 : "%s Warning: Media type unsupported (%s).",
2655 0 : sdp_p->debug_str, tmp);
2656 0 : SDP_FREE(cap_p);
2657 0 : sdp_p->conf_p->num_invalid_param++;
2658 0 : return (SDP_INVALID_PARAMETER);
2659 : }
2660 :
2661 : /* Find the transport protocol type. */
2662 0 : ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
2663 0 : if (result != SDP_SUCCESS) {
2664 0 : sdp_parse_error(sdp_p,
2665 : "%s No transport protocol type specified, "
2666 0 : "unable to parse.", sdp_p->debug_str);
2667 0 : SDP_FREE(cap_p);
2668 0 : sdp_p->conf_p->num_invalid_param++;
2669 0 : return (SDP_INVALID_PARAMETER);
2670 : }
2671 0 : cap_p->transport = SDP_TRANSPORT_UNSUPPORTED;
2672 0 : for (i=0; i < SDP_MAX_TRANSPORT_TYPES; i++) {
2673 0 : if (cpr_strncasecmp(tmp, sdp_transport[i].name,
2674 0 : sdp_transport[i].strlen) == 0) {
2675 0 : cap_p->transport = (sdp_transport_e)i;
2676 0 : break;
2677 : }
2678 : }
2679 0 : if (cap_p->transport == SDP_TRANSPORT_UNSUPPORTED) {
2680 0 : sdp_parse_error(sdp_p,
2681 : "%s Warning: Transport protocol type unsupported (%s).",
2682 0 : sdp_p->debug_str, tmp);
2683 0 : SDP_FREE(cap_p);
2684 0 : sdp_p->conf_p->num_invalid_param++;
2685 0 : return (SDP_INVALID_PARAMETER);
2686 : }
2687 :
2688 : /* Find payload formats. AAL2 X-cap lines allow multiple
2689 : * transport/profile types per line, so these are handled differently.
2690 : */
2691 0 : if ((cap_p->transport == SDP_TRANSPORT_AAL2_ITU) ||
2692 0 : (cap_p->transport == SDP_TRANSPORT_AAL2_ATMF) ||
2693 0 : (cap_p->transport == SDP_TRANSPORT_AAL2_CUSTOM)) {
2694 : /* Capability processing is not currently defined for AAL2 types
2695 : * with multiple profiles. We don't process. */
2696 0 : sdp_parse_error(sdp_p,
2697 : "%s Warning: AAL2 profiles unsupported with "
2698 0 : "%s attributes.", sdp_p->debug_str,
2699 : sdp_get_attr_name(attr_p->type));
2700 0 : SDP_FREE(cap_p);
2701 0 : sdp_p->conf_p->num_invalid_param++;
2702 0 : return (SDP_INVALID_PARAMETER);
2703 : } else {
2704 : /* Transport is a non-AAL2 type. Parse payloads normally. */
2705 0 : sdp_parse_payload_types(sdp_p, cap_p, ptr);
2706 0 : if (cap_p->num_payloads == 0) {
2707 0 : SDP_FREE(cap_p);
2708 0 : sdp_p->conf_p->num_invalid_param++;
2709 0 : return (SDP_INVALID_PARAMETER);
2710 : }
2711 : }
2712 :
2713 0 : attr_p->attr.cap_p = cap_p;
2714 : /*
2715 : * This capability attr is valid. We can now handle X-cpar or
2716 : * cpar attrs.
2717 : */
2718 0 : sdp_p->cap_valid = TRUE;
2719 0 : sdp_p->last_cap_inst++;
2720 :
2721 0 : if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
2722 0 : SDP_PRINT("%s Parsed %s media type %s, Transport %s, "
2723 : "Num payloads %u", sdp_p->debug_str,
2724 : sdp_get_attr_name(attr_p->type),
2725 : sdp_get_media_name(cap_p->media),
2726 : sdp_get_transport_name(cap_p->transport),
2727 : cap_p->num_payloads);
2728 : }
2729 0 : return (SDP_SUCCESS);
2730 : }
2731 :
2732 0 : sdp_result_e sdp_build_attr_cap (sdp_t *sdp_p, sdp_attr_t *attr_p,
2733 : flex_string *fs)
2734 : {
2735 : uint16_t i, j;
2736 : sdp_mca_t *cap_p;
2737 : sdp_media_profiles_t *profile_p;
2738 :
2739 : /* Get a pointer to the capability structure. */
2740 0 : cap_p = attr_p->attr.cap_p;
2741 :
2742 0 : if (cap_p == NULL) {
2743 0 : CSFLogError(logTag, "%s Invalid %s attribute, unable to build.",
2744 : sdp_p->debug_str, sdp_get_attr_name(attr_p->type));
2745 0 : sdp_p->conf_p->num_invalid_param++;
2746 : /* Return success so build won't fail. */
2747 0 : return (SDP_SUCCESS);
2748 : }
2749 :
2750 : /* Validate params for this capability line */
2751 0 : if ((cap_p->media >= SDP_MAX_MEDIA_TYPES) ||
2752 0 : (cap_p->transport >= SDP_MAX_TRANSPORT_TYPES)) {
2753 0 : CSFLogDebug(logTag, logTag, "%s Media or transport type invalid for %s "
2754 : "attribute, unable to build.", sdp_p->debug_str,
2755 : sdp_get_attr_name(attr_p->type));
2756 0 : sdp_p->conf_p->num_invalid_param++;
2757 : /* Return success so build won't fail. */
2758 0 : return (SDP_SUCCESS);
2759 : }
2760 :
2761 0 : flex_string_sprintf(fs, "a=%s: %u %s ", sdp_attr[attr_p->type].name,
2762 0 : sdp_p->cur_cap_num, sdp_get_media_name(cap_p->media));
2763 :
2764 : /* If the X-cap line has AAL2 profiles, build them differently. */
2765 0 : if ((cap_p->transport == SDP_TRANSPORT_AAL2_ITU) ||
2766 0 : (cap_p->transport == SDP_TRANSPORT_AAL2_ATMF) ||
2767 0 : (cap_p->transport == SDP_TRANSPORT_AAL2_CUSTOM)) {
2768 0 : profile_p = cap_p->media_profiles_p;
2769 0 : for (i=0; i < profile_p->num_profiles; i++) {
2770 0 : flex_string_sprintf(fs, "%s",
2771 : sdp_get_transport_name(profile_p->profile[i]));
2772 :
2773 0 : for (j=0; j < profile_p->num_payloads[i]; j++) {
2774 0 : flex_string_sprintf(fs, " %u",
2775 0 : profile_p->payload_type[i][j]);
2776 : }
2777 0 : flex_string_append(fs, " ");
2778 : }
2779 :
2780 0 : flex_string_append(fs, "\r\n");
2781 0 : if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
2782 0 : SDP_PRINT("%s Built m= media line", sdp_p->debug_str);
2783 : }
2784 0 : return SDP_SUCCESS;
2785 : }
2786 :
2787 : /* Build the transport name */
2788 0 : flex_string_sprintf(fs, "%s", sdp_get_transport_name(cap_p->transport));
2789 :
2790 : /* Build the format lists */
2791 0 : for (i=0; i < cap_p->num_payloads; i++) {
2792 0 : if (cap_p->payload_indicator[i] == SDP_PAYLOAD_ENUM) {
2793 0 : flex_string_sprintf(fs, " %s",
2794 0 : sdp_get_payload_name((sdp_payload_e)cap_p->payload_type[i]));
2795 : } else {
2796 0 : flex_string_sprintf(fs, " %u", cap_p->payload_type[i]);
2797 : }
2798 : }
2799 :
2800 0 : flex_string_append(fs, "\r\n");
2801 :
2802 : /* Increment the current capability number for the next X-cap/cdsc attr. */
2803 0 : sdp_p->cur_cap_num += cap_p->num_payloads;
2804 0 : sdp_p->last_cap_type = attr_p->type;
2805 :
2806 : /* Build any X-cpar/cpar attributes associated with this X-cap/cdsc line. */
2807 0 : return sdp_build_attr_cpar(sdp_p, cap_p->media_attrs_p, fs);
2808 : }
2809 :
2810 :
2811 0 : sdp_result_e sdp_parse_attr_cpar (sdp_t *sdp_p, sdp_attr_t *attr_p,
2812 : const char *ptr)
2813 : {
2814 : uint16_t i;
2815 : sdp_result_e result;
2816 : sdp_mca_t *cap_p;
2817 0 : sdp_attr_t *cap_attr_p = NULL;
2818 : sdp_attr_t *prev_attr_p;
2819 : char tmp[SDP_MAX_STRING_LEN];
2820 :
2821 : /* Make sure we've processed a valid X-cap/cdsc attr prior to this and
2822 : * if so, get the cap pointer. */
2823 0 : if (sdp_p->cap_valid == TRUE) {
2824 : sdp_attr_e cap_type;
2825 :
2826 0 : if (attr_p->type == SDP_ATTR_CPAR) {
2827 0 : cap_type = SDP_ATTR_CDSC;
2828 : } else {
2829 : /* Default to X-CAP for everything else */
2830 0 : cap_type = SDP_ATTR_X_CAP;
2831 : }
2832 :
2833 0 : if (sdp_p->mca_count == 0) {
2834 0 : cap_attr_p = sdp_find_attr(sdp_p, SDP_SESSION_LEVEL, 0,
2835 0 : cap_type, sdp_p->last_cap_inst);
2836 : } else {
2837 0 : cap_attr_p = sdp_find_attr(sdp_p, sdp_p->mca_count, 0,
2838 0 : cap_type, sdp_p->last_cap_inst);
2839 : }
2840 : }
2841 0 : if ((cap_attr_p == NULL) || (cap_attr_p->attr.cap_p == NULL)) {
2842 0 : sdp_parse_error(sdp_p,
2843 : "%s Warning: %s attribute specified with no "
2844 0 : "prior %s attribute", sdp_p->debug_str,
2845 : sdp_get_attr_name(attr_p->type),
2846 0 : (attr_p->type == SDP_ATTR_CPAR)?
2847 : (sdp_get_attr_name(SDP_ATTR_CDSC)) :
2848 : (sdp_get_attr_name(SDP_ATTR_X_CAP)) );
2849 0 : sdp_p->conf_p->num_invalid_param++;
2850 0 : return (SDP_INVALID_PARAMETER);
2851 : }
2852 :
2853 : /*
2854 : * Ensure there is no mixed syntax like CDSC followed by X-CPAR
2855 : * or X-CAP followed by CPAR.
2856 : */
2857 0 : if (((cap_attr_p->type == SDP_ATTR_CDSC) &&
2858 0 : (attr_p->type == SDP_ATTR_X_CPAR)) ||
2859 0 : ( (cap_attr_p->type == SDP_ATTR_X_CAP) &&
2860 0 : (attr_p->type == SDP_ATTR_CPAR)) ) {
2861 0 : sdp_parse_error(sdp_p,
2862 : "%s Warning: %s attribute inconsistent with "
2863 0 : "prior %s attribute", sdp_p->debug_str,
2864 : sdp_get_attr_name(attr_p->type),
2865 : sdp_get_attr_name(cap_attr_p->type));
2866 0 : sdp_p->conf_p->num_invalid_param++;
2867 0 : return (SDP_INVALID_PARAMETER);
2868 : }
2869 0 : cap_p = cap_attr_p->attr.cap_p;
2870 :
2871 : /* a= is the only token we handle in an X-cpar/cpar attribute. */
2872 0 : ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), "= \t", &result);
2873 :
2874 0 : if ((result != SDP_SUCCESS) || (tmp[0] != 'a') || (tmp[1] != '\0')) {
2875 0 : sdp_parse_error(sdp_p,
2876 : "%s Warning: Invalid token type (%s) in %s "
2877 0 : "attribute, unable to parse", sdp_p->debug_str, tmp,
2878 : sdp_get_attr_name(attr_p->type));
2879 0 : sdp_p->conf_p->num_invalid_param++;
2880 0 : return (SDP_INVALID_PARAMETER);
2881 : }
2882 : /*sa_ignore NO_NULL_CHK
2883 : *{ptr is valid since the pointer was checked earlier and the
2884 : * function would have exited if NULL.}
2885 : */
2886 0 : if (*ptr == '=') {
2887 0 : ptr++;
2888 : }
2889 :
2890 : /* Find the attribute type. */
2891 0 : ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), ": \t", &result);
2892 : /*sa_ignore NO_NULL_CHK
2893 : *{ptr is valid since the pointer was checked earlier and the
2894 : * function would have exited if NULL.}
2895 : */
2896 0 : if (ptr[0] == ':') {
2897 : /* Skip the ':' char for parsing attribute parameters. */
2898 0 : ptr++;
2899 : }
2900 0 : if (result != SDP_SUCCESS) {
2901 0 : sdp_parse_error(sdp_p,
2902 : "%s No attribute type specified for %s attribute, unable to parse.",
2903 0 : sdp_p->debug_str,
2904 : sdp_get_attr_name(attr_p->type));
2905 0 : sdp_p->conf_p->num_invalid_param++;
2906 0 : return (SDP_INVALID_PARAMETER);
2907 : }
2908 :
2909 : /* Reset the type of the attribute from X-cpar/cpar to whatever the
2910 : * specified type is. */
2911 0 : attr_p->type = SDP_ATTR_INVALID;
2912 0 : attr_p->next_p = NULL;
2913 0 : for (i=0; i < SDP_MAX_ATTR_TYPES; i++) {
2914 0 : if (cpr_strncasecmp(tmp, sdp_attr[i].name, sdp_attr[i].strlen) == 0) {
2915 0 : attr_p->type = (sdp_attr_e)i;
2916 : }
2917 : }
2918 0 : if (attr_p->type == SDP_ATTR_INVALID) {
2919 0 : sdp_parse_error(sdp_p,
2920 : "%s Warning: Unrecognized attribute (%s) for %s attribute, unable to parse.",
2921 0 : sdp_p->debug_str, tmp,
2922 : sdp_get_attr_name(attr_p->type));
2923 0 : sdp_p->conf_p->num_invalid_param++;
2924 0 : return (SDP_INVALID_PARAMETER);
2925 : }
2926 :
2927 : /* We don't allow recursion with the capability attributes. */
2928 0 : if ((attr_p->type == SDP_ATTR_X_SQN) ||
2929 0 : (attr_p->type == SDP_ATTR_X_CAP) ||
2930 0 : (attr_p->type == SDP_ATTR_X_CPAR) ||
2931 0 : (attr_p->type == SDP_ATTR_SQN) ||
2932 0 : (attr_p->type == SDP_ATTR_CDSC) ||
2933 0 : (attr_p->type == SDP_ATTR_CPAR)) {
2934 0 : sdp_parse_error(sdp_p,
2935 : "%s Warning: Invalid attribute (%s) for %s"
2936 0 : " attribute, unable to parse.", sdp_p->debug_str, tmp,
2937 : sdp_get_attr_name(attr_p->type));
2938 0 : sdp_p->conf_p->num_invalid_param++;
2939 0 : return (SDP_INVALID_PARAMETER);
2940 : }
2941 :
2942 : /* Parse the attribute. */
2943 0 : result = sdp_attr[attr_p->type].parse_func(sdp_p, attr_p, ptr);
2944 0 : if (result != SDP_SUCCESS) {
2945 0 : return (result);
2946 : }
2947 :
2948 : /* Hook the attribute into the capability structure. */
2949 0 : if (cap_p->media_attrs_p == NULL) {
2950 0 : cap_p->media_attrs_p = attr_p;
2951 : } else {
2952 0 : for (prev_attr_p = cap_p->media_attrs_p;
2953 0 : prev_attr_p->next_p != NULL;
2954 0 : prev_attr_p = prev_attr_p->next_p) {
2955 : ; /* Empty for */
2956 : }
2957 0 : prev_attr_p->next_p = attr_p;
2958 : }
2959 :
2960 0 : return (SDP_SUCCESS);
2961 : }
2962 :
2963 0 : sdp_result_e sdp_build_attr_cpar (sdp_t *sdp_p, sdp_attr_t *attr_p,
2964 : flex_string *fs)
2965 : {
2966 : sdp_result_e result;
2967 : const char *cpar_name;
2968 :
2969 : /* Determine whether to use cpar or X-cpar */
2970 0 : if (sdp_p->last_cap_type == SDP_ATTR_CDSC) {
2971 0 : cpar_name = sdp_get_attr_name(SDP_ATTR_CPAR);
2972 : } else {
2973 : /*
2974 : * Default to X-CPAR if anything else. This is the backward
2975 : * compatible value.
2976 : */
2977 0 : cpar_name = sdp_get_attr_name(SDP_ATTR_X_CPAR);
2978 : }
2979 :
2980 0 : while (attr_p != NULL) {
2981 0 : if (attr_p->type >= SDP_MAX_ATTR_TYPES) {
2982 0 : CSFLogDebug(logTag, "%s Invalid attribute type to build (%u)",
2983 : sdp_p->debug_str, (unsigned)attr_p->type);
2984 : } else {
2985 0 : flex_string_sprintf(fs, "a=%s: ", cpar_name);
2986 :
2987 0 : result = sdp_attr[attr_p->type].build_func(sdp_p, attr_p, fs);
2988 :
2989 0 : if (result == SDP_SUCCESS) {
2990 0 : if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
2991 0 : SDP_PRINT("%s Built %s a=%s attribute line",
2992 : sdp_p->debug_str, cpar_name,
2993 : sdp_get_attr_name(attr_p->type));
2994 : }
2995 : }
2996 : }
2997 0 : attr_p = attr_p->next_p;
2998 : }
2999 :
3000 0 : return (SDP_SUCCESS);
3001 : }
3002 :
3003 0 : sdp_result_e sdp_parse_attr_rtcp (sdp_t *sdp_p, sdp_attr_t *attr_p,
3004 : const char *ptr)
3005 : {
3006 : sdp_result_e result;
3007 : char nettype[SDP_MAX_STRING_LEN];
3008 0 : sdp_rtcp_t *rtcp_p = &(attr_p->attr.rtcp);
3009 : int enum_raw;
3010 :
3011 0 : memset(rtcp_p, 0, sizeof(sdp_rtcp_t));
3012 :
3013 0 : rtcp_p->port = (uint16_t)sdp_getnextnumtok(ptr, &ptr, " \t", &result);
3014 0 : if (result != SDP_SUCCESS) {
3015 0 : sdp_parse_error(sdp_p,
3016 : "%s Warning: could not parse port for rtcp attribute",
3017 0 : sdp_p->debug_str);
3018 0 : sdp_p->conf_p->num_invalid_param++;
3019 :
3020 0 : return SDP_INVALID_PARAMETER;
3021 : }
3022 :
3023 : /* The rest is optional, although it is all-or-nothing */
3024 0 : (void)sdp_getnextstrtok(ptr, nettype, sizeof(nettype), " \t", &result);
3025 0 : if (result == SDP_EMPTY_TOKEN) {
3026 : /* Nothing after the port */
3027 0 : return SDP_SUCCESS;
3028 : }
3029 :
3030 0 : enum_raw = find_token_enum("Nettype", sdp_p, &ptr, sdp_nettype,
3031 : SDP_MAX_NETWORK_TYPES, SDP_NT_UNSUPPORTED);
3032 0 : if (enum_raw == -1) {
3033 0 : return SDP_INVALID_PARAMETER;
3034 : }
3035 0 : rtcp_p->nettype = (sdp_nettype_e)enum_raw;
3036 :
3037 0 : enum_raw = find_token_enum("Addrtype", sdp_p, &ptr, sdp_addrtype,
3038 : SDP_MAX_ADDR_TYPES, SDP_AT_UNSUPPORTED);
3039 0 : if (enum_raw == -1) {
3040 0 : return SDP_INVALID_PARAMETER;
3041 : }
3042 0 : rtcp_p->addrtype = (sdp_addrtype_e)enum_raw;
3043 :
3044 0 : ptr = sdp_getnextstrtok(ptr, rtcp_p->addr, sizeof(rtcp_p->addr), " \t",
3045 : &result);
3046 0 : if (result != SDP_SUCCESS) {
3047 0 : sdp_parse_error(sdp_p,
3048 : "%s Warning: could not parse addr for rtcp attribute",
3049 0 : sdp_p->debug_str);
3050 0 : sdp_p->conf_p->num_invalid_param++;
3051 :
3052 0 : return SDP_INVALID_PARAMETER;
3053 : }
3054 :
3055 0 : return SDP_SUCCESS;
3056 : }
3057 :
3058 0 : sdp_result_e sdp_build_attr_rtcp (sdp_t *sdp_p, sdp_attr_t *attr_p,
3059 : flex_string *fs)
3060 : {
3061 : /* We should not be serializing SDP anyway, but we need this function until
3062 : * Bug 1112737 is resolved. */
3063 0 : return SDP_FAILURE;
3064 : }
3065 :
3066 0 : sdp_result_e sdp_parse_attr_rtr (sdp_t *sdp_p, sdp_attr_t *attr_p,
3067 : const char *ptr)
3068 : {
3069 : sdp_result_e result;
3070 : char tmp[SDP_MAX_STRING_LEN];
3071 :
3072 0 : if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
3073 0 : SDP_PRINT("%s Parsing a=%s", sdp_p->debug_str,
3074 : sdp_get_attr_name(attr_p->type));
3075 : }
3076 : /*Default confirm to FALSE. */
3077 0 : attr_p->attr.rtr.confirm = FALSE;
3078 :
3079 0 : ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
3080 0 : if (result != SDP_SUCCESS){ // No confirm tag specified is not an error
3081 0 : return (SDP_SUCCESS);
3082 : } else {
3083 : /* See if confirm was specified. Defaults to FALSE. */
3084 0 : if (cpr_strncasecmp(tmp, "confirm", sizeof("confirm")) == 0) {
3085 0 : attr_p->attr.rtr.confirm = TRUE;
3086 : }
3087 0 : if (attr_p->attr.rtr.confirm == FALSE) {
3088 0 : sdp_parse_error(sdp_p,
3089 : "%s Warning: RTR confirm parameter invalid (%s)",
3090 0 : sdp_p->debug_str, tmp);
3091 0 : sdp_p->conf_p->num_invalid_param++;
3092 0 : return (SDP_INVALID_PARAMETER);
3093 : }
3094 0 : if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
3095 0 : SDP_PRINT("%s Parsed a=%s, %s", sdp_p->debug_str,
3096 : sdp_get_attr_name(attr_p->type),
3097 : tmp);
3098 : }
3099 0 : return (SDP_SUCCESS);
3100 : }
3101 : }
3102 :
3103 0 : sdp_result_e sdp_build_attr_rtr (sdp_t *sdp_p, sdp_attr_t *attr_p,
3104 : flex_string *fs)
3105 : {
3106 0 : flex_string_sprintf(fs, "a=%s%s\r\n",
3107 0 : sdp_attr[attr_p->type].name,
3108 0 : attr_p->attr.rtr.confirm ? ":confirm" : "");
3109 :
3110 0 : return SDP_SUCCESS;
3111 : }
3112 :
3113 0 : sdp_result_e sdp_parse_attr_comediadir (sdp_t *sdp_p, sdp_attr_t *attr_p,
3114 : const char *ptr)
3115 : {
3116 : int i;
3117 : sdp_result_e result;
3118 0 : tinybool type_found = FALSE;
3119 : char tmp[SDP_MAX_STRING_LEN];
3120 :
3121 0 : attr_p->attr.comediadir.role = SDP_MEDIADIR_ROLE_PASSIVE;
3122 0 : attr_p->attr.comediadir.conn_info_present = FALSE;
3123 0 : attr_p->attr.comediadir.conn_info.nettype = SDP_NT_INVALID;
3124 0 : attr_p->attr.comediadir.src_port = 0;
3125 :
3126 : /* Find the media direction role. */
3127 0 : ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), ": \t", &result);
3128 :
3129 0 : if (result != SDP_SUCCESS) {
3130 0 : sdp_parse_error(sdp_p,
3131 : "%s Warning: No role parameter specified for "
3132 0 : "comediadir attribute.", sdp_p->debug_str);
3133 0 : sdp_p->conf_p->num_invalid_param++;
3134 0 : return (SDP_INVALID_PARAMETER);
3135 : }
3136 0 : attr_p->attr.comediadir.role = SDP_MEDIADIR_ROLE_UNSUPPORTED;
3137 0 : for (i=0; i < SDP_MAX_MEDIADIR_ROLES; i++) {
3138 0 : if (cpr_strncasecmp(tmp, sdp_mediadir_role[i].name,
3139 0 : sdp_mediadir_role[i].strlen) == 0) {
3140 0 : type_found = TRUE;
3141 0 : attr_p->attr.comediadir.role = (sdp_mediadir_role_e)i;
3142 0 : break;
3143 : }
3144 : }
3145 0 : if (attr_p->attr.comediadir.role == SDP_MEDIADIR_ROLE_UNSUPPORTED) {
3146 0 : sdp_parse_error(sdp_p,
3147 : "%s Warning: Invalid role type specified for "
3148 0 : "comediadir attribute (%s).", sdp_p->debug_str, tmp);
3149 0 : sdp_p->conf_p->num_invalid_param++;
3150 0 : return (SDP_INVALID_PARAMETER);
3151 : }
3152 :
3153 : /* If the role is passive, we don't expect any more params. */
3154 0 : if (attr_p->attr.comediadir.role == SDP_MEDIADIR_ROLE_PASSIVE) {
3155 0 : if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
3156 0 : SDP_PRINT("%s Parsed a=%s, passive",
3157 : sdp_p->debug_str, sdp_get_attr_name(attr_p->type));
3158 : }
3159 0 : return (SDP_SUCCESS);
3160 : }
3161 :
3162 : /* Find the connection information if present */
3163 : /* parse to get the nettype */
3164 0 : ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
3165 0 : if (result != SDP_SUCCESS) {
3166 0 : sdp_parse_error(sdp_p,
3167 : "%s Warning: No network type specified in comediadir "
3168 0 : "attribute.", sdp_p->debug_str);
3169 0 : sdp_p->conf_p->num_invalid_param++;
3170 0 : return (SDP_SUCCESS); /* as the optional parameters are not there */
3171 : }
3172 0 : attr_p->attr.comediadir.conn_info.nettype = SDP_NT_UNSUPPORTED;
3173 0 : for (i=0; i < SDP_MAX_NETWORK_TYPES; i++) {
3174 0 : if (cpr_strncasecmp(tmp, sdp_nettype[i].name,
3175 0 : sdp_nettype[i].strlen) == 0) {
3176 0 : type_found = TRUE;
3177 : }
3178 0 : if (type_found == TRUE) {
3179 0 : if (sdp_p->conf_p->nettype_supported[i] == TRUE) {
3180 0 : attr_p->attr.comediadir.conn_info.nettype = (sdp_nettype_e)i;
3181 : }
3182 0 : type_found = FALSE;
3183 : }
3184 : }
3185 0 : if (attr_p->attr.comediadir.conn_info.nettype == SDP_NT_UNSUPPORTED) {
3186 0 : sdp_parse_error(sdp_p,
3187 : "%s Warning: ConnInfo in Comediadir: network type "
3188 0 : "unsupported (%s).", sdp_p->debug_str, tmp);
3189 0 : sdp_p->conf_p->num_invalid_param++;
3190 : }
3191 :
3192 : /* Find the comedia address type. */
3193 0 : ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
3194 0 : if (result != SDP_SUCCESS) {
3195 0 : sdp_parse_error(sdp_p,
3196 : "%s Warning: No address type specified in comediadir"
3197 0 : " attribute.", sdp_p->debug_str);
3198 0 : sdp_p->conf_p->num_invalid_param++;
3199 : }
3200 0 : attr_p->attr.comediadir.conn_info.addrtype = SDP_AT_UNSUPPORTED;
3201 0 : for (i=0; i < SDP_MAX_ADDR_TYPES; i++) {
3202 0 : if (cpr_strncasecmp(tmp, sdp_addrtype[i].name,
3203 0 : sdp_addrtype[i].strlen) == 0) {
3204 0 : type_found = TRUE;
3205 : }
3206 0 : if (type_found == TRUE) {
3207 0 : if (sdp_p->conf_p->addrtype_supported[i] == TRUE) {
3208 0 : attr_p->attr.comediadir.conn_info.addrtype = (sdp_addrtype_e)i;
3209 : }
3210 0 : type_found = FALSE;
3211 : }
3212 : }
3213 0 : if (attr_p->attr.comediadir.conn_info.addrtype == SDP_AT_UNSUPPORTED) {
3214 0 : sdp_parse_error(sdp_p,
3215 : "%s Warning: Conninfo address type unsupported "
3216 0 : "(%s).", sdp_p->debug_str, tmp);
3217 0 : sdp_p->conf_p->num_invalid_param++;
3218 : }
3219 :
3220 : /* Find the conninfo address. */
3221 0 : ptr = sdp_getnextstrtok(ptr, attr_p->attr.comediadir.conn_info.conn_addr,
3222 : sizeof(attr_p->attr.comediadir.conn_info.conn_addr), " \t", &result);
3223 0 : if (result != SDP_SUCCESS) {
3224 0 : sdp_parse_error(sdp_p,
3225 : "%s Warning: No conninfo address specified in "
3226 0 : "comediadir attribute.", sdp_p->debug_str);
3227 0 : sdp_p->conf_p->num_invalid_param++;
3228 : }
3229 :
3230 : /* Find the src port info , if any */
3231 0 : attr_p->attr.comediadir.src_port = sdp_getnextnumtok(ptr, &ptr, " \t",
3232 : &result);
3233 0 : if (result != SDP_SUCCESS) {
3234 0 : sdp_parse_error(sdp_p,
3235 : "%s Warning: No src port specified in "
3236 0 : "comediadir attribute.", sdp_p->debug_str);
3237 0 : sdp_p->conf_p->num_invalid_param++;
3238 : }
3239 :
3240 0 : if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
3241 0 : SDP_PRINT("%s Parsed a=%s, network %s, addr type %s, address %s "
3242 : "srcport %u ",
3243 : sdp_p->debug_str, sdp_get_attr_name(attr_p->type),
3244 : sdp_get_network_name(attr_p->attr.comediadir.conn_info.nettype),
3245 : sdp_get_address_name(attr_p->attr.comediadir.conn_info.addrtype),
3246 : attr_p->attr.comediadir.conn_info.conn_addr,
3247 : (unsigned int)attr_p->attr.comediadir.src_port);
3248 : }
3249 :
3250 0 : if (sdp_p->conf_p->num_invalid_param > 0) {
3251 0 : return (SDP_INVALID_PARAMETER);
3252 : }
3253 0 : return (SDP_SUCCESS);
3254 : }
3255 :
3256 : sdp_result_e
3257 0 : sdp_build_attr_comediadir (sdp_t *sdp_p, sdp_attr_t *attr_p,
3258 : flex_string *fs)
3259 : {
3260 0 : flex_string_sprintf(fs, "a=%s:%s\r\n",
3261 0 : sdp_attr[attr_p->type].name,
3262 : sdp_get_mediadir_role_name(attr_p->attr.comediadir.role));
3263 :
3264 0 : return SDP_SUCCESS;
3265 : }
3266 :
3267 0 : sdp_result_e sdp_parse_attr_silencesupp (sdp_t *sdp_p, sdp_attr_t *attr_p,
3268 : const char *ptr)
3269 : {
3270 : int i;
3271 : sdp_result_e result;
3272 : char tmp[SDP_MAX_STRING_LEN];
3273 :
3274 : /* Find silenceSuppEnable */
3275 0 : ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
3276 :
3277 0 : if (result != SDP_SUCCESS) {
3278 0 : sdp_parse_error(sdp_p,
3279 : "%s No silenceSupp enable value specified, parse failed.",
3280 0 : sdp_p->debug_str);
3281 0 : sdp_p->conf_p->num_invalid_param++;
3282 0 : return (SDP_INVALID_PARAMETER);
3283 : }
3284 :
3285 0 : if (cpr_strncasecmp(tmp, "on", sizeof("on")) == 0) {
3286 0 : attr_p->attr.silencesupp.enabled = TRUE;
3287 0 : } else if (cpr_strncasecmp(tmp, "off", sizeof("off")) == 0) {
3288 0 : attr_p->attr.silencesupp.enabled = FALSE;
3289 0 : } else if (cpr_strncasecmp(tmp, "-", sizeof("-")) == 0) {
3290 0 : attr_p->attr.silencesupp.enabled = FALSE;
3291 : } else {
3292 0 : sdp_parse_error(sdp_p,
3293 : "%s Warning: silenceSuppEnable parameter invalid (%s)",
3294 0 : sdp_p->debug_str, tmp);
3295 0 : sdp_p->conf_p->num_invalid_param++;
3296 0 : return (SDP_INVALID_PARAMETER);
3297 : }
3298 :
3299 : /* Find silenceTimer -- uint16_t or "-" */
3300 :
3301 0 : attr_p->attr.silencesupp.timer =
3302 0 : (uint16_t)sdp_getnextnumtok_or_null(ptr, &ptr, " \t",
3303 : &attr_p->attr.silencesupp.timer_null,
3304 : &result);
3305 0 : if (result != SDP_SUCCESS) {
3306 0 : sdp_parse_error(sdp_p,
3307 : "%s Warning: Invalid timer value specified for "
3308 0 : "silenceSupp attribute.", sdp_p->debug_str);
3309 0 : sdp_p->conf_p->num_invalid_param++;
3310 0 : return (SDP_INVALID_PARAMETER);
3311 : }
3312 :
3313 : /* Find suppPref */
3314 0 : ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
3315 0 : if (result != SDP_SUCCESS) {
3316 0 : sdp_parse_error(sdp_p,
3317 : "%s Warning: No silenceSupp pref specified.",
3318 0 : sdp_p->debug_str);
3319 0 : sdp_p->conf_p->num_invalid_param++;
3320 0 : return (SDP_INVALID_PARAMETER);
3321 : }
3322 0 : attr_p->attr.silencesupp.pref = SDP_SILENCESUPP_PREF_UNKNOWN;
3323 0 : for (i=0; i < SDP_MAX_SILENCESUPP_PREF; i++) {
3324 0 : if (cpr_strncasecmp(tmp, sdp_silencesupp_pref[i].name,
3325 0 : sdp_silencesupp_pref[i].strlen) == 0) {
3326 0 : attr_p->attr.silencesupp.pref = (sdp_silencesupp_pref_e)i;
3327 : }
3328 : }
3329 0 : if (attr_p->attr.silencesupp.pref == SDP_SILENCESUPP_PREF_UNKNOWN) {
3330 0 : sdp_parse_error(sdp_p,
3331 : "%s Warning: silenceSupp pref unrecognized (%s)",
3332 0 : sdp_p->debug_str, tmp);
3333 0 : sdp_p->conf_p->num_invalid_param++;
3334 0 : return (SDP_INVALID_PARAMETER);
3335 : }
3336 :
3337 : /* Find sidUse */
3338 0 : ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
3339 0 : if (result != SDP_SUCCESS) {
3340 0 : sdp_parse_error(sdp_p,
3341 : "%s Warning: No silenceSupp sidUse specified.",
3342 0 : sdp_p->debug_str);
3343 0 : sdp_p->conf_p->num_invalid_param++;
3344 0 : return (SDP_INVALID_PARAMETER);
3345 : }
3346 0 : attr_p->attr.silencesupp.siduse = SDP_SILENCESUPP_SIDUSE_UNKNOWN;
3347 0 : for (i=0; i < SDP_MAX_SILENCESUPP_SIDUSE; i++) {
3348 0 : if (cpr_strncasecmp(tmp, sdp_silencesupp_siduse[i].name,
3349 0 : sdp_silencesupp_siduse[i].strlen) == 0) {
3350 0 : attr_p->attr.silencesupp.siduse = (sdp_silencesupp_siduse_e)i;
3351 : }
3352 : }
3353 0 : if (attr_p->attr.silencesupp.siduse == SDP_SILENCESUPP_SIDUSE_UNKNOWN) {
3354 0 : sdp_parse_error(sdp_p,
3355 : "%s Warning: silenceSupp sidUse unrecognized (%s)",
3356 0 : sdp_p->debug_str, tmp);
3357 0 : sdp_p->conf_p->num_invalid_param++;
3358 0 : return (SDP_INVALID_PARAMETER);
3359 : }
3360 :
3361 : /* Find fxnslevel -- uint8_t or "-" */
3362 0 : attr_p->attr.silencesupp.fxnslevel =
3363 0 : (uint8_t)sdp_getnextnumtok_or_null(ptr, &ptr, " \t",
3364 : &attr_p->attr.silencesupp.fxnslevel_null,
3365 : &result);
3366 :
3367 0 : if (result != SDP_SUCCESS) {
3368 0 : sdp_parse_error(sdp_p,
3369 : "%s Warning: Invalid fxnslevel value specified for "
3370 0 : "silenceSupp attribute.", sdp_p->debug_str);
3371 0 : sdp_p->conf_p->num_invalid_param++;
3372 0 : return (SDP_INVALID_PARAMETER);
3373 : }
3374 :
3375 0 : if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
3376 0 : SDP_PRINT("%s Parsed a=%s, enabled %s",
3377 : sdp_p->debug_str, sdp_get_attr_name(attr_p->type),
3378 : (attr_p->attr.silencesupp.enabled ? "on" : "off"));
3379 0 : if (attr_p->attr.silencesupp.timer_null) {
3380 0 : SDP_PRINT(" timer=-");
3381 : } else {
3382 0 : SDP_PRINT(" timer=%u,", attr_p->attr.silencesupp.timer);
3383 : }
3384 0 : SDP_PRINT(" pref=%s, siduse=%s,",
3385 : sdp_get_silencesupp_pref_name(attr_p->attr.silencesupp.pref),
3386 : sdp_get_silencesupp_siduse_name(
3387 : attr_p->attr.silencesupp.siduse));
3388 0 : if (attr_p->attr.silencesupp.fxnslevel_null) {
3389 0 : SDP_PRINT(" fxnslevel=-");
3390 : } else {
3391 0 : SDP_PRINT(" fxnslevel=%u,", attr_p->attr.silencesupp.fxnslevel);
3392 : }
3393 : }
3394 :
3395 0 : return (SDP_SUCCESS);
3396 : }
3397 :
3398 0 : sdp_result_e sdp_build_attr_silencesupp (sdp_t *sdp_p, sdp_attr_t *attr_p,
3399 : flex_string *fs)
3400 : {
3401 : char temp_timer_string[11];
3402 : char temp_fxnslevel_string[11];
3403 :
3404 0 : if (attr_p->attr.silencesupp.timer_null) {
3405 0 : snprintf(temp_timer_string, sizeof(temp_timer_string), "-");
3406 : } else {
3407 0 : snprintf(temp_timer_string, sizeof(temp_timer_string), "%u", attr_p->attr.silencesupp.timer);
3408 : }
3409 :
3410 0 : if (attr_p->attr.silencesupp.fxnslevel_null) {
3411 0 : snprintf(temp_fxnslevel_string, sizeof(temp_fxnslevel_string), "-");
3412 : } else {
3413 0 : snprintf(temp_fxnslevel_string, sizeof(temp_fxnslevel_string), "%u", attr_p->attr.silencesupp.fxnslevel);
3414 : }
3415 :
3416 0 : flex_string_sprintf(fs, "a=%s:%s %s %s %s %s\r\n",
3417 0 : sdp_attr[attr_p->type].name,
3418 0 : (attr_p->attr.silencesupp.enabled ? "on" : "off"),
3419 : temp_timer_string,
3420 : sdp_get_silencesupp_pref_name(attr_p->attr.silencesupp.pref),
3421 : sdp_get_silencesupp_siduse_name(attr_p->attr.silencesupp.siduse),
3422 : temp_fxnslevel_string);
3423 :
3424 0 : return SDP_SUCCESS;
3425 : }
3426 :
3427 : /*
3428 : * sdp_parse_context_crypto_suite
3429 : *
3430 : * This routine parses the crypto suite pointed to by str, stores the crypto suite value into the
3431 : * srtp context suite component of the LocalConnectionOptions pointed to by lco_node_ptr and stores
3432 : * pointer to the next crypto parameter in tmp_ptr
3433 : */
3434 0 : tinybool sdp_parse_context_crypto_suite(char * str, sdp_attr_t *attr_p, sdp_t *sdp_p) {
3435 : /*
3436 : * Three crypto_suites are defined: (Notice no SPACE between "crypto:" and the <crypto-suite>
3437 : * AES_CM_128_HMAC_SHA1_80
3438 : * AES_CM_128_HMAC_SHA1_32
3439 : * F8_128_HMAC_SHA1_80
3440 : */
3441 :
3442 : int i;
3443 :
3444 : /* Check crypto suites */
3445 0 : for(i=0; i<SDP_SRTP_MAX_NUM_CRYPTO_SUITES; i++) {
3446 0 : if (!cpr_strcasecmp(sdp_srtp_crypto_suite_array[i].crypto_suite_str, str)) {
3447 0 : attr_p->attr.srtp_context.suite = sdp_srtp_crypto_suite_array[i].crypto_suite_val;
3448 0 : attr_p->attr.srtp_context.master_key_size_bytes =
3449 0 : sdp_srtp_crypto_suite_array[i].key_size_bytes;
3450 0 : attr_p->attr.srtp_context.master_salt_size_bytes =
3451 0 : sdp_srtp_crypto_suite_array[i].salt_size_bytes;
3452 0 : return TRUE; /* There is a succesful match so exit */
3453 : }
3454 : }
3455 : /* couldn't find a matching crypto suite */
3456 0 : sdp_parse_error(sdp_p,
3457 : "%s No Matching crypto suite for SRTP Context(%s)-'X-crypto:v1' expected",
3458 0 : sdp_p->debug_str, str);
3459 :
3460 0 : return FALSE;
3461 : }
3462 :
3463 :
3464 0 : sdp_result_e sdp_build_attr_srtpcontext (sdp_t *sdp_p, sdp_attr_t *attr_p,
3465 : flex_string *fs)
3466 : {
3467 : #define MAX_BASE64_ENCODE_SIZE_BYTES 60
3468 0 : int output_len = MAX_BASE64_ENCODE_SIZE_BYTES;
3469 0 : int key_size = attr_p->attr.srtp_context.master_key_size_bytes;
3470 0 : int salt_size = attr_p->attr.srtp_context.master_salt_size_bytes;
3471 : unsigned char base64_encoded_data[MAX_BASE64_ENCODE_SIZE_BYTES];
3472 : unsigned char base64_encoded_input[MAX_BASE64_ENCODE_SIZE_BYTES];
3473 : base64_result_t status;
3474 :
3475 0 : output_len = MAX_BASE64_ENCODE_SIZE_BYTES;
3476 :
3477 : /* Append master and salt keys */
3478 0 : memcpy(base64_encoded_input,
3479 0 : attr_p->attr.srtp_context.master_key,
3480 : key_size );
3481 0 : memcpy(base64_encoded_input + key_size,
3482 0 : attr_p->attr.srtp_context.master_salt,
3483 : salt_size );
3484 :
3485 0 : if ((status = base64_encode(base64_encoded_input, key_size + salt_size,
3486 : base64_encoded_data, &output_len)) != BASE64_SUCCESS) {
3487 0 : if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
3488 0 : CSFLogError(logTag, "%s Error: Failure to Base64 Encoded data (%s) ",
3489 : sdp_p->debug_str, BASE64_RESULT_TO_STRING(status));
3490 : }
3491 0 : return (SDP_INVALID_PARAMETER);
3492 : }
3493 :
3494 0 : *(base64_encoded_data + output_len) = '\0';
3495 :
3496 0 : flex_string_sprintf(fs, "a=%s:%s inline:%s||\r\n",
3497 0 : sdp_attr[attr_p->type].name,
3498 0 : sdp_srtp_context_crypto_suite[attr_p->attr.srtp_context.suite].name,
3499 : base64_encoded_data);
3500 :
3501 0 : return SDP_SUCCESS;
3502 : }
3503 :
3504 : /*
3505 : * sdp_parse_attr_mptime
3506 : * This function parses the a=mptime sdp line. This parameter consists of
3507 : * one or more numbers or hyphens ("-"). The first parameter must be a
3508 : * number. The number of parameters must match the number of formats specified
3509 : * on the m= line. This function is liberal in that it does not match against
3510 : * the m= line or require a number for the first parameter.
3511 : */
3512 0 : sdp_result_e sdp_parse_attr_mptime (
3513 : sdp_t *sdp_p,
3514 : sdp_attr_t *attr_p,
3515 : const char *ptr)
3516 : {
3517 : uint16_t i; /* loop counter for parameters */
3518 : sdp_result_e result; /* value returned by this function */
3519 : tinybool null_ind; /* true if a parameter is "-" */
3520 :
3521 : /*
3522 : * Scan the input line up to the maximum number of parameters supported.
3523 : * Look for numbers or hyphens and store the resulting values. Hyphens
3524 : * are stored as zeros.
3525 : */
3526 0 : for (i=0; i<SDP_MAX_PAYLOAD_TYPES; i++) {
3527 0 : attr_p->attr.mptime.intervals[i] =
3528 0 : (ushort)sdp_getnextnumtok_or_null(ptr,&ptr," \t",&null_ind,&result);
3529 0 : if (result != SDP_SUCCESS) {
3530 0 : break;
3531 : }
3532 0 : attr_p->attr.mptime.num_intervals++;
3533 : }
3534 :
3535 : /*
3536 : * At least one parameter must be supplied. If not, return an error
3537 : * and optionally log the failure.
3538 : */
3539 0 : if (attr_p->attr.mptime.num_intervals == 0) {
3540 0 : sdp_parse_error(sdp_p,
3541 : "%s Warning: No intervals specified for %s attr.",
3542 0 : sdp_p->debug_str, sdp_attr[attr_p->type].name);
3543 0 : sdp_p->conf_p->num_invalid_param++;
3544 0 : return (SDP_INVALID_PARAMETER);
3545 : }
3546 :
3547 : /*
3548 : * Here is some debugging code that helps us track what data
3549 : * is received and parsed.
3550 : */
3551 0 : if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
3552 0 : SDP_PRINT("%s Parsed a=%s, num intervals %u, intervals: ",
3553 : sdp_p->debug_str, sdp_get_attr_name(attr_p->type),
3554 : attr_p->attr.mptime.num_intervals);
3555 0 : for (i=0; i < attr_p->attr.mptime.num_intervals; i++) {
3556 0 : SDP_PRINT("%u ", attr_p->attr.mptime.intervals[i]);
3557 : }
3558 : }
3559 :
3560 0 : return SDP_SUCCESS;
3561 : }
3562 :
3563 : /*
3564 : * sdp_build_attr_mptime
3565 : * This function builds the a=mptime sdp line. It reads the selected attribute
3566 : * from the sdp structure. Parameters with a value of zero are replaced by
3567 : * hyphens.
3568 : */
3569 0 : sdp_result_e sdp_build_attr_mptime (
3570 : sdp_t *sdp_p,
3571 : sdp_attr_t *attr_p,
3572 : flex_string *fs)
3573 : {
3574 : int i;
3575 :
3576 0 : flex_string_sprintf(fs, "a=%s:", sdp_attr[attr_p->type].name);
3577 :
3578 : /*
3579 : * Run the list of mptime parameter values and write each one
3580 : * to the sdp line. Replace zeros with hyphens.
3581 : */
3582 0 : for (i=0; i < attr_p->attr.mptime.num_intervals; i++) {
3583 0 : if (i > 0) {
3584 0 : flex_string_append(fs, " ");
3585 : }
3586 :
3587 0 : if (attr_p->attr.mptime.intervals[i] == 0) {
3588 0 : flex_string_append(fs, "-");
3589 : } else {
3590 0 : flex_string_sprintf(fs, "%u", attr_p->attr.mptime.intervals[i]);
3591 : }
3592 : }
3593 :
3594 0 : flex_string_append(fs, "\r\n");
3595 :
3596 0 : return SDP_SUCCESS;
3597 : }
3598 :
3599 :
3600 :
3601 0 : sdp_result_e sdp_parse_attr_x_sidin (sdp_t *sdp_p, sdp_attr_t *attr_p,
3602 : const char *ptr)
3603 : {
3604 : sdp_result_e result;
3605 0 : attr_p->attr.stream_data.x_sidin[0] = '\0';
3606 :
3607 0 : if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
3608 0 : SDP_PRINT("%s Parsing a=%s", sdp_p->debug_str,
3609 : sdp_get_attr_name(attr_p->type));
3610 : }
3611 :
3612 : /* Find the X-sidin value */
3613 0 : ptr = sdp_getnextstrtok(ptr, attr_p->attr.stream_data.x_sidin,
3614 : sizeof(attr_p->attr.stream_data.x_sidin), " \t", &result);
3615 0 : if (result != SDP_SUCCESS) {
3616 0 : sdp_parse_error(sdp_p,
3617 : "%s Warning: No Stream Id incoming specified for X-sidin attribute.",
3618 0 : sdp_p->debug_str);
3619 0 : sdp_p->conf_p->num_invalid_param++;
3620 0 : return (SDP_INVALID_PARAMETER);
3621 : }
3622 :
3623 0 : if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
3624 0 : SDP_PRINT("%s Parsed a=%s, %s", sdp_p->debug_str,
3625 : sdp_get_attr_name(attr_p->type),
3626 : attr_p->attr.stream_data.x_sidin);
3627 : }
3628 0 : return (SDP_SUCCESS);
3629 : }
3630 :
3631 0 : sdp_result_e sdp_build_attr_x_sidin (sdp_t *sdp_p, sdp_attr_t *attr_p,
3632 : flex_string *fs)
3633 : {
3634 0 : flex_string_sprintf(fs, "a=%s:%s\r\n",
3635 0 : sdp_attr[attr_p->type].name,
3636 0 : attr_p->attr.stream_data.x_sidin);
3637 :
3638 0 : return SDP_SUCCESS;
3639 : }
3640 :
3641 0 : sdp_result_e sdp_parse_attr_x_sidout (sdp_t *sdp_p, sdp_attr_t *attr_p,
3642 : const char *ptr)
3643 : {
3644 : sdp_result_e result;
3645 0 : attr_p->attr.stream_data.x_sidout[0] = '\0';
3646 :
3647 0 : if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
3648 0 : SDP_PRINT("%s Parsing a=%s", sdp_p->debug_str,
3649 : sdp_get_attr_name(attr_p->type));
3650 : }
3651 :
3652 : /* Find the X-sidout value */
3653 0 : ptr = sdp_getnextstrtok(ptr, attr_p->attr.stream_data.x_sidout,
3654 : sizeof(attr_p->attr.stream_data.x_sidout), " \t", &result);
3655 0 : if (result != SDP_SUCCESS) {
3656 0 : sdp_parse_error(sdp_p,
3657 : "%s Warning: No Stream Id outgoing specified for X-sidout attribute.",
3658 0 : sdp_p->debug_str);
3659 0 : sdp_p->conf_p->num_invalid_param++;
3660 0 : return (SDP_INVALID_PARAMETER);
3661 : }
3662 :
3663 0 : if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
3664 0 : SDP_PRINT("%s Parsed a=%s, %s", sdp_p->debug_str,
3665 : sdp_get_attr_name(attr_p->type),
3666 : attr_p->attr.stream_data.x_sidout);
3667 : }
3668 0 : return (SDP_SUCCESS);
3669 : }
3670 :
3671 0 : sdp_result_e sdp_build_attr_x_sidout (sdp_t *sdp_p, sdp_attr_t *attr_p,
3672 : flex_string *fs)
3673 : {
3674 0 : flex_string_sprintf(fs, "a=%s:%s\r\n",
3675 0 : sdp_attr[attr_p->type].name,
3676 0 : attr_p->attr.stream_data.x_sidout);
3677 :
3678 0 : return SDP_SUCCESS;
3679 : }
3680 :
3681 :
3682 0 : sdp_result_e sdp_parse_attr_x_confid (sdp_t *sdp_p, sdp_attr_t *attr_p,
3683 : const char *ptr)
3684 : {
3685 : sdp_result_e result;
3686 0 : attr_p->attr.stream_data.x_confid[0] = '\0';
3687 :
3688 0 : if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
3689 0 : SDP_PRINT("%s Parsing a=%s", sdp_p->debug_str,
3690 : sdp_get_attr_name(attr_p->type));
3691 : }
3692 :
3693 : /* Find the X-confid value */
3694 0 : ptr = sdp_getnextstrtok(ptr, attr_p->attr.stream_data.x_confid,
3695 : sizeof(attr_p->attr.stream_data.x_confid), " \t", &result);
3696 0 : if (result != SDP_SUCCESS) {
3697 0 : sdp_parse_error(sdp_p,
3698 : "%s Warning: No Conf Id incoming specified for "
3699 0 : "X-confid attribute.", sdp_p->debug_str);
3700 0 : sdp_p->conf_p->num_invalid_param++;
3701 0 : return (SDP_INVALID_PARAMETER);
3702 : }
3703 :
3704 0 : if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
3705 0 : SDP_PRINT("%s Parsed a=%s, %s", sdp_p->debug_str,
3706 : sdp_get_attr_name(attr_p->type),
3707 : attr_p->attr.stream_data.x_confid);
3708 : }
3709 0 : return (SDP_SUCCESS);
3710 : }
3711 :
3712 0 : sdp_result_e sdp_build_attr_x_confid (sdp_t *sdp_p, sdp_attr_t *attr_p,
3713 : flex_string *fs)
3714 : {
3715 0 : if (strlen(attr_p->attr.stream_data.x_confid) <= 0) {
3716 0 : if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
3717 0 : SDP_PRINT("%s X-confid value is not set. Cannot build a=X-confid line\n",
3718 : sdp_p->debug_str);
3719 : }
3720 :
3721 0 : return SDP_INVALID_PARAMETER;
3722 : }
3723 :
3724 0 : flex_string_sprintf(fs, "a=%s:%s\r\n",
3725 0 : sdp_attr[attr_p->type].name,
3726 0 : attr_p->attr.stream_data.x_confid);
3727 :
3728 0 : return SDP_SUCCESS;
3729 : }
3730 :
3731 0 : sdp_result_e sdp_parse_attr_group (sdp_t *sdp_p, sdp_attr_t *attr_p,
3732 : const char *ptr)
3733 : {
3734 : sdp_result_e result;
3735 : char tmp[64];
3736 0 : int i=0;
3737 :
3738 0 : if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
3739 0 : SDP_PRINT("%s Parsing a=%s", sdp_p->debug_str,
3740 : sdp_get_attr_name(attr_p->type));
3741 : }
3742 :
3743 : /* Find the a=group:<attrib> <id1> < id2> ... values */
3744 0 : ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
3745 0 : if (result != SDP_SUCCESS) {
3746 0 : sdp_parse_error(sdp_p,
3747 : "%s Warning: No group attribute value specified for "
3748 0 : "a=group line", sdp_p->debug_str);
3749 0 : sdp_p->conf_p->num_invalid_param++;
3750 0 : return (SDP_INVALID_PARAMETER);
3751 : }
3752 :
3753 0 : attr_p->attr.stream_data.group_attr = SDP_GROUP_ATTR_UNSUPPORTED;
3754 0 : for (i=0; i < SDP_MAX_GROUP_ATTR_VAL; i++) {
3755 0 : if (cpr_strncasecmp(tmp, sdp_group_attr_val[i].name,
3756 0 : sdp_group_attr_val[i].strlen) == 0) {
3757 0 : attr_p->attr.stream_data.group_attr = (sdp_group_attr_e)i;
3758 0 : break;
3759 : }
3760 : }
3761 :
3762 0 : if (attr_p->attr.stream_data.group_attr == SDP_GROUP_ATTR_UNSUPPORTED) {
3763 0 : sdp_parse_error(sdp_p,
3764 : "%s Warning: Group attribute type unsupported (%s).",
3765 0 : sdp_p->debug_str, tmp);
3766 : }
3767 :
3768 :
3769 : /*
3770 : * Scan the input line up after group:<attr> to the maximum number
3771 : * of id available.
3772 : */
3773 0 : attr_p->attr.stream_data.num_group_id =0;
3774 :
3775 0 : for (i=0; i<SDP_MAX_MEDIA_STREAMS; i++) {
3776 0 : ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
3777 :
3778 0 : if (result != SDP_SUCCESS) {
3779 0 : break;
3780 : }
3781 0 : attr_p->attr.stream_data.group_ids[i] = cpr_strdup(tmp);
3782 0 : if (!attr_p->attr.stream_data.group_ids[i]) {
3783 0 : break;
3784 : }
3785 :
3786 0 : attr_p->attr.stream_data.num_group_id++;
3787 : }
3788 :
3789 0 : if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
3790 0 : SDP_PRINT("%s Parsed a=%s:%s\n", sdp_p->debug_str,
3791 : sdp_get_attr_name(attr_p->type),
3792 : sdp_get_group_attr_name (attr_p->attr.stream_data.group_attr));
3793 0 : for (i=0; i < attr_p->attr.stream_data.num_group_id; i++) {
3794 0 : SDP_PRINT("%s Parsed group line id : %s\n", sdp_p->debug_str,
3795 : attr_p->attr.stream_data.group_ids[i]);
3796 : }
3797 : }
3798 0 : return (SDP_SUCCESS);
3799 : }
3800 :
3801 0 : sdp_result_e sdp_build_attr_group (sdp_t *sdp_p, sdp_attr_t *attr_p,
3802 : flex_string *fs)
3803 : {
3804 : int i;
3805 :
3806 0 : flex_string_sprintf(fs, "a=%s:%s",
3807 0 : sdp_attr[attr_p->type].name,
3808 : sdp_get_group_attr_name(attr_p->attr.stream_data.group_attr));
3809 :
3810 0 : for (i=0; i < attr_p->attr.stream_data.num_group_id; i++) {
3811 0 : if (attr_p->attr.stream_data.group_ids[i]) {
3812 0 : flex_string_sprintf(fs, " %s",
3813 : attr_p->attr.stream_data.group_ids[i]);
3814 : }
3815 : }
3816 :
3817 0 : flex_string_append(fs, "\r\n");
3818 :
3819 0 : return SDP_SUCCESS;
3820 : }
3821 :
3822 : /* Parse the source-filter attribute
3823 : * "a=source-filter:<filter-mode><filter-spec>"
3824 : * <filter-spec> = <nettype><addrtype><dest-addr><src_addr><src_addr>...
3825 : */
3826 0 : sdp_result_e sdp_parse_attr_source_filter (sdp_t *sdp_p, sdp_attr_t *attr_p,
3827 : const char *ptr)
3828 : {
3829 : int i;
3830 : sdp_result_e result;
3831 : char tmp[SDP_MAX_STRING_LEN];
3832 :
3833 0 : attr_p->attr.source_filter.mode = SDP_FILTER_MODE_NOT_PRESENT;
3834 0 : attr_p->attr.source_filter.nettype = SDP_NT_UNSUPPORTED;
3835 0 : attr_p->attr.source_filter.addrtype = SDP_AT_UNSUPPORTED;
3836 0 : attr_p->attr.source_filter.dest_addr[0] = '\0';
3837 0 : attr_p->attr.source_filter.num_src_addr = 0;
3838 :
3839 : /* Find the filter mode */
3840 0 : ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
3841 0 : if (result != SDP_SUCCESS) {
3842 0 : sdp_parse_error(sdp_p,
3843 : "%s Warning: No src filter attribute value specified for "
3844 0 : "a=source-filter line", sdp_p->debug_str);
3845 0 : sdp_p->conf_p->num_invalid_param++;
3846 0 : return (SDP_INVALID_PARAMETER);
3847 : }
3848 0 : for (i = 0; i < SDP_MAX_FILTER_MODE; i++) {
3849 0 : if (cpr_strncasecmp(tmp, sdp_src_filter_mode_val[i].name,
3850 0 : sdp_src_filter_mode_val[i].strlen) == 0) {
3851 0 : attr_p->attr.source_filter.mode = (sdp_src_filter_mode_e)i;
3852 0 : break;
3853 : }
3854 : }
3855 0 : if (attr_p->attr.source_filter.mode == SDP_FILTER_MODE_NOT_PRESENT) {
3856 : /* No point continuing */
3857 0 : sdp_parse_error(sdp_p,
3858 : "%s Warning: Invalid src filter mode for a=source-filter "
3859 0 : "line", sdp_p->debug_str);
3860 0 : sdp_p->conf_p->num_invalid_param++;
3861 0 : return (SDP_INVALID_PARAMETER);
3862 : }
3863 :
3864 : /* Find the network type */
3865 0 : ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
3866 0 : if (result != SDP_SUCCESS) {
3867 0 : sdp_p->conf_p->num_invalid_param++;
3868 0 : return (SDP_INVALID_PARAMETER);
3869 : }
3870 0 : for (i = 0; i < SDP_MAX_NETWORK_TYPES; i++) {
3871 0 : if (cpr_strncasecmp(tmp, sdp_nettype[i].name,
3872 0 : sdp_nettype[i].strlen) == 0) {
3873 0 : if (sdp_p->conf_p->nettype_supported[i] == TRUE) {
3874 0 : attr_p->attr.source_filter.nettype = (sdp_nettype_e)i;
3875 : }
3876 : }
3877 : }
3878 0 : if (attr_p->attr.source_filter.nettype == SDP_NT_UNSUPPORTED) {
3879 0 : sdp_parse_error(sdp_p,
3880 : "%s Warning: Network type unsupported "
3881 0 : "(%s) for a=source-filter", sdp_p->debug_str, tmp);
3882 0 : sdp_p->conf_p->num_invalid_param++;
3883 0 : return (SDP_INVALID_PARAMETER);
3884 : }
3885 :
3886 : /* Find the address type */
3887 0 : ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
3888 0 : if (result != SDP_SUCCESS) {
3889 0 : sdp_p->conf_p->num_invalid_param++;
3890 0 : return (SDP_INVALID_PARAMETER);
3891 : }
3892 0 : for (i = 0; i < SDP_MAX_ADDR_TYPES; i++) {
3893 0 : if (cpr_strncasecmp(tmp, sdp_addrtype[i].name,
3894 0 : sdp_addrtype[i].strlen) == 0) {
3895 0 : if (sdp_p->conf_p->addrtype_supported[i] == TRUE) {
3896 0 : attr_p->attr.source_filter.addrtype = (sdp_addrtype_e)i;
3897 : }
3898 : }
3899 : }
3900 0 : if (attr_p->attr.source_filter.addrtype == SDP_AT_UNSUPPORTED) {
3901 0 : if (strncmp(tmp, "*", 1) == 0) {
3902 0 : attr_p->attr.source_filter.addrtype = SDP_AT_FQDN;
3903 : } else {
3904 0 : sdp_parse_error(sdp_p,
3905 : "%s Warning: Address type unsupported "
3906 0 : "(%s) for a=source-filter", sdp_p->debug_str, tmp);
3907 0 : sdp_p->conf_p->num_invalid_param++;
3908 0 : return (SDP_INVALID_PARAMETER);
3909 : }
3910 : }
3911 :
3912 : /* Find the destination addr */
3913 0 : ptr = sdp_getnextstrtok(ptr, attr_p->attr.source_filter.dest_addr,
3914 : sizeof(attr_p->attr.source_filter.dest_addr), " \t", &result);
3915 0 : if (result != SDP_SUCCESS) {
3916 0 : sdp_parse_error(sdp_p,
3917 : "%s No filter destination address specified for "
3918 0 : "a=source-filter", sdp_p->debug_str);
3919 0 : sdp_p->conf_p->num_invalid_param++;
3920 0 : return (SDP_INVALID_PARAMETER);
3921 : }
3922 :
3923 : /* Find the list of source address to apply the filter */
3924 0 : for (i = 0; i < SDP_MAX_SRC_ADDR_LIST; i++) {
3925 0 : ptr = sdp_getnextstrtok(ptr, attr_p->attr.source_filter.src_list[i],
3926 : sizeof(attr_p->attr.source_filter.src_list[i]), " \t", &result);
3927 0 : if (result != SDP_SUCCESS) {
3928 0 : break;
3929 : }
3930 0 : attr_p->attr.source_filter.num_src_addr++;
3931 : }
3932 0 : if (attr_p->attr.source_filter.num_src_addr == 0) {
3933 0 : sdp_parse_error(sdp_p,
3934 : "%s Warning: No source list provided "
3935 0 : "for a=source-filter", sdp_p->debug_str);
3936 0 : sdp_p->conf_p->num_invalid_param++;
3937 0 : return (SDP_INVALID_PARAMETER);
3938 : }
3939 :
3940 0 : return (SDP_SUCCESS);
3941 : }
3942 :
3943 0 : sdp_result_e sdp_build_source_filter (sdp_t *sdp_p, sdp_attr_t *attr_p,
3944 : flex_string *fs)
3945 : {
3946 : int i;
3947 :
3948 0 : flex_string_sprintf(fs, "a=%s:%s %s %s %s",
3949 : sdp_get_attr_name(attr_p->type),
3950 : sdp_get_src_filter_mode_name(attr_p->attr.source_filter.mode),
3951 : sdp_get_network_name(attr_p->attr.source_filter.nettype),
3952 : sdp_get_address_name(attr_p->attr.source_filter.addrtype),
3953 0 : attr_p->attr.source_filter.dest_addr);
3954 :
3955 0 : for (i = 0; i < attr_p->attr.source_filter.num_src_addr; i++) {
3956 0 : flex_string_append(fs, " ");
3957 0 : flex_string_append(fs, attr_p->attr.source_filter.src_list[i]);
3958 : }
3959 :
3960 0 : flex_string_append(fs, "\r\n");
3961 :
3962 0 : return SDP_SUCCESS;
3963 : }
3964 :
3965 : /* Parse the rtcp-unicast attribute
3966 : * "a=rtcp-unicast:<reflection|rsi>"
3967 : */
3968 0 : sdp_result_e sdp_parse_attr_rtcp_unicast (sdp_t *sdp_p, sdp_attr_t *attr_p,
3969 : const char *ptr)
3970 : {
3971 : sdp_result_e result;
3972 : uint32_t i;
3973 : char tmp[SDP_MAX_STRING_LEN];
3974 :
3975 0 : attr_p->attr.u32_val = SDP_RTCP_UNICAST_MODE_NOT_PRESENT;
3976 :
3977 0 : memset(tmp, 0, sizeof(tmp));
3978 :
3979 0 : ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
3980 0 : if (result != SDP_SUCCESS) {
3981 0 : sdp_parse_error(sdp_p,
3982 : "%s Warning: No rtcp unicast mode specified for "
3983 0 : "a=rtcp-unicast line", sdp_p->debug_str);
3984 0 : sdp_p->conf_p->num_invalid_param++;
3985 0 : return (SDP_INVALID_PARAMETER);
3986 : }
3987 0 : for (i = 0; i < SDP_RTCP_MAX_UNICAST_MODE; i++) {
3988 0 : if (cpr_strncasecmp(tmp, sdp_rtcp_unicast_mode_val[i].name,
3989 0 : sdp_rtcp_unicast_mode_val[i].strlen) == 0) {
3990 0 : attr_p->attr.u32_val = i;
3991 0 : break;
3992 : }
3993 : }
3994 0 : if (attr_p->attr.u32_val == SDP_RTCP_UNICAST_MODE_NOT_PRESENT) {
3995 0 : sdp_parse_error(sdp_p,
3996 : "%s Warning: Invalid rtcp unicast mode for "
3997 0 : "a=rtcp-unicast line", sdp_p->debug_str);
3998 0 : sdp_p->conf_p->num_invalid_param++;
3999 0 : return (SDP_INVALID_PARAMETER);
4000 : }
4001 0 : return (SDP_SUCCESS);
4002 : }
4003 :
4004 0 : sdp_result_e sdp_build_attr_rtcp_unicast (sdp_t *sdp_p, sdp_attr_t *attr_p,
4005 : flex_string *fs)
4006 : {
4007 0 : if (attr_p->attr.u32_val >= SDP_RTCP_MAX_UNICAST_MODE) {
4008 0 : return SDP_INVALID_PARAMETER;
4009 : }
4010 :
4011 0 : flex_string_sprintf(fs, "a=%s:%s\r\n",
4012 : sdp_get_attr_name(attr_p->type),
4013 0 : sdp_get_rtcp_unicast_mode_name((sdp_rtcp_unicast_mode_e)attr_p->attr.u32_val));
4014 :
4015 0 : return SDP_SUCCESS;
4016 : }
4017 :
4018 :
4019 : /*
4020 : * store_sdescriptions_mki_or_lifetime
4021 : *
4022 : * Verifies the syntax of the MKI or lifetime parameter and stores
4023 : * it in the sdescriptions attribute struct.
4024 : *
4025 : * Inputs:
4026 : * buf - pointer to MKI or lifetime string assumes string is null
4027 : * terminated.
4028 : * attr_p - pointer to attribute struct
4029 : *
4030 : * Outputs:
4031 : * Return TRUE all is good otherwise FALSE for error.
4032 : */
4033 :
4034 : tinybool
4035 0 : store_sdescriptions_mki_or_lifetime (char *buf, sdp_attr_t *attr_p)
4036 : {
4037 :
4038 : tinybool result;
4039 : uint16_t mkiLen;
4040 : char mkiValue[SDP_SRTP_MAX_MKI_SIZE_BYTES];
4041 :
4042 : /* MKI has a colon */
4043 0 : if (strstr(buf, ":")) {
4044 0 : result = verify_sdescriptions_mki(buf, mkiValue, &mkiLen);
4045 0 : if (result) {
4046 0 : attr_p->attr.srtp_context.mki_size_bytes = mkiLen;
4047 0 : sstrncpy((char*)attr_p->attr.srtp_context.mki, mkiValue,
4048 : SDP_SRTP_MAX_MKI_SIZE_BYTES);
4049 : }
4050 :
4051 : } else {
4052 0 : result = verify_sdescriptions_lifetime(buf);
4053 0 : if (result) {
4054 0 : sstrncpy((char*)attr_p->attr.srtp_context.master_key_lifetime, buf,
4055 : SDP_SRTP_MAX_LIFETIME_BYTES);
4056 : }
4057 : }
4058 :
4059 0 : return result;
4060 :
4061 : }
4062 :
4063 : /*
4064 : * sdp_parse_sdescriptions_key_param
4065 : *
4066 : * This routine parses the srtp key-params pointed to by str.
4067 : *
4068 : * key-params = <key-method> ":" <key-info>
4069 : * key-method = "inline" / key-method-ext [note V9 only supports 'inline']
4070 : * key-info = srtp-key-info
4071 : * srtp-key-info = key-salt ["|" lifetime] ["|" mki]
4072 : * key-salt = 1*(base64) ; binary key and salt values
4073 : * ; concatenated together, and then
4074 : * ; base64 encoded [section 6.8 of
4075 : * ; RFC2046]
4076 : *
4077 : * lifetime = ["2^"] 1*(DIGIT)
4078 : * mki = mki-value ":" mki-length
4079 : * mki-value = 1*DIGIT
4080 : * mki-length = 1*3DIGIT ; range 1..128.
4081 : *
4082 : * Inputs: str - pointer to beginning of key-params and assumes
4083 : * null terminated string.
4084 : */
4085 :
4086 :
4087 : tinybool
4088 0 : sdp_parse_sdescriptions_key_param (const char *str, sdp_attr_t *attr_p,
4089 : sdp_t *sdp_p)
4090 : {
4091 : char buf[SDP_MAX_STRING_LEN],
4092 : base64decodeData[SDP_MAX_STRING_LEN];
4093 : const char *ptr;
4094 0 : sdp_result_e result = SDP_SUCCESS;
4095 0 : tinybool keyFound = FALSE;
4096 : int len,
4097 : keySize,
4098 : saltSize;
4099 : base64_result_t status;
4100 :
4101 0 : ptr = str;
4102 0 : if (cpr_strncasecmp(ptr, "inline:", 7) != 0) {
4103 0 : sdp_parse_error(sdp_p,
4104 0 : "%s Could not find keyword inline", sdp_p->debug_str);
4105 0 : sdp_p->conf_p->num_invalid_param++;
4106 0 : return FALSE;
4107 : }
4108 :
4109 : /* advance pass the inline key word */
4110 0 : ptr = ptr + 7;
4111 0 : ptr = sdp_getnextstrtok(ptr, buf, sizeof(buf), "|", &result);
4112 0 : while (result == SDP_SUCCESS) {
4113 : /* the fist time this loop executes, the key is gotten */
4114 0 : if (keyFound == FALSE) {
4115 0 : keyFound = TRUE;
4116 0 : len = SDP_MAX_STRING_LEN;
4117 : /* The key is base64 encoded composed of the master key concatenated with the
4118 : * master salt.
4119 : */
4120 0 : status = base64_decode((unsigned char *)buf, strlen(buf),
4121 : (unsigned char *)base64decodeData, &len);
4122 :
4123 0 : if (status != BASE64_SUCCESS) {
4124 0 : sdp_parse_error(sdp_p,
4125 : "%s key-salt error decoding buffer: %s",
4126 0 : sdp_p->debug_str, BASE64_RESULT_TO_STRING(status));
4127 0 : return FALSE;
4128 : }
4129 :
4130 0 : keySize = attr_p->attr.srtp_context.master_key_size_bytes;
4131 0 : saltSize = attr_p->attr.srtp_context.master_salt_size_bytes;
4132 :
4133 0 : if (len != keySize + saltSize) {
4134 0 : sdp_parse_error(sdp_p,
4135 : "%s key-salt size doesn't match: (%d, %d, %d)",
4136 0 : sdp_p->debug_str, len, keySize, saltSize);
4137 0 : return(FALSE);
4138 : }
4139 :
4140 0 : memcpy(attr_p->attr.srtp_context.master_key,
4141 : base64decodeData,
4142 : keySize);
4143 :
4144 0 : memcpy(attr_p->attr.srtp_context.master_salt,
4145 : base64decodeData + keySize,
4146 : saltSize);
4147 :
4148 : /* Used only for MGCP */
4149 0 : SDP_SRTP_CONTEXT_SET_MASTER_KEY
4150 : (attr_p->attr.srtp_context.selection_flags);
4151 0 : SDP_SRTP_CONTEXT_SET_MASTER_SALT
4152 : (attr_p->attr.srtp_context.selection_flags);
4153 :
4154 0 : } else if (store_sdescriptions_mki_or_lifetime(buf, attr_p) == FALSE) {
4155 0 : return FALSE;
4156 : }
4157 :
4158 : /* if we haven't reached the end of line, get the next token */
4159 0 : ptr = sdp_getnextstrtok(ptr, buf, sizeof(buf), "|", &result);
4160 : }
4161 :
4162 : /* if we didn't find the key, error out */
4163 0 : if (keyFound == FALSE) {
4164 0 : sdp_parse_error(sdp_p,
4165 0 : "%s Could not find sdescriptions key", sdp_p->debug_str);
4166 0 : sdp_p->conf_p->num_invalid_param++;
4167 0 : return FALSE;
4168 : }
4169 :
4170 0 : return TRUE;
4171 :
4172 : }
4173 :
4174 : /*
4175 : * sdp_build_attr_sdescriptions
4176 : *
4177 : * Builds a=crypto line for attribute type SDP_ATTR_SDESCRIPTIONS.
4178 : *
4179 : * a=crypto:tag 1*WSP crypto-suite 1*WSP key-params
4180 : *
4181 : * Where key-params = inline: <key|salt> ["|"lifetime] ["|" MKI:length]
4182 : * The key and salt is base64 encoded and lifetime and MKI/length are optional.
4183 : */
4184 :
4185 : sdp_result_e
4186 0 : sdp_build_attr_sdescriptions (sdp_t *sdp_p, sdp_attr_t *attr_p,
4187 : flex_string *fs)
4188 : {
4189 :
4190 : unsigned char base64_encoded_data[MAX_BASE64_STRING_LEN];
4191 : unsigned char base64_encoded_input[MAX_BASE64_STRING_LEN];
4192 : int keySize,
4193 : saltSize,
4194 : outputLen;
4195 : base64_result_t status;
4196 :
4197 0 : keySize = attr_p->attr.srtp_context.master_key_size_bytes;
4198 0 : saltSize = attr_p->attr.srtp_context.master_salt_size_bytes;
4199 :
4200 : /* concatenate the master key + salt then base64 encode it */
4201 0 : memcpy(base64_encoded_input,
4202 0 : attr_p->attr.srtp_context.master_key,
4203 : keySize);
4204 :
4205 0 : memcpy(base64_encoded_input + keySize,
4206 0 : attr_p->attr.srtp_context.master_salt,
4207 : saltSize);
4208 :
4209 0 : outputLen = MAX_BASE64_STRING_LEN;
4210 0 : status = base64_encode(base64_encoded_input, keySize + saltSize,
4211 : base64_encoded_data, &outputLen);
4212 :
4213 0 : if (status != BASE64_SUCCESS) {
4214 0 : if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
4215 0 : CSFLogError(logTag, "%s Error: Failure to Base64 Encoded data (%s) ",
4216 : sdp_p->debug_str, BASE64_RESULT_TO_STRING(status));
4217 : }
4218 0 : return (SDP_INVALID_PARAMETER);
4219 :
4220 : }
4221 :
4222 0 : base64_encoded_data[outputLen] = 0;
4223 :
4224 : /* lifetime and MKI parameters are optional. Only inlcude them if
4225 : * they were set.
4226 : */
4227 :
4228 :
4229 0 : if (attr_p->attr.srtp_context.master_key_lifetime[0] != 0 &&
4230 0 : attr_p->attr.srtp_context.mki[0] != 0) {
4231 0 : flex_string_sprintf(fs, "a=%s:%d %s inline:%s|%s|%s:%d\r\n",
4232 0 : sdp_attr[attr_p->type].name,
4233 : attr_p->attr.srtp_context.tag,
4234 0 : sdp_srtp_context_crypto_suite[attr_p->attr.srtp_context.suite].name,
4235 : base64_encoded_data,
4236 0 : attr_p->attr.srtp_context.master_key_lifetime,
4237 0 : attr_p->attr.srtp_context.mki,
4238 0 : attr_p->attr.srtp_context.mki_size_bytes);
4239 :
4240 0 : return SDP_SUCCESS;
4241 : }
4242 :
4243 : /* if we get here, either lifetime is populated and mki and is not or mki is populated
4244 : * and lifetime is not or neither is populated
4245 : */
4246 :
4247 0 : if (attr_p->attr.srtp_context.master_key_lifetime[0] != 0) {
4248 0 : flex_string_sprintf(fs, "a=%s:%d %s inline:%s|%s\r\n",
4249 0 : sdp_attr[attr_p->type].name,
4250 : attr_p->attr.srtp_context.tag,
4251 0 : sdp_srtp_context_crypto_suite[attr_p->attr.srtp_context.suite].name,
4252 : base64_encoded_data,
4253 0 : attr_p->attr.srtp_context.master_key_lifetime);
4254 :
4255 0 : } else if (attr_p->attr.srtp_context.mki[0] != 0) {
4256 0 : flex_string_sprintf(fs, "a=%s:%d %s inline:%s|%s:%d\r\n",
4257 0 : sdp_attr[attr_p->type].name,
4258 : attr_p->attr.srtp_context.tag,
4259 0 : sdp_srtp_context_crypto_suite[attr_p->attr.srtp_context.suite].name,
4260 : base64_encoded_data,
4261 0 : attr_p->attr.srtp_context.mki,
4262 0 : attr_p->attr.srtp_context.mki_size_bytes);
4263 :
4264 : } else {
4265 0 : flex_string_sprintf(fs, "a=%s:%d %s inline:%s\r\n",
4266 0 : sdp_attr[attr_p->type].name,
4267 : attr_p->attr.srtp_context.tag,
4268 0 : sdp_srtp_context_crypto_suite[attr_p->attr.srtp_context.suite].name,
4269 : base64_encoded_data);
4270 :
4271 : }
4272 :
4273 0 : return SDP_SUCCESS;
4274 :
4275 : }
4276 :
4277 :
4278 : /*
4279 : * sdp_parse_attr_srtp
4280 : *
4281 : * Parses Session Description for Protocol Security Descriptions
4282 : * version 2 or version 9. Grammar is of the form:
4283 : *
4284 : * a=crypto:<tag> <crypto-suite> <key-params> [<session-params>]
4285 : *
4286 : * Note session-params is not supported and will not be parsed.
4287 : * Version 2 does not contain a tag.
4288 : *
4289 : * Inputs:
4290 : * sdp_p - pointer to sdp handle
4291 : * attr_p - pointer to attribute structure
4292 : * ptr - pointer to string to be parsed
4293 : * vtype - version type
4294 : */
4295 :
4296 : sdp_result_e
4297 0 : sdp_parse_attr_srtp (sdp_t *sdp_p, sdp_attr_t *attr_p,
4298 : const char *ptr, sdp_attr_e vtype)
4299 : {
4300 :
4301 : char tmp[SDP_MAX_STRING_LEN];
4302 0 : sdp_result_e result = SDP_FAILURE;
4303 0 : int k = 0;
4304 :
4305 : /* initialize only the optional parameters */
4306 0 : attr_p->attr.srtp_context.master_key_lifetime[0] = 0;
4307 0 : attr_p->attr.srtp_context.mki[0] = 0;
4308 :
4309 : /* used only for MGCP */
4310 0 : SDP_SRTP_CONTEXT_SET_ENCRYPT_AUTHENTICATE
4311 : (attr_p->attr.srtp_context.selection_flags);
4312 :
4313 : /* get the tag only if we are version 9 */
4314 0 : if (vtype == SDP_ATTR_SDESCRIPTIONS) {
4315 0 : attr_p->attr.srtp_context.tag =
4316 0 : sdp_getnextnumtok(ptr, &ptr, " \t", &result);
4317 :
4318 0 : if (result != SDP_SUCCESS) {
4319 0 : sdp_parse_error(sdp_p,
4320 : "%s Could not find sdescriptions tag",
4321 0 : sdp_p->debug_str);
4322 0 : sdp_p->conf_p->num_invalid_param++;
4323 0 : return (SDP_INVALID_PARAMETER);
4324 :
4325 : }
4326 : }
4327 :
4328 : /* get the crypto suite */
4329 0 : ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
4330 0 : if (result != SDP_SUCCESS) {
4331 0 : sdp_parse_error(sdp_p,
4332 0 : "%s Could not find sdescriptions crypto suite", sdp_p->debug_str);
4333 0 : sdp_p->conf_p->num_invalid_param++;
4334 0 : return (SDP_INVALID_PARAMETER);
4335 : }
4336 :
4337 0 : if (!sdp_parse_context_crypto_suite(tmp, attr_p, sdp_p)) {
4338 0 : sdp_parse_error(sdp_p,
4339 0 : "%s Unsupported crypto suite", sdp_p->debug_str);
4340 0 : return (SDP_INVALID_PARAMETER);
4341 : }
4342 :
4343 0 : ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
4344 0 : if (result != SDP_SUCCESS) {
4345 0 : sdp_parse_error(sdp_p,
4346 0 : "%s Could not find sdescriptions key params", sdp_p->debug_str);
4347 0 : sdp_p->conf_p->num_invalid_param++;
4348 0 : return (SDP_INVALID_PARAMETER);
4349 : }
4350 :
4351 0 : if (!sdp_parse_sdescriptions_key_param(tmp, attr_p, sdp_p)) {
4352 0 : sdp_parse_error(sdp_p,
4353 0 : "%s Failed to parse key-params", sdp_p->debug_str);
4354 0 : return (SDP_INVALID_PARAMETER);
4355 : }
4356 :
4357 : /* if there are session parameters, scan the session parameters
4358 : * into tmp until we reach end of line. Currently the sdp parser
4359 : * does not parse session parameters but if they are present,
4360 : * we store them for the application.
4361 : */
4362 : /*sa_ignore NO_NULL_CHK
4363 : *{ptr is valid since the pointer was checked earlier and the
4364 : * function would have exited if NULL.}
4365 : */
4366 0 : while (*ptr && *ptr != '\n' && *ptr != '\r' && k < SDP_MAX_STRING_LEN) {
4367 0 : tmp[k++] = *ptr++;
4368 : }
4369 :
4370 0 : if ((k) && (k < SDP_MAX_STRING_LEN)) {
4371 0 : tmp[k] = 0;
4372 0 : attr_p->attr.srtp_context.session_parameters = cpr_strdup(tmp);
4373 : }
4374 :
4375 0 : return SDP_SUCCESS;
4376 :
4377 : }
4378 :
4379 : /* Parses crypto attribute based on the sdescriptions version
4380 : * 9 grammar.
4381 : *
4382 : */
4383 :
4384 : sdp_result_e
4385 0 : sdp_parse_attr_sdescriptions (sdp_t *sdp_p, sdp_attr_t *attr_p,
4386 : const char *ptr)
4387 : {
4388 :
4389 0 : return sdp_parse_attr_srtp(sdp_p, attr_p, ptr,
4390 : SDP_ATTR_SDESCRIPTIONS);
4391 :
4392 : }
4393 :
4394 : /* Parses X-crypto attribute based on the sdescriptions version
4395 : * 2 grammar.
4396 : *
4397 : */
4398 :
4399 0 : sdp_result_e sdp_parse_attr_srtpcontext (sdp_t *sdp_p, sdp_attr_t *attr_p,
4400 : const char *ptr)
4401 : {
4402 :
4403 0 : return sdp_parse_attr_srtp(sdp_p, attr_p, ptr,
4404 : SDP_ATTR_SRTP_CONTEXT);
4405 : }
4406 :
4407 :
4408 0 : sdp_result_e sdp_build_attr_ice_attr (sdp_t *sdp_p, sdp_attr_t *attr_p,
4409 : flex_string *fs) {
4410 0 : flex_string_sprintf(fs, "a=%s:%s\r\n",
4411 : sdp_get_attr_name(attr_p->type),
4412 0 : attr_p->attr.ice_attr);
4413 :
4414 0 : return SDP_SUCCESS;
4415 : }
4416 :
4417 :
4418 0 : sdp_result_e sdp_parse_attr_ice_attr (sdp_t *sdp_p, sdp_attr_t *attr_p, const char *ptr) {
4419 : sdp_result_e result;
4420 : char tmp[SDP_MAX_STRING_LEN];
4421 :
4422 0 : ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), "\r\n", &result);
4423 0 : if (result != SDP_SUCCESS){
4424 0 : sdp_parse_error(sdp_p,
4425 0 : "%s Warning: problem parsing ice attribute ", sdp_p->debug_str);
4426 0 : sdp_p->conf_p->num_invalid_param++;
4427 0 : return (SDP_INVALID_PARAMETER);
4428 : }
4429 :
4430 0 : snprintf(attr_p->attr.ice_attr, sizeof(attr_p->attr.ice_attr), "%s", tmp);
4431 :
4432 0 : if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
4433 0 : SDP_PRINT("%s Parsed a=%s, %s", sdp_p->debug_str, sdp_get_attr_name(attr_p->type), tmp);
4434 : }
4435 0 : return (SDP_SUCCESS);
4436 : }
4437 :
4438 :
4439 0 : sdp_result_e sdp_build_attr_simple_flag (sdp_t *sdp_p, sdp_attr_t *attr_p,
4440 : flex_string *fs) {
4441 0 : flex_string_sprintf(fs, "a=%s\r\n", sdp_get_attr_name(attr_p->type));
4442 :
4443 0 : return SDP_SUCCESS;
4444 : }
4445 :
4446 :
4447 0 : sdp_result_e sdp_parse_attr_simple_flag (sdp_t *sdp_p, sdp_attr_t *attr_p,
4448 : const char *ptr) {
4449 : /* No parameters to parse. */
4450 :
4451 0 : if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
4452 0 : SDP_PRINT("%s Parsed a=%s", sdp_p->debug_str,
4453 : sdp_get_attr_name(attr_p->type));
4454 : }
4455 :
4456 0 : return (SDP_SUCCESS);
4457 : }
4458 :
4459 0 : static sdp_result_e sdp_parse_attr_line(sdp_t *sdp_p, sdp_attr_t *attr_p,
4460 : const char *ptr, char *buf, size_t buf_len) {
4461 : sdp_result_e result;
4462 :
4463 0 : (void)sdp_getnextstrtok(ptr, buf, buf_len, "\r\n", &result);
4464 :
4465 0 : if (result != SDP_SUCCESS) {
4466 0 : sdp_parse_error(sdp_p,
4467 : "%s Warning: No string token found for %s attribute",
4468 0 : sdp_p->debug_str, sdp_get_attr_name(attr_p->type));
4469 0 : sdp_p->conf_p->num_invalid_param++;
4470 0 : return (SDP_INVALID_PARAMETER);
4471 : } else {
4472 0 : if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
4473 0 : SDP_PRINT("%s Parsed a=%s, %s", sdp_p->debug_str,
4474 : sdp_get_attr_name(attr_p->type),
4475 : buf);
4476 : }
4477 0 : return (SDP_SUCCESS);
4478 : }
4479 : }
4480 :
4481 0 : sdp_result_e sdp_parse_attr_complete_line (sdp_t *sdp_p, sdp_attr_t *attr_p,
4482 : const char *ptr)
4483 : {
4484 0 : return sdp_parse_attr_line(sdp_p, attr_p, ptr,
4485 0 : attr_p->attr.string_val,
4486 : sizeof(attr_p->attr.string_val));
4487 : }
4488 :
4489 0 : sdp_result_e sdp_parse_attr_long_line (sdp_t *sdp_p, sdp_attr_t *attr_p,
4490 : const char *ptr)
4491 : {
4492 : sdp_result_e result;
4493 : char buffer[SDP_MAX_LONG_STRING_LEN];
4494 :
4495 0 : result = sdp_parse_attr_line(sdp_p, attr_p, ptr,
4496 : buffer, sizeof(buffer));
4497 0 : if (result == SDP_SUCCESS) {
4498 0 : attr_p->attr.stringp = cpr_strdup(buffer);
4499 : }
4500 0 : return result;
4501 : }
4502 :
4503 0 : sdp_result_e sdp_build_attr_long_line (sdp_t *sdp_p, sdp_attr_t *attr_p,
4504 : flex_string *fs)
4505 : {
4506 0 : flex_string_sprintf(fs, "a=%s:%s\r\n", sdp_attr[attr_p->type].name,
4507 : attr_p->attr.stringp);
4508 0 : return SDP_SUCCESS;
4509 : }
4510 :
4511 0 : sdp_result_e sdp_build_attr_rtcp_fb(sdp_t *sdp_p,
4512 : sdp_attr_t *attr_p,
4513 : flex_string *fs)
4514 : {
4515 0 : flex_string_sprintf(fs, "a=%s:", sdp_attr[attr_p->type].name);
4516 :
4517 : /* Payload Type */
4518 0 : if (attr_p->attr.rtcp_fb.payload_num == SDP_ALL_PAYLOADS) {
4519 0 : flex_string_sprintf(fs, "* ");
4520 : } else {
4521 0 : flex_string_sprintf(fs, "%d ",attr_p->attr.rtcp_fb.payload_num);
4522 : }
4523 :
4524 : /* Feedback Type */
4525 0 : if (attr_p->attr.rtcp_fb.feedback_type < SDP_RTCP_FB_UNKNOWN) {
4526 0 : flex_string_sprintf(fs, "%s",
4527 0 : sdp_rtcp_fb_type_val[attr_p->attr.rtcp_fb.feedback_type].name);
4528 : }
4529 :
4530 : /* Feedback Type Parameters */
4531 0 : switch (attr_p->attr.rtcp_fb.feedback_type) {
4532 : case SDP_RTCP_FB_ACK:
4533 0 : if (attr_p->attr.rtcp_fb.param.ack < SDP_MAX_RTCP_FB_ACK) {
4534 0 : flex_string_sprintf(fs, " %s",
4535 0 : sdp_rtcp_fb_ack_type_val[attr_p->attr.rtcp_fb.param.ack]
4536 : .name);
4537 : }
4538 0 : break;
4539 : case SDP_RTCP_FB_CCM: /* RFC 5104 */
4540 0 : if (attr_p->attr.rtcp_fb.param.ccm < SDP_MAX_RTCP_FB_CCM) {
4541 0 : flex_string_sprintf(fs, " %s",
4542 0 : sdp_rtcp_fb_ccm_type_val[attr_p->attr.rtcp_fb.param.ccm]
4543 : .name);
4544 : }
4545 0 : break;
4546 : case SDP_RTCP_FB_NACK:
4547 0 : if (attr_p->attr.rtcp_fb.param.nack > SDP_RTCP_FB_NACK_BASIC
4548 0 : && attr_p->attr.rtcp_fb.param.nack < SDP_MAX_RTCP_FB_NACK) {
4549 0 : flex_string_sprintf(fs, " %s",
4550 0 : sdp_rtcp_fb_nack_type_val[attr_p->attr.rtcp_fb.param.nack]
4551 : .name);
4552 : }
4553 0 : break;
4554 : case SDP_RTCP_FB_TRR_INT:
4555 0 : flex_string_sprintf(fs, " %u", attr_p->attr.rtcp_fb.param.trr_int);
4556 0 : break;
4557 : case SDP_RTCP_FB_REMB:
4558 : /* No additional params after REMB */
4559 0 : break;
4560 :
4561 : case SDP_RTCP_FB_UNKNOWN:
4562 : /* Contents are in the "extra" field */
4563 0 : break;
4564 :
4565 : default:
4566 0 : CSFLogError(logTag, "%s Error: Invalid rtcp-fb enum (%d)",
4567 : sdp_p->debug_str, attr_p->attr.rtcp_fb.feedback_type);
4568 0 : return SDP_FAILURE;
4569 : }
4570 :
4571 : /* Tack on any information that cannot otherwise be represented by
4572 : * the sdp_fmtp_fb_t structure. */
4573 0 : if (attr_p->attr.rtcp_fb.extra[0]) {
4574 0 : flex_string_sprintf(fs, " %s", attr_p->attr.rtcp_fb.extra);
4575 : }
4576 :
4577 : /* Line ending */
4578 0 : flex_string_sprintf(fs, "\r\n");
4579 :
4580 0 : return SDP_SUCCESS;
4581 : }
4582 :
4583 0 : sdp_result_e sdp_parse_attr_rtcp_fb (sdp_t *sdp_p,
4584 : sdp_attr_t *attr_p,
4585 : const char *ptr)
4586 : {
4587 0 : sdp_result_e result = SDP_SUCCESS;
4588 0 : sdp_fmtp_fb_t *rtcp_fb_p = &(attr_p->attr.rtcp_fb);
4589 : int i;
4590 :
4591 : /* Set up attribute fields */
4592 0 : rtcp_fb_p->payload_num = 0;
4593 0 : rtcp_fb_p->feedback_type = SDP_RTCP_FB_UNKNOWN;
4594 0 : rtcp_fb_p->extra[0] = '\0';
4595 :
4596 : /* Skip WS (just in case) */
4597 0 : while (*ptr == ' ' || *ptr == '\t') {
4598 0 : ptr++;
4599 : }
4600 :
4601 : /* Look for the special "*" payload type */
4602 0 : if (*ptr == '*') {
4603 0 : rtcp_fb_p->payload_num = SDP_ALL_PAYLOADS;
4604 0 : ptr++;
4605 : } else {
4606 : /* If the pt is not '*', parse it out as an integer */
4607 0 : rtcp_fb_p->payload_num = (uint16_t)sdp_getnextnumtok(ptr, &ptr,
4608 : " \t", &result);
4609 0 : if (result != SDP_SUCCESS) {
4610 0 : sdp_parse_error(sdp_p,
4611 : "%s Warning: could not parse payload type for rtcp-fb attribute",
4612 0 : sdp_p->debug_str);
4613 0 : sdp_p->conf_p->num_invalid_param++;
4614 :
4615 0 : return SDP_INVALID_PARAMETER;
4616 : }
4617 : }
4618 :
4619 : /* Read feedback type */
4620 0 : i = find_token_enum("rtcp-fb attribute", sdp_p, &ptr, sdp_rtcp_fb_type_val,
4621 : SDP_MAX_RTCP_FB, SDP_RTCP_FB_UNKNOWN);
4622 0 : if (i < 0) {
4623 0 : sdp_parse_error(sdp_p,
4624 : "%s Warning: could not parse feedback type for rtcp-fb attribute",
4625 0 : sdp_p->debug_str);
4626 0 : sdp_p->conf_p->num_invalid_param++;
4627 0 : return SDP_INVALID_PARAMETER;
4628 : }
4629 0 : rtcp_fb_p->feedback_type = (sdp_rtcp_fb_type_e) i;
4630 :
4631 0 : switch(rtcp_fb_p->feedback_type) {
4632 : case SDP_RTCP_FB_ACK:
4633 0 : i = find_token_enum("rtcp-fb ack type", sdp_p, &ptr,
4634 : sdp_rtcp_fb_ack_type_val,
4635 : SDP_MAX_RTCP_FB_ACK, SDP_RTCP_FB_ACK_UNKNOWN);
4636 0 : if (i < 0) {
4637 0 : sdp_parse_error(sdp_p,
4638 : "%s Warning: could not parse ack type for rtcp-fb attribute",
4639 0 : sdp_p->debug_str);
4640 0 : sdp_p->conf_p->num_invalid_param++;
4641 0 : return SDP_INVALID_PARAMETER;
4642 : }
4643 0 : rtcp_fb_p->param.ack = (sdp_rtcp_fb_ack_type_e) i;
4644 0 : break;
4645 :
4646 : case SDP_RTCP_FB_CCM:
4647 0 : i = find_token_enum("rtcp-fb ccm type", sdp_p, &ptr,
4648 : sdp_rtcp_fb_ccm_type_val,
4649 : SDP_MAX_RTCP_FB_CCM, SDP_RTCP_FB_CCM_UNKNOWN);
4650 0 : if (i < 0) {
4651 0 : sdp_parse_error(sdp_p,
4652 : "%s Warning: could not parse ccm type for rtcp-fb attribute",
4653 0 : sdp_p->debug_str);
4654 0 : sdp_p->conf_p->num_invalid_param++;
4655 0 : return SDP_INVALID_PARAMETER;
4656 : }
4657 0 : rtcp_fb_p->param.ccm = (sdp_rtcp_fb_ccm_type_e) i;
4658 :
4659 : /* TODO -- We don't currently parse tmmbr parameters or vbcm
4660 : submessage types. If we decide to support these modes of
4661 : operation, we probably want to add parsing code for them.
4662 : For the time being, they'll just end up parsed into "extra"
4663 : Bug 1097169.
4664 : */
4665 0 : break;
4666 :
4667 : case SDP_RTCP_FB_NACK:
4668 : /* Skip any remaining WS -- see
4669 : http://code.google.com/p/webrtc/issues/detail?id=1922 */
4670 0 : while (*ptr == ' ' || *ptr == '\t') {
4671 0 : ptr++;
4672 : }
4673 : /* Check for empty string */
4674 0 : if (*ptr == '\r') {
4675 0 : rtcp_fb_p->param.nack = SDP_RTCP_FB_NACK_BASIC;
4676 0 : break;
4677 : }
4678 0 : i = find_token_enum("rtcp-fb nack type", sdp_p, &ptr,
4679 : sdp_rtcp_fb_nack_type_val,
4680 : SDP_MAX_RTCP_FB_NACK, SDP_RTCP_FB_NACK_UNKNOWN);
4681 0 : if (i < 0) {
4682 0 : sdp_parse_error(sdp_p,
4683 : "%s Warning: could not parse nack type for rtcp-fb attribute",
4684 0 : sdp_p->debug_str);
4685 0 : sdp_p->conf_p->num_invalid_param++;
4686 0 : return SDP_INVALID_PARAMETER;
4687 : }
4688 0 : rtcp_fb_p->param.nack = (sdp_rtcp_fb_nack_type_e) i;
4689 0 : break;
4690 :
4691 : case SDP_RTCP_FB_TRR_INT:
4692 0 : rtcp_fb_p->param.trr_int = sdp_getnextnumtok(ptr, &ptr,
4693 : " \t", &result);
4694 0 : if (result != SDP_SUCCESS) {
4695 0 : sdp_parse_error(sdp_p,
4696 : "%s Warning: could not parse trr-int value for rtcp-fb "
4697 0 : "attribute", sdp_p->debug_str);
4698 0 : sdp_p->conf_p->num_invalid_param++;
4699 0 : return SDP_INVALID_PARAMETER;
4700 : }
4701 0 : break;
4702 :
4703 : case SDP_RTCP_FB_REMB:
4704 : /* No additional tokens to parse after goog-remb */
4705 0 : break;
4706 :
4707 : case SDP_RTCP_FB_UNKNOWN:
4708 : /* Handled by "extra", below */
4709 0 : break;
4710 :
4711 : default:
4712 : /* This is an internal error, not a parsing error */
4713 0 : CSFLogError(logTag, "%s Error: Invalid rtcp-fb enum (%d)",
4714 : sdp_p->debug_str, attr_p->attr.rtcp_fb.feedback_type);
4715 0 : return SDP_FAILURE;
4716 : }
4717 :
4718 : /* Skip any remaining WS */
4719 0 : while (*ptr == ' ' || *ptr == '\t') {
4720 0 : ptr++;
4721 : }
4722 :
4723 : /* Just store the rest of the line in "extra" -- this will return
4724 : a failure result if there is no more text, but that's fine. */
4725 0 : ptr = sdp_getnextstrtok(ptr, rtcp_fb_p->extra,
4726 : sizeof(rtcp_fb_p->extra), "\r\n", &result);
4727 :
4728 0 : return SDP_SUCCESS;
4729 : }
4730 :
4731 0 : sdp_result_e sdp_build_attr_setup(sdp_t *sdp_p,
4732 : sdp_attr_t *attr_p,
4733 : flex_string *fs)
4734 : {
4735 0 : switch (attr_p->attr.setup) {
4736 : case SDP_SETUP_ACTIVE:
4737 : case SDP_SETUP_PASSIVE:
4738 : case SDP_SETUP_ACTPASS:
4739 : case SDP_SETUP_HOLDCONN:
4740 0 : flex_string_sprintf(fs, "a=%s:%s\r\n",
4741 0 : sdp_attr[attr_p->type].name,
4742 0 : sdp_setup_type_val[attr_p->attr.setup].name);
4743 0 : break;
4744 : default:
4745 0 : CSFLogError(logTag, "%s Error: Invalid setup enum (%d)",
4746 : sdp_p->debug_str, attr_p->attr.setup);
4747 0 : return SDP_FAILURE;
4748 : }
4749 :
4750 0 : return SDP_SUCCESS;
4751 : }
4752 :
4753 0 : sdp_result_e sdp_parse_attr_setup(sdp_t *sdp_p,
4754 : sdp_attr_t *attr_p,
4755 : const char *ptr)
4756 : {
4757 0 : int i = find_token_enum("setup attribute", sdp_p, &ptr,
4758 : sdp_setup_type_val,
4759 : SDP_MAX_SETUP, SDP_SETUP_UNKNOWN);
4760 :
4761 0 : if (i < 0) {
4762 0 : sdp_parse_error(sdp_p,
4763 : "%s Warning: could not parse setup attribute",
4764 0 : sdp_p->debug_str);
4765 0 : sdp_p->conf_p->num_invalid_param++;
4766 0 : return SDP_INVALID_PARAMETER;
4767 : }
4768 :
4769 0 : attr_p->attr.setup = (sdp_setup_type_e) i;
4770 :
4771 0 : switch (attr_p->attr.setup) {
4772 : case SDP_SETUP_ACTIVE:
4773 : case SDP_SETUP_PASSIVE:
4774 : case SDP_SETUP_ACTPASS:
4775 : case SDP_SETUP_HOLDCONN:
4776 : /* All these values are OK */
4777 0 : break;
4778 : case SDP_SETUP_UNKNOWN:
4779 0 : sdp_parse_error(sdp_p,
4780 : "%s Warning: Unknown setup attribute",
4781 0 : sdp_p->debug_str);
4782 0 : return SDP_INVALID_PARAMETER;
4783 : default:
4784 : /* This is an internal error, not a parsing error */
4785 0 : CSFLogError(logTag, "%s Error: Invalid setup enum (%d)",
4786 : sdp_p->debug_str, attr_p->attr.setup);
4787 0 : return SDP_FAILURE;
4788 : }
4789 :
4790 0 : return SDP_SUCCESS;
4791 : }
4792 :
4793 0 : sdp_result_e sdp_build_attr_connection(sdp_t *sdp_p,
4794 : sdp_attr_t *attr_p,
4795 : flex_string *fs)
4796 : {
4797 0 : switch (attr_p->attr.connection) {
4798 : case SDP_CONNECTION_NEW:
4799 : case SDP_CONNECTION_EXISTING:
4800 0 : flex_string_sprintf(fs, "a=%s:%s\r\n",
4801 0 : sdp_attr[attr_p->type].name,
4802 0 : sdp_connection_type_val[attr_p->attr.connection].name);
4803 0 : break;
4804 : default:
4805 0 : CSFLogError(logTag, "%s Error: Invalid connection enum (%d)",
4806 : sdp_p->debug_str, attr_p->attr.connection);
4807 0 : return SDP_FAILURE;
4808 : }
4809 :
4810 0 : return SDP_SUCCESS;
4811 : }
4812 :
4813 0 : sdp_result_e sdp_parse_attr_connection(sdp_t *sdp_p,
4814 : sdp_attr_t *attr_p,
4815 : const char *ptr)
4816 : {
4817 0 : int i = find_token_enum("connection attribute", sdp_p, &ptr,
4818 : sdp_connection_type_val,
4819 : SDP_MAX_CONNECTION, SDP_CONNECTION_UNKNOWN);
4820 :
4821 0 : if (i < 0) {
4822 0 : sdp_parse_error(sdp_p,
4823 : "%s Warning: could not parse connection attribute",
4824 0 : sdp_p->debug_str);
4825 0 : sdp_p->conf_p->num_invalid_param++;
4826 0 : return SDP_INVALID_PARAMETER;
4827 : }
4828 :
4829 0 : attr_p->attr.connection = (sdp_connection_type_e) i;
4830 :
4831 0 : switch (attr_p->attr.connection) {
4832 : case SDP_CONNECTION_NEW:
4833 : case SDP_CONNECTION_EXISTING:
4834 : /* All these values are OK */
4835 0 : break;
4836 : case SDP_CONNECTION_UNKNOWN:
4837 0 : sdp_parse_error(sdp_p,
4838 : "%s Warning: Unknown connection attribute",
4839 0 : sdp_p->debug_str);
4840 0 : return SDP_INVALID_PARAMETER;
4841 : default:
4842 : /* This is an internal error, not a parsing error */
4843 0 : CSFLogError(logTag, "%s Error: Invalid connection enum (%d)",
4844 : sdp_p->debug_str, attr_p->attr.connection);
4845 0 : return SDP_FAILURE;
4846 : }
4847 0 : return SDP_SUCCESS;
4848 : }
4849 :
4850 0 : sdp_result_e sdp_build_attr_extmap(sdp_t *sdp_p,
4851 : sdp_attr_t *attr_p,
4852 : flex_string *fs)
4853 : {
4854 0 : flex_string_sprintf(fs, "a=extmap:%d %s\r\n",
4855 0 : attr_p->attr.extmap.id,
4856 0 : attr_p->attr.extmap.uri);
4857 :
4858 0 : return SDP_SUCCESS;
4859 : }
4860 :
4861 0 : sdp_result_e sdp_parse_attr_extmap(sdp_t *sdp_p,
4862 : sdp_attr_t *attr_p,
4863 : const char *ptr)
4864 : {
4865 : sdp_result_e result;
4866 :
4867 0 : attr_p->attr.extmap.id = 0;
4868 0 : attr_p->attr.extmap.media_direction = SDP_DIRECTION_SENDRECV;
4869 0 : attr_p->attr.extmap.media_direction_specified = FALSE;
4870 0 : attr_p->attr.extmap.uri[0] = '\0';
4871 0 : attr_p->attr.extmap.extension_attributes[0] = '\0';
4872 :
4873 : /* Find the payload type number. */
4874 0 : attr_p->attr.extmap.id =
4875 0 : (uint16_t)sdp_getnextnumtok(ptr, &ptr, "/ \t", &result);
4876 0 : if (result != SDP_SUCCESS) {
4877 0 : sdp_parse_error(sdp_p,
4878 : "%s Warning: Invalid extmap id specified for %s attribute.",
4879 0 : sdp_p->debug_str, sdp_get_attr_name(attr_p->type));
4880 0 : sdp_p->conf_p->num_invalid_param++;
4881 0 : return (SDP_INVALID_PARAMETER);
4882 : }
4883 :
4884 0 : if (*ptr == '/') {
4885 : char direction[SDP_MAX_STRING_LEN+1];
4886 0 : ++ptr; /* Skip over '/' */
4887 0 : ptr = sdp_getnextstrtok(ptr, direction,
4888 : sizeof(direction), " \t", &result);
4889 0 : if (result != SDP_SUCCESS) {
4890 0 : sdp_parse_error(sdp_p,
4891 : "%s Warning: Invalid direction specified in %s attribute.",
4892 0 : sdp_p->debug_str, sdp_get_attr_name(attr_p->type));
4893 0 : sdp_p->conf_p->num_invalid_param++;
4894 0 : return (SDP_INVALID_PARAMETER);
4895 : }
4896 :
4897 0 : if (!cpr_strcasecmp(direction, "sendrecv")) {
4898 0 : attr_p->attr.extmap.media_direction = SDP_DIRECTION_SENDRECV;
4899 0 : } else if (!cpr_strcasecmp(direction, "sendonly")) {
4900 0 : attr_p->attr.extmap.media_direction = SDP_DIRECTION_SENDONLY;
4901 0 : } else if (!cpr_strcasecmp(direction, "recvonly")) {
4902 0 : attr_p->attr.extmap.media_direction = SDP_DIRECTION_RECVONLY;
4903 0 : } else if (!cpr_strcasecmp(direction, "inactive")) {
4904 0 : attr_p->attr.extmap.media_direction = SDP_DIRECTION_INACTIVE;
4905 : } else {
4906 0 : sdp_parse_error(sdp_p,
4907 : "%s Warning: Invalid direction specified in %s attribute.",
4908 0 : sdp_p->debug_str, sdp_get_attr_name(attr_p->type));
4909 0 : sdp_p->conf_p->num_invalid_param++;
4910 0 : return (SDP_INVALID_PARAMETER);
4911 : }
4912 0 : attr_p->attr.extmap.media_direction_specified = TRUE;
4913 : }
4914 :
4915 0 : ptr = sdp_getnextstrtok(ptr, attr_p->attr.extmap.uri,
4916 : sizeof(attr_p->attr.extmap.uri), " \t", &result);
4917 0 : if (result != SDP_SUCCESS) {
4918 0 : sdp_parse_error(sdp_p,
4919 : "%s Warning: No uri specified in %s attribute.",
4920 0 : sdp_p->debug_str, sdp_get_attr_name(attr_p->type));
4921 0 : sdp_p->conf_p->num_invalid_param++;
4922 0 : return (SDP_INVALID_PARAMETER);
4923 : }
4924 :
4925 0 : while (*ptr == ' ' || *ptr == '\t') {
4926 0 : ++ptr;
4927 : }
4928 :
4929 : /* Grab everything that follows, even if it contains whitespace */
4930 0 : ptr = sdp_getnextstrtok(ptr, attr_p->attr.extmap.extension_attributes,
4931 : sizeof(attr_p->attr.extmap.extension_attributes), "\r\n", &result);
4932 :
4933 0 : if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
4934 0 : SDP_PRINT("%s Parsed a=%s, id %u, direction %s, "
4935 : "uri %s, extension %s", sdp_p->debug_str,
4936 : sdp_get_attr_name(attr_p->type),
4937 : attr_p->attr.extmap.id,
4938 : SDP_DIRECTION_PRINT(attr_p->attr.extmap.media_direction),
4939 : attr_p->attr.extmap.uri,
4940 : attr_p->attr.extmap.extension_attributes);
4941 : }
4942 :
4943 0 : return (SDP_SUCCESS);
4944 : }
4945 :
4946 0 : sdp_result_e sdp_parse_attr_msid(sdp_t *sdp_p,
4947 : sdp_attr_t *attr_p,
4948 : const char *ptr)
4949 : {
4950 : sdp_result_e result;
4951 :
4952 0 : ptr = sdp_getnextstrtok(ptr, attr_p->attr.msid.identifier,
4953 : sizeof(attr_p->attr.msid.identifier), " \t", &result);
4954 0 : if (result != SDP_SUCCESS) {
4955 0 : sdp_parse_error(sdp_p, "%s Warning: Bad msid identity value",
4956 0 : sdp_p->debug_str);
4957 0 : sdp_p->conf_p->num_invalid_param++;
4958 0 : return SDP_INVALID_PARAMETER;
4959 : }
4960 :
4961 0 : ptr = sdp_getnextstrtok(ptr, attr_p->attr.msid.appdata,
4962 : sizeof(attr_p->attr.msid.appdata), " \t", &result);
4963 0 : if ((result != SDP_SUCCESS) && (result != SDP_EMPTY_TOKEN)) {
4964 0 : sdp_parse_error(sdp_p, "%s Warning: Bad msid appdata value",
4965 0 : sdp_p->debug_str);
4966 0 : sdp_p->conf_p->num_invalid_param++;
4967 0 : return SDP_INVALID_PARAMETER;
4968 : }
4969 0 : if (result == SDP_EMPTY_TOKEN) {
4970 0 : attr_p->attr.msid.appdata[0] = '\0';
4971 : }
4972 :
4973 0 : if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
4974 0 : SDP_PRINT("%s Parsed a=msid, %s %s", sdp_p->debug_str,
4975 : attr_p->attr.msid.identifier, attr_p->attr.msid.appdata);
4976 : }
4977 :
4978 0 : return SDP_SUCCESS;
4979 : }
4980 :
4981 :
4982 0 : sdp_result_e sdp_build_attr_msid(sdp_t *sdp_p,
4983 : sdp_attr_t *attr_p,
4984 : flex_string *fs)
4985 : {
4986 0 : flex_string_sprintf(fs, "a=msid:%s%s%s\r\n",
4987 0 : attr_p->attr.msid.identifier,
4988 0 : attr_p->attr.msid.appdata[0] ? " " : "",
4989 0 : attr_p->attr.msid.appdata);
4990 0 : return SDP_SUCCESS;
4991 : }
4992 :
4993 0 : sdp_result_e sdp_parse_attr_msid_semantic(sdp_t *sdp_p,
4994 : sdp_attr_t *attr_p,
4995 : const char *ptr)
4996 : {
4997 : sdp_result_e result;
4998 : int i;
4999 :
5000 0 : ptr = sdp_getnextstrtok(ptr,
5001 0 : attr_p->attr.msid_semantic.semantic,
5002 : sizeof(attr_p->attr.msid_semantic.semantic),
5003 : " \t",
5004 : &result);
5005 :
5006 0 : if (result != SDP_SUCCESS) {
5007 0 : sdp_parse_error(sdp_p, "%s Warning: Bad msid-semantic attribute; "
5008 : "missing semantic",
5009 0 : sdp_p->debug_str);
5010 0 : sdp_p->conf_p->num_invalid_param++;
5011 0 : return SDP_INVALID_PARAMETER;
5012 : }
5013 :
5014 0 : for (i = 0; i < SDP_MAX_MEDIA_STREAMS; ++i) {
5015 : /* msid-id can be up to 64 characters long, plus null terminator */
5016 : char temp[65];
5017 0 : ptr = sdp_getnextstrtok(ptr, temp, sizeof(temp), " \t", &result);
5018 :
5019 0 : if (result != SDP_SUCCESS) {
5020 0 : break;
5021 : }
5022 :
5023 0 : attr_p->attr.msid_semantic.msids[i] = cpr_strdup(temp);
5024 : }
5025 :
5026 0 : if ((result != SDP_SUCCESS) && (result != SDP_EMPTY_TOKEN)) {
5027 0 : sdp_parse_error(sdp_p, "%s Warning: Bad msid-semantic attribute",
5028 0 : sdp_p->debug_str);
5029 0 : sdp_p->conf_p->num_invalid_param++;
5030 0 : return SDP_INVALID_PARAMETER;
5031 : }
5032 :
5033 0 : if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
5034 0 : SDP_PRINT("%s Parsed a=msid-semantic, %s", sdp_p->debug_str,
5035 : attr_p->attr.msid_semantic.semantic);
5036 0 : for (i = 0; i < SDP_MAX_MEDIA_STREAMS; ++i) {
5037 0 : if (!attr_p->attr.msid_semantic.msids[i]) {
5038 0 : break;
5039 : }
5040 :
5041 0 : SDP_PRINT("%s ... msid %s", sdp_p->debug_str,
5042 : attr_p->attr.msid_semantic.msids[i]);
5043 : }
5044 : }
5045 :
5046 0 : return SDP_SUCCESS;
5047 : }
5048 :
5049 :
5050 0 : sdp_result_e sdp_build_attr_msid_semantic(sdp_t *sdp_p,
5051 : sdp_attr_t *attr_p,
5052 : flex_string *fs)
5053 : {
5054 : int i;
5055 0 : flex_string_sprintf(fs, "a=msid-semantic:%s",
5056 0 : attr_p->attr.msid_semantic.semantic);
5057 0 : for (i = 0; i < SDP_MAX_MEDIA_STREAMS; ++i) {
5058 0 : if (!attr_p->attr.msid_semantic.msids[i]) {
5059 0 : break;
5060 : }
5061 :
5062 0 : flex_string_sprintf(fs, " %s",
5063 : attr_p->attr.msid_semantic.msids[i]);
5064 : }
5065 0 : flex_string_sprintf(fs, "\r\n");
5066 0 : return SDP_SUCCESS;
5067 : }
5068 :
5069 0 : sdp_result_e sdp_parse_attr_ssrc(sdp_t *sdp_p,
5070 : sdp_attr_t *attr_p,
5071 : const char *ptr)
5072 : {
5073 : sdp_result_e result;
5074 :
5075 0 : attr_p->attr.ssrc.ssrc =
5076 0 : (uint32_t)sdp_getnextnumtok(ptr, &ptr, " \t", &result);
5077 :
5078 0 : if (result != SDP_SUCCESS) {
5079 0 : sdp_parse_error(sdp_p, "%s Warning: Bad ssrc attribute, cannot parse ssrc",
5080 0 : sdp_p->debug_str);
5081 0 : sdp_p->conf_p->num_invalid_param++;
5082 0 : return SDP_INVALID_PARAMETER;
5083 : }
5084 :
5085 : /* Skip any remaining WS */
5086 0 : while (*ptr == ' ' || *ptr == '\t') {
5087 0 : ptr++;
5088 : }
5089 :
5090 : /* Just store the rest of the line in "attribute" -- this will return
5091 : a failure result if there is no more text, but that's fine. */
5092 0 : ptr = sdp_getnextstrtok(ptr,
5093 0 : attr_p->attr.ssrc.attribute,
5094 : sizeof(attr_p->attr.ssrc.attribute),
5095 : "\r\n",
5096 : &result);
5097 :
5098 0 : return SDP_SUCCESS;
5099 : }
5100 :
5101 :
5102 0 : sdp_result_e sdp_build_attr_ssrc(sdp_t *sdp_p,
5103 : sdp_attr_t *attr_p,
5104 : flex_string *fs)
5105 : {
5106 0 : flex_string_sprintf(fs, "a=ssrc:%s%s%s\r\n",
5107 : attr_p->attr.ssrc.ssrc,
5108 0 : attr_p->attr.ssrc.attribute[0] ? " " : "",
5109 0 : attr_p->attr.ssrc.attribute);
5110 0 : return SDP_SUCCESS;
5111 : }
|