mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-26 14:22:01 +00:00
b6b3c20d6f
Differential Revision: https://phabricator.services.mozilla.com/D89943
1687 lines
60 KiB
C
1687 lines
60 KiB
C
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#include <errno.h>
|
|
|
|
#include "sdp_os_defs.h"
|
|
#include "sipcc_sdp.h"
|
|
#include "sdp_private.h"
|
|
|
|
#include "sdp_log.h"
|
|
#include "prprf.h"
|
|
|
|
static const char *logTag = "sdp_token";
|
|
|
|
#define MCAST_STRING_LEN 4
|
|
|
|
|
|
sdp_result_e sdp_parse_version (sdp_t *sdp_p, uint16_t level, const char *ptr)
|
|
{
|
|
sdp_result_e result = SDP_FAILURE;
|
|
|
|
sdp_p->version = (uint16_t)sdp_getnextnumtok(ptr, &ptr, " \t", &result);
|
|
if ((result != SDP_SUCCESS) || (sdp_p->version != SDP_CURRENT_VERSION)) {
|
|
sdp_parse_error(sdp_p,
|
|
"%s Invalid version (%u) found, parse failed.",
|
|
sdp_p->debug_str, (unsigned)sdp_p->version);
|
|
sdp_p->conf_p->num_invalid_param++;
|
|
return (SDP_INVALID_PARAMETER);
|
|
}
|
|
|
|
if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
|
|
SDP_PRINT("%s Parse version line successful, version %u",
|
|
sdp_p->debug_str, (unsigned)sdp_p->version);
|
|
}
|
|
return (SDP_SUCCESS);
|
|
}
|
|
|
|
sdp_result_e sdp_build_version (sdp_t *sdp_p, uint16_t level, flex_string *fs)
|
|
{
|
|
if (sdp_p->version == SDP_INVALID_VALUE) {
|
|
if (sdp_p->conf_p->version_reqd == TRUE) {
|
|
SDPLogError(logTag, "%s Invalid version for v= line, "
|
|
"build failed.", sdp_p->debug_str);
|
|
sdp_p->conf_p->num_invalid_param++;
|
|
return (SDP_INVALID_PARAMETER);
|
|
} else {
|
|
/* v= line is not required. */
|
|
return (SDP_SUCCESS);
|
|
}
|
|
}
|
|
|
|
flex_string_sprintf(fs, "v=%u\r\n", (unsigned)sdp_p->version);
|
|
|
|
if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
|
|
SDP_PRINT("%s Built v= version line", sdp_p->debug_str);
|
|
}
|
|
return (SDP_SUCCESS);
|
|
}
|
|
|
|
static sdp_result_e sdp_verify_unsigned(const char *ptr, uint64_t max_value)
|
|
{
|
|
uint64_t numeric_value;
|
|
/* Checking for only numbers since PR_sscanf will ignore trailing
|
|
characters */
|
|
size_t end = strspn(ptr, "0123456789");
|
|
|
|
if (ptr[end] != '\0')
|
|
return SDP_INVALID_PARAMETER;
|
|
|
|
if (PR_sscanf(ptr, "%llu", &numeric_value) != 1)
|
|
return SDP_INVALID_PARAMETER;
|
|
|
|
if (numeric_value > max_value)
|
|
return SDP_INVALID_PARAMETER;
|
|
|
|
return SDP_SUCCESS;
|
|
}
|
|
|
|
sdp_result_e sdp_parse_owner (sdp_t *sdp_p, uint16_t level, const char *ptr)
|
|
{
|
|
int i;
|
|
sdp_result_e result;
|
|
char tmp[SDP_MAX_STRING_LEN];
|
|
/* The spec says this:
|
|
|
|
The numeric value of the session id
|
|
and version in the o line MUST be representable with a 64 bit signed
|
|
integer. The initial value of the version MUST be less than
|
|
(2**62)-1, to avoid rollovers.
|
|
*/
|
|
const uint64_t max_value_sessid = ((((uint64_t) 1) << 63) - 1);
|
|
/* Do not check that this is 2^62 - 1; that's just the limit on
|
|
* the initial version, not every version number. */
|
|
const uint64_t max_value_version = ((((uint64_t) 1) << 63) - 1);
|
|
|
|
if (sdp_p->owner_name[0] != '\0') {
|
|
sdp_p->conf_p->num_invalid_token_order++;
|
|
sdp_parse_error(sdp_p,
|
|
"%s Warning: More than one o= line specified.",
|
|
sdp_p->debug_str);
|
|
}
|
|
|
|
/* Find the owner name. */
|
|
ptr = sdp_getnextstrtok(ptr, sdp_p->owner_name, sizeof(sdp_p->owner_name), " \t", &result);
|
|
if (result != SDP_SUCCESS) {
|
|
sdp_parse_error(sdp_p,
|
|
"%s No owner name specified for o=.",
|
|
sdp_p->debug_str);
|
|
sdp_p->conf_p->num_invalid_param++;
|
|
return (SDP_INVALID_PARAMETER);
|
|
}
|
|
|
|
/* Find the owner session id. This is a numeric field but is
|
|
* stored as a string since it may be 64 bit.
|
|
*/
|
|
ptr = sdp_getnextstrtok(ptr, sdp_p->owner_sessid, sizeof(sdp_p->owner_sessid), " \t", &result);
|
|
if (result == SDP_SUCCESS) {
|
|
/* Make sure the sessid is numeric, even though we store it as
|
|
* a string.
|
|
*/
|
|
result = sdp_verify_unsigned(sdp_p->owner_sessid, max_value_sessid);
|
|
}
|
|
if (result != SDP_SUCCESS) {
|
|
sdp_parse_error(sdp_p,
|
|
"%s Invalid owner session id specified for o=.",
|
|
sdp_p->debug_str);
|
|
sdp_p->conf_p->num_invalid_param++;
|
|
return (SDP_INVALID_PARAMETER);
|
|
}
|
|
|
|
/* Find the owner version. */
|
|
ptr = sdp_getnextstrtok(ptr, sdp_p->owner_version, sizeof(sdp_p->owner_version), " \t", &result);
|
|
if (result == SDP_SUCCESS) {
|
|
/* Make sure the version is numeric, even though we store it as
|
|
* a string.
|
|
*/
|
|
result = sdp_verify_unsigned(sdp_p->owner_version, max_value_version);
|
|
}
|
|
if (result != SDP_SUCCESS) {
|
|
sdp_parse_error(sdp_p,
|
|
"%s Invalid owner version specified for o=.",
|
|
sdp_p->debug_str);
|
|
sdp_p->conf_p->num_invalid_param++;
|
|
return (SDP_INVALID_PARAMETER);
|
|
}
|
|
|
|
/* Find the owner network type. */
|
|
ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
|
|
if (result != SDP_SUCCESS) {
|
|
sdp_parse_error(sdp_p,
|
|
"%s No owner network type specified for o=.",
|
|
sdp_p->debug_str);
|
|
sdp_p->conf_p->num_invalid_param++;
|
|
return (SDP_INVALID_PARAMETER);
|
|
}
|
|
sdp_p->owner_network_type = SDP_NT_UNSUPPORTED;
|
|
for (i=0; i < SDP_MAX_NETWORK_TYPES; i++) {
|
|
if (cpr_strncasecmp(tmp, sdp_nettype[i].name,
|
|
sdp_nettype[i].strlen) == 0) {
|
|
if (sdp_p->conf_p->nettype_supported[i] == TRUE) {
|
|
sdp_p->owner_network_type = (sdp_nettype_e)i;
|
|
}
|
|
}
|
|
}
|
|
if (sdp_p->owner_network_type == SDP_NT_UNSUPPORTED) {
|
|
sdp_parse_error(sdp_p,
|
|
"%s Owner network type unsupported (%s)",
|
|
sdp_p->debug_str, tmp);
|
|
sdp_p->conf_p->num_invalid_param++;
|
|
return (SDP_INVALID_PARAMETER);
|
|
}
|
|
|
|
/* Find the owner address type. */
|
|
ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
|
|
if (result != SDP_SUCCESS) {
|
|
sdp_parse_error(sdp_p,
|
|
"%s No owner address type specified for o=.",
|
|
sdp_p->debug_str);
|
|
sdp_p->conf_p->num_invalid_param++;
|
|
return (SDP_INVALID_PARAMETER);
|
|
}
|
|
sdp_p->owner_addr_type = SDP_AT_UNSUPPORTED;
|
|
for (i=0; i < SDP_MAX_ADDR_TYPES; i++) {
|
|
if (cpr_strncasecmp(tmp, sdp_addrtype[i].name,
|
|
sdp_addrtype[i].strlen) == 0) {
|
|
if (sdp_p->conf_p->addrtype_supported[i] == TRUE) {
|
|
sdp_p->owner_addr_type = (sdp_addrtype_e)i;
|
|
}
|
|
}
|
|
}
|
|
if ((sdp_p->owner_addr_type == SDP_AT_UNSUPPORTED) &&
|
|
(sdp_p->owner_network_type != SDP_NT_ATM)) {
|
|
sdp_parse_error(sdp_p,
|
|
"%s Owner address type unsupported (%s)",
|
|
sdp_p->debug_str, tmp);
|
|
sdp_p->conf_p->num_invalid_param++;
|
|
return (SDP_INVALID_PARAMETER);
|
|
}
|
|
|
|
/* Find the owner address. */
|
|
ptr = sdp_getnextstrtok(ptr, sdp_p->owner_addr, sizeof(sdp_p->owner_addr), " \t", &result);
|
|
if (result != SDP_SUCCESS) {
|
|
sdp_parse_error(sdp_p,
|
|
"%s No owner address specified.", sdp_p->debug_str);
|
|
sdp_p->conf_p->num_invalid_param++;
|
|
return (SDP_INVALID_PARAMETER);
|
|
}
|
|
|
|
if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
|
|
SDP_PRINT("%s Parse owner: name %s, session id %s, version %s",
|
|
sdp_p->debug_str, sdp_p->owner_name, sdp_p->owner_sessid,
|
|
sdp_p->owner_version);
|
|
SDP_PRINT("%s network %s, address type %s, "
|
|
"address %s", sdp_p->debug_str,
|
|
sdp_get_network_name(sdp_p->owner_network_type),
|
|
sdp_get_address_name(sdp_p->owner_addr_type),
|
|
sdp_p->owner_addr);
|
|
}
|
|
return (SDP_SUCCESS);
|
|
}
|
|
|
|
sdp_result_e sdp_build_owner (sdp_t *sdp_p, uint16_t level, flex_string *fs)
|
|
{
|
|
if ((sdp_p->owner_name[0] == '\0') ||
|
|
(sdp_p->owner_network_type >= SDP_MAX_NETWORK_TYPES) ||
|
|
(sdp_p->owner_addr_type >= SDP_MAX_ADDR_TYPES) ||
|
|
(sdp_p->owner_addr[0] == '\0')) {
|
|
|
|
if((sdp_p->owner_network_type == SDP_NT_ATM) &&
|
|
(sdp_p->owner_addr_type == SDP_AT_INVALID)) {
|
|
flex_string_sprintf(fs, "o=%s %s %s %s - -\r\n",
|
|
sdp_p->owner_name, sdp_p->owner_sessid,
|
|
sdp_p->owner_version,
|
|
sdp_get_network_name(sdp_p->owner_network_type));
|
|
}
|
|
|
|
if (sdp_p->conf_p->owner_reqd == TRUE) {
|
|
SDPLogError(logTag, "%s Invalid params for o= owner line, "
|
|
"build failed.", sdp_p->debug_str);
|
|
sdp_p->conf_p->num_invalid_param++;
|
|
return (SDP_INVALID_PARAMETER);
|
|
} else {
|
|
/* o= line is not required. */
|
|
return (SDP_SUCCESS);
|
|
}
|
|
}
|
|
|
|
flex_string_sprintf(fs, "o=%s %s %s %s %s %s\r\n",
|
|
sdp_p->owner_name, sdp_p->owner_sessid,
|
|
sdp_p->owner_version,
|
|
sdp_get_network_name(sdp_p->owner_network_type),
|
|
sdp_get_address_name(sdp_p->owner_addr_type),
|
|
sdp_p->owner_addr);
|
|
|
|
if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
|
|
SDP_PRINT("%s Built o= owner line", sdp_p->debug_str);
|
|
}
|
|
return (SDP_SUCCESS);
|
|
}
|
|
|
|
sdp_result_e sdp_parse_sessname (sdp_t *sdp_p, uint16_t level, const char *ptr)
|
|
{
|
|
int str_len;
|
|
char *endptr;
|
|
|
|
if (sdp_p->sessname[0] != '\0') {
|
|
sdp_p->conf_p->num_invalid_token_order++;
|
|
sdp_parse_error(sdp_p,
|
|
"%s Warning: More than one s= line specified.",
|
|
sdp_p->debug_str);
|
|
}
|
|
|
|
endptr = sdp_findchar(ptr, "\r\n");
|
|
if (ptr == endptr) {
|
|
sdp_parse_error(sdp_p,
|
|
"%s Warning: No session name specified.",
|
|
sdp_p->debug_str);
|
|
}
|
|
str_len = MIN(endptr - ptr, SDP_MAX_STRING_LEN);
|
|
sstrncpy(sdp_p->sessname, ptr, str_len+1);
|
|
|
|
if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
|
|
SDP_PRINT("%s Parse session name, %s",
|
|
sdp_p->debug_str, sdp_p->sessname);
|
|
}
|
|
return (SDP_SUCCESS);
|
|
}
|
|
|
|
sdp_result_e sdp_build_sessname (sdp_t *sdp_p, uint16_t level, flex_string *fs)
|
|
{
|
|
if (sdp_p->sessname[0] == '\0') {
|
|
if (sdp_p->conf_p->session_name_reqd == TRUE) {
|
|
SDPLogError(logTag, "%s No param defined for s= session name line, "
|
|
"build failed.", sdp_p->debug_str);
|
|
sdp_p->conf_p->num_invalid_param++;
|
|
return (SDP_INVALID_PARAMETER);
|
|
} else {
|
|
/* s= line is not required. */
|
|
return (SDP_SUCCESS);
|
|
}
|
|
}
|
|
|
|
flex_string_sprintf(fs, "s=%s\r\n", sdp_p->sessname);
|
|
|
|
if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
|
|
SDP_PRINT("%s Built s= session name line", sdp_p->debug_str);
|
|
}
|
|
return (SDP_SUCCESS);
|
|
}
|
|
|
|
/* We don't want to store the session info, but we do want to validate
|
|
* that at most one i= line exists at each level and if the line exists
|
|
* there should be a parameter.
|
|
*/
|
|
sdp_result_e sdp_parse_sessinfo (sdp_t *sdp_p, uint16_t level, const char *ptr)
|
|
{
|
|
char *endptr;
|
|
sdp_mca_t *mca_p;
|
|
|
|
if (level == SDP_SESSION_LEVEL) {
|
|
if (sdp_p->sessinfo_found == TRUE) {
|
|
sdp_p->conf_p->num_invalid_token_order++;
|
|
sdp_parse_error(sdp_p,
|
|
"%s Warning: More than one i= line specified.",
|
|
sdp_p->debug_str);
|
|
}
|
|
sdp_p->sessinfo_found = TRUE;
|
|
} else {
|
|
mca_p = sdp_find_media_level(sdp_p, level);
|
|
if (mca_p == NULL) {
|
|
return (SDP_FAILURE);
|
|
}
|
|
if (mca_p->sessinfo_found == TRUE) {
|
|
sdp_p->conf_p->num_invalid_token_order++;
|
|
sdp_parse_error(sdp_p,
|
|
"%s Warning: More than one i= line specified"
|
|
" for media line %u.", sdp_p->debug_str, (unsigned)level);
|
|
}
|
|
mca_p->sessinfo_found = TRUE;
|
|
}
|
|
|
|
endptr = sdp_findchar(ptr, "\n");
|
|
if (ptr == endptr) {
|
|
sdp_parse_error(sdp_p,
|
|
"%s Warning: No session info specified.",
|
|
sdp_p->debug_str);
|
|
}
|
|
|
|
if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
|
|
SDP_PRINT("%s Parsed session info line.", sdp_p->debug_str);
|
|
}
|
|
return (SDP_SUCCESS);
|
|
}
|
|
|
|
sdp_result_e sdp_build_sessinfo (sdp_t *sdp_p, uint16_t level, flex_string *fs)
|
|
{
|
|
/* Build session info line not supported. */
|
|
return (SDP_SUCCESS);
|
|
}
|
|
|
|
sdp_result_e sdp_parse_uri (sdp_t *sdp_p, uint16_t level, const char *ptr)
|
|
{
|
|
char *endptr;
|
|
|
|
if (sdp_p->uri_found == TRUE) {
|
|
sdp_p->conf_p->num_invalid_token_order++;
|
|
sdp_parse_error(sdp_p,
|
|
"%s Warning: More than one u= line specified.",
|
|
sdp_p->debug_str);
|
|
}
|
|
sdp_p->uri_found = TRUE;
|
|
|
|
endptr = sdp_findchar(ptr, "\n");
|
|
if (ptr == endptr) {
|
|
sdp_parse_error(sdp_p,
|
|
"%s Warning: No URI info specified.", sdp_p->debug_str);
|
|
}
|
|
|
|
if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
|
|
SDP_PRINT("%s Parsed URI line.", sdp_p->debug_str);
|
|
}
|
|
return (SDP_SUCCESS);
|
|
}
|
|
|
|
sdp_result_e sdp_build_uri (sdp_t *sdp_p, uint16_t level, flex_string *fs)
|
|
{
|
|
/* Build URI line not supported. */
|
|
return (SDP_SUCCESS);
|
|
}
|
|
|
|
sdp_result_e sdp_parse_email (sdp_t *sdp_p, uint16_t level, const char *ptr)
|
|
{
|
|
char *endptr;
|
|
|
|
endptr = sdp_findchar(ptr, "\n");
|
|
if (ptr == endptr) {
|
|
sdp_parse_error(sdp_p,
|
|
"%s Warning: No email info specified.", sdp_p->debug_str);
|
|
}
|
|
|
|
if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
|
|
SDP_PRINT("%s Parse email line", sdp_p->debug_str);
|
|
}
|
|
return (SDP_SUCCESS);
|
|
}
|
|
|
|
sdp_result_e sdp_build_email (sdp_t *sdp_p, uint16_t level, flex_string *fs)
|
|
{
|
|
/* Build email line not supported. */
|
|
return (SDP_SUCCESS);
|
|
}
|
|
|
|
sdp_result_e sdp_parse_phonenum (sdp_t *sdp_p, uint16_t level, const char *ptr)
|
|
{
|
|
char *endptr;
|
|
|
|
endptr = sdp_findchar(ptr, "\n");
|
|
if (ptr == endptr) {
|
|
sdp_parse_error(sdp_p,
|
|
"%s Warning: No phone number info specified.",
|
|
sdp_p->debug_str);
|
|
}
|
|
|
|
if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
|
|
SDP_PRINT("%s Parse phone number line", sdp_p->debug_str);
|
|
}
|
|
return (SDP_SUCCESS);
|
|
}
|
|
|
|
sdp_result_e sdp_build_phonenum (sdp_t *sdp_p, uint16_t level, flex_string *fs)
|
|
{
|
|
/* Build phone number line not supported. */
|
|
return (SDP_SUCCESS);
|
|
}
|
|
|
|
sdp_result_e sdp_parse_connection (sdp_t *sdp_p, uint16_t level, const char *ptr)
|
|
{
|
|
int i;
|
|
const char *slash_ptr;
|
|
sdp_result_e result;
|
|
sdp_conn_t *conn_p;
|
|
sdp_mca_t *mca_p;
|
|
char tmp[SDP_MAX_STRING_LEN];
|
|
char mcast_str[MCAST_STRING_LEN];
|
|
int mcast_bits;
|
|
unsigned long strtoul_result;
|
|
char *strtoul_end;
|
|
|
|
if (level == SDP_SESSION_LEVEL) {
|
|
conn_p = &(sdp_p->default_conn);
|
|
} else {
|
|
mca_p = sdp_find_media_level(sdp_p, level);
|
|
if (mca_p == NULL) {
|
|
return (SDP_FAILURE);
|
|
}
|
|
conn_p = &(mca_p->conn);
|
|
}
|
|
|
|
/* See if the c= line is already defined at this level. We don't
|
|
* currently support multihoming and so we only support one c= at
|
|
* each level.
|
|
*/
|
|
if (conn_p->nettype != SDP_NT_INVALID) {
|
|
sdp_p->conf_p->num_invalid_token_order++;
|
|
sdp_parse_error(sdp_p,
|
|
"%s c= line specified twice at same level, "
|
|
"parse failed.", sdp_p->debug_str);
|
|
return (SDP_INVALID_TOKEN_ORDERING);
|
|
}
|
|
|
|
/* Find the connection network type. */
|
|
ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
|
|
if (result != SDP_SUCCESS) {
|
|
sdp_parse_error(sdp_p,
|
|
"%s No connection network type specified for c=.",
|
|
sdp_p->debug_str);
|
|
sdp_p->conf_p->num_invalid_param++;
|
|
return (SDP_INVALID_PARAMETER);
|
|
}
|
|
conn_p->nettype = SDP_NT_UNSUPPORTED;
|
|
for (i=0; i < SDP_MAX_NETWORK_TYPES; i++) {
|
|
if (cpr_strncasecmp(tmp, sdp_nettype[i].name,
|
|
sdp_nettype[i].strlen) == 0) {
|
|
if (sdp_p->conf_p->nettype_supported[i] == TRUE) {
|
|
conn_p->nettype = (sdp_nettype_e)i;
|
|
}
|
|
}
|
|
}
|
|
if (conn_p->nettype == SDP_NT_UNSUPPORTED) {
|
|
sdp_parse_error(sdp_p,
|
|
"%s Warning: Connection network type unsupported "
|
|
"(%s) for c=.", sdp_p->debug_str, tmp);
|
|
}
|
|
|
|
/* Find the connection address type. */
|
|
ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
|
|
if (result != SDP_SUCCESS) {
|
|
if (conn_p->nettype == SDP_NT_ATM) {
|
|
/* If the nettype is ATM, addr type and addr are not reqd */
|
|
if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
|
|
SDP_PRINT("%s Parse connection: network %s", sdp_p->debug_str,
|
|
sdp_get_network_name(conn_p->nettype));
|
|
}
|
|
return (SDP_SUCCESS);
|
|
} else {
|
|
sdp_parse_error(sdp_p,
|
|
"%s No connection address type specified for "
|
|
"c=.", sdp_p->debug_str);
|
|
sdp_p->conf_p->num_invalid_param++;
|
|
return (SDP_INVALID_PARAMETER);
|
|
}
|
|
}
|
|
conn_p->addrtype = SDP_AT_UNSUPPORTED;
|
|
for (i=0; i < SDP_MAX_ADDR_TYPES; i++) {
|
|
if (cpr_strncasecmp(tmp, sdp_addrtype[i].name,
|
|
sdp_addrtype[i].strlen) == 0) {
|
|
if (sdp_p->conf_p->addrtype_supported[i] == TRUE) {
|
|
conn_p->addrtype = (sdp_addrtype_e)i;
|
|
}
|
|
}
|
|
}
|
|
if (conn_p->addrtype == SDP_AT_UNSUPPORTED) {
|
|
sdp_parse_error(sdp_p,
|
|
"%s Warning: Connection address type unsupported "
|
|
"(%s) for c=.", sdp_p->debug_str, tmp);
|
|
}
|
|
|
|
/* Find the connection address. */
|
|
ptr = sdp_getnextstrtok(ptr, conn_p->conn_addr, sizeof(conn_p->conn_addr), " \t", &result);
|
|
if (result != SDP_SUCCESS) {
|
|
sdp_parse_error(sdp_p,
|
|
"%s No connection address specified for c=.",
|
|
sdp_p->debug_str);
|
|
sdp_p->conf_p->num_invalid_param++;
|
|
return (SDP_INVALID_PARAMETER);
|
|
}
|
|
/* We currently only support addrs containing '/'s for EPN addrs.
|
|
* For other addrs this would indicate multicast addrs. */
|
|
/* Multicast host group addresses are defined to be the IP addresses
|
|
* whose high-order four bits are 1110, giving an address range from
|
|
* 224.0.0.0 through 239.255.255.255
|
|
*/
|
|
/* multicast addr check */
|
|
sstrncpy (mcast_str, conn_p->conn_addr, MCAST_STRING_LEN);
|
|
|
|
if (conn_p->addrtype == SDP_AT_IP4) {
|
|
errno = 0;
|
|
strtoul_result = strtoul(mcast_str, &strtoul_end, 10);
|
|
|
|
if (errno || mcast_str == strtoul_end || strtoul_result > 255) {
|
|
sdp_parse_error(sdp_p,
|
|
"%s Error parsing address %s for mcast.",
|
|
sdp_p->debug_str, mcast_str);
|
|
sdp_p->conf_p->num_invalid_param++;
|
|
return SDP_INVALID_PARAMETER;
|
|
}
|
|
|
|
|
|
mcast_bits = (int) strtoul_result;
|
|
if ((mcast_bits >= SDP_MIN_MCAST_ADDR_HI_BIT_VAL ) &&
|
|
(mcast_bits <= SDP_MAX_MCAST_ADDR_HI_BIT_VAL)) {
|
|
SDP_PRINT("%s Parsed to be a multicast address with mcast bits %d",
|
|
sdp_p->debug_str, mcast_bits);
|
|
conn_p->is_multicast = TRUE;
|
|
}
|
|
}
|
|
|
|
if (conn_p->addrtype != SDP_AT_EPN) {
|
|
slash_ptr = sdp_findchar(conn_p->conn_addr, "/");
|
|
if (slash_ptr[0] != '\0') {
|
|
/* this used to rely on the above busted multicast check */
|
|
SDP_PRINT("%s An address with slash %s",
|
|
sdp_p->debug_str, conn_p->conn_addr);
|
|
conn_p->conn_addr[slash_ptr - conn_p->conn_addr] = '\0';
|
|
slash_ptr++;
|
|
slash_ptr = sdp_getnextstrtok(slash_ptr, tmp, sizeof(tmp),
|
|
"/", &result);
|
|
if (result != SDP_SUCCESS) {
|
|
sdp_parse_error(sdp_p,
|
|
"%s No ttl value specified for this multicast addr with a slash",
|
|
sdp_p->debug_str);
|
|
sdp_p->conf_p->num_invalid_param++;
|
|
return (SDP_INVALID_PARAMETER);
|
|
}
|
|
|
|
errno = 0;
|
|
strtoul_result = strtoul(tmp, &strtoul_end, 10);
|
|
|
|
if (errno || tmp == strtoul_end || conn_p->ttl > SDP_MAX_TTL_VALUE) {
|
|
sdp_parse_error(sdp_p,
|
|
"%s Invalid TTL: Value must be in the range 0-255 ",
|
|
sdp_p->debug_str);
|
|
sdp_p->conf_p->num_invalid_param++;
|
|
return (SDP_INVALID_PARAMETER);
|
|
}
|
|
|
|
conn_p->ttl = (int) strtoul_result;
|
|
|
|
/* search for num of addresses */
|
|
/*sa_ignore NO_NULL_CHK
|
|
{ptr is valid since the pointer was checked earlier and the
|
|
function would have exited if NULL.}*/
|
|
slash_ptr = sdp_findchar(slash_ptr, "/");
|
|
if (slash_ptr != NULL &&
|
|
slash_ptr[0] != '\0') {
|
|
SDP_PRINT("%s Found a num addr field for multicast addr %s ",
|
|
sdp_p->debug_str,slash_ptr);
|
|
slash_ptr++;
|
|
|
|
errno = 0;
|
|
strtoul_result = strtoul(slash_ptr, &strtoul_end, 10);
|
|
|
|
if (errno || slash_ptr == strtoul_end || strtoul_result == 0) {
|
|
sdp_parse_error(sdp_p,
|
|
"%s Invalid Num of addresses: Value must be > 0 ",
|
|
sdp_p->debug_str);
|
|
sdp_p->conf_p->num_invalid_param++;
|
|
return SDP_INVALID_PARAMETER;
|
|
}
|
|
|
|
conn_p->num_of_addresses = (int) strtoul_result;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* See if the address is the choose param and if it's allowed. */
|
|
if ((sdp_p->conf_p->allow_choose[SDP_CHOOSE_CONN_ADDR] == FALSE) &&
|
|
(strcmp(conn_p->conn_addr, "$") == 0)) {
|
|
sdp_parse_error(sdp_p,
|
|
"%s Warning: Choose parameter for connection "
|
|
"address specified but not allowed.", sdp_p->debug_str);
|
|
}
|
|
|
|
if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
|
|
SDP_PRINT("%s Parse connection: network %s, address type %s, "
|
|
"address %s ttl= %u num of addresses = %u",
|
|
sdp_p->debug_str,
|
|
sdp_get_network_name(conn_p->nettype),
|
|
sdp_get_address_name(conn_p->addrtype),
|
|
conn_p->conn_addr, (unsigned)conn_p->ttl, (unsigned)conn_p->num_of_addresses);
|
|
}
|
|
return (SDP_SUCCESS);
|
|
}
|
|
|
|
sdp_result_e sdp_build_connection (sdp_t *sdp_p, uint16_t level, flex_string *fs)
|
|
{
|
|
sdp_mca_t *mca_p;
|
|
sdp_conn_t *conn_p;
|
|
|
|
if (level == SDP_SESSION_LEVEL) {
|
|
conn_p = &(sdp_p->default_conn);
|
|
} else {
|
|
mca_p = sdp_find_media_level(sdp_p, level);
|
|
if (mca_p == NULL) {
|
|
return (SDP_FAILURE);
|
|
}
|
|
conn_p = &(mca_p->conn);
|
|
}
|
|
|
|
if((conn_p->nettype == SDP_NT_ATM ) &&
|
|
(conn_p->addrtype == SDP_AT_INVALID)) {
|
|
/*allow c= line to be built without address type and address fields
|
|
* This is a special case for ATM PVC*/
|
|
flex_string_sprintf(fs, "c=%s\r\n",
|
|
sdp_get_network_name(conn_p->nettype));
|
|
return SDP_SUCCESS;
|
|
}
|
|
if ((conn_p->nettype >= SDP_MAX_NETWORK_TYPES) ||
|
|
(conn_p->addrtype >= SDP_MAX_ADDR_TYPES) ||
|
|
(conn_p->conn_addr[0] == '\0')) {
|
|
/* Connection info isn't set - don't need to build the token. */
|
|
return (SDP_SUCCESS);
|
|
}
|
|
|
|
if (conn_p->is_multicast) {
|
|
if (conn_p->num_of_addresses > 1) {
|
|
flex_string_sprintf(fs, "c=%s %s %s/%u/%u\r\n",
|
|
sdp_get_network_name(conn_p->nettype),
|
|
sdp_get_address_name(conn_p->addrtype),
|
|
conn_p->conn_addr,
|
|
(unsigned)conn_p->ttl,
|
|
(unsigned)conn_p->num_of_addresses);
|
|
} else {
|
|
flex_string_sprintf(fs, "c=%s %s %s/%u\r\n",
|
|
sdp_get_network_name(conn_p->nettype),
|
|
sdp_get_address_name(conn_p->addrtype),
|
|
conn_p->conn_addr,
|
|
(unsigned)conn_p->ttl);
|
|
}
|
|
} else {
|
|
|
|
flex_string_sprintf(fs, "c=%s %s %s\r\n",
|
|
sdp_get_network_name(conn_p->nettype),
|
|
sdp_get_address_name(conn_p->addrtype),
|
|
conn_p->conn_addr);
|
|
}
|
|
|
|
if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
|
|
SDP_PRINT("%s Built c= connection line", sdp_p->debug_str);
|
|
}
|
|
return (SDP_SUCCESS);
|
|
}
|
|
|
|
/*
|
|
* sdp_parse_bandwidth
|
|
*
|
|
* This function parses a bandwidth field. The parsing is done in accordance
|
|
* to the following ABNF:
|
|
*
|
|
* bandwidth-fields = *("b=" bwtype ":" bandwidth CRLF)
|
|
* bwtype = 1*(alpha-numeric)
|
|
* bandwidth = 1*(DIGIT)
|
|
*
|
|
* It currently supports three types of valid bwtypes - AS, CT and TIAS
|
|
*/
|
|
sdp_result_e sdp_parse_bandwidth (sdp_t *sdp_p, uint16_t level, const char *ptr)
|
|
{
|
|
int i;
|
|
sdp_mca_t *mca_p;
|
|
sdp_bw_t *bw_p;
|
|
sdp_bw_data_t *bw_data_p;
|
|
sdp_bw_data_t *new_bw_data_p;
|
|
sdp_result_e result;
|
|
char tmp[SDP_MAX_STRING_LEN];
|
|
sdp_bw_modifier_e bw_modifier = SDP_BW_MODIFIER_UNSUPPORTED;
|
|
int bw_val = 0;
|
|
|
|
if (level == SDP_SESSION_LEVEL) {
|
|
bw_p = &(sdp_p->bw);
|
|
} else {
|
|
mca_p = sdp_find_media_level(sdp_p, level);
|
|
if (mca_p == NULL) {
|
|
return (SDP_FAILURE);
|
|
}
|
|
bw_p = &(mca_p->bw);
|
|
}
|
|
|
|
if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
|
|
SDP_PRINT("%s Parse bandwidth line", sdp_p->debug_str);
|
|
}
|
|
|
|
/* Find the bw type (AS, CT or TIAS) */
|
|
ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), ":", &result);
|
|
if (result != SDP_SUCCESS) {
|
|
sdp_parse_error(sdp_p,
|
|
"%s No bandwidth type specified for b= ",
|
|
sdp_p->debug_str);
|
|
sdp_p->conf_p->num_invalid_param++;
|
|
return (SDP_INVALID_PARAMETER);
|
|
}
|
|
for (i=0; i < SDP_MAX_BW_MODIFIER_VAL; i++) {
|
|
if (cpr_strncasecmp(tmp, sdp_bw_modifier_val[i].name,
|
|
sdp_bw_modifier_val[i].strlen) == 0) {
|
|
bw_modifier = (sdp_bw_modifier_e)i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (bw_modifier == SDP_BW_MODIFIER_UNSUPPORTED) {
|
|
/* We don't understand this parameter, so according to RFC4566 sec 5.8
|
|
* ignore it. */
|
|
return (SDP_SUCCESS);
|
|
}
|
|
|
|
/* Find the BW type value */
|
|
/*sa_ignore NO_NULL_CHK
|
|
{ptr is valid since the pointer was checked earlier and the
|
|
function would have exited if NULL.}*/
|
|
if (*ptr == ':') {
|
|
ptr++;
|
|
bw_val = sdp_getnextnumtok(ptr, &ptr, " \t", &result);
|
|
if ((result != SDP_SUCCESS)) {
|
|
sdp_parse_error(sdp_p,
|
|
"%s Error: No BW Value specified ",
|
|
sdp_p->debug_str);
|
|
sdp_p->conf_p->num_invalid_param++;
|
|
return (SDP_INVALID_PARAMETER);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Allocate a new sdp_bw_data_t instance and set it's values from the
|
|
* input parameters.
|
|
*/
|
|
new_bw_data_p = (sdp_bw_data_t*)SDP_MALLOC(sizeof(sdp_bw_data_t));
|
|
if (new_bw_data_p == NULL) {
|
|
sdp_p->conf_p->num_invalid_param++;
|
|
return (SDP_NO_RESOURCE);
|
|
}
|
|
new_bw_data_p->next_p = NULL;
|
|
new_bw_data_p->bw_modifier = bw_modifier;
|
|
new_bw_data_p->bw_val = bw_val;
|
|
|
|
/*
|
|
* Enqueue the sdp_bw_data_t instance at the end of the list of
|
|
* sdp_bw_data_t instances.
|
|
*/
|
|
if (bw_p->bw_data_list == NULL) {
|
|
bw_p->bw_data_list = new_bw_data_p;
|
|
} else {
|
|
for (bw_data_p = bw_p->bw_data_list;
|
|
bw_data_p->next_p != NULL;
|
|
bw_data_p = bw_data_p->next_p) {
|
|
; // Empty For
|
|
}
|
|
bw_data_p->next_p = new_bw_data_p;
|
|
}
|
|
bw_p->bw_data_count++;
|
|
|
|
if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
|
|
SDP_PRINT("%s Parsed bw type %s, value %d", sdp_p->debug_str,
|
|
sdp_get_bw_modifier_name(new_bw_data_p->bw_modifier),
|
|
new_bw_data_p->bw_val);
|
|
}
|
|
|
|
return (SDP_SUCCESS);
|
|
}
|
|
|
|
/*
|
|
* sdp_build_bandwidth
|
|
*
|
|
* Builds *all* the bandwith lines for the specified level.
|
|
*/
|
|
sdp_result_e sdp_build_bandwidth (sdp_t *sdp_p, uint16_t level, flex_string *fs)
|
|
{
|
|
sdp_bw_t *bw_p;
|
|
sdp_bw_data_t *bw_data_p;
|
|
sdp_mca_t *mca_p;
|
|
|
|
if (level == SDP_SESSION_LEVEL) {
|
|
bw_p = &(sdp_p->bw);
|
|
} else {
|
|
mca_p = sdp_find_media_level(sdp_p, level);
|
|
if (mca_p == NULL) {
|
|
return (SDP_FAILURE);
|
|
}
|
|
bw_p = &(mca_p->bw);
|
|
}
|
|
|
|
bw_data_p = bw_p->bw_data_list;
|
|
while (bw_data_p) {
|
|
flex_string_sprintf(fs, "b=%s:%d\r\n",
|
|
sdp_get_bw_modifier_name(bw_data_p->bw_modifier),
|
|
bw_data_p->bw_val);
|
|
|
|
if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
|
|
SDP_PRINT("%s Built b=%s:%d bandwidth line", sdp_p->debug_str,
|
|
sdp_get_bw_modifier_name(bw_data_p->bw_modifier),
|
|
bw_data_p->bw_val);
|
|
}
|
|
|
|
bw_data_p = bw_data_p->next_p;
|
|
}
|
|
|
|
return (SDP_SUCCESS);
|
|
}
|
|
|
|
sdp_result_e sdp_parse_timespec (sdp_t *sdp_p, uint16_t level, const char *ptr)
|
|
{
|
|
char *tmpptr;
|
|
sdp_result_e result;
|
|
sdp_timespec_t *timespec_p;
|
|
sdp_timespec_t *next_timespec_p;
|
|
|
|
timespec_p = (sdp_timespec_t *)SDP_MALLOC(sizeof(sdp_timespec_t));
|
|
if (timespec_p == NULL) {
|
|
sdp_p->conf_p->num_no_resource++;
|
|
return (SDP_NO_RESOURCE);
|
|
}
|
|
|
|
/* Validate start and stop times. */
|
|
ptr = sdp_getnextstrtok(ptr, timespec_p->start_time, sizeof(timespec_p->start_time), " \t", &result);
|
|
if (result == SDP_SUCCESS) {
|
|
/* Make sure the start_time is numeric, even though we store it as
|
|
* a string.
|
|
*/
|
|
(void)sdp_getnextnumtok(timespec_p->start_time,
|
|
(const char **)&tmpptr, " \t", &result);
|
|
}
|
|
if (result != SDP_SUCCESS) {
|
|
sdp_parse_error(sdp_p,
|
|
"%s Invalid timespec start time specified.",
|
|
sdp_p->debug_str);
|
|
sdp_p->conf_p->num_invalid_param++;
|
|
SDP_FREE(timespec_p);
|
|
return (SDP_INVALID_PARAMETER);
|
|
}
|
|
|
|
ptr = sdp_getnextstrtok(ptr, timespec_p->stop_time, sizeof(timespec_p->stop_time), " \t", &result);
|
|
if (result == SDP_SUCCESS) {
|
|
/* Make sure the start_time is numeric, even though we store it as
|
|
* a string.
|
|
*/
|
|
(void)sdp_getnextnumtok(timespec_p->stop_time,
|
|
(const char **)&tmpptr, " \t", &result);
|
|
}
|
|
if (result != SDP_SUCCESS) {
|
|
sdp_parse_error(sdp_p,
|
|
"%s Invalid timespec stop time specified.",
|
|
sdp_p->debug_str);
|
|
sdp_p->conf_p->num_invalid_param++;
|
|
SDP_FREE(timespec_p);
|
|
return (SDP_INVALID_PARAMETER);
|
|
}
|
|
|
|
/* Link the new timespec in to the end of the list. */
|
|
if (sdp_p->timespec_p == NULL) {
|
|
sdp_p->timespec_p = timespec_p;
|
|
} else {
|
|
next_timespec_p = sdp_p->timespec_p;
|
|
while (next_timespec_p->next_p != NULL) {
|
|
next_timespec_p = next_timespec_p->next_p;
|
|
}
|
|
next_timespec_p->next_p = timespec_p;
|
|
}
|
|
|
|
if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
|
|
SDP_PRINT("%s Parsed timespec line", sdp_p->debug_str);
|
|
}
|
|
return (SDP_SUCCESS);
|
|
}
|
|
|
|
sdp_result_e sdp_build_timespec (sdp_t *sdp_p, uint16_t level, flex_string *fs)
|
|
{
|
|
if ((sdp_p->timespec_p == NULL) ||
|
|
(sdp_p->timespec_p->start_time[0] == '\0') ||
|
|
(sdp_p->timespec_p->stop_time[0] == '\0')) {
|
|
if (sdp_p->conf_p->timespec_reqd == TRUE) {
|
|
SDPLogError(logTag, "%s Invalid params for t= time spec line, "
|
|
"build failed.", sdp_p->debug_str);
|
|
sdp_p->conf_p->num_invalid_param++;
|
|
return (SDP_INVALID_PARAMETER);
|
|
} else {
|
|
/* t= line not required. */
|
|
return (SDP_SUCCESS);
|
|
}
|
|
}
|
|
|
|
/* Note: We only support one t= line currently. */
|
|
flex_string_sprintf(fs, "t=%s %s\r\n", sdp_p->timespec_p->start_time,
|
|
sdp_p->timespec_p->stop_time);
|
|
|
|
if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
|
|
SDP_PRINT("%s Built t= timespec line", sdp_p->debug_str);
|
|
}
|
|
return (SDP_SUCCESS);
|
|
}
|
|
|
|
sdp_result_e sdp_parse_repeat_time (sdp_t *sdp_p, uint16_t level, const char *ptr)
|
|
{
|
|
char *endptr;
|
|
|
|
endptr = sdp_findchar(ptr, "\n");
|
|
if (ptr == endptr) {
|
|
sdp_parse_error(sdp_p,
|
|
"%s Warning: No repeat time parameters "
|
|
"specified.", sdp_p->debug_str);
|
|
}
|
|
|
|
if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
|
|
SDP_PRINT("%s Parsed repeat time line", sdp_p->debug_str);
|
|
}
|
|
return (SDP_SUCCESS);
|
|
}
|
|
|
|
sdp_result_e sdp_build_repeat_time (sdp_t *sdp_p, uint16_t level, flex_string *fs)
|
|
{
|
|
/* Build repeat time line not supported. */
|
|
return (SDP_SUCCESS);
|
|
}
|
|
|
|
sdp_result_e sdp_parse_timezone_adj (sdp_t *sdp_p, uint16_t level, const char *ptr)
|
|
{
|
|
char *endptr;
|
|
|
|
endptr = sdp_findchar(ptr, "\n");
|
|
if (ptr == endptr) {
|
|
sdp_parse_error(sdp_p,
|
|
"%s Warning: No timezone parameters specified.",
|
|
sdp_p->debug_str);
|
|
}
|
|
|
|
if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
|
|
SDP_PRINT("%s Parse timezone adustment line", sdp_p->debug_str);
|
|
}
|
|
return (SDP_SUCCESS);
|
|
}
|
|
|
|
sdp_result_e sdp_build_timezone_adj (sdp_t *sdp_p, uint16_t level, flex_string *fs)
|
|
{
|
|
/* Build timezone adjustment line not supported. */
|
|
return (SDP_SUCCESS);
|
|
}
|
|
|
|
sdp_result_e sdp_parse_encryption (sdp_t *sdp_p, uint16_t level, const char *ptr)
|
|
{
|
|
int i;
|
|
sdp_result_e result;
|
|
sdp_encryptspec_t *encrypt_p;
|
|
sdp_mca_t *mca_p;
|
|
char tmp[SDP_MAX_STRING_LEN];
|
|
|
|
if (level == SDP_SESSION_LEVEL) {
|
|
encrypt_p = &(sdp_p->encrypt);
|
|
} else {
|
|
mca_p = sdp_find_media_level(sdp_p, level);
|
|
if (mca_p == NULL) {
|
|
return (SDP_FAILURE);
|
|
}
|
|
encrypt_p = &(mca_p->encrypt);
|
|
}
|
|
encrypt_p->encrypt_key[0] = '\0';
|
|
|
|
/* Find the encryption type. */
|
|
ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), ":", &result);
|
|
if (result != SDP_SUCCESS) {
|
|
sdp_parse_error(sdp_p,
|
|
"%s No encryption type specified for k=.",
|
|
sdp_p->debug_str);
|
|
sdp_p->conf_p->num_invalid_param++;
|
|
return (SDP_INVALID_PARAMETER);
|
|
}
|
|
encrypt_p->encrypt_type = SDP_ENCRYPT_UNSUPPORTED;
|
|
for (i=0; i < SDP_MAX_ENCRYPT_TYPES; i++) {
|
|
if (cpr_strncasecmp(tmp, sdp_encrypt[i].name,
|
|
sdp_encrypt[i].strlen) == 0) {
|
|
encrypt_p->encrypt_type = (sdp_encrypt_type_e)i;
|
|
break;
|
|
}
|
|
}
|
|
if (encrypt_p->encrypt_type == SDP_ENCRYPT_UNSUPPORTED) {
|
|
sdp_parse_error(sdp_p,
|
|
"%s Warning: Encryption type unsupported (%s).",
|
|
sdp_p->debug_str, tmp);
|
|
}
|
|
|
|
/* Find the encryption key. */
|
|
encrypt_p->encrypt_key[0] = '\0';
|
|
/*sa_ignore NO_NULL_CHK
|
|
{ptr is valid since the pointer was checked earlier and the
|
|
function would have exited if NULL.}*/
|
|
if (*ptr == ':')
|
|
ptr++;
|
|
if (encrypt_p->encrypt_type != SDP_ENCRYPT_PROMPT) {
|
|
ptr = sdp_getnextstrtok(ptr, encrypt_p->encrypt_key, sizeof(encrypt_p->encrypt_key), " \t", &result);
|
|
if ((result != SDP_SUCCESS) &&
|
|
((encrypt_p->encrypt_type == SDP_ENCRYPT_CLEAR) ||
|
|
(encrypt_p->encrypt_type == SDP_ENCRYPT_BASE64) ||
|
|
(encrypt_p->encrypt_type == SDP_ENCRYPT_URI))) {
|
|
sdp_parse_error(sdp_p,
|
|
"%s Warning: No encryption key specified "
|
|
"as required.", sdp_p->debug_str);
|
|
sdp_p->conf_p->num_invalid_param++;
|
|
return (SDP_INVALID_PARAMETER);
|
|
}
|
|
}
|
|
|
|
if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
|
|
SDP_PRINT("%s Parse encryption type %s, key %s", sdp_p->debug_str,
|
|
sdp_get_encrypt_name(encrypt_p->encrypt_type),
|
|
encrypt_p->encrypt_key);
|
|
}
|
|
return (SDP_SUCCESS);
|
|
}
|
|
|
|
/* If the encryption info is valid, we build it. Else skip it. */
|
|
sdp_result_e sdp_build_encryption (sdp_t *sdp_p, uint16_t level, flex_string *fs)
|
|
{
|
|
sdp_encryptspec_t *encrypt_p;
|
|
sdp_mca_t *mca_p;
|
|
|
|
if (level == SDP_SESSION_LEVEL) {
|
|
encrypt_p = &(sdp_p->encrypt);
|
|
} else {
|
|
mca_p = sdp_find_media_level(sdp_p, level);
|
|
if (mca_p == NULL) {
|
|
return (SDP_FAILURE);
|
|
}
|
|
encrypt_p = &(mca_p->encrypt);
|
|
}
|
|
|
|
if ((encrypt_p->encrypt_type >= SDP_MAX_ENCRYPT_TYPES) ||
|
|
((encrypt_p->encrypt_type != SDP_ENCRYPT_PROMPT) &&
|
|
(encrypt_p->encrypt_key[0] == '\0'))) {
|
|
/* Encryption info isn't set - don't need to build the token. */
|
|
return (SDP_SUCCESS);
|
|
}
|
|
|
|
flex_string_sprintf(fs, "k=%s",
|
|
sdp_get_encrypt_name(encrypt_p->encrypt_type));
|
|
|
|
if (encrypt_p->encrypt_type == SDP_ENCRYPT_PROMPT) {
|
|
/* There is no key to print. */
|
|
flex_string_sprintf(fs, "\r\n");
|
|
} else {
|
|
flex_string_sprintf(fs, ":%s\r\n", encrypt_p->encrypt_key);
|
|
}
|
|
|
|
if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
|
|
SDP_PRINT("%s Built k= encryption line", sdp_p->debug_str);
|
|
}
|
|
return (SDP_SUCCESS);
|
|
}
|
|
|
|
sdp_result_e sdp_parse_media (sdp_t *sdp_p, uint16_t level, const char *ptr)
|
|
{
|
|
uint16_t i;
|
|
uint16_t num_port_params=0;
|
|
int32_t num[SDP_MAX_PORT_PARAMS];
|
|
tinybool valid_param = FALSE;
|
|
sdp_result_e result;
|
|
sdp_mca_t *mca_p;
|
|
sdp_mca_t *next_mca_p;
|
|
char tmp[SDP_MAX_STRING_LEN];
|
|
char port[SDP_MAX_STRING_LEN];
|
|
const char *port_ptr;
|
|
int32_t sctp_port;
|
|
|
|
/* Allocate resource for new media stream. */
|
|
mca_p = sdp_alloc_mca(sdp_p->parse_line);
|
|
if (mca_p == NULL) {
|
|
sdp_p->conf_p->num_no_resource++;
|
|
return (SDP_NO_RESOURCE);
|
|
}
|
|
|
|
/* Find the media type. */
|
|
ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
|
|
if (result != SDP_SUCCESS) {
|
|
sdp_parse_error(sdp_p,
|
|
"%s No media type specified, parse failed.",
|
|
sdp_p->debug_str);
|
|
SDP_FREE(mca_p);
|
|
sdp_p->conf_p->num_invalid_param++;
|
|
return (SDP_INVALID_PARAMETER);
|
|
}
|
|
mca_p->media = SDP_MEDIA_UNSUPPORTED;
|
|
for (i=0; i < SDP_MAX_MEDIA_TYPES; i++) {
|
|
if (cpr_strncasecmp(tmp, sdp_media[i].name,
|
|
sdp_media[i].strlen) == 0) {
|
|
mca_p->media = (sdp_media_e)i;
|
|
}
|
|
}
|
|
if (mca_p->media == SDP_MEDIA_UNSUPPORTED) {
|
|
sdp_parse_error(sdp_p,
|
|
"%s Warning: Media type unsupported (%s).",
|
|
sdp_p->debug_str, tmp);
|
|
}
|
|
|
|
/* Find the port token parameters, but don't process it until
|
|
* we determine the transport protocol as that determines what
|
|
* port number formats are valid.
|
|
*/
|
|
ptr = sdp_getnextstrtok(ptr, port, sizeof(port), " \t", &result);
|
|
if (result != SDP_SUCCESS) {
|
|
sdp_parse_error(sdp_p,
|
|
"%s No port specified in m= media line, "
|
|
"parse failed.", sdp_p->debug_str);
|
|
SDP_FREE(mca_p);
|
|
sdp_p->conf_p->num_invalid_param++;
|
|
return (SDP_INVALID_PARAMETER);
|
|
}
|
|
port_ptr = port;
|
|
for (i=0; i < SDP_MAX_PORT_PARAMS; i++) {
|
|
num[i] = sdp_getnextnumtok(port_ptr, (const char **)&port_ptr,
|
|
"/ \t", &result);
|
|
if (result != SDP_SUCCESS) {
|
|
break;
|
|
}
|
|
num_port_params++;
|
|
}
|
|
|
|
/* Find the transport protocol type. */
|
|
ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
|
|
if (result != SDP_SUCCESS) {
|
|
sdp_parse_error(sdp_p,
|
|
"%s No transport protocol type specified, "
|
|
"parse failed.", sdp_p->debug_str);
|
|
SDP_FREE(mca_p);
|
|
sdp_p->conf_p->num_invalid_param++;
|
|
return (SDP_INVALID_PARAMETER);
|
|
}
|
|
mca_p->transport = SDP_TRANSPORT_UNSUPPORTED;
|
|
for (i=0; i < SDP_MAX_TRANSPORT_TYPES; i++) {
|
|
if (cpr_strncasecmp(tmp, sdp_transport[i].name,
|
|
sdp_transport[i].strlen) == 0) {
|
|
mca_p->transport = (sdp_transport_e)i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (mca_p->transport == SDP_TRANSPORT_UNSUPPORTED) {
|
|
/* If we don't recognize or don't support the transport type,
|
|
* just store the first num as the port.
|
|
*/
|
|
mca_p->port = num[0];
|
|
sdp_parse_error(sdp_p,
|
|
"%s Warning: Transport protocol type unsupported "
|
|
"(%s).", sdp_p->debug_str, tmp);
|
|
}
|
|
|
|
/* Check for each of the possible port formats according to the
|
|
* type of transport protocol specified.
|
|
*/
|
|
valid_param = FALSE;
|
|
switch (num_port_params) {
|
|
case 1:
|
|
if ((mca_p->transport == SDP_TRANSPORT_RTPAVP) ||
|
|
(mca_p->transport == SDP_TRANSPORT_RTPSAVP) ||
|
|
(mca_p->transport == SDP_TRANSPORT_RTPSAVPF) ||
|
|
(mca_p->transport == SDP_TRANSPORT_UDPTLSRTPSAVP) ||
|
|
(mca_p->transport == SDP_TRANSPORT_UDPTLSRTPSAVPF) ||
|
|
(mca_p->transport == SDP_TRANSPORT_TCPDTLSRTPSAVP) ||
|
|
(mca_p->transport == SDP_TRANSPORT_TCPDTLSRTPSAVPF) ||
|
|
(mca_p->transport == SDP_TRANSPORT_UDP) ||
|
|
(mca_p->transport == SDP_TRANSPORT_TCP) ||
|
|
(mca_p->transport == SDP_TRANSPORT_UDPTL) ||
|
|
(mca_p->transport == SDP_TRANSPORT_UDPSPRT) ||
|
|
(mca_p->transport == SDP_TRANSPORT_LOCAL) ||
|
|
(mca_p->transport == SDP_TRANSPORT_DTLSSCTP) ||
|
|
(mca_p->transport == SDP_TRANSPORT_UDPDTLSSCTP) ||
|
|
(mca_p->transport == SDP_TRANSPORT_TCPDTLSSCTP)) {
|
|
/* Port format is simply <port>. Make sure that either
|
|
* the choose param is allowed or that the choose value
|
|
* wasn't specified.
|
|
*/
|
|
if ((sdp_p->conf_p->allow_choose[SDP_CHOOSE_PORTNUM]) ||
|
|
(num[0] != SDP_CHOOSE_PARAM)) {
|
|
mca_p->port = num[0];
|
|
mca_p->port_format = SDP_PORT_NUM_ONLY;
|
|
valid_param = TRUE;
|
|
}
|
|
} else if (mca_p->transport == SDP_TRANSPORT_AAL1AVP) {
|
|
/* Port format is simply <vcci>, choose param is not allowed.
|
|
*/
|
|
if (num[0] != SDP_CHOOSE_PARAM) {
|
|
mca_p->vcci = num[0];
|
|
mca_p->port_format = SDP_PORT_VCCI;
|
|
valid_param = TRUE;
|
|
}
|
|
} else if ((mca_p->transport == SDP_TRANSPORT_AAL2_ITU) ||
|
|
(mca_p->transport == SDP_TRANSPORT_AAL2_ATMF) ||
|
|
(mca_p->transport == SDP_TRANSPORT_AAL2_CUSTOM)) {
|
|
/* Port format is simply <port>, and choose param is allowed,
|
|
* according to AAL2 definitions.
|
|
*/
|
|
mca_p->port = num[0];
|
|
mca_p->port_format = SDP_PORT_NUM_ONLY;
|
|
valid_param = TRUE;
|
|
}
|
|
break;
|
|
case 2:
|
|
if ((mca_p->transport == SDP_TRANSPORT_RTPAVP) ||
|
|
(mca_p->transport == SDP_TRANSPORT_RTPSAVP) ||
|
|
(mca_p->transport == SDP_TRANSPORT_RTPSAVPF) ||
|
|
(mca_p->transport == SDP_TRANSPORT_UDPTLSRTPSAVP) ||
|
|
(mca_p->transport == SDP_TRANSPORT_UDPTLSRTPSAVPF) ||
|
|
(mca_p->transport == SDP_TRANSPORT_TCPDTLSRTPSAVP) ||
|
|
(mca_p->transport == SDP_TRANSPORT_TCPDTLSRTPSAVPF) ||
|
|
(mca_p->transport == SDP_TRANSPORT_UDP) ||
|
|
(mca_p->transport == SDP_TRANSPORT_LOCAL)) {
|
|
/* Port format is <port>/<num of ports>. Make sure choose
|
|
* params were not specified.
|
|
*/
|
|
if ((num[0] != SDP_CHOOSE_PARAM) &&
|
|
(num[1] != SDP_CHOOSE_PARAM)) {
|
|
mca_p->port = num[0];
|
|
mca_p->num_ports = num[1];
|
|
mca_p->port_format = SDP_PORT_NUM_COUNT;
|
|
valid_param = TRUE;
|
|
}
|
|
} else if (mca_p->transport == SDP_TRANSPORT_UDPTL) {
|
|
/* Port format is <port>/<num of ports>. Make sure choose
|
|
* params were not specified. For UDPTL, only "1" may
|
|
* be specified for number of ports.
|
|
*/
|
|
if ((num[0] != SDP_CHOOSE_PARAM) &&
|
|
(num[1] == 1)) {
|
|
mca_p->port = num[0];
|
|
mca_p->num_ports = 1;
|
|
mca_p->port_format = SDP_PORT_NUM_COUNT;
|
|
valid_param = TRUE;
|
|
}
|
|
} else if (mca_p->transport == SDP_TRANSPORT_CES10) {
|
|
/* Port format is <vpi>/<vci>. Make sure choose
|
|
* params were not specified.
|
|
*/
|
|
if ((num[0] != SDP_CHOOSE_PARAM) &&
|
|
(num[1] != SDP_CHOOSE_PARAM)) {
|
|
mca_p->vpi = num[0];
|
|
mca_p->vci = num[1];
|
|
mca_p->port_format = SDP_PORT_VPI_VCI;
|
|
valid_param = TRUE;
|
|
}
|
|
} else if ((mca_p->transport == SDP_TRANSPORT_AAL2_ITU) ||
|
|
(mca_p->transport == SDP_TRANSPORT_AAL2_ATMF) ||
|
|
(mca_p->transport == SDP_TRANSPORT_AAL2_CUSTOM)) {
|
|
/* Port format is either <vcci>/<cid> or $/$. If one
|
|
* param is '$' the other must be also. The choose params
|
|
* are allowed by default and don't need to be allowed
|
|
* through the appl config.
|
|
*/
|
|
if (((num[0] != SDP_CHOOSE_PARAM) &&
|
|
(num[1] != SDP_CHOOSE_PARAM)) ||
|
|
((num[0] == SDP_CHOOSE_PARAM) &&
|
|
(num[1] == SDP_CHOOSE_PARAM))) {
|
|
mca_p->vcci = num[0];
|
|
mca_p->cid = num[1];
|
|
mca_p->port_format = SDP_PORT_VCCI_CID;
|
|
valid_param = TRUE;
|
|
}
|
|
}
|
|
break;
|
|
case 3:
|
|
if (mca_p->transport == SDP_TRANSPORT_AAL1AVP) {
|
|
/* Port format is <port>/<vpi>/<vci>. Make sure choose
|
|
* params were not specified.
|
|
*/
|
|
if ((num[0] != SDP_CHOOSE_PARAM) &&
|
|
(num[1] != SDP_CHOOSE_PARAM) &&
|
|
(num[2] != SDP_CHOOSE_PARAM)) {
|
|
mca_p->port = num[0];
|
|
mca_p->vpi = num[1];
|
|
mca_p->vci = num[2];
|
|
mca_p->port_format = SDP_PORT_NUM_VPI_VCI;
|
|
valid_param = TRUE;
|
|
}
|
|
}
|
|
break;
|
|
case 4:
|
|
if ((mca_p->transport == SDP_TRANSPORT_AAL2_ITU) ||
|
|
(mca_p->transport == SDP_TRANSPORT_AAL2_ATMF) ||
|
|
(mca_p->transport == SDP_TRANSPORT_AAL2_CUSTOM)) {
|
|
/* Port format is <port>/<vpi>/<vci>/<cid>. Make sure choose
|
|
* params were not specified.
|
|
*/
|
|
if ((num[0] != SDP_CHOOSE_PARAM) &&
|
|
(num[1] != SDP_CHOOSE_PARAM) &&
|
|
(num[2] != SDP_CHOOSE_PARAM) &&
|
|
(num[3] != SDP_CHOOSE_PARAM)) {
|
|
mca_p->port = num[0];
|
|
mca_p->vpi = num[1];
|
|
mca_p->vci = num[2];
|
|
mca_p->cid = num[3];
|
|
mca_p->port_format = SDP_PORT_NUM_VPI_VCI_CID;
|
|
valid_param = TRUE;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
if (valid_param == FALSE) {
|
|
sdp_parse_error(sdp_p,
|
|
"%s Invalid port format (%s) specified for transport "
|
|
"protocol (%s), parse failed.", sdp_p->debug_str,
|
|
port, sdp_get_transport_name(mca_p->transport));
|
|
sdp_p->conf_p->num_invalid_param++;
|
|
SDP_FREE(mca_p);
|
|
return (SDP_INVALID_PARAMETER);
|
|
}
|
|
|
|
if ((mca_p->transport == SDP_TRANSPORT_DTLSSCTP) ||
|
|
(mca_p->transport == SDP_TRANSPORT_UDPDTLSSCTP) ||
|
|
(mca_p->transport == SDP_TRANSPORT_TCPDTLSSCTP)) {
|
|
ptr = sdp_getnextstrtok(ptr, port, sizeof(port), " \t", &result);
|
|
if (result != SDP_SUCCESS) {
|
|
sdp_parse_error(sdp_p,
|
|
"%s No sctp port specified in m= media line, "
|
|
"parse failed.", sdp_p->debug_str);
|
|
SDP_FREE(mca_p);
|
|
sdp_p->conf_p->num_invalid_param++;
|
|
return (SDP_INVALID_PARAMETER);
|
|
}
|
|
port_ptr = port;
|
|
|
|
if ((mca_p->transport == SDP_TRANSPORT_UDPDTLSSCTP) ||
|
|
(mca_p->transport == SDP_TRANSPORT_TCPDTLSSCTP)) {
|
|
if (cpr_strncasecmp(port_ptr, "webrtc-datachannel",
|
|
sizeof("webrtc-datachannel")) != 0) {
|
|
sdp_parse_error(sdp_p,
|
|
"%s No webrtc-datachannel token in m= media line, "
|
|
"parse failed.", sdp_p->debug_str);
|
|
SDP_FREE(mca_p);
|
|
sdp_p->conf_p->num_invalid_param++;
|
|
return (SDP_INVALID_PARAMETER);
|
|
}
|
|
mca_p->sctp_fmt = SDP_SCTP_MEDIA_FMT_WEBRTC_DATACHANNEL;
|
|
} else {
|
|
sctp_port = sdp_getnextnumtok(port_ptr, (const char **)&port_ptr,
|
|
"/ \t", &result);
|
|
if (result != SDP_SUCCESS) {
|
|
sdp_parse_error(sdp_p,
|
|
"%s No sctp port specified in m= media line, "
|
|
"parse failed.", sdp_p->debug_str);
|
|
SDP_FREE(mca_p);
|
|
sdp_p->conf_p->num_invalid_param++;
|
|
return (SDP_INVALID_PARAMETER);
|
|
}
|
|
mca_p->sctpport = sctp_port;
|
|
}
|
|
} else {
|
|
/* Transport is a non-AAL2 type and not SCTP. Parse payloads
|
|
normally. */
|
|
sdp_parse_payload_types(sdp_p, mca_p, ptr);
|
|
}
|
|
|
|
|
|
/* Media line params are valid. Add it into the SDP. */
|
|
sdp_p->mca_count++;
|
|
if (sdp_p->mca_p == NULL) {
|
|
sdp_p->mca_p = mca_p;
|
|
} else {
|
|
for (next_mca_p = sdp_p->mca_p; next_mca_p->next_p != NULL;
|
|
next_mca_p = next_mca_p->next_p) {
|
|
; // Empty For
|
|
}
|
|
next_mca_p->next_p = mca_p;
|
|
}
|
|
|
|
if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
|
|
|
|
SDP_PRINT("%s Parsed media type %s, ", sdp_p->debug_str,
|
|
sdp_get_media_name(mca_p->media));
|
|
switch (mca_p->port_format) {
|
|
case SDP_PORT_NUM_ONLY:
|
|
SDP_PRINT("Port num %d, ", mca_p->port);
|
|
break;
|
|
|
|
case SDP_PORT_NUM_COUNT:
|
|
SDP_PRINT("Port num %d, count %d, ",
|
|
mca_p->port, mca_p->num_ports);
|
|
break;
|
|
case SDP_PORT_VPI_VCI:
|
|
SDP_PRINT("VPI/VCI %d/%u, ", mca_p->vpi, mca_p->vci);
|
|
break;
|
|
case SDP_PORT_VCCI:
|
|
SDP_PRINT("VCCI %d, ", mca_p->vcci);
|
|
break;
|
|
case SDP_PORT_NUM_VPI_VCI:
|
|
SDP_PRINT("Port %d, VPI/VCI %d/%u, ", mca_p->port,
|
|
mca_p->vpi, mca_p->vci);
|
|
break;
|
|
case SDP_PORT_VCCI_CID:
|
|
SDP_PRINT("VCCI %d, CID %d, ", mca_p->vcci, mca_p->cid);
|
|
break;
|
|
case SDP_PORT_NUM_VPI_VCI_CID:
|
|
SDP_PRINT("Port %d, VPI/VCI %d/%u, CID %d, ", mca_p->port,
|
|
mca_p->vpi, mca_p->vci, mca_p->cid);
|
|
break;
|
|
default:
|
|
SDP_PRINT("Port format not valid, ");
|
|
break;
|
|
}
|
|
|
|
if ((mca_p->transport >= SDP_TRANSPORT_AAL2_ITU) &&
|
|
(mca_p->transport <= SDP_TRANSPORT_AAL2_CUSTOM)) {
|
|
for (i=0; i < mca_p->media_profiles_p->num_profiles; i++) {
|
|
SDP_PRINT("Profile %s, Num payloads %u ",
|
|
sdp_get_transport_name(mca_p->media_profiles_p->profile[i]),
|
|
(unsigned)mca_p->media_profiles_p->num_payloads[i]);
|
|
}
|
|
} else {
|
|
SDP_PRINT("Transport %s, Num payloads %u",
|
|
sdp_get_transport_name(mca_p->transport),
|
|
(unsigned)mca_p->num_payloads);
|
|
}
|
|
}
|
|
return (SDP_SUCCESS);
|
|
}
|
|
|
|
sdp_result_e sdp_build_media (sdp_t *sdp_p, uint16_t level, flex_string *fs)
|
|
{
|
|
int i, j;
|
|
sdp_mca_t *mca_p;
|
|
tinybool invalid_params=FALSE;
|
|
sdp_media_profiles_t *profile_p;
|
|
|
|
/* Find the right media line */
|
|
mca_p = sdp_find_media_level(sdp_p, level);
|
|
if (mca_p == NULL) {
|
|
return (SDP_FAILURE);
|
|
}
|
|
|
|
/* Validate params for this media line */
|
|
if ((mca_p->media >= SDP_MAX_MEDIA_TYPES) ||
|
|
(mca_p->port_format >= SDP_MAX_PORT_FORMAT_TYPES) ||
|
|
(mca_p->transport >= SDP_MAX_TRANSPORT_TYPES)) {
|
|
invalid_params = TRUE;
|
|
}
|
|
|
|
if (invalid_params == TRUE) {
|
|
SDPLogError(logTag, "%s Invalid params for m= media line, "
|
|
"build failed.", sdp_p->debug_str);
|
|
sdp_p->conf_p->num_invalid_param++;
|
|
return (SDP_INVALID_PARAMETER);
|
|
}
|
|
|
|
/* Build the media type */
|
|
flex_string_sprintf(fs, "m=%s ", sdp_get_media_name(mca_p->media));
|
|
|
|
/* Build the port based on the specified port format */
|
|
if (mca_p->port_format == SDP_PORT_NUM_ONLY) {
|
|
if (mca_p->port == SDP_CHOOSE_PARAM) {
|
|
flex_string_sprintf(fs, "$ ");
|
|
} else {
|
|
flex_string_sprintf(fs, "%u ", (unsigned)mca_p->port);
|
|
}
|
|
} else if (mca_p->port_format == SDP_PORT_NUM_COUNT) {
|
|
flex_string_sprintf(fs, "%u/%u ", (unsigned)mca_p->port,
|
|
(unsigned)mca_p->num_ports);
|
|
} else if (mca_p->port_format == SDP_PORT_VPI_VCI) {
|
|
flex_string_sprintf(fs, "%u/%u ",
|
|
(unsigned)mca_p->vpi, (unsigned)mca_p->vci);
|
|
} else if (mca_p->port_format == SDP_PORT_VCCI) {
|
|
flex_string_sprintf(fs, "%u ", (unsigned)mca_p->vcci);
|
|
} else if (mca_p->port_format == SDP_PORT_NUM_VPI_VCI) {
|
|
flex_string_sprintf(fs, "%u/%u/%u ", (unsigned)mca_p->port,
|
|
(unsigned)mca_p->vpi, (unsigned)mca_p->vci);
|
|
} else if (mca_p->port_format == SDP_PORT_VCCI_CID) {
|
|
if ((mca_p->vcci == SDP_CHOOSE_PARAM) &&
|
|
(mca_p->cid == SDP_CHOOSE_PARAM)) {
|
|
flex_string_sprintf(fs, "$/$ ");
|
|
} else if ((mca_p->vcci == SDP_CHOOSE_PARAM) ||
|
|
(mca_p->cid == SDP_CHOOSE_PARAM)) {
|
|
/* If one is set but not the other, this is an error. */
|
|
SDPLogError(logTag, "%s Invalid params for m= port parameter, "
|
|
"build failed.", sdp_p->debug_str);
|
|
sdp_p->conf_p->num_invalid_param++;
|
|
return (SDP_INVALID_PARAMETER);
|
|
} else {
|
|
flex_string_sprintf(fs, "%u/%u ",
|
|
(unsigned)mca_p->vcci, (unsigned)mca_p->cid);
|
|
}
|
|
} else if (mca_p->port_format == SDP_PORT_NUM_VPI_VCI_CID) {
|
|
flex_string_sprintf(fs, "%u/%u/%u/%u ", (unsigned)mca_p->port,
|
|
(unsigned)mca_p->vpi, (unsigned)mca_p->vci, (unsigned)mca_p->cid);
|
|
}
|
|
|
|
/* If the media line has AAL2 profiles, build them differently. */
|
|
if ((mca_p->transport == SDP_TRANSPORT_AAL2_ITU) ||
|
|
(mca_p->transport == SDP_TRANSPORT_AAL2_ATMF) ||
|
|
(mca_p->transport == SDP_TRANSPORT_AAL2_CUSTOM)) {
|
|
profile_p = mca_p->media_profiles_p;
|
|
for (i=0; i < profile_p->num_profiles; i++) {
|
|
flex_string_sprintf(fs, "%s",
|
|
sdp_get_transport_name(profile_p->profile[i]));
|
|
|
|
for (j=0; j < profile_p->num_payloads[i]; j++) {
|
|
flex_string_sprintf(fs, " %u",
|
|
(unsigned)profile_p->payload_type[i][j]);
|
|
}
|
|
flex_string_sprintf(fs, " ");
|
|
}
|
|
flex_string_sprintf(fs, "\n");
|
|
if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
|
|
SDP_PRINT("%s Built m= media line", sdp_p->debug_str);
|
|
}
|
|
return (SDP_SUCCESS);
|
|
}
|
|
|
|
/* Build the transport name */
|
|
flex_string_sprintf(fs, "%s",
|
|
sdp_get_transport_name(mca_p->transport));
|
|
|
|
if(mca_p->transport != SDP_TRANSPORT_DTLSSCTP) {
|
|
|
|
/* Build the format lists */
|
|
for (i=0; i < mca_p->num_payloads; i++) {
|
|
if (mca_p->payload_indicator[i] == SDP_PAYLOAD_ENUM) {
|
|
flex_string_sprintf(fs, " %s",
|
|
sdp_get_payload_name((sdp_payload_e)mca_p->payload_type[i]));
|
|
} else {
|
|
flex_string_sprintf(fs, " %u", (unsigned)mca_p->payload_type[i]);
|
|
}
|
|
}
|
|
} else {
|
|
/* Add port to SDP if transport is DTLS/SCTP */
|
|
flex_string_sprintf(fs, " %u", (unsigned)mca_p->sctpport);
|
|
}
|
|
|
|
flex_string_sprintf(fs, "\r\n");
|
|
|
|
if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
|
|
SDP_PRINT("%s Built m= media line", sdp_p->debug_str);
|
|
}
|
|
return (SDP_SUCCESS);
|
|
}
|
|
|
|
|
|
/* Function: sdp_parse_payload_types
|
|
* Description: Parse a list of payload types. The list may be part of
|
|
* a media line or part of a capability line.
|
|
* Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
|
|
* mca_p The mca structure the payload types should be
|
|
* added to.
|
|
* ptr The pointer to the list of payloads.
|
|
* Returns: Nothing.
|
|
*/
|
|
void sdp_parse_payload_types (sdp_t *sdp_p, sdp_mca_t *mca_p, const char *ptr)
|
|
{
|
|
uint16_t i;
|
|
uint16_t num_payloads;
|
|
sdp_result_e result;
|
|
tinybool valid_payload;
|
|
char tmp[SDP_MAX_STRING_LEN];
|
|
char *tmp2;
|
|
|
|
for (num_payloads = 0; (num_payloads < SDP_MAX_PAYLOAD_TYPES); ) {
|
|
ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
|
|
if (result != SDP_SUCCESS) {
|
|
/* If there are no more payload types, we're finished */
|
|
break;
|
|
}
|
|
mca_p->payload_type[num_payloads] = (uint16_t)sdp_getnextnumtok(tmp,
|
|
(const char **)&tmp2,
|
|
" \t", &result);
|
|
if (result == SDP_SUCCESS) {
|
|
if ((mca_p->media == SDP_MEDIA_IMAGE) &&
|
|
(mca_p->transport == SDP_TRANSPORT_UDPTL)) {
|
|
sdp_parse_error(sdp_p,
|
|
"%s Warning: Numeric payload type not "
|
|
"valid for media %s with transport %s.",
|
|
sdp_p->debug_str,
|
|
sdp_get_media_name(mca_p->media),
|
|
sdp_get_transport_name(mca_p->transport));
|
|
} else {
|
|
mca_p->payload_indicator[num_payloads] = SDP_PAYLOAD_NUMERIC;
|
|
mca_p->num_payloads++;
|
|
num_payloads++;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
valid_payload = FALSE;
|
|
for (i=0; i < SDP_MAX_STRING_PAYLOAD_TYPES; i++) {
|
|
if (cpr_strncasecmp(tmp, sdp_payload[i].name,
|
|
sdp_payload[i].strlen) == 0) {
|
|
valid_payload = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
if (valid_payload == TRUE) {
|
|
/* We recognized the payload type. Make sure it
|
|
* is valid for this media line. */
|
|
valid_payload = FALSE;
|
|
if ((mca_p->media == SDP_MEDIA_IMAGE) &&
|
|
(mca_p->transport == SDP_TRANSPORT_UDPTL) &&
|
|
(i == SDP_PAYLOAD_T38)) {
|
|
valid_payload = TRUE;
|
|
} else if ((mca_p->media == SDP_MEDIA_APPLICATION) &&
|
|
(mca_p->transport == SDP_TRANSPORT_UDP) &&
|
|
(i == SDP_PAYLOAD_XTMR)) {
|
|
valid_payload = TRUE;
|
|
} else if ((mca_p->media == SDP_MEDIA_APPLICATION) &&
|
|
(mca_p->transport == SDP_TRANSPORT_TCP) &&
|
|
(i == SDP_PAYLOAD_T120)) {
|
|
valid_payload = TRUE;
|
|
}
|
|
|
|
if (valid_payload == TRUE) {
|
|
mca_p->payload_indicator[num_payloads] = SDP_PAYLOAD_ENUM;
|
|
mca_p->payload_type[num_payloads] = i;
|
|
mca_p->num_payloads++;
|
|
num_payloads++;
|
|
} else {
|
|
sdp_parse_error(sdp_p,
|
|
"%s Warning: Payload type %s not valid for "
|
|
"media %s with transport %s.",
|
|
sdp_p->debug_str,
|
|
sdp_get_payload_name((sdp_payload_e)i),
|
|
sdp_get_media_name(mca_p->media),
|
|
sdp_get_transport_name(mca_p->transport));
|
|
}
|
|
} else {
|
|
/* Payload type wasn't recognized. */
|
|
sdp_parse_error(sdp_p,
|
|
"%s Warning: Payload type "
|
|
"unsupported (%s).", sdp_p->debug_str, tmp);
|
|
}
|
|
}
|
|
if (mca_p->num_payloads == 0) {
|
|
sdp_parse_error(sdp_p,
|
|
"%s Warning: No payload types specified.",
|
|
sdp_p->debug_str);
|
|
}
|
|
}
|
|
|