Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/third_party/sipcc/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 59 kB image not shown  

Quelle  sdp_token.c   Sprache: 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);
    }
}


Messung V0.5
C=95 H=94 G=94

¤ Dauer der Verarbeitung: 0.21 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

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.