/* This Source Code Form is subject to the terms of the Mozilla Public *License,v.2.0.IfacopyoftheMPLwasnotdistributedwiththis
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* If this is an X-cpar or cpar attribute, set the flag. The attribute
* type will be changed by the parse. */ if ((attr_p->type == SDP_ATTR_X_CPAR) ||
(attr_p->type == SDP_ATTR_CPAR)) {
xcpar_flag = TRUE;
}
/* Parse the attribute. */
result = sdp_attr[attr_p->type].parse_func(sdp_p, attr_p, ptr); if (result != SDP_SUCCESS) {
sdp_free_attr(attr_p); /* Return success so the parse won't fail. We don't want to *failonerrorswithattributesbutjustignorethem.
*/ return (SDP_SUCCESS);
}
/* If this was an X-cpar/cpar attribute, it was hooked into the X-cap/cdsc *structure,sowe'refinished.
*/ if (xcpar_flag == TRUE) { return (result);
}
/* Add the attribute in the appropriate place. */ if (level == SDP_SESSION_LEVEL) { for (next_attr_p = sdp_p->sess_attrs_p; next_attr_p != NULL;
prev_attr_p = next_attr_p,
next_attr_p = next_attr_p->next_p) {
; /* Empty for */
} if (prev_attr_p == NULL) {
sdp_p->sess_attrs_p = attr_p;
} else {
prev_attr_p->next_p = attr_p;
}
} else { for (next_attr_p = mca_p->media_attrs_p; next_attr_p != NULL;
prev_attr_p = next_attr_p,
next_attr_p = next_attr_p->next_p) {
; /* Empty for */
} if (prev_attr_p == NULL) {
mca_p->media_attrs_p = attr_p;
} else {
prev_attr_p->next_p = attr_p;
}
}
return (result);
}
/* Build all of the attributes defined for the specified level. */
sdp_result_e sdp_build_attribute (sdp_t *sdp_p, uint16_t level, flex_string *fs)
{
sdp_attr_t *attr_p;
sdp_mca_t *mca_p=NULL;
sdp_result_e result;
if (level == SDP_SESSION_LEVEL) {
attr_p = sdp_p->sess_attrs_p;
} else {
mca_p = sdp_find_media_level(sdp_p, level); if (mca_p == NULL) { return (SDP_FAILURE);
}
attr_p = mca_p->media_attrs_p;
} /* Re-initialize the current capability number for this new level. */
sdp_p->cur_cap_num = 1;
/* Build all of the attributes for this level. Note that if there
* is a problem building an attribute, we don't fail but just ignore it.*/ while (attr_p != NULL) { if (attr_p->type >= SDP_MAX_ATTR_TYPES) { if (sdp_p->debug_flag[SDP_DEBUG_WARNINGS]) {
SDPLogDebug(logTag, "%s Invalid attribute type to build (%u)",
sdp_p->debug_str, (unsigned)attr_p->type);
}
} else {
result = sdp_attr[attr_p->type].build_func(sdp_p, attr_p, fs);
if (result != SDP_SUCCESS) {
SDPLogError(logTag, "%s error building attribute %d", __FUNCTION__, result); return result;
}
if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
SDP_PRINT("%s Built a=%s attribute line", sdp_p->debug_str,
sdp_get_attr_name(attr_p->type));
}
}
attr_p = attr_p->next_p;
}
if (result != SDP_SUCCESS) {
sdp_parse_error(sdp_p, "%s Warning: No string token found for %s attribute",
sdp_p->debug_str, sdp_get_attr_name(attr_p->type));
sdp_p->conf_p->num_invalid_param++; return (SDP_INVALID_PARAMETER);
} else { if (!sdp_validate_maxprate(attr_p->attr.string_val)) {
sdp_parse_error(sdp_p, "%s is not a valid maxprate value.",
attr_p->attr.string_val);
sdp_p->conf_p->num_invalid_param++; return (SDP_INVALID_PARAMETER);
}
// make sure the basics are good: // - at least 1 character // - no illegal chars // - first char is a number if (len < 1
|| strspn(fmtpVal, "0123456789,-") != len
|| PL_strstr(fmtpVal, ",,")
|| fmtpVal[len-1] == ','
|| !('0' <= fmtpVal[0] && fmtpVal[0] <= '9')) { return SDP_INVALID_PARAMETER;
}
// Now that we've passed the basic sanity test, copy the string so we // can tokenize and check the format of the tokens without disturbing // the input string. char dtmf_tones[SDP_MAX_STRING_LEN+1];
PL_strncpyz(dtmf_tones, fmtpVal, sizeof(dtmf_tones));
while (temp != NULL) {
len = strlen(temp); if (len > 5) { // an example of a max size token is "11-15", so if the // token is longer than 5 it is bad return SDP_INVALID_PARAMETER;
}
// case where we have 1 or 2 characters, example 4 or 23 if (len < 3 && strspn(temp, "0123456789") != len) { return SDP_INVALID_PARAMETER;
} elseif (len >= 3) { // case where we have 3-5 characters, ex 3-5, 2-33, or 10-20
sdp_result_e result1 = SDP_SUCCESS;
sdp_result_e result2 = SDP_SUCCESS;
uint8_t low_val;
uint8_t high_val;
low_val = (uint8_t)sdp_getnextnumtok(temp, (constchar **)&temp, "-", &result1);
high_val = (uint8_t)sdp_getnextnumtok(temp, (constchar **)&temp, "-", &result2); if (temp[0] // we don't want to find a second hyphen
|| result1 != SDP_SUCCESS
|| result2 != SDP_SUCCESS) { return SDP_INVALID_PARAMETER;
}
temp=PL_strtok_r(tok, ":", &strtok_state); if (temp) {
iter=1; /* get par width and par height for the aspect ratio */ while (temp != NULL) {
errno = 0;
strtoul_result = strtoul(temp, &strtoul_end, 10);
} elseif (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[47].name,
sdp_fmtp_codec_param[47].strlen) == 0) {
result1 = sdp_get_fmtp_tok(sdp_p, &fmtp_ptr, "maxcodedaudiobandwidth", tmp, sizeof(tmp), &tok); // this one is different for some reason. Most others don't increment // the num_invalid_param field. (mjf) if (result1 == SDP_INVALID_PARAMETER) { sdp_p->conf_p->num_invalid_param++; } if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; }
if (event_id % SDP_NE_BITS_PER_WORD) {
mask <<= 1;
} else { /* crossed a bitmap word boundary */
mask = SDP_NE_BIT_0; if (!range_start && !range_end && !fmtp_p->bmap[mapword]) { /* no events in this word, skip to the last event id
* in this bitmap word. */
event_id += SDP_NE_BITS_PER_WORD - 1; continue;
}
}
if (fmtp_p->bmap[mapword] & mask) { if (!range_start) {
range_start = TRUE;
min = max = (uint8_t)event_id;
} else {
max = (uint8_t)event_id;
}
range_end = (max == fmtp_p->maxval);
} else { /* If we were in the middle of a range, then we've hit the
* end. If we weren't, there is no end to hit. */
range_end = range_start;
}
/* If this is the end of the range, print it to the string. */ if (range_end) {
range_start = range_end = FALSE;
flex_string_sprintf(fs, "%u", min);
if (min != max) {
flex_string_sprintf(fs, "-%u", max);
}
/* Check qos status type */
ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result); if (result != SDP_SUCCESS) {
sdp_parse_error(sdp_p, "%s Warning: No curr attr type specified.",
sdp_p->debug_str);
sdp_p->conf_p->num_invalid_param++; return (SDP_INVALID_PARAMETER);
}
attr_p->attr.curr.status_type = SDP_QOS_STATUS_TYPE_UNKNOWN; for (i=0; i < SDP_MAX_QOS_STATUS_TYPES; i++) { if (cpr_strncasecmp(tmp, sdp_qos_status_type[i].name,
sdp_qos_status_type[i].strlen) == 0) {
attr_p->attr.curr.status_type = (sdp_qos_status_types_e)i;
}
}
/* Find the qos direction. */
ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result); if (result != SDP_SUCCESS) {
sdp_parse_error(sdp_p, "%s Warning: No qos direction specified.",
sdp_p->debug_str);
sdp_p->conf_p->num_invalid_param++; return (SDP_INVALID_PARAMETER);
}
attr_p->attr.curr.direction = SDP_QOS_DIR_UNKNOWN; for (i=0; i < SDP_MAX_QOS_DIR; i++) { if (cpr_strncasecmp(tmp, sdp_qos_direction[i].name,
sdp_qos_direction[i].strlen) == 0) {
attr_p->attr.curr.direction = (sdp_qos_dir_e)i;
}
} if (attr_p->attr.curr.direction == SDP_QOS_DIR_UNKNOWN) {
sdp_parse_error(sdp_p, "%s Warning: QOS direction unrecognized (%s)",
sdp_p->debug_str, tmp);
sdp_p->conf_p->num_invalid_param++; return (SDP_INVALID_PARAMETER);
}
if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
SDP_PRINT("%s Parsed a=%s, type %s status type %s, direction %s",
sdp_p->debug_str, sdp_get_attr_name(attr_p->type),
sdp_get_curr_type_name(attr_p->attr.curr.type),
sdp_get_qos_status_type_name(attr_p->attr.curr.status_type),
sdp_get_qos_direction_name(attr_p->attr.curr.direction));
}
/* Find the strength tag. */
ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result); if (result != SDP_SUCCESS) {
sdp_parse_error(sdp_p, "%s Warning: No qos strength tag specified.",
sdp_p->debug_str);
sdp_p->conf_p->num_invalid_param++; return (SDP_INVALID_PARAMETER);
}
attr_p->attr.des.strength = SDP_QOS_STRENGTH_UNKNOWN; for (i=0; i < SDP_MAX_QOS_STRENGTH; i++) { if (cpr_strncasecmp(tmp, sdp_qos_strength[i].name,
sdp_qos_strength[i].strlen) == 0) {
attr_p->attr.des.strength = (sdp_qos_strength_e)i;
}
} if (attr_p->attr.des.strength == SDP_QOS_STRENGTH_UNKNOWN) {
sdp_parse_error(sdp_p, "%s Warning: QOS strength tag unrecognized (%s)",
sdp_p->debug_str, tmp);
sdp_p->conf_p->num_invalid_param++; return (SDP_INVALID_PARAMETER);
}
/* Check qos status type */
ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result); if (result != SDP_SUCCESS) {
sdp_parse_error(sdp_p, "%s Warning: No des attr type specified.",
sdp_p->debug_str);
sdp_p->conf_p->num_invalid_param++; return (SDP_INVALID_PARAMETER);
}
attr_p->attr.des.status_type = SDP_QOS_STATUS_TYPE_UNKNOWN; for (i=0; i < SDP_MAX_QOS_STATUS_TYPES; i++) { if (cpr_strncasecmp(tmp, sdp_qos_status_type[i].name,
sdp_qos_status_type[i].strlen) == 0) {
attr_p->attr.des.status_type = (sdp_qos_status_types_e)i;
}
}
/* Find the qos direction. */
ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result); if (result != SDP_SUCCESS) {
sdp_parse_error(sdp_p, "%s Warning: No qos direction specified.",
sdp_p->debug_str);
sdp_p->conf_p->num_invalid_param++; return (SDP_INVALID_PARAMETER);
}
attr_p->attr.des.direction = SDP_QOS_DIR_UNKNOWN; for (i=0; i < SDP_MAX_QOS_DIR; i++) { if (cpr_strncasecmp(tmp, sdp_qos_direction[i].name,
sdp_qos_direction[i].strlen) == 0) {
attr_p->attr.des.direction = (sdp_qos_dir_e)i;
}
} if (attr_p->attr.des.direction == SDP_QOS_DIR_UNKNOWN) {
sdp_parse_error(sdp_p, "%s Warning: QOS direction unrecognized (%s)",
sdp_p->debug_str, tmp);
sdp_p->conf_p->num_invalid_param++; return (SDP_INVALID_PARAMETER);
}
if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
SDP_PRINT("%s Parsed a=%s, type %s strength %s status type %s, direction %s",
sdp_p->debug_str, sdp_get_attr_name(attr_p->type),
sdp_get_des_type_name(attr_p->attr.des.type),
sdp_get_qos_strength_name(attr_p->attr.qos.strength),
sdp_get_qos_status_type_name(attr_p->attr.des.status_type),
sdp_get_qos_direction_name(attr_p->attr.des.direction));
}
/* Check qos status type */
ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result); if (result != SDP_SUCCESS) {
sdp_parse_error(sdp_p, "%s Warning: No conf attr type specified.",
sdp_p->debug_str);
sdp_p->conf_p->num_invalid_param++; return (SDP_INVALID_PARAMETER);
}
attr_p->attr.conf.status_type = SDP_QOS_STATUS_TYPE_UNKNOWN; for (i=0; i < SDP_MAX_QOS_STATUS_TYPES; i++) { if (cpr_strncasecmp(tmp, sdp_qos_status_type[i].name,
sdp_qos_status_type[i].strlen) == 0) {
attr_p->attr.conf.status_type = (sdp_qos_status_types_e)i;
}
}
/* Find the qos direction. */
ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result); if (result != SDP_SUCCESS) {
sdp_parse_error(sdp_p, "%s Warning: No qos direction specified.",
sdp_p->debug_str);
sdp_p->conf_p->num_invalid_param++; return (SDP_INVALID_PARAMETER);
}
attr_p->attr.conf.direction = SDP_QOS_DIR_UNKNOWN; for (i=0; i < SDP_MAX_QOS_DIR; i++) { if (cpr_strncasecmp(tmp, sdp_qos_direction[i].name,
sdp_qos_direction[i].strlen) == 0) {
attr_p->attr.conf.direction = (sdp_qos_dir_e)i;
}
} if (attr_p->attr.conf.direction == SDP_QOS_DIR_UNKNOWN) {
sdp_parse_error(sdp_p, "%s Warning: QOS direction unrecognized (%s)",
sdp_p->debug_str, tmp);
sdp_p->conf_p->num_invalid_param++; return (SDP_INVALID_PARAMETER);
}
if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
SDP_PRINT("%s Parsed a=%s, type %s status type %s, direction %s",
sdp_p->debug_str, sdp_get_attr_name(attr_p->type),
sdp_get_conf_type_name(attr_p->attr.conf.type),
sdp_get_qos_status_type_name(attr_p->attr.conf.status_type),
sdp_get_qos_direction_name(attr_p->attr.conf.direction));
}
/* Find the payload type number. */
attr_p->attr.transport_map.payload_num =
(uint16_t)sdp_getnextnumtok(ptr, &ptr, " \t", &result); if (result != SDP_SUCCESS) {
sdp_parse_error(sdp_p, "%s Warning: Invalid payload type specified for %s attribute.",
sdp_p->debug_str, sdp_get_attr_name(attr_p->type));
sdp_p->conf_p->num_invalid_param++; return (SDP_INVALID_PARAMETER);
}
/* Find the encoding name. */
ptr = sdp_getnextstrtok(ptr, attr_p->attr.transport_map.encname, sizeof(attr_p->attr.transport_map.encname), "/ \t", &result); if (result != SDP_SUCCESS) {
sdp_parse_error(sdp_p, "%s Warning: No encoding name specified in %s attribute.",
sdp_p->debug_str, sdp_get_attr_name(attr_p->type));
sdp_p->conf_p->num_invalid_param++; return (SDP_INVALID_PARAMETER);
}
/* Find the clockrate. */
attr_p->attr.transport_map.clockrate =
sdp_getnextnumtok(ptr, &ptr, "/ \t", &result); if (result != SDP_SUCCESS) {
sdp_parse_error(sdp_p, "%s Warning: No clockrate specified for " "%s attribute, set to default of 8000.",
sdp_p->debug_str, sdp_get_attr_name(attr_p->type));
attr_p->attr.transport_map.clockrate = 8000;
}
/* Find the number of channels, if specified. This is optional. */ if (*ptr == '/') { /* If a '/' exists, expect something valid beyond it. */
attr_p->attr.transport_map.num_chan =
(uint16_t)sdp_getnextnumtok(ptr, &ptr, "/ \t", &result); if (result != SDP_SUCCESS) {
sdp_parse_error(sdp_p, "%s Warning: Invalid number of channels parameter" " for rtpmap attribute.", 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 Parsed a=%s, payload type %u, encoding name %s, " "clockrate %u", sdp_p->debug_str,
sdp_get_attr_name(attr_p->type),
attr_p->attr.transport_map.payload_num,
attr_p->attr.transport_map.encname,
attr_p->attr.transport_map.clockrate); if (attr_p->attr.transport_map.num_chan != 1) {
SDP_PRINT("/%u", attr_p->attr.transport_map.num_chan);
}
}
/* Set the capability pointer to NULL for now in case we encounter *anerrorinparsing.
*/
attr_p->attr.cap_p = NULL; /* Set the capability valid flag to FALSE in case we encounter an *error.Ifwedo,wedon'twanttoprocessanyX-cpar/cparattributes
* from this point until we process the next valid X-cap/cdsc attr. */
sdp_p->cap_valid = FALSE;
/* Allocate resource for new capability. Note that the capability *usesthesamestructureusedformedialines.
*/
cap_p = sdp_alloc_mca(sdp_p->parse_line); if (cap_p == NULL) {
sdp_p->conf_p->num_no_resource++; return (SDP_NO_RESOURCE);
}
/* Find the capability number. We don't need to store this since we
* calculate it for ourselves as we need to. But it must be specified. */
(void)sdp_getnextnumtok(ptr, &ptr, "/ \t", &result); if (result != SDP_SUCCESS) {
sdp_parse_error(sdp_p, "%s Warning: Capability not specified for %s, " "unable to parse.", sdp_p->debug_str,
sdp_get_attr_name(attr_p->type));
SDP_FREE(cap_p);
sdp_p->conf_p->num_invalid_param++; return (SDP_INVALID_PARAMETER);
}
/* 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 for %s attribute, " "unable to parse.",
sdp_p->debug_str, sdp_get_attr_name(attr_p->type));
SDP_FREE(cap_p);
sdp_p->conf_p->num_invalid_param++; return (SDP_INVALID_PARAMETER);
}
cap_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) {
cap_p->media = (sdp_media_e)i; break;
}
} if (cap_p->media == SDP_MEDIA_UNSUPPORTED) {
sdp_parse_error(sdp_p, "%s Warning: Media type unsupported (%s).",
sdp_p->debug_str, tmp);
SDP_FREE(cap_p);
sdp_p->conf_p->num_invalid_param++; return (SDP_INVALID_PARAMETER);
}
/* 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, " "unable to parse.", sdp_p->debug_str);
SDP_FREE(cap_p);
sdp_p->conf_p->num_invalid_param++; return (SDP_INVALID_PARAMETER);
}
cap_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) {
cap_p->transport = (sdp_transport_e)i; break;
}
} if (cap_p->transport == SDP_TRANSPORT_UNSUPPORTED) {
sdp_parse_error(sdp_p, "%s Warning: Transport protocol type unsupported (%s).",
sdp_p->debug_str, tmp);
SDP_FREE(cap_p);
sdp_p->conf_p->num_invalid_param++; return (SDP_INVALID_PARAMETER);
}
/* Find payload formats. AAL2 X-cap lines allow multiple *transport/profiletypesperline,sothesearehandleddifferently.
*/ if ((cap_p->transport == SDP_TRANSPORT_AAL2_ITU) ||
(cap_p->transport == SDP_TRANSPORT_AAL2_ATMF) ||
(cap_p->transport == SDP_TRANSPORT_AAL2_CUSTOM)) { /* Capability processing is not currently defined for AAL2 types
* with multiple profiles. We don't process. */
sdp_parse_error(sdp_p, "%s Warning: AAL2 profiles unsupported with " "%s attributes.", sdp_p->debug_str,
sdp_get_attr_name(attr_p->type));
SDP_FREE(cap_p);
sdp_p->conf_p->num_invalid_param++; return (SDP_INVALID_PARAMETER);
} else { /* Transport is a non-AAL2 type. Parse payloads normally. */
sdp_parse_payload_types(sdp_p, cap_p, ptr); if (cap_p->num_payloads == 0) {
SDP_FREE(cap_p);
sdp_p->conf_p->num_invalid_param++; return (SDP_INVALID_PARAMETER);
}
}
/* Get a pointer to the capability structure. */
cap_p = attr_p->attr.cap_p;
if (cap_p == NULL) {
SDPLogError(logTag, "%s Invalid %s attribute, unable to build.",
sdp_p->debug_str, sdp_get_attr_name(attr_p->type));
sdp_p->conf_p->num_invalid_param++; /* Return success so build won't fail. */ return (SDP_SUCCESS);
}
/* Validate params for this capability line */ if ((cap_p->media >= SDP_MAX_MEDIA_TYPES) ||
(cap_p->transport >= SDP_MAX_TRANSPORT_TYPES)) {
SDPLogDebug(logTag, logTag, "%s Media or transport type invalid for %s " "attribute, unable to build.", sdp_p->debug_str,
sdp_get_attr_name(attr_p->type));
sdp_p->conf_p->num_invalid_param++; /* Return success so build won't fail. */ return (SDP_SUCCESS);
}
/* If the X-cap line has AAL2 profiles, build them differently. */ if ((cap_p->transport == SDP_TRANSPORT_AAL2_ITU) ||
(cap_p->transport == SDP_TRANSPORT_AAL2_ATMF) ||
(cap_p->transport == SDP_TRANSPORT_AAL2_CUSTOM)) {
profile_p = cap_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]));
flex_string_append(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;
}
/* Build the transport name */
flex_string_sprintf(fs, "%s", sdp_get_transport_name(cap_p->transport));
/* Build the format lists */ for (i=0; i < cap_p->num_payloads; i++) { if (cap_p->payload_indicator[i] == SDP_PAYLOAD_ENUM) {
flex_string_sprintf(fs, " %s",
sdp_get_payload_name((sdp_payload_e)cap_p->payload_type[i]));
} else {
flex_string_sprintf(fs, " %u", cap_p->payload_type[i]);
}
}
flex_string_append(fs, "\r\n");
/* Increment the current capability number for the next X-cap/cdsc attr. */
sdp_p->cur_cap_num += cap_p->num_payloads;
sdp_p->last_cap_type = attr_p->type;
/* Build any X-cpar/cpar attributes associated with this X-cap/cdsc line. */ return sdp_build_attr_cpar(sdp_p, cap_p->media_attrs_p, fs);
}
/* Make sure we've processed a valid X-cap/cdsc attr prior to this and
* if so, get the cap pointer. */ if (sdp_p->cap_valid == TRUE) {
sdp_attr_e cap_type;
if (attr_p->type == SDP_ATTR_CPAR) {
cap_type = SDP_ATTR_CDSC;
} else { /* Default to X-CAP for everything else */
cap_type = SDP_ATTR_X_CAP;
}
/* a= is the only token we handle in an X-cpar/cpar attribute. */
ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), "= \t", &result);
if ((result != SDP_SUCCESS) || (tmp[0] != 'a') || (tmp[1] != '\0')) {
sdp_parse_error(sdp_p, "%s Warning: Invalid token type in %s " "attribute, unable to parse", sdp_p->debug_str,
sdp_get_attr_name(attr_p->type));
sdp_p->conf_p->num_invalid_param++; return (SDP_INVALID_PARAMETER);
} /*sa_ignore NO_NULL_CHK *{ptrisvalidsincethepointerwascheckedearlierandthe *functionwouldhaveexitedifNULL.}
*/ if (*ptr == '=') {
ptr++;
}
/* Find the attribute type. */
ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), ": \t", &result); /*sa_ignore NO_NULL_CHK *{ptrisvalidsincethepointerwascheckedearlierandthe *functionwouldhaveexitedifNULL.}
*/ if (ptr[0] == ':') { /* Skip the ':' char for parsing attribute parameters. */
ptr++;
} if (result != SDP_SUCCESS) {
sdp_parse_error(sdp_p, "%s No attribute type specified for %s attribute, unable to parse.",
sdp_p->debug_str,
sdp_get_attr_name(attr_p->type));
sdp_p->conf_p->num_invalid_param++; return (SDP_INVALID_PARAMETER);
}
/* Reset the type of the attribute from X-cpar/cpar to whatever the
* specified type is. */
attr_p->type = SDP_ATTR_INVALID;
attr_p->next_p = NULL; for (i=0; i < SDP_MAX_ATTR_TYPES; i++) { if (cpr_strncasecmp(tmp, sdp_attr[i].name, sdp_attr[i].strlen) == 0) {
attr_p->type = (sdp_attr_e)i;
}
} if (attr_p->type == SDP_ATTR_INVALID) {
sdp_parse_error(sdp_p, "%s Warning: Unrecognized attribute (%s) for %s attribute, unable to parse.",
sdp_p->debug_str, tmp,
sdp_get_attr_name(attr_p->type));
sdp_p->conf_p->num_invalid_param++; return (SDP_INVALID_PARAMETER);
}
/* We don't allow recursion with the capability attributes. */ if ((attr_p->type == SDP_ATTR_X_SQN) ||
(attr_p->type == SDP_ATTR_X_CAP) ||
(attr_p->type == SDP_ATTR_X_CPAR) ||
(attr_p->type == SDP_ATTR_SQN) ||
(attr_p->type == SDP_ATTR_CDSC) ||
(attr_p->type == SDP_ATTR_CPAR)) {
sdp_parse_error(sdp_p, "%s Warning: Invalid attribute (%s) for %s" " attribute, unable to parse.", sdp_p->debug_str, tmp,
sdp_get_attr_name(attr_p->type));
sdp_p->conf_p->num_invalid_param++; return (SDP_INVALID_PARAMETER);
}
/* Parse the attribute. */
result = sdp_attr[attr_p->type].parse_func(sdp_p, attr_p, ptr); if (result != SDP_SUCCESS) { return (result);
}
/* Hook the attribute into the capability structure. */ if (cap_p->media_attrs_p == NULL) {
cap_p->media_attrs_p = attr_p;
} else { for (prev_attr_p = cap_p->media_attrs_p;
prev_attr_p->next_p != NULL;
prev_attr_p = prev_attr_p->next_p) {
; /* Empty for */
}
prev_attr_p->next_p = attr_p;
}
rtcp_p->port = (uint16_t)sdp_getnextnumtok(ptr, &ptr, " \t", &result); if (result != SDP_SUCCESS) {
sdp_parse_error(sdp_p, "%s Warning: could not parse port for rtcp attribute",
sdp_p->debug_str);
sdp_p->conf_p->num_invalid_param++;
return SDP_INVALID_PARAMETER;
}
/* The rest is optional, although it is all-or-nothing */
(void)sdp_getnextstrtok(ptr, nettype, sizeof(nettype), " \t", &result); if (result == SDP_EMPTY_TOKEN) { /* Nothing after the port */ return SDP_SUCCESS;
}
ptr = sdp_getnextstrtok(ptr, rtcp_p->addr, sizeof(rtcp_p->addr), " \t",
&result); if (result != SDP_SUCCESS) {
sdp_parse_error(sdp_p, "%s Warning: could not parse addr for rtcp attribute",
sdp_p->debug_str);
sdp_p->conf_p->num_invalid_param++;
return SDP_INVALID_PARAMETER;
}
return SDP_SUCCESS;
}
sdp_result_e sdp_build_attr_rtcp (sdp_t *sdp_p, sdp_attr_t *attr_p,
flex_string *fs)
{ /* We should not be serializing SDP anyway, but we need this function until
* Bug 1112737 is resolved. */ return SDP_FAILURE;
}
/* Find the media direction role. */
ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), ": \t", &result);
if (result != SDP_SUCCESS) {
sdp_parse_error(sdp_p, "%s Warning: No role parameter specified for " "comediadir attribute.", sdp_p->debug_str);
sdp_p->conf_p->num_invalid_param++; return (SDP_INVALID_PARAMETER);
}
attr_p->attr.comediadir.role = SDP_MEDIADIR_ROLE_UNSUPPORTED; for (i=0; i < SDP_MAX_MEDIADIR_ROLES; i++) { if (cpr_strncasecmp(tmp, sdp_mediadir_role[i].name,
sdp_mediadir_role[i].strlen) == 0) {
type_found = TRUE;
attr_p->attr.comediadir.role = (sdp_mediadir_role_e)i; break;
}
} if (attr_p->attr.comediadir.role == SDP_MEDIADIR_ROLE_UNSUPPORTED) {
sdp_parse_error(sdp_p, "%s Warning: Invalid role type specified for " "comediadir attribute (%s).", sdp_p->debug_str, tmp);
sdp_p->conf_p->num_invalid_param++; return (SDP_INVALID_PARAMETER);
}
/* If the role is passive, we don't expect any more params. */ if (attr_p->attr.comediadir.role == SDP_MEDIADIR_ROLE_PASSIVE) { if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
SDP_PRINT("%s Parsed a=%s, passive",
sdp_p->debug_str, sdp_get_attr_name(attr_p->type));
} return (SDP_SUCCESS);
}
/* Find the connection information if present */ /* parse to get the nettype */
ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result); if (result != SDP_SUCCESS) {
sdp_parse_error(sdp_p, "%s Warning: No network type specified in comediadir " "attribute.", sdp_p->debug_str);
sdp_p->conf_p->num_invalid_param++; return (SDP_SUCCESS); /* as the optional parameters are not there */
}
attr_p->attr.comediadir.conn_info.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) {
type_found = TRUE;
} if (type_found == TRUE) { if (sdp_p->conf_p->nettype_supported[i] == TRUE) {
attr_p->attr.comediadir.conn_info.nettype = (sdp_nettype_e)i;
}
type_found = FALSE;
}
} if (attr_p->attr.comediadir.conn_info.nettype == SDP_NT_UNSUPPORTED) {
sdp_parse_error(sdp_p, "%s Warning: ConnInfo in Comediadir: network type " "unsupported (%s).", sdp_p->debug_str, tmp);
sdp_p->conf_p->num_invalid_param++;
}
/* Find the comedia address type. */
ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result); if (result != SDP_SUCCESS) {
sdp_parse_error(sdp_p, "%s Warning: No address type specified in comediadir" " attribute.", sdp_p->debug_str);
sdp_p->conf_p->num_invalid_param++;
}
attr_p->attr.comediadir.conn_info.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) {
type_found = TRUE;
} if (type_found == TRUE) { if (sdp_p->conf_p->addrtype_supported[i] == TRUE) {
attr_p->attr.comediadir.conn_info.addrtype = (sdp_addrtype_e)i;
}
type_found = FALSE;
}
} if (attr_p->attr.comediadir.conn_info.addrtype == SDP_AT_UNSUPPORTED) {
sdp_parse_error(sdp_p, "%s Warning: Conninfo address type unsupported " "(%s).", sdp_p->debug_str, tmp);
sdp_p->conf_p->num_invalid_param++;
}
/* Find the conninfo address. */
ptr = sdp_getnextstrtok(ptr, attr_p->attr.comediadir.conn_info.conn_addr, sizeof(attr_p->attr.comediadir.conn_info.conn_addr), " \t", &result); if (result != SDP_SUCCESS) {
sdp_parse_error(sdp_p, "%s Warning: No conninfo address specified in " "comediadir attribute.", sdp_p->debug_str);
sdp_p->conf_p->num_invalid_param++;
}
/* Find the src port info , if any */
attr_p->attr.comediadir.src_port = sdp_getnextnumtok(ptr, &ptr, " \t",
&result); if (result != SDP_SUCCESS) {
sdp_parse_error(sdp_p, "%s Warning: No src port specified in " "comediadir attribute.", sdp_p->debug_str);
sdp_p->conf_p->num_invalid_param++;
}
/* Check crypto suites */ for(i=0; i<SDP_SRTP_MAX_NUM_CRYPTO_SUITES; i++) { if (!cpr_strcasecmp(sdp_srtp_crypto_suite_array[i].crypto_suite_str, str)) {
attr_p->attr.srtp_context.suite = sdp_srtp_crypto_suite_array[i].crypto_suite_val;
attr_p->attr.srtp_context.master_key_size_bytes =
sdp_srtp_crypto_suite_array[i].key_size_bytes;
attr_p->attr.srtp_context.master_salt_size_bytes =
sdp_srtp_crypto_suite_array[i].salt_size_bytes; returnTRUE; /* There is a succesful match so exit */
}
} /* couldn't find a matching crypto suite */
sdp_parse_error(sdp_p, "%s No Matching crypto suite for SRTP Context(%s)-'X-crypto:v1' expected",
sdp_p->debug_str, str);
returnFALSE;
}
sdp_result_e sdp_build_attr_srtpcontext (sdp_t *sdp_p, sdp_attr_t *attr_p,
flex_string *fs)
{ #define MAX_BASE64_ENCODE_SIZE_BYTES 60 int output_len = MAX_BASE64_ENCODE_SIZE_BYTES; int key_size = attr_p->attr.srtp_context.master_key_size_bytes; int salt_size = attr_p->attr.srtp_context.master_salt_size_bytes; unsignedchar base64_encoded_data[MAX_BASE64_ENCODE_SIZE_BYTES]; unsignedchar base64_encoded_input[MAX_BASE64_ENCODE_SIZE_BYTES];
base64_result_t status;
output_len = MAX_BASE64_ENCODE_SIZE_BYTES;
/* Append master and salt keys */
memcpy(base64_encoded_input,
attr_p->attr.srtp_context.master_key,
key_size );
memcpy(base64_encoded_input + key_size,
attr_p->attr.srtp_context.master_salt,
salt_size );
if ((status = base64_encode(base64_encoded_input, key_size + salt_size,
base64_encoded_data, &output_len)) != BASE64_SUCCESS) { if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
SDPLogError(logTag, "%s Error: Failure to Base64 Encoded data (%s) ",
sdp_p->debug_str, BASE64_RESULT_TO_STRING(status));
} return (SDP_INVALID_PARAMETER);
}
/* *sdp_parse_attr_mptime *Thisfunctionparsesthea=mptimesdpline.Thisparameterconsistsof *oneormorenumbersorhyphens("-").Thefirstparametermustbea *number.Thenumberofparametersmustmatchthenumberofformatsspecified *onthem=line.Thisfunctionisliberalinthatitdoesnotmatchagainst *them=lineorrequireanumberforthefirstparameter.
*/
sdp_result_e sdp_parse_attr_mptime (
sdp_t *sdp_p,
sdp_attr_t *attr_p, constchar *ptr)
{
uint16_t i; /* loop counter for parameters */
sdp_result_e result; /* value returned by this function */
tinybool null_ind; /* true if a parameter is "-" */
/* *Runthelistofmptimeparametervaluesandwriteeachone *tothesdpline.Replacezeroswithhyphens.
*/ for (i=0; i < attr_p->attr.mptime.num_intervals; i++) { if (i > 0) {
flex_string_append(fs, " ");
}
/* Find the filter mode */
ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result); if (result != SDP_SUCCESS) {
sdp_parse_error(sdp_p, "%s Warning: No src filter attribute value specified for " "a=source-filter line", sdp_p->debug_str);
sdp_p->conf_p->num_invalid_param++; return (SDP_INVALID_PARAMETER);
} for (i = 0; i < SDP_MAX_FILTER_MODE; i++) { if (cpr_strncasecmp(tmp, sdp_src_filter_mode_val[i].name,
sdp_src_filter_mode_val[i].strlen) == 0) {
attr_p->attr.source_filter.mode = (sdp_src_filter_mode_e)i; break;
}
} if (attr_p->attr.source_filter.mode == SDP_FILTER_MODE_NOT_PRESENT) { /* No point continuing */
sdp_parse_error(sdp_p, "%s Warning: Invalid src filter mode for a=source-filter " "line", sdp_p->debug_str);
sdp_p->conf_p->num_invalid_param++; return (SDP_INVALID_PARAMETER);
}
/* Find the network type */
ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result); if (result != SDP_SUCCESS) {
sdp_p->conf_p->num_invalid_param++; return (SDP_INVALID_PARAMETER);
} 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) {
attr_p->attr.source_filter.nettype = (sdp_nettype_e)i;
}
}
} if (attr_p->attr.source_filter.nettype == SDP_NT_UNSUPPORTED) {
sdp_parse_error(sdp_p, "%s Warning: Network type unsupported " "(%s) for a=source-filter", sdp_p->debug_str, tmp);
sdp_p->conf_p->num_invalid_param++; return (SDP_INVALID_PARAMETER);
}
/* Find the address type */
ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result); if (result != SDP_SUCCESS) {
sdp_p->conf_p->num_invalid_param++; return (SDP_INVALID_PARAMETER);
} 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) {
attr_p->attr.source_filter.addrtype = (sdp_addrtype_e)i;
}
}
} if (attr_p->attr.source_filter.addrtype == SDP_AT_UNSUPPORTED) { if (strncmp(tmp, "*", 1) == 0) {
attr_p->attr.source_filter.addrtype = SDP_AT_FQDN;
} else {
sdp_parse_error(sdp_p, "%s Warning: Address type unsupported " "(%s) for a=source-filter", sdp_p->debug_str, tmp);
sdp_p->conf_p->num_invalid_param++; return (SDP_INVALID_PARAMETER);
}
}
/* Find the destination addr */
ptr = sdp_getnextstrtok(ptr, attr_p->attr.source_filter.dest_addr, sizeof(attr_p->attr.source_filter.dest_addr), " \t", &result); if (result != SDP_SUCCESS) {
sdp_parse_error(sdp_p, "%s No filter destination address specified for " "a=source-filter", sdp_p->debug_str);
sdp_p->conf_p->num_invalid_param++; return (SDP_INVALID_PARAMETER);
}
/* Find the list of source address to apply the filter */ for (i = 0; i < SDP_MAX_SRC_ADDR_LIST; i++) {
ptr = sdp_getnextstrtok(ptr, attr_p->attr.source_filter.src_list[i], sizeof(attr_p->attr.source_filter.src_list[i]), " \t", &result); if (result != SDP_SUCCESS) { break;
}
attr_p->attr.source_filter.num_src_addr++;
} if (attr_p->attr.source_filter.num_src_addr == 0) {
sdp_parse_error(sdp_p, "%s Warning: No source list provided " "for a=source-filter", sdp_p->debug_str);
sdp_p->conf_p->num_invalid_param++; return (SDP_INVALID_PARAMETER);
}
for (i = 0; i < attr_p->attr.source_filter.num_src_addr; i++) {
flex_string_append(fs, " ");
flex_string_append(fs, attr_p->attr.source_filter.src_list[i]);
}
/* MKI has a colon */ if (strstr(buf, ":")) {
result = verify_sdescriptions_mki(buf, mkiValue, &mkiLen); if (result) {
attr_p->attr.srtp_context.mki_size_bytes = mkiLen;
sstrncpy((char*)attr_p->attr.srtp_context.mki, mkiValue,
SDP_SRTP_MAX_MKI_SIZE_BYTES);
}
} else {
result = verify_sdescriptions_lifetime(buf); if (result) {
sstrncpy((char*)attr_p->attr.srtp_context.master_key_lifetime, buf,
SDP_SRTP_MAX_LIFETIME_BYTES);
}
}
ptr = str; if (cpr_strncasecmp(ptr, "inline:", 7) != 0) {
sdp_parse_error(sdp_p, "%s Could not find keyword inline", sdp_p->debug_str);
sdp_p->conf_p->num_invalid_param++; returnFALSE;
}
/* advance pass the inline key word */
ptr = ptr + 7;
ptr = sdp_getnextstrtok(ptr, buf, sizeof(buf), "|", &result); while (result == SDP_SUCCESS) { /* the fist time this loop executes, the key is gotten */ if (keyFound == FALSE) {
keyFound = TRUE;
len = SDP_MAX_STRING_LEN; /* The key is base64 encoded composed of the master key concatenated with the *mastersalt.
*/
status = base64_decode((unsignedchar *)buf, strlen(buf),
(unsignedchar *)base64decodeData, &len);
/* Used only for MGCP */
SDP_SRTP_CONTEXT_SET_MASTER_KEY
(attr_p->attr.srtp_context.selection_flags);
SDP_SRTP_CONTEXT_SET_MASTER_SALT
(attr_p->attr.srtp_context.selection_flags);
/* if we haven't reached the end of line, get the next token */
ptr = sdp_getnextstrtok(ptr, buf, sizeof(buf), "|", &result);
}
/* if we didn't find the key, error out */ if (keyFound == FALSE) {
sdp_parse_error(sdp_p, "%s Could not find sdescriptions key", sdp_p->debug_str);
sdp_p->conf_p->num_invalid_param++; returnFALSE;
}
char tmp[SDP_MAX_STRING_LEN];
sdp_result_e result = SDP_FAILURE; int k = 0;
/* initialize only the optional parameters */
attr_p->attr.srtp_context.master_key_lifetime[0] = 0;
attr_p->attr.srtp_context.mki[0] = 0;
/* used only for MGCP */
SDP_SRTP_CONTEXT_SET_ENCRYPT_AUTHENTICATE
(attr_p->attr.srtp_context.selection_flags);
/* get the tag only if we are version 9 */ if (vtype == SDP_ATTR_SDESCRIPTIONS) {
attr_p->attr.srtp_context.tag =
sdp_getnextnumtok(ptr, &ptr, " \t", &result);
if (result != SDP_SUCCESS) {
sdp_parse_error(sdp_p, "%s Could not find sdescriptions tag",
sdp_p->debug_str);
sdp_p->conf_p->num_invalid_param++; return (SDP_INVALID_PARAMETER);
}
}
/* get the crypto suite */
ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result); if (result != SDP_SUCCESS) {
sdp_parse_error(sdp_p, "%s Could not find sdescriptions crypto suite", sdp_p->debug_str);
sdp_p->conf_p->num_invalid_param++; return (SDP_INVALID_PARAMETER);
}
/* Tack on any information that cannot otherwise be represented by
* the sdp_fmtp_fb_t structure. */ if (attr_p->attr.rtcp_fb.extra[0]) {
flex_string_sprintf(fs, " %s", attr_p->attr.rtcp_fb.extra);
}
/* Line ending */
flex_string_sprintf(fs, "\r\n");
return SDP_SUCCESS;
}
sdp_result_e sdp_parse_attr_rtcp_fb (sdp_t *sdp_p,
sdp_attr_t *attr_p, constchar *ptr)
{
sdp_result_e result = SDP_SUCCESS;
sdp_fmtp_fb_t *rtcp_fb_p = &(attr_p->attr.rtcp_fb); int i;
/* Set up attribute fields */
rtcp_fb_p->payload_num = 0;
rtcp_fb_p->feedback_type = SDP_RTCP_FB_UNKNOWN;
rtcp_fb_p->extra[0] = '\0';
/* Skip WS (just in case) */ while (*ptr == ' ' || *ptr == '\t') {
ptr++;
}
/* Look for the special "*" payload type */ if (*ptr == '*') {
rtcp_fb_p->payload_num = SDP_ALL_PAYLOADS;
ptr++;
} else { /* If the pt is not '*', parse it out as an integer */
rtcp_fb_p->payload_num = (uint16_t)sdp_getnextnumtok(ptr, &ptr, " \t", &result); if (result != SDP_SUCCESS) {
sdp_parse_error(sdp_p, "%s Warning: could not parse payload type for rtcp-fb attribute",
sdp_p->debug_str);
sdp_p->conf_p->num_invalid_param++;
return SDP_INVALID_PARAMETER;
}
}
/* Read feedback type */
i = find_token_enum("rtcp-fb attribute", sdp_p, &ptr, sdp_rtcp_fb_type_val,
SDP_MAX_RTCP_FB, SDP_RTCP_FB_UNKNOWN); if (i < 0) {
sdp_parse_error(sdp_p, "%s Warning: could not parse feedback type for rtcp-fb attribute",
sdp_p->debug_str);
sdp_p->conf_p->num_invalid_param++; return SDP_INVALID_PARAMETER;
}
rtcp_fb_p->feedback_type = (sdp_rtcp_fb_type_e) i;
switch(rtcp_fb_p->feedback_type) { case SDP_RTCP_FB_ACK:
i = find_token_enum("rtcp-fb ack type", sdp_p, &ptr,
sdp_rtcp_fb_ack_type_val,
SDP_MAX_RTCP_FB_ACK, SDP_RTCP_FB_ACK_UNKNOWN); if (i < 0) {
sdp_parse_error(sdp_p, "%s Warning: could not parse ack type for rtcp-fb attribute",
sdp_p->debug_str);
sdp_p->conf_p->num_invalid_param++; return SDP_INVALID_PARAMETER;
}
rtcp_fb_p->param.ack = (sdp_rtcp_fb_ack_type_e) i; break;
case SDP_RTCP_FB_CCM:
i = find_token_enum("rtcp-fb ccm type", sdp_p, &ptr,
sdp_rtcp_fb_ccm_type_val,
SDP_MAX_RTCP_FB_CCM, SDP_RTCP_FB_CCM_UNKNOWN); if (i < 0) {
sdp_parse_error(sdp_p, "%s Warning: could not parse ccm type for rtcp-fb attribute",
sdp_p->debug_str);
sdp_p->conf_p->num_invalid_param++; return SDP_INVALID_PARAMETER;
}
rtcp_fb_p->param.ccm = (sdp_rtcp_fb_ccm_type_e) i;
/* TODO -- We don't currently parse tmmbr parameters or vbcm submessagetypes.Ifwedecidetosupportthesemodesof operation,weprobablywanttoaddparsingcodeforthem. Forthetimebeing,they'lljustendupparsedinto"extra" Bug1097169.
*/ break;
case SDP_RTCP_FB_NACK: /* Skip any remaining WS -- see http://code.google.com/p/webrtc/issues/detail?id=1922 */ while (*ptr == ' ' || *ptr == '\t') {
ptr++;
} /* Check for empty string */ if (*ptr == '\r' || *ptr == '\n') {
rtcp_fb_p->param.nack = SDP_RTCP_FB_NACK_BASIC; break;
}
i = find_token_enum("rtcp-fb nack type", sdp_p, &ptr,
sdp_rtcp_fb_nack_type_val,
SDP_MAX_RTCP_FB_NACK, SDP_RTCP_FB_NACK_UNKNOWN); if (i < 0) {
sdp_parse_error(sdp_p, "%s Warning: could not parse nack type for rtcp-fb attribute",
sdp_p->debug_str);
sdp_p->conf_p->num_invalid_param++; return SDP_INVALID_PARAMETER;
}
rtcp_fb_p->param.nack = (sdp_rtcp_fb_nack_type_e) i; break;
case SDP_RTCP_FB_TRR_INT:
rtcp_fb_p->param.trr_int = sdp_getnextnumtok(ptr, &ptr, " \t", &result); if (result != SDP_SUCCESS) {
sdp_parse_error(sdp_p, "%s Warning: could not parse trr-int value for rtcp-fb " "attribute", sdp_p->debug_str);
sdp_p->conf_p->num_invalid_param++; return SDP_INVALID_PARAMETER;
} break;
case SDP_RTCP_FB_REMB: /* No additional tokens to parse after goog-remb */ break;
case SDP_RTCP_FB_TRANSPORT_CC: /* No additional tokens to parse after transport-cc */ break;
case SDP_RTCP_FB_UNKNOWN: /* Handled by "extra", below */ break;
default: /* This is an internal error, not a parsing error */
SDPLogError(logTag, "%s Error: Invalid rtcp-fb enum (%d)",
sdp_p->debug_str, attr_p->attr.rtcp_fb.feedback_type); return SDP_FAILURE;
}
/* Skip any remaining WS */ while (*ptr == ' ' || *ptr == '\t') {
ptr++;
}
/* Just store the rest of the line in "extra" -- this will return
a failure result if there is no more text, but that's fine. */
ptr = sdp_getnextstrtok(ptr, rtcp_fb_p->extra, sizeof(rtcp_fb_p->extra), "\r\n", &result);
return SDP_SUCCESS;
}
sdp_result_e sdp_build_attr_setup(sdp_t *sdp_p,
sdp_attr_t *attr_p,
flex_string *fs)
{ switch (attr_p->attr.setup) { case SDP_SETUP_ACTIVE: case SDP_SETUP_PASSIVE: case SDP_SETUP_ACTPASS: case SDP_SETUP_HOLDCONN:
flex_string_sprintf(fs, "a=%s:%s\r\n",
sdp_attr[attr_p->type].name,
sdp_setup_type_val[attr_p->attr.setup].name); break; default:
SDPLogError(logTag, "%s Error: Invalid setup enum (%d)",
sdp_p->debug_str, attr_p->attr.setup); return SDP_FAILURE;
}
return SDP_SUCCESS;
}
sdp_result_e sdp_parse_attr_setup(sdp_t *sdp_p,
sdp_attr_t *attr_p, constchar *ptr)
{ int i = find_token_enum("setup attribute", sdp_p, &ptr,
sdp_setup_type_val,
SDP_MAX_SETUP, SDP_SETUP_UNKNOWN);
if (i < 0) {
sdp_parse_error(sdp_p, "%s Warning: could not parse setup attribute",
sdp_p->debug_str);
sdp_p->conf_p->num_invalid_param++; return SDP_INVALID_PARAMETER;
}
attr_p->attr.setup = (sdp_setup_type_e) i;
switch (attr_p->attr.setup) { case SDP_SETUP_ACTIVE: case SDP_SETUP_PASSIVE: case SDP_SETUP_ACTPASS: case SDP_SETUP_HOLDCONN: /* All these values are OK */ break; case SDP_SETUP_UNKNOWN:
sdp_parse_error(sdp_p, "%s Warning: Unknown setup attribute",
sdp_p->debug_str); return SDP_INVALID_PARAMETER; default: /* This is an internal error, not a parsing error */
SDPLogError(logTag, "%s Error: Invalid setup enum (%d)",
sdp_p->debug_str, attr_p->attr.setup); return SDP_FAILURE;
}
sdp_result_e sdp_parse_attr_connection(sdp_t *sdp_p,
sdp_attr_t *attr_p, constchar *ptr)
{ int i = find_token_enum("connection attribute", sdp_p, &ptr,
sdp_connection_type_val,
SDP_MAX_CONNECTION, SDP_CONNECTION_UNKNOWN);
if (i < 0) {
sdp_parse_error(sdp_p, "%s Warning: could not parse connection attribute",
sdp_p->debug_str);
sdp_p->conf_p->num_invalid_param++; return SDP_INVALID_PARAMETER;
}
switch (attr_p->attr.connection) { case SDP_CONNECTION_NEW: case SDP_CONNECTION_EXISTING: /* All these values are OK */ break; case SDP_CONNECTION_UNKNOWN:
sdp_parse_error(sdp_p, "%s Warning: Unknown connection attribute",
sdp_p->debug_str); return SDP_INVALID_PARAMETER; default: /* This is an internal error, not a parsing error */
SDPLogError(logTag, "%s Error: Invalid connection enum (%d)",
sdp_p->debug_str, attr_p->attr.connection); return SDP_FAILURE;
} return SDP_SUCCESS;
}
ptr = sdp_getnextstrtok(ptr, attr_p->attr.extmap.uri, sizeof(attr_p->attr.extmap.uri), " \t", &result); if (result != SDP_SUCCESS) {
sdp_parse_error(sdp_p, "%s Warning: No uri specified in %s attribute.",
sdp_p->debug_str, sdp_get_attr_name(attr_p->type));
sdp_p->conf_p->num_invalid_param++; return (SDP_INVALID_PARAMETER);
}
while (*ptr == ' ' || *ptr == '\t') {
++ptr;
}
/* Grab everything that follows, even if it contains whitespace */
ptr = sdp_getnextstrtok(ptr, attr_p->attr.extmap.extension_attributes, sizeof(attr_p->attr.extmap.extension_attributes), "\r\n", &result);
if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
SDP_PRINT("%s Parsed a=%s, id %u, direction %s, " "uri %s, extension %s", sdp_p->debug_str,
sdp_get_attr_name(attr_p->type),
attr_p->attr.extmap.id,
SDP_DIRECTION_PRINT(attr_p->attr.extmap.media_direction),
attr_p->attr.extmap.uri,
attr_p->attr.extmap.extension_attributes);
}
if (result != SDP_SUCCESS) {
sdp_parse_error(sdp_p, "%s Warning: Bad msid-semantic attribute; " "missing semantic",
sdp_p->debug_str);
sdp_p->conf_p->num_invalid_param++; return SDP_INVALID_PARAMETER;
}
for (i = 0; i < SDP_MAX_MEDIA_STREAMS; ++i) { /* msid-id can be up to 64 characters long, plus null terminator */ char temp[65];
ptr = sdp_getnextstrtok(ptr, temp, sizeof(temp), " \t", &result);
if ((result != SDP_SUCCESS) && (result != SDP_EMPTY_TOKEN)) {
sdp_parse_error(sdp_p, "%s Warning: Bad msid-semantic attribute",
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 Parsed a=msid-semantic, %s", sdp_p->debug_str,
attr_p->attr.msid_semantic.semantic); for (i = 0; i < SDP_MAX_MEDIA_STREAMS; ++i) { if (!attr_p->attr.msid_semantic.msids[i]) { break;
}
if (result != SDP_SUCCESS) {
sdp_parse_error(sdp_p, "%s Warning: Bad ssrc attribute, cannot parse ssrc",
sdp_p->debug_str);
sdp_p->conf_p->num_invalid_param++; return SDP_INVALID_PARAMETER;
}
/* Skip any remaining WS */ while (*ptr == ' ' || *ptr == '\t') {
ptr++;
}
/* Just store the rest of the line in "attribute" -- this will return
a failure result if there is no more text, but that's fine. */
ptr = sdp_getnextstrtok(ptr,
attr_p->attr.ssrc.attribute, sizeof(attr_p->attr.ssrc.attribute), "\r\n",
&result);
if (attr_p->attr.ssrc_group.num_ssrcs == 0) {
sdp_parse_error(sdp_p, "%s Warning: Ssrc group must contain at least one ssrc (%s).",
sdp_p->debug_str, tmp);
sdp_p->conf_p->num_invalid_param++; return (SDP_INVALID_PARAMETER);
}
if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
SDP_PRINT("%s Parsed a=ssrc-group, semantic %s", sdp_p->debug_str,
sdp_get_ssrc_group_attr_name(attr_p->attr.ssrc_group.semantic)); for (i = 0; i < attr_p->attr.ssrc_group.num_ssrcs; ++i) {
SDP_PRINT("%s ... ssrc %u", sdp_p->debug_str,
attr_p->attr.ssrc_group.ssrcs[i]);
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.