Bug 1890689 apply drift correction to input rate instead of output rate r=pehrsons
[gecko.git] / third_party / sipcc / sdp_token.c
blobb570d8169009f66beb3b9bc07b10b70e1e940b3b
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/. */
5 #include <errno.h>
7 #include "sdp_os_defs.h"
8 #include "sipcc_sdp.h"
9 #include "sdp_private.h"
11 #include "sdp_log.h"
12 #include "prprf.h"
14 static const char *logTag = "sdp_token";
16 #define MCAST_STRING_LEN 4
19 sdp_result_e sdp_parse_version (sdp_t *sdp_p, uint16_t level, const char *ptr)
21 sdp_result_e result = SDP_FAILURE;
23 sdp_p->version = (uint16_t)sdp_getnextnumtok(ptr, &ptr, " \t", &result);
24 if ((result != SDP_SUCCESS) || (sdp_p->version != SDP_CURRENT_VERSION)) {
25 sdp_parse_error(sdp_p,
26 "%s Invalid version (%u) found, parse failed.",
27 sdp_p->debug_str, (unsigned)sdp_p->version);
28 sdp_p->conf_p->num_invalid_param++;
29 return (SDP_INVALID_PARAMETER);
32 if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
33 SDP_PRINT("%s Parse version line successful, version %u",
34 sdp_p->debug_str, (unsigned)sdp_p->version);
36 return (SDP_SUCCESS);
39 sdp_result_e sdp_build_version (sdp_t *sdp_p, uint16_t level, flex_string *fs)
41 if (sdp_p->version == SDP_INVALID_VALUE) {
42 if (sdp_p->conf_p->version_reqd == TRUE) {
43 SDPLogError(logTag, "%s Invalid version for v= line, "
44 "build failed.", sdp_p->debug_str);
45 sdp_p->conf_p->num_invalid_param++;
46 return (SDP_INVALID_PARAMETER);
47 } else {
48 /* v= line is not required. */
49 return (SDP_SUCCESS);
53 flex_string_sprintf(fs, "v=%u\r\n", (unsigned)sdp_p->version);
55 if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
56 SDP_PRINT("%s Built v= version line", sdp_p->debug_str);
58 return (SDP_SUCCESS);
61 static sdp_result_e sdp_verify_unsigned(const char *ptr, uint64_t max_value)
63 uint64_t numeric_value;
64 /* Checking for only numbers since PR_sscanf will ignore trailing
65 characters */
66 size_t end = strspn(ptr, "0123456789");
68 if (ptr[end] != '\0')
69 return SDP_INVALID_PARAMETER;
71 if (PR_sscanf(ptr, "%llu", &numeric_value) != 1)
72 return SDP_INVALID_PARAMETER;
74 if (numeric_value > max_value)
75 return SDP_INVALID_PARAMETER;
77 return SDP_SUCCESS;
80 sdp_result_e sdp_parse_owner (sdp_t *sdp_p, uint16_t level, const char *ptr)
82 int i;
83 sdp_result_e result;
84 char tmp[SDP_MAX_STRING_LEN];
85 /* The spec says this:
87 The numeric value of the session id
88 and version in the o line MUST be representable with a 64 bit signed
89 integer. The initial value of the version MUST be less than
90 (2**62)-1, to avoid rollovers.
92 const uint64_t max_value_sessid = ((((uint64_t) 1) << 63) - 1);
93 /* Do not check that this is 2^62 - 1; that's just the limit on
94 * the initial version, not every version number. */
95 const uint64_t max_value_version = ((((uint64_t) 1) << 63) - 1);
97 if (sdp_p->owner_name[0] != '\0') {
98 sdp_p->conf_p->num_invalid_token_order++;
99 sdp_parse_error(sdp_p,
100 "%s Warning: More than one o= line specified.",
101 sdp_p->debug_str);
104 /* Find the owner name. */
105 ptr = sdp_getnextstrtok(ptr, sdp_p->owner_name, sizeof(sdp_p->owner_name), " \t", &result);
106 if (result != SDP_SUCCESS) {
107 sdp_parse_error(sdp_p,
108 "%s No owner name specified for o=.",
109 sdp_p->debug_str);
110 sdp_p->conf_p->num_invalid_param++;
111 return (SDP_INVALID_PARAMETER);
114 /* Find the owner session id. This is a numeric field but is
115 * stored as a string since it may be 64 bit.
117 ptr = sdp_getnextstrtok(ptr, sdp_p->owner_sessid, sizeof(sdp_p->owner_sessid), " \t", &result);
118 if (result == SDP_SUCCESS) {
119 /* Make sure the sessid is numeric, even though we store it as
120 * a string.
122 result = sdp_verify_unsigned(sdp_p->owner_sessid, max_value_sessid);
124 if (result != SDP_SUCCESS) {
125 sdp_parse_error(sdp_p,
126 "%s Invalid owner session id specified for o=.",
127 sdp_p->debug_str);
128 sdp_p->conf_p->num_invalid_param++;
129 return (SDP_INVALID_PARAMETER);
132 /* Find the owner version. */
133 ptr = sdp_getnextstrtok(ptr, sdp_p->owner_version, sizeof(sdp_p->owner_version), " \t", &result);
134 if (result == SDP_SUCCESS) {
135 /* Make sure the version is numeric, even though we store it as
136 * a string.
138 result = sdp_verify_unsigned(sdp_p->owner_version, max_value_version);
140 if (result != SDP_SUCCESS) {
141 sdp_parse_error(sdp_p,
142 "%s Invalid owner version specified for o=.",
143 sdp_p->debug_str);
144 sdp_p->conf_p->num_invalid_param++;
145 return (SDP_INVALID_PARAMETER);
148 /* Find the owner network type. */
149 ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
150 if (result != SDP_SUCCESS) {
151 sdp_parse_error(sdp_p,
152 "%s No owner network type specified for o=.",
153 sdp_p->debug_str);
154 sdp_p->conf_p->num_invalid_param++;
155 return (SDP_INVALID_PARAMETER);
157 sdp_p->owner_network_type = SDP_NT_UNSUPPORTED;
158 for (i=0; i < SDP_MAX_NETWORK_TYPES; i++) {
159 if (cpr_strncasecmp(tmp, sdp_nettype[i].name,
160 sdp_nettype[i].strlen) == 0) {
161 if (sdp_p->conf_p->nettype_supported[i] == TRUE) {
162 sdp_p->owner_network_type = (sdp_nettype_e)i;
166 if (sdp_p->owner_network_type == SDP_NT_UNSUPPORTED) {
167 sdp_parse_error(sdp_p,
168 "%s Owner network type unsupported (%s)",
169 sdp_p->debug_str, tmp);
170 sdp_p->conf_p->num_invalid_param++;
171 return (SDP_INVALID_PARAMETER);
174 /* Find the owner address type. */
175 ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
176 if (result != SDP_SUCCESS) {
177 sdp_parse_error(sdp_p,
178 "%s No owner address type specified for o=.",
179 sdp_p->debug_str);
180 sdp_p->conf_p->num_invalid_param++;
181 return (SDP_INVALID_PARAMETER);
183 sdp_p->owner_addr_type = SDP_AT_UNSUPPORTED;
184 for (i=0; i < SDP_MAX_ADDR_TYPES; i++) {
185 if (cpr_strncasecmp(tmp, sdp_addrtype[i].name,
186 sdp_addrtype[i].strlen) == 0) {
187 if (sdp_p->conf_p->addrtype_supported[i] == TRUE) {
188 sdp_p->owner_addr_type = (sdp_addrtype_e)i;
192 if ((sdp_p->owner_addr_type == SDP_AT_UNSUPPORTED) &&
193 (sdp_p->owner_network_type != SDP_NT_ATM)) {
194 sdp_parse_error(sdp_p,
195 "%s Owner address type unsupported (%s)",
196 sdp_p->debug_str, tmp);
197 sdp_p->conf_p->num_invalid_param++;
198 return (SDP_INVALID_PARAMETER);
201 /* Find the owner address. */
202 ptr = sdp_getnextstrtok(ptr, sdp_p->owner_addr, sizeof(sdp_p->owner_addr), " \t", &result);
203 if (result != SDP_SUCCESS) {
204 sdp_parse_error(sdp_p,
205 "%s No owner address specified.", sdp_p->debug_str);
206 sdp_p->conf_p->num_invalid_param++;
207 return (SDP_INVALID_PARAMETER);
210 if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
211 SDP_PRINT("%s Parse owner: name %s, session id %s, version %s",
212 sdp_p->debug_str, sdp_p->owner_name, sdp_p->owner_sessid,
213 sdp_p->owner_version);
214 SDP_PRINT("%s network %s, address type %s, "
215 "address %s", sdp_p->debug_str,
216 sdp_get_network_name(sdp_p->owner_network_type),
217 sdp_get_address_name(sdp_p->owner_addr_type),
218 sdp_p->owner_addr);
220 return (SDP_SUCCESS);
223 sdp_result_e sdp_build_owner (sdp_t *sdp_p, uint16_t level, flex_string *fs)
225 if ((sdp_p->owner_name[0] == '\0') ||
226 (sdp_p->owner_network_type >= SDP_MAX_NETWORK_TYPES) ||
227 (sdp_p->owner_addr_type >= SDP_MAX_ADDR_TYPES) ||
228 (sdp_p->owner_addr[0] == '\0')) {
230 if((sdp_p->owner_network_type == SDP_NT_ATM) &&
231 (sdp_p->owner_addr_type == SDP_AT_INVALID)) {
232 flex_string_sprintf(fs, "o=%s %s %s %s - -\r\n",
233 sdp_p->owner_name, sdp_p->owner_sessid,
234 sdp_p->owner_version,
235 sdp_get_network_name(sdp_p->owner_network_type));
238 if (sdp_p->conf_p->owner_reqd == TRUE) {
239 SDPLogError(logTag, "%s Invalid params for o= owner line, "
240 "build failed.", sdp_p->debug_str);
241 sdp_p->conf_p->num_invalid_param++;
242 return (SDP_INVALID_PARAMETER);
243 } else {
244 /* o= line is not required. */
245 return (SDP_SUCCESS);
249 flex_string_sprintf(fs, "o=%s %s %s %s %s %s\r\n",
250 sdp_p->owner_name, sdp_p->owner_sessid,
251 sdp_p->owner_version,
252 sdp_get_network_name(sdp_p->owner_network_type),
253 sdp_get_address_name(sdp_p->owner_addr_type),
254 sdp_p->owner_addr);
256 if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
257 SDP_PRINT("%s Built o= owner line", sdp_p->debug_str);
259 return (SDP_SUCCESS);
262 sdp_result_e sdp_parse_sessname (sdp_t *sdp_p, uint16_t level, const char *ptr)
264 int str_len;
265 char *endptr;
267 if (sdp_p->sessname[0] != '\0') {
268 sdp_p->conf_p->num_invalid_token_order++;
269 sdp_parse_error(sdp_p,
270 "%s Warning: More than one s= line specified.",
271 sdp_p->debug_str);
274 endptr = sdp_findchar(ptr, "\r\n");
275 if (ptr == endptr) {
276 sdp_parse_error(sdp_p,
277 "%s Warning: No session name specified.",
278 sdp_p->debug_str);
280 str_len = MIN(endptr - ptr, SDP_MAX_STRING_LEN);
281 sstrncpy(sdp_p->sessname, ptr, str_len+1);
283 if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
284 SDP_PRINT("%s Parse session name, %s",
285 sdp_p->debug_str, sdp_p->sessname);
287 return (SDP_SUCCESS);
290 sdp_result_e sdp_build_sessname (sdp_t *sdp_p, uint16_t level, flex_string *fs)
292 if (sdp_p->sessname[0] == '\0') {
293 if (sdp_p->conf_p->session_name_reqd == TRUE) {
294 SDPLogError(logTag, "%s No param defined for s= session name line, "
295 "build failed.", sdp_p->debug_str);
296 sdp_p->conf_p->num_invalid_param++;
297 return (SDP_INVALID_PARAMETER);
298 } else {
299 /* s= line is not required. */
300 return (SDP_SUCCESS);
304 flex_string_sprintf(fs, "s=%s\r\n", sdp_p->sessname);
306 if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
307 SDP_PRINT("%s Built s= session name line", sdp_p->debug_str);
309 return (SDP_SUCCESS);
312 /* We don't want to store the session info, but we do want to validate
313 * that at most one i= line exists at each level and if the line exists
314 * there should be a parameter.
316 sdp_result_e sdp_parse_sessinfo (sdp_t *sdp_p, uint16_t level, const char *ptr)
318 char *endptr;
319 sdp_mca_t *mca_p;
321 if (level == SDP_SESSION_LEVEL) {
322 if (sdp_p->sessinfo_found == TRUE) {
323 sdp_p->conf_p->num_invalid_token_order++;
324 sdp_parse_error(sdp_p,
325 "%s Warning: More than one i= line specified.",
326 sdp_p->debug_str);
328 sdp_p->sessinfo_found = TRUE;
329 } else {
330 mca_p = sdp_find_media_level(sdp_p, level);
331 if (mca_p == NULL) {
332 return (SDP_FAILURE);
334 if (mca_p->sessinfo_found == TRUE) {
335 sdp_p->conf_p->num_invalid_token_order++;
336 sdp_parse_error(sdp_p,
337 "%s Warning: More than one i= line specified"
338 " for media line %u.", sdp_p->debug_str, (unsigned)level);
340 mca_p->sessinfo_found = TRUE;
343 endptr = sdp_findchar(ptr, "\n");
344 if (ptr == endptr) {
345 sdp_parse_error(sdp_p,
346 "%s Warning: No session info specified.",
347 sdp_p->debug_str);
350 if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
351 SDP_PRINT("%s Parsed session info line.", sdp_p->debug_str);
353 return (SDP_SUCCESS);
356 sdp_result_e sdp_build_sessinfo (sdp_t *sdp_p, uint16_t level, flex_string *fs)
358 /* Build session info line not supported. */
359 return (SDP_SUCCESS);
362 sdp_result_e sdp_parse_uri (sdp_t *sdp_p, uint16_t level, const char *ptr)
364 char *endptr;
366 if (sdp_p->uri_found == TRUE) {
367 sdp_p->conf_p->num_invalid_token_order++;
368 sdp_parse_error(sdp_p,
369 "%s Warning: More than one u= line specified.",
370 sdp_p->debug_str);
372 sdp_p->uri_found = TRUE;
374 endptr = sdp_findchar(ptr, "\n");
375 if (ptr == endptr) {
376 sdp_parse_error(sdp_p,
377 "%s Warning: No URI info specified.", sdp_p->debug_str);
380 if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
381 SDP_PRINT("%s Parsed URI line.", sdp_p->debug_str);
383 return (SDP_SUCCESS);
386 sdp_result_e sdp_build_uri (sdp_t *sdp_p, uint16_t level, flex_string *fs)
388 /* Build URI line not supported. */
389 return (SDP_SUCCESS);
392 sdp_result_e sdp_parse_email (sdp_t *sdp_p, uint16_t level, const char *ptr)
394 char *endptr;
396 endptr = sdp_findchar(ptr, "\n");
397 if (ptr == endptr) {
398 sdp_parse_error(sdp_p,
399 "%s Warning: No email info specified.", sdp_p->debug_str);
402 if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
403 SDP_PRINT("%s Parse email line", sdp_p->debug_str);
405 return (SDP_SUCCESS);
408 sdp_result_e sdp_build_email (sdp_t *sdp_p, uint16_t level, flex_string *fs)
410 /* Build email line not supported. */
411 return (SDP_SUCCESS);
414 sdp_result_e sdp_parse_phonenum (sdp_t *sdp_p, uint16_t level, const char *ptr)
416 char *endptr;
418 endptr = sdp_findchar(ptr, "\n");
419 if (ptr == endptr) {
420 sdp_parse_error(sdp_p,
421 "%s Warning: No phone number info specified.",
422 sdp_p->debug_str);
425 if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
426 SDP_PRINT("%s Parse phone number line", sdp_p->debug_str);
428 return (SDP_SUCCESS);
431 sdp_result_e sdp_build_phonenum (sdp_t *sdp_p, uint16_t level, flex_string *fs)
433 /* Build phone number line not supported. */
434 return (SDP_SUCCESS);
437 sdp_result_e sdp_parse_connection (sdp_t *sdp_p, uint16_t level, const char *ptr)
439 int i;
440 const char *slash_ptr;
441 sdp_result_e result;
442 sdp_conn_t *conn_p;
443 sdp_mca_t *mca_p;
444 char tmp[SDP_MAX_STRING_LEN];
445 char mcast_str[MCAST_STRING_LEN];
446 int mcast_bits;
447 unsigned long strtoul_result;
448 char *strtoul_end;
450 if (level == SDP_SESSION_LEVEL) {
451 conn_p = &(sdp_p->default_conn);
452 } else {
453 mca_p = sdp_find_media_level(sdp_p, level);
454 if (mca_p == NULL) {
455 return (SDP_FAILURE);
457 conn_p = &(mca_p->conn);
460 /* See if the c= line is already defined at this level. We don't
461 * currently support multihoming and so we only support one c= at
462 * each level.
464 if (conn_p->nettype != SDP_NT_INVALID) {
465 sdp_p->conf_p->num_invalid_token_order++;
466 sdp_parse_error(sdp_p,
467 "%s c= line specified twice at same level, "
468 "parse failed.", sdp_p->debug_str);
469 return (SDP_INVALID_TOKEN_ORDERING);
472 /* Find the connection network type. */
473 ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
474 if (result != SDP_SUCCESS) {
475 sdp_parse_error(sdp_p,
476 "%s No connection network type specified for c=.",
477 sdp_p->debug_str);
478 sdp_p->conf_p->num_invalid_param++;
479 return (SDP_INVALID_PARAMETER);
481 conn_p->nettype = SDP_NT_UNSUPPORTED;
482 for (i=0; i < SDP_MAX_NETWORK_TYPES; i++) {
483 if (cpr_strncasecmp(tmp, sdp_nettype[i].name,
484 sdp_nettype[i].strlen) == 0) {
485 if (sdp_p->conf_p->nettype_supported[i] == TRUE) {
486 conn_p->nettype = (sdp_nettype_e)i;
490 if (conn_p->nettype == SDP_NT_UNSUPPORTED) {
491 sdp_parse_error(sdp_p,
492 "%s Warning: Connection network type unsupported "
493 "(%s) for c=.", sdp_p->debug_str, tmp);
496 /* Find the connection address type. */
497 ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
498 if (result != SDP_SUCCESS) {
499 if (conn_p->nettype == SDP_NT_ATM) {
500 /* If the nettype is ATM, addr type and addr are not reqd */
501 if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
502 SDP_PRINT("%s Parse connection: network %s", sdp_p->debug_str,
503 sdp_get_network_name(conn_p->nettype));
505 return (SDP_SUCCESS);
506 } else {
507 sdp_parse_error(sdp_p,
508 "%s No connection address type specified for "
509 "c=.", sdp_p->debug_str);
510 sdp_p->conf_p->num_invalid_param++;
511 return (SDP_INVALID_PARAMETER);
514 conn_p->addrtype = SDP_AT_UNSUPPORTED;
515 for (i=0; i < SDP_MAX_ADDR_TYPES; i++) {
516 if (cpr_strncasecmp(tmp, sdp_addrtype[i].name,
517 sdp_addrtype[i].strlen) == 0) {
518 if (sdp_p->conf_p->addrtype_supported[i] == TRUE) {
519 conn_p->addrtype = (sdp_addrtype_e)i;
523 if (conn_p->addrtype == SDP_AT_UNSUPPORTED) {
524 sdp_parse_error(sdp_p,
525 "%s Warning: Connection address type unsupported "
526 "(%s) for c=.", sdp_p->debug_str, tmp);
529 /* Find the connection address. */
530 ptr = sdp_getnextstrtok(ptr, conn_p->conn_addr, sizeof(conn_p->conn_addr), " \t", &result);
531 if (result != SDP_SUCCESS) {
532 sdp_parse_error(sdp_p,
533 "%s No connection address specified for c=.",
534 sdp_p->debug_str);
535 sdp_p->conf_p->num_invalid_param++;
536 return (SDP_INVALID_PARAMETER);
538 /* We currently only support addrs containing '/'s for EPN addrs.
539 * For other addrs this would indicate multicast addrs. */
540 /* Multicast host group addresses are defined to be the IP addresses
541 * whose high-order four bits are 1110, giving an address range from
542 * 224.0.0.0 through 239.255.255.255
544 /* multicast addr check */
545 sstrncpy (mcast_str, conn_p->conn_addr, MCAST_STRING_LEN);
547 if (conn_p->addrtype == SDP_AT_IP4) {
548 errno = 0;
549 strtoul_result = strtoul(mcast_str, &strtoul_end, 10);
551 if (errno || mcast_str == strtoul_end || strtoul_result > 255) {
552 sdp_parse_error(sdp_p,
553 "%s Error parsing address %s for mcast.",
554 sdp_p->debug_str, mcast_str);
555 sdp_p->conf_p->num_invalid_param++;
556 return SDP_INVALID_PARAMETER;
560 mcast_bits = (int) strtoul_result;
561 if ((mcast_bits >= SDP_MIN_MCAST_ADDR_HI_BIT_VAL ) &&
562 (mcast_bits <= SDP_MAX_MCAST_ADDR_HI_BIT_VAL)) {
563 SDP_PRINT("%s Parsed to be a multicast address with mcast bits %d",
564 sdp_p->debug_str, mcast_bits);
565 conn_p->is_multicast = TRUE;
569 if (conn_p->addrtype != SDP_AT_EPN) {
570 slash_ptr = sdp_findchar(conn_p->conn_addr, "/");
571 if (slash_ptr[0] != '\0') {
572 /* this used to rely on the above busted multicast check */
573 SDP_PRINT("%s An address with slash %s",
574 sdp_p->debug_str, conn_p->conn_addr);
575 conn_p->conn_addr[slash_ptr - conn_p->conn_addr] = '\0';
576 slash_ptr++;
577 slash_ptr = sdp_getnextstrtok(slash_ptr, tmp, sizeof(tmp),
578 "/", &result);
579 if (result != SDP_SUCCESS) {
580 sdp_parse_error(sdp_p,
581 "%s No ttl value specified for this multicast addr with a slash",
582 sdp_p->debug_str);
583 sdp_p->conf_p->num_invalid_param++;
584 return (SDP_INVALID_PARAMETER);
587 errno = 0;
588 strtoul_result = strtoul(tmp, &strtoul_end, 10);
590 if (errno || tmp == strtoul_end || conn_p->ttl > SDP_MAX_TTL_VALUE) {
591 sdp_parse_error(sdp_p,
592 "%s Invalid TTL: Value must be in the range 0-255 ",
593 sdp_p->debug_str);
594 sdp_p->conf_p->num_invalid_param++;
595 return (SDP_INVALID_PARAMETER);
598 conn_p->ttl = (int) strtoul_result;
600 /* search for num of addresses */
601 /*sa_ignore NO_NULL_CHK
602 {ptr is valid since the pointer was checked earlier and the
603 function would have exited if NULL.}*/
604 slash_ptr = sdp_findchar(slash_ptr, "/");
605 if (slash_ptr != NULL &&
606 slash_ptr[0] != '\0') {
607 SDP_PRINT("%s Found a num addr field for multicast addr %s ",
608 sdp_p->debug_str,slash_ptr);
609 slash_ptr++;
611 errno = 0;
612 strtoul_result = strtoul(slash_ptr, &strtoul_end, 10);
614 if (errno || slash_ptr == strtoul_end || strtoul_result == 0) {
615 sdp_parse_error(sdp_p,
616 "%s Invalid Num of addresses: Value must be > 0 ",
617 sdp_p->debug_str);
618 sdp_p->conf_p->num_invalid_param++;
619 return SDP_INVALID_PARAMETER;
622 conn_p->num_of_addresses = (int) strtoul_result;
627 /* See if the address is the choose param and if it's allowed. */
628 if ((sdp_p->conf_p->allow_choose[SDP_CHOOSE_CONN_ADDR] == FALSE) &&
629 (strcmp(conn_p->conn_addr, "$") == 0)) {
630 sdp_parse_error(sdp_p,
631 "%s Warning: Choose parameter for connection "
632 "address specified but not allowed.", sdp_p->debug_str);
635 if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
636 SDP_PRINT("%s Parse connection: network %s, address type %s, "
637 "address %s ttl= %u num of addresses = %u",
638 sdp_p->debug_str,
639 sdp_get_network_name(conn_p->nettype),
640 sdp_get_address_name(conn_p->addrtype),
641 conn_p->conn_addr, (unsigned)conn_p->ttl, (unsigned)conn_p->num_of_addresses);
643 return (SDP_SUCCESS);
646 sdp_result_e sdp_build_connection (sdp_t *sdp_p, uint16_t level, flex_string *fs)
648 sdp_mca_t *mca_p;
649 sdp_conn_t *conn_p;
651 if (level == SDP_SESSION_LEVEL) {
652 conn_p = &(sdp_p->default_conn);
653 } else {
654 mca_p = sdp_find_media_level(sdp_p, level);
655 if (mca_p == NULL) {
656 return (SDP_FAILURE);
658 conn_p = &(mca_p->conn);
661 if((conn_p->nettype == SDP_NT_ATM ) &&
662 (conn_p->addrtype == SDP_AT_INVALID)) {
663 /*allow c= line to be built without address type and address fields
664 * This is a special case for ATM PVC*/
665 flex_string_sprintf(fs, "c=%s\r\n",
666 sdp_get_network_name(conn_p->nettype));
667 return SDP_SUCCESS;
669 if ((conn_p->nettype >= SDP_MAX_NETWORK_TYPES) ||
670 (conn_p->addrtype >= SDP_MAX_ADDR_TYPES) ||
671 (conn_p->conn_addr[0] == '\0')) {
672 /* Connection info isn't set - don't need to build the token. */
673 return (SDP_SUCCESS);
676 if (conn_p->is_multicast) {
677 if (conn_p->num_of_addresses > 1) {
678 flex_string_sprintf(fs, "c=%s %s %s/%u/%u\r\n",
679 sdp_get_network_name(conn_p->nettype),
680 sdp_get_address_name(conn_p->addrtype),
681 conn_p->conn_addr,
682 (unsigned)conn_p->ttl,
683 (unsigned)conn_p->num_of_addresses);
684 } else {
685 flex_string_sprintf(fs, "c=%s %s %s/%u\r\n",
686 sdp_get_network_name(conn_p->nettype),
687 sdp_get_address_name(conn_p->addrtype),
688 conn_p->conn_addr,
689 (unsigned)conn_p->ttl);
691 } else {
693 flex_string_sprintf(fs, "c=%s %s %s\r\n",
694 sdp_get_network_name(conn_p->nettype),
695 sdp_get_address_name(conn_p->addrtype),
696 conn_p->conn_addr);
699 if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
700 SDP_PRINT("%s Built c= connection line", sdp_p->debug_str);
702 return (SDP_SUCCESS);
706 * sdp_parse_bandwidth
708 * This function parses a bandwidth field. The parsing is done in accordance
709 * to the following ABNF:
711 * bandwidth-fields = *("b=" bwtype ":" bandwidth CRLF)
712 * bwtype = 1*(alpha-numeric)
713 * bandwidth = 1*(DIGIT)
715 * It currently supports three types of valid bwtypes - AS, CT and TIAS
717 sdp_result_e sdp_parse_bandwidth (sdp_t *sdp_p, uint16_t level, const char *ptr)
719 int i;
720 sdp_mca_t *mca_p;
721 sdp_bw_t *bw_p;
722 sdp_bw_data_t *bw_data_p;
723 sdp_bw_data_t *new_bw_data_p;
724 sdp_result_e result;
725 char tmp[SDP_MAX_STRING_LEN];
726 sdp_bw_modifier_e bw_modifier = SDP_BW_MODIFIER_UNSUPPORTED;
727 int bw_val = 0;
729 if (level == SDP_SESSION_LEVEL) {
730 bw_p = &(sdp_p->bw);
731 } else {
732 mca_p = sdp_find_media_level(sdp_p, level);
733 if (mca_p == NULL) {
734 return (SDP_FAILURE);
736 bw_p = &(mca_p->bw);
739 if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
740 SDP_PRINT("%s Parse bandwidth line", sdp_p->debug_str);
743 /* Find the bw type (AS, CT or TIAS) */
744 ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), ":", &result);
745 if (result != SDP_SUCCESS) {
746 sdp_parse_error(sdp_p,
747 "%s No bandwidth type specified for b= ",
748 sdp_p->debug_str);
749 sdp_p->conf_p->num_invalid_param++;
750 return (SDP_INVALID_PARAMETER);
752 for (i=0; i < SDP_MAX_BW_MODIFIER_VAL; i++) {
753 if (cpr_strncasecmp(tmp, sdp_bw_modifier_val[i].name,
754 sdp_bw_modifier_val[i].strlen) == 0) {
755 bw_modifier = (sdp_bw_modifier_e)i;
756 break;
760 if (bw_modifier == SDP_BW_MODIFIER_UNSUPPORTED) {
761 /* We don't understand this parameter, so according to RFC4566 sec 5.8
762 * ignore it. */
763 return (SDP_SUCCESS);
766 /* Find the BW type value */
767 /*sa_ignore NO_NULL_CHK
768 {ptr is valid since the pointer was checked earlier and the
769 function would have exited if NULL.}*/
770 if (*ptr == ':') {
771 ptr++;
772 bw_val = sdp_getnextnumtok(ptr, &ptr, " \t", &result);
773 if ((result != SDP_SUCCESS)) {
774 sdp_parse_error(sdp_p,
775 "%s Error: No BW Value specified ",
776 sdp_p->debug_str);
777 sdp_p->conf_p->num_invalid_param++;
778 return (SDP_INVALID_PARAMETER);
783 * Allocate a new sdp_bw_data_t instance and set it's values from the
784 * input parameters.
786 new_bw_data_p = (sdp_bw_data_t*)SDP_MALLOC(sizeof(sdp_bw_data_t));
787 if (new_bw_data_p == NULL) {
788 sdp_p->conf_p->num_invalid_param++;
789 return (SDP_NO_RESOURCE);
791 new_bw_data_p->next_p = NULL;
792 new_bw_data_p->bw_modifier = bw_modifier;
793 new_bw_data_p->bw_val = bw_val;
796 * Enqueue the sdp_bw_data_t instance at the end of the list of
797 * sdp_bw_data_t instances.
799 if (bw_p->bw_data_list == NULL) {
800 bw_p->bw_data_list = new_bw_data_p;
801 } else {
802 for (bw_data_p = bw_p->bw_data_list;
803 bw_data_p->next_p != NULL;
804 bw_data_p = bw_data_p->next_p) {
805 ; // Empty For
807 bw_data_p->next_p = new_bw_data_p;
809 bw_p->bw_data_count++;
811 if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
812 SDP_PRINT("%s Parsed bw type %s, value %d", sdp_p->debug_str,
813 sdp_get_bw_modifier_name(new_bw_data_p->bw_modifier),
814 new_bw_data_p->bw_val);
817 return (SDP_SUCCESS);
821 * sdp_build_bandwidth
823 * Builds *all* the bandwith lines for the specified level.
825 sdp_result_e sdp_build_bandwidth (sdp_t *sdp_p, uint16_t level, flex_string *fs)
827 sdp_bw_t *bw_p;
828 sdp_bw_data_t *bw_data_p;
829 sdp_mca_t *mca_p;
831 if (level == SDP_SESSION_LEVEL) {
832 bw_p = &(sdp_p->bw);
833 } else {
834 mca_p = sdp_find_media_level(sdp_p, level);
835 if (mca_p == NULL) {
836 return (SDP_FAILURE);
838 bw_p = &(mca_p->bw);
841 bw_data_p = bw_p->bw_data_list;
842 while (bw_data_p) {
843 flex_string_sprintf(fs, "b=%s:%d\r\n",
844 sdp_get_bw_modifier_name(bw_data_p->bw_modifier),
845 bw_data_p->bw_val);
847 if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
848 SDP_PRINT("%s Built b=%s:%d bandwidth line", sdp_p->debug_str,
849 sdp_get_bw_modifier_name(bw_data_p->bw_modifier),
850 bw_data_p->bw_val);
853 bw_data_p = bw_data_p->next_p;
856 return (SDP_SUCCESS);
859 sdp_result_e sdp_parse_timespec (sdp_t *sdp_p, uint16_t level, const char *ptr)
861 char *tmpptr;
862 sdp_result_e result;
863 sdp_timespec_t *timespec_p;
864 sdp_timespec_t *next_timespec_p;
866 timespec_p = (sdp_timespec_t *)SDP_MALLOC(sizeof(sdp_timespec_t));
867 if (timespec_p == NULL) {
868 sdp_p->conf_p->num_no_resource++;
869 return (SDP_NO_RESOURCE);
872 /* Validate start and stop times. */
873 ptr = sdp_getnextstrtok(ptr, timespec_p->start_time, sizeof(timespec_p->start_time), " \t", &result);
874 if (result == SDP_SUCCESS) {
875 /* Make sure the start_time is numeric, even though we store it as
876 * a string.
878 (void)sdp_getnextnumtok(timespec_p->start_time,
879 (const char **)&tmpptr, " \t", &result);
881 if (result != SDP_SUCCESS) {
882 sdp_parse_error(sdp_p,
883 "%s Invalid timespec start time specified.",
884 sdp_p->debug_str);
885 sdp_p->conf_p->num_invalid_param++;
886 SDP_FREE(timespec_p);
887 return (SDP_INVALID_PARAMETER);
890 ptr = sdp_getnextstrtok(ptr, timespec_p->stop_time, sizeof(timespec_p->stop_time), " \t", &result);
891 if (result == SDP_SUCCESS) {
892 /* Make sure the start_time is numeric, even though we store it as
893 * a string.
895 (void)sdp_getnextnumtok(timespec_p->stop_time,
896 (const char **)&tmpptr, " \t", &result);
898 if (result != SDP_SUCCESS) {
899 sdp_parse_error(sdp_p,
900 "%s Invalid timespec stop time specified.",
901 sdp_p->debug_str);
902 sdp_p->conf_p->num_invalid_param++;
903 SDP_FREE(timespec_p);
904 return (SDP_INVALID_PARAMETER);
907 /* Link the new timespec in to the end of the list. */
908 if (sdp_p->timespec_p == NULL) {
909 sdp_p->timespec_p = timespec_p;
910 } else {
911 next_timespec_p = sdp_p->timespec_p;
912 while (next_timespec_p->next_p != NULL) {
913 next_timespec_p = next_timespec_p->next_p;
915 next_timespec_p->next_p = timespec_p;
918 if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
919 SDP_PRINT("%s Parsed timespec line", sdp_p->debug_str);
921 return (SDP_SUCCESS);
924 sdp_result_e sdp_build_timespec (sdp_t *sdp_p, uint16_t level, flex_string *fs)
926 if ((sdp_p->timespec_p == NULL) ||
927 (sdp_p->timespec_p->start_time[0] == '\0') ||
928 (sdp_p->timespec_p->stop_time[0] == '\0')) {
929 if (sdp_p->conf_p->timespec_reqd == TRUE) {
930 SDPLogError(logTag, "%s Invalid params for t= time spec line, "
931 "build failed.", sdp_p->debug_str);
932 sdp_p->conf_p->num_invalid_param++;
933 return (SDP_INVALID_PARAMETER);
934 } else {
935 /* t= line not required. */
936 return (SDP_SUCCESS);
940 /* Note: We only support one t= line currently. */
941 flex_string_sprintf(fs, "t=%s %s\r\n", sdp_p->timespec_p->start_time,
942 sdp_p->timespec_p->stop_time);
944 if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
945 SDP_PRINT("%s Built t= timespec line", sdp_p->debug_str);
947 return (SDP_SUCCESS);
950 sdp_result_e sdp_parse_repeat_time (sdp_t *sdp_p, uint16_t level, const char *ptr)
952 char *endptr;
954 endptr = sdp_findchar(ptr, "\n");
955 if (ptr == endptr) {
956 sdp_parse_error(sdp_p,
957 "%s Warning: No repeat time parameters "
958 "specified.", sdp_p->debug_str);
961 if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
962 SDP_PRINT("%s Parsed repeat time line", sdp_p->debug_str);
964 return (SDP_SUCCESS);
967 sdp_result_e sdp_build_repeat_time (sdp_t *sdp_p, uint16_t level, flex_string *fs)
969 /* Build repeat time line not supported. */
970 return (SDP_SUCCESS);
973 sdp_result_e sdp_parse_timezone_adj (sdp_t *sdp_p, uint16_t level, const char *ptr)
975 char *endptr;
977 endptr = sdp_findchar(ptr, "\n");
978 if (ptr == endptr) {
979 sdp_parse_error(sdp_p,
980 "%s Warning: No timezone parameters specified.",
981 sdp_p->debug_str);
984 if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
985 SDP_PRINT("%s Parse timezone adustment line", sdp_p->debug_str);
987 return (SDP_SUCCESS);
990 sdp_result_e sdp_build_timezone_adj (sdp_t *sdp_p, uint16_t level, flex_string *fs)
992 /* Build timezone adjustment line not supported. */
993 return (SDP_SUCCESS);
996 sdp_result_e sdp_parse_encryption (sdp_t *sdp_p, uint16_t level, const char *ptr)
998 int i;
999 sdp_result_e result;
1000 sdp_encryptspec_t *encrypt_p;
1001 sdp_mca_t *mca_p;
1002 char tmp[SDP_MAX_STRING_LEN];
1004 if (level == SDP_SESSION_LEVEL) {
1005 encrypt_p = &(sdp_p->encrypt);
1006 } else {
1007 mca_p = sdp_find_media_level(sdp_p, level);
1008 if (mca_p == NULL) {
1009 return (SDP_FAILURE);
1011 encrypt_p = &(mca_p->encrypt);
1013 encrypt_p->encrypt_key[0] = '\0';
1015 /* Find the encryption type. */
1016 ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), ":", &result);
1017 if (result != SDP_SUCCESS) {
1018 sdp_parse_error(sdp_p,
1019 "%s No encryption type specified for k=.",
1020 sdp_p->debug_str);
1021 sdp_p->conf_p->num_invalid_param++;
1022 return (SDP_INVALID_PARAMETER);
1024 encrypt_p->encrypt_type = SDP_ENCRYPT_UNSUPPORTED;
1025 for (i=0; i < SDP_MAX_ENCRYPT_TYPES; i++) {
1026 if (cpr_strncasecmp(tmp, sdp_encrypt[i].name,
1027 sdp_encrypt[i].strlen) == 0) {
1028 encrypt_p->encrypt_type = (sdp_encrypt_type_e)i;
1029 break;
1032 if (encrypt_p->encrypt_type == SDP_ENCRYPT_UNSUPPORTED) {
1033 sdp_parse_error(sdp_p,
1034 "%s Warning: Encryption type unsupported (%s).",
1035 sdp_p->debug_str, tmp);
1038 /* Find the encryption key. */
1039 encrypt_p->encrypt_key[0] = '\0';
1040 /*sa_ignore NO_NULL_CHK
1041 {ptr is valid since the pointer was checked earlier and the
1042 function would have exited if NULL.}*/
1043 if (*ptr == ':')
1044 ptr++;
1045 if (encrypt_p->encrypt_type != SDP_ENCRYPT_PROMPT) {
1046 ptr = sdp_getnextstrtok(ptr, encrypt_p->encrypt_key, sizeof(encrypt_p->encrypt_key), " \t", &result);
1047 if ((result != SDP_SUCCESS) &&
1048 ((encrypt_p->encrypt_type == SDP_ENCRYPT_CLEAR) ||
1049 (encrypt_p->encrypt_type == SDP_ENCRYPT_BASE64) ||
1050 (encrypt_p->encrypt_type == SDP_ENCRYPT_URI))) {
1051 sdp_parse_error(sdp_p,
1052 "%s Warning: No encryption key specified "
1053 "as required.", sdp_p->debug_str);
1054 sdp_p->conf_p->num_invalid_param++;
1055 return (SDP_INVALID_PARAMETER);
1059 if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
1060 SDP_PRINT("%s Parse encryption type %s, key %s", sdp_p->debug_str,
1061 sdp_get_encrypt_name(encrypt_p->encrypt_type),
1062 encrypt_p->encrypt_key);
1064 return (SDP_SUCCESS);
1067 /* If the encryption info is valid, we build it. Else skip it. */
1068 sdp_result_e sdp_build_encryption (sdp_t *sdp_p, uint16_t level, flex_string *fs)
1070 sdp_encryptspec_t *encrypt_p;
1071 sdp_mca_t *mca_p;
1073 if (level == SDP_SESSION_LEVEL) {
1074 encrypt_p = &(sdp_p->encrypt);
1075 } else {
1076 mca_p = sdp_find_media_level(sdp_p, level);
1077 if (mca_p == NULL) {
1078 return (SDP_FAILURE);
1080 encrypt_p = &(mca_p->encrypt);
1083 if ((encrypt_p->encrypt_type >= SDP_MAX_ENCRYPT_TYPES) ||
1084 ((encrypt_p->encrypt_type != SDP_ENCRYPT_PROMPT) &&
1085 (encrypt_p->encrypt_key[0] == '\0'))) {
1086 /* Encryption info isn't set - don't need to build the token. */
1087 return (SDP_SUCCESS);
1090 flex_string_sprintf(fs, "k=%s",
1091 sdp_get_encrypt_name(encrypt_p->encrypt_type));
1093 if (encrypt_p->encrypt_type == SDP_ENCRYPT_PROMPT) {
1094 /* There is no key to print. */
1095 flex_string_sprintf(fs, "\r\n");
1096 } else {
1097 flex_string_sprintf(fs, ":%s\r\n", encrypt_p->encrypt_key);
1100 if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
1101 SDP_PRINT("%s Built k= encryption line", sdp_p->debug_str);
1103 return (SDP_SUCCESS);
1106 sdp_result_e sdp_parse_media (sdp_t *sdp_p, uint16_t level, const char *ptr)
1108 uint16_t i;
1109 uint16_t num_port_params=0;
1110 int32_t num[SDP_MAX_PORT_PARAMS];
1111 tinybool valid_param = FALSE;
1112 sdp_result_e result;
1113 sdp_mca_t *mca_p;
1114 sdp_mca_t *next_mca_p;
1115 char tmp[SDP_MAX_STRING_LEN];
1116 char port[SDP_MAX_STRING_LEN];
1117 const char *port_ptr;
1118 int32_t sctp_port;
1120 /* Allocate resource for new media stream. */
1121 mca_p = sdp_alloc_mca(sdp_p->parse_line);
1122 if (mca_p == NULL) {
1123 sdp_p->conf_p->num_no_resource++;
1124 return (SDP_NO_RESOURCE);
1127 /* Find the media type. */
1128 ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
1129 if (result != SDP_SUCCESS) {
1130 sdp_parse_error(sdp_p,
1131 "%s No media type specified, parse failed.",
1132 sdp_p->debug_str);
1133 SDP_FREE(mca_p);
1134 sdp_p->conf_p->num_invalid_param++;
1135 return (SDP_INVALID_PARAMETER);
1137 mca_p->media = SDP_MEDIA_UNSUPPORTED;
1138 for (i=0; i < SDP_MAX_MEDIA_TYPES; i++) {
1139 if (cpr_strncasecmp(tmp, sdp_media[i].name,
1140 sdp_media[i].strlen) == 0) {
1141 mca_p->media = (sdp_media_e)i;
1144 if (mca_p->media == SDP_MEDIA_UNSUPPORTED) {
1145 sdp_parse_error(sdp_p,
1146 "%s Warning: Media type unsupported (%s).",
1147 sdp_p->debug_str, tmp);
1150 /* Find the port token parameters, but don't process it until
1151 * we determine the transport protocol as that determines what
1152 * port number formats are valid.
1154 ptr = sdp_getnextstrtok(ptr, port, sizeof(port), " \t", &result);
1155 if (result != SDP_SUCCESS) {
1156 sdp_parse_error(sdp_p,
1157 "%s No port specified in m= media line, "
1158 "parse failed.", sdp_p->debug_str);
1159 SDP_FREE(mca_p);
1160 sdp_p->conf_p->num_invalid_param++;
1161 return (SDP_INVALID_PARAMETER);
1163 port_ptr = port;
1164 for (i=0; i < SDP_MAX_PORT_PARAMS; i++) {
1165 num[i] = sdp_getnextnumtok(port_ptr, (const char **)&port_ptr,
1166 "/ \t", &result);
1167 if (result != SDP_SUCCESS) {
1168 break;
1170 num_port_params++;
1173 /* Find the transport protocol type. */
1174 ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
1175 if (result != SDP_SUCCESS) {
1176 sdp_parse_error(sdp_p,
1177 "%s No transport protocol type specified, "
1178 "parse failed.", sdp_p->debug_str);
1179 SDP_FREE(mca_p);
1180 sdp_p->conf_p->num_invalid_param++;
1181 return (SDP_INVALID_PARAMETER);
1183 mca_p->transport = SDP_TRANSPORT_UNSUPPORTED;
1184 for (i=0; i < SDP_MAX_TRANSPORT_TYPES; i++) {
1185 if (cpr_strncasecmp(tmp, sdp_transport[i].name,
1186 sdp_transport[i].strlen) == 0) {
1187 mca_p->transport = (sdp_transport_e)i;
1188 break;
1192 if (mca_p->transport == SDP_TRANSPORT_UNSUPPORTED) {
1193 /* If we don't recognize or don't support the transport type,
1194 * just store the first num as the port.
1196 mca_p->port = num[0];
1197 sdp_parse_error(sdp_p,
1198 "%s Warning: Transport protocol type unsupported "
1199 "(%s).", sdp_p->debug_str, tmp);
1202 /* Check for each of the possible port formats according to the
1203 * type of transport protocol specified.
1205 valid_param = FALSE;
1206 switch (num_port_params) {
1207 case 1:
1208 if ((mca_p->transport == SDP_TRANSPORT_RTPAVP) ||
1209 (mca_p->transport == SDP_TRANSPORT_RTPSAVP) ||
1210 (mca_p->transport == SDP_TRANSPORT_RTPSAVPF) ||
1211 (mca_p->transport == SDP_TRANSPORT_UDPTLSRTPSAVP) ||
1212 (mca_p->transport == SDP_TRANSPORT_UDPTLSRTPSAVPF) ||
1213 (mca_p->transport == SDP_TRANSPORT_TCPDTLSRTPSAVP) ||
1214 (mca_p->transport == SDP_TRANSPORT_TCPDTLSRTPSAVPF) ||
1215 (mca_p->transport == SDP_TRANSPORT_UDP) ||
1216 (mca_p->transport == SDP_TRANSPORT_TCP) ||
1217 (mca_p->transport == SDP_TRANSPORT_UDPTL) ||
1218 (mca_p->transport == SDP_TRANSPORT_UDPSPRT) ||
1219 (mca_p->transport == SDP_TRANSPORT_LOCAL) ||
1220 (mca_p->transport == SDP_TRANSPORT_DTLSSCTP) ||
1221 (mca_p->transport == SDP_TRANSPORT_UDPDTLSSCTP) ||
1222 (mca_p->transport == SDP_TRANSPORT_TCPDTLSSCTP)) {
1223 /* Port format is simply <port>. Make sure that either
1224 * the choose param is allowed or that the choose value
1225 * wasn't specified.
1227 if ((sdp_p->conf_p->allow_choose[SDP_CHOOSE_PORTNUM]) ||
1228 (num[0] != SDP_CHOOSE_PARAM)) {
1229 mca_p->port = num[0];
1230 mca_p->port_format = SDP_PORT_NUM_ONLY;
1231 valid_param = TRUE;
1233 } else if (mca_p->transport == SDP_TRANSPORT_AAL1AVP) {
1234 /* Port format is simply <vcci>, choose param is not allowed.
1236 if (num[0] != SDP_CHOOSE_PARAM) {
1237 mca_p->vcci = num[0];
1238 mca_p->port_format = SDP_PORT_VCCI;
1239 valid_param = TRUE;
1241 } else if ((mca_p->transport == SDP_TRANSPORT_AAL2_ITU) ||
1242 (mca_p->transport == SDP_TRANSPORT_AAL2_ATMF) ||
1243 (mca_p->transport == SDP_TRANSPORT_AAL2_CUSTOM)) {
1244 /* Port format is simply <port>, and choose param is allowed,
1245 * according to AAL2 definitions.
1247 mca_p->port = num[0];
1248 mca_p->port_format = SDP_PORT_NUM_ONLY;
1249 valid_param = TRUE;
1251 break;
1252 case 2:
1253 if ((mca_p->transport == SDP_TRANSPORT_RTPAVP) ||
1254 (mca_p->transport == SDP_TRANSPORT_RTPSAVP) ||
1255 (mca_p->transport == SDP_TRANSPORT_RTPSAVPF) ||
1256 (mca_p->transport == SDP_TRANSPORT_UDPTLSRTPSAVP) ||
1257 (mca_p->transport == SDP_TRANSPORT_UDPTLSRTPSAVPF) ||
1258 (mca_p->transport == SDP_TRANSPORT_TCPDTLSRTPSAVP) ||
1259 (mca_p->transport == SDP_TRANSPORT_TCPDTLSRTPSAVPF) ||
1260 (mca_p->transport == SDP_TRANSPORT_UDP) ||
1261 (mca_p->transport == SDP_TRANSPORT_LOCAL)) {
1262 /* Port format is <port>/<num of ports>. Make sure choose
1263 * params were not specified.
1265 if ((num[0] != SDP_CHOOSE_PARAM) &&
1266 (num[1] != SDP_CHOOSE_PARAM)) {
1267 mca_p->port = num[0];
1268 mca_p->num_ports = num[1];
1269 mca_p->port_format = SDP_PORT_NUM_COUNT;
1270 valid_param = TRUE;
1272 } else if (mca_p->transport == SDP_TRANSPORT_UDPTL) {
1273 /* Port format is <port>/<num of ports>. Make sure choose
1274 * params were not specified. For UDPTL, only "1" may
1275 * be specified for number of ports.
1277 if ((num[0] != SDP_CHOOSE_PARAM) &&
1278 (num[1] == 1)) {
1279 mca_p->port = num[0];
1280 mca_p->num_ports = 1;
1281 mca_p->port_format = SDP_PORT_NUM_COUNT;
1282 valid_param = TRUE;
1284 } else if (mca_p->transport == SDP_TRANSPORT_CES10) {
1285 /* Port format is <vpi>/<vci>. Make sure choose
1286 * params were not specified.
1288 if ((num[0] != SDP_CHOOSE_PARAM) &&
1289 (num[1] != SDP_CHOOSE_PARAM)) {
1290 mca_p->vpi = num[0];
1291 mca_p->vci = num[1];
1292 mca_p->port_format = SDP_PORT_VPI_VCI;
1293 valid_param = TRUE;
1295 } else if ((mca_p->transport == SDP_TRANSPORT_AAL2_ITU) ||
1296 (mca_p->transport == SDP_TRANSPORT_AAL2_ATMF) ||
1297 (mca_p->transport == SDP_TRANSPORT_AAL2_CUSTOM)) {
1298 /* Port format is either <vcci>/<cid> or $/$. If one
1299 * param is '$' the other must be also. The choose params
1300 * are allowed by default and don't need to be allowed
1301 * through the appl config.
1303 if (((num[0] != SDP_CHOOSE_PARAM) &&
1304 (num[1] != SDP_CHOOSE_PARAM)) ||
1305 ((num[0] == SDP_CHOOSE_PARAM) &&
1306 (num[1] == SDP_CHOOSE_PARAM))) {
1307 mca_p->vcci = num[0];
1308 mca_p->cid = num[1];
1309 mca_p->port_format = SDP_PORT_VCCI_CID;
1310 valid_param = TRUE;
1313 break;
1314 case 3:
1315 if (mca_p->transport == SDP_TRANSPORT_AAL1AVP) {
1316 /* Port format is <port>/<vpi>/<vci>. Make sure choose
1317 * params were not specified.
1319 if ((num[0] != SDP_CHOOSE_PARAM) &&
1320 (num[1] != SDP_CHOOSE_PARAM) &&
1321 (num[2] != SDP_CHOOSE_PARAM)) {
1322 mca_p->port = num[0];
1323 mca_p->vpi = num[1];
1324 mca_p->vci = num[2];
1325 mca_p->port_format = SDP_PORT_NUM_VPI_VCI;
1326 valid_param = TRUE;
1329 break;
1330 case 4:
1331 if ((mca_p->transport == SDP_TRANSPORT_AAL2_ITU) ||
1332 (mca_p->transport == SDP_TRANSPORT_AAL2_ATMF) ||
1333 (mca_p->transport == SDP_TRANSPORT_AAL2_CUSTOM)) {
1334 /* Port format is <port>/<vpi>/<vci>/<cid>. Make sure choose
1335 * params were not specified.
1337 if ((num[0] != SDP_CHOOSE_PARAM) &&
1338 (num[1] != SDP_CHOOSE_PARAM) &&
1339 (num[2] != SDP_CHOOSE_PARAM) &&
1340 (num[3] != SDP_CHOOSE_PARAM)) {
1341 mca_p->port = num[0];
1342 mca_p->vpi = num[1];
1343 mca_p->vci = num[2];
1344 mca_p->cid = num[3];
1345 mca_p->port_format = SDP_PORT_NUM_VPI_VCI_CID;
1346 valid_param = TRUE;
1349 break;
1351 if (valid_param == FALSE) {
1352 sdp_parse_error(sdp_p,
1353 "%s Invalid port format (%s) specified for transport "
1354 "protocol (%s), parse failed.", sdp_p->debug_str,
1355 port, sdp_get_transport_name(mca_p->transport));
1356 sdp_p->conf_p->num_invalid_param++;
1357 SDP_FREE(mca_p);
1358 return (SDP_INVALID_PARAMETER);
1361 if ((mca_p->transport == SDP_TRANSPORT_DTLSSCTP) ||
1362 (mca_p->transport == SDP_TRANSPORT_UDPDTLSSCTP) ||
1363 (mca_p->transport == SDP_TRANSPORT_TCPDTLSSCTP)) {
1364 ptr = sdp_getnextstrtok(ptr, port, sizeof(port), " \t", &result);
1365 if (result != SDP_SUCCESS) {
1366 sdp_parse_error(sdp_p,
1367 "%s No sctp port specified in m= media line, "
1368 "parse failed.", sdp_p->debug_str);
1369 SDP_FREE(mca_p);
1370 sdp_p->conf_p->num_invalid_param++;
1371 return (SDP_INVALID_PARAMETER);
1373 port_ptr = port;
1375 if ((mca_p->transport == SDP_TRANSPORT_UDPDTLSSCTP) ||
1376 (mca_p->transport == SDP_TRANSPORT_TCPDTLSSCTP)) {
1377 if (cpr_strncasecmp(port_ptr, "webrtc-datachannel",
1378 sizeof("webrtc-datachannel")) != 0) {
1379 sdp_parse_error(sdp_p,
1380 "%s No webrtc-datachannel token in m= media line, "
1381 "parse failed.", sdp_p->debug_str);
1382 SDP_FREE(mca_p);
1383 sdp_p->conf_p->num_invalid_param++;
1384 return (SDP_INVALID_PARAMETER);
1386 mca_p->sctp_fmt = SDP_SCTP_MEDIA_FMT_WEBRTC_DATACHANNEL;
1387 } else {
1388 sctp_port = sdp_getnextnumtok(port_ptr, (const char **)&port_ptr,
1389 "/ \t", &result);
1390 if (result != SDP_SUCCESS) {
1391 sdp_parse_error(sdp_p,
1392 "%s No sctp port specified in m= media line, "
1393 "parse failed.", sdp_p->debug_str);
1394 SDP_FREE(mca_p);
1395 sdp_p->conf_p->num_invalid_param++;
1396 return (SDP_INVALID_PARAMETER);
1398 mca_p->sctpport = sctp_port;
1400 } else {
1401 /* Transport is a non-AAL2 type and not SCTP. Parse payloads
1402 normally. */
1403 sdp_parse_payload_types(sdp_p, mca_p, ptr);
1407 /* Media line params are valid. Add it into the SDP. */
1408 sdp_p->mca_count++;
1409 if (sdp_p->mca_p == NULL) {
1410 sdp_p->mca_p = mca_p;
1411 } else {
1412 for (next_mca_p = sdp_p->mca_p; next_mca_p->next_p != NULL;
1413 next_mca_p = next_mca_p->next_p) {
1414 ; // Empty For
1416 next_mca_p->next_p = mca_p;
1419 if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
1421 SDP_PRINT("%s Parsed media type %s, ", sdp_p->debug_str,
1422 sdp_get_media_name(mca_p->media));
1423 switch (mca_p->port_format) {
1424 case SDP_PORT_NUM_ONLY:
1425 SDP_PRINT("Port num %d, ", mca_p->port);
1426 break;
1428 case SDP_PORT_NUM_COUNT:
1429 SDP_PRINT("Port num %d, count %d, ",
1430 mca_p->port, mca_p->num_ports);
1431 break;
1432 case SDP_PORT_VPI_VCI:
1433 SDP_PRINT("VPI/VCI %d/%u, ", mca_p->vpi, mca_p->vci);
1434 break;
1435 case SDP_PORT_VCCI:
1436 SDP_PRINT("VCCI %d, ", mca_p->vcci);
1437 break;
1438 case SDP_PORT_NUM_VPI_VCI:
1439 SDP_PRINT("Port %d, VPI/VCI %d/%u, ", mca_p->port,
1440 mca_p->vpi, mca_p->vci);
1441 break;
1442 case SDP_PORT_VCCI_CID:
1443 SDP_PRINT("VCCI %d, CID %d, ", mca_p->vcci, mca_p->cid);
1444 break;
1445 case SDP_PORT_NUM_VPI_VCI_CID:
1446 SDP_PRINT("Port %d, VPI/VCI %d/%u, CID %d, ", mca_p->port,
1447 mca_p->vpi, mca_p->vci, mca_p->cid);
1448 break;
1449 default:
1450 SDP_PRINT("Port format not valid, ");
1451 break;
1454 if ((mca_p->transport >= SDP_TRANSPORT_AAL2_ITU) &&
1455 (mca_p->transport <= SDP_TRANSPORT_AAL2_CUSTOM)) {
1456 for (i=0; i < mca_p->media_profiles_p->num_profiles; i++) {
1457 SDP_PRINT("Profile %s, Num payloads %u ",
1458 sdp_get_transport_name(mca_p->media_profiles_p->profile[i]),
1459 (unsigned)mca_p->media_profiles_p->num_payloads[i]);
1461 } else {
1462 SDP_PRINT("Transport %s, Num payloads %u",
1463 sdp_get_transport_name(mca_p->transport),
1464 (unsigned)mca_p->num_payloads);
1467 return (SDP_SUCCESS);
1470 sdp_result_e sdp_build_media (sdp_t *sdp_p, uint16_t level, flex_string *fs)
1472 int i, j;
1473 sdp_mca_t *mca_p;
1474 tinybool invalid_params=FALSE;
1475 sdp_media_profiles_t *profile_p;
1477 /* Find the right media line */
1478 mca_p = sdp_find_media_level(sdp_p, level);
1479 if (mca_p == NULL) {
1480 return (SDP_FAILURE);
1483 /* Validate params for this media line */
1484 if ((mca_p->media >= SDP_MAX_MEDIA_TYPES) ||
1485 (mca_p->port_format >= SDP_MAX_PORT_FORMAT_TYPES) ||
1486 (mca_p->transport >= SDP_MAX_TRANSPORT_TYPES)) {
1487 invalid_params = TRUE;
1490 if (invalid_params == TRUE) {
1491 SDPLogError(logTag, "%s Invalid params for m= media line, "
1492 "build failed.", sdp_p->debug_str);
1493 sdp_p->conf_p->num_invalid_param++;
1494 return (SDP_INVALID_PARAMETER);
1497 /* Build the media type */
1498 flex_string_sprintf(fs, "m=%s ", sdp_get_media_name(mca_p->media));
1500 /* Build the port based on the specified port format */
1501 if (mca_p->port_format == SDP_PORT_NUM_ONLY) {
1502 if (mca_p->port == SDP_CHOOSE_PARAM) {
1503 flex_string_sprintf(fs, "$ ");
1504 } else {
1505 flex_string_sprintf(fs, "%u ", (unsigned)mca_p->port);
1507 } else if (mca_p->port_format == SDP_PORT_NUM_COUNT) {
1508 flex_string_sprintf(fs, "%u/%u ", (unsigned)mca_p->port,
1509 (unsigned)mca_p->num_ports);
1510 } else if (mca_p->port_format == SDP_PORT_VPI_VCI) {
1511 flex_string_sprintf(fs, "%u/%u ",
1512 (unsigned)mca_p->vpi, (unsigned)mca_p->vci);
1513 } else if (mca_p->port_format == SDP_PORT_VCCI) {
1514 flex_string_sprintf(fs, "%u ", (unsigned)mca_p->vcci);
1515 } else if (mca_p->port_format == SDP_PORT_NUM_VPI_VCI) {
1516 flex_string_sprintf(fs, "%u/%u/%u ", (unsigned)mca_p->port,
1517 (unsigned)mca_p->vpi, (unsigned)mca_p->vci);
1518 } else if (mca_p->port_format == SDP_PORT_VCCI_CID) {
1519 if ((mca_p->vcci == SDP_CHOOSE_PARAM) &&
1520 (mca_p->cid == SDP_CHOOSE_PARAM)) {
1521 flex_string_sprintf(fs, "$/$ ");
1522 } else if ((mca_p->vcci == SDP_CHOOSE_PARAM) ||
1523 (mca_p->cid == SDP_CHOOSE_PARAM)) {
1524 /* If one is set but not the other, this is an error. */
1525 SDPLogError(logTag, "%s Invalid params for m= port parameter, "
1526 "build failed.", sdp_p->debug_str);
1527 sdp_p->conf_p->num_invalid_param++;
1528 return (SDP_INVALID_PARAMETER);
1529 } else {
1530 flex_string_sprintf(fs, "%u/%u ",
1531 (unsigned)mca_p->vcci, (unsigned)mca_p->cid);
1533 } else if (mca_p->port_format == SDP_PORT_NUM_VPI_VCI_CID) {
1534 flex_string_sprintf(fs, "%u/%u/%u/%u ", (unsigned)mca_p->port,
1535 (unsigned)mca_p->vpi, (unsigned)mca_p->vci, (unsigned)mca_p->cid);
1538 /* If the media line has AAL2 profiles, build them differently. */
1539 if ((mca_p->transport == SDP_TRANSPORT_AAL2_ITU) ||
1540 (mca_p->transport == SDP_TRANSPORT_AAL2_ATMF) ||
1541 (mca_p->transport == SDP_TRANSPORT_AAL2_CUSTOM)) {
1542 profile_p = mca_p->media_profiles_p;
1543 for (i=0; i < profile_p->num_profiles; i++) {
1544 flex_string_sprintf(fs, "%s",
1545 sdp_get_transport_name(profile_p->profile[i]));
1547 for (j=0; j < profile_p->num_payloads[i]; j++) {
1548 flex_string_sprintf(fs, " %u",
1549 (unsigned)profile_p->payload_type[i][j]);
1551 flex_string_sprintf(fs, " ");
1553 flex_string_sprintf(fs, "\n");
1554 if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
1555 SDP_PRINT("%s Built m= media line", sdp_p->debug_str);
1557 return (SDP_SUCCESS);
1560 /* Build the transport name */
1561 flex_string_sprintf(fs, "%s",
1562 sdp_get_transport_name(mca_p->transport));
1564 if(mca_p->transport != SDP_TRANSPORT_DTLSSCTP) {
1566 /* Build the format lists */
1567 for (i=0; i < mca_p->num_payloads; i++) {
1568 if (mca_p->payload_indicator[i] == SDP_PAYLOAD_ENUM) {
1569 flex_string_sprintf(fs, " %s",
1570 sdp_get_payload_name((sdp_payload_e)mca_p->payload_type[i]));
1571 } else {
1572 flex_string_sprintf(fs, " %u", (unsigned)mca_p->payload_type[i]);
1575 } else {
1576 /* Add port to SDP if transport is DTLS/SCTP */
1577 flex_string_sprintf(fs, " %u", (unsigned)mca_p->sctpport);
1580 flex_string_sprintf(fs, "\r\n");
1582 if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
1583 SDP_PRINT("%s Built m= media line", sdp_p->debug_str);
1585 return (SDP_SUCCESS);
1589 /* Function: sdp_parse_payload_types
1590 * Description: Parse a list of payload types. The list may be part of
1591 * a media line or part of a capability line.
1592 * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
1593 * mca_p The mca structure the payload types should be
1594 * added to.
1595 * ptr The pointer to the list of payloads.
1596 * Returns: Nothing.
1598 void sdp_parse_payload_types (sdp_t *sdp_p, sdp_mca_t *mca_p, const char *ptr)
1600 uint16_t i;
1601 uint16_t num_payloads;
1602 sdp_result_e result;
1603 tinybool valid_payload;
1604 char tmp[SDP_MAX_STRING_LEN];
1605 char *tmp2;
1607 for (num_payloads = 0; (num_payloads < SDP_MAX_PAYLOAD_TYPES); ) {
1608 ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
1609 if (result != SDP_SUCCESS) {
1610 /* If there are no more payload types, we're finished */
1611 break;
1613 mca_p->payload_type[num_payloads] = (uint16_t)sdp_getnextnumtok(tmp,
1614 (const char **)&tmp2,
1615 " \t", &result);
1616 if (result == SDP_SUCCESS) {
1617 if ((mca_p->media == SDP_MEDIA_IMAGE) &&
1618 (mca_p->transport == SDP_TRANSPORT_UDPTL)) {
1619 sdp_parse_error(sdp_p,
1620 "%s Warning: Numeric payload type not "
1621 "valid for media %s with transport %s.",
1622 sdp_p->debug_str,
1623 sdp_get_media_name(mca_p->media),
1624 sdp_get_transport_name(mca_p->transport));
1625 } else {
1626 mca_p->payload_indicator[num_payloads] = SDP_PAYLOAD_NUMERIC;
1627 mca_p->num_payloads++;
1628 num_payloads++;
1630 continue;
1633 valid_payload = FALSE;
1634 for (i=0; i < SDP_MAX_STRING_PAYLOAD_TYPES; i++) {
1635 if (cpr_strncasecmp(tmp, sdp_payload[i].name,
1636 sdp_payload[i].strlen) == 0) {
1637 valid_payload = TRUE;
1638 break;
1641 if (valid_payload == TRUE) {
1642 /* We recognized the payload type. Make sure it
1643 * is valid for this media line. */
1644 valid_payload = FALSE;
1645 if ((mca_p->media == SDP_MEDIA_IMAGE) &&
1646 (mca_p->transport == SDP_TRANSPORT_UDPTL) &&
1647 (i == SDP_PAYLOAD_T38)) {
1648 valid_payload = TRUE;
1649 } else if ((mca_p->media == SDP_MEDIA_APPLICATION) &&
1650 (mca_p->transport == SDP_TRANSPORT_UDP) &&
1651 (i == SDP_PAYLOAD_XTMR)) {
1652 valid_payload = TRUE;
1653 } else if ((mca_p->media == SDP_MEDIA_APPLICATION) &&
1654 (mca_p->transport == SDP_TRANSPORT_TCP) &&
1655 (i == SDP_PAYLOAD_T120)) {
1656 valid_payload = TRUE;
1659 if (valid_payload == TRUE) {
1660 mca_p->payload_indicator[num_payloads] = SDP_PAYLOAD_ENUM;
1661 mca_p->payload_type[num_payloads] = i;
1662 mca_p->num_payloads++;
1663 num_payloads++;
1664 } else {
1665 sdp_parse_error(sdp_p,
1666 "%s Warning: Payload type %s not valid for "
1667 "media %s with transport %s.",
1668 sdp_p->debug_str,
1669 sdp_get_payload_name((sdp_payload_e)i),
1670 sdp_get_media_name(mca_p->media),
1671 sdp_get_transport_name(mca_p->transport));
1673 } else {
1674 /* Payload type wasn't recognized. */
1675 sdp_parse_error(sdp_p,
1676 "%s Warning: Payload type "
1677 "unsupported (%s).", sdp_p->debug_str, tmp);
1680 if (mca_p->num_payloads == 0) {
1681 sdp_parse_error(sdp_p,
1682 "%s Warning: No payload types specified.",
1683 sdp_p->debug_str);