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