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/. */
7 #include "sdp_os_defs.h"
9 #include "sdp_private.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
);
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
);
48 /* v= line is not required. */
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
);
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
66 size_t end
= strspn(ptr
, "0123456789");
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
;
80 sdp_result_e
sdp_parse_owner (sdp_t
*sdp_p
, uint16_t level
, const char *ptr
)
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.",
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=.",
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
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=.",
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
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=.",
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=.",
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=.",
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
),
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
);
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
),
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
)
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.",
274 endptr
= sdp_findchar(ptr
, "\r\n");
276 sdp_parse_error(sdp_p
,
277 "%s Warning: No session name specified.",
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
);
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
)
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.",
328 sdp_p
->sessinfo_found
= TRUE
;
330 mca_p
= sdp_find_media_level(sdp_p
, level
);
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");
345 sdp_parse_error(sdp_p
,
346 "%s Warning: No session info specified.",
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
)
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.",
372 sdp_p
->uri_found
= TRUE
;
374 endptr
= sdp_findchar(ptr
, "\n");
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
)
396 endptr
= sdp_findchar(ptr
, "\n");
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
)
418 endptr
= sdp_findchar(ptr
, "\n");
420 sdp_parse_error(sdp_p
,
421 "%s Warning: No phone number info specified.",
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
)
440 const char *slash_ptr
;
444 char tmp
[SDP_MAX_STRING_LEN
];
445 char mcast_str
[MCAST_STRING_LEN
];
447 unsigned long strtoul_result
;
450 if (level
== SDP_SESSION_LEVEL
) {
451 conn_p
= &(sdp_p
->default_conn
);
453 mca_p
= sdp_find_media_level(sdp_p
, level
);
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
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=.",
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
);
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=.",
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
) {
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';
577 slash_ptr
= sdp_getnextstrtok(slash_ptr
, tmp
, sizeof(tmp
),
579 if (result
!= SDP_SUCCESS
) {
580 sdp_parse_error(sdp_p
,
581 "%s No ttl value specified for this multicast addr with a slash",
583 sdp_p
->conf_p
->num_invalid_param
++;
584 return (SDP_INVALID_PARAMETER
);
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 ",
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
);
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 ",
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",
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
)
651 if (level
== SDP_SESSION_LEVEL
) {
652 conn_p
= &(sdp_p
->default_conn
);
654 mca_p
= sdp_find_media_level(sdp_p
, level
);
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
));
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
),
682 (unsigned)conn_p
->ttl
,
683 (unsigned)conn_p
->num_of_addresses
);
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
),
689 (unsigned)conn_p
->ttl
);
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
),
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
)
722 sdp_bw_data_t
*bw_data_p
;
723 sdp_bw_data_t
*new_bw_data_p
;
725 char tmp
[SDP_MAX_STRING_LEN
];
726 sdp_bw_modifier_e bw_modifier
= SDP_BW_MODIFIER_UNSUPPORTED
;
729 if (level
== SDP_SESSION_LEVEL
) {
732 mca_p
= sdp_find_media_level(sdp_p
, level
);
734 return (SDP_FAILURE
);
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= ",
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
;
760 if (bw_modifier
== SDP_BW_MODIFIER_UNSUPPORTED
) {
761 /* We don't understand this parameter, so according to RFC4566 sec 5.8
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.}*/
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 ",
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
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
;
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
) {
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
)
828 sdp_bw_data_t
*bw_data_p
;
831 if (level
== SDP_SESSION_LEVEL
) {
834 mca_p
= sdp_find_media_level(sdp_p
, level
);
836 return (SDP_FAILURE
);
841 bw_data_p
= bw_p
->bw_data_list
;
843 flex_string_sprintf(fs
, "b=%s:%d\r\n",
844 sdp_get_bw_modifier_name(bw_data_p
->bw_modifier
),
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
),
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
)
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
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.",
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
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.",
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
;
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
);
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
)
954 endptr
= sdp_findchar(ptr
, "\n");
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
)
977 endptr
= sdp_findchar(ptr
, "\n");
979 sdp_parse_error(sdp_p
,
980 "%s Warning: No timezone parameters specified.",
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
)
1000 sdp_encryptspec_t
*encrypt_p
;
1002 char tmp
[SDP_MAX_STRING_LEN
];
1004 if (level
== SDP_SESSION_LEVEL
) {
1005 encrypt_p
= &(sdp_p
->encrypt
);
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=.",
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
;
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.}*/
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
;
1073 if (level
== SDP_SESSION_LEVEL
) {
1074 encrypt_p
= &(sdp_p
->encrypt
);
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");
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
)
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
;
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
;
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.",
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
);
1160 sdp_p
->conf_p
->num_invalid_param
++;
1161 return (SDP_INVALID_PARAMETER
);
1164 for (i
=0; i
< SDP_MAX_PORT_PARAMS
; i
++) {
1165 num
[i
] = sdp_getnextnumtok(port_ptr
, (const char **)&port_ptr
,
1167 if (result
!= SDP_SUCCESS
) {
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
);
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
;
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
) {
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
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
;
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
;
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
;
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
;
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
) &&
1279 mca_p
->port
= num
[0];
1280 mca_p
->num_ports
= 1;
1281 mca_p
->port_format
= SDP_PORT_NUM_COUNT
;
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
;
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
;
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
;
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
;
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
++;
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
);
1370 sdp_p
->conf_p
->num_invalid_param
++;
1371 return (SDP_INVALID_PARAMETER
);
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
);
1383 sdp_p
->conf_p
->num_invalid_param
++;
1384 return (SDP_INVALID_PARAMETER
);
1386 mca_p
->sctp_fmt
= SDP_SCTP_MEDIA_FMT_WEBRTC_DATACHANNEL
;
1388 sctp_port
= sdp_getnextnumtok(port_ptr
, (const char **)&port_ptr
,
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
);
1395 sdp_p
->conf_p
->num_invalid_param
++;
1396 return (SDP_INVALID_PARAMETER
);
1398 mca_p
->sctpport
= sctp_port
;
1401 /* Transport is a non-AAL2 type and not SCTP. Parse payloads
1403 sdp_parse_payload_types(sdp_p
, mca_p
, ptr
);
1407 /* Media line params are valid. Add it into the SDP. */
1409 if (sdp_p
->mca_p
== NULL
) {
1410 sdp_p
->mca_p
= mca_p
;
1412 for (next_mca_p
= sdp_p
->mca_p
; next_mca_p
->next_p
!= NULL
;
1413 next_mca_p
= next_mca_p
->next_p
) {
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
);
1428 case SDP_PORT_NUM_COUNT
:
1429 SDP_PRINT("Port num %d, count %d, ",
1430 mca_p
->port
, mca_p
->num_ports
);
1432 case SDP_PORT_VPI_VCI
:
1433 SDP_PRINT("VPI/VCI %d/%u, ", mca_p
->vpi
, mca_p
->vci
);
1436 SDP_PRINT("VCCI %d, ", mca_p
->vcci
);
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
);
1442 case SDP_PORT_VCCI_CID
:
1443 SDP_PRINT("VCCI %d, CID %d, ", mca_p
->vcci
, mca_p
->cid
);
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
);
1450 SDP_PRINT("Port format not valid, ");
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
]);
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
)
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
, "$ ");
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
);
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
]));
1572 flex_string_sprintf(fs
, " %u", (unsigned)mca_p
->payload_type
[i
]);
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
1595 * ptr The pointer to the list of payloads.
1598 void sdp_parse_payload_types (sdp_t
*sdp_p
, sdp_mca_t
*mca_p
, const char *ptr
)
1601 uint16_t num_payloads
;
1602 sdp_result_e result
;
1603 tinybool valid_payload
;
1604 char tmp
[SDP_MAX_STRING_LEN
];
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 */
1613 mca_p
->payload_type
[num_payloads
] = (uint16_t)sdp_getnextnumtok(tmp
,
1614 (const char **)&tmp2
,
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.",
1623 sdp_get_media_name(mca_p
->media
),
1624 sdp_get_transport_name(mca_p
->transport
));
1626 mca_p
->payload_indicator
[num_payloads
] = SDP_PAYLOAD_NUMERIC
;
1627 mca_p
->num_payloads
++;
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
;
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
++;
1665 sdp_parse_error(sdp_p
,
1666 "%s Warning: Payload type %s not valid for "
1667 "media %s with transport %s.",
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
));
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.",