diff options
Diffstat (limited to 'third_party/sipcc')
25 files changed, 21729 insertions, 0 deletions
diff --git a/third_party/sipcc/ccsdp.h b/third_party/sipcc/ccsdp.h new file mode 100644 index 0000000000..39e3c71f68 --- /dev/null +++ b/third_party/sipcc/ccsdp.h @@ -0,0 +1,212 @@ +/* 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/. */ + +#ifndef __CCSDP_H__ +#define __CCSDP_H__ + +#include "cpr_types.h" +#include "ccsdp_rtcp_fb.h" + +#define SIPSDP_ILBC_MODE20 20 + +/** + * Return codes for sdp helper APIs + */ +typedef enum rtp_ptype_ +{ + RTP_NONE = -1, + RTP_PCMU = 0, + RTP_CELP = 1, + RTP_G726 = 2, + RTP_GSM = 3, + RTP_G723 = 4, + RTP_DVI4 = 5, + RTP_DVI4_II = 6, + RTP_LPC = 7, + RTP_PCMA = 8, + RTP_G722 = 9, + RTP_G728 = 15, + RTP_G729 = 18, + RTP_JPEG = 26, + RTP_NV = 28, + RTP_H261 = 31, + RTP_H264_P0 = 97, + RTP_H264_P1 = 126, + RTP_TELEPHONE_EVENT = 101, + RTP_L16 = 102, + RTP_H263 = 103, + RTP_ILBC = 116, /* used only to make an offer */ + RTP_OPUS = 109, + RTP_VP8 = 120, + RTP_VP9 = 121, + RTP_RED = 122, + RTP_ULPFEC = 123, + RTP_I420 = 124, + RTP_ISAC = 124, + RTP_RTX = 125 +} rtp_ptype; + +typedef struct { + const char *name; + int value; +} ccsdp_key_table_entry_t; + +typedef enum max_coded_audio_bandwidth_ { + opus_nb = 0, /* Narrowband */ + opus_mb = 1, /* Mediumband */ + opus_wb = 2, /* Wideband */ + opus_swb = 3, /* Super-wideband */ + opus_fb = 4 /* Fullband */ +} max_coded_audio_bandwidth; + +static const ccsdp_key_table_entry_t max_coded_audio_bandwidth_table[] = { + {"nb", opus_nb}, + {"mb", opus_mb}, + {"wb", opus_wb}, + {"swb", opus_swb}, + {"fb", opus_fb} +}; + +typedef enum { + SDP_SUCCESS, /**< Success */ + SDP_FAILURE, + SDP_INVALID_SDP_PTR, + SDP_NOT_SDP_DESCRIPTION, + SDP_INVALID_TOKEN_ORDERING, + SDP_INVALID_PARAMETER, + SDP_INVALID_MEDIA_LEVEL, + SDP_INVALID_CAPABILITY, + SDP_NO_RESOURCE, + SDP_UNRECOGNIZED_TOKEN, + SDP_NULL_BUF_PTR, + SDP_POTENTIAL_SDP_OVERFLOW, + SDP_EMPTY_TOKEN, + SDP_MAX_RC +} sdp_result_e; + +/** + * Indicates invalid bandwidth value + */ +#define SDP_INVALID_VALUE (-2) + +/** + * Bandwidth modifier type for b= SDP line + */ +typedef enum { + SDP_BW_MODIFIER_INVALID = -1, + SDP_BW_MODIFIER_AS, /** < b=AS: */ + SDP_BW_MODIFIER_CT, /** < b=CT: */ + SDP_BW_MODIFIER_TIAS, /** < b=TIAS: */ + SDP_MAX_BW_MODIFIER_VAL, + SDP_BW_MODIFIER_UNSUPPORTED +} sdp_bw_modifier_e; + +/** + * SDP attribute types + */ +/* Attribute Types */ +typedef enum { + SDP_ATTR_BEARER = 0, + SDP_ATTR_CALLED, + SDP_ATTR_CONN_TYPE, + SDP_ATTR_DIALED, + SDP_ATTR_DIALING, + SDP_ATTR_DIRECTION, + SDP_ATTR_EECID, + SDP_ATTR_FMTP, + SDP_ATTR_SCTPMAP, + SDP_ATTR_FRAMING, + SDP_ATTR_INACTIVE, + SDP_ATTR_PTIME, + SDP_ATTR_QOS, + SDP_ATTR_CURR, + SDP_ATTR_DES, + SDP_ATTR_CONF, + SDP_ATTR_RECVONLY, + SDP_ATTR_RTPMAP, + SDP_ATTR_SECURE, + SDP_ATTR_SENDONLY, + SDP_ATTR_SENDRECV, + SDP_ATTR_SUBNET, + SDP_ATTR_T38_VERSION, + SDP_ATTR_T38_MAXBITRATE, + SDP_ATTR_T38_FILLBITREMOVAL, + SDP_ATTR_T38_TRANSCODINGMMR, + SDP_ATTR_T38_TRANSCODINGJBIG, + SDP_ATTR_T38_RATEMGMT, + SDP_ATTR_T38_MAXBUFFER, + SDP_ATTR_T38_MAXDGRAM, + SDP_ATTR_T38_UDPEC, + SDP_ATTR_X_CAP, + SDP_ATTR_X_CPAR, + SDP_ATTR_X_PC_CODEC, + SDP_ATTR_X_PC_QOS, + SDP_ATTR_X_QOS, + SDP_ATTR_X_SQN, + SDP_ATTR_TMRGWXID, + SDP_ATTR_TC1_PAYLOAD_BYTES, + SDP_ATTR_TC1_WINDOW_SIZE, + SDP_ATTR_TC2_PAYLOAD_BYTES, + SDP_ATTR_TC2_WINDOW_SIZE, + SDP_ATTR_RTCP, + SDP_ATTR_RTR, + SDP_ATTR_SILENCESUPP, + SDP_ATTR_SRTP_CONTEXT, /* version 2 sdescriptions */ + SDP_ATTR_MPTIME, + SDP_ATTR_X_SIDIN, + SDP_ATTR_X_SIDOUT, + SDP_ATTR_X_CONFID, + SDP_ATTR_GROUP, + SDP_ATTR_MID, + SDP_ATTR_SOURCE_FILTER, + SDP_ATTR_RTCP_UNICAST, + SDP_ATTR_MAXPRATE, + SDP_ATTR_SQN, + SDP_ATTR_CDSC, + SDP_ATTR_CPAR, + SDP_ATTR_SPRTMAP, + SDP_ATTR_SDESCRIPTIONS, /* version 9 sdescriptions */ + SDP_ATTR_LABEL, + SDP_ATTR_FRAMERATE, + SDP_ATTR_ICE_CANDIDATE, + SDP_ATTR_ICE_UFRAG, + SDP_ATTR_ICE_PWD, + SDP_ATTR_ICE_LITE, + SDP_ATTR_RTCP_MUX, + SDP_ATTR_DTLS_FINGERPRINT, + SDP_ATTR_MAXPTIME, + SDP_ATTR_RTCP_FB, /* RFC 4585 */ + SDP_ATTR_SETUP, + SDP_ATTR_CONNECTION, + SDP_ATTR_EXTMAP, /* RFC 5285 */ + SDP_ATTR_IDENTITY, + SDP_ATTR_MSID, + SDP_ATTR_MSID_SEMANTIC, + SDP_ATTR_BUNDLE_ONLY, + SDP_ATTR_END_OF_CANDIDATES, + SDP_ATTR_ICE_OPTIONS, + SDP_ATTR_SSRC, + SDP_ATTR_IMAGEATTR, + SDP_ATTR_SIMULCAST, + SDP_ATTR_RID, + SDP_ATTR_DTLS_MESSAGE, + SDP_ATTR_SCTPPORT, + SDP_ATTR_MAXMESSAGESIZE, + SDP_ATTR_SSRC_GROUP, + SDP_ATTR_RTCP_RSIZE, + SDP_MAX_ATTR_TYPES, + SDP_ATTR_INVALID +} sdp_attr_e; + +typedef enum { + SDP_SETUP_NOT_FOUND = -1, + SDP_SETUP_ACTIVE = 0, + SDP_SETUP_PASSIVE, + SDP_SETUP_ACTPASS, + SDP_SETUP_HOLDCONN, + SDP_MAX_SETUP, + SDP_SETUP_UNKNOWN +} sdp_setup_type_e; + +#endif diff --git a/third_party/sipcc/ccsdp_rtcp_fb.h b/third_party/sipcc/ccsdp_rtcp_fb.h new file mode 100644 index 0000000000..2f56210ba0 --- /dev/null +++ b/third_party/sipcc/ccsdp_rtcp_fb.h @@ -0,0 +1,65 @@ +/* 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/. */ + +#ifndef __CCSDP_RTCP_FB_H__ +#define __CCSDP_RTCP_FB_H__ + +/* a=rtcp-fb enumerations */ + +typedef enum { + SDP_RTCP_FB_ANY = -1, + SDP_RTCP_FB_ACK = 0, + SDP_RTCP_FB_CCM, + SDP_RTCP_FB_NACK, + SDP_RTCP_FB_TRR_INT, + // from https://www.ietf.org/archive/id/draft-alvestrand-rmcat-remb-03.txt + SDP_RTCP_FB_REMB, + // from https://tools.ietf.org/html/draft-holmer-rmcat-transport-wide-cc-extensions-01 + SDP_RTCP_FB_TRANSPORT_CC, + SDP_MAX_RTCP_FB, + SDP_RTCP_FB_UNKNOWN +} sdp_rtcp_fb_type_e; + +typedef enum { + SDP_RTCP_FB_NACK_NOT_FOUND = -1, + SDP_RTCP_FB_NACK_BASIC = 0, + SDP_RTCP_FB_NACK_SLI, + SDP_RTCP_FB_NACK_PLI, + SDP_RTCP_FB_NACK_RPSI, + SDP_RTCP_FB_NACK_APP, + SDP_RTCP_FB_NACK_RAI, + SDP_RTCP_FB_NACK_TLLEI, + SDP_RTCP_FB_NACK_PSLEI, + SDP_RTCP_FB_NACK_ECN, + SDP_MAX_RTCP_FB_NACK, + SDP_RTCP_FB_NACK_UNKNOWN +} sdp_rtcp_fb_nack_type_e; + +typedef enum { + SDP_RTCP_FB_ACK_NOT_FOUND = -1, + SDP_RTCP_FB_ACK_RPSI = 0, + SDP_RTCP_FB_ACK_APP, + SDP_MAX_RTCP_FB_ACK, + SDP_RTCP_FB_ACK_UNKNOWN +} sdp_rtcp_fb_ack_type_e; + +// Codec Control Messages - defined by RFC 5104 +typedef enum { + SDP_RTCP_FB_CCM_NOT_FOUND = -1, + SDP_RTCP_FB_CCM_FIR = 0, + SDP_RTCP_FB_CCM_TMMBR, + SDP_RTCP_FB_CCM_TSTR, + SDP_RTCP_FB_CCM_VBCM, + SDP_MAX_RTCP_FB_CCM, + SDP_RTCP_FB_CCM_UNKNOWN +} sdp_rtcp_fb_ccm_type_e; + +#ifdef __cplusplus +static_assert(SDP_MAX_RTCP_FB_NACK + + SDP_MAX_RTCP_FB_ACK + + SDP_MAX_RTCP_FB_CCM < 32, + "rtcp-fb Bitmap is larger than 32 bits"); +#endif + +#endif diff --git a/third_party/sipcc/cpr_darwin_types.h b/third_party/sipcc/cpr_darwin_types.h new file mode 100644 index 0000000000..97a2644b57 --- /dev/null +++ b/third_party/sipcc/cpr_darwin_types.h @@ -0,0 +1,68 @@ +/* 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/. */ + +#ifndef _CPR_DARWIN_TYPES_H_ +#define _CPR_DARWIN_TYPES_H_ + +#include <sys/types.h> +#include <sys/param.h> +#include <stddef.h> +#include "inttypes.h" + + +/** + * @typedef boolean + * + * Define boolean as an unsigned byte + * + * @note There are differences within TNP header files + * @li curses.h: bool => char + * @li types.h: boolean_t => enum + * @li dki_lock.h: bool_t => int + */ +typedef uint8_t boolean; + +/* + * Define min/max + * defined in param.h + * + * The GNU versions of the MAX and MIN macros do two things better than + * the old versions: + * 1. they are more optimal as they only evaluate a & b once by creating a + * a variable of each type on the local stack. + * 2. they fix potential errors due to side-effects where a and b were + * evaluated twice, i.e. MIN(i++,j++) + * + * @note b could be cast to a's type, to help with usage where the code + * compares signed and unsigned types. + */ +#ifndef MIN +#ifdef __GNUC__ +#define MIN(a,b) ({ typeof(a) _a = (a); typeof(b) _b = (b); _a < _b ? _a : _b; }) +#else +#define MIN(a,b) (((a) < (b)) ? (a) : (b)) +#endif +#endif + +#ifndef MAX +#ifdef __GNUC__ +#define MAX(a,b) ({ typeof(a) _a = (a); typeof(b) _b = (b); _a > _b ? _a : _b; }) +#else +#define MAX(a,b) (((a) > (b)) ? (a) : (b)) +#endif +#endif + +/** + * Define TRUE/FALSE + * defined in several header files + */ +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +#endif diff --git a/third_party/sipcc/cpr_linux_types.h b/third_party/sipcc/cpr_linux_types.h new file mode 100644 index 0000000000..78f05f413f --- /dev/null +++ b/third_party/sipcc/cpr_linux_types.h @@ -0,0 +1,82 @@ +/* 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/. */ + +#ifndef _CPR_LINUX_TYPES_H_ +#define _CPR_LINUX_TYPES_H_ + +#include "sys/types.h" +#include "stddef.h" +#include "inttypes.h" + +/** + * @typedef boolean + * + * Define boolean as an unsigned byte + * + * @note There are differences within TNP header files + * @li curses.h: bool => char + * @li types.h: boolean_t => enum + * @li dki_lock.h: bool_t => int + */ +typedef uint8_t boolean; + +/* + * Define size_t + * defined in numerous header files + */ +/* DONE (sys/types.h => unsigned int) */ + +/* + * Define ssize_t + */ +/* DONE (sys/types.h => int) */ + +/* + * Define MIN/MAX + * defined in param.h + * + * The GNU versions of the MAX and MIN macros do two things better than + * the old versions: + * 1. they are more optimal as they only evaluate a & b once by creating a + * a variable of each type on the local stack. + * 2. they fix potential errors due to side-effects where a and b were + * evaluated twice, i.e. MIN(i++,j++) + * + * @note b could be cast to a's type, to help with usage where the code + * compares signed and unsigned types. + */ +#ifndef MIN +#ifdef __GNUC__ +#define MIN(a,b) ({ typeof(a) _a = (a); typeof(b) _b = (b); _a < _b ? _a : _b; }) +#else +#define MIN(a,b) (((a) < (b)) ? (a) : (b)) +#endif +#endif + +#ifndef MAX +#ifdef __GNUC__ +#define MAX(a,b) ({ typeof(a) _a = (a); typeof(b) _b = (b); _a > _b ? _a : _b; }) +#else +#define MAX(a,b) (((a) > (b)) ? (a) : (b)) +#endif +#endif + +/** + * Define TRUE/FALSE + * defined in several header files + */ +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +/* + * Define offsetof + */ +/* DONE (stddef.h) */ + +#endif diff --git a/third_party/sipcc/cpr_string.c b/third_party/sipcc/cpr_string.c new file mode 100644 index 0000000000..1e97c186ae --- /dev/null +++ b/third_party/sipcc/cpr_string.c @@ -0,0 +1,278 @@ +/* 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 <stdarg.h> + +#include "mozilla/Assertions.h" +#include "cpr_types.h" +#include "cpr_string.h" +#include "cpr_strings.h" + +/* From cpr_stdlib.h */ +#ifdef CPR_STRING_USE_FALLIBLE_MALLOC +#define cpr_malloc(a) malloc(a) +#define cpr_calloc(a, b) calloc(a, b) +#define cpr_realloc(a, b) realloc(a, b) +#define cpr_free(a) free(a) +#else +#include "mozilla/mozalloc.h" + +#define cpr_malloc(a) moz_xmalloc(a) +#define cpr_calloc(a, b) moz_xcalloc(a, b) +#define cpr_realloc(a, b) moz_xrealloc(a, b) +#define cpr_free(a) free(a) +#endif + +/** + * sstrncpy + * + * This is Cisco's *safe* version of strncpy. The string will always + * be NUL terminated (which is not ANSI compliant). + * + * Parameters: s1 - first string + * s2 - second string + * max - maximum length in octets to concat. + * + * Return: Pointer to the *end* of the string + * + * Remarks: Modified to be explicitly safe for all inputs. + * Also return the number of characters copied excluding the + * NUL terminator vs. the original string s1. This simplifies + * code where sstrncat functions follow. + */ +unsigned long +sstrncpy (char *dst, const char *src, unsigned long max) +{ + unsigned long cnt = 0; + + if (dst == NULL) { + return 0; + } + + if (src) { + while ((max-- > 1) && (*src)) { + *dst = *src; + dst++; + src++; + cnt++; + } + } + +#if defined(CPR_SSTRNCPY_PAD) + /* + * To be equivalent to the TI compiler version + * v2.01, SSTRNCPY_PAD needs to be defined + */ + while (max-- > 1) { + *dst = '\0'; + dst++; + } +#endif + *dst = '\0'; + + return cnt; +} + +/** + * sstrncat + * + * This is Cisco's *safe* version of strncat. The string will always + * be NUL terminated (which is not ANSI compliant). + * + * Parameters: s1 - first string + * s2 - second string + * max - maximum length in octets to concatenate + * + * Return: Pointer to the *end* of the string + * + * Remarks: Modified to be explicitly safe for all inputs. + * Also return the end vs. the beginning of the string s1 + * which is useful for multiple sstrncat calls. + */ +char * +sstrncat (char *s1, const char *s2, unsigned long max) +{ + if (s1 == NULL) + return (char *) NULL; + + while (*s1) + s1++; + + if (s2) { + while ((max-- > 1) && (*s2)) { + *s1 = *s2; + s1++; + s2++; + } + } + *s1 = '\0'; + + return s1; +} + +/* + * flex_string + */ + +/* + * flex_string_init + * + * Not thread-safe + */ +void flex_string_init(flex_string *fs) { + fs->buffer_length = FLEX_STRING_CHUNK_SIZE; + fs->string_length = 0; + fs->buffer = cpr_malloc(fs->buffer_length); + fs->buffer[0] = '\0'; +} + +/* + * flex_string_free + * + * Not thread-safe + */ +void flex_string_free(flex_string *fs) { + fs->buffer_length = 0; + fs->string_length = 0; + cpr_free(fs->buffer); + fs->buffer = NULL; +} + +/* For sanity check before alloc */ +#define FLEX_STRING_MAX_SIZE (10 * 1024 * 1024) /* 10MB */ + +/* + * flex_string_check_alloc + * + * Allocate enough chunks to hold the new minimum size. + * + * Not thread-safe + */ +void flex_string_check_alloc(flex_string *fs, size_t new_min_length) { + if (new_min_length > fs->buffer_length) { + /* Oversize, allocate more */ + + /* Sanity check on allocation size */ + if (new_min_length > FLEX_STRING_MAX_SIZE) { + MOZ_CRASH(); + } + + /* Alloc to nearest chunk */ + fs->buffer_length = (((new_min_length - 1) / FLEX_STRING_CHUNK_SIZE) + 1) * FLEX_STRING_CHUNK_SIZE; + + fs->buffer = cpr_realloc(fs->buffer, fs->buffer_length); + } +} + +/* + * flex_string_append + * + * Not thread-safe + */ +void flex_string_append(flex_string *fs, const char *more) { + fs->string_length += strlen(more); + + flex_string_check_alloc(fs, fs->string_length + 1); + + sstrncat(fs->buffer, more, fs->buffer_length - strlen(fs->buffer)); +} + +/* + * va_copy is part of the C99 spec but MSVC doesn't have it. + */ +#ifndef va_copy +#define va_copy(d,s) ((d) = (s)) +#endif + +/* + * flex_string_vsprintf + * + * Not thread-safe + */ +void flex_string_vsprintf(flex_string *fs, const char *format, va_list original_ap) { + va_list ap; + int vsnprintf_result; + + va_copy(ap, original_ap); + vsnprintf_result = vsnprintf(fs->buffer + fs->string_length, fs->buffer_length - fs->string_length, format, ap); + va_end(ap); + + /* Special case just for Windows where vsnprintf is broken + and returns -1 if buffer too large unless you size it 0. */ + if (vsnprintf_result < 0) { + va_copy(ap, original_ap); + vsnprintf_result = vsnprintf(NULL, 0, format, ap); + va_end(ap); + } + + if (fs->string_length + vsnprintf_result >= fs->buffer_length) { + /* Buffer overflow, resize */ + flex_string_check_alloc(fs, fs->string_length + vsnprintf_result + 1); + + /* Try again with new buffer */ + va_copy(ap, original_ap); + vsnprintf_result = vsnprintf(fs->buffer + fs->string_length, fs->buffer_length - fs->string_length, format, ap); + va_end(ap); + MOZ_ASSERT(vsnprintf_result > 0 && + (size_t)vsnprintf_result < (fs->buffer_length - fs->string_length)); + } + + if (vsnprintf_result > 0) { + fs->string_length += vsnprintf_result; + } +} + +/* + * flex_string_sprintf + * + * Not thread-safe + */ +void flex_string_sprintf(flex_string *fs, const char *format, ...) { + va_list ap; + + va_start(ap, format); + flex_string_vsprintf(fs, format, ap); + va_end(ap); +} + + + +/* From cpr_linux_string.c */ +/** + * cpr_strdup + * + * @brief The CPR wrapper for strdup + + * The cpr_strdup shall return a pointer to a new string, which is a duplicate + * of the string pointed to by "str" argument. A null pointer is returned if the + * new string cannot be created. + * + * @param[in] str - The string that needs to be duplicated + * + * @return The duplicated string or NULL in case of no memory + * + */ +char * +cpr_strdup (const char *str) +{ + char *dup; + size_t len; + + if (!str) { + return (char *) NULL; + } + + len = strlen(str); + if (len == 0) { + return (char *) NULL; + } + len++; + + dup = cpr_malloc(len * sizeof(char)); + if (!dup) { + return (char *) NULL; + } + (void) memcpy(dup, str, len); + return dup; +} diff --git a/third_party/sipcc/cpr_string.h b/third_party/sipcc/cpr_string.h new file mode 100644 index 0000000000..de6b1cc8a0 --- /dev/null +++ b/third_party/sipcc/cpr_string.h @@ -0,0 +1,139 @@ +/* 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/. */ + +#ifndef _CPR_STRING_H_ +#define _CPR_STRING_H_ + +#include <stdarg.h> + +#include "cpr_types.h" +#include "cpr_strings.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * sstrncpy + * + * @brief The CPR wrapper for strncpy + * + * This is Cisco's *safe* version of strncpy. The string will always + * be NUL terminated (which is not ANSI compliant). + * + * @param[in] dst - The destination string + * @param[in] src - The source + * @param[in] max - maximum length in octets to concatenate + * + * @return Pointer to the @b end of the string + * + * @note Modified to be explicitly safe for all inputs. + * Also return the number of characters copied excluding the + * NUL terminator vs. the original string s1. This simplifies + * code where sstrncat functions follow. + */ +unsigned long +sstrncpy(char *dst, const char *src, unsigned long max); + + +/** + * sstrncat + * + * @brief The CPR wrapper for strncat + * + * This is Cisco's *safe* version of strncat. The string will always + * be NUL terminated (which is not ANSI compliant). + * + * @param[in] s1 - first string + * @param[in] s2 - second string + * @param[in] max - maximum length in octets to concatenate + * + * @return Pointer to the @b end of the string + * + * @note Modified to be explicitly safe for all inputs. + * Also return the end vs. the beginning of the string s1 + * which is useful for multiple sstrncat calls. + */ +char * +sstrncat(char *s1, const char *s2, unsigned long max); + + +/* + * flex_string + */ +#define FLEX_STRING_CHUNK_SIZE 256 + +typedef struct { + char *buffer; + size_t buffer_length; + size_t string_length; +} flex_string; + +/* + * flex_string_init + * + * Not thread-safe + */ +void flex_string_init(flex_string *fs); + +/* + * flex_string_free + * + * Not thread-safe + */ +void flex_string_free(flex_string *fs); + +/* + * flex_string_check_alloc + * + * Allocate enough chunks to hold the new minimum size. + * + * Not thread-safe + */ +void flex_string_check_alloc(flex_string *fs, size_t new_min_length); + +/* + * flex_string_append + * + * Not thread-safe + */ +void flex_string_append(flex_string *fs, const char *more); + +/* + * flex_string_sprintf + * + * Not thread-safe + */ +void flex_string_vsprintf(flex_string *fs, const char *format, va_list original_ap); + +/* + * flex_string_sprintf + * + * Not thread-safe + */ +void flex_string_sprintf(flex_string *fs, const char *format, ...); + + +/* From cpr_linux_string.h */ +/* cpr_strdup + * + * @brief The CPR wrapper for strdup + + * The cpr_strdup shall return a pointer to a new string, which is a duplicate + * of the string pointed to by "str" argument. A null pointer is returned if the + * new string cannot be created. + * + * @param[in] str - The string that needs to be duplicated + * + * @return The duplicated string or NULL in case of no memory + * + */ +char * +cpr_strdup(const char *str); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/sipcc/cpr_strings.h b/third_party/sipcc/cpr_strings.h new file mode 100644 index 0000000000..2d18d4638a --- /dev/null +++ b/third_party/sipcc/cpr_strings.h @@ -0,0 +1,22 @@ +/* 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/. */ + +#ifndef _CPR_STRINGS_H_ +#define _CPR_STRINGS_H_ + +#include "cpr_types.h" + +#include <string.h> + +#if defined(_MSC_VER) +#define cpr_strcasecmp _stricmp +#define cpr_strncasecmp _strnicmp +#else // _MSC_VER + +#define cpr_strcasecmp strcasecmp +#define cpr_strncasecmp strncasecmp + +#endif // _MSC_VER + +#endif diff --git a/third_party/sipcc/cpr_types.h b/third_party/sipcc/cpr_types.h new file mode 100644 index 0000000000..f048e72be1 --- /dev/null +++ b/third_party/sipcc/cpr_types.h @@ -0,0 +1,128 @@ +/* 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/. */ + +#ifndef _CPR_TYPES_H_ +#define _CPR_TYPES_H_ + +#include <inttypes.h> + +#if defined SIP_OS_LINUX +#include "cpr_linux_types.h" +#elif defined SIP_OS_WINDOWS +#include "cpr_win_types.h" +#elif defined SIP_OS_OSX +#include "cpr_darwin_types.h" +#else +//lol +//#error "Unsupported platform" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * CPR Return Codes + */ +typedef enum +{ + CPR_SUCCESS, + CPR_FAILURE +} cpr_status_e; +typedef cpr_status_e cprRC_t; + +/* + * IPv4 address structure + */ +typedef uint32_t cpr_in_addr_t; + +struct in_addr_s +{ +#ifdef s_addr + /* can occur with Windows winsock.h */ + union { + struct { + unsigned char s_b1, s_b2, sb_b3, s_b4; + } S_un_b; + cpr_in_addr_t S_addr; + } S_un; +#else + cpr_in_addr_t s_addr; +#endif +}; + +/* + * IPv6 address structure + */ +typedef struct +{ + union + { + uint8_t base8[16]; + uint16_t base16[8]; + uint32_t base32[4]; + } addr; +} cpr_in6_addr_t; + +#ifndef s6_addr +#define s6_addr addr.base8 +#endif +#ifndef s6_addr16 +#define s6_addr16 addr.base16 +#endif +#ifndef s6_addr32 +#define s6_addr32 addr.base32 +#endif + +typedef enum +{ + CPR_IP_ADDR_INVALID=0, + CPR_IP_ADDR_IPV4, + CPR_IP_ADDR_IPV6 +} cpr_ip_type; + +typedef enum +{ + CPR_IP_MODE_IPV4 = 0, + CPR_IP_MODE_IPV6, + CPR_IP_MODE_DUAL +} +cpr_ip_mode_e; +/* + * IP address structure + */ +typedef struct +{ + cpr_ip_type type; + union + { + cpr_in_addr_t ip4; + cpr_in6_addr_t ip6; + } u; +} cpr_ip_addr_t; + +extern const cpr_ip_addr_t ip_addr_invalid; + +#define MAX_IPADDR_STR_LEN 48 + + +#define CPR_IP_ADDR_INIT(a) a.type = CPR_IP_ADDR_INVALID; + +/* + * !!! NOTE !!! + * + * The strings of type string_t are actually very special blocks + * of memory that have a "hidden" header block immediately preceding + * the pointer. You MUST use the functions in string_lib.c to + * create, manipulate, destroy, copy, or otherwise work with these + * strings. + */ + +typedef const char *string_t; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/sipcc/cpr_win_types.h b/third_party/sipcc/cpr_win_types.h new file mode 100644 index 0000000000..c4dfa0b72a --- /dev/null +++ b/third_party/sipcc/cpr_win_types.h @@ -0,0 +1,71 @@ +/* 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/. */ + +#ifndef _CPR_WIN_TYPES_H_ +#define _CPR_WIN_TYPES_H_ + +#include <sys/types.h> + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif + +#include <windows.h> +#ifdef SIPCC_BUILD +#include <winsock2.h> +#include <ws2tcpip.h> +#include <windef.h> +#endif +#include <stddef.h> +#include <stdlib.h> + +/* + * Define POSIX types + * [u]int[8,16,32,64]_t + */ +#include <stdint.h> + +/* + * Define boolean + * in windef.h: BOOL => int + */ +typedef uint8_t boolean; + +/* + * Define ssize_t if required. The MinGW W32API already defines ssize_t + * in <sys/types.h> (protected by _SSIZE_T_) so this will only apply to + * Microsoft SDK. + * + * NOTE: size_t should already be declared by both the MinGW and Microsoft + * SDKs. + */ +#ifndef _SSIZE_T_ +#define _SSIZE_T_ +typedef int ssize_t; +#endif + +/* + * Define pid_t. + */ +typedef int pid_t; + +/* + * Define min/max + * defined in windef.h as lowercase + */ +#ifndef MIN +#define MIN min +#endif + +#ifndef MAX +#define MAX max +#endif + +/* + * Define NULL + * defined in numerous header files + */ +/* DONE defined in windef.h */ + +#endif // _CPR_WIN_TYPES_H_ diff --git a/third_party/sipcc/moz.build b/third_party/sipcc/moz.build new file mode 100644 index 0000000000..851032c370 --- /dev/null +++ b/third_party/sipcc/moz.build @@ -0,0 +1,45 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# 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/. +if CONFIG['MOZ_WEBRTC_SIGNALING']: + if CONFIG['OS_TARGET'] == 'WINNT': + DEFINES['SIP_OS_WINDOWS'] = True + SOURCES += [ + 'sdp_services_win32.c', + ] + elif CONFIG['OS_TARGET'] == 'Darwin': + DEFINES['SIP_OS_OSX'] = True + SOURCES += [ + 'sdp_services_unix.c', + ] + else: + DEFINES['SIP_OS_LINUX'] = True + SOURCES += [ + 'sdp_services_unix.c', + ] + + # Add libFuzzer configuration directives + include('/tools/fuzzing/libfuzzer-config.mozbuild') + + EXPORTS += [ + 'sdp_log.h', + 'sipcc_sdp.h', + ] + + SOURCES += [ + # Multiple definitions of "logTag" mean we can't use unified build here. + 'cpr_string.c', + 'sdp_access.c', + 'sdp_attr.c', + 'sdp_attr_access.c', + 'sdp_base64.c', + 'sdp_config.c', + 'sdp_main.c', + 'sdp_token.c', + 'sdp_utils.c', + ] + + FINAL_LIBRARY = 'xul' + diff --git a/third_party/sipcc/sdp_access.c b/third_party/sipcc/sdp_access.c new file mode 100644 index 0000000000..8a065e2a6a --- /dev/null +++ b/third_party/sipcc/sdp_access.c @@ -0,0 +1,2100 @@ +/* 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 "sdp_os_defs.h" +#include "sipcc_sdp.h" +#include "sdp_private.h" + +#include "sdp_log.h" + +static const char* logTag = "sdp_access"; + +/* Pulled in from ccsip_sdp.h */ +/* Possible encoding names of static payload types*/ +#define SIPSDP_ATTR_ENCNAME_PCMU "PCMU" +#define SIPSDP_ATTR_ENCNAME_PCMA "PCMA" +#define SIPSDP_ATTR_ENCNAME_G729 "G729" +#define SIPSDP_ATTR_ENCNAME_G723 "G723" +#define SIPSDP_ATTR_ENCNAME_G726 "G726-32" +#define SIPSDP_ATTR_ENCNAME_G728 "G728" +#define SIPSDP_ATTR_ENCNAME_GSM "GSM" +#define SIPSDP_ATTR_ENCNAME_CN "CN" +#define SIPSDP_ATTR_ENCNAME_G722 "G722" +#define SIPSDP_ATTR_ENCNAME_ILBC "iLBC" +#define SIPSDP_ATTR_ENCNAME_H263v2 "H263-1998" +#define SIPSDP_ATTR_ENCNAME_H264 "H264" +#define SIPSDP_ATTR_ENCNAME_VP8 "VP8" +#define SIPSDP_ATTR_ENCNAME_VP9 "VP9" +#define SIPSDP_ATTR_ENCNAME_L16_256K "L16" +#define SIPSDP_ATTR_ENCNAME_ISAC "ISAC" +#define SIPSDP_ATTR_ENCNAME_OPUS "opus" +#define SIPSDP_ATTR_ENCNAME_RED "red" +#define SIPSDP_ATTR_ENCNAME_ULPFEC "ulpfec" +#define SIPSDP_ATTR_ENCNAME_TELEPHONE_EVENT "telephone-event" +#define SIPSDP_ATTR_ENCNAME_RTX "rtx" + +/* Function: sdp_find_media_level + * Description: Find and return a pointer to the specified media level, + * if it exists. + * Note: This is not an API for the application but an internal + * routine used by the SDP library. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The media level to find. + * Returns: Pointer to the media level or NULL if not found. + */ +sdp_mca_t *sdp_find_media_level (sdp_t *sdp_p, uint16_t level) +{ + int i; + sdp_mca_t *mca_p = NULL; + + if ((level >= 1) && (level <= sdp_p->mca_count)) { + for (i=1, mca_p = sdp_p->mca_p; + ((i < level) && (mca_p != NULL)); + mca_p = mca_p->next_p, i++) { + + /*sa_ignore EMPTYLOOP*/ + ; /* Do nothing. */ + } + } + + return (mca_p); +} + +/* Function: sdp_version_valid + * Description: Returns true or false depending on whether the version + * set for this SDP is valid. Currently the only valid + * version is 0. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * Returns: TRUE or FALSE. + */ +tinybool sdp_version_valid (sdp_t *sdp_p) +{ + if (sdp_p->version == SDP_INVALID_VALUE) { + return (FALSE); + } else { + return (TRUE); + } +} + +/* Function: sdp_get_version + * Description: Returns the version value set for the given SDP. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * Returns: Version value. + */ +int32_t sdp_get_version (sdp_t *sdp_p) +{ + return (sdp_p->version); +} + +/* Function: sdp_set_version + * Description: Sets the value of the version parameter for the v= version + * token line. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * version Version to set. + * Returns: SDP_SUCCESS + */ +sdp_result_e sdp_set_version (sdp_t *sdp_p, int32_t version) +{ + sdp_p->version = version; + return (SDP_SUCCESS); +} + +/* Function: sdp_owner_valid + * Description: Returns true or false depending on whether the owner + * token line has been defined for this SDP. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * Returns: TRUE or FALSE. + */ +tinybool sdp_owner_valid (sdp_t *sdp_p) +{ + if ((sdp_p->owner_name[0] == '\0') || + (sdp_p->owner_network_type == SDP_NT_INVALID) || + (sdp_p->owner_addr_type == SDP_AT_INVALID) || + (sdp_p->owner_addr[0] == '\0')) { + return (FALSE); + } else { + return (TRUE); + } +} + +/* Function: sdp_get_owner_username + * Description: Returns a pointer to the value of the username parameter + * from the o= owner token line. Value is returned as a + * const ptr and so cannot be modified by the application. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * Returns: Version value. + */ +const char *sdp_get_owner_username (sdp_t *sdp_p) +{ + return (sdp_p->owner_name); +} + +/* Function: sdp_get_owner_sessionid + * Description: Returns the session id parameter from the o= owner token + * line. Because the value may be larger than 32 bits, this + * parameter is returned as a string, though has been verified + * to be numeric. Value is returned as a const ptr and so + * cannot be modified by the application. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * Returns: Ptr to owner session id or NULL. + */ +const char *sdp_get_owner_sessionid (sdp_t *sdp_p) +{ + return (sdp_p->owner_sessid); +} + +/* Function: sdp_get_owner_version + * Description: Returns the version parameter from the o= owner token + * line. Because the value may be larger than 32 bits, this + * parameter is returned as a string, though has been verified + * to be numeric. Value is returned as a const ptr and so + * cannot be modified by the application. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * Returns: Ptr to owner version or NULL. + */ +const char *sdp_get_owner_version (sdp_t *sdp_p) +{ + return (sdp_p->owner_version); +} + +/* Function: sdp_get_owner_network_type + * Description: Returns the network type parameter from the o= owner token + * line. If network type has not been set SDP_NT_INVALID will + * be returned. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * Returns: Network type or SDP_NT_INVALID. + */ +sdp_nettype_e sdp_get_owner_network_type (sdp_t *sdp_p) +{ + return (sdp_p->owner_network_type); +} + +/* Function: sdp_get_owner_address_type + * Description: Returns the address type parameter from the o= owner token + * line. If address type has not been set SDP_AT_INVALID will + * be returned. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * Returns: Address type or SDP_AT_INVALID. + */ +sdp_addrtype_e sdp_get_owner_address_type (sdp_t *sdp_p) +{ + return (sdp_p->owner_addr_type); +} + +/* Function: sdp_get_owner_address + * Description: Returns the address parameter from the o= owner token + * line. Value is returned as a const ptr and so + * cannot be modified by the application. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * Returns: Ptr to address or NULL. + */ +const char *sdp_get_owner_address (sdp_t *sdp_p) +{ + return (sdp_p->owner_addr); +} + +/* Function: sdp_set_owner_username + * Description: Sets the value of the username parameter for the o= owner + * token line. The string is copied into the SDP structure + * so application memory will not be referenced by the SDP lib. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * username Ptr to the username string. + * Returns: SDP_SUCCESS + */ +sdp_result_e sdp_set_owner_username (sdp_t *sdp_p, const char *username) +{ + sstrncpy(sdp_p->owner_name, username, sizeof(sdp_p->owner_name)); + return (SDP_SUCCESS); +} + +/* Function: sdp_set_owner_username + * Description: Sets the value of the session id parameter for the o= owner + * token line. The string is copied into the SDP structure + * so application memory will not be referenced by the SDP lib. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * sessionid Ptr to the sessionid string. + * Returns: SDP_SUCCESS + */ +sdp_result_e sdp_set_owner_sessionid (sdp_t *sdp_p, const char *sessionid) +{ + sstrncpy(sdp_p->owner_sessid, sessionid, sizeof(sdp_p->owner_sessid)); + return (SDP_SUCCESS); +} + +/* Function: sdp_set_owner_version + * Description: Sets the value of the version parameter for the o= owner + * token line. The string is copied into the SDP structure + * so application memory will not be referenced by the SDP lib. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * version Ptr to the version string. + * Returns: SDP_SUCCESS + */ +sdp_result_e sdp_set_owner_version (sdp_t *sdp_p, const char *version) +{ + sstrncpy(sdp_p->owner_version, version, sizeof(sdp_p->owner_version)); + return (SDP_SUCCESS); +} + +/* Function: sdp_set_owner_network_type + * Description: Sets the value of the network type parameter for the o= owner + * token line. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * network_type Network type for the owner line. + * Returns: SDP_SUCCESS + */ +sdp_result_e sdp_set_owner_network_type (sdp_t *sdp_p, + sdp_nettype_e network_type) +{ + sdp_p->owner_network_type = network_type; + return (SDP_SUCCESS); +} + +/* Function: sdp_set_owner_address_type + * Description: Sets the value of the address type parameter for the o= owner + * token line. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * address_type Address type for the owner line. + * Returns: SDP_SUCCESS + */ +sdp_result_e sdp_set_owner_address_type (sdp_t *sdp_p, + sdp_addrtype_e address_type) +{ + sdp_p->owner_addr_type = address_type; + return (SDP_SUCCESS); +} + +/* Function: sdp_set_owner_address + * Description: Sets the value of the address parameter for the o= owner + * token line. The string is copied into the SDP structure + * so application memory will not be referenced by the SDP lib. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * version Ptr to the version string. + * Returns: SDP_SUCCESS + */ +sdp_result_e sdp_set_owner_address (sdp_t *sdp_p, const char *address) +{ + sstrncpy(sdp_p->owner_addr, address, sizeof(sdp_p->owner_addr)); + return (SDP_SUCCESS); +} + +/* Function: sdp_session_name_valid + * Description: Returns true or false depending on whether the session name + * s= token line has been defined for this SDP. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * Returns: TRUE or FALSE. + */ +tinybool sdp_session_name_valid (sdp_t *sdp_p) +{ + if (sdp_p->sessname[0] == '\0') { + return (FALSE); + } else { + return (TRUE); + } +} + +/* Function: sdp_get_session_name + * Description: Returns the session name parameter from the s= session + * name token line. Value is returned as a const ptr and so + * cannot be modified by the application. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * Returns: Ptr to session name or NULL. + */ +const char *sdp_get_session_name (sdp_t *sdp_p) +{ + return (sdp_p->sessname); +} + +/* Function: sdp_set_session_name + * Description: Sets the value of the session name parameter for the s= + * session name token line. The string is copied into the + * SDP structure so application memory will not be + * referenced by the SDP lib. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * sessname Ptr to the session name string. + * Returns: SDP_SUCCESS + */ +sdp_result_e sdp_set_session_name (sdp_t *sdp_p, const char *sessname) +{ + sstrncpy(sdp_p->sessname, sessname, sizeof(sdp_p->sessname)); + return (SDP_SUCCESS); +} + +/* Function: sdp_timespec_valid + * Description: Returns true or false depending on whether the timespec t= + * token line has been defined for this SDP. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * Returns: TRUE or FALSE. + */ +tinybool sdp_timespec_valid (sdp_t *sdp_p) +{ + if ((sdp_p->timespec_p == NULL) || + (sdp_p->timespec_p->start_time[0] == '\0') || + (sdp_p->timespec_p->stop_time[0] == '\0')) { + return (FALSE); + } else { + return (TRUE); + } +} + +/* Function: sdp_get_time_start + * Description: Returns the start time parameter from the t= timespec token + * line. Because the value may be larger than 32 bits, this + * parameter is returned as a string, though has been verified + * to be numeric. Value is returned as a const ptr and so + * cannot be modified by the application. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * Returns: Ptr to start time or NULL. + */ +const char *sdp_get_time_start (sdp_t *sdp_p) +{ + if (sdp_p->timespec_p != NULL) { + return (sdp_p->timespec_p->start_time); + } else { + return (NULL); + } +} + +/* Function: sdp_get_time_stop + * Description: Returns the stop time parameter from the t= timespec token + * line. Because the value may be larger than 32 bits, this + * parameter is returned as a string, though has been verified + * to be numeric. Value is returned as a const ptr and so + * cannot be modified by the application. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * Returns: Ptr to stop time or NULL. + */ +const char *sdp_get_time_stop (sdp_t *sdp_p) +{ + if (sdp_p->timespec_p != NULL) { + return (sdp_p->timespec_p->stop_time); + } else { + return (NULL); + } +} + +/* Function: sdp_set_time_start + * Description: Sets the value of the start time parameter for the t= + * timespec token line. The string is copied into the + * SDP structure so application memory will not be + * referenced by the SDP lib. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * start_time Ptr to the start time string. + * Returns: SDP_SUCCESS + */ +sdp_result_e sdp_set_time_start (sdp_t *sdp_p, const char *start_time) +{ + if (sdp_p->timespec_p == NULL) { + sdp_p->timespec_p = (sdp_timespec_t *)SDP_MALLOC(sizeof(sdp_timespec_t)); + if (sdp_p->timespec_p == NULL) { + sdp_p->conf_p->num_no_resource++; + return (SDP_NO_RESOURCE); + } + sdp_p->timespec_p->start_time[0] = '\0'; + sdp_p->timespec_p->stop_time[0] = '\0'; + } + sstrncpy(sdp_p->timespec_p->start_time, start_time, + sizeof(sdp_p->timespec_p->start_time)); + return (SDP_SUCCESS); +} + +/* Function: sdp_set_time_stop + * Description: Sets the value of the stop time parameter for the t= + * timespec token line. The string is copied into the + * SDP structure so application memory will not be + * referenced by the SDP lib. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * stop_time Ptr to the stop time string. + * Returns: SDP_SUCCESS + */ +sdp_result_e sdp_set_time_stop (sdp_t *sdp_p, const char *stop_time) +{ + if (sdp_p->timespec_p == NULL) { + sdp_p->timespec_p = (sdp_timespec_t *)SDP_MALLOC(sizeof(sdp_timespec_t)); + if (sdp_p->timespec_p == NULL) { + sdp_p->conf_p->num_no_resource++; + return (SDP_NO_RESOURCE); + } + sdp_p->timespec_p->start_time[0] = '\0'; + sdp_p->timespec_p->stop_time[0] = '\0'; + } + sstrncpy(sdp_p->timespec_p->stop_time, stop_time, + sizeof(sdp_p->timespec_p->stop_time)); + return (SDP_SUCCESS); +} + +/* Function: sdp_encryption_valid + * Description: Returns true or false depending on whether the encryption k= + * token line has been defined for this SDP at the given level. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the k= line. Will be + * either SDP_SESSION_LEVEL or 1-n specifying a + * media line level. + * Returns: TRUE or FALSE. + */ +tinybool sdp_encryption_valid (sdp_t *sdp_p, uint16_t level) +{ + 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 (FALSE); + } + encrypt_p = &(mca_p->encrypt); + } + + if ((encrypt_p->encrypt_type == SDP_ENCRYPT_INVALID) || + ((encrypt_p->encrypt_type != SDP_ENCRYPT_PROMPT) && + (encrypt_p->encrypt_key[0] == '\0'))) { + return (FALSE); + } else { + return (TRUE); + } +} + +/* Function: sdp_get_encryption_method + * Description: Returns the encryption method parameter from the k= + * encryption token line. If encryption method has not been + * set SDP_ENCRYPT_INVALID will be returned. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the c= line. Will be + * either SDP_SESSION_LEVEL or 1-n specifying a + * media line level. + * Returns: Encryption method or SDP_ENCRYPT_INVALID. + */ +sdp_encrypt_type_e sdp_get_encryption_method (sdp_t *sdp_p, uint16_t level) +{ + 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_ENCRYPT_INVALID); + } + encrypt_p = &(mca_p->encrypt); + } + + return (encrypt_p->encrypt_type); +} + +/* Function: sdp_get_encryption_key + * Description: Returns a pointer to the encryption key parameter + * from the k= encryption token line. Value is returned as a + * const ptr and so cannot be modified by the application. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the c= line. Will be + * either SDP_SESSION_LEVEL or 1-n specifying a + * media line level. + * Returns: Ptr to encryption key or NULL. + */ +const char *sdp_get_encryption_key (sdp_t *sdp_p, uint16_t level) +{ + 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 (NULL); + } + encrypt_p = &(mca_p->encrypt); + } + + return (encrypt_p->encrypt_key); +} + +/* Function: sdp_connection_valid + * Description: Returns true or false depending on whether the connection c= + * token line has been defined for this SDP at the given level. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the c= line. Will be + * either SDP_SESSION_LEVEL or 1-n specifying a + * media line level. + * Returns: TRUE or FALSE. + */ +tinybool sdp_connection_valid (sdp_t *sdp_p, uint16_t level) +{ + sdp_conn_t *conn_p; + sdp_mca_t *mca_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 (FALSE); + } + conn_p = &(mca_p->conn); + } + + /*if network type is ATM . then allow c= line without address type + * and address . This is a special case to cover PVC + */ + if (conn_p->nettype == SDP_NT_ATM && + conn_p->addrtype == SDP_AT_INVALID) { + return TRUE; + } + + if ((conn_p->nettype >= SDP_MAX_NETWORK_TYPES) || + (conn_p->addrtype >= SDP_MAX_ADDR_TYPES) || + (conn_p->conn_addr[0] == '\0')) { + return (FALSE); + } else { + return (TRUE); + } +} + +/* Function: sdp_bandwidth_valid + * Description: Returns true or false depending on whether the bandwidth b= + * token line has been defined for this SDP at the given level. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the c= line. Will be + * either SDP_SESSION_LEVEL or 1-n specifying a + * media line level. + * inst_num instance number of bw line at that level. The first + * instance has a inst_num of 1 and so on. + * Returns: TRUE or FALSE. + */ +tinybool sdp_bandwidth_valid (sdp_t *sdp_p, uint16_t level, uint16_t inst_num) +{ + sdp_bw_data_t *bw_data_p; + + bw_data_p = sdp_find_bw_line(sdp_p, level, inst_num); + if (bw_data_p != NULL) { + if ((bw_data_p->bw_modifier < SDP_BW_MODIFIER_AS) || + (bw_data_p->bw_modifier >= SDP_MAX_BW_MODIFIER_VAL)) { + return FALSE; + } else { + return TRUE; + } + } else { + return FALSE; + } +} + +/* + * sdp_bw_line_exists + * + * Description: This api retruns true if there exists a bw line at the + * instance and level specified. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the c= line. Will be + * either SDP_SESSION_LEVEL or 1-n specifying a + * media line level. + * inst_num instance number of bw line at that level. The first + * instance has a inst_num of 1 and so on. + * Returns: TRUE or FALSE + */ +tinybool sdp_bw_line_exists (sdp_t *sdp_p, uint16_t level, uint16_t inst_num) +{ + sdp_bw_data_t *bw_data_p; + + bw_data_p = sdp_find_bw_line(sdp_p, level, inst_num); + if (bw_data_p != NULL) { + return TRUE; + } else { + return FALSE; + } +} + +/* Function: sdp_get_conn_nettype + * Description: Returns the network type parameter from the c= + * connection token line. If network type has not been + * set SDP_NT_INVALID will be returned. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the c= line. Will be + * either SDP_SESSION_LEVEL or 1-n specifying a + * media line level. + * Returns: Network type or SDP_NT_INVALID. + */ +sdp_nettype_e sdp_get_conn_nettype (sdp_t *sdp_p, uint16_t level) +{ + sdp_conn_t *conn_p; + sdp_mca_t *mca_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_NT_INVALID); + } + conn_p = &(mca_p->conn); + } + + return (conn_p->nettype); +} + +/* Function: sdp_get_conn_addrtype + * Description: Returns the address type parameter from the c= + * connection token line. If address type has not been + * set SDP_AT_INVALID will be returned. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the c= line. Will be + * either SDP_SESSION_LEVEL or 1-n specifying a + * media line level. + * Returns: Address type or SDP_AT_INVALID. + */ +sdp_addrtype_e sdp_get_conn_addrtype (sdp_t *sdp_p, uint16_t level) +{ + sdp_conn_t *conn_p; + sdp_mca_t *mca_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_AT_INVALID); + } + conn_p = &(mca_p->conn); + } + + return (conn_p->addrtype); +} + +/* Function: sdp_get_conn_address + * Description: Returns a pointer to the address parameter + * from the c= connection token line. Value is returned as a + * const ptr and so cannot be modified by the application. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the c= line. Will be + * either SDP_SESSION_LEVEL or 1-n specifying a + * media line level. + * Returns: Ptr to address or NULL. + */ +const char *sdp_get_conn_address (sdp_t *sdp_p, uint16_t level) +{ + sdp_conn_t *conn_p; + sdp_mca_t *mca_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 (NULL); + } + conn_p = &(mca_p->conn); + } + + return (conn_p->conn_addr); +} + +/* Function: sdp_is_mcast_addr + * Description: Returns a boolean to indicate if the addr is multicast in + * the c=line. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the c= line. Will be + * either SDP_SESSION_LEVEL or 1-n specifying a + * media line level. + * Returns: TRUE if the addr is multicast, FALSE if not. + */ + +tinybool sdp_is_mcast_addr (sdp_t *sdp_p, uint16_t level) +{ + sdp_conn_t *conn_p; + sdp_mca_t *mca_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) { + conn_p = &(mca_p->conn); + } else { + return (FALSE); + } + } + + if ((conn_p) && (conn_p->is_multicast)) { + return (TRUE); + } else { + return (FALSE); + } +} + +/* Function: sdp_get_mcast_ttl + * Description: Get the time to live(ttl) value for the multicast address + * if present. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the c= line. Will be + * either SDP_SESSION_LEVEL or 1-n specifying a + * media line level. + * Returns: Multicast address - Time to live (ttl) value + */ + +int32_t sdp_get_mcast_ttl (sdp_t *sdp_p, uint16_t level) +{ + sdp_conn_t *conn_p; + sdp_mca_t *mca_p; + uint16_t ttl=0; + + 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) { + conn_p = &(mca_p->conn); + } else { + return SDP_INVALID_VALUE; + } + } + + if (conn_p) { + ttl = conn_p->ttl; + } + return ttl; +} + +/* Function: sdp_get_mcast_num_of_addresses + * Description: Get the number of addresses value for the multicast address + * if present. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the c= line. Will be + * either SDP_SESSION_LEVEL or 1-n specifying a + * media line level. + * Returns: Multicast address - number of addresses value + */ + +int32_t sdp_get_mcast_num_of_addresses (sdp_t *sdp_p, uint16_t level) +{ + sdp_conn_t *conn_p; + sdp_mca_t *mca_p; + uint16_t num_addr = 0; + + 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) { + conn_p = &(mca_p->conn); + } else { + return (SDP_INVALID_VALUE); + } + } + + if (conn_p) { + num_addr = conn_p->num_of_addresses; + } + return num_addr; +} +/* Function: sdp_set_conn_nettype + * Description: Sets the value of the network type parameter for the c= + * connection token line. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * nettype Network type for the connection line. + * level The level to check for the c= line. Will be + * either SDP_SESSION_LEVEL or 1-n specifying a + * media line level. + * Returns: SDP_SUCCESS or SDP_INVALID_PARAMETER + */ +sdp_result_e sdp_set_conn_nettype (sdp_t *sdp_p, uint16_t level, + sdp_nettype_e nettype) +{ + sdp_conn_t *conn_p; + sdp_mca_t *mca_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) { + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_PARAMETER); + } + conn_p = &(mca_p->conn); + } + + conn_p->nettype = nettype; + return (SDP_SUCCESS); +} + +/* Function: sdp_set_conn_addrtype + * Description: Sets the value of the address type parameter for the c= + * connection token line. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * addrtype Address type for the connection line. + * level The level to check for the c= line. Will be + * either SDP_SESSION_LEVEL or 1-n specifying a + * media line level. + * Returns: SDP_SUCCESS or SDP_INVALID_PARAMETER + */ +sdp_result_e sdp_set_conn_addrtype (sdp_t *sdp_p, uint16_t level, + sdp_addrtype_e addrtype) +{ + sdp_conn_t *conn_p; + sdp_mca_t *mca_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) { + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_PARAMETER); + } + conn_p = &(mca_p->conn); + } + + conn_p->addrtype = addrtype; + return (SDP_SUCCESS); +} + +/* Function: sdp_set_conn_address + * Description: Sets the value of the address parameter for the c= + * connection token line. The string is copied into the + * SDP structure so application memory will not be + * referenced by the SDP lib. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the c= line. Will be + * either SDP_SESSION_LEVEL or 1-n specifying a + * media line level. + * address Ptr to the address string. + * Returns: SDP_SUCCESS + */ +sdp_result_e sdp_set_conn_address (sdp_t *sdp_p, uint16_t level, + const char *address) +{ + sdp_conn_t *conn_p; + sdp_mca_t *mca_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) { + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_PARAMETER); + } + conn_p = &(mca_p->conn); + } + + sstrncpy(conn_p->conn_addr, address, sizeof(conn_p->conn_addr)); + return (SDP_SUCCESS); +} + +/* Function: sdp_media_line_valid + * Description: Returns true or false depending on whether the specified + * media line m= has been defined for this SDP. The + * SDP_SESSION_LEVEL level is not valid for this check since, + * by definition, this is a media level. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the c= line. Will be + * 1-n specifying a media line level. + * Returns: TRUE or FALSE. + */ +tinybool sdp_media_line_valid (sdp_t *sdp_p, uint16_t level) +{ + sdp_mca_t *mca_p; + + mca_p = sdp_find_media_level(sdp_p, level); + if (mca_p == NULL) { + return (FALSE); + } + + /* 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) || + (mca_p->num_payloads == 0)) { + return (FALSE); + } else { + return (TRUE); + } +} + +/* Function: sdp_get_num_media_lines + * Description: Returns the number of media lines associated with the SDP. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * Returns: Number of media lines. + */ +uint16_t sdp_get_num_media_lines (sdp_t *sdp_p) +{ + return (sdp_p->mca_count); +} + +/* Function: sdp_get_media_type + * Description: Returns the media type parameter from the m= + * media token line. If media type has not been + * set SDP_MEDIA_INVALID will be returned. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to of the m= media line. Will be 1-n. + * Returns: Media type or SDP_MEDIA_INVALID. + */ +sdp_media_e sdp_get_media_type (sdp_t *sdp_p, uint16_t level) +{ + sdp_mca_t *mca_p; + + mca_p = sdp_find_media_level(sdp_p, level); + if (mca_p == NULL) { + return (SDP_MEDIA_INVALID); + } + + return (mca_p->media); +} + +/* Function: sdp_get_media_line_number + * Description: Returns the line number in the SDP the media + * section starts on. Only set if SDP has been parsed + * (rather than built). + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to of the m= media line. Will be 1-n. + * Returns: Line number (0 if not found or if locally built) + */ +uint32_t sdp_get_media_line_number (sdp_t *sdp_p, uint16_t level) +{ + sdp_mca_t *mca_p; + + mca_p = sdp_find_media_level(sdp_p, level); + if (mca_p == NULL) { + return 0; + } + + return (mca_p->line_number); +} + +/* Function: sdp_get_media_port_format + * Description: Returns the port format type associated with the m= + * media token line. If port format type has not been + * set SDP_PORT_FORMAT_INVALID will be returned. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to of the m= media line. Will be 1-n. + * Returns: Port format type or SDP_PORT_FORMAT_INVALID. + */ +sdp_port_format_e sdp_get_media_port_format (sdp_t *sdp_p, uint16_t level) +{ + sdp_mca_t *mca_p; + + mca_p = sdp_find_media_level(sdp_p, level); + if (mca_p == NULL) { + return (SDP_PORT_FORMAT_INVALID); + } + + return (mca_p->port_format); +} + +/* Function: sdp_get_media_portnum + * Description: Returns the port number associated with the m= + * media token line. If port number has not been + * set SDP_INVALID_VALUE will be returned. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to of the m= media line. Will be 1-n. + * Returns: Port number or SDP_INVALID_VALUE. + */ +int32_t sdp_get_media_portnum (sdp_t *sdp_p, uint16_t level) +{ + sdp_mca_t *mca_p; + + mca_p = sdp_find_media_level(sdp_p, level); + if (mca_p == NULL) { + return (SDP_INVALID_VALUE); + } + + /* Make sure port number is valid for the specified format. */ + if ((mca_p->port_format != SDP_PORT_NUM_ONLY) && + (mca_p->port_format != SDP_PORT_NUM_COUNT) && + (mca_p->port_format != SDP_PORT_NUM_VPI_VCI) && + (mca_p->port_format != SDP_PORT_NUM_VPI_VCI_CID)) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s Port num not valid for media line %u", + sdp_p->debug_str, (unsigned)level); + } + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_VALUE); + } + + return (mca_p->port); +} + +/* Function: sdp_get_media_portcount + * Description: Returns the port count associated with the m= + * media token line. If port count has not been + * set SDP_INVALID_VALUE will be returned. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to of the m= media line. Will be 1-n. + * Returns: Port count or SDP_INVALID_VALUE. + */ +int32_t sdp_get_media_portcount (sdp_t *sdp_p, uint16_t level) +{ + sdp_mca_t *mca_p; + + mca_p = sdp_find_media_level(sdp_p, level); + if (mca_p == NULL) { + return (SDP_INVALID_VALUE); + } + + /* Make sure port number is valid for the specified format. */ + if (mca_p->port_format != SDP_PORT_NUM_COUNT) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s Port count not valid for media line %u", + sdp_p->debug_str, (unsigned)level); + } + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_VALUE); + } + + return (mca_p->num_ports); +} + +/* Function: sdp_get_media_vpi + * Description: Returns the VPI parameter associated with the m= + * media token line. If VPI has not been set + * SDP_INVALID_VALUE will be returned. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to of the m= media line. Will be 1-n. + * Returns: VPI or SDP_INVALID_VALUE. + */ +int32_t sdp_get_media_vpi (sdp_t *sdp_p, uint16_t level) +{ + sdp_mca_t *mca_p; + + mca_p = sdp_find_media_level(sdp_p, level); + if (mca_p == NULL) { + return (SDP_INVALID_VALUE); + } + + /* Make sure port number is valid for the specified format. */ + if ((mca_p->port_format != SDP_PORT_VPI_VCI) && + (mca_p->port_format != SDP_PORT_NUM_VPI_VCI) && + (mca_p->port_format != SDP_PORT_NUM_VPI_VCI_CID)) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s VPI not valid for media line %u", + sdp_p->debug_str, (unsigned)level); + } + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_VALUE); + } + + return (mca_p->vpi); +} + +/* Function: sdp_get_media_vci + * Description: Returns the VCI parameter associated with the m= + * media token line. If VCI has not been set + * SDP_INVALID_VALUE will be returned. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to of the m= media line. Will be 1-n. + * Returns: VCI or zero. + */ +uint32_t sdp_get_media_vci (sdp_t *sdp_p, uint16_t level) +{ + sdp_mca_t *mca_p; + + mca_p = sdp_find_media_level(sdp_p, level); + if (mca_p == NULL) { + return (0); + } + + /* Make sure port number is valid for the specified format. */ + if ((mca_p->port_format != SDP_PORT_VPI_VCI) && + (mca_p->port_format != SDP_PORT_NUM_VPI_VCI) && + (mca_p->port_format != SDP_PORT_NUM_VPI_VCI_CID)) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s VCI not valid for media line %u", + sdp_p->debug_str, (unsigned)level); + } + sdp_p->conf_p->num_invalid_param++; + return (0); + } + + return (mca_p->vci); +} + +/* Function: sdp_get_media_vcci + * Description: Returns the VCCI parameter associated with the m= + * media token line. If VCCI has not been set + * SDP_INVALID_VALUE will be returned. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to of the m= media line. Will be 1-n. + * Returns: VCCI or SDP_INVALID_VALUE. + */ +int32_t sdp_get_media_vcci (sdp_t *sdp_p, uint16_t level) +{ + sdp_mca_t *mca_p; + + mca_p = sdp_find_media_level(sdp_p, level); + if (mca_p == NULL) { + return (SDP_INVALID_VALUE); + } + + /* Make sure port number is valid for the specified format. */ + if ((mca_p->port_format != SDP_PORT_VCCI) && + (mca_p->port_format != SDP_PORT_VCCI_CID)) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s VCCI not valid for media line %u", + sdp_p->debug_str, (unsigned)level); + } + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_VALUE); + } + + return (mca_p->vcci); +} + +/* Function: sdp_get_media_cid + * Description: Returns the CID parameter associated with the m= + * media token line. If CID has not been set + * SDP_INVALID_VALUE will be returned. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to of the m= media line. Will be 1-n. + * Returns: CID or SDP_INVALID_VALUE. + */ +int32_t sdp_get_media_cid (sdp_t *sdp_p, uint16_t level) +{ + sdp_mca_t *mca_p; + + mca_p = sdp_find_media_level(sdp_p, level); + if (mca_p == NULL) { + return (SDP_INVALID_VALUE); + } + + /* Make sure port number is valid for the specified format. */ + if ((mca_p->port_format != SDP_PORT_VCCI_CID) && + (mca_p->port_format != SDP_PORT_NUM_VPI_VCI_CID)) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s CID not valid for media line %u", + sdp_p->debug_str, (unsigned)level); + } + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_VALUE); + } + + return (mca_p->cid); +} + +/* Function: sdp_get_media_transport + * Description: Returns the transport type parameter associated with the m= + * media token line. If transport type has not been set + * SDP_TRANSPORT_INVALID will be returned. If the transport + * type is one of the AAL2 variants, the profile routines below + * should be used to access multiple profile types and payload + * lists per m= line. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to of the m= media line. Will be 1-n. + * Returns: CID or SDP_TRANSPORT_INVALID. + */ +sdp_transport_e sdp_get_media_transport (sdp_t *sdp_p, uint16_t level) +{ + sdp_mca_t *mca_p; + + mca_p = sdp_find_media_level(sdp_p, level); + if (mca_p == NULL) { + return (SDP_TRANSPORT_INVALID); + } + + return (mca_p->transport); +} + +/* Function: sdp_get_media_num_profiles + * Description: Returns the number of profiles associated with the m= + * media token line. If the media line is invalid, zero will + * be returned. Application must validate the media line + * before using this routine. Multiple profile types per + * media line is currently only used for AAL2. If the appl + * detects that the transport type is one of the AAL2 types, + * it should use these profile access routines to access the + * profile types and payload list for each. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to of the m= media line. Will be 1-n. + * Returns: Number of profiles or zero. + */ +uint16_t sdp_get_media_num_profiles (sdp_t *sdp_p, uint16_t level) +{ + sdp_mca_t *mca_p; + + mca_p = sdp_find_media_level(sdp_p, level); + if (mca_p == NULL) { + return (0); + } + + if (mca_p->media_profiles_p == NULL) { + return (0); + } else { + return (mca_p->media_profiles_p->num_profiles); + } +} + +/* Function: sdp_get_media_profile + * Description: Returns the specified profile type associated with the m= + * media token line. If the media line or profile number is + * invalid, SDP_TRANSPORT_INVALID will be returned. + * Applications must validate the media line before using this + * routine. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to of the m= media line. Will be 1-n. + * profile_num The specific profile type number to be retrieved. + * Returns: The profile type or SDP_TRANSPORT_INVALID. + */ +sdp_transport_e sdp_get_media_profile (sdp_t *sdp_p, uint16_t level, + uint16_t profile_num) +{ + sdp_mca_t *mca_p; + + mca_p = sdp_find_media_level(sdp_p, level); + if (mca_p == NULL) { + return (SDP_TRANSPORT_INVALID); + } + + if ((profile_num < 1) || + (profile_num > mca_p->media_profiles_p->num_profiles)) { + return (SDP_TRANSPORT_INVALID); + } else { + return (mca_p->media_profiles_p->profile[profile_num-1]); + } +} + +/* Function: sdp_get_media_num_payload_types + * Description: Returns the number of payload types associated with the m= + * media token line. If the media line is invalid, zero will + * be returned. Application must validate the media line + * before using this routine. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to of the m= media line. Will be 1-n. + * Returns: Number of payload types or zero. + */ +uint16_t sdp_get_media_num_payload_types (sdp_t *sdp_p, uint16_t level) +{ + sdp_mca_t *mca_p; + + mca_p = sdp_find_media_level(sdp_p, level); + if (mca_p == NULL) { + return (0); + } + + return (mca_p->num_payloads); +} + +/* Function: sdp_get_media_profile_num_payload_types + * Description: Returns the number of payload types associated with the + * specified profile on the m= media token line. If the + * media line or profile number is invalid, zero will + * be returned. Application must validate the media line + * and profile before using this routine. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to of the m= media line. Will be 1-n. + * profile_num The specific profile number. Will be 1-n. + * Returns: Number of payload types or zero. + */ +uint16_t sdp_get_media_profile_num_payload_types (sdp_t *sdp_p, uint16_t level, + uint16_t profile_num) +{ + sdp_mca_t *mca_p; + + mca_p = sdp_find_media_level(sdp_p, level); + if (mca_p == NULL) { + return (0); + } + + if ((profile_num < 1) || + (profile_num > mca_p->media_profiles_p->num_profiles)) { + return (0); + } else { + return (mca_p->media_profiles_p->num_payloads[profile_num-1]); + } +} + +rtp_ptype sdp_get_known_payload_type(sdp_t *sdp_p, + uint16_t level, + uint16_t payload_type_raw) { + sdp_attr_t *attr_p; + sdp_transport_map_t *rtpmap; + uint16_t pack_mode = 0; /*default 0, if remote did not provide any */ + const char *encname = NULL; + uint16_t num_a_lines = 0; + int i; + + /* + * Get number of RTPMAP attributes for the media line + */ + (void) sdp_attr_num_instances(sdp_p, level, 0, SDP_ATTR_RTPMAP, + &num_a_lines); + + /* + * Loop through media line RTPMAP attributes. + */ + for (i = 0; i < num_a_lines; i++) { + attr_p = sdp_find_attr(sdp_p, level, 0, SDP_ATTR_RTPMAP, (i + 1)); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s rtpmap attribute, level %u instance %u " + "not found.", + sdp_p->debug_str, + (unsigned)level, + (unsigned)(i + 1)); + } + sdp_p->conf_p->num_invalid_param++; + return (RTP_NONE); + } + + rtpmap = &(attr_p->attr.transport_map); + + if (rtpmap->payload_num == payload_type_raw) { + encname = rtpmap->encname; + if (encname) { + if (cpr_strcasecmp(encname, SIPSDP_ATTR_ENCNAME_ILBC) == 0) { + return (RTP_ILBC); + } + if (cpr_strcasecmp(encname, SIPSDP_ATTR_ENCNAME_L16_256K) == 0) { + return (RTP_L16); + } + if (cpr_strcasecmp(encname, SIPSDP_ATTR_ENCNAME_ISAC) == 0) { + return (RTP_ISAC); + } + if (cpr_strcasecmp(encname, SIPSDP_ATTR_ENCNAME_OPUS) == 0) { + return (RTP_OPUS); + } + if (cpr_strcasecmp(encname, SIPSDP_ATTR_ENCNAME_PCMU) == 0) { + return (RTP_PCMU); + } + if (cpr_strcasecmp(encname, SIPSDP_ATTR_ENCNAME_PCMA) == 0) { + return (RTP_PCMA); + } + if (cpr_strcasecmp(encname, SIPSDP_ATTR_ENCNAME_G722) == 0) { + return (RTP_G722); + } + if (cpr_strcasecmp(encname, SIPSDP_ATTR_ENCNAME_H264) == 0) { + int fmtp_inst = sdp_find_fmtp_inst(sdp_p, level, rtpmap->payload_num); + if (fmtp_inst < 0) { + return (RTP_H264_P0); + } else { + sdp_attr_get_fmtp_pack_mode(sdp_p, level, 0, (uint16_t) fmtp_inst, &pack_mode); + if (pack_mode == SDP_DEFAULT_PACKETIZATION_MODE_VALUE) { + return (RTP_H264_P0); + } else { + return (RTP_H264_P1); + } + } + } + if (cpr_strcasecmp(encname, SIPSDP_ATTR_ENCNAME_VP8) == 0) { + return (RTP_VP8); + } + if (cpr_strcasecmp(encname, SIPSDP_ATTR_ENCNAME_VP9) == 0) { + return (RTP_VP9); + } + if (cpr_strcasecmp(encname, SIPSDP_ATTR_ENCNAME_RED) == 0) { + return (RTP_RED); + } + if (cpr_strcasecmp(encname, SIPSDP_ATTR_ENCNAME_ULPFEC) == 0) { + return (RTP_ULPFEC); + } + if (cpr_strcasecmp(encname, SIPSDP_ATTR_ENCNAME_TELEPHONE_EVENT) == 0) { + return (RTP_TELEPHONE_EVENT); + } + if (cpr_strcasecmp(encname, SIPSDP_ATTR_ENCNAME_RTX) == 0) { + return (RTP_RTX); + } + } + } + } + + return (RTP_NONE); +} + +/* Function: sdp_get_media_payload_type + * Description: Returns the payload type of the specified payload for the m= + * media token line. If the media line or payload number is + * invalid, zero will be returned. Application must validate + * the media line before using this routine. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to of the m= media line. Will be 1-n. + * payload_num Number of the payload type to retrieve. The + * range is (1 - max num payloads). + * indicator Returns the type of payload returned, either + * NUMERIC or ENUM. + * Returns: Payload type or zero. + */ +uint32_t sdp_get_media_payload_type (sdp_t *sdp_p, uint16_t level, uint16_t payload_num, + sdp_payload_ind_e *indicator) +{ + sdp_mca_t *mca_p; + rtp_ptype ptype; + + mca_p = sdp_find_media_level(sdp_p, level); + if (mca_p == NULL) { + return (0); + } + + if ((payload_num < 1) || (payload_num > mca_p->num_payloads)) { + return (0); + } + + *indicator = mca_p->payload_indicator[payload_num-1]; + if ((mca_p->payload_type[payload_num-1] >= SDP_MIN_DYNAMIC_PAYLOAD) && + (mca_p->payload_type[payload_num-1] <= SDP_MAX_DYNAMIC_PAYLOAD)) { + ptype = sdp_get_known_payload_type(sdp_p, + level, + mca_p->payload_type[payload_num-1]); + if (ptype != RTP_NONE) { + return (SET_PAYLOAD_TYPE_WITH_DYNAMIC( + mca_p->payload_type[payload_num-1], ptype)); + } + + } + return (mca_p->payload_type[payload_num-1]); +} + +/* Function: sdp_get_media_profile_payload_type + * Description: Returns the payload type of the specified payload for the m= + * media token line. If the media line or payload number is + * invalid, zero will be returned. Application must validate + * the media line before using this routine. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to of the m= media line. Will be 1-n. + * payload_num Number of the payload type to retrieve. The + * range is (1 - max num payloads). + * indicator Returns the type of payload returned, either + * NUMERIC or ENUM. + * Returns: Payload type or zero. + */ +uint32_t sdp_get_media_profile_payload_type (sdp_t *sdp_p, uint16_t level, uint16_t prof_num, + uint16_t payload_num, + sdp_payload_ind_e *indicator) +{ + sdp_mca_t *mca_p; + sdp_media_profiles_t *prof_p; + + mca_p = sdp_find_media_level(sdp_p, level); + if (mca_p == NULL) { + return (0); + } + + prof_p = mca_p->media_profiles_p; + if ((prof_num < 1) || + (prof_num > prof_p->num_profiles)) { + return (0); + } + + if ((payload_num < 1) || + (payload_num > prof_p->num_payloads[prof_num-1])) { + return (0); + } + + *indicator = prof_p->payload_indicator[prof_num-1][payload_num-1]; + return (prof_p->payload_type[prof_num-1][payload_num-1]); +} + +/* Function: sdp_insert_media_line + * Description: Insert a new media line at the level specified for the + * given SDP. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The new media level to insert. Will be 1-n. + * Returns: SDP_SUCCESS, SDP_NO_RESOURCE, or SDP_INVALID_PARAMETER + */ +sdp_result_e sdp_insert_media_line (sdp_t *sdp_p, uint16_t level) +{ + sdp_mca_t *mca_p; + sdp_mca_t *new_mca_p; + + if ((level < 1) || (level > (sdp_p->mca_count+1))) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s Invalid media line (%u) to insert, max is " + "(%u).", sdp_p->debug_str, (unsigned)level, (unsigned)sdp_p->mca_count); + } + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_PARAMETER); + } + + /* Allocate resource for new media stream. */ + new_mca_p = sdp_alloc_mca(0); + if (new_mca_p == NULL) { + sdp_p->conf_p->num_no_resource++; + return (SDP_NO_RESOURCE); + } + + if (level == 1) { + /* We're inserting the first media line */ + new_mca_p->next_p = sdp_p->mca_p; + sdp_p->mca_p = new_mca_p; + } else { + /* Find the pointer to the media stream just prior to where + * we want to insert the new stream. + */ + mca_p = sdp_find_media_level(sdp_p, (uint16_t)(level-1)); + if (mca_p == NULL) { + SDP_FREE(new_mca_p); + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_PARAMETER); + } + + new_mca_p->next_p = mca_p->next_p; + mca_p->next_p = new_mca_p; + } + + sdp_p->mca_count++; + return (SDP_SUCCESS); +} + +/* Function: sdp_set_media_type + * Description: Sets the value of the media type parameter for the m= + * media token line. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The media level to set the param. Will be 1-n. + * media Media type for the media line. + * Returns: SDP_SUCCESS or SDP_INVALID_PARAMETER + */ +sdp_result_e sdp_set_media_type (sdp_t *sdp_p, uint16_t level, sdp_media_e media) +{ + sdp_mca_t *mca_p; + + mca_p = sdp_find_media_level(sdp_p, level); + if (mca_p == NULL) { + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_PARAMETER); + } + + mca_p->media = media; + return (SDP_SUCCESS); +} + +/* Function: sdp_set_media_portnum + * Description: Sets the value of the port number parameter for the m= + * media token line. If the port number is not valid with the + * port format specified for the media line, this call will + * fail. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The media level to set the param. Will be 1-n. + * portnum Port number to set. + * sctpport sctp port for application m= line + * Returns: SDP_SUCCESS or SDP_INVALID_PARAMETER + */ +sdp_result_e sdp_set_media_portnum (sdp_t *sdp_p, uint16_t level, int32_t portnum, int32_t sctp_port) +{ + sdp_mca_t *mca_p; + + mca_p = sdp_find_media_level(sdp_p, level); + if (mca_p == NULL) { + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_PARAMETER); + } + + mca_p->port = portnum; + mca_p->sctpport = sctp_port; + return (SDP_SUCCESS); +} + +/* Function: sdp_get_media_sctp_port + * Description: Gets the value of the sctp port number parameter for the m= + * media token line. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The media level to set the param. Will be 1-n. + * Returns: sctp_port or -1 on failure + */ +int32_t sdp_get_media_sctp_port(sdp_t *sdp_p, uint16_t level) +{ + sdp_mca_t *mca_p; + + mca_p = sdp_find_media_level(sdp_p, level); + if (!mca_p) { + sdp_p->conf_p->num_invalid_param++; + return -1; + } + + return mca_p->sctpport; +} + +sdp_sctp_media_fmt_type_e sdp_get_media_sctp_fmt(sdp_t *sdp_p, uint16_t level) +{ + sdp_mca_t *mca_p; + + mca_p = sdp_find_media_level(sdp_p, level); + if (!mca_p) { + sdp_p->conf_p->num_invalid_param++; + return -1; + } + + return mca_p->sctp_fmt; +} + +/* Function: sdp_set_media_transport + * Description: Sets the value of the transport type parameter for the m= + * media token line. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The media level to set the param. Will be 1-n. + * transport The transport type to set. + * Returns: SDP_SUCCESS or SDP_INVALID_PARAMETER + */ +sdp_result_e sdp_set_media_transport (sdp_t *sdp_p, uint16_t level, + sdp_transport_e transport) +{ + sdp_mca_t *mca_p; + + mca_p = sdp_find_media_level(sdp_p, level); + if (mca_p == NULL) { + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_PARAMETER); + } + + mca_p->transport = transport; + return (SDP_SUCCESS); +} + +/* Function: sdp_add_media_profile + * Description: Add a new profile type for the m= media token line. This is + * used for AAL2 transport/profile types where more than one can + * be specified per media line. All other transport types should + * use the other transport access routines rather than this. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The media level to add the param. Will be 1-n. + * profile The profile type to add. + * Returns: SDP_SUCCESS or SDP_INVALID_PARAMETER + */ +sdp_result_e sdp_add_media_profile (sdp_t *sdp_p, uint16_t level, + sdp_transport_e profile) +{ + uint16_t prof_num; + sdp_mca_t *mca_p; + + mca_p = sdp_find_media_level(sdp_p, level); + if (mca_p == NULL) { + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_PARAMETER); + } + + if (mca_p->media_profiles_p == NULL) { + mca_p->media_profiles_p = (sdp_media_profiles_t *) \ + SDP_MALLOC(sizeof(sdp_media_profiles_t)); + if (mca_p->media_profiles_p == NULL) { + sdp_p->conf_p->num_no_resource++; + return (SDP_NO_RESOURCE); + } else { + mca_p->media_profiles_p->num_profiles = 0; + /* Set the transport type to this first profile type. */ + mca_p->transport = profile; + } + } + + if (mca_p->media_profiles_p->num_profiles >= SDP_MAX_PROFILES) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s Max number of media profiles already specified" + " for media level %u", sdp_p->debug_str, (unsigned)level); + } + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_PARAMETER); + } + + prof_num = mca_p->media_profiles_p->num_profiles++; + mca_p->media_profiles_p->profile[prof_num] = profile; + mca_p->media_profiles_p->num_payloads[prof_num] = 0; + return (SDP_SUCCESS); +} + +/* Function: sdp_add_media_payload_type + * Description: Add a new payload type for the media line at the level + * specified. The new payload type will be added at the end + * of the payload type list. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The media level to add the payload. Will be 1-n. + * payload_type The new payload type. + * indicator Defines the type of payload returned, either + * NUMERIC or ENUM. + * Returns: SDP_SUCCESS or SDP_INVALID_PARAMETER + */ +sdp_result_e sdp_add_media_payload_type (sdp_t *sdp_p, uint16_t level, + uint16_t payload_type, + sdp_payload_ind_e indicator) +{ + sdp_mca_t *mca_p; + + mca_p = sdp_find_media_level(sdp_p, level); + if (mca_p == NULL) { + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_PARAMETER); + } + + if (mca_p->num_payloads == SDP_MAX_PAYLOAD_TYPES) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s Max number of payload types already defined " + "for media line %u", sdp_p->debug_str, (unsigned)level); + } + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_PARAMETER); + } + + mca_p->payload_indicator[mca_p->num_payloads] = indicator; + mca_p->payload_type[mca_p->num_payloads++] = payload_type; + return (SDP_SUCCESS); +} + +/* Function: sdp_add_media_profile_payload_type + * Description: Add a new payload type for the media line at the level + * specified. The new payload type will be added at the end + * of the payload type list. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The media level to add the payload. Will be 1-n. + * prof_num The profile number to add the payload type. + * payload_type The new payload type. + * indicator Defines the type of payload returned, either + * NUMERIC or ENUM. + * Returns: SDP_SUCCESS or SDP_INVALID_PARAMETER + */ +sdp_result_e sdp_add_media_profile_payload_type (sdp_t *sdp_p, uint16_t level, + uint16_t prof_num, uint16_t payload_type, + sdp_payload_ind_e indicator) +{ + uint16_t num_payloads; + sdp_mca_t *mca_p; + + mca_p = sdp_find_media_level(sdp_p, level); + if (mca_p == NULL) { + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_PARAMETER); + } + + if ((prof_num < 1) || + (prof_num > mca_p->media_profiles_p->num_profiles)) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s Invalid profile number (%u) for set profile " + " payload type", sdp_p->debug_str, (unsigned)level); + } + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_PARAMETER); + } + + if (mca_p->media_profiles_p->num_payloads[prof_num-1] == + SDP_MAX_PAYLOAD_TYPES) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s Max number of profile payload types already " + "defined profile %u on media line %u", + sdp_p->debug_str, (unsigned)prof_num, (unsigned)level); + } + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_PARAMETER); + } + + /* Get the current num payloads for this profile, and inc the number + * of payloads at the same time. Then store the new payload type. */ + num_payloads = mca_p->media_profiles_p->num_payloads[prof_num-1]++; + mca_p->media_profiles_p->payload_indicator[prof_num-1][num_payloads] = + indicator; + mca_p->media_profiles_p->payload_type[prof_num-1][num_payloads] = + payload_type; + return (SDP_SUCCESS); +} + +/* + * sdp_find_bw_line + * + * This helper function locates a specific bw line instance given the + * sdp, the level and the instance number of the bw line. + * + * Returns: Pointer to the sdp_bw_data_t instance, or NULL. + */ +sdp_bw_data_t* sdp_find_bw_line (sdp_t *sdp_p, uint16_t level, uint16_t inst_num) +{ + sdp_bw_t *bw_p; + sdp_bw_data_t *bw_data_p; + sdp_mca_t *mca_p; + int bw_attr_count=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) { + sdp_p->conf_p->num_invalid_param++; + return (NULL); + } + bw_p = &(mca_p->bw); + } + + for (bw_data_p = bw_p->bw_data_list; + bw_data_p != NULL; + bw_data_p = bw_data_p->next_p) { + bw_attr_count++; + if (bw_attr_count == inst_num) { + return bw_data_p; + } + } + + return NULL; +} + +/* + * sdp_copy_all_bw_lines + * + * Appends all the bw lines from the specified level of the orig sdp to the + * specified level of the dst sdp. + * + * Parameters: src_sdp_p The source SDP handle. + * dst_sdp_p The dest SDP handle. + * src_level The level in the src sdp from where to get the + * attributes. + * dst_level The level in the dst sdp where to put the + * attributes. + * Returns: SDP_SUCCESS Attributes were successfully copied. + */ +sdp_result_e sdp_copy_all_bw_lines (sdp_t *src_sdp_p, sdp_t *dst_sdp_p, + uint16_t src_level, uint16_t dst_level) +{ + sdp_bw_data_t *orig_bw_data_p; + sdp_bw_data_t *new_bw_data_p; + sdp_bw_data_t *bw_data_p; + sdp_bw_t *src_bw_p; + sdp_bw_t *dst_bw_p; + sdp_mca_t *mca_p; + + /* Find src bw list */ + if (src_level == SDP_SESSION_LEVEL) { + src_bw_p = &(src_sdp_p->bw); + } else { + mca_p = sdp_find_media_level(src_sdp_p, src_level); + if (mca_p == NULL) { + if (src_sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s Invalid src media level (%u) for copy all " + "attrs ", src_sdp_p->debug_str, (unsigned)src_level); + } + return (SDP_INVALID_PARAMETER); + } + src_bw_p = &(mca_p->bw); + } + + /* Find dst bw list */ + if (dst_level == SDP_SESSION_LEVEL) { + dst_bw_p = &(dst_sdp_p->bw); + } else { + mca_p = sdp_find_media_level(dst_sdp_p, dst_level); + if (mca_p == NULL) { + if (src_sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s Invalid dst media level (%u) for copy all " + "attrs ", src_sdp_p->debug_str, (unsigned)dst_level); + } + return (SDP_INVALID_PARAMETER); + } + dst_bw_p = &(mca_p->bw); + } + + orig_bw_data_p = src_bw_p->bw_data_list; + while (orig_bw_data_p) { + /* For ever bw line in the src, allocate a new one for the dst */ + new_bw_data_p = (sdp_bw_data_t*)SDP_MALLOC(sizeof(sdp_bw_data_t)); + if (new_bw_data_p == NULL) { + return (SDP_NO_RESOURCE); + } + new_bw_data_p->next_p = NULL; + new_bw_data_p->bw_modifier = orig_bw_data_p->bw_modifier; + new_bw_data_p->bw_val = orig_bw_data_p->bw_val; + + /* + * Enqueue the sdp_bw_data_t instance at the end of the list of + * sdp_bw_data_t instances. + */ + if (dst_bw_p->bw_data_list == NULL) { + dst_bw_p->bw_data_list = new_bw_data_p; + } else { + for (bw_data_p = dst_bw_p->bw_data_list; + bw_data_p->next_p != NULL; + bw_data_p = bw_data_p->next_p) { + + /*sa_ignore EMPTYLOOP*/ + ; /* Do nothing. */ + } + + bw_data_p->next_p = new_bw_data_p; + } + dst_bw_p->bw_data_count++; + + orig_bw_data_p = orig_bw_data_p->next_p; + } + + return (SDP_SUCCESS); +} + +/* Function: sdp_get_bw_modifier + * Description: Returns the bandwidth modifier parameter from the b= + * line. If no bw modifier has been set , + * SDP_BW_MODIFIER_UNSUPPORTED will be returned. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level from which to get the bw modifier. + * inst_num instance number of bw line at that level. The first + * instance has a inst_num of 1 and so on. + * Returns: Valid modifer value or SDP_BW_MODIFIER_UNSUPPORTED. + */ +sdp_bw_modifier_e sdp_get_bw_modifier (sdp_t *sdp_p, uint16_t level, uint16_t inst_num) +{ + sdp_bw_data_t *bw_data_p; + + bw_data_p = sdp_find_bw_line(sdp_p, level, inst_num); + + if (bw_data_p) { + return (bw_data_p->bw_modifier); + } else { + return (SDP_BW_MODIFIER_UNSUPPORTED); + } +} + +/* Function: sdp_get_bw_value + * Description: Returns the bandwidth value parameter from the b= + * line. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level from which to get the bw value. + * inst_num instance number of bw line at the level. The first + * instance has a inst_num of 1 and so on. + * Returns: A valid numerical bw value or SDP_INVALID_VALUE. + */ +int32_t sdp_get_bw_value (sdp_t *sdp_p, uint16_t level, uint16_t inst_num) +{ + sdp_bw_data_t *bw_data_p; + + bw_data_p = sdp_find_bw_line(sdp_p, level, inst_num); + + if (bw_data_p) { + return (bw_data_p->bw_val); + } else { + return (SDP_INVALID_VALUE); + } +} + +/* + * sdp_get_num_bw_lines + * + * Returns the number of bw lines are present at a given level. + * + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level at which the count of bw lines is required + * + * Returns: A valid count or SDP_INVALID_VALUE + */ +int32_t sdp_get_num_bw_lines (sdp_t *sdp_p, uint16_t level) +{ + sdp_bw_t *bw_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) { + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_VALUE); + } + bw_p = &(mca_p->bw); + } + + return (bw_p->bw_data_count); +} + +/* + * sdp_add_new_bw_line + * + * To specify bandwidth parameters at any level, a bw line must first be + * added at that level using this function. After this addition, you can set + * the properties of the added bw line by using sdp_set_bw(). + * + * Note carefully though, that since there can be multiple instances of bw + * lines at any level, you must specify the instance number when setting + * or getting the properties of a bw line at any level. + * + * This function returns within the inst_num variable, the instance number + * of the created bw_line at that level. The instance number is 1-based. + * For example: + * v=0 #Session Level + * o=mhandley 2890844526 2890842807 IN IP4 126.16.64.4 + * s=SDP Seminar + * c=IN IP4 10.1.0.2 + * t=0 0 + * b=AS:60 # instance number 1 + * b=TIAS:50780 # instance number 2 + * m=audio 1234 RTP/AVP 0 101 102 # 1st Media level + * b=AS:12 # instance number 1 + * b=TIAS:8480 # instance number 2 + * m=audio 1234 RTP/AVP 0 101 102 # 2nd Media level + * b=AS:20 # instance number 1 + * + * Parameters: + * sdp_p The SDP handle returned by sdp_init_description. + * level The level to create the bw line. + * bw_modifier The Type of bandwidth, CT, AS or TIAS. + * *inst_num This memory is set with the instance number of the newly + * created bw line instance. + */ +sdp_result_e sdp_add_new_bw_line (sdp_t *sdp_p, uint16_t level, sdp_bw_modifier_e bw_modifier, uint16_t *inst_num) +{ + sdp_bw_t *bw_p; + sdp_mca_t *mca_p; + sdp_bw_data_t *new_bw_data_p; + sdp_bw_data_t *bw_data_p = NULL; + + *inst_num = 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) { + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_PARAMETER); + } + bw_p = &(mca_p->bw); + } + + //see if a bw line already exist for this bw_modifier. + for(bw_data_p = bw_p->bw_data_list; bw_data_p != NULL; bw_data_p = bw_data_p->next_p) { + ++(*inst_num); + if (bw_data_p->bw_modifier == bw_modifier) { + return (SDP_SUCCESS); + } + } + + /* + * 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_no_resource++; + return (SDP_NO_RESOURCE); + } + new_bw_data_p->next_p = NULL; + new_bw_data_p->bw_modifier = SDP_BW_MODIFIER_UNSUPPORTED; + new_bw_data_p->bw_val = 0; + + /* + * 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) { + + /*sa_ignore EMPTYLOOP*/ + ; /* Do nothing. */ + } + + bw_data_p->next_p = new_bw_data_p; + } + *inst_num = ++bw_p->bw_data_count; + + return (SDP_SUCCESS); +} + +/* Function: sdp_get_mid_value + * Description: Returns the mid value parameter from the a= mid: line. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level SDP_MEDIA_LEVEL + * Returns: mid value. + */ +int32_t sdp_get_mid_value (sdp_t *sdp_p, uint16_t level) +{ + sdp_mca_t *mca_p; + + mca_p = sdp_find_media_level(sdp_p, level); + if (mca_p == NULL) { + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_VALUE); + } + return (mca_p->mid); +} + diff --git a/third_party/sipcc/sdp_attr.c b/third_party/sipcc/sdp_attr.c new file mode 100644 index 0000000000..4f75a98fa3 --- /dev/null +++ b/third_party/sipcc/sdp_attr.c @@ -0,0 +1,5251 @@ +/* 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 <limits.h> +#include <stdio.h> + +#include "plstr.h" +#include "sdp_os_defs.h" +#include "sipcc_sdp.h" +#include "sdp_private.h" +#include "sdp_base64.h" + +#include "sdp_log.h" + +static const char* logTag = "sdp_attr"; + +/* + * Macro for sdp_build_attr_fmtp + * Adds name-value pair where value is char* + */ +#define FMTP_BUILD_STRING(condition, name, value) \ + if ((condition)) { \ + sdp_append_name_and_string(fs, (name), (value), semicolon); \ + semicolon = TRUE; \ + } + +/* + * Macro for sdp_build_attr_fmtp + * Adds name-value pair where value is unsigned + */ +#define FMTP_BUILD_UNSIGNED(condition, name, value) \ + if ((condition)) { \ + sdp_append_name_and_unsigned(fs, (name), (value), semicolon); \ + semicolon = TRUE; \ + } + +/* + * Macro for sdp_build_attr_fmtp + * Adds flag string on condition + */ +#define FMTP_BUILD_FLAG(condition, name) \ + if ((condition)) { \ + if (semicolon) { \ + flex_string_append(fs, ";"); \ + } \ + flex_string_append(fs, name); \ + semicolon = TRUE; \ + } + +static int find_token_enum(const char *attr_name, + sdp_t *sdp_p, + const char **ptr, + const sdp_namearray_t *types, + int type_count, + int unknown_value) +{ + sdp_result_e result = SDP_SUCCESS; + char tmp[SDP_MAX_STRING_LEN+1]; + int i; + + *ptr = sdp_getnextstrtok(*ptr, tmp, sizeof(tmp), " \t", &result); + if (result != SDP_SUCCESS) { + sdp_parse_error(sdp_p, + "%s Warning: problem parsing %s", sdp_p->debug_str, attr_name); + sdp_p->conf_p->num_invalid_param++; + return -1; + } + + for (i=0; i < type_count; i++) { + if (!cpr_strncasecmp(tmp, types[i].name, types[i].strlen)) { + return i; + } + } + return unknown_value; +} + +/* + * Helper function for adding nv-pair where value is string. + */ +static void sdp_append_name_and_string(flex_string *fs, + const char *name, + const char *value, + tinybool semicolon) +{ + flex_string_sprintf(fs, "%s%s=%s", + semicolon ? ";" : "", + name, + value); +} + +/* + * Helper function for adding nv-pair where value is unsigned. + */ +static void sdp_append_name_and_unsigned(flex_string *fs, + const char *name, + unsigned int value, + tinybool semicolon) +{ + flex_string_sprintf(fs, "%s%s=%u", + semicolon ? ";" : "", + name, + value); +} + +/* Function: sdp_parse_attribute + * Description: Figure out the type of attribute and call the appropriate + * parsing routine. If parsing errors are encountered, + * warnings will be printed and the attribute will be ignored. + * Unrecognized/invalid attributes do not cause overall parsing + * errors. All errors detected are noted as warnings. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * ptr Pointer to the attribute string to parse. + */ +sdp_result_e sdp_parse_attribute (sdp_t *sdp_p, uint16_t level, const char *ptr) +{ + int i; + uint8_t xcpar_flag = FALSE; + sdp_result_e result; + sdp_mca_t *mca_p=NULL; + sdp_attr_t *attr_p; + sdp_attr_t *next_attr_p; + sdp_attr_t *prev_attr_p = NULL; + char tmp[SDP_MAX_STRING_LEN]; + + /* Validate the level */ + if (level != SDP_SESSION_LEVEL) { + mca_p = sdp_find_media_level(sdp_p, level); + if (mca_p == NULL) { + return (SDP_FAILURE); + } + } + + /* Find the attribute type. */ + ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), ": \t", &result); + if (ptr == NULL) { + sdp_parse_error(sdp_p, + "%s No attribute type specified, parse failed.", sdp_p->debug_str); + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_PARAMETER); + } + 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, parse failed.", sdp_p->debug_str); + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_PARAMETER); + } + + attr_p = (sdp_attr_t *)SDP_MALLOC(sizeof(sdp_attr_t)); + if (attr_p == NULL) { + sdp_p->conf_p->num_no_resource++; + return (SDP_NO_RESOURCE); + } + attr_p->line_number = sdp_p->parse_line; + 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; + break; + } + } + if (attr_p->type == SDP_ATTR_INVALID) { + sdp_parse_error(sdp_p, + "%s Warning: Unrecognized attribute (%s) ", + sdp_p->debug_str, tmp); + sdp_free_attr(attr_p); + return (SDP_SUCCESS); + } + + /* 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 + * fail on errors with attributes but just ignore them. + */ + return (SDP_SUCCESS); + } + + /* If this was an X-cpar/cpar attribute, it was hooked into the X-cap/cdsc + * structure, so we're finished. + */ + 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; + } + + return SDP_SUCCESS; +} + +sdp_result_e sdp_parse_attr_simple_string (sdp_t *sdp_p, sdp_attr_t *attr_p, + const char *ptr) +{ + sdp_result_e result; + + ptr = sdp_getnextstrtok(ptr, attr_p->attr.string_val, + sizeof(attr_p->attr.string_val), " \t", &result); + + 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_p->debug_flag[SDP_DEBUG_TRACE]) { + SDP_PRINT("%s Parsed a=%s, %s", sdp_p->debug_str, + sdp_get_attr_name(attr_p->type), + attr_p->attr.string_val); + } + return (SDP_SUCCESS); + } +} + +sdp_result_e sdp_build_attr_simple_string (sdp_t *sdp_p, sdp_attr_t *attr_p, + flex_string *fs) +{ + flex_string_sprintf(fs, "a=%s:%s\r\n", sdp_attr[attr_p->type].name, + attr_p->attr.string_val); + + return SDP_SUCCESS; +} + +sdp_result_e sdp_parse_attr_simple_u32 (sdp_t *sdp_p, sdp_attr_t *attr_p, + const char *ptr) +{ + sdp_result_e result; + + attr_p->attr.u32_val = sdp_getnextnumtok(ptr, &ptr, " \t", &result); + + if (result != SDP_SUCCESS) { + sdp_parse_error(sdp_p, + "%s Warning: Numeric token for %s attribute not found", + 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_p->debug_flag[SDP_DEBUG_TRACE]) { + SDP_PRINT("%s Parsed a=%s, %u", sdp_p->debug_str, + sdp_get_attr_name(attr_p->type), attr_p->attr.u32_val); + } + return (SDP_SUCCESS); + } +} + +sdp_result_e sdp_build_attr_simple_u32 (sdp_t *sdp_p, sdp_attr_t *attr_p, + flex_string *fs) +{ + flex_string_sprintf(fs, "a=%s:%u\r\n", sdp_attr[attr_p->type].name, + attr_p->attr.u32_val); + + return SDP_SUCCESS; +} + +sdp_result_e sdp_parse_attr_simple_bool (sdp_t *sdp_p, sdp_attr_t *attr_p, + const char *ptr) +{ + sdp_result_e result; + + if (sdp_getnextnumtok(ptr, &ptr, " \t", &result) == 0) { + attr_p->attr.boolean_val = FALSE; + } else { + attr_p->attr.boolean_val= TRUE; + } + + if (result != SDP_SUCCESS) { + sdp_parse_error(sdp_p, + "%s Warning: Boolean token for %s attribute not found", + 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_p->debug_flag[SDP_DEBUG_TRACE]) { + if (attr_p->attr.boolean_val) { + SDP_PRINT("%s Parsed a=%s, boolean is TRUE", sdp_p->debug_str, + sdp_get_attr_name(attr_p->type)); + } else { + SDP_PRINT("%s Parsed a=%s, boolean is FALSE", sdp_p->debug_str, + sdp_get_attr_name(attr_p->type)); + } + } + return (SDP_SUCCESS); + } +} + +sdp_result_e sdp_build_attr_simple_bool (sdp_t *sdp_p, sdp_attr_t *attr_p, + flex_string *fs) +{ + flex_string_sprintf(fs, "a=%s:%s\r\n", sdp_attr[attr_p->type].name, + attr_p->attr.boolean_val ? "1" : "0"); + + return SDP_SUCCESS; +} + +/* + * sdp_parse_attr_maxprate + * + * This function parses maxprate attribute lines. The ABNF for this a= + * line is: + * max-p-rate-def = "a" "=" "maxprate" ":" packet-rate CRLF + * packet-rate = 1*DIGIT ["." 1*DIGIT] + * + * Returns: + * SDP_INVALID_PARAMETER - If we are unable to parse the string OR if + * packet-rate is not in the right format as per + * the ABNF. + * + * SDP_SUCCESS - If we are able to successfully parse the a= line. + */ +sdp_result_e sdp_parse_attr_maxprate (sdp_t *sdp_p, sdp_attr_t *attr_p, + const char *ptr) +{ + sdp_result_e result; + + ptr = sdp_getnextstrtok(ptr, attr_p->attr.string_val, + sizeof(attr_p->attr.string_val), " \t", &result); + + 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); + } + + if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) { + SDP_PRINT("%s Parsed a=%s, %s", sdp_p->debug_str, + sdp_get_attr_name(attr_p->type), + attr_p->attr.string_val); + } + return (SDP_SUCCESS); + } +} + +/* + * sdp_attr_fmtp_no_value + * Helper function for sending the warning when a parameter value is + * missing. + * + */ +static void sdp_attr_fmtp_no_value(sdp_t *sdp, const char *param_name) +{ + sdp_parse_error(sdp, + "%s Warning: No %s value specified for fmtp attribute", + sdp->debug_str, param_name); + sdp->conf_p->num_invalid_param++; +} + +/* + * sdp_attr_fmtp_invalid_value + * Helper function for sending the warning when a parameter value is + * incorrect. + * + */ +static void sdp_attr_fmtp_invalid_value(sdp_t *sdp, const char *param_name, + const char* param_value) +{ + sdp_parse_error(sdp, + "%s Warning: Invalid %s: %s specified for fmtp attribute", + sdp->debug_str, param_name, param_value); + sdp->conf_p->num_invalid_param++; +} + +/* + * sdp_verify_attr_fmtp_telephone_event + * Helper function for verifying the telephone-event fmtp format + */ +static sdp_result_e sdp_verify_attr_fmtp_telephone_event(char *fmtpVal) +{ + size_t len = fmtpVal ? strlen(fmtpVal) : 0; + + // 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)); + + char *strtok_state; + char *temp = PL_strtok_r(dtmf_tones, ",", &strtok_state); + + 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; + } else if (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, (const char **)&temp, + "-", &result1); + high_val = (uint8_t)sdp_getnextnumtok(temp, (const char **)&temp, + "-", &result2); + if (temp[0] // we don't want to find a second hyphen + || result1 != SDP_SUCCESS + || result2 != SDP_SUCCESS) { + return SDP_INVALID_PARAMETER; + } + + if (low_val > 99 + || high_val > 99 + || high_val <= low_val) { + return SDP_INVALID_PARAMETER; + } + } + + temp=PL_strtok_r(NULL, ",", &strtok_state); + } + + return SDP_SUCCESS; +} + +/* Note: The fmtp attribute formats currently handled are: + * fmtp:<payload type> <event>,<event>... + * fmtp:<payload_type> [annexa=yes/no] [annexb=yes/no] [bitrate=<value>] + * [QCIF =<value>] [CIF =<value>] [MaxBR = <value>] one or more + * Other FMTP params as per H.263, H.263+, H.264 codec support. + * Note -"value" is a numeric value > 0 and each event is a + * single number or a range separated by a '-'. + * Example: fmtp:101 1,3-15,20 + * Video codecs have annexes that can be listed in the following legal formats: + * a) a=fmtp:34 param1=token;D;I;J;K=1;N=2;P=1,3 + * b) a=fmtp:34 param1=token;D;I;J;K=1;N=2;P=1,3;T + * c) a=fmtp:34 param1=token;D;I;J + * + */ +sdp_result_e sdp_get_fmtp_tok(sdp_t *sdp_p, + const char** fmtp_ptr, + const char* fmtp_name, + char* buf, + size_t buf_size, + char** tok) +{ + sdp_result_e result1 = SDP_SUCCESS; + + *fmtp_ptr = sdp_getnextstrtok(*fmtp_ptr, buf, buf_size, "; \t", &result1); + if (result1 != SDP_SUCCESS) { + *fmtp_ptr = sdp_getnextstrtok(*fmtp_ptr, buf, buf_size, " \t", &result1); + if (result1 != SDP_SUCCESS) { + sdp_attr_fmtp_no_value(sdp_p, fmtp_name); + return SDP_INVALID_PARAMETER; + } + } + *tok = buf; + (*tok)++; + + return SDP_SUCCESS; +} + +sdp_result_e sdp_get_fmtp_tok_val(sdp_t *sdp_p, + const char** fmtp_ptr, + const char* fmtp_name, + char* buf, + size_t buf_size, + char** tok, + unsigned long* strtoul_result, + unsigned long illegal_value, + unsigned long min_limit, + unsigned long max_limit) +{ + sdp_result_e result1 = SDP_SUCCESS; + unsigned long value; + char* strtoul_end; + + result1 = sdp_get_fmtp_tok(sdp_p, fmtp_ptr, fmtp_name, buf, buf_size, tok); + if (result1 != SDP_SUCCESS) return result1; + + errno = 0; + value = strtoul(*tok, &strtoul_end, 10); + + if (errno + || (*tok == strtoul_end) + || (illegal_value != ULONG_MAX && value == illegal_value) + || (min_limit != ULONG_MAX && value < min_limit) + || (max_limit != ULONG_MAX && value > max_limit)) { + sdp_attr_fmtp_invalid_value(sdp_p, fmtp_name, *tok); + return SDP_INVALID_PARAMETER; + } + *strtoul_result = value; + + return SDP_SUCCESS; +} + +sdp_result_e sdp_parse_attr_fmtp (sdp_t *sdp_p, sdp_attr_t *attr_p, + const char *ptr) +{ + uint16_t i; + uint32_t mapword; + uint32_t bmap; + uint8_t low_val; + uint8_t high_val; + const char *ptr2; + const char *fmtp_ptr; + sdp_result_e result1 = SDP_SUCCESS; + sdp_result_e result2 = SDP_SUCCESS; + tinybool done = FALSE; + tinybool codec_info_found = FALSE; + sdp_fmtp_t *fmtp_p; + char tmp[SDP_MAX_STRING_LEN]; + char *src_ptr; + char *temp_ptr = NULL; + char *tok=NULL; + char *temp=NULL; + uint16_t custom_x=0; + uint16_t custom_y=0; + uint16_t custom_mpi=0; + uint16_t par_height=0; + uint16_t par_width=0; + uint16_t cpcf=0; + uint16_t iter=0; + + ulong l_val = 0; + char* strtok_state; + unsigned long strtoul_result; + char* strtoul_end; + + /* Find the payload type number. */ + attr_p->attr.fmtp.payload_num = (uint16_t)sdp_getnextnumtok(ptr, &ptr, + " \t", &result1); + if (result1 != SDP_SUCCESS) { + sdp_attr_fmtp_no_value(sdp_p, "payload type"); + return SDP_INVALID_PARAMETER; + } + fmtp_p = &(attr_p->attr.fmtp); + fmtp_p->fmtp_format = SDP_FMTP_UNKNOWN_TYPE; + fmtp_p->parameter_add = 1; + fmtp_p->flag = 0; + + /* + * set default value of packetization mode and level-asymmetry-allowed. If + * remote sdp does not specify any value for these two parameters, then the + * default value will be assumed for remote sdp. If remote sdp does specify + * any value for these parameters, then default value will be overridden. + */ + fmtp_p->packetization_mode = SDP_DEFAULT_PACKETIZATION_MODE_VALUE; + fmtp_p->level_asymmetry_allowed = SDP_DEFAULT_LEVEL_ASYMMETRY_ALLOWED_VALUE; + + temp_ptr = cpr_strdup(ptr); + if (temp_ptr == NULL) { + return (SDP_FAILURE); + } + fmtp_ptr = src_ptr = temp_ptr; + + src_ptr = temp_ptr; + while (!done) { + fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "= \t", &result1); + if (result1 == SDP_SUCCESS) { + if (cpr_strncasecmp(tmp, sdp_fmtp_codec_param[1].name, + sdp_fmtp_codec_param[1].strlen) == 0) { + result1 = sdp_get_fmtp_tok(sdp_p, &fmtp_ptr, "annexb", tmp, sizeof(tmp), &tok); + if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; } + + if (cpr_strncasecmp(tok,sdp_fmtp_codec_param_val[0].name, + sdp_fmtp_codec_param_val[0].strlen) == 0) { + fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO; + fmtp_p->annexb_required = TRUE; + fmtp_p->annexb = TRUE; + } else if (cpr_strncasecmp(tok,sdp_fmtp_codec_param_val[1].name, + sdp_fmtp_codec_param_val[1].strlen) == 0) { + fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO; + fmtp_p->annexb_required = TRUE; + fmtp_p->annexb = FALSE; + } else { + sdp_attr_fmtp_invalid_value(sdp_p, "annexb", tok); + SDP_FREE(temp_ptr); + return SDP_INVALID_PARAMETER; + } + codec_info_found = TRUE; + + } else if (cpr_strncasecmp(tmp, sdp_fmtp_codec_param[0].name, + sdp_fmtp_codec_param[0].strlen) == 0) { + result1 = sdp_get_fmtp_tok(sdp_p, &fmtp_ptr, "annexa", tmp, sizeof(tmp), &tok); + if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; } + + if (cpr_strncasecmp(tok,sdp_fmtp_codec_param_val[0].name, + sdp_fmtp_codec_param_val[0].strlen) == 0) { + fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO; + fmtp_p->annexa = TRUE; + fmtp_p->annexa_required = TRUE; + } else if (cpr_strncasecmp(tok,sdp_fmtp_codec_param_val[1].name, + sdp_fmtp_codec_param_val[1].strlen) == 0) { + fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO; + fmtp_p->annexa = FALSE; + fmtp_p->annexa_required = TRUE; + } else { + sdp_attr_fmtp_invalid_value(sdp_p, "annexa", tok); + SDP_FREE(temp_ptr); + return SDP_INVALID_PARAMETER; + } + codec_info_found = TRUE; + + } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[2].name, + sdp_fmtp_codec_param[2].strlen) == 0) { + result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "bitrate", tmp, sizeof(tmp), + &tok, &strtoul_result, 0, -1, UINT_MAX); + if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; } + + fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO; + fmtp_p->bitrate = (uint32_t) strtoul_result; + codec_info_found = TRUE; + + } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[41].name, + sdp_fmtp_codec_param[41].strlen) == 0) { + result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "mode", tmp, sizeof(tmp), + &tok, &strtoul_result, -1, -1, UINT_MAX); + if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; } + + fmtp_p->fmtp_format = SDP_FMTP_MODE; + fmtp_p->mode = (uint32_t) strtoul_result; + codec_info_found = TRUE; + + } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[3].name, + sdp_fmtp_codec_param[3].strlen) == 0) { + result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "qcif", tmp, sizeof(tmp), + &tok, &strtoul_result, -1, SDP_MIN_CIF_VALUE, SDP_MAX_CIF_VALUE); + if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; } + + fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO; + fmtp_p->qcif = (uint16_t) strtoul_result; + codec_info_found = TRUE; + + } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[4].name, + sdp_fmtp_codec_param[4].strlen) == 0) { + result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "cif", tmp, sizeof(tmp), + &tok, &strtoul_result, -1, SDP_MIN_CIF_VALUE, SDP_MAX_CIF_VALUE); + if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; } + + fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO; + fmtp_p->cif = (uint16_t) strtoul_result; + codec_info_found = TRUE; + + } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[5].name, + sdp_fmtp_codec_param[5].strlen) == 0) { + result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "maxbr", tmp, sizeof(tmp), + &tok, &strtoul_result, 0, -1, USHRT_MAX); + if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; } + + fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO; + fmtp_p->maxbr = (uint16_t) strtoul_result; + codec_info_found = TRUE; + + } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[6].name, + sdp_fmtp_codec_param[6].strlen) == 0) { + result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "sqcif", tmp, sizeof(tmp), + &tok, &strtoul_result, -1, SDP_MIN_CIF_VALUE, SDP_MAX_CIF_VALUE); + if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; } + + fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO; + fmtp_p->sqcif = (uint16_t) strtoul_result; + codec_info_found = TRUE; + + } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[7].name, + sdp_fmtp_codec_param[7].strlen) == 0) { + result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "cif4", tmp, sizeof(tmp), + &tok, &strtoul_result, -1, SDP_MIN_CIF_VALUE, SDP_MAX_CIF_VALUE); + if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; } + + fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO; + fmtp_p->cif4 = (uint16_t) strtoul_result; + codec_info_found = TRUE; + + } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[8].name, + sdp_fmtp_codec_param[8].strlen) == 0) { + result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "cif16", tmp, sizeof(tmp), + &tok, &strtoul_result, -1, SDP_MIN_CIF_VALUE, SDP_MAX_CIF_VALUE); + if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; } + + fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO; + fmtp_p->cif16 = (uint16_t) strtoul_result; + codec_info_found = TRUE; + + } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[9].name, + sdp_fmtp_codec_param[9].strlen) == 0) { + result1 = sdp_get_fmtp_tok(sdp_p, &fmtp_ptr, "custom", tmp, sizeof(tmp), &tok); + if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; } + + temp=PL_strtok_r(tok, ",", &strtok_state); + iter++; + if (temp) { + iter=1; + while (temp != NULL) { + errno = 0; + strtoul_result = strtoul(temp, &strtoul_end, 10); + + if (errno || temp == strtoul_end || strtoul_result > USHRT_MAX){ + custom_x = custom_y = custom_mpi = 0; + break; + } + + if (iter == 1) + custom_x = (uint16_t) strtoul_result; + if (iter == 2) + custom_y = (uint16_t) strtoul_result; + if (iter == 3) + custom_mpi = (uint16_t) strtoul_result; + + temp=PL_strtok_r(NULL, ",", &strtok_state); + iter++; + } + } + + /* custom x,y and mpi values from tmp */ + if (!custom_x || !custom_y || !custom_mpi) { + sdp_attr_fmtp_invalid_value(sdp_p, "x/y/MPI", temp); + SDP_FREE(temp_ptr); + return SDP_INVALID_PARAMETER; + } + fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO; + fmtp_p->custom_x = custom_x; + fmtp_p->custom_y = custom_y; + fmtp_p->custom_mpi = custom_mpi; + codec_info_found = TRUE; + + } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[10].name, + sdp_fmtp_codec_param[10].strlen) == 0) { + result1 = sdp_get_fmtp_tok(sdp_p, &fmtp_ptr, "par", tmp, sizeof(tmp), &tok); + if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; } + + 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); + + if (errno || temp == strtoul_end || strtoul_result > USHRT_MAX) { + par_width = par_height = 0; + break; + } + + if (iter == 1) + par_width = (uint16_t) strtoul_result; + else + par_height = (uint16_t) strtoul_result; + + temp=PL_strtok_r(NULL, ",", &strtok_state); + iter++; + } + } + if (!par_width || !par_height) { + sdp_attr_fmtp_invalid_value(sdp_p, "par_width or par_height", temp); + SDP_FREE(temp_ptr); + return SDP_INVALID_PARAMETER; + } + fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO; + fmtp_p->par_width = par_width; + fmtp_p->par_height = par_height; + codec_info_found = TRUE; + + } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[11].name, + sdp_fmtp_codec_param[11].strlen) == 0) { + result1 = sdp_get_fmtp_tok(sdp_p, &fmtp_ptr, "cpcf", tmp, sizeof(tmp), &tok); + if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; } + + temp=PL_strtok_r(tok, ".", &strtok_state); + if ( temp != NULL ) { + errno = 0; + strtoul_result = strtoul(temp, &strtoul_end, 10); + + if (errno || temp == strtoul_end || strtoul_result > USHRT_MAX) { + cpcf = 0; + } else { + cpcf = (uint16_t) strtoul_result; + } + } + + if (!cpcf) { + sdp_attr_fmtp_invalid_value(sdp_p, "cpcf", tok); + SDP_FREE(temp_ptr); + return SDP_INVALID_PARAMETER; + } + fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO; + fmtp_p->cpcf = cpcf; + codec_info_found = TRUE; + + } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[12].name, + sdp_fmtp_codec_param[12].strlen) == 0) { + result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "bpp", tmp, sizeof(tmp), + &tok, &strtoul_result, 0, -1, USHRT_MAX); + if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; } + + fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO; + fmtp_p->bpp = (uint16_t) strtoul_result; + codec_info_found = TRUE; + + } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[13].name, + sdp_fmtp_codec_param[13].strlen) == 0) { + result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "hrd", tmp, sizeof(tmp), + &tok, &strtoul_result, 0, -1, USHRT_MAX); + if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; } + + fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO; + fmtp_p->hrd = (uint16_t) strtoul_result; + codec_info_found = TRUE; + + } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[14].name, + sdp_fmtp_codec_param[14].strlen) == 0) { + result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "profile", tmp, sizeof(tmp), + &tok, &strtoul_result, -1, -1, SDP_MAX_PROFILE_VALUE); + if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; } + + fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO; + fmtp_p->profile = (short) strtoul_result; + codec_info_found = TRUE; + + } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[15].name, + sdp_fmtp_codec_param[15].strlen) == 0) { + result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "level", tmp, sizeof(tmp), + &tok, &strtoul_result, -1, -1, SDP_MAX_LEVEL_VALUE); + if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; } + + fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO; + fmtp_p->level = (short) strtoul_result; + codec_info_found = TRUE; + + } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[16].name, + sdp_fmtp_codec_param[16].strlen) == 0) { + fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO; + fmtp_p->is_interlace = TRUE; + codec_info_found = TRUE; + + } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[17].name, + sdp_fmtp_codec_param[17].strlen) == 0) { + result1 = sdp_get_fmtp_tok(sdp_p, &fmtp_ptr, "profile_level_id", tmp, sizeof(tmp), &tok); + if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; } + + fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO; + sstrncpy(fmtp_p->profile_level_id , tok, sizeof(fmtp_p->profile_level_id)); + codec_info_found = TRUE; + + } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[18].name, + sdp_fmtp_codec_param[18].strlen) == 0) { + result1 = sdp_get_fmtp_tok(sdp_p, &fmtp_ptr, "parameter_sets", tmp, sizeof(tmp), &tok); + if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; } + + fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO; + sstrncpy(fmtp_p->parameter_sets , tok, sizeof(fmtp_p->parameter_sets)); + codec_info_found = TRUE; + + } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[19].name, + sdp_fmtp_codec_param[19].strlen) == 0) { + result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "packetization_mode", tmp, sizeof(tmp), + &tok, &strtoul_result, -1, -1, 2); + // 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; } + + fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO; + fmtp_p->packetization_mode = (int16_t) strtoul_result; + codec_info_found = TRUE; + + } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[20].name, + sdp_fmtp_codec_param[20].strlen) == 0) { + result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "interleaving_depth", tmp, sizeof(tmp), + &tok, &strtoul_result, 0, -1, USHRT_MAX); + if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; } + + fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO; + fmtp_p->interleaving_depth = (uint16_t) strtoul_result; + codec_info_found = TRUE; + + } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[21].name, + sdp_fmtp_codec_param[21].strlen) == 0) { + result1 = sdp_get_fmtp_tok(sdp_p, &fmtp_ptr, "deint_buf", tmp, sizeof(tmp), &tok); + if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; } + + if (sdp_checkrange(sdp_p, tok, &l_val) == TRUE) { + fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO; + fmtp_p->deint_buf_req = (uint32_t) l_val; + fmtp_p->flag |= SDP_DEINT_BUF_REQ_FLAG; + codec_info_found = TRUE; + } else { + sdp_attr_fmtp_invalid_value(sdp_p, "deint_buf_req", tok); + SDP_FREE(temp_ptr); + return SDP_INVALID_PARAMETER; + } + + } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[22].name, + sdp_fmtp_codec_param[22].strlen) == 0) { + result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "max_don_diff", tmp, sizeof(tmp), + &tok, &strtoul_result, 0, -1, UINT_MAX); + if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; } + + fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO; + fmtp_p->max_don_diff = (uint32_t) strtoul_result; + codec_info_found = TRUE; + + } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[23].name, + sdp_fmtp_codec_param[23].strlen) == 0) { + result1 = sdp_get_fmtp_tok(sdp_p, &fmtp_ptr, "init_buf_time", tmp, sizeof(tmp), &tok); + if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; } + + if (sdp_checkrange(sdp_p, tok, &l_val) == TRUE) { + fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO; + fmtp_p->init_buf_time = (uint32_t) l_val; + fmtp_p->flag |= SDP_INIT_BUF_TIME_FLAG; + codec_info_found = TRUE; + } else { + sdp_attr_fmtp_invalid_value(sdp_p, "init_buf_time", tok); + SDP_FREE(temp_ptr); + return SDP_INVALID_PARAMETER; + } + + } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[24].name, + sdp_fmtp_codec_param[24].strlen) == 0) { + result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "max_mbps", tmp, sizeof(tmp), + &tok, &strtoul_result, 0, -1, UINT_MAX); + if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; } + + fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO; + fmtp_p->max_mbps = (uint32_t) strtoul_result; + codec_info_found = TRUE; + + } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[25].name, + sdp_fmtp_codec_param[25].strlen) == 0) { + result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "max-fs", tmp, sizeof(tmp), + &tok, &strtoul_result, 0, -1, UINT_MAX); + if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; } + + fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO; + fmtp_p->max_fs = (uint32_t) strtoul_result; + codec_info_found = TRUE; + + } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[26].name, + sdp_fmtp_codec_param[26].strlen) == 0) { + result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "max_cbp", tmp, sizeof(tmp), + &tok, &strtoul_result, 0, -1, UINT_MAX); + if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; } + + fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO; + fmtp_p->max_cpb = (uint32_t) strtoul_result; + codec_info_found = TRUE; + + } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[27].name, + sdp_fmtp_codec_param[27].strlen) == 0) { + result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "max_dpb", tmp, sizeof(tmp), + &tok, &strtoul_result, 0, -1, UINT_MAX); + if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; } + + fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO; + fmtp_p->max_dpb = (uint32_t) strtoul_result; + codec_info_found = TRUE; + + } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[28].name, + sdp_fmtp_codec_param[28].strlen) == 0) { + result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "max_br", tmp, sizeof(tmp), + &tok, &strtoul_result, 0, -1, UINT_MAX); + if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; } + + fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO; + fmtp_p->max_br = (uint32_t) strtoul_result; + codec_info_found = TRUE; + + } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[29].name, + sdp_fmtp_codec_param[29].strlen) == 0) { + result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "redundant_pic_cap", tmp, sizeof(tmp), + &tok, &strtoul_result, 0, -1, 1); + fmtp_p->redundant_pic_cap = (result1 == SDP_SUCCESS); + codec_info_found = TRUE; + + } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[30].name, + sdp_fmtp_codec_param[30].strlen) == 0) { + result1 = sdp_get_fmtp_tok(sdp_p, &fmtp_ptr, "deint_buf_cap", tmp, sizeof(tmp), &tok); + if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; } + + if (sdp_checkrange(sdp_p, tok, &l_val) == TRUE) { + fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO; + fmtp_p->deint_buf_cap = (uint32_t) l_val; + fmtp_p->flag |= SDP_DEINT_BUF_CAP_FLAG; + codec_info_found = TRUE; + } else { + sdp_attr_fmtp_invalid_value(sdp_p, "deint_buf_cap", tok); + SDP_FREE(temp_ptr); + return SDP_INVALID_PARAMETER; + } + + } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[31].name, + sdp_fmtp_codec_param[31].strlen) == 0) { + result1 = sdp_get_fmtp_tok(sdp_p, &fmtp_ptr, "max_rcmd_nalu_size", tmp, sizeof(tmp), &tok); + if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; } + + if (sdp_checkrange(sdp_p, tok, &l_val) == TRUE) { + fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO; + fmtp_p->max_rcmd_nalu_size = (uint32_t) l_val; + fmtp_p->flag |= SDP_MAX_RCMD_NALU_SIZE_FLAG; + codec_info_found = TRUE; + } else { + sdp_attr_fmtp_invalid_value(sdp_p, "max_rcmd_nalu_size", tok); + SDP_FREE(temp_ptr); + return SDP_INVALID_PARAMETER; + } + + } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[32].name, + sdp_fmtp_codec_param[32].strlen) == 0) { + result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "parameter_add", tmp, sizeof(tmp), + &tok, &strtoul_result, 0, -1, 1); + if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; } + + fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO; + fmtp_p->parameter_add = (uint16_t) strtoul_result; + codec_info_found = TRUE; + + } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[33].name, + sdp_fmtp_codec_param[33].strlen) == 0) { + fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO; + fmtp_p->annex_d = TRUE; + codec_info_found = TRUE; + + } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[34].name, + sdp_fmtp_codec_param[34].strlen) == 0) { + fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO; + fmtp_p->annex_f = TRUE; + codec_info_found = TRUE; + + } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[35].name, + sdp_fmtp_codec_param[35].strlen) == 0) { + fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO; + fmtp_p->annex_i = TRUE; + codec_info_found = TRUE; + + } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[36].name, + sdp_fmtp_codec_param[36].strlen) == 0) { + fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO; + fmtp_p->annex_j = TRUE; + codec_info_found = TRUE; + + } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[37].name, + sdp_fmtp_codec_param[36].strlen) == 0) { + fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO; + fmtp_p->annex_t = TRUE; + codec_info_found = TRUE; + + } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[38].name, + sdp_fmtp_codec_param[38].strlen) == 0) { + result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "annex_k", tmp, sizeof(tmp), + &tok, &strtoul_result, 0, -1, USHRT_MAX); + if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; } + + fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO; + fmtp_p->annex_k_val = (uint16_t) strtoul_result; + codec_info_found = TRUE; + + } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[39].name, + sdp_fmtp_codec_param[39].strlen) == 0) { + result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "annex_n", tmp, sizeof(tmp), + &tok, &strtoul_result, 0, -1, USHRT_MAX); + if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; } + + fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO; + fmtp_p->annex_n_val = (uint16_t) strtoul_result; + codec_info_found = TRUE; + + } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[40].name, + sdp_fmtp_codec_param[40].strlen) == 0) { + result1 = sdp_get_fmtp_tok(sdp_p, &fmtp_ptr, "annex_p", tmp, sizeof(tmp), &tok); + if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; } + + fmtp_p->annex_p_val_picture_resize = 0; + fmtp_p->annex_p_val_warp = 0; + temp = PL_strtok_r(tok, ",", &strtok_state); + if (temp) { + iter=1; + while (temp != NULL) { + errno = 0; + strtoul_result = strtoul(temp, &strtoul_end, 10); + + if (errno || temp == strtoul_end || strtoul_result > USHRT_MAX) { + break; + } + + if (iter == 1) + fmtp_p->annex_p_val_picture_resize = (uint16_t) strtoul_result; + else if (iter == 2) + fmtp_p->annex_p_val_warp = (uint16_t) strtoul_result; + + temp = PL_strtok_r(NULL, ",", &strtok_state); + iter++; + } + } else { + SDP_FREE(temp_ptr); + return SDP_INVALID_PARAMETER; + } + + fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO; + codec_info_found = TRUE; + + } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[42].name, + sdp_fmtp_codec_param[42].strlen) == 0) { + result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "level_asymmetry_allowed", tmp, sizeof(tmp), + &tok, &strtoul_result, -1, -1, SDP_MAX_LEVEL_ASYMMETRY_ALLOWED_VALUE); + if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; } + + fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO; + fmtp_p->level_asymmetry_allowed = (int) strtoul_result; + codec_info_found = TRUE; + + } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[43].name, + sdp_fmtp_codec_param[43].strlen) == 0) { + result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "maxaveragebitrate", tmp, sizeof(tmp), + &tok, &strtoul_result, 0, -1, UINT_MAX); + if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; } + + fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO; + fmtp_p->maxaveragebitrate = (uint32_t) strtoul_result; + codec_info_found = TRUE; + + } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[44].name, + sdp_fmtp_codec_param[44].strlen) == 0) { + result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "usedtx", tmp, sizeof(tmp), + &tok, &strtoul_result, -1, -1, 1); + if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; } + + fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO; + fmtp_p->usedtx = (uint16_t) strtoul_result; + codec_info_found = TRUE; + + } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[45].name, + sdp_fmtp_codec_param[45].strlen) == 0) { + result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "stereo", tmp, sizeof(tmp), + &tok, &strtoul_result, -1, -1, 1); + if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; } + + fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO; + fmtp_p->stereo = (uint16_t) strtoul_result; + codec_info_found = TRUE; + + } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[46].name, + sdp_fmtp_codec_param[46].strlen) == 0) { + result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "useinbandfec", tmp, sizeof(tmp), + &tok, &strtoul_result, -1, -1, 1); + if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; } + + fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO; + fmtp_p->useinbandfec = (uint16_t) strtoul_result; + codec_info_found = TRUE; + + } else if (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; } + + fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO; + sstrncpy(fmtp_p->maxcodedaudiobandwidth , tok, sizeof(fmtp_p->maxcodedaudiobandwidth)); + codec_info_found = TRUE; + + } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[48].name, + sdp_fmtp_codec_param[48].strlen) == 0) { + result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "cbr", tmp, sizeof(tmp), + &tok, &strtoul_result, -1, -1, 1); + if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; } + + fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO; + fmtp_p->cbr = (uint16_t) strtoul_result; + codec_info_found = TRUE; + + } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[49].name, + sdp_fmtp_codec_param[49].strlen) == 0) { + result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "max-fr", tmp, sizeof(tmp), + &tok, &strtoul_result, 0, -1, UINT_MAX); + if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; } + + fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO; + fmtp_p->max_fr = (uint32_t) strtoul_result; + codec_info_found = TRUE; + + } else if (cpr_strncasecmp(tmp,sdp_fmtp_codec_param[50].name, + sdp_fmtp_codec_param[50].strlen) == 0) { + result1 = sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "maxplaybackrate", tmp, sizeof(tmp), + &tok, &strtoul_result, 0, -1, UINT_MAX); + if (result1 != SDP_SUCCESS) { SDP_FREE(temp_ptr); return result1; } + + fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO; + fmtp_p->maxplaybackrate = (uint32_t) strtoul_result; + codec_info_found = TRUE; + + } else if (cpr_strncasecmp(tmp, sdp_fmtp_codec_param[51].name, + sdp_fmtp_codec_param[51].strlen) == 0) { + result1 = + sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "apt", tmp, sizeof(tmp), + &tok, &strtoul_result, -1, 0, UINT8_MAX); + if (result1 != SDP_SUCCESS) { + SDP_FREE(temp_ptr); + return result1; + } + + fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO; + fmtp_p->apt = (uint8_t)strtoul_result; + + codec_info_found = TRUE; + + } else if (cpr_strncasecmp(tmp, sdp_fmtp_codec_param[52].name, + sdp_fmtp_codec_param[52].strlen) == 0) { + + result1 = + sdp_get_fmtp_tok_val(sdp_p, &fmtp_ptr, "rtx_time", tmp, sizeof(tmp), + &tok, &strtoul_result, -1, 0, UINT_MAX); + if (result1 != SDP_SUCCESS) { + SDP_FREE(temp_ptr); + return result1; + } + + fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO; + fmtp_p->has_rtx_time = TRUE; + fmtp_p->rtx_time = (uint32_t)strtoul_result; + + codec_info_found = TRUE; + + } else if (fmtp_ptr != NULL && *fmtp_ptr == '\n') { + temp=PL_strtok_r(tmp, ";", &strtok_state); + if (temp) { + if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) { + SDP_PRINT("%s Annexes are possibly there for this fmtp %s tmp: %s line\n", + sdp_p->debug_str, fmtp_ptr, tmp); + } + while (temp != NULL) { + if (strchr(temp, 'D') !=NULL) { + attr_p->attr.fmtp.annex_d = TRUE; + } + if (strchr(temp, 'F') !=NULL) { + attr_p->attr.fmtp.annex_f = TRUE; + } + if (strchr(temp, 'I') !=NULL) { + attr_p->attr.fmtp.annex_i = TRUE; + } + if (strchr(temp, 'J') !=NULL) { + attr_p->attr.fmtp.annex_j = TRUE; + } + if (strchr(temp, 'T') !=NULL) { + attr_p->attr.fmtp.annex_t = TRUE; + } + temp=PL_strtok_r(NULL, ";", &strtok_state); + } + } /* if (temp) */ + done = TRUE; + } else if (strchr(tmp, '/')) { + // XXX Note that because RFC 5109 so conveniently specified + // this fmtp with no param names, we hope that nothing else + // has a slash in the string because otherwise we won't know + // how to differentiate. + temp=PL_strtok_r(tmp, "/", &strtok_state); + if (temp) { + iter = 0; + while (temp != NULL) { + errno = 0; + strtoul_result = strtoul(temp, &strtoul_end, 10); + + if (errno || + temp == strtoul_end || strtoul_result > USHRT_MAX) { + temp = NULL; + continue; + } + fmtp_p->redundant_encodings[iter++] = + (uint8_t)strtoul_result; + temp=PL_strtok_r(NULL, "/", &strtok_state); + } + } /* if (temp) */ + } else if (SDP_SUCCESS == sdp_verify_attr_fmtp_telephone_event(tmp)) { + // XXX Note that DTMF fmtp will fall into here: + // a=fmtp:101 0-15 (or 0-15,NN,NN etc) + sstrncpy(fmtp_p->dtmf_tones , tmp, sizeof(fmtp_p->dtmf_tones)); + codec_info_found = TRUE; + } else { + // unknown parameter - eat chars until ';' + SDPLogDebug(logTag, "%s Unknown fmtp type (%s) - ignoring", __FUNCTION__, + tmp); + fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), "; \t", + &result1); + if (result1 != SDP_SUCCESS) { + fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), " \t", &result1); + if (result1 != SDP_SUCCESS) { + // hmmm, no ; or spaces or tabs; continue on + } + } + } + if (*fmtp_ptr == '\n') { + // reached end of line, stop parsing + done = TRUE; + } else { + fmtp_ptr++; + } + } else { + done = TRUE; + } + } /* while - done loop*/ + + if (codec_info_found) { + + if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) { + SDP_PRINT("%s Parsed a=%s, payload type %u, bitrate %u, mode %u QCIF = %u, CIF = %u, MAXBR= %u, SQCIF=%u, CIF4= %u, CIF16=%u, CUSTOM=%u,%u,%u , PAR=%u:%u,CPCF=%u, BPP=%u, HRD=%u \n", + sdp_p->debug_str, + sdp_get_attr_name(attr_p->type), + attr_p->attr.fmtp.payload_num, + attr_p->attr.fmtp.bitrate, + attr_p->attr.fmtp.mode, + attr_p->attr.fmtp.qcif, + attr_p->attr.fmtp.cif, + attr_p->attr.fmtp.maxbr, + attr_p->attr.fmtp.sqcif, + attr_p->attr.fmtp.cif4, + attr_p->attr.fmtp.cif16, + attr_p->attr.fmtp.custom_x,attr_p->attr.fmtp.custom_y, + attr_p->attr.fmtp.custom_mpi, + attr_p->attr.fmtp.par_width, + attr_p->attr.fmtp.par_height, + attr_p->attr.fmtp.cpcf, + attr_p->attr.fmtp.bpp, + attr_p->attr.fmtp.hrd + ); + } + + if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) { + SDP_PRINT("%s Parsed a=%s, payload type %u,PROFILE=%u,LEVEL=%u, INTERLACE - %s", + sdp_p->debug_str, + sdp_get_attr_name(attr_p->type), + attr_p->attr.fmtp.payload_num, + attr_p->attr.fmtp.profile, + attr_p->attr.fmtp.level, + attr_p->attr.fmtp.is_interlace ? "YES":"NO"); + } + + if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) { + SDP_PRINT("%s Parsed H.264 attributes: profile-level-id=%s, parameter-sets=%s, packetization-mode=%d level-asymmetry-allowed=%d interleaving-depth=%d deint-buf-req=%u max-don-diff=%u, init_buf-time=%u\n", + sdp_p->debug_str, + attr_p->attr.fmtp.profile_level_id, + attr_p->attr.fmtp.parameter_sets, + attr_p->attr.fmtp.packetization_mode, + attr_p->attr.fmtp.level_asymmetry_allowed, + attr_p->attr.fmtp.interleaving_depth, + attr_p->attr.fmtp.deint_buf_req, + attr_p->attr.fmtp.max_don_diff, + attr_p->attr.fmtp.init_buf_time + ); + } + + if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) { + SDP_PRINT("\n%s Parsed H.264 opt attributes: max-mbps=%u, max-fs=%u, max-cpb=%u max-dpb=%u max-br=%u redundant-pic-cap=%d, deint-buf-cap=%u, max-rcmd-nalu-size=%u , parameter-add=%d\n", + sdp_p->debug_str, + attr_p->attr.fmtp.max_mbps, + attr_p->attr.fmtp.max_fs, + attr_p->attr.fmtp.max_cpb, + attr_p->attr.fmtp.max_dpb, + attr_p->attr.fmtp.max_br, + attr_p->attr.fmtp.redundant_pic_cap, + attr_p->attr.fmtp.deint_buf_cap, + attr_p->attr.fmtp.max_rcmd_nalu_size, + attr_p->attr.fmtp.parameter_add); + + } + if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) { + SDP_PRINT("%s Parsed annexes are : D=%d F=%d I=%d J=%d T=%d, K=%d N=%d P=%d,%d\n", + sdp_p->debug_str, + attr_p->attr.fmtp.annex_d, + attr_p->attr.fmtp.annex_f, attr_p->attr.fmtp.annex_i, + attr_p->attr.fmtp.annex_j, attr_p->attr.fmtp.annex_t, + attr_p->attr.fmtp.annex_k_val, + attr_p->attr.fmtp.annex_n_val, + attr_p->attr.fmtp.annex_p_val_picture_resize, + attr_p->attr.fmtp.annex_p_val_warp); + + } + SDP_FREE(temp_ptr); + return (SDP_SUCCESS); + } else { + done = FALSE; + fmtp_ptr = src_ptr; + tmp[0] = '\0'; + } + + for (i=0; !done; i++) { + fmtp_p->fmtp_format = SDP_FMTP_NTE; + /* Look for comma separated events */ + fmtp_ptr = sdp_getnextstrtok(fmtp_ptr, tmp, sizeof(tmp), ", \t", &result1); + if (result1 != SDP_SUCCESS) { + done = TRUE; + continue; + } + /* Now look for '-' separated range */ + ptr2 = tmp; + low_val = (uint8_t)sdp_getnextnumtok(ptr2, (const char **)&ptr2, + "- \t", &result1); + if (*ptr2 == '-') { + high_val = (uint8_t)sdp_getnextnumtok(ptr2, (const char **)&ptr2, + "- \t", &result2); + } else { + high_val = low_val; + } + + if ((result1 != SDP_SUCCESS) || (result2 != SDP_SUCCESS)) { + sdp_parse_error(sdp_p, + "%s Warning: Invalid named events specified for fmtp attribute.", + sdp_p->debug_str); + sdp_p->conf_p->num_invalid_param++; + SDP_FREE(temp_ptr); + return (SDP_INVALID_PARAMETER); + } + + for (i = low_val; i <= high_val; i++) { + mapword = i/SDP_NE_BITS_PER_WORD; + bmap = ((unsigned)SDP_NE_BIT_0) << (i%32); + fmtp_p->bmap[mapword] |= bmap; + } + if (high_val > fmtp_p->maxval) { + fmtp_p->maxval = high_val; + } + } + + if (fmtp_p->maxval == 0) { + sdp_parse_error(sdp_p, + "%s Warning: No named events specified for fmtp attribute.", + sdp_p->debug_str); + sdp_p->conf_p->num_invalid_param++; + SDP_FREE(temp_ptr); + return (SDP_INVALID_PARAMETER); + } + + if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) { + SDP_PRINT("%s Parsed a=%s, payload type %u, ", sdp_p->debug_str, + sdp_get_attr_name(attr_p->type), + attr_p->attr.fmtp.payload_num); + } + SDP_FREE(temp_ptr); + return (SDP_SUCCESS); +} + +sdp_result_e +sdp_build_attr_fmtp_params (sdp_t *sdp_p, sdp_fmtp_t *fmtp_p, flex_string *fs) +{ + uint16_t event_id; + uint32_t mask; + uint32_t mapword; + uint8_t min = 0; + uint8_t max = 0; + tinybool range_start = FALSE; + tinybool range_end = FALSE; + tinybool semicolon = FALSE; + + switch (fmtp_p->fmtp_format) { + case SDP_FMTP_MODE: + sdp_append_name_and_unsigned(fs, "mode", fmtp_p->mode, FALSE); + break; + + case SDP_FMTP_CODEC_INFO: + FMTP_BUILD_UNSIGNED(fmtp_p->bitrate > 0, "bitrate", fmtp_p->bitrate) + + FMTP_BUILD_STRING(fmtp_p->annexa_required, + "annexa", (fmtp_p->annexa ? "yes" : "no")) + + FMTP_BUILD_STRING(fmtp_p->annexb_required, + "annexb", (fmtp_p->annexa ? "yes" : "no")) + + FMTP_BUILD_UNSIGNED(fmtp_p->qcif > 0, "QCIF", fmtp_p->qcif) + + FMTP_BUILD_UNSIGNED(fmtp_p->cif > 0, "CIF", fmtp_p->cif) + + FMTP_BUILD_UNSIGNED(fmtp_p->maxbr > 0, "MAXBR", fmtp_p->maxbr) + + FMTP_BUILD_UNSIGNED(fmtp_p->sqcif > 0, "SQCIF", fmtp_p->sqcif) + + FMTP_BUILD_UNSIGNED(fmtp_p->cif4 > 0, "CIF4", fmtp_p->cif4) + + FMTP_BUILD_UNSIGNED(fmtp_p->cif16 > 0, "CIF16", fmtp_p->cif16) + + if ((fmtp_p->custom_x > 0) && (fmtp_p->custom_y > 0) && + (fmtp_p->custom_mpi > 0)) { + flex_string_sprintf(fs, "%sCUSTOM=%u,%u,%u", + semicolon ? ";" : "", + fmtp_p->custom_x, + fmtp_p->custom_y, + fmtp_p->custom_mpi); + + semicolon = TRUE; + } + + if ((fmtp_p->par_height > 0) && (fmtp_p->par_width > 0)) { + flex_string_sprintf(fs, "%sPAR=%u:%u", + semicolon ? ";" : "", + fmtp_p->par_width, + fmtp_p->par_width); + + semicolon = TRUE; + } + + FMTP_BUILD_UNSIGNED(fmtp_p->cpcf > 0, "CPCF", fmtp_p->cpcf) + + FMTP_BUILD_UNSIGNED(fmtp_p->bpp > 0, "BPP", fmtp_p->bpp) + + FMTP_BUILD_UNSIGNED(fmtp_p->hrd > 0, "HRD", fmtp_p->hrd) + + FMTP_BUILD_UNSIGNED(fmtp_p->profile >= 0, "PROFILE", fmtp_p->profile) + + FMTP_BUILD_UNSIGNED(fmtp_p->level >= 0, "LEVEL", fmtp_p->level) + + FMTP_BUILD_FLAG(fmtp_p->is_interlace, "INTERLACE") + + FMTP_BUILD_FLAG(fmtp_p->annex_d, "D") + + FMTP_BUILD_FLAG(fmtp_p->annex_f, "F") + + FMTP_BUILD_FLAG(fmtp_p->annex_i, "I") + + FMTP_BUILD_FLAG(fmtp_p->annex_j, "J") + + FMTP_BUILD_FLAG(fmtp_p->annex_t, "T") + + FMTP_BUILD_UNSIGNED(fmtp_p->annex_k_val > 0, + "K", fmtp_p->annex_k_val) + + FMTP_BUILD_UNSIGNED(fmtp_p->annex_n_val > 0, + "N", fmtp_p->annex_n_val) + + if ((fmtp_p->annex_p_val_picture_resize > 0) && + (fmtp_p->annex_p_val_warp > 0)) { + flex_string_sprintf(fs, "%sP=%d:%d", + semicolon ? ";" : "", + fmtp_p->annex_p_val_picture_resize, + fmtp_p->annex_p_val_warp); + + semicolon = TRUE; + } + + FMTP_BUILD_STRING(strlen(fmtp_p->profile_level_id) > 0, + "profile-level-id", fmtp_p->profile_level_id) + + FMTP_BUILD_STRING(strlen(fmtp_p->parameter_sets) > 0, + "sprop-parameter-sets", fmtp_p->parameter_sets) + + FMTP_BUILD_UNSIGNED( + fmtp_p->packetization_mode < SDP_MAX_PACKETIZATION_MODE_VALUE, + "packetization-mode", fmtp_p->packetization_mode) + + FMTP_BUILD_UNSIGNED( + fmtp_p->level_asymmetry_allowed <= + SDP_MAX_LEVEL_ASYMMETRY_ALLOWED_VALUE, + "level-asymmetry-allowed", fmtp_p->level_asymmetry_allowed) + + FMTP_BUILD_UNSIGNED(fmtp_p->interleaving_depth > 0, + "sprop-interleaving-depth", fmtp_p->interleaving_depth) + + FMTP_BUILD_UNSIGNED(fmtp_p->flag & SDP_DEINT_BUF_REQ_FLAG, + "sprop-deint-buf-req", fmtp_p->deint_buf_req) + + FMTP_BUILD_UNSIGNED(fmtp_p->max_don_diff > 0, + "sprop-max-don-diff", fmtp_p->max_don_diff) + + FMTP_BUILD_UNSIGNED(fmtp_p->flag & SDP_INIT_BUF_TIME_FLAG, + "sprop-init-buf-time", fmtp_p->init_buf_time) + + FMTP_BUILD_UNSIGNED(fmtp_p->max_mbps > 0, + "max-mbps", fmtp_p->max_mbps) + + FMTP_BUILD_UNSIGNED(fmtp_p->max_fs > 0, "max-fs", fmtp_p->max_fs) + + FMTP_BUILD_UNSIGNED(fmtp_p->max_fr > 0, "max-fr", fmtp_p->max_fr) + + FMTP_BUILD_UNSIGNED(fmtp_p->max_cpb > 0, "max-cpb", fmtp_p->max_cpb) + + FMTP_BUILD_UNSIGNED(fmtp_p->max_dpb > 0, "max-dpb", fmtp_p->max_dpb) + + FMTP_BUILD_UNSIGNED(fmtp_p->max_br > 0, "max-br", fmtp_p->max_br) + + FMTP_BUILD_UNSIGNED(fmtp_p->redundant_pic_cap > 0, + "redundant-pic-cap", fmtp_p->redundant_pic_cap) + + FMTP_BUILD_UNSIGNED(fmtp_p->flag & SDP_DEINT_BUF_CAP_FLAG, + "deint-buf-cap", fmtp_p->deint_buf_cap) + + FMTP_BUILD_UNSIGNED(fmtp_p->flag & SDP_MAX_RCMD_NALU_SIZE_FLAG, + "max-rcmd-naFMTP_BUILD_FLlu-size", fmtp_p->max_rcmd_nalu_size) + + FMTP_BUILD_UNSIGNED(fmtp_p->parameter_add <= 1, "parameter-add", + fmtp_p->parameter_add) + + FMTP_BUILD_UNSIGNED(fmtp_p->maxaveragebitrate > 0, + "maxaveragebitrate", fmtp_p->maxaveragebitrate) + + FMTP_BUILD_UNSIGNED(fmtp_p->usedtx <= 1, "usedtx", fmtp_p->usedtx) + + FMTP_BUILD_UNSIGNED(fmtp_p->stereo <= 1, "stereo", fmtp_p->stereo) + + FMTP_BUILD_UNSIGNED(fmtp_p->useinbandfec <= 1, + "useinbandfec", fmtp_p->useinbandfec) + + FMTP_BUILD_STRING(strlen(fmtp_p->maxcodedaudiobandwidth) > 0, + "maxcodedaudiobandwidth", fmtp_p->maxcodedaudiobandwidth) + + FMTP_BUILD_UNSIGNED(fmtp_p->cbr <= 1, "cbr", fmtp_p->cbr) + + break; + + case SDP_FMTP_NTE: + default: + break; + } + + for(event_id = 0, mapword = 0, mask = SDP_NE_BIT_0; + event_id <= fmtp_p->maxval; + event_id++, mapword = event_id/SDP_NE_BITS_PER_WORD ) { + + 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); + } + + if (max != fmtp_p->maxval) { + flex_string_append(fs, ","); + } + } + } + return SDP_SUCCESS; +} + +sdp_result_e sdp_build_attr_fmtp (sdp_t *sdp_p, sdp_attr_t *attr_p, flex_string *fs) +{ + sdp_fmtp_t *fmtp_p; + sdp_result_e result; + + flex_string_sprintf(fs, "a=%s:%u ", + sdp_attr[attr_p->type].name, + attr_p->attr.fmtp.payload_num); + + fmtp_p = &(attr_p->attr.fmtp); + + result = sdp_build_attr_fmtp_params(sdp_p, fmtp_p, fs); + + if (result != SDP_SUCCESS) { + return result; + } + + flex_string_append(fs, "\r\n"); + + return SDP_SUCCESS; +} + +sdp_result_e sdp_parse_attr_sctpmap(sdp_t *sdp_p, sdp_attr_t *attr_p, + const char *ptr) +{ + sdp_result_e result = SDP_SUCCESS; + char tmp[SDP_MAX_STRING_LEN]; + uint32_t streams; + + /* Find the payload type number. */ + attr_p->attr.sctpmap.port = (uint16_t)sdp_getnextnumtok(ptr, &ptr, + " \t", &result); + if (result != SDP_SUCCESS) { + sdp_parse_error(sdp_p, + "%s Warning: no sctpmap port number", + sdp_p->debug_str); + return SDP_INVALID_PARAMETER; + } + + ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result); + if (result != SDP_SUCCESS) { + sdp_parse_error(sdp_p, + "%s Warning: No sctpmap protocol specified.", + sdp_p->debug_str); + sdp_p->conf_p->num_invalid_param++; + return SDP_INVALID_PARAMETER; + } + sstrncpy(attr_p->attr.sctpmap.protocol, tmp, + sizeof (attr_p->attr.sctpmap.protocol)); + + streams = sdp_getnextnumtok(ptr, &ptr, " \t", &result); + if (result != SDP_SUCCESS) { + sdp_parse_error(sdp_p, + "%s Warning: No sctpmap streams specified.", + sdp_p->debug_str); + sdp_p->conf_p->num_invalid_param++; + return SDP_INVALID_PARAMETER; + } + + attr_p->attr.sctpmap.streams = streams; + + return SDP_SUCCESS; +} + +sdp_result_e sdp_build_attr_sctpmap(sdp_t *sdp_p, sdp_attr_t *attr_p, + flex_string *fs) +{ + flex_string_sprintf(fs, "a=%s:%u %s %u\r\n", + sdp_attr[attr_p->type].name, + attr_p->attr.sctpmap.port, + attr_p->attr.sctpmap.protocol, + attr_p->attr.sctpmap.streams); + + return SDP_SUCCESS; +} + +sdp_result_e sdp_parse_attr_direction (sdp_t *sdp_p, sdp_attr_t *attr_p, + const char *ptr) +{ + /* No parameters to parse. */ + if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) { + SDP_PRINT("%s Parsed a=%s", sdp_p->debug_str, + sdp_get_attr_name(attr_p->type)); + } + + return (SDP_SUCCESS); +} + +sdp_result_e sdp_build_attr_direction (sdp_t *sdp_p, sdp_attr_t *attr_p, flex_string *fs) +{ + flex_string_sprintf(fs, "a=%s\r\n", sdp_get_attr_name(attr_p->type)); + + return SDP_SUCCESS; +} + +sdp_result_e sdp_parse_attr_qos (sdp_t *sdp_p, sdp_attr_t *attr_p, + const char *ptr) +{ + int i; + sdp_result_e result; + char tmp[SDP_MAX_STRING_LEN]; + + /* 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.qos.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.qos.strength = (sdp_qos_strength_e)i; + } + } + if (attr_p->attr.qos.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); + } + + /* 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.qos.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.qos.direction = (sdp_qos_dir_e)i; + } + } + if (attr_p->attr.qos.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); + } + + /* See if confirm was specified. Defaults to FALSE. */ + attr_p->attr.qos.confirm = FALSE; + ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result); + if (result == SDP_SUCCESS) { + if (cpr_strncasecmp(tmp, "confirm", sizeof("confirm")) == 0) { + attr_p->attr.qos.confirm = TRUE; + } + if (attr_p->attr.qos.confirm == FALSE) { + sdp_parse_error(sdp_p, + "%s Warning: QOS confirm parameter invalid (%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, strength %s, direction %s, confirm %s", + sdp_p->debug_str, sdp_get_attr_name(attr_p->type), + sdp_get_qos_strength_name(attr_p->attr.qos.strength), + sdp_get_qos_direction_name(attr_p->attr.qos.direction), + (attr_p->attr.qos.confirm ? "set" : "not set")); + } + + return (SDP_SUCCESS); +} + +sdp_result_e sdp_build_attr_qos (sdp_t *sdp_p, sdp_attr_t *attr_p, flex_string *fs) +{ + flex_string_sprintf(fs, "a=%s:%s %s%s\r\n", sdp_attr[attr_p->type].name, + sdp_get_qos_strength_name(attr_p->attr.qos.strength), + sdp_get_qos_direction_name(attr_p->attr.qos.direction), + attr_p->attr.qos.confirm ? " confirm" : ""); + + return SDP_SUCCESS; +} + +sdp_result_e sdp_parse_attr_curr (sdp_t *sdp_p, sdp_attr_t *attr_p, + const char *ptr) +{ + int i; + sdp_result_e result; + char tmp[SDP_MAX_STRING_LEN]; + + /* Find the curr type tag. */ + 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.type = SDP_CURR_UNKNOWN_TYPE; + for (i=0; i < SDP_MAX_CURR_TYPES; i++) { + if (cpr_strncasecmp(tmp, sdp_curr_type[i].name, + sdp_curr_type[i].strlen) == 0) { + attr_p->attr.curr.type = (sdp_curr_type_e)i; + } + } + + if (attr_p->attr.curr.type != SDP_CURR_QOS_TYPE) { + sdp_parse_error(sdp_p, + "%s Warning: Unknown curr type.", + sdp_p->debug_str); + 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 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)); + } + + return (SDP_SUCCESS); +} + +sdp_result_e sdp_build_attr_curr (sdp_t *sdp_p, sdp_attr_t *attr_p, flex_string *fs) +{ + flex_string_sprintf(fs, "a=%s:%s %s %s\r\n", + sdp_attr[attr_p->type].name, + 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)); + + return SDP_SUCCESS; +} + +sdp_result_e sdp_parse_attr_des (sdp_t *sdp_p, sdp_attr_t *attr_p, + const char *ptr) +{ + int i; + sdp_result_e result; + char tmp[SDP_MAX_STRING_LEN]; + + /* Find the curr type tag. */ + 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.type = SDP_DES_UNKNOWN_TYPE; + for (i=0; i < SDP_MAX_CURR_TYPES; i++) { + if (cpr_strncasecmp(tmp, sdp_des_type[i].name, + sdp_des_type[i].strlen) == 0) { + attr_p->attr.des.type = (sdp_des_type_e)i; + } + } + + if (attr_p->attr.des.type != SDP_DES_QOS_TYPE) { + sdp_parse_error(sdp_p, + "%s Warning: Unknown conf type.", + sdp_p->debug_str); + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_PARAMETER); + } + + /* 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)); + } + + return (SDP_SUCCESS); +} + + +sdp_result_e sdp_build_attr_des (sdp_t *sdp_p, sdp_attr_t *attr_p, flex_string *fs) +{ + flex_string_sprintf(fs, "a=%s:%s %s %s %s\r\n", + sdp_attr[attr_p->type].name, + sdp_get_curr_type_name((sdp_curr_type_e)attr_p->attr.des.type), + sdp_get_qos_strength_name(attr_p->attr.des.strength), + sdp_get_qos_status_type_name(attr_p->attr.des.status_type), + sdp_get_qos_direction_name(attr_p->attr.des.direction)); + + return SDP_SUCCESS; +} + +sdp_result_e sdp_parse_attr_conf (sdp_t *sdp_p, sdp_attr_t *attr_p, + const char *ptr) +{ + int i; + sdp_result_e result; + char tmp[SDP_MAX_STRING_LEN]; + + /* Find the curr type tag. */ + 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.type = SDP_CONF_UNKNOWN_TYPE; + for (i=0; i < SDP_MAX_CURR_TYPES; i++) { + if (cpr_strncasecmp(tmp, sdp_conf_type[i].name, + sdp_conf_type[i].strlen) == 0) { + attr_p->attr.conf.type = (sdp_conf_type_e)i; + } + } + + if (attr_p->attr.conf.type != SDP_CONF_QOS_TYPE) { + sdp_parse_error(sdp_p, + "%s Warning: Unknown conf type.", + sdp_p->debug_str); + 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 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)); + } + + return (SDP_SUCCESS); +} + +sdp_result_e sdp_build_attr_conf (sdp_t *sdp_p, sdp_attr_t *attr_p, flex_string *fs) +{ + flex_string_sprintf(fs, "a=%s:%s %s %s\r\n", + sdp_attr[attr_p->type].name, + 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)); + + return SDP_SUCCESS; +} + +/* + * Parse a rtpmap or a sprtmap. Both formats use the same structure + * the only difference being the keyword "rtpmap" vs "sprtmap". The + * rtpmap field in the sdp_attr_t is used to store both mappings. + */ +sdp_result_e sdp_parse_attr_transport_map (sdp_t *sdp_p, sdp_attr_t *attr_p, + const char *ptr) +{ + sdp_result_e result; + + attr_p->attr.transport_map.payload_num = 0; + attr_p->attr.transport_map.encname[0] = '\0'; + attr_p->attr.transport_map.clockrate = 0; + attr_p->attr.transport_map.num_chan = 1; + + /* 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); + } + } + + return (SDP_SUCCESS); +} + +/* + * Build a rtpmap or a sprtmap. Both formats use the same structure + * the only difference being the keyword "rtpmap" vs "sprtmap". The + * rtpmap field in the sdp_attr_t is used for both mappings. + */ +sdp_result_e sdp_build_attr_transport_map (sdp_t *sdp_p, sdp_attr_t *attr_p, + flex_string *fs) +{ + if (attr_p->attr.transport_map.num_chan == 1) { + flex_string_sprintf(fs, "a=%s:%u %s/%u\r\n", + sdp_attr[attr_p->type].name, + attr_p->attr.transport_map.payload_num, + attr_p->attr.transport_map.encname, + attr_p->attr.transport_map.clockrate); + } else { + flex_string_sprintf(fs, "a=%s:%u %s/%u/%u\r\n", + sdp_attr[attr_p->type].name, + attr_p->attr.transport_map.payload_num, + attr_p->attr.transport_map.encname, + attr_p->attr.transport_map.clockrate, + attr_p->attr.transport_map.num_chan); + } + + return SDP_SUCCESS; +} + +sdp_result_e sdp_parse_attr_subnet (sdp_t *sdp_p, sdp_attr_t *attr_p, + const char *ptr) +{ + int i; + char *slash_ptr; + sdp_result_e result; + tinybool type_found = FALSE; + char tmp[SDP_MAX_STRING_LEN]; + + /* Find the subnet network type. */ + 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 subnet attribute.", + sdp_p->debug_str); + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_PARAMETER); + } + attr_p->attr.subnet.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.subnet.nettype = (sdp_nettype_e)i; + } + type_found = FALSE; + } + } + if (attr_p->attr.subnet.nettype == SDP_NT_UNSUPPORTED) { + sdp_parse_error(sdp_p, + "%s Warning: Subnet network type unsupported (%s).", + sdp_p->debug_str, tmp); + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_PARAMETER); + } + + /* Find the subnet 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 subnet attribute.", + sdp_p->debug_str); + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_PARAMETER); + } + attr_p->attr.subnet.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.subnet.addrtype = (sdp_addrtype_e)i; + } + type_found = FALSE; + } + } + if (attr_p->attr.subnet.addrtype == SDP_AT_UNSUPPORTED) { + sdp_parse_error(sdp_p, + "%s Warning: Subnet address type unsupported (%s).", + sdp_p->debug_str, tmp); + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_PARAMETER); + } + + /* Find the subnet address. */ + ptr = sdp_getnextstrtok(ptr, attr_p->attr.subnet.addr, + sizeof(attr_p->attr.subnet.addr), " \t", &result); + if (result != SDP_SUCCESS) { + sdp_parse_error(sdp_p, + "%s Warning: No subnet address specified in " + "subnet attribute.", sdp_p->debug_str); + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_PARAMETER); + } + slash_ptr = sdp_findchar(attr_p->attr.subnet.addr, "/"); + if (*slash_ptr == '/') { + *slash_ptr++ = '\0'; + /* If the '/' exists, expect a valid prefix to follow. */ + attr_p->attr.subnet.prefix = sdp_getnextnumtok(slash_ptr, + (const char **)&slash_ptr, + " \t", &result); + if (result != SDP_SUCCESS) { + sdp_parse_error(sdp_p, + "%s Warning: Invalid subnet prefix specified in " + "subnet attribute.", sdp_p->debug_str); + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_PARAMETER); + } + } else { + attr_p->attr.subnet.prefix = SDP_INVALID_VALUE; + } + + if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) { + SDP_PRINT("%s Parsed a=%s, network %s, addr type %s, address %s ", + sdp_p->debug_str, sdp_get_attr_name(attr_p->type), + sdp_get_network_name(attr_p->attr.subnet.nettype), + sdp_get_address_name(attr_p->attr.subnet.addrtype), + attr_p->attr.subnet.addr); + if (attr_p->attr.subnet.prefix != SDP_INVALID_VALUE) { + SDP_PRINT("/%u", (ushort)attr_p->attr.subnet.prefix); + } + } + + return (SDP_SUCCESS); +} + +sdp_result_e sdp_build_attr_subnet (sdp_t *sdp_p, sdp_attr_t *attr_p, + flex_string *fs) +{ + if (attr_p->attr.subnet.prefix == SDP_INVALID_VALUE) { + flex_string_sprintf(fs, "a=%s:%s %s %s\r\n", + sdp_attr[attr_p->type].name, + sdp_get_network_name(attr_p->attr.subnet.nettype), + sdp_get_address_name(attr_p->attr.subnet.addrtype), + attr_p->attr.subnet.addr); + } else { + flex_string_sprintf(fs, "a=%s:%s %s %s/%u\r\n", + sdp_attr[attr_p->type].name, + sdp_get_network_name(attr_p->attr.subnet.nettype), + sdp_get_address_name(attr_p->attr.subnet.addrtype), + attr_p->attr.subnet.addr, + (ushort)attr_p->attr.subnet.prefix); + } + + return SDP_SUCCESS; +} + +sdp_result_e sdp_parse_attr_t38_ratemgmt (sdp_t *sdp_p, sdp_attr_t *attr_p, + const char *ptr) +{ + int i; + sdp_result_e result; + char tmp[SDP_MAX_STRING_LEN]; + + /* Find the rate mgmt. */ + ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result); + if (result != SDP_SUCCESS) { + sdp_parse_error(sdp_p, + "%s Warning: No t38 rate management specified.", + sdp_p->debug_str); + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_PARAMETER); + } + attr_p->attr.t38ratemgmt = SDP_T38_UNKNOWN_RATE; + for (i=0; i < SDP_T38_MAX_RATES; i++) { + if (cpr_strncasecmp(tmp, sdp_t38_rate[i].name, + sdp_t38_rate[i].strlen) == 0) { + attr_p->attr.t38ratemgmt = (sdp_t38_ratemgmt_e)i; + } + } + + if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) { + SDP_PRINT("%s Parsed a=%s, rate %s", sdp_p->debug_str, + sdp_get_attr_name(attr_p->type), + sdp_get_t38_ratemgmt_name(attr_p->attr.t38ratemgmt)); + } + + return (SDP_SUCCESS); +} + +sdp_result_e sdp_build_attr_t38_ratemgmt (sdp_t *sdp_p, sdp_attr_t *attr_p, + flex_string *fs) +{ + flex_string_sprintf(fs, "a=%s:%s\r\n", + sdp_attr[attr_p->type].name, + sdp_get_t38_ratemgmt_name(attr_p->attr.t38ratemgmt)); + + return SDP_SUCCESS; +} + +sdp_result_e sdp_parse_attr_t38_udpec (sdp_t *sdp_p, sdp_attr_t *attr_p, + const char *ptr) +{ + int i; + sdp_result_e result; + char tmp[SDP_MAX_STRING_LEN]; + + /* Find the udpec. */ + ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result); + if (result != SDP_SUCCESS) { + sdp_parse_error(sdp_p, + "%s Warning: No t38 udpEC specified.", + sdp_p->debug_str); + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_PARAMETER); + } + attr_p->attr.t38udpec = SDP_T38_UDPEC_UNKNOWN; + for (i=0; i < SDP_T38_MAX_UDPEC; i++) { + if (cpr_strncasecmp(tmp, sdp_t38_udpec[i].name, + sdp_t38_udpec[i].strlen) == 0) { + attr_p->attr.t38udpec = (sdp_t38_udpec_e)i; + } + } + + if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) { + SDP_PRINT("%s Parsed a=%s, udpec %s", sdp_p->debug_str, + sdp_get_attr_name(attr_p->type), + sdp_get_t38_udpec_name(attr_p->attr.t38udpec)); + } + + return (SDP_SUCCESS); +} + +sdp_result_e sdp_build_attr_t38_udpec (sdp_t *sdp_p, sdp_attr_t *attr_p, + flex_string *fs) +{ + flex_string_sprintf(fs, "a=%s:%s\r\n", + sdp_attr[attr_p->type].name, + sdp_get_t38_udpec_name(attr_p->attr.t38udpec)); + + return SDP_SUCCESS; +} + +sdp_result_e sdp_parse_attr_pc_codec (sdp_t *sdp_p, sdp_attr_t *attr_p, + const char *ptr) +{ + uint16_t i; + sdp_result_e result; + + for (i=0; i < SDP_MAX_PAYLOAD_TYPES; i++) { + attr_p->attr.pccodec.payload_type[i] = (ushort)sdp_getnextnumtok(ptr, &ptr, + " \t", &result); + if (result != SDP_SUCCESS) { + break; + } + attr_p->attr.pccodec.num_payloads++; + } + + if (attr_p->attr.pccodec.num_payloads == 0) { + sdp_parse_error(sdp_p, + "%s Warning: No payloads specified for %s attr.", + sdp_p->debug_str, sdp_attr[attr_p->type].name); + 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, num payloads %u, payloads: ", + sdp_p->debug_str, sdp_get_attr_name(attr_p->type), + attr_p->attr.pccodec.num_payloads); + for (i=0; i < attr_p->attr.pccodec.num_payloads; i++) { + SDP_PRINT("%u ", attr_p->attr.pccodec.payload_type[i]); + } + } + + return (SDP_SUCCESS); +} + +sdp_result_e sdp_build_attr_pc_codec (sdp_t *sdp_p, sdp_attr_t *attr_p, + flex_string *fs) +{ + int i; + + flex_string_sprintf(fs, "a=%s: ", sdp_attr[attr_p->type].name); + + for (i=0; i < attr_p->attr.pccodec.num_payloads; i++) { + flex_string_sprintf(fs, "%u ", attr_p->attr.pccodec.payload_type[i]); + } + + flex_string_append(fs, "\r\n"); + + return SDP_SUCCESS; +} + + +sdp_result_e sdp_parse_attr_cap (sdp_t *sdp_p, sdp_attr_t *attr_p, + const char *ptr) +{ + uint16_t i; + sdp_result_e result; + sdp_mca_t *cap_p; + char tmp[SDP_MAX_STRING_LEN]; + + /* Set the capability pointer to NULL for now in case we encounter + * an error in parsing. + */ + attr_p->attr.cap_p = NULL; + /* Set the capability valid flag to FALSE in case we encounter an + * error. If we do, we don't want to process any X-cpar/cpar attributes + * 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 + * uses the same structure used for media lines. + */ + 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/profile types per line, so these are handled differently. + */ + 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); + } + } + + attr_p->attr.cap_p = cap_p; + /* + * This capability attr is valid. We can now handle X-cpar or + * cpar attrs. + */ + sdp_p->cap_valid = TRUE; + sdp_p->last_cap_inst++; + + if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) { + SDP_PRINT("%s Parsed %s media type %s, Transport %s, " + "Num payloads %u", sdp_p->debug_str, + sdp_get_attr_name(attr_p->type), + sdp_get_media_name(cap_p->media), + sdp_get_transport_name(cap_p->transport), + cap_p->num_payloads); + } + return (SDP_SUCCESS); +} + +sdp_result_e sdp_build_attr_cap (sdp_t *sdp_p, sdp_attr_t *attr_p, + flex_string *fs) +{ + uint16_t i, j; + sdp_mca_t *cap_p; + sdp_media_profiles_t *profile_p; + + /* 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); + } + + flex_string_sprintf(fs, "a=%s: %u %s ", sdp_attr[attr_p->type].name, + sdp_p->cur_cap_num, sdp_get_media_name(cap_p->media)); + + /* 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])); + + for (j=0; j < profile_p->num_payloads[i]; j++) { + flex_string_sprintf(fs, " %u", + profile_p->payload_type[i][j]); + } + flex_string_append(fs, " "); + } + + 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); +} + + +sdp_result_e sdp_parse_attr_cpar (sdp_t *sdp_p, sdp_attr_t *attr_p, + const char *ptr) +{ + uint16_t i; + sdp_result_e result; + sdp_mca_t *cap_p; + sdp_attr_t *cap_attr_p = NULL; + sdp_attr_t *prev_attr_p; + char tmp[SDP_MAX_STRING_LEN] = {0}; + + /* 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; + } + + if (sdp_p->mca_count == 0) { + cap_attr_p = sdp_find_attr(sdp_p, SDP_SESSION_LEVEL, 0, + cap_type, sdp_p->last_cap_inst); + } else { + cap_attr_p = sdp_find_attr(sdp_p, sdp_p->mca_count, 0, + cap_type, sdp_p->last_cap_inst); + } + } + if ((cap_attr_p == NULL) || (cap_attr_p->attr.cap_p == NULL)) { + sdp_parse_error(sdp_p, + "%s Warning: %s attribute specified with no " + "prior %s attribute", sdp_p->debug_str, + sdp_get_attr_name(attr_p->type), + (attr_p->type == SDP_ATTR_CPAR)? + (sdp_get_attr_name(SDP_ATTR_CDSC)) : + (sdp_get_attr_name(SDP_ATTR_X_CAP)) ); + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_PARAMETER); + } + + /* + * Ensure there is no mixed syntax like CDSC followed by X-CPAR + * or X-CAP followed by CPAR. + */ + if (((cap_attr_p->type == SDP_ATTR_CDSC) && + (attr_p->type == SDP_ATTR_X_CPAR)) || + ( (cap_attr_p->type == SDP_ATTR_X_CAP) && + (attr_p->type == SDP_ATTR_CPAR)) ) { + sdp_parse_error(sdp_p, + "%s Warning: %s attribute inconsistent with " + "prior %s attribute", sdp_p->debug_str, + sdp_get_attr_name(attr_p->type), + sdp_get_attr_name(cap_attr_p->type)); + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_PARAMETER); + } + cap_p = cap_attr_p->attr.cap_p; + + /* 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 + *{ptr is valid since the pointer was checked earlier and the + * function would have exited if NULL.} + */ + if (*ptr == '=') { + ptr++; + } + + /* Find the attribute type. */ + ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), ": \t", &result); + /*sa_ignore NO_NULL_CHK + *{ptr is valid since the pointer was checked earlier and the + * function would have exited if NULL.} + */ + 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; + } + + return (SDP_SUCCESS); +} + +sdp_result_e sdp_build_attr_cpar (sdp_t *sdp_p, sdp_attr_t *attr_p, + flex_string *fs) +{ + sdp_result_e result; + const char *cpar_name; + + /* Determine whether to use cpar or X-cpar */ + if (sdp_p->last_cap_type == SDP_ATTR_CDSC) { + cpar_name = sdp_get_attr_name(SDP_ATTR_CPAR); + } else { + /* + * Default to X-CPAR if anything else. This is the backward + * compatible value. + */ + cpar_name = sdp_get_attr_name(SDP_ATTR_X_CPAR); + } + + while (attr_p != NULL) { + if (attr_p->type >= SDP_MAX_ATTR_TYPES) { + SDPLogDebug(logTag, "%s Invalid attribute type to build (%u)", + sdp_p->debug_str, (unsigned)attr_p->type); + } else { + flex_string_sprintf(fs, "a=%s: ", cpar_name); + + result = sdp_attr[attr_p->type].build_func(sdp_p, attr_p, fs); + + if (result == SDP_SUCCESS) { + if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) { + SDP_PRINT("%s Built %s a=%s attribute line", + sdp_p->debug_str, cpar_name, + sdp_get_attr_name(attr_p->type)); + } + } + } + attr_p = attr_p->next_p; + } + + return (SDP_SUCCESS); +} + +sdp_result_e sdp_parse_attr_rtcp (sdp_t *sdp_p, sdp_attr_t *attr_p, + const char *ptr) +{ + sdp_result_e result; + char nettype[SDP_MAX_STRING_LEN]; + sdp_rtcp_t *rtcp_p = &(attr_p->attr.rtcp); + int enum_raw; + + memset(rtcp_p, 0, sizeof(sdp_rtcp_t)); + + 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; + } + + enum_raw = find_token_enum("Nettype", sdp_p, &ptr, sdp_nettype, + SDP_MAX_NETWORK_TYPES, SDP_NT_UNSUPPORTED); + if (enum_raw == -1) { + return SDP_INVALID_PARAMETER; + } + rtcp_p->nettype = (sdp_nettype_e)enum_raw; + + enum_raw = find_token_enum("Addrtype", sdp_p, &ptr, sdp_addrtype, + SDP_MAX_ADDR_TYPES, SDP_AT_UNSUPPORTED); + if (enum_raw == -1) { + return SDP_INVALID_PARAMETER; + } + rtcp_p->addrtype = (sdp_addrtype_e)enum_raw; + + 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; +} + +sdp_result_e sdp_parse_attr_rtr (sdp_t *sdp_p, sdp_attr_t *attr_p, + const char *ptr) +{ + sdp_result_e result; + char tmp[SDP_MAX_STRING_LEN]; + + if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) { + SDP_PRINT("%s Parsing a=%s", sdp_p->debug_str, + sdp_get_attr_name(attr_p->type)); + } + /*Default confirm to FALSE. */ + attr_p->attr.rtr.confirm = FALSE; + + ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result); + if (result != SDP_SUCCESS){ // No confirm tag specified is not an error + return (SDP_SUCCESS); + } else { + /* See if confirm was specified. Defaults to FALSE. */ + if (cpr_strncasecmp(tmp, "confirm", sizeof("confirm")) == 0) { + attr_p->attr.rtr.confirm = TRUE; + } + if (attr_p->attr.rtr.confirm == FALSE) { + sdp_parse_error(sdp_p, + "%s Warning: RTR confirm parameter invalid (%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, %s", sdp_p->debug_str, + sdp_get_attr_name(attr_p->type), + tmp); + } + return (SDP_SUCCESS); + } +} + +sdp_result_e sdp_build_attr_rtr (sdp_t *sdp_p, sdp_attr_t *attr_p, + flex_string *fs) +{ + flex_string_sprintf(fs, "a=%s%s\r\n", + sdp_attr[attr_p->type].name, + attr_p->attr.rtr.confirm ? ":confirm" : ""); + + return SDP_SUCCESS; +} + +sdp_result_e sdp_parse_attr_comediadir (sdp_t *sdp_p, sdp_attr_t *attr_p, + const char *ptr) +{ + int i; + sdp_result_e result; + tinybool type_found = FALSE; + char tmp[SDP_MAX_STRING_LEN]; + + attr_p->attr.comediadir.role = SDP_MEDIADIR_ROLE_PASSIVE; + attr_p->attr.comediadir.conn_info_present = FALSE; + attr_p->attr.comediadir.conn_info.nettype = SDP_NT_INVALID; + attr_p->attr.comediadir.src_port = 0; + + /* 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++; + } + + if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) { + SDP_PRINT("%s Parsed a=%s, network %s, addr type %s, address %s " + "srcport %u ", + sdp_p->debug_str, sdp_get_attr_name(attr_p->type), + sdp_get_network_name(attr_p->attr.comediadir.conn_info.nettype), + sdp_get_address_name(attr_p->attr.comediadir.conn_info.addrtype), + attr_p->attr.comediadir.conn_info.conn_addr, + (unsigned int)attr_p->attr.comediadir.src_port); + } + + if (sdp_p->conf_p->num_invalid_param > 0) { + return (SDP_INVALID_PARAMETER); + } + return (SDP_SUCCESS); +} + +sdp_result_e +sdp_build_attr_comediadir (sdp_t *sdp_p, sdp_attr_t *attr_p, + flex_string *fs) +{ + flex_string_sprintf(fs, "a=%s:%s\r\n", + sdp_attr[attr_p->type].name, + sdp_get_mediadir_role_name(attr_p->attr.comediadir.role)); + + return SDP_SUCCESS; +} + +sdp_result_e sdp_parse_attr_silencesupp (sdp_t *sdp_p, sdp_attr_t *attr_p, + const char *ptr) +{ + int i; + sdp_result_e result; + char tmp[SDP_MAX_STRING_LEN]; + + /* Find silenceSuppEnable */ + ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result); + + if (result != SDP_SUCCESS) { + sdp_parse_error(sdp_p, + "%s No silenceSupp enable value specified, parse failed.", + sdp_p->debug_str); + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_PARAMETER); + } + + if (cpr_strncasecmp(tmp, "on", sizeof("on")) == 0) { + attr_p->attr.silencesupp.enabled = TRUE; + } else if (cpr_strncasecmp(tmp, "off", sizeof("off")) == 0) { + attr_p->attr.silencesupp.enabled = FALSE; + } else if (cpr_strncasecmp(tmp, "-", sizeof("-")) == 0) { + attr_p->attr.silencesupp.enabled = FALSE; + } else { + sdp_parse_error(sdp_p, + "%s Warning: silenceSuppEnable parameter invalid (%s)", + sdp_p->debug_str, tmp); + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_PARAMETER); + } + + /* Find silenceTimer -- uint16_t or "-" */ + + attr_p->attr.silencesupp.timer = + (uint16_t)sdp_getnextnumtok_or_null(ptr, &ptr, " \t", + &attr_p->attr.silencesupp.timer_null, + &result); + if (result != SDP_SUCCESS) { + sdp_parse_error(sdp_p, + "%s Warning: Invalid timer value specified for " + "silenceSupp attribute.", sdp_p->debug_str); + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_PARAMETER); + } + + /* Find suppPref */ + ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result); + if (result != SDP_SUCCESS) { + sdp_parse_error(sdp_p, + "%s Warning: No silenceSupp pref specified.", + sdp_p->debug_str); + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_PARAMETER); + } + attr_p->attr.silencesupp.pref = SDP_SILENCESUPP_PREF_UNKNOWN; + for (i=0; i < SDP_MAX_SILENCESUPP_PREF; i++) { + if (cpr_strncasecmp(tmp, sdp_silencesupp_pref[i].name, + sdp_silencesupp_pref[i].strlen) == 0) { + attr_p->attr.silencesupp.pref = (sdp_silencesupp_pref_e)i; + } + } + if (attr_p->attr.silencesupp.pref == SDP_SILENCESUPP_PREF_UNKNOWN) { + sdp_parse_error(sdp_p, + "%s Warning: silenceSupp pref unrecognized (%s)", + sdp_p->debug_str, tmp); + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_PARAMETER); + } + + /* Find sidUse */ + ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result); + if (result != SDP_SUCCESS) { + sdp_parse_error(sdp_p, + "%s Warning: No silenceSupp sidUse specified.", + sdp_p->debug_str); + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_PARAMETER); + } + attr_p->attr.silencesupp.siduse = SDP_SILENCESUPP_SIDUSE_UNKNOWN; + for (i=0; i < SDP_MAX_SILENCESUPP_SIDUSE; i++) { + if (cpr_strncasecmp(tmp, sdp_silencesupp_siduse[i].name, + sdp_silencesupp_siduse[i].strlen) == 0) { + attr_p->attr.silencesupp.siduse = (sdp_silencesupp_siduse_e)i; + } + } + if (attr_p->attr.silencesupp.siduse == SDP_SILENCESUPP_SIDUSE_UNKNOWN) { + sdp_parse_error(sdp_p, + "%s Warning: silenceSupp sidUse unrecognized (%s)", + sdp_p->debug_str, tmp); + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_PARAMETER); + } + + /* Find fxnslevel -- uint8_t or "-" */ + attr_p->attr.silencesupp.fxnslevel = + (uint8_t)sdp_getnextnumtok_or_null(ptr, &ptr, " \t", + &attr_p->attr.silencesupp.fxnslevel_null, + &result); + + if (result != SDP_SUCCESS) { + sdp_parse_error(sdp_p, + "%s Warning: Invalid fxnslevel value specified for " + "silenceSupp 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, enabled %s", + sdp_p->debug_str, sdp_get_attr_name(attr_p->type), + (attr_p->attr.silencesupp.enabled ? "on" : "off")); + if (attr_p->attr.silencesupp.timer_null) { + SDP_PRINT(" timer=-"); + } else { + SDP_PRINT(" timer=%u,", attr_p->attr.silencesupp.timer); + } + SDP_PRINT(" pref=%s, siduse=%s,", + sdp_get_silencesupp_pref_name(attr_p->attr.silencesupp.pref), + sdp_get_silencesupp_siduse_name( + attr_p->attr.silencesupp.siduse)); + if (attr_p->attr.silencesupp.fxnslevel_null) { + SDP_PRINT(" fxnslevel=-"); + } else { + SDP_PRINT(" fxnslevel=%u,", attr_p->attr.silencesupp.fxnslevel); + } + } + + return (SDP_SUCCESS); +} + +sdp_result_e sdp_build_attr_silencesupp (sdp_t *sdp_p, sdp_attr_t *attr_p, + flex_string *fs) +{ + char temp_timer_string[11]; + char temp_fxnslevel_string[11]; + + if (attr_p->attr.silencesupp.timer_null) { + snprintf(temp_timer_string, sizeof(temp_timer_string), "-"); + } else { + snprintf(temp_timer_string, sizeof(temp_timer_string), "%u", attr_p->attr.silencesupp.timer); + } + + if (attr_p->attr.silencesupp.fxnslevel_null) { + snprintf(temp_fxnslevel_string, sizeof(temp_fxnslevel_string), "-"); + } else { + snprintf(temp_fxnslevel_string, sizeof(temp_fxnslevel_string), "%u", attr_p->attr.silencesupp.fxnslevel); + } + + flex_string_sprintf(fs, "a=%s:%s %s %s %s %s\r\n", + sdp_attr[attr_p->type].name, + (attr_p->attr.silencesupp.enabled ? "on" : "off"), + temp_timer_string, + sdp_get_silencesupp_pref_name(attr_p->attr.silencesupp.pref), + sdp_get_silencesupp_siduse_name(attr_p->attr.silencesupp.siduse), + temp_fxnslevel_string); + + return SDP_SUCCESS; +} + +/* + * sdp_parse_context_crypto_suite + * + * This routine parses the crypto suite pointed to by str, stores the crypto suite value into the + * srtp context suite component of the LocalConnectionOptions pointed to by lco_node_ptr and stores + * pointer to the next crypto parameter in tmp_ptr + */ +tinybool sdp_parse_context_crypto_suite(char * str, sdp_attr_t *attr_p, sdp_t *sdp_p) { + /* + * Three crypto_suites are defined: (Notice no SPACE between "crypto:" and the <crypto-suite> + * AES_CM_128_HMAC_SHA1_80 + * AES_CM_128_HMAC_SHA1_32 + * F8_128_HMAC_SHA1_80 + */ + + int i; + + /* 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; + return TRUE; /* 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); + + return FALSE; +} + + +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; + unsigned char base64_encoded_data[MAX_BASE64_ENCODE_SIZE_BYTES]; + unsigned char 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); + } + + *(base64_encoded_data + output_len) = '\0'; + + flex_string_sprintf(fs, "a=%s:%s inline:%s||\r\n", + sdp_attr[attr_p->type].name, + sdp_srtp_context_crypto_suite[attr_p->attr.srtp_context.suite].name, + base64_encoded_data); + + return SDP_SUCCESS; +} + +/* + * sdp_parse_attr_mptime + * This function parses the a=mptime sdp line. This parameter consists of + * one or more numbers or hyphens ("-"). The first parameter must be a + * number. The number of parameters must match the number of formats specified + * on the m= line. This function is liberal in that it does not match against + * the m= line or require a number for the first parameter. + */ +sdp_result_e sdp_parse_attr_mptime ( + sdp_t *sdp_p, + sdp_attr_t *attr_p, + const char *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 "-" */ + + /* + * Scan the input line up to the maximum number of parameters supported. + * Look for numbers or hyphens and store the resulting values. Hyphens + * are stored as zeros. + */ + for (i=0; i<SDP_MAX_PAYLOAD_TYPES; i++) { + attr_p->attr.mptime.intervals[i] = + (ushort)sdp_getnextnumtok_or_null(ptr,&ptr," \t",&null_ind,&result); + if (result != SDP_SUCCESS) { + break; + } + attr_p->attr.mptime.num_intervals++; + } + + /* + * At least one parameter must be supplied. If not, return an error + * and optionally log the failure. + */ + if (attr_p->attr.mptime.num_intervals == 0) { + sdp_parse_error(sdp_p, + "%s Warning: No intervals specified for %s attr.", + sdp_p->debug_str, sdp_attr[attr_p->type].name); + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_PARAMETER); + } + + /* + * Here is some debugging code that helps us track what data + * is received and parsed. + */ + if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) { + SDP_PRINT("%s Parsed a=%s, num intervals %u, intervals: ", + sdp_p->debug_str, sdp_get_attr_name(attr_p->type), + attr_p->attr.mptime.num_intervals); + for (i=0; i < attr_p->attr.mptime.num_intervals; i++) { + SDP_PRINT("%u ", attr_p->attr.mptime.intervals[i]); + } + } + + return SDP_SUCCESS; +} + +/* + * sdp_build_attr_mptime + * This function builds the a=mptime sdp line. It reads the selected attribute + * from the sdp structure. Parameters with a value of zero are replaced by + * hyphens. + */ +sdp_result_e sdp_build_attr_mptime ( + sdp_t *sdp_p, + sdp_attr_t *attr_p, + flex_string *fs) +{ + int i; + + flex_string_sprintf(fs, "a=%s:", sdp_attr[attr_p->type].name); + + /* + * Run the list of mptime parameter values and write each one + * to the sdp line. Replace zeros with hyphens. + */ + for (i=0; i < attr_p->attr.mptime.num_intervals; i++) { + if (i > 0) { + flex_string_append(fs, " "); + } + + if (attr_p->attr.mptime.intervals[i] == 0) { + flex_string_append(fs, "-"); + } else { + flex_string_sprintf(fs, "%u", attr_p->attr.mptime.intervals[i]); + } + } + + flex_string_append(fs, "\r\n"); + + return SDP_SUCCESS; +} + + + +sdp_result_e sdp_parse_attr_x_sidin (sdp_t *sdp_p, sdp_attr_t *attr_p, + const char *ptr) +{ + sdp_result_e result; + attr_p->attr.stream_data.x_sidin[0] = '\0'; + + if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) { + SDP_PRINT("%s Parsing a=%s", sdp_p->debug_str, + sdp_get_attr_name(attr_p->type)); + } + + /* Find the X-sidin value */ + ptr = sdp_getnextstrtok(ptr, attr_p->attr.stream_data.x_sidin, + sizeof(attr_p->attr.stream_data.x_sidin), " \t", &result); + if (result != SDP_SUCCESS) { + sdp_parse_error(sdp_p, + "%s Warning: No Stream Id incoming specified for X-sidin 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, %s", sdp_p->debug_str, + sdp_get_attr_name(attr_p->type), + attr_p->attr.stream_data.x_sidin); + } + return (SDP_SUCCESS); +} + +sdp_result_e sdp_build_attr_x_sidin (sdp_t *sdp_p, sdp_attr_t *attr_p, + flex_string *fs) +{ + flex_string_sprintf(fs, "a=%s:%s\r\n", + sdp_attr[attr_p->type].name, + attr_p->attr.stream_data.x_sidin); + + return SDP_SUCCESS; +} + +sdp_result_e sdp_parse_attr_x_sidout (sdp_t *sdp_p, sdp_attr_t *attr_p, + const char *ptr) +{ + sdp_result_e result; + attr_p->attr.stream_data.x_sidout[0] = '\0'; + + if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) { + SDP_PRINT("%s Parsing a=%s", sdp_p->debug_str, + sdp_get_attr_name(attr_p->type)); + } + + /* Find the X-sidout value */ + ptr = sdp_getnextstrtok(ptr, attr_p->attr.stream_data.x_sidout, + sizeof(attr_p->attr.stream_data.x_sidout), " \t", &result); + if (result != SDP_SUCCESS) { + sdp_parse_error(sdp_p, + "%s Warning: No Stream Id outgoing specified for X-sidout 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, %s", sdp_p->debug_str, + sdp_get_attr_name(attr_p->type), + attr_p->attr.stream_data.x_sidout); + } + return (SDP_SUCCESS); +} + +sdp_result_e sdp_build_attr_x_sidout (sdp_t *sdp_p, sdp_attr_t *attr_p, + flex_string *fs) +{ + flex_string_sprintf(fs, "a=%s:%s\r\n", + sdp_attr[attr_p->type].name, + attr_p->attr.stream_data.x_sidout); + + return SDP_SUCCESS; +} + + +sdp_result_e sdp_parse_attr_x_confid (sdp_t *sdp_p, sdp_attr_t *attr_p, + const char *ptr) +{ + sdp_result_e result; + attr_p->attr.stream_data.x_confid[0] = '\0'; + + if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) { + SDP_PRINT("%s Parsing a=%s", sdp_p->debug_str, + sdp_get_attr_name(attr_p->type)); + } + + /* Find the X-confid value */ + ptr = sdp_getnextstrtok(ptr, attr_p->attr.stream_data.x_confid, + sizeof(attr_p->attr.stream_data.x_confid), " \t", &result); + if (result != SDP_SUCCESS) { + sdp_parse_error(sdp_p, + "%s Warning: No Conf Id incoming specified for " + "X-confid 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, %s", sdp_p->debug_str, + sdp_get_attr_name(attr_p->type), + attr_p->attr.stream_data.x_confid); + } + return (SDP_SUCCESS); +} + +sdp_result_e sdp_build_attr_x_confid (sdp_t *sdp_p, sdp_attr_t *attr_p, + flex_string *fs) +{ + if (strlen(attr_p->attr.stream_data.x_confid) <= 0) { + if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) { + SDP_PRINT("%s X-confid value is not set. Cannot build a=X-confid line\n", + sdp_p->debug_str); + } + + return SDP_INVALID_PARAMETER; + } + + flex_string_sprintf(fs, "a=%s:%s\r\n", + sdp_attr[attr_p->type].name, + attr_p->attr.stream_data.x_confid); + + return SDP_SUCCESS; +} + +sdp_result_e sdp_parse_attr_group (sdp_t *sdp_p, sdp_attr_t *attr_p, + const char *ptr) +{ + sdp_result_e result; + char tmp[64]; + int i=0; + + if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) { + SDP_PRINT("%s Parsing a=%s", sdp_p->debug_str, + sdp_get_attr_name(attr_p->type)); + } + + /* Find the a=group:<attrib> <id1> < id2> ... values */ + ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result); + if (result != SDP_SUCCESS) { + sdp_parse_error(sdp_p, + "%s Warning: No group attribute value specified for " + "a=group line", sdp_p->debug_str); + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_PARAMETER); + } + + attr_p->attr.stream_data.group_attr = SDP_GROUP_ATTR_UNSUPPORTED; + for (i=0; i < SDP_MAX_GROUP_ATTR_VAL; i++) { + if (cpr_strncasecmp(tmp, sdp_group_attr_val[i].name, + sdp_group_attr_val[i].strlen) == 0) { + attr_p->attr.stream_data.group_attr = (sdp_group_attr_e)i; + break; + } + } + + if (attr_p->attr.stream_data.group_attr == SDP_GROUP_ATTR_UNSUPPORTED) { + sdp_parse_error(sdp_p, + "%s Warning: Group attribute type unsupported (%s).", + sdp_p->debug_str, tmp); + } + + + /* + * Scan the input line up after group:<attr> to the maximum number + * of id available. + */ + attr_p->attr.stream_data.num_group_id =0; + + for (i=0; i<SDP_MAX_MEDIA_STREAMS; i++) { + ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result); + + if (result != SDP_SUCCESS) { + break; + } + attr_p->attr.stream_data.group_ids[i] = cpr_strdup(tmp); + if (!attr_p->attr.stream_data.group_ids[i]) { + break; + } + + attr_p->attr.stream_data.num_group_id++; + } + + if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) { + SDP_PRINT("%s Parsed a=%s:%s\n", sdp_p->debug_str, + sdp_get_attr_name(attr_p->type), + sdp_get_group_attr_name (attr_p->attr.stream_data.group_attr)); + for (i=0; i < attr_p->attr.stream_data.num_group_id; i++) { + SDP_PRINT("%s Parsed group line id : %s\n", sdp_p->debug_str, + attr_p->attr.stream_data.group_ids[i]); + } + } + return (SDP_SUCCESS); +} + +sdp_result_e sdp_build_attr_group (sdp_t *sdp_p, sdp_attr_t *attr_p, + flex_string *fs) +{ + int i; + + flex_string_sprintf(fs, "a=%s:%s", + sdp_attr[attr_p->type].name, + sdp_get_group_attr_name(attr_p->attr.stream_data.group_attr)); + + for (i=0; i < attr_p->attr.stream_data.num_group_id; i++) { + if (attr_p->attr.stream_data.group_ids[i]) { + flex_string_sprintf(fs, " %s", + attr_p->attr.stream_data.group_ids[i]); + } + } + + flex_string_append(fs, "\r\n"); + + return SDP_SUCCESS; +} + +/* Parse the source-filter attribute + * "a=source-filter:<filter-mode><filter-spec>" + * <filter-spec> = <nettype><addrtype><dest-addr><src_addr><src_addr>... + */ +sdp_result_e sdp_parse_attr_source_filter (sdp_t *sdp_p, sdp_attr_t *attr_p, + const char *ptr) +{ + int i; + sdp_result_e result; + char tmp[SDP_MAX_STRING_LEN]; + + attr_p->attr.source_filter.mode = SDP_FILTER_MODE_NOT_PRESENT; + attr_p->attr.source_filter.nettype = SDP_NT_UNSUPPORTED; + attr_p->attr.source_filter.addrtype = SDP_AT_UNSUPPORTED; + attr_p->attr.source_filter.dest_addr[0] = '\0'; + attr_p->attr.source_filter.num_src_addr = 0; + + /* 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); + } + + return (SDP_SUCCESS); +} + +sdp_result_e sdp_build_source_filter (sdp_t *sdp_p, sdp_attr_t *attr_p, + flex_string *fs) +{ + int i; + + flex_string_sprintf(fs, "a=%s:%s %s %s %s", + sdp_get_attr_name(attr_p->type), + sdp_get_src_filter_mode_name(attr_p->attr.source_filter.mode), + sdp_get_network_name(attr_p->attr.source_filter.nettype), + sdp_get_address_name(attr_p->attr.source_filter.addrtype), + attr_p->attr.source_filter.dest_addr); + + 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]); + } + + flex_string_append(fs, "\r\n"); + + return SDP_SUCCESS; +} + +/* Parse the rtcp-unicast attribute + * "a=rtcp-unicast:<reflection|rsi>" + */ +sdp_result_e sdp_parse_attr_rtcp_unicast (sdp_t *sdp_p, sdp_attr_t *attr_p, + const char *ptr) +{ + sdp_result_e result; + uint32_t i; + char tmp[SDP_MAX_STRING_LEN]; + + attr_p->attr.u32_val = SDP_RTCP_UNICAST_MODE_NOT_PRESENT; + + memset(tmp, 0, sizeof(tmp)); + + ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result); + if (result != SDP_SUCCESS) { + sdp_parse_error(sdp_p, + "%s Warning: No rtcp unicast mode specified for " + "a=rtcp-unicast line", sdp_p->debug_str); + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_PARAMETER); + } + for (i = 0; i < SDP_RTCP_MAX_UNICAST_MODE; i++) { + if (cpr_strncasecmp(tmp, sdp_rtcp_unicast_mode_val[i].name, + sdp_rtcp_unicast_mode_val[i].strlen) == 0) { + attr_p->attr.u32_val = i; + break; + } + } + if (attr_p->attr.u32_val == SDP_RTCP_UNICAST_MODE_NOT_PRESENT) { + sdp_parse_error(sdp_p, + "%s Warning: Invalid rtcp unicast mode for " + "a=rtcp-unicast line", 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_unicast (sdp_t *sdp_p, sdp_attr_t *attr_p, + flex_string *fs) +{ + if (attr_p->attr.u32_val >= SDP_RTCP_MAX_UNICAST_MODE) { + return SDP_INVALID_PARAMETER; + } + + flex_string_sprintf(fs, "a=%s:%s\r\n", + sdp_get_attr_name(attr_p->type), + sdp_get_rtcp_unicast_mode_name((sdp_rtcp_unicast_mode_e)attr_p->attr.u32_val)); + + return SDP_SUCCESS; +} + + +/* + * store_sdescriptions_mki_or_lifetime + * + * Verifies the syntax of the MKI or lifetime parameter and stores + * it in the sdescriptions attribute struct. + * + * Inputs: + * buf - pointer to MKI or lifetime string assumes string is null + * terminated. + * attr_p - pointer to attribute struct + * + * Outputs: + * Return TRUE all is good otherwise FALSE for error. + */ + +tinybool +store_sdescriptions_mki_or_lifetime (char *buf, sdp_attr_t *attr_p) +{ + + tinybool result; + uint16_t mkiLen; + char mkiValue[SDP_SRTP_MAX_MKI_SIZE_BYTES]; + + /* 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); + } + } + + return result; + +} + +/* + * sdp_parse_sdescriptions_key_param + * + * This routine parses the srtp key-params pointed to by str. + * + * key-params = <key-method> ":" <key-info> + * key-method = "inline" / key-method-ext [note V9 only supports 'inline'] + * key-info = srtp-key-info + * srtp-key-info = key-salt ["|" lifetime] ["|" mki] + * key-salt = 1*(base64) ; binary key and salt values + * ; concatenated together, and then + * ; base64 encoded [section 6.8 of + * ; RFC2046] + * + * lifetime = ["2^"] 1*(DIGIT) + * mki = mki-value ":" mki-length + * mki-value = 1*DIGIT + * mki-length = 1*3DIGIT ; range 1..128. + * + * Inputs: str - pointer to beginning of key-params and assumes + * null terminated string. + */ + + +tinybool +sdp_parse_sdescriptions_key_param (const char *str, sdp_attr_t *attr_p, + sdp_t *sdp_p) +{ + char buf[SDP_MAX_STRING_LEN], + base64decodeData[SDP_MAX_STRING_LEN]; + const char *ptr; + sdp_result_e result = SDP_SUCCESS; + tinybool keyFound = FALSE; + int len, + keySize, + saltSize; + base64_result_t status; + + 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++; + return FALSE; + } + + /* 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 + * master salt. + */ + status = base64_decode((unsigned char *)buf, strlen(buf), + (unsigned char *)base64decodeData, &len); + + if (status != BASE64_SUCCESS) { + sdp_parse_error(sdp_p, + "%s key-salt error decoding buffer: %s", + sdp_p->debug_str, BASE64_RESULT_TO_STRING(status)); + return FALSE; + } + + keySize = attr_p->attr.srtp_context.master_key_size_bytes; + saltSize = attr_p->attr.srtp_context.master_salt_size_bytes; + + if (len != keySize + saltSize) { + sdp_parse_error(sdp_p, + "%s key-salt size doesn't match: (%d, %d, %d)", + sdp_p->debug_str, len, keySize, saltSize); + return(FALSE); + } + + memcpy(attr_p->attr.srtp_context.master_key, + base64decodeData, + keySize); + + memcpy(attr_p->attr.srtp_context.master_salt, + base64decodeData + keySize, + saltSize); + + /* 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); + + } else if (store_sdescriptions_mki_or_lifetime(buf, attr_p) == FALSE) { + return FALSE; + } + + /* 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++; + return FALSE; + } + + return TRUE; + +} + +/* + * sdp_build_attr_sdescriptions + * + * Builds a=crypto line for attribute type SDP_ATTR_SDESCRIPTIONS. + * + * a=crypto:tag 1*WSP crypto-suite 1*WSP key-params + * + * Where key-params = inline: <key|salt> ["|"lifetime] ["|" MKI:length] + * The key and salt is base64 encoded and lifetime and MKI/length are optional. + */ + +sdp_result_e +sdp_build_attr_sdescriptions (sdp_t *sdp_p, sdp_attr_t *attr_p, + flex_string *fs) +{ + + unsigned char base64_encoded_data[MAX_BASE64_STRING_LEN]; + unsigned char base64_encoded_input[MAX_BASE64_STRING_LEN]; + int keySize, + saltSize, + outputLen; + base64_result_t status; + + keySize = attr_p->attr.srtp_context.master_key_size_bytes; + saltSize = attr_p->attr.srtp_context.master_salt_size_bytes; + + /* concatenate the master key + salt then base64 encode it */ + memcpy(base64_encoded_input, + attr_p->attr.srtp_context.master_key, + keySize); + + memcpy(base64_encoded_input + keySize, + attr_p->attr.srtp_context.master_salt, + saltSize); + + outputLen = MAX_BASE64_STRING_LEN; + status = base64_encode(base64_encoded_input, keySize + saltSize, + base64_encoded_data, &outputLen); + + if (status != 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); + + } + + base64_encoded_data[outputLen] = 0; + + /* lifetime and MKI parameters are optional. Only inlcude them if + * they were set. + */ + + + if (attr_p->attr.srtp_context.master_key_lifetime[0] != 0 && + attr_p->attr.srtp_context.mki[0] != 0) { + flex_string_sprintf(fs, "a=%s:%d %s inline:%s|%s|%s:%d\r\n", + sdp_attr[attr_p->type].name, + attr_p->attr.srtp_context.tag, + sdp_srtp_context_crypto_suite[attr_p->attr.srtp_context.suite].name, + base64_encoded_data, + attr_p->attr.srtp_context.master_key_lifetime, + attr_p->attr.srtp_context.mki, + attr_p->attr.srtp_context.mki_size_bytes); + + return SDP_SUCCESS; + } + + /* if we get here, either lifetime is populated and mki and is not or mki is populated + * and lifetime is not or neither is populated + */ + + if (attr_p->attr.srtp_context.master_key_lifetime[0] != 0) { + flex_string_sprintf(fs, "a=%s:%d %s inline:%s|%s\r\n", + sdp_attr[attr_p->type].name, + attr_p->attr.srtp_context.tag, + sdp_srtp_context_crypto_suite[attr_p->attr.srtp_context.suite].name, + base64_encoded_data, + attr_p->attr.srtp_context.master_key_lifetime); + + } else if (attr_p->attr.srtp_context.mki[0] != 0) { + flex_string_sprintf(fs, "a=%s:%d %s inline:%s|%s:%d\r\n", + sdp_attr[attr_p->type].name, + attr_p->attr.srtp_context.tag, + sdp_srtp_context_crypto_suite[attr_p->attr.srtp_context.suite].name, + base64_encoded_data, + attr_p->attr.srtp_context.mki, + attr_p->attr.srtp_context.mki_size_bytes); + + } else { + flex_string_sprintf(fs, "a=%s:%d %s inline:%s\r\n", + sdp_attr[attr_p->type].name, + attr_p->attr.srtp_context.tag, + sdp_srtp_context_crypto_suite[attr_p->attr.srtp_context.suite].name, + base64_encoded_data); + + } + + return SDP_SUCCESS; + +} + + +/* + * sdp_parse_attr_srtp + * + * Parses Session Description for Protocol Security Descriptions + * version 2 or version 9. Grammar is of the form: + * + * a=crypto:<tag> <crypto-suite> <key-params> [<session-params>] + * + * Note session-params is not supported and will not be parsed. + * Version 2 does not contain a tag. + * + * Inputs: + * sdp_p - pointer to sdp handle + * attr_p - pointer to attribute structure + * ptr - pointer to string to be parsed + * vtype - version type + */ + +sdp_result_e +sdp_parse_attr_srtp (sdp_t *sdp_p, sdp_attr_t *attr_p, + const char *ptr, sdp_attr_e vtype) +{ + + 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); + } + + if (!sdp_parse_context_crypto_suite(tmp, attr_p, sdp_p)) { + sdp_parse_error(sdp_p, + "%s Unsupported crypto suite", sdp_p->debug_str); + return (SDP_INVALID_PARAMETER); + } + + ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result); + if (result != SDP_SUCCESS) { + sdp_parse_error(sdp_p, + "%s Could not find sdescriptions key params", sdp_p->debug_str); + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_PARAMETER); + } + + if (!sdp_parse_sdescriptions_key_param(tmp, attr_p, sdp_p)) { + sdp_parse_error(sdp_p, + "%s Failed to parse key-params", sdp_p->debug_str); + return (SDP_INVALID_PARAMETER); + } + + /* if there are session parameters, scan the session parameters + * into tmp until we reach end of line. Currently the sdp parser + * does not parse session parameters but if they are present, + * we store them for the application. + */ + /*sa_ignore NO_NULL_CHK + *{ptr is valid since the pointer was checked earlier and the + * function would have exited if NULL.} + */ + while (*ptr && *ptr != '\n' && *ptr != '\r' && k < SDP_MAX_STRING_LEN) { + tmp[k++] = *ptr++; + } + + if ((k) && (k < SDP_MAX_STRING_LEN)) { + tmp[k] = 0; + attr_p->attr.srtp_context.session_parameters = cpr_strdup(tmp); + } + + return SDP_SUCCESS; + +} + +/* Parses crypto attribute based on the sdescriptions version + * 9 grammar. + * + */ + +sdp_result_e +sdp_parse_attr_sdescriptions (sdp_t *sdp_p, sdp_attr_t *attr_p, + const char *ptr) +{ + + return sdp_parse_attr_srtp(sdp_p, attr_p, ptr, + SDP_ATTR_SDESCRIPTIONS); + +} + +/* Parses X-crypto attribute based on the sdescriptions version + * 2 grammar. + * + */ + +sdp_result_e sdp_parse_attr_srtpcontext (sdp_t *sdp_p, sdp_attr_t *attr_p, + const char *ptr) +{ + + return sdp_parse_attr_srtp(sdp_p, attr_p, ptr, + SDP_ATTR_SRTP_CONTEXT); +} + + +sdp_result_e sdp_build_attr_ice_attr (sdp_t *sdp_p, sdp_attr_t *attr_p, + flex_string *fs) { + flex_string_sprintf(fs, "a=%s:%s\r\n", + sdp_get_attr_name(attr_p->type), + attr_p->attr.ice_attr); + + return SDP_SUCCESS; +} + + +sdp_result_e sdp_parse_attr_ice_attr (sdp_t *sdp_p, sdp_attr_t *attr_p, const char *ptr) { + sdp_result_e result; + char tmp[SDP_MAX_STRING_LEN]; + + ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), "\r\n", &result); + if (result != SDP_SUCCESS){ + sdp_parse_error(sdp_p, + "%s Warning: problem parsing ice attribute ", sdp_p->debug_str); + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_PARAMETER); + } + + snprintf(attr_p->attr.ice_attr, sizeof(attr_p->attr.ice_attr), "%s", tmp); + + if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) { + SDP_PRINT("%s Parsed a=%s, %s", sdp_p->debug_str, sdp_get_attr_name(attr_p->type), tmp); + } + return (SDP_SUCCESS); +} + + +sdp_result_e sdp_build_attr_simple_flag (sdp_t *sdp_p, sdp_attr_t *attr_p, + flex_string *fs) { + flex_string_sprintf(fs, "a=%s\r\n", sdp_get_attr_name(attr_p->type)); + + return SDP_SUCCESS; +} + + +sdp_result_e sdp_parse_attr_simple_flag (sdp_t *sdp_p, sdp_attr_t *attr_p, + const char *ptr) { + /* No parameters to parse. */ + + if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) { + SDP_PRINT("%s Parsed a=%s", sdp_p->debug_str, + sdp_get_attr_name(attr_p->type)); + } + + return (SDP_SUCCESS); +} + +static sdp_result_e sdp_parse_attr_line(sdp_t *sdp_p, sdp_attr_t *attr_p, + const char *ptr, char *buf, size_t buf_len) { + sdp_result_e result; + + (void)sdp_getnextstrtok(ptr, buf, buf_len, "\r\n", &result); + + 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_p->debug_flag[SDP_DEBUG_TRACE]) { + SDP_PRINT("%s Parsed a=%s, %s", sdp_p->debug_str, + sdp_get_attr_name(attr_p->type), + buf); + } + return (SDP_SUCCESS); + } +} + +sdp_result_e sdp_parse_attr_complete_line (sdp_t *sdp_p, sdp_attr_t *attr_p, + const char *ptr) +{ + return sdp_parse_attr_line(sdp_p, attr_p, ptr, + attr_p->attr.string_val, + sizeof(attr_p->attr.string_val)); +} + +sdp_result_e sdp_parse_attr_long_line (sdp_t *sdp_p, sdp_attr_t *attr_p, + const char *ptr) +{ + sdp_result_e result; + char buffer[SDP_MAX_LONG_STRING_LEN]; + + result = sdp_parse_attr_line(sdp_p, attr_p, ptr, + buffer, sizeof(buffer)); + if (result == SDP_SUCCESS) { + attr_p->attr.stringp = cpr_strdup(buffer); + } + return result; +} + +sdp_result_e sdp_build_attr_long_line (sdp_t *sdp_p, sdp_attr_t *attr_p, + flex_string *fs) +{ + flex_string_sprintf(fs, "a=%s:%s\r\n", sdp_attr[attr_p->type].name, + attr_p->attr.stringp); + return SDP_SUCCESS; +} + +sdp_result_e sdp_build_attr_rtcp_fb(sdp_t *sdp_p, + sdp_attr_t *attr_p, + flex_string *fs) +{ + flex_string_sprintf(fs, "a=%s:", sdp_attr[attr_p->type].name); + + /* Payload Type */ + if (attr_p->attr.rtcp_fb.payload_num == SDP_ALL_PAYLOADS) { + flex_string_sprintf(fs, "* "); + } else { + flex_string_sprintf(fs, "%d ",attr_p->attr.rtcp_fb.payload_num); + } + + /* Feedback Type */ + if (attr_p->attr.rtcp_fb.feedback_type < SDP_RTCP_FB_UNKNOWN) { + flex_string_sprintf(fs, "%s", + sdp_rtcp_fb_type_val[attr_p->attr.rtcp_fb.feedback_type].name); + } + + /* Feedback Type Parameters */ + switch (attr_p->attr.rtcp_fb.feedback_type) { + case SDP_RTCP_FB_ACK: + if (attr_p->attr.rtcp_fb.param.ack < SDP_MAX_RTCP_FB_ACK) { + flex_string_sprintf(fs, " %s", + sdp_rtcp_fb_ack_type_val[attr_p->attr.rtcp_fb.param.ack] + .name); + } + break; + case SDP_RTCP_FB_CCM: /* RFC 5104 */ + if (attr_p->attr.rtcp_fb.param.ccm < SDP_MAX_RTCP_FB_CCM) { + flex_string_sprintf(fs, " %s", + sdp_rtcp_fb_ccm_type_val[attr_p->attr.rtcp_fb.param.ccm] + .name); + } + break; + case SDP_RTCP_FB_NACK: + if (attr_p->attr.rtcp_fb.param.nack > SDP_RTCP_FB_NACK_BASIC + && attr_p->attr.rtcp_fb.param.nack < SDP_MAX_RTCP_FB_NACK) { + flex_string_sprintf(fs, " %s", + sdp_rtcp_fb_nack_type_val[attr_p->attr.rtcp_fb.param.nack] + .name); + } + break; + case SDP_RTCP_FB_TRR_INT: + flex_string_sprintf(fs, " %u", attr_p->attr.rtcp_fb.param.trr_int); + break; + case SDP_RTCP_FB_REMB: + /* No additional params after REMB */ + break; + case SDP_RTCP_FB_TRANSPORT_CC: + /* No additional params after Transport-CC */ + break; + + case SDP_RTCP_FB_UNKNOWN: + /* Contents are in the "extra" field */ + break; + + default: + SDPLogError(logTag, "%s Error: Invalid rtcp-fb enum (%d)", + sdp_p->debug_str, attr_p->attr.rtcp_fb.feedback_type); + return SDP_FAILURE; + } + + /* 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, + const char *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 + submessage types. If we decide to support these modes of + operation, we probably want to add parsing code for them. + For the time being, they'll just end up parsed into "extra" + Bug 1097169. + */ + 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, + const char *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; + } + + return SDP_SUCCESS; +} + +sdp_result_e sdp_build_attr_connection(sdp_t *sdp_p, + sdp_attr_t *attr_p, + flex_string *fs) +{ + switch (attr_p->attr.connection) { + case SDP_CONNECTION_NEW: + case SDP_CONNECTION_EXISTING: + flex_string_sprintf(fs, "a=%s:%s\r\n", + sdp_attr[attr_p->type].name, + sdp_connection_type_val[attr_p->attr.connection].name); + break; + default: + SDPLogError(logTag, "%s Error: Invalid connection enum (%d)", + sdp_p->debug_str, attr_p->attr.connection); + return SDP_FAILURE; + } + + return SDP_SUCCESS; +} + +sdp_result_e sdp_parse_attr_connection(sdp_t *sdp_p, + sdp_attr_t *attr_p, + const char *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; + } + + attr_p->attr.connection = (sdp_connection_type_e) i; + + 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; +} + +sdp_result_e sdp_build_attr_extmap(sdp_t *sdp_p, + sdp_attr_t *attr_p, + flex_string *fs) +{ + flex_string_sprintf(fs, "a=extmap:%d %s\r\n", + attr_p->attr.extmap.id, + attr_p->attr.extmap.uri); + + return SDP_SUCCESS; +} + +sdp_result_e sdp_parse_attr_extmap(sdp_t *sdp_p, + sdp_attr_t *attr_p, + const char *ptr) +{ + sdp_result_e result; + + attr_p->attr.extmap.id = 0; + attr_p->attr.extmap.media_direction = SDP_DIRECTION_SENDRECV; + attr_p->attr.extmap.media_direction_specified = FALSE; + attr_p->attr.extmap.uri[0] = '\0'; + attr_p->attr.extmap.extension_attributes[0] = '\0'; + + /* Find the payload type number. */ + attr_p->attr.extmap.id = + (uint16_t)sdp_getnextnumtok(ptr, &ptr, "/ \t", &result); + if (result != SDP_SUCCESS) { + sdp_parse_error(sdp_p, + "%s Warning: Invalid extmap id 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); + } + + if (*ptr == '/') { + char direction[SDP_MAX_STRING_LEN+1]; + ++ptr; /* Skip over '/' */ + ptr = sdp_getnextstrtok(ptr, direction, + sizeof(direction), " \t", &result); + if (result != SDP_SUCCESS) { + sdp_parse_error(sdp_p, + "%s Warning: Invalid direction 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); + } + + if (!cpr_strcasecmp(direction, "sendrecv")) { + attr_p->attr.extmap.media_direction = SDP_DIRECTION_SENDRECV; + } else if (!cpr_strcasecmp(direction, "sendonly")) { + attr_p->attr.extmap.media_direction = SDP_DIRECTION_SENDONLY; + } else if (!cpr_strcasecmp(direction, "recvonly")) { + attr_p->attr.extmap.media_direction = SDP_DIRECTION_RECVONLY; + } else if (!cpr_strcasecmp(direction, "inactive")) { + attr_p->attr.extmap.media_direction = SDP_DIRECTION_INACTIVE; + } else { + sdp_parse_error(sdp_p, + "%s Warning: Invalid direction 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); + } + attr_p->attr.extmap.media_direction_specified = TRUE; + } + + 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); + } + + return (SDP_SUCCESS); +} + +sdp_result_e sdp_parse_attr_msid(sdp_t *sdp_p, + sdp_attr_t *attr_p, + const char *ptr) +{ + sdp_result_e result; + + ptr = sdp_getnextstrtok(ptr, attr_p->attr.msid.identifier, + sizeof(attr_p->attr.msid.identifier), " \t", &result); + if (result != SDP_SUCCESS) { + sdp_parse_error(sdp_p, "%s Warning: Bad msid identity value", + sdp_p->debug_str); + sdp_p->conf_p->num_invalid_param++; + return SDP_INVALID_PARAMETER; + } + + ptr = sdp_getnextstrtok(ptr, attr_p->attr.msid.appdata, + sizeof(attr_p->attr.msid.appdata), " \t", &result); + if ((result != SDP_SUCCESS) && (result != SDP_EMPTY_TOKEN)) { + sdp_parse_error(sdp_p, "%s Warning: Bad msid appdata value", + sdp_p->debug_str); + sdp_p->conf_p->num_invalid_param++; + return SDP_INVALID_PARAMETER; + } + if (result == SDP_EMPTY_TOKEN) { + attr_p->attr.msid.appdata[0] = '\0'; + } + + if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) { + SDP_PRINT("%s Parsed a=msid, %s %s", sdp_p->debug_str, + attr_p->attr.msid.identifier, attr_p->attr.msid.appdata); + } + + return SDP_SUCCESS; +} + + +sdp_result_e sdp_build_attr_msid(sdp_t *sdp_p, + sdp_attr_t *attr_p, + flex_string *fs) +{ + flex_string_sprintf(fs, "a=msid:%s%s%s\r\n", + attr_p->attr.msid.identifier, + attr_p->attr.msid.appdata[0] ? " " : "", + attr_p->attr.msid.appdata); + return SDP_SUCCESS; +} + +sdp_result_e sdp_parse_attr_msid_semantic(sdp_t *sdp_p, + sdp_attr_t *attr_p, + const char *ptr) +{ + sdp_result_e result; + int i; + + ptr = sdp_getnextstrtok(ptr, + attr_p->attr.msid_semantic.semantic, + sizeof(attr_p->attr.msid_semantic.semantic), + " \t", + &result); + + 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) { + break; + } + + attr_p->attr.msid_semantic.msids[i] = cpr_strdup(temp); + } + + 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; + } + + SDP_PRINT("%s ... msid %s", sdp_p->debug_str, + attr_p->attr.msid_semantic.msids[i]); + } + } + + return SDP_SUCCESS; +} + + +sdp_result_e sdp_build_attr_msid_semantic(sdp_t *sdp_p, + sdp_attr_t *attr_p, + flex_string *fs) +{ + int i; + flex_string_sprintf(fs, "a=msid-semantic:%s", + attr_p->attr.msid_semantic.semantic); + for (i = 0; i < SDP_MAX_MEDIA_STREAMS; ++i) { + if (!attr_p->attr.msid_semantic.msids[i]) { + break; + } + + flex_string_sprintf(fs, " %s", + attr_p->attr.msid_semantic.msids[i]); + } + flex_string_sprintf(fs, "\r\n"); + return SDP_SUCCESS; +} + +sdp_result_e sdp_parse_attr_ssrc(sdp_t *sdp_p, + sdp_attr_t *attr_p, + const char *ptr) +{ + sdp_result_e result; + + attr_p->attr.ssrc.ssrc = + (uint32_t)sdp_getnextnumtok(ptr, &ptr, " \t", &result); + + 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); + + return SDP_SUCCESS; +} + + +sdp_result_e sdp_build_attr_ssrc(sdp_t *sdp_p, + sdp_attr_t *attr_p, + flex_string *fs) +{ + flex_string_sprintf(fs, "a=ssrc:%s%s%s\r\n", + attr_p->attr.ssrc.ssrc, + attr_p->attr.ssrc.attribute[0] ? " " : "", + attr_p->attr.ssrc.attribute); + return SDP_SUCCESS; +} + + +sdp_result_e sdp_parse_attr_ssrc_group(sdp_t *sdp_p, sdp_attr_t *attr_p, + const char *ptr) +{ + sdp_result_e result; + char tmp[SDP_MAX_STRING_LEN + 1]; + int i; + + /* Find the a=ssrc-group:<semantic> <ssrc1> <ssrc2> ... values */ + ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result); + if (result != SDP_SUCCESS) { + sdp_parse_error(sdp_p, + "%s Warning: No semantic attribute value specified for " + "a=ssrc-group line", + sdp_p->debug_str); + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_PARAMETER); + } + + attr_p->attr.ssrc_group.semantic = SDP_SSRC_GROUP_ATTR_UNSUPPORTED; + for (i = 0; i < SDP_MAX_SSRC_GROUP_ATTR_VAL; i++) { + if (cpr_strncasecmp(tmp, sdp_ssrc_group_attr_val[i].name, + sdp_ssrc_group_attr_val[i].strlen) == 0) { + attr_p->attr.ssrc_group.semantic = (sdp_ssrc_group_attr_e)i; + break; + } + } + + if (attr_p->attr.ssrc_group.semantic == SDP_SSRC_GROUP_ATTR_UNSUPPORTED) { + sdp_parse_error(sdp_p, + "%s Warning: Ssrc group attribute type unsupported (%s).", + sdp_p->debug_str, tmp); + } + + for (i = 0; i < SDP_MAX_SSRC_GROUP_SSRCS; ++i) { + attr_p->attr.ssrc_group.ssrcs[i] = + (uint32_t)sdp_getnextnumtok(ptr, &ptr, " \t", &result); + + if (result != SDP_SUCCESS) { + break; + } + + attr_p->attr.ssrc_group.num_ssrcs++; + } + + ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result); + if (result == SDP_SUCCESS) { + sdp_parse_error(sdp_p, + "%s Warning: Trailing tokens while parsing ssrc-group (%s).", + sdp_p->debug_str, tmp); + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_PARAMETER); + } + + 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]); + } + } + + return (SDP_SUCCESS); +} + +sdp_result_e sdp_build_attr_ssrc_group(sdp_t *sdp_p, sdp_attr_t *attr_p, + flex_string *fs) +{ + int i; + flex_string_sprintf( + fs, "a=ssrc-group:%s", + sdp_get_ssrc_group_attr_name(attr_p->attr.ssrc_group.semantic)); + + if (attr_p->attr.ssrc_group.num_ssrcs) { + return (SDP_FAILURE); + } + + for (i = 0; i < attr_p->attr.ssrc_group.num_ssrcs; ++i) { + flex_string_sprintf(fs, " %u", attr_p->attr.ssrc_group.ssrcs[i]); + } + flex_string_sprintf(fs, "\r\n"); + return (SDP_SUCCESS); +} diff --git a/third_party/sipcc/sdp_attr_access.c b/third_party/sipcc/sdp_attr_access.c new file mode 100644 index 0000000000..b3efa3e6b6 --- /dev/null +++ b/third_party/sipcc/sdp_attr_access.c @@ -0,0 +1,6426 @@ +/* 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 "sdp_os_defs.h" +#include "sipcc_sdp.h" +#include "sdp_private.h" + +#include "sdp_log.h" + +static const char* logTag = "sdp_attr_access"; + +/* Attribute access routines are all defined by the following parameters. + * + * sdp_p The SDP handle returned by sdp_init_description. + * level The level the attribute is defined. Can be either + * SDP_SESSION_LEVEL or 0-n specifying a media line level. + * inst_num The instance number of the attribute. Multiple instances + * of a particular attribute may exist at each level and so + * the inst_num determines the particular attribute at that + * level that should be accessed. Note that this is the + * instance number of the specified type of attribute, not the + * overall attribute number at the level. Also note that the + * instance number is 1-based. For example: + * v=0 + * o=mhandley 2890844526 2890842807 IN IP4 126.16.64.4 + * s=SDP Seminar + * c=IN IP4 10.1.0.2 + * t=0 0 + * m=audio 1234 RTP/AVP 0 101 102 + * a=foo 1 + * a=foo 2 + * a=bar 1 # This is instance 1 of attribute bar. + * a=foo 3 # This is instance 3 of attribute foo. + * cap_num Almost all of the attributes may be defined as X-cpar + * parameters (with the exception of X-sqn, X-cap, and X-cpar). + * If the cap_num is set to zero, then the attribute is not + * an X-cpar parameter attribute. If the cap_num is any other + * value, it specifies the capability number that the X-cpar + * attribute is specified for. + */ + +/* Attribute handling: + * + * There are two basic types of attributes handled by the SDP library, + * those defined by a= token lines, and those embedded with a=X-cpar lines. + * The handling for each of these is described here. + * + * Simple (non X-cpar attributes): + * + * Attributes not embedded in a=X-cpar lines are referenced by level and + * instance number. For these attributes the capability number is always + * set to zero. + * + * An application will typically process these attributes in one of two ways. + * With the first method, the application can determine the total number + * of attributes defined at a given level and process them one at a time. + * For each attribute, the application will query the library to find out + * what type of attribute it is and which instance within that type. The + * application can then process this particular attribute referencing it + * by level and instance number. + * + * A second method of processing attributes is for applications to determine + * each type of attribute they are interested in, query the SDP library to + * find out how many of that type of attribute exist at a given level, and + * process each one at a time. + * + * X-cpar attribute processing: + * + * X-cpar attributes can contain embedded attributes. They are associated + * with X-cap attribute lines. An example of X-cap and X-cpar attributes + * found in an SDP is as follows: + * + * v=0 + * o=- 25678 753849 IN IP4 128.96.41.1 + * s=- + * t=0 0 + * c=IN IP4 10.1.0.2 + * m=audio 3456 RTP/AVP 18 96 + * a=rtpmap:96 telephone-event/8000 + * a=fmtp:96 0-15,32-35 + * a=X-sqn: 0 + * a=X-cap: 1 audio RTP/AVP 0 18 96 97 + * a=X-cpar: a=fmtp:96 0-16,32-35 + * a=X-cpar: a=rtpmap:97 X-NSE/8000 + * a=X-cpar: a=fmtp:97 195-197 + * a=X-cap: 5 image udptl t38 + * a=X-cap: 6 application udp X-tmr + * a=X-cap: 7 audio RTP/AVP 100 101 + * a=X-cpar: a=rtpmap:100 g.711/8000 + * a=X-cpar: a=rtpmap:101 g.729/8000 + * + * X-cap attributes can be defined at the SESSION_LEVEL or any media level. + * An X-cap attr is defined by the level and instance number just like + * other attributes. In the example above, X-cap attrs are defined at + * media level 1 and there are four instances at that level. + * + * The X-cpar attributes can also be referenced by level and instance number. + * However, the embedded attribute within an X-cpar attribute must be + * referenced by level, instance number, and capability number. This is + * because the X-cpar attribute is associated with a particular X-cap/ + * capability. + * For all attributes that are not embedded within an X-cpar attribute, the + * cap_num should be referenced as zero. But for X-cpar attributes, the + * cap_num is specified to be one of the capability numbers of the previous + * X-cap line. The number of capabilities specified in an X-cap line is + * equal to the number of payloads. Thus, in this example, the first X-cap + * attr instance specifies capabilities 1-4, the second specifies capability + * 5, the third capability 6, and the fourth capabilities 7-8. + * + * X-cpar attributes can be processed with methods similar to the two + * previously mentioned. For each X-cap attribute, the application can + * use one of two methods to process the X-cpar attributes. First, it + * can query the total number of X-cpar attributes associated with a + * given X-cap attribute. The X-cap attribute is here defined by a level + * and a capability number. In the example above, the total number of + * attributes defined is as follows: + * level 1, cap_num 1 - total attrs: 3 + * level 1, cap_num 5 - total attrs: 0 + * level 1, cap_num 6 - total attrs: 0 + * level 1, cap_num 7 - total attrs: 2 + * + * Note that if the application queried the number of attributes for + * cap_num 2, 3, or 4, it would also return 3 attrs, and for cap_num + * 8 the library would return 2. + * + * Once the application determines the total number of attributes for + * that capability, it can again query the embedded attribute type and + * instance. For example, sdp_get_attr_type would return the following: + * level 1, cap_num 1, attr 1 -> attr type fmtp, instance 1 + * level 1, cap_num 1, attr 2 -> attr type rtpmap, instance 1 + * level 1, cap_num 1, attr 3 -> attr type fmtp, instance 2 + * level 1, cap_num 7, attr 1 -> attr type rtpmap, instance 1 + * level 1, cap_num 7, attr 2 -> attr type rtpmap, instance 2 + * + * The individual embedded attributes can then be accessed by level, + * cap_num, and instance number. + * + * With the second method for handling X-cpar attributes, the application + * determines the types of attributes it is interested in. It can then + * query the SDP library to determine the number of attributes of that + * type found for that level and cap_num, and then process each one at + * a time. e.g., calling sdp_attr_num_instances would give: + * level 1, cap_num 1, attr_type fmtp -> two instances + * level 1, cap_num 1, attr_type rtpmap -> one instance + * level 1, cap_num 7, attr_type fmtp -> zero instances + * level 1, cap_num 7, attr_type rtpmap -> two instances + */ + + +/* Function: sdp_add_new_attr + * Description: Add a new attribute of the specified type at the given + * level and capability level or base attribute if cap_num + * is zero. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * attr_type The type of attribute to add. + * inst_num Pointer to a uint16_t in which to return the instance + * number of the newly added attribute. + * Returns: SDP_SUCCESS Attribute was added successfully. + * SDP_NO_RESOURCE No memory avail for new attribute. + * SDP_INVALID_PARAMETER Specified media line is not defined. + */ +sdp_result_e sdp_add_new_attr (sdp_t *sdp_p, uint16_t level, uint8_t cap_num, + sdp_attr_e attr_type, uint16_t *inst_num) +{ + uint16_t i; + sdp_mca_t *mca_p; + sdp_mca_t *cap_p; + sdp_attr_t *attr_p; + sdp_attr_t *new_attr_p; + sdp_attr_t *prev_attr_p=NULL; + sdp_fmtp_t *fmtp_p; + sdp_comediadir_t *comediadir_p; + + *inst_num = 0; + + if ((cap_num != 0) && + ((attr_type == SDP_ATTR_X_CAP) || (attr_type == SDP_ATTR_X_CPAR) || + (attr_type == SDP_ATTR_X_SQN) || (attr_type == SDP_ATTR_CDSC) || + (attr_type == SDP_ATTR_CPAR) || (attr_type == SDP_ATTR_SQN))) { + if (sdp_p->debug_flag[SDP_DEBUG_WARNINGS]) { + SDPLogDebug(logTag, "%s Warning: Invalid attribute type for X-cpar/cdsc " + "parameter.", sdp_p->debug_str); + } + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_PARAMETER); + } + + /* Some attributes are valid only under media level */ + if (level == SDP_SESSION_LEVEL) { + switch (attr_type) { + case SDP_ATTR_RTCP: + case SDP_ATTR_LABEL: + return (SDP_INVALID_MEDIA_LEVEL); + + default: + break; + } + } + + new_attr_p = (sdp_attr_t *)SDP_MALLOC(sizeof(sdp_attr_t)); + if (new_attr_p == NULL) { + sdp_p->conf_p->num_no_resource++; + return (SDP_NO_RESOURCE); + } + + new_attr_p->type = attr_type; + new_attr_p->next_p = NULL; + + /* Initialize the new attribute structure */ + if ((new_attr_p->type == SDP_ATTR_X_CAP) || + (new_attr_p->type == SDP_ATTR_CDSC)) { + new_attr_p->attr.cap_p = (sdp_mca_t *)SDP_MALLOC(sizeof(sdp_mca_t)); + if (new_attr_p->attr.cap_p == NULL) { + sdp_free_attr(new_attr_p); + sdp_p->conf_p->num_no_resource++; + return (SDP_NO_RESOURCE); + } + } else if (new_attr_p->type == SDP_ATTR_FMTP) { + fmtp_p = &(new_attr_p->attr.fmtp); + fmtp_p->fmtp_format = SDP_FMTP_UNKNOWN_TYPE; + // set to invalid value + fmtp_p->packetization_mode = SDP_INVALID_PACKETIZATION_MODE_VALUE; + fmtp_p->level_asymmetry_allowed = SDP_INVALID_LEVEL_ASYMMETRY_ALLOWED_VALUE; + fmtp_p->annexb_required = FALSE; + fmtp_p->annexa_required = FALSE; + fmtp_p->maxval = 0; + fmtp_p->bitrate = 0; + fmtp_p->cif = 0; + fmtp_p->qcif = 0; + fmtp_p->profile = SDP_INVALID_VALUE; + fmtp_p->level = SDP_INVALID_VALUE; + fmtp_p->parameter_add = SDP_FMTP_UNUSED; + fmtp_p->usedtx = SDP_FMTP_UNUSED; + fmtp_p->stereo = SDP_FMTP_UNUSED; + fmtp_p->useinbandfec = SDP_FMTP_UNUSED; + fmtp_p->cbr = SDP_FMTP_UNUSED; + for (i=0; i < SDP_NE_NUM_BMAP_WORDS; i++) { + fmtp_p->bmap[i] = 0; + } + } else if ((new_attr_p->type == SDP_ATTR_RTPMAP) || + (new_attr_p->type == SDP_ATTR_SPRTMAP)) { + new_attr_p->attr.transport_map.num_chan = 1; + } else if (new_attr_p->type == SDP_ATTR_DIRECTION) { + comediadir_p = &(new_attr_p->attr.comediadir); + comediadir_p->role = SDP_MEDIADIR_ROLE_PASSIVE; + comediadir_p->conn_info_present = FALSE; + } else if (new_attr_p->type == SDP_ATTR_MPTIME) { + sdp_mptime_t *mptime = &(new_attr_p->attr.mptime); + mptime->num_intervals = 0; + } + + if (cap_num == 0) { + /* Add a new attribute. */ + if (level == SDP_SESSION_LEVEL) { + if (sdp_p->sess_attrs_p == NULL) { + sdp_p->sess_attrs_p = new_attr_p; + } else { + for (attr_p = sdp_p->sess_attrs_p; + attr_p != NULL; + prev_attr_p = attr_p, attr_p = attr_p->next_p) { + /* Count the num instances of this type. */ + if (attr_p->type == attr_type) { + (*inst_num)++; + } + } + prev_attr_p->next_p = new_attr_p; + } + } else { + mca_p = sdp_find_media_level(sdp_p, level); + if (mca_p == NULL) { + sdp_free_attr(new_attr_p); + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_PARAMETER); + } + if (mca_p->media_attrs_p == NULL) { + mca_p->media_attrs_p = new_attr_p; + } else { + for (attr_p = mca_p->media_attrs_p; + attr_p != NULL; + prev_attr_p = attr_p, attr_p = attr_p->next_p) { + /* Count the num instances of this type. */ + if (attr_p->type == attr_type) { + (*inst_num)++; + } + } + prev_attr_p->next_p = new_attr_p; + } + } + } else { + /* Add a new capability attribute - find the capability attr. */ + attr_p = sdp_find_capability(sdp_p, level, cap_num); + if (attr_p == NULL) { + sdp_free_attr(new_attr_p); + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_PARAMETER); + } + cap_p = attr_p->attr.cap_p; + if (cap_p->media_attrs_p == NULL) { + cap_p->media_attrs_p = new_attr_p; + } else { + for (attr_p = cap_p->media_attrs_p; + attr_p != NULL; + prev_attr_p = attr_p, attr_p = attr_p->next_p) { + /* Count the num instances of this type. */ + if (attr_p->type == attr_type) { + (*inst_num)++; + } + } + prev_attr_p->next_p = new_attr_p; + } + } + + /* Increment the instance num for the attr just added. */ + (*inst_num)++; + return (SDP_SUCCESS); +} + +/* Function: sdp_attr_num_instances + * Description: Get the number of attributes of the specified type at + * the given level and capability level. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * attr_type The type of attribute to add. + * num_attr_inst Pointer to a uint16_t in which to return the + * number of attributes. + * Returns: SDP_SUCCESS Attribute was added successfully. + * SDP_INVALID_PARAMETER Specified media line is not defined. + */ +sdp_result_e sdp_attr_num_instances (sdp_t *sdp_p, uint16_t level, uint8_t cap_num, + sdp_attr_e attr_type, uint16_t *num_attr_inst) +{ + sdp_attr_t *attr_p; + sdp_result_e rc; + static char fname[] = "attr_num_instances"; + + *num_attr_inst = 0; + + rc = sdp_find_attr_list(sdp_p, level, cap_num, &attr_p, fname); + if (rc == SDP_SUCCESS) { + /* Found the attr list. Count the number of attrs of the given + * type at this level. */ + for (; attr_p != NULL; attr_p = attr_p->next_p) { + if (attr_p->type == attr_type) { + (*num_attr_inst)++; + } + } + + } + + return (rc); +} + +/* Forward declaration for use in sdp_free_attr */ +static boolean sdp_attr_is_long_string(sdp_attr_e attr_type); + + +/* Internal routine to free the memory associated with an attribute. + * Certain attributes allocate additional memory. Free this and then + * free the attribute itself. + * Note that this routine may be called at any point (i.e., may be + * called due to a failure case) and so the additional memory + * associated with an attribute may or may not have been already + * allocated. This routine should check this carefully. + */ +void sdp_free_attr (sdp_attr_t *attr_p) +{ + sdp_mca_t *cap_p; + sdp_attr_t *cpar_p; + sdp_attr_t *next_cpar_p; + int i; + + /* If this is an X-cap/cdsc attr, free the cap_p structure and + * all X-cpar/cpar attributes. */ + if ((attr_p->type == SDP_ATTR_X_CAP) || + (attr_p->type == SDP_ATTR_CDSC)) { + cap_p = attr_p->attr.cap_p; + if (cap_p != NULL) { + for (cpar_p = cap_p->media_attrs_p; cpar_p != NULL;) { + next_cpar_p = cpar_p->next_p; + sdp_free_attr(cpar_p); + cpar_p = next_cpar_p; + } + SDP_FREE(cap_p); + } + } else if ((attr_p->type == SDP_ATTR_SDESCRIPTIONS) || + (attr_p->type == SDP_ATTR_SRTP_CONTEXT)) { + SDP_FREE(attr_p->attr.srtp_context.session_parameters); + } else if (sdp_attr_is_long_string(attr_p->type)) { + SDP_FREE(attr_p->attr.stringp); + } + + if (attr_p->type == SDP_ATTR_GROUP) { + for (i = 0; i < attr_p->attr.stream_data.num_group_id; i++) { + SDP_FREE(attr_p->attr.stream_data.group_ids[i]); + } + } else if (attr_p->type == SDP_ATTR_MSID_SEMANTIC) { + for (i = 0; i < SDP_MAX_MEDIA_STREAMS; ++i) { + SDP_FREE(attr_p->attr.msid_semantic.msids[i]); + } + } + + /* Now free the actual attribute memory. */ + SDP_FREE(attr_p); + +} + + +/* Function: sdp_find_attr_list + * Description: Find the attribute list for the specified level and cap_num. + * Note: This is not an API for the application but an internal + * routine used by the SDP library. + * Parameters: sdp_p Pointer to the SDP to search. + * level The level to check for the attribute list. + * cap_num The capability number associated with the + * attribute list. If none, should be zero. + * attr_p Pointer to the attr list pointer. Will be + * filled in on return if successful. + * fname String function name calling this routine. + * Use for printing debug. + * Returns: SDP_SUCCESS + * SDP_INVALID_MEDIA_LEVEL + * SDP_INVALID_CAPABILITY + * SDP_FAILURE + */ +sdp_result_e sdp_find_attr_list (sdp_t *sdp_p, uint16_t level, uint8_t cap_num, + sdp_attr_t **attr_p, char *fname) +{ + sdp_mca_t *mca_p; + sdp_mca_t *cap_p; + sdp_attr_t *cap_attr_p; + + /* Initialize the attr pointer. */ + *attr_p = NULL; + + if (cap_num == 0) { + /* Find attribute list at the specified level. */ + 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) { + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_PARAMETER); + } + *attr_p = mca_p->media_attrs_p; + } + } else { + /* Find the attr list for the capability specified. */ + cap_attr_p = sdp_find_capability(sdp_p, level, cap_num); + if (cap_attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s %s, invalid capability %u at " + "level %u specified.", sdp_p->debug_str, fname, + (unsigned)cap_num, (unsigned)level); + } + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_CAPABILITY); + } + cap_p = cap_attr_p->attr.cap_p; + *attr_p = cap_p->media_attrs_p; + } + + return (SDP_SUCCESS); +} + +/* Find fmtp inst_num with correct payload value or -1 for failure */ +int sdp_find_fmtp_inst (sdp_t *sdp_p, uint16_t level, uint16_t payload_num) +{ + uint16_t attr_count=0; + sdp_mca_t *mca_p; + sdp_attr_t *attr_p; + + /* Attr is at a media level */ + mca_p = sdp_find_media_level(sdp_p, level); + if (mca_p == NULL) { + return (-1); + } + for (attr_p = mca_p->media_attrs_p; attr_p != NULL; + attr_p = attr_p->next_p) { + if (attr_p->type == SDP_ATTR_FMTP) { + attr_count++; + if (attr_p->attr.fmtp.payload_num == payload_num) { + return (attr_count); + } + } + } + + return (-1); + +} + +/* Function: sdp_find_attr + * Description: Find the specified attribute in an SDP structure. + * Note: This is not an API for the application but an internal + * routine used by the SDP library. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * attr_type The type of attribute to find. + * inst_num The instance num of the attribute to find. + * Range should be (1 - max num insts of this + * particular type of attribute at this level). + * Returns: Pointer to the attribute or NULL if not found. + */ +sdp_attr_t *sdp_find_attr (sdp_t *sdp_p, uint16_t level, uint8_t cap_num, + sdp_attr_e attr_type, uint16_t inst_num) +{ + uint16_t attr_count=0; + sdp_mca_t *mca_p; + sdp_mca_t *cap_p; + sdp_attr_t *attr_p; + + if (inst_num < 1) { + return (NULL); + } + + if (cap_num == 0) { + if (level == SDP_SESSION_LEVEL) { + for (attr_p = sdp_p->sess_attrs_p; attr_p != NULL; + attr_p = attr_p->next_p) { + if (attr_p->type == attr_type) { + attr_count++; + if (attr_count == inst_num) { + return (attr_p); + } + } + } + } else { /* Attr is at a media level */ + mca_p = sdp_find_media_level(sdp_p, level); + if (mca_p == NULL) { + return (NULL); + } + for (attr_p = mca_p->media_attrs_p; attr_p != NULL; + attr_p = attr_p->next_p) { + if (attr_p->type == attr_type) { + attr_count++; + if (attr_count == inst_num) { + return (attr_p); + } + } + } + } /* Attr is at a media level */ + } else { + /* Attr is a capability X-cpar/cpar attribute. */ + attr_p = sdp_find_capability(sdp_p, level, cap_num); + if (attr_p == NULL) { + return (NULL); + } + cap_p = attr_p->attr.cap_p; + /* Now find the specific attribute. */ + for (attr_p = cap_p->media_attrs_p; attr_p != NULL; + attr_p = attr_p->next_p) { + if (attr_p->type == attr_type) { + attr_count++; + if (attr_count == inst_num) { + return (attr_p); + } + } + } + } + + return (NULL); +} + +/* Function: sdp_find_capability + * Description: Find the specified capability attribute in an SDP structure. + * Note: This is not an API for the application but an internal + * routine used by the SDP library. + * Parameters: sdp_p The SDP handle. + * level The level to check for the capability. + * cap_num The capability number to locate. + * Returns: Pointer to the capability attribute or NULL if not found. + */ +sdp_attr_t *sdp_find_capability (sdp_t *sdp_p, uint16_t level, uint8_t cap_num) +{ + uint8_t cur_cap_num=0; + sdp_mca_t *mca_p; + sdp_mca_t *cap_p; + sdp_attr_t *attr_p; + + if (level == SDP_SESSION_LEVEL) { + for (attr_p = sdp_p->sess_attrs_p; attr_p != NULL; + attr_p = attr_p->next_p) { + if ((attr_p->type == SDP_ATTR_X_CAP) || + (attr_p->type == SDP_ATTR_CDSC)) { + cap_p = attr_p->attr.cap_p; + cur_cap_num += cap_p->num_payloads; + if (cap_num <= cur_cap_num) { + /* This is the right capability */ + return (attr_p); + } + } + } + } else { /* Capability is at a media level */ + mca_p = sdp_find_media_level(sdp_p, level); + if (mca_p == NULL) { + return (NULL); + } + for (attr_p = mca_p->media_attrs_p; attr_p != NULL; + attr_p = attr_p->next_p) { + if ((attr_p->type == SDP_ATTR_X_CAP) || + (attr_p->type == SDP_ATTR_CDSC)) { + cap_p = attr_p->attr.cap_p; + cur_cap_num += cap_p->num_payloads; + if (cap_num <= cur_cap_num) { + /* This is the right capability */ + return (attr_p); + } + } + } + } + + /* We didn't find the specified capability. */ + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s Unable to find specified capability (level %u, " + "cap_num %u).", sdp_p->debug_str, (unsigned)level, (unsigned)cap_num); + } + sdp_p->conf_p->num_invalid_param++; + return (NULL); +} + +/* Function: sdp_attr_valid(sdp_t *sdp_p) + * Description: Returns true or false depending on whether the specified + * instance of the given attribute has been defined at the + * given level. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * attr_type The attribute type to validate. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * Returns: TRUE or FALSE. + */ +tinybool sdp_attr_valid (sdp_t *sdp_p, sdp_attr_e attr_type, uint16_t level, + uint8_t cap_num, uint16_t inst_num) +{ + if (sdp_find_attr(sdp_p, level, cap_num, attr_type, inst_num) == NULL) { + return (FALSE); + } else { + return (TRUE); + } +} + +/* Function: sdp_attr_line_number(sdp_t *sdp_p) + * Description: Returns the line number this attribute appears on. + * Only works if the SDP was parsed rather than created + * locally. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * attr_type The attribute type to validate. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * Returns: line number, or 0 if an error + */ +uint32_t sdp_attr_line_number (sdp_t *sdp_p, sdp_attr_e attr_type, uint16_t level, + uint8_t cap_num, uint16_t inst_num) +{ + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, attr_type, inst_num); + if (attr_p == NULL) { + return 0; + } else { + return attr_p->line_number; + } +} + +static boolean sdp_attr_is_simple_string(sdp_attr_e attr_type) { + if ((attr_type != SDP_ATTR_BEARER) && + (attr_type != SDP_ATTR_CALLED) && + (attr_type != SDP_ATTR_CONN_TYPE) && + (attr_type != SDP_ATTR_DIALED) && + (attr_type != SDP_ATTR_DIALING) && + (attr_type != SDP_ATTR_FRAMING) && + (attr_type != SDP_ATTR_MID) && + (attr_type != SDP_ATTR_X_SIDIN) && + (attr_type != SDP_ATTR_X_SIDOUT)&& + (attr_type != SDP_ATTR_X_CONFID) && + (attr_type != SDP_ATTR_LABEL) && + (attr_type != SDP_ATTR_ICE_OPTIONS) && + (attr_type != SDP_ATTR_IMAGEATTR) && + (attr_type != SDP_ATTR_SIMULCAST) && + (attr_type != SDP_ATTR_RID)) { + return FALSE; + } + return TRUE; +} + +/* Function: sdp_attr_get_simple_string + * Description: Returns a pointer to a string attribute parameter. This + * routine can only be called for attributes that have just + * one string parameter. The value is returned as a const + * ptr and so cannot be modified by the application. If the + * given attribute is not defined, NULL will be returned. + * Attributes with a simple string parameter currently include: + * bearer, called, connection_type, dialed, dialing, direction + * and framing. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * attr_type The simple string attribute type. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * Returns: Pointer to the parameter value. + */ +const char *sdp_attr_get_simple_string (sdp_t *sdp_p, sdp_attr_e attr_type, + uint16_t level, uint8_t cap_num, uint16_t inst_num) +{ + sdp_attr_t *attr_p; + + if (!sdp_attr_is_simple_string(attr_type)) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s Attribute type is not a simple string (%s)", + sdp_p->debug_str, sdp_get_attr_name(attr_type)); + } + sdp_p->conf_p->num_invalid_param++; + return (NULL); + } + + attr_p = sdp_find_attr(sdp_p, level, cap_num, attr_type, inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s Attribute %s, level %u instance %u not found.", + sdp_p->debug_str, sdp_get_attr_name(attr_type), + (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (NULL); + } else { + return (attr_p->attr.string_val); + } +} + +static boolean sdp_attr_is_long_string(sdp_attr_e attr_type) { + return (attr_type == SDP_ATTR_IDENTITY || attr_type == SDP_ATTR_DTLS_MESSAGE); +} + +/* Identical in usage to sdp_attr_get_simple_string() */ +const char *sdp_attr_get_long_string (sdp_t *sdp_p, sdp_attr_e attr_type, + uint16_t level, uint8_t cap_num, uint16_t inst_num) +{ + sdp_attr_t *attr_p; + + if (!sdp_attr_is_long_string(attr_type)) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s Attribute type is not a long string (%s)", + sdp_p->debug_str, sdp_get_attr_name(attr_type)); + } + sdp_p->conf_p->num_invalid_param++; + return (NULL); + } + + attr_p = sdp_find_attr(sdp_p, level, cap_num, attr_type, inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s Attribute %s, level %u instance %u not found.", + sdp_p->debug_str, sdp_get_attr_name(attr_type), + (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (NULL); + } else { + return (attr_p->attr.stringp); + } +} + +static boolean sdp_attr_is_simple_u32(sdp_attr_e attr_type) { + if ((attr_type != SDP_ATTR_EECID) && + (attr_type != SDP_ATTR_PTIME) && + (attr_type != SDP_ATTR_MAXPTIME) && + (attr_type != SDP_ATTR_SCTPPORT) && + (attr_type != SDP_ATTR_MAXMESSAGESIZE) && + (attr_type != SDP_ATTR_T38_VERSION) && + (attr_type != SDP_ATTR_T38_MAXBITRATE) && + (attr_type != SDP_ATTR_T38_MAXBUFFER) && + (attr_type != SDP_ATTR_T38_MAXDGRAM) && + (attr_type != SDP_ATTR_X_SQN) && + (attr_type != SDP_ATTR_TC1_PAYLOAD_BYTES) && + (attr_type != SDP_ATTR_TC1_WINDOW_SIZE) && + (attr_type != SDP_ATTR_TC2_PAYLOAD_BYTES) && + (attr_type != SDP_ATTR_TC2_WINDOW_SIZE) && + (attr_type != SDP_ATTR_FRAMERATE)) { + return FALSE; + } + + return TRUE; +} + +/* Function: sdp_attr_get_simple_u32 + * Description: Returns an unsigned 32-bit attribute parameter. This + * routine can only be called for attributes that have just + * one uint32_t parameter. If the given attribute is not defined, + * zero will be returned. There is no way for the application + * to determine if zero is the actual value or the attribute + * wasn't defined, so the application must use the + * sdp_attr_valid function to determine this. + * Attributes with a simple uint32_t parameter currently include: + * eecid, ptime, T38FaxVersion, T38maxBitRate, T38FaxMaxBuffer, + * T38FaxMaxDatagram, X-sqn, TC1PayloadBytes, TC1WindowSize, + * TC2PayloadBytes, TC2WindowSize, rtcp. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * attr_type The simple uint32_t attribute type. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * Returns: uint32_t parameter value. + */ +uint32_t sdp_attr_get_simple_u32 (sdp_t *sdp_p, sdp_attr_e attr_type, uint16_t level, + uint8_t cap_num, uint16_t inst_num) +{ + sdp_attr_t *attr_p; + + if (!sdp_attr_is_simple_u32(attr_type)) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s Attribute type is not a simple uint32_t (%s)", + sdp_p->debug_str, sdp_get_attr_name(attr_type)); + } + sdp_p->conf_p->num_invalid_param++; + return (0); + } + + attr_p = sdp_find_attr(sdp_p, level, cap_num, attr_type, inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s Attribute %s, level %u instance %u not found.", + sdp_p->debug_str, sdp_get_attr_name(attr_type), + (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (0); + } else { + return (attr_p->attr.u32_val); + } +} + +/* Function: sdp_attr_get_simple_boolean + * Description: Returns a boolean attribute parameter. This + * routine can only be called for attributes that have just + * one boolean parameter. If the given attribute is not defined, + * FALSE will be returned. There is no way for the application + * to determine if FALSE is the actual value or the attribute + * wasn't defined, so the application must use the + * sdp_attr_valid function to determine this. + * Attributes with a simple boolean parameter currently include: + * T38FaxFillBitRemoval, T38FaxTranscodingMMR, + * T38FaxTranscodingJBIG, and TMRGwXid. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * attr_type The simple boolean attribute type. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * Returns: Boolean value. + */ +tinybool sdp_attr_get_simple_boolean (sdp_t *sdp_p, sdp_attr_e attr_type, + uint16_t level, uint8_t cap_num, uint16_t inst_num) +{ + sdp_attr_t *attr_p; + + if ((attr_type != SDP_ATTR_T38_FILLBITREMOVAL) && + (attr_type != SDP_ATTR_T38_TRANSCODINGMMR) && + (attr_type != SDP_ATTR_T38_TRANSCODINGJBIG) && + (attr_type != SDP_ATTR_TMRGWXID)) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s Attribute type is not a simple boolean (%s)", + sdp_p->debug_str, sdp_get_attr_name(attr_type)); + } + sdp_p->conf_p->num_invalid_param++; + return (FALSE); + } + + attr_p = sdp_find_attr(sdp_p, level, cap_num, attr_type, inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s Attribute %s, level %u instance %u not found.", + sdp_p->debug_str, sdp_get_attr_name(attr_type), + (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (FALSE); + } else { + return (attr_p->attr.boolean_val); + } +} + +/* + * sdp_attr_get_maxprate + * + * This function is used by the application layer to get the packet-rate + * within the maxprate attribute. + * + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * inst_num The attribute instance number to set. + * + * Returns a pointer to a constant char array that stores the packet-rate, + * OR null if the attribute does not exist. + */ +const char* +sdp_attr_get_maxprate (sdp_t *sdp_p, uint16_t level, uint16_t inst_num) +{ + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, 0, SDP_ATTR_MAXPRATE, inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s Attribute %s, level %u instance %u not found.", + sdp_p->debug_str, sdp_get_attr_name(SDP_ATTR_MAXPRATE), + (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (NULL); + } else { + return (attr_p->attr.string_val); + } +} + +/* Function: sdp_attr_get_t38ratemgmt + * Description: Returns the value of the t38ratemgmt attribute + * parameter specified for the given attribute. If the given + * attribute is not defined, SDP_T38_UNKNOWN_RATE is returned. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * Returns: Ratemgmt value. + */ +sdp_t38_ratemgmt_e sdp_attr_get_t38ratemgmt (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num) +{ + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, + SDP_ATTR_T38_RATEMGMT, inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s t38ratemgmt attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (SDP_T38_UNKNOWN_RATE); + } else { + return (attr_p->attr.t38ratemgmt); + } +} + +/* Function: sdp_attr_get_t38udpec + * Description: Returns the value of the t38udpec attribute + * parameter specified for the given attribute. If the given + * attribute is not defined, SDP_T38_UDPEC_UNKNOWN is returned. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * Returns: UDP EC value. + */ +sdp_t38_udpec_e sdp_attr_get_t38udpec (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num) +{ + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, + SDP_ATTR_T38_UDPEC, inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s t38udpec attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (SDP_T38_UDPEC_UNKNOWN); + } else { + return (attr_p->attr.t38udpec); + } +} + +/* Function: sdp_get_media_direction + * Description: Determines the direction defined for a given level. The + * direction will be inactive, sendonly, recvonly, or sendrecv + * as determined by the last of these attributes specified at + * the given level. If none of these attributes are specified, + * the direction will be sendrecv by default. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * Returns: An SDP direction enum value. + */ +sdp_direction_e sdp_get_media_direction (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num) +{ + sdp_mca_t *mca_p; + sdp_attr_t *attr_p; + sdp_direction_e direction = SDP_DIRECTION_SENDRECV; + + if (cap_num == 0) { + /* Find the pointer to the attr list for this level. */ + if (level == SDP_SESSION_LEVEL) { + attr_p = sdp_p->sess_attrs_p; + } else { /* Attr is at a media level */ + mca_p = sdp_find_media_level(sdp_p, level); + if (mca_p == NULL) { + return (direction); + } + attr_p = mca_p->media_attrs_p; + } + + /* Scan for direction oriented attributes. Last one wins. */ + for (; attr_p != NULL; attr_p = attr_p->next_p) { + if (attr_p->type == SDP_ATTR_INACTIVE) { + direction = SDP_DIRECTION_INACTIVE; + } else if (attr_p->type == SDP_ATTR_SENDONLY) { + direction = SDP_DIRECTION_SENDONLY; + } else if (attr_p->type == SDP_ATTR_RECVONLY) { + direction = SDP_DIRECTION_RECVONLY; + } else if (attr_p->type == SDP_ATTR_SENDRECV) { + direction = SDP_DIRECTION_SENDRECV; + } + } + } else { + if (sdp_p->debug_flag[SDP_DEBUG_WARNINGS]) { + SDPLogDebug(logTag, "%s Warning: Invalid cap_num for media direction.", + sdp_p->debug_str); + } + } + + return (direction); +} + +/* Since there are four different attribute names which all have the same + * qos parameters, all of these attributes are accessed through this same + * set of APIs. To distinguish between specific attributes, the application + * must also pass the attribute type. The attribute must be one of: + * SDP_ATTR_QOS, SDP_ATTR_SECURE, SDP_ATTR_X_PC_QOS, and SDP_ATTR_X_QOS. + */ +tinybool sdp_validate_qos_attr (sdp_attr_e qos_attr) +{ + if ((qos_attr == SDP_ATTR_QOS) || + (qos_attr == SDP_ATTR_SECURE) || + (qos_attr == SDP_ATTR_X_PC_QOS) || + (qos_attr == SDP_ATTR_X_QOS) || + (qos_attr == SDP_ATTR_CURR) || + (qos_attr == SDP_ATTR_DES) || + (qos_attr == SDP_ATTR_CONF)){ + return (TRUE); + } else { + return (FALSE); + } +} + +/* Function: sdp_attr_get_qos_strength + * Description: Returns the value of the qos attribute strength + * parameter specified for the given attribute. If the given + * attribute is not defined, SDP_QOS_STRENGTH_UNKNOWN is + * returned. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * qos_attr The specific type of qos attribute. May be + * qos, secure, X-pc-qos, or X-qos. + * inst_num The attribute instance number to check. + * Returns: Qos strength value. + */ +sdp_qos_strength_e sdp_attr_get_qos_strength (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, sdp_attr_e qos_attr, uint16_t inst_num) +{ + sdp_attr_t *attr_p; + + if (sdp_validate_qos_attr(qos_attr) == FALSE) { + if (sdp_p->debug_flag[SDP_DEBUG_WARNINGS]) { + SDPLogDebug(logTag, "%s Warning: Invalid QOS attribute specified for" + "get qos strength.", sdp_p->debug_str); + } + return (SDP_QOS_STRENGTH_UNKNOWN); + } + attr_p = sdp_find_attr(sdp_p, level, cap_num, qos_attr, inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s %s attribute, level %u instance %u " + "not found.", sdp_p->debug_str, + sdp_get_attr_name(qos_attr), (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (SDP_QOS_STRENGTH_UNKNOWN); + } else { + switch (qos_attr) { + case SDP_ATTR_QOS: + return (attr_p->attr.qos.strength); + case SDP_ATTR_DES: + return (attr_p->attr.des.strength); + default: + return SDP_QOS_STRENGTH_UNKNOWN; + + } + } +} + +/* Function: sdp_attr_get_qos_direction + * Description: Returns the value of the qos attribute direction + * parameter specified for the given attribute. If the given + * attribute is not defined, SDP_QOS_DIR_UNKNOWN is + * returned. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * qos_attr The specific type of qos attribute. May be + * qos, secure, X-pc-qos, or X-qos. + * inst_num The attribute instance number to check. + * Returns: Qos direction value. + */ +sdp_qos_dir_e sdp_attr_get_qos_direction (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, sdp_attr_e qos_attr, uint16_t inst_num) +{ + sdp_attr_t *attr_p; + + if (sdp_validate_qos_attr(qos_attr) == FALSE) { + if (sdp_p->debug_flag[SDP_DEBUG_WARNINGS]) { + SDPLogDebug(logTag, "%s Warning: Invalid QOS attribute specified " + "for get qos direction.", sdp_p->debug_str); + } + return (SDP_QOS_DIR_UNKNOWN); + } + attr_p = sdp_find_attr(sdp_p, level, cap_num, qos_attr, inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s %s attribute, level %u instance %u " + "not found.", sdp_p->debug_str, + sdp_get_attr_name(qos_attr), (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (SDP_QOS_DIR_UNKNOWN); + } else { + switch (qos_attr) { + case SDP_ATTR_QOS: + return (attr_p->attr.qos.direction); + case SDP_ATTR_CURR: + return (attr_p->attr.curr.direction); + case SDP_ATTR_DES: + return (attr_p->attr.des.direction); + case SDP_ATTR_CONF: + return (attr_p->attr.conf.direction); + default: + return SDP_QOS_DIR_UNKNOWN; + + } + } +} + +/* Function: sdp_attr_get_qos_status_type + * Description: Returns the value of the qos attribute status_type + * parameter specified for the given attribute. If the given + * attribute is not defined, SDP_QOS_STATUS_TYPE_UNKNOWN is + * returned. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * qos_attr The specific type of qos attribute. May be + * qos, secure, X-pc-qos, or X-qos. + * inst_num The attribute instance number to check. + * Returns: Qos direction value. + */ +sdp_qos_status_types_e sdp_attr_get_qos_status_type (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, sdp_attr_e qos_attr, uint16_t inst_num) +{ + sdp_attr_t *attr_p; + + if (sdp_validate_qos_attr(qos_attr) == FALSE) { + if (sdp_p->debug_flag[SDP_DEBUG_WARNINGS]) { + SDPLogDebug(logTag, "%s Warning: Invalid QOS attribute specified " + "for get qos status_type.", sdp_p->debug_str); + } + return (SDP_QOS_STATUS_TYPE_UNKNOWN); + } + attr_p = sdp_find_attr(sdp_p, level, cap_num, qos_attr, inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s %s attribute, level %u instance %u " + "not found.", sdp_p->debug_str, + sdp_get_attr_name(qos_attr), (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (SDP_QOS_STATUS_TYPE_UNKNOWN); + } else { + switch (qos_attr) { + case SDP_ATTR_CURR: + return (attr_p->attr.curr.status_type); + case SDP_ATTR_DES: + return (attr_p->attr.des.status_type); + case SDP_ATTR_CONF: + return (attr_p->attr.conf.status_type); + default: + return SDP_QOS_STATUS_TYPE_UNKNOWN; + + } + } +} + +/* Function: sdp_attr_get_qos_confirm + * Description: Returns the value of the qos attribute confirm + * parameter specified for the given attribute. Returns TRUE if + * the confirm parameter is specified. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * qos_attr The specific type of qos attribute. May be + * qos, secure, X-pc-qos, or X-qos. + * inst_num The attribute instance number to check. + * Returns: Boolean value. + */ +tinybool sdp_attr_get_qos_confirm (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, sdp_attr_e qos_attr, uint16_t inst_num) +{ + sdp_attr_t *attr_p; + + if (sdp_validate_qos_attr(qos_attr) == FALSE) { + if (sdp_p->debug_flag[SDP_DEBUG_WARNINGS]) { + SDPLogDebug(logTag, "%s Warning: Invalid QOS attribute specified " + "for get qos confirm.", sdp_p->debug_str); + } + return (FALSE); + } + attr_p = sdp_find_attr(sdp_p, level, cap_num, qos_attr, inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s %s attribute, level %u instance %u " + "not found.", sdp_p->debug_str, + sdp_get_attr_name(qos_attr), (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (FALSE); + } else { + return (attr_p->attr.qos.confirm); + } +} + +/* Function: sdp_attr_get_curr_type + * Description: Returns the value of the curr attribute status_type + * parameter specified for the given attribute. If the given + * attribute is not defined, SDP_CURR_UNKNOWN_TYPE is + * returned. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * qos_attr The specific type of qos attribute. May be + * qos, secure, X-pc-qos, or X-qos. + * inst_num The attribute instance number to check. + * Returns: Curr type value. + */ +sdp_curr_type_e sdp_attr_get_curr_type (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, sdp_attr_e qos_attr, uint16_t inst_num) +{ + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, qos_attr, inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s %s attribute, level %u instance %u " + "not found.", sdp_p->debug_str, + sdp_get_attr_name(qos_attr), (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (SDP_CURR_UNKNOWN_TYPE); + } else { + return (attr_p->attr.curr.type); + } +} + +/* Function: sdp_attr_get_des_type + * Description: Returns the value of the des attribute status_type + * parameter specified for the given attribute. If the given + * attribute is not defined, SDP_DES_UNKNOWN_TYPE is + * returned. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * qos_attr The specific type of qos attribute. May be + * qos, secure, X-pc-qos, or X-qos. + * inst_num The attribute instance number to check. + * Returns: DES type value. + */ +sdp_des_type_e sdp_attr_get_des_type (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, sdp_attr_e qos_attr, uint16_t inst_num) +{ + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, qos_attr, inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s %s attribute, level %u instance %u " + "not found.", sdp_p->debug_str, + sdp_get_attr_name(qos_attr), (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (SDP_DES_UNKNOWN_TYPE); + } else { + return (attr_p->attr.des.type); + } +} + +/* Function: sdp_attr_get_conf_type + * Description: Returns the value of the des attribute status_type + * parameter specified for the given attribute. If the given + * attribute is not defined, SDP_CONF_UNKNOWN_TYPE is + * returned. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * qos_attr The specific type of qos attribute. May be + * qos, secure, X-pc-qos, or X-qos. + * inst_num The attribute instance number to check. + * Returns: CONF type value. + */ +sdp_conf_type_e sdp_attr_get_conf_type (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, sdp_attr_e qos_attr, uint16_t inst_num) +{ + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, qos_attr, inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s %s attribute, level %u instance %u " + "not found.", sdp_p->debug_str, + sdp_get_attr_name(qos_attr), (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (SDP_CONF_UNKNOWN_TYPE); + } else { + return (attr_p->attr.conf.type); + } +} + +/* Function: sdp_attr_get_subnet_nettype + * Description: Returns the value of the subnet attribute network type + * parameter specified for the given attribute. If the given + * attribute is not defined, SDP_NT_INVALID is returned. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * Returns: Nettype value. + */ +sdp_nettype_e sdp_attr_get_subnet_nettype (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num) +{ + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, + SDP_ATTR_SUBNET, inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s Subnet attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (SDP_NT_INVALID); + } else { + return (attr_p->attr.subnet.nettype); + } +} + +/* Function: sdp_attr_get_subnet_addrtype + * Description: Returns the value of the subnet attribute address type + * parameter specified for the given attribute. If the given + * attribute is not defined, SDP_AT_INVALID is returned. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * Returns: Addrtype value. + */ +sdp_addrtype_e sdp_attr_get_subnet_addrtype (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num) +{ + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, + SDP_ATTR_SUBNET, inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s Subnet attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (SDP_AT_INVALID); + } else { + return (attr_p->attr.subnet.addrtype); + } +} + +/* Function: sdp_attr_get_subnet_addr + * Description: Returns the value of the subnet attribute address + * parameter specified for the given attribute. If the given + * attribute is not defined, NULL is returned. Value is + * returned as a const ptr and so cannot be modified by the + * application. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * Returns: Pointer to address or NULL. + */ +const char *sdp_attr_get_subnet_addr (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num) +{ + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, + SDP_ATTR_SUBNET, inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s Subnet attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (NULL); + } else { + return (attr_p->attr.subnet.addr); + } +} + +/* Function: sdp_attr_get_subnet_prefix + * Description: Returns the value of the subnet attribute prefix + * parameter specified for the given attribute. If the given + * attribute is not defined, SDP_INVALID_PARAM is returned. + * Note that this is value is defined to be (-2) and is + * different from the return code SDP_INVALID_PARAMETER. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * Returns: Prefix value or SDP_INVALID_PARAM. + */ +int32_t sdp_attr_get_subnet_prefix (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num) +{ + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, + SDP_ATTR_SUBNET, inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s Subnet attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_VALUE); + } else { + return (attr_p->attr.subnet.prefix); + } +} + +/* Function: sdp_attr_rtpmap_payload_valid + * Description: Returns true or false depending on whether an rtpmap + * attribute was specified with the given payload value + * at the given level. If it was, the instance number of + * that attribute is returned. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number of the attribute + * found is returned via this param. + * Returns: TRUE or FALSE. + */ +tinybool sdp_attr_rtpmap_payload_valid (sdp_t *sdp_p, uint16_t level, uint8_t cap_num, + uint16_t *inst_num, uint16_t payload_type) +{ + uint16_t i; + sdp_attr_t *attr_p; + uint16_t num_instances; + + *inst_num = 0; + + if (sdp_attr_num_instances(sdp_p, level, cap_num, + SDP_ATTR_RTPMAP, &num_instances) != SDP_SUCCESS) { + return (FALSE); + } + + for (i=1; i <= num_instances; i++) { + attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_RTPMAP, i); + if ((attr_p != NULL) && + (attr_p->attr.transport_map.payload_num == payload_type)) { + *inst_num = i; + return (TRUE); + } + } + + return (FALSE); +} + +/* Function: sdp_attr_get_rtpmap_payload_type + * Description: Returns the value of the rtpmap attribute payload type + * parameter specified for the given attribute. If the given + * attribute is not defined, zero is returned. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * Returns: Payload type value. + */ +uint16_t sdp_attr_get_rtpmap_payload_type (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num) +{ + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_RTPMAP, inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s rtpmap attribute, level %u instance %u " + "not found.", + sdp_p->debug_str, + (unsigned)level, + (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (0); + } else { + return (attr_p->attr.transport_map.payload_num); + } +} + +/* Function: sdp_attr_get_rtpmap_encname + * Description: Returns a pointer to the value of the encoding name + * parameter specified for the given attribute. Value is + * returned as a const ptr and so cannot be modified by the + * application. If the given attribute is not defined, NULL + * will be returned. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * Returns: Codec value or SDP_CODEC_INVALID. + */ +const char *sdp_attr_get_rtpmap_encname (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num) +{ + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_RTPMAP, inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s rtpmap attribute, level %u instance %u " + "not found.", + sdp_p->debug_str, + (unsigned)level, + (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (NULL); + } else { + return (attr_p->attr.transport_map.encname); + } +} + +/* Function: sdp_attr_get_rtpmap_clockrate + * Description: Returns the value of the rtpmap attribute clockrate + * parameter specified for the given attribute. If the given + * attribute is not defined, zero is returned. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * Returns: Clockrate value. + */ +uint32_t sdp_attr_get_rtpmap_clockrate (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num) +{ + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_RTPMAP, inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s rtpmap attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (0); + } else { + return (attr_p->attr.transport_map.clockrate); + } +} + +/* Function: sdp_attr_get_rtpmap_num_chan + * Description: Returns the value of the rtpmap attribute num_chan + * parameter specified for the given attribute. If the given + * attribute is not defined, zero is returned. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * Returns: Number of channels param or zero. + */ +uint16_t sdp_attr_get_rtpmap_num_chan (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num) +{ + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_RTPMAP, inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s rtpmap attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (0); + } else { + return (attr_p->attr.transport_map.num_chan); + } +} + +/* Function: sdp_attr_get_ice_attribute + * Description: Returns the value of an ice attribute at a given level + * + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * ice_attrib Returns an ice attrib string + * Returns: + * SDP_SUCCESS Attribute param was set successfully. + * SDP_INVALID_SDP_PTR SDP pointer invalid + * SDP_INVALID_PARAMETER Specified attribute is not defined. + */ + +sdp_result_e sdp_attr_get_ice_attribute (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, sdp_attr_e sdp_attr, uint16_t inst_num, + char **out) +{ + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, sdp_attr, inst_num); + if (attr_p != NULL) { + *out = attr_p->attr.ice_attr; + return (SDP_SUCCESS); + } else { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s ice attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_PARAMETER); + } +} + +/* Function: sdp_attr_is_present + * Description: Returns a boolean value based on attribute being present or + * not + * + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * attr_type The attribute type. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * Returns: + * Boolean value. + */ + +tinybool sdp_attr_is_present (sdp_t *sdp_p, sdp_attr_e attr_type, uint16_t level, + uint8_t cap_num) +{ + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, attr_type, 1); + if (attr_p != NULL) { + return (TRUE); + } + if (sdp_p->debug_flag[SDP_DEBUG_WARNINGS]) { + SDPLogDebug(logTag, "%s Attribute %s, level %u not found.", + sdp_p->debug_str, sdp_get_attr_name(attr_type), level); + } + + return (FALSE); +} + + + +/* Function: sdp_attr_get_rtcp_mux_attribute + * Description: Returns the value of an rtcp-mux attribute at a given level + * + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * rtcp_mux Returns an rtcp-mux attrib bool + * Returns: + * SDP_SUCCESS Attribute param was set successfully. + * SDP_INVALID_SDP_PTR SDP pointer invalid + * SDP_INVALID_PARAMETER Specified attribute is not defined. + */ +sdp_result_e sdp_attr_get_rtcp_mux_attribute (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, sdp_attr_e sdp_attr, uint16_t inst_num, + tinybool *rtcp_mux) +{ + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, sdp_attr, inst_num); + if (attr_p != NULL) { + *rtcp_mux = attr_p->attr.boolean_val; + return (SDP_SUCCESS); + } else { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s rtcp-mux attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_PARAMETER); + } +} + +/* Function: sdp_attr_get_setup_attribute + * Description: Returns the value of a setup attribute at a given level + * + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * setup_type Returns sdp_setup_type_e enum + * Returns: + * SDP_SUCCESS Attribute param was set successfully. + * SDP_INVALID_SDP_PTR SDP pointer invalid + * SDP_INVALID_PARAMETER Specified attribute is not defined. + */ +sdp_result_e sdp_attr_get_setup_attribute (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num, sdp_setup_type_e *setup_type) +{ + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_SETUP, inst_num); + if (!attr_p) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, + "%s setup attribute, level %u instance %u not found.", + sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return SDP_INVALID_PARAMETER; + } + + *setup_type = attr_p->attr.setup; + return SDP_SUCCESS; +} + +/* Function: sdp_attr_get_connection_attribute + * Description: Returns the value of a connection attribute at a given level + * + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * connection_type Returns sdp_connection_type_e enum + * Returns: + * SDP_SUCCESS Attribute param was set successfully. + * SDP_INVALID_SDP_PTR SDP pointer invalid + * SDP_INVALID_PARAMETER Specified attribute is not defined. + */ +sdp_result_e sdp_attr_get_connection_attribute (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num, sdp_connection_type_e *connection_type) +{ + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_CONNECTION, + inst_num); + if (!attr_p) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, + "%s setup attribute, level %u instance %u not found.", + sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return SDP_INVALID_PARAMETER; + } + + *connection_type = attr_p->attr.connection; + return SDP_SUCCESS; +} + +/* Function: sdp_attr_get_dtls_fingerprint_attribute + * Description: Returns the value of dtls fingerprint attribute at a given level + * + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * dtls_fingerprint Returns an dtls fingerprint attrib string + * Returns: + * SDP_SUCCESS Attribute param was set successfully. + * SDP_INVALID_SDP_PTR SDP pointer invalid + * SDP_INVALID_PARAMETER Specified attribute is not defined. + */ +sdp_result_e sdp_attr_get_dtls_fingerprint_attribute (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, sdp_attr_e sdp_attr, uint16_t inst_num, + char **out) +{ + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, sdp_attr, inst_num); + if (attr_p != NULL) { + *out = attr_p->attr.string_val; + return (SDP_SUCCESS); + } else { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s dtls fingerprint attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_PARAMETER); + } +} + +/* Function: sdp_attr_sprtmap_payload_valid + * Description: Returns true or false depending on whether an sprtmap + * attribute was specified with the given payload value + * at the given level. If it was, the instance number of + * that attribute is returned. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number of the attribute + * found is returned via this param. + * Returns: TRUE or FALSE. + */ +tinybool sdp_attr_sprtmap_payload_valid (sdp_t *sdp_p, uint16_t level, uint8_t cap_num, + uint16_t *inst_num, uint16_t payload_type) +{ + uint16_t i; + sdp_attr_t *attr_p; + uint16_t num_instances; + + *inst_num = 0; + + if (sdp_attr_num_instances(sdp_p, level, cap_num, + SDP_ATTR_SPRTMAP, &num_instances) != SDP_SUCCESS) { + return (FALSE); + } + + for (i=1; i <= num_instances; i++) { + attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_SPRTMAP, i); + if ((attr_p != NULL) && + (attr_p->attr.transport_map.payload_num == payload_type)) { + *inst_num = i; + return (TRUE); + } + } + + return (FALSE); +} + +/* Function: sdp_attr_get_sprtmap_payload_type + * Description: Returns the value of the sprtmap attribute payload type + * parameter specified for the given attribute. If the given + * attribute is not defined, zero is returned. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * Returns: Payload type value. + */ +uint16_t sdp_attr_get_sprtmap_payload_type (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num) +{ + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_SPRTMAP, inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s sprtmap attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (0); + } else { + return (attr_p->attr.transport_map.payload_num); + } +} + +/* Function: sdp_attr_get_sprtmap_encname + * Description: Returns a pointer to the value of the encoding name + * parameter specified for the given attribute. Value is + * returned as a const ptr and so cannot be modified by the + * application. If the given attribute is not defined, NULL + * will be returned. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * Returns: Codec value or SDP_CODEC_INVALID. + */ +const char *sdp_attr_get_sprtmap_encname (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num) +{ + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_SPRTMAP, inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s sprtmap attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (NULL); + } else { + return (attr_p->attr.transport_map.encname); + } +} + +/* Function: sdp_attr_get_sprtmap_clockrate + * Description: Returns the value of the sprtmap attribute clockrate + * parameter specified for the given attribute. If the given + * attribute is not defined, zero is returned. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * Returns: Clockrate value. + */ +uint32_t sdp_attr_get_sprtmap_clockrate (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num) +{ + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_SPRTMAP, inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s sprtmap attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (0); + } else { + return (attr_p->attr.transport_map.clockrate); + } +} + +/* Function: sdp_attr_get_sprtmap_num_chan + * Description: Returns the value of the sprtmap attribute num_chan + * parameter specified for the given attribute. If the given + * attribute is not defined, zero is returned. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * Returns: Number of channels param or zero. + */ +uint16_t sdp_attr_get_sprtmap_num_chan (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num) +{ + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_SPRTMAP, inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s sprtmap attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (0); + } else { + return (attr_p->attr.transport_map.num_chan); + } +} + +/* Note: The fmtp attribute formats currently handled are: + * fmtp:<payload type> <event>,<event>... + * fmtp:<payload_type> [annexa=yes/no] [annexb=yes/no] [bitrate=<value>] + * where "value" is a numeric value > 0 + * where each event is a single number or a range separated + * by a '-'. + * Example: fmtp:101 1,3-15,20 + */ + +/* Function: tinybool sdp_attr_fmtp_valid(sdp_t *sdp_p) + * Description: Returns true or false depending on whether an fmtp + * attribute was specified with the given payload value + * at the given level. If it was, the instance number of + * that attribute is returned. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * Returns: TRUE or FALSE. + */ +tinybool sdp_attr_fmtp_payload_valid (sdp_t *sdp_p, uint16_t level, uint8_t cap_num, + uint16_t *inst_num, uint16_t payload_type) +{ + uint16_t i; + sdp_attr_t *attr_p; + uint16_t num_instances; + + if (sdp_attr_num_instances(sdp_p, level, cap_num, + SDP_ATTR_FMTP, &num_instances) != SDP_SUCCESS) { + return (FALSE); + } + + for (i=1; i <= num_instances; i++) { + attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, i); + if ((attr_p != NULL) && + (attr_p->attr.fmtp.payload_num == payload_type)) { + *inst_num = i; + return (TRUE); + } + } + + return (FALSE); +} + +/* Function: sdp_attr_get_fmtp_payload_type + * Description: Returns the value of the fmtp attribute payload type + * parameter specified for the given attribute. If the given + * attribute is not defined, zero is returned. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * Returns: Payload type value. + */ +uint16_t sdp_attr_get_fmtp_payload_type (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num) +{ + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s fmtp attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (0); + } else { + return (attr_p->attr.fmtp.payload_num); + } +} + + +/* Function: sdp_attr_fmtp_is_range_set + * Description: Determines if a range of events is set in an fmtp attribute. + * The overall range for events is 0-255. + * This will return either FULL_MATCH, PARTIAL_MATCH, or NO_MATCH + * depending on whether all, some, or none of the specified + * events are defined. If the given attribute is not defined, + * NO_MATCH will be returned. It is up to the appl to verify + * the validity of the attribute before calling this routine. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * low_val Low value of the range. Range is 0-255. + * high_val High value of the range. + * Returns: SDP_FULL_MATCH, SDP_PARTIAL_MATCH, SDP_NO_MATCH + */ +sdp_ne_res_e sdp_attr_fmtp_is_range_set (sdp_t *sdp_p, uint16_t level, uint8_t cap_num, + uint16_t inst_num, uint8_t low_val, uint8_t high_val) +{ + uint16_t i; + uint32_t mapword; + uint32_t bmap; + uint32_t num_vals = 0; + uint32_t num_vals_set = 0; + sdp_attr_t *attr_p; + sdp_fmtp_t *fmtp_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s fmtp attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (SDP_NO_MATCH); + } + + fmtp_p = &(attr_p->attr.fmtp); + for (i = low_val; i <= high_val; i++) { + num_vals++; + mapword = i/SDP_NE_BITS_PER_WORD; + bmap = SDP_NE_BIT_0 << (i%32); + if (fmtp_p->bmap[ mapword ] & bmap) { + num_vals_set++; + } + } + + if (num_vals == num_vals_set) { + return (SDP_FULL_MATCH); + } else if (num_vals_set == 0) { + return (SDP_NO_MATCH); + } else { + return (SDP_PARTIAL_MATCH); + } +} + +/* Function: sdp_attr_fmtp_valid + * Description: Determines the validity of the events in the fmtp. + * The overall range for events is 0-255. + * The user passes an event list with valid events supported by Appl. + * This routine will do a simple AND comparison and report the result. + * + * This will return TRUE if ftmp events are valid, and FALSE otherwise. + * It is up to the appl to verify the validity of the attribute + * before calling this routine. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * appl_maxval Max event value supported by Appl. Range is 0-255. + * evt_array Bitmap containing events supported by application. + * Returns: TRUE, FALSE + */ +tinybool +sdp_attr_fmtp_valid(sdp_t *sdp_p, uint16_t level, uint8_t cap_num, + uint16_t inst_num, uint16_t appl_maxval, uint32_t* evt_array) +{ + uint16_t i; + uint32_t mapword; + sdp_attr_t *attr_p; + sdp_fmtp_t *fmtp_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s fmtp attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return FALSE; + } + + fmtp_p = &(attr_p->attr.fmtp); + + /* Do quick test. If application max value is lower than fmtp's then error */ + if (fmtp_p->maxval > appl_maxval) + return FALSE; + + /* Ok, events are within range. Now check that only + * allowed events have been received + */ + mapword = appl_maxval/SDP_NE_BITS_PER_WORD; + for (i=0; i<mapword; i++) { + if (fmtp_p->bmap[i] & ~(evt_array[i])) { + /* Remote SDP is requesting events not supported by Application */ + return FALSE; + } + } + return TRUE; +} + +/* Function: sdp_attr_set_fmtp_payload_type + * Description: Sets the value of the fmtp attribute payload type parameter + * for the given attribute. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * payload_type New payload type value. + * Returns: SDP_SUCCESS Attribute param was set successfully. + * SDP_INVALID_PARAMETER Specified attribute is not defined. + */ +sdp_result_e sdp_attr_set_fmtp_payload_type (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num, + uint16_t payload_num) +{ + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s fmtp attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_PARAMETER); + } else { + attr_p->attr.fmtp.payload_num = payload_num; + return (SDP_SUCCESS); + } +} + +/* Function: sdp_attr_get_fmtp_range + * Description: Get a range of named events for an fmtp attribute. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * bmap The 8 word data array holding the bitmap + * Returns: SDP_SUCCESS + */ +sdp_result_e sdp_attr_get_fmtp_range (sdp_t *sdp_p, uint16_t level, uint8_t cap_num, + uint16_t inst_num, uint32_t *bmap) +{ + sdp_attr_t *attr_p; + sdp_fmtp_t *fmtp_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s fmtp attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_PARAMETER); + } + + fmtp_p = &(attr_p->attr.fmtp); + memcpy(bmap, fmtp_p->bmap, SDP_NE_NUM_BMAP_WORDS * sizeof(uint32_t) ); + + return (SDP_SUCCESS); +} + +/* Function: sdp_attr_clear_fmtp_range + * Description: Clear a range of named events for an fmtp attribute. The low + * value specified must be <= the high value. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * low_val The low value of the range. Range is 0-255 + * high_val The high value of the range. May be == low. + * Returns: SDP_SUCCESS + */ +sdp_result_e sdp_attr_clear_fmtp_range (sdp_t *sdp_p, uint16_t level, uint8_t cap_num, + uint16_t inst_num, uint8_t low_val, uint8_t high_val) +{ + uint16_t i; + uint32_t mapword; + uint32_t bmap; + sdp_attr_t *attr_p; + sdp_fmtp_t *fmtp_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s fmtp attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_PARAMETER); + } + + fmtp_p = &(attr_p->attr.fmtp); + for (i = low_val; i <= high_val; i++) { + mapword = i/SDP_NE_BITS_PER_WORD; + bmap = SDP_NE_BIT_0 << (i%32); + fmtp_p->bmap[ mapword ] &= ~bmap; + } + if (high_val > fmtp_p->maxval) { + fmtp_p->maxval = high_val; + } + return (SDP_SUCCESS); +} + +/* Function: sdp_attr_compare_fmtp_ranges + * Description: Compare the named events set of two fmtp attributes. If all + * events are the same (either set or not), FULL_MATCH will be + * returned. If no events match, NO_MATCH will be returned. + * Otherwise PARTIAL_MATCH will be returned. If either attr is + * invalid, NO_MATCH will be returned. + * Parameters: src_sdp_p The SDP handle returned by sdp_init_description. + * dst_sdp_p The SDP handle returned by sdp_init_description. + * src_level The level of the src fmtp attribute. + * dst_level The level to the dst fmtp attribute. + * src_cap_num The capability number of the src attr. + * dst_cap_num The capability number of the dst attr. + * src_inst_numh The attribute instance of the src attr. + * dst_inst_numh The attribute instance of the dst attr. + * Returns: SDP_FULL_MATCH, SDP_PARTIAL_MATCH, SDP_NO_MATCH. + */ +sdp_ne_res_e sdp_attr_compare_fmtp_ranges (sdp_t *src_sdp_p,sdp_t *dst_sdp_p, + uint16_t src_level, uint16_t dst_level, + uint8_t src_cap_num, uint8_t dst_cap_num, + uint16_t src_inst_num, uint16_t dst_inst_num) +{ + uint16_t i,j; + uint32_t bmap; + uint32_t num_vals_match = 0; + sdp_attr_t *src_attr_p; + sdp_attr_t *dst_attr_p; + sdp_fmtp_t *src_fmtp_p; + sdp_fmtp_t *dst_fmtp_p; + + src_attr_p = sdp_find_attr(src_sdp_p, src_level, src_cap_num, + SDP_ATTR_FMTP, src_inst_num); + dst_attr_p = sdp_find_attr(dst_sdp_p, dst_level, dst_cap_num, + SDP_ATTR_FMTP, dst_inst_num); + if ((src_attr_p == NULL) || (dst_attr_p == NULL)) { + if (src_sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s source or destination fmtp attribute for " + "compare not found.", src_sdp_p->debug_str); + } + src_sdp_p->conf_p->num_invalid_param++; + return (SDP_NO_MATCH); + } + + src_fmtp_p = &(src_attr_p->attr.fmtp); + dst_fmtp_p = &(dst_attr_p->attr.fmtp); + for (i = 0; i < SDP_NE_NUM_BMAP_WORDS; i++) { + for (j = 0; j < SDP_NE_BITS_PER_WORD; j++) { + bmap = SDP_NE_BIT_0 << j; + if ((src_fmtp_p->bmap[i] & bmap) && (dst_fmtp_p->bmap[i] & bmap)) { + num_vals_match++; + } else if ((!(src_fmtp_p->bmap[i] & bmap)) && + (!(dst_fmtp_p->bmap[i] & bmap))) { + num_vals_match++; + } + } + } + + if (num_vals_match == (SDP_NE_NUM_BMAP_WORDS * SDP_NE_BITS_PER_WORD)) { + return (SDP_FULL_MATCH); + } else if (num_vals_match == 0) { + return (SDP_NO_MATCH); + } else { + return (SDP_PARTIAL_MATCH); + } +} + +/* Function: sdp_attr_copy_fmtp_ranges + * Description: Copy the named events set for one fmtp attribute to another. + * Parameters: src_sdp_p The SDP handle returned by sdp_init_description. + * dst_sdp_p The SDP handle returned by sdp_init_description. + * src_level The level of the src fmtp attribute. + * dst_level The level to the dst fmtp attribute. + * src_cap_num The capability number of the src attr. + * dst_cap_num The capability number of the dst attr. + * src_inst_numh The attribute instance of the src attr. + * dst_inst_numh The attribute instance of the dst attr. + * Returns: SDP_SUCCESS + */ +sdp_result_e sdp_attr_copy_fmtp_ranges (sdp_t *src_sdp_p, sdp_t *dst_sdp_p, + uint16_t src_level, uint16_t dst_level, + uint8_t src_cap_num, uint8_t dst_cap_num, + uint16_t src_inst_num, uint16_t dst_inst_num) +{ + uint16_t i; + sdp_attr_t *src_attr_p; + sdp_attr_t *dst_attr_p; + sdp_fmtp_t *src_fmtp_p; + sdp_fmtp_t *dst_fmtp_p; + + if (!src_sdp_p || !dst_sdp_p) { + return (SDP_INVALID_SDP_PTR); + } + + src_attr_p = sdp_find_attr(src_sdp_p, src_level, src_cap_num, + SDP_ATTR_FMTP, src_inst_num); + dst_attr_p = sdp_find_attr(dst_sdp_p, dst_level, dst_cap_num, + SDP_ATTR_FMTP, dst_inst_num); + if ((src_attr_p == NULL) || (dst_attr_p == NULL)) { + if (src_sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s source or destination fmtp attribute for " + "copy not found.", src_sdp_p->debug_str); + } + src_sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_PARAMETER); + } + + src_fmtp_p = &(src_attr_p->attr.fmtp); + dst_fmtp_p = &(dst_attr_p->attr.fmtp); + dst_fmtp_p->maxval = src_fmtp_p->maxval; + for (i = 0; i < SDP_NE_NUM_BMAP_WORDS; i++) { + dst_fmtp_p->bmap[i] = src_fmtp_p->bmap[i]; + } + return (SDP_SUCCESS); +} + +/* Function: sdp_attr_get_fmtp_mode + * Description: Gets the value of the fmtp attribute mode parameter + * for the given attribute. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * payload_type payload type. + * Returns: mode value or zero if mode attribute not found + */ +uint32_t sdp_attr_get_fmtp_mode_for_payload_type (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint32_t payload_type) +{ + uint16_t num_a_lines = 0; + int i; + sdp_attr_t *attr_p; + + /* + * Get number of FMTP attributes for the AUDIO line + */ + (void) sdp_attr_num_instances(sdp_p, level, cap_num, SDP_ATTR_FMTP, + &num_a_lines); + for (i = 0; i < num_a_lines; i++) { + attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, (uint16_t) (i + 1)); + if ((attr_p != NULL) && + (attr_p->attr.fmtp.payload_num == (uint16_t)payload_type)) { + if (attr_p->attr.fmtp.fmtp_format == SDP_FMTP_MODE) { + return attr_p->attr.fmtp.mode; + } + } + } + return 0; +} + +sdp_result_e sdp_attr_set_fmtp_max_fs (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num, + uint32_t max_fs) +{ + sdp_attr_t *attr_p; + sdp_fmtp_t *fmtp_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s fmtp attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_PARAMETER); + } + + fmtp_p = &(attr_p->attr.fmtp); + fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO; + + if (max_fs > 0) { + fmtp_p->max_fs = max_fs; + return (SDP_SUCCESS); + } else { + return (SDP_FAILURE); + } +} + +sdp_result_e sdp_attr_set_fmtp_max_fr (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num, + uint32_t max_fr) +{ + sdp_attr_t *attr_p; + sdp_fmtp_t *fmtp_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s fmtp attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_PARAMETER); + } + + fmtp_p = &(attr_p->attr.fmtp); + fmtp_p->fmtp_format = SDP_FMTP_CODEC_INFO; + + if (max_fr > 0) { + fmtp_p->max_fr = max_fr; + return (SDP_SUCCESS); + } else { + return (SDP_FAILURE); + } +} + +/* Function: sdp_attr_get_fmtp_max_average_bitrate + * Description: Gets the value of the fmtp attribute- maxaveragebitrate parameter for the OPUS codec + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * Returns: max-br value. + */ + +sdp_result_e sdp_attr_get_fmtp_max_average_bitrate (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num, uint32_t* val) +{ + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, 1); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s fmtp attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_PARAMETER); + } else { + *val = attr_p->attr.fmtp.maxaveragebitrate; + return (SDP_SUCCESS); + } +} + + +/* Function: sdp_attr_get_fmtp_usedtx + * Description: Gets the value of the fmtp attribute- usedtx parameter for the OPUS codec + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * Returns: usedtx value. + */ + +sdp_result_e sdp_attr_get_fmtp_usedtx (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num, tinybool* val) +{ + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, + inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s fmtp attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_PARAMETER); + } else { + *val = (tinybool)attr_p->attr.fmtp.usedtx; + return (SDP_SUCCESS); + } +} + +/* Function: sdp_attr_get_fmtp_usedtx + * Description: Gets the value of the fmtp attribute- usedtx parameter for the OPUS codec + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * Returns: stereo value. + */ + +sdp_result_e sdp_attr_get_fmtp_stereo (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num, tinybool* val) +{ + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, + inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s fmtp attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_PARAMETER); + } else { + *val = (tinybool)attr_p->attr.fmtp.stereo; + return (SDP_SUCCESS); + } +} + +/* Function: sdp_attr_get_fmtp_useinbandfec + * Description: Gets the value of the fmtp attribute useinbandfec parameter for the OPUS codec + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * Returns: useinbandfec value. + */ + +sdp_result_e sdp_attr_get_fmtp_useinbandfec (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num, tinybool* val) +{ + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, + inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s fmtp attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_PARAMETER); + } else { + *val = (tinybool)attr_p->attr.fmtp.useinbandfec; + return (SDP_SUCCESS); + } +} + +/* Function: sdp_attr_get_fmtp_maxcodedaudiobandwidth + * Description: Gets the value of the fmtp attribute maxcodedaudiobandwidth parameter for OPUS codec + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * Returns: maxcodedaudiobandwidth value. + */ +char* sdp_attr_get_fmtp_maxcodedaudiobandwidth (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num) +{ + + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, + inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s fmtp attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (0); + } else { + return (attr_p->attr.fmtp.maxcodedaudiobandwidth); + } +} + +/* Function: sdp_attr_get_fmtp_cbr + * Description: Gets the value of the fmtp attribute cbr parameter for the OPUS codec + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * Returns: cbr value. + */ + +sdp_result_e sdp_attr_get_fmtp_cbr (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num, tinybool* val) +{ + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, + inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s fmtp attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_PARAMETER); + } else { + *val = (tinybool)attr_p->attr.fmtp.cbr; + return (SDP_SUCCESS); + } +} + +uint16_t sdp_attr_get_sctpmap_port(sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num) +{ + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_SCTPMAP, inst_num); + if (!attr_p) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s sctpmap port, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return 0; + } else { + return attr_p->attr.sctpmap.port; + } +} + +sdp_result_e sdp_attr_get_sctpmap_streams (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num, uint32_t* val) +{ + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_SCTPMAP, inst_num); + if (!attr_p) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s sctpmap streams, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_PARAMETER); + } else { + *val = attr_p->attr.sctpmap.streams; + return (SDP_SUCCESS); + } +} + +sdp_result_e sdp_attr_get_sctpmap_protocol (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num, + char* protocol) +{ + + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_SCTPMAP, + inst_num); + if (!attr_p) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s sctpmap, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_PARAMETER); + } else { + sstrncpy(protocol, attr_p->attr.sctpmap.protocol, SDP_MAX_STRING_LEN+1); + } + return (SDP_SUCCESS); +} + +/* Function: sdp_attr_fmtp_is_annexb_set + * Description: Gives the value of the fmtp attribute annexb type parameter + * for the given attribute. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * + * + * Returns: TRUE or FALSE. + */ +tinybool sdp_attr_fmtp_is_annexb_set (sdp_t *sdp_p, uint16_t level, uint8_t cap_num, + uint16_t inst_num) +{ + + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, + inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s fmtp attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (FALSE); + } else { + return (attr_p->attr.fmtp.annexb); + } +} + +/* Function: sdp_attr_fmtp_is_annexa_set + * Description: Gives the value of the fmtp attribute annexa type parameter + * for the given attribute. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * + * + * Returns: TRUE or FALSE. + */ +tinybool sdp_attr_fmtp_is_annexa_set (sdp_t *sdp_p, uint16_t level, uint8_t cap_num, + uint16_t inst_num) +{ + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, + inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s fmtp attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (FALSE); + } else { + return (attr_p->attr.fmtp.annexa); + } +} + +/* Function: sdp_attr_get_fmtp_bitrate_type + * Description: Gets the value of the fmtp attribute bitrate type parameter + * for the given attribute. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * Returns: Bitrate type value. + */ +int32_t sdp_attr_get_fmtp_bitrate_type (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num) +{ + + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, + inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s fmtp attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_VALUE); + } else { + return (attr_p->attr.fmtp.bitrate); + } +} + +/* Function: sdp_attr_get_fmtp_qcif + * Description: Gets the value of the fmtp attribute QCIF type parameter + * for a given Video codec. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * Returns: QCIF value. + */ +int32_t sdp_attr_get_fmtp_qcif (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num) +{ + + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, + inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s fmtp attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_VALUE); + } else { + return (attr_p->attr.fmtp.qcif); + } +} +/* Function: sdp_attr_get_fmtp_cif + * Description: Gets the value of the fmtp attribute CIF type parameter + * for a given Video codec. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * Returns: CIF value. + */ +int32_t sdp_attr_get_fmtp_cif (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num) +{ + + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, + inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s fmtp attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_VALUE); + } else { + return (attr_p->attr.fmtp.cif); + } +} + + +/* Function: sdp_attr_get_fmtp_sqcif + * Description: Gets the value of the fmtp attribute sqcif type parameter + * for a given Video codec. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * Returns: sqcif value. + */ +int32_t sdp_attr_get_fmtp_sqcif (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num) +{ + + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, + inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s fmtp attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_VALUE); + } else { + return (attr_p->attr.fmtp.sqcif); + } +} + +/* Function: sdp_attr_get_fmtp_cif4 + * Description: Gets the value of the fmtp attribute CIF4 type parameter + * for a given Video codec. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * Returns: CIF4 value. + */ +int32_t sdp_attr_get_fmtp_cif4 (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num) +{ + + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, + inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s fmtp attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_VALUE); + } else { + return (attr_p->attr.fmtp.cif4); + } +} + +/* Function: sdp_attr_get_fmtp_cif16 + * Description: Gets the value of the fmtp attribute CIF16 type parameter + * for a given Video codec. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * Returns: CIF16 value. + */ + +int32_t sdp_attr_get_fmtp_cif16 (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num) +{ + + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, + inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s fmtp attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_VALUE); + } else { + return (attr_p->attr.fmtp.cif16); + } +} + + +/* Function: sdp_attr_get_fmtp_maxbr + * Description: Gets the value of the fmtp attribute MAXBR type parameter + * for a given Video codec. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * Returns: MAXBR value. + */ +int32_t sdp_attr_get_fmtp_maxbr (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num) +{ + + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, + inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s fmtp attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_VALUE); + } else { + return (attr_p->attr.fmtp.maxbr); + } +} + +/* Function: sdp_attr_get_fmtp_custom_x + * Description: Gets the value of the fmtp attribute CUSTOM type parameter + * for a given Video codec. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * Returns: CUSTOM x value. + */ + +int32_t sdp_attr_get_fmtp_custom_x (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num) +{ + + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, + inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s fmtp attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_VALUE); + } else { + return (attr_p->attr.fmtp.custom_x); + } +} +/* Function: sdp_attr_get_fmtp_custom_y + * Description: Gets the value of the fmtp attribute custom_y type parameter + * for a given Video codec. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * Returns: CUSTOM Y-AXIS value. + */ + +int32_t sdp_attr_get_fmtp_custom_y (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num) +{ + + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, + inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s fmtp attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_VALUE); + } else { + return (attr_p->attr.fmtp.custom_y); + } +} + +/* Function: sdp_attr_get_fmtp_custom_mpi + * Description: Gets the value of the fmtp attribute CUSTOM type parameter + * for a given Video codec. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * Returns: CUSTOM MPI value. + */ + +int32_t sdp_attr_get_fmtp_custom_mpi (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num) +{ + + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, + inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s fmtp attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_VALUE); + } else { + return (attr_p->attr.fmtp.custom_mpi); + } +} + +/* Function: sdp_attr_get_fmtp_par_width + * Description: Gets the value of the fmtp attribute PAR (width) parameter + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * Returns: PAR - width value. + */ +int32_t sdp_attr_get_fmtp_par_width (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num) +{ + + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, + inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s fmtp attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_VALUE); + } else { + return (attr_p->attr.fmtp.par_width); + } +} + +/* Function: sdp_attr_get_fmtp_par_height + * Description: Gets the value of the fmtp attribute PAR (height) parameter + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * Returns: PAR - height value. + */ +int32_t sdp_attr_get_fmtp_par_height (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num) +{ + + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, + inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s fmtp attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_VALUE); + } else { + return (attr_p->attr.fmtp.par_height); + } +} + +/* Function: sdp_attr_get_fmtp_cpcf + * Description: Gets the value of the fmtp attribute- CPCF parameter + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * Returns: CPCF value. + */ +int32_t sdp_attr_get_fmtp_cpcf (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num) +{ + + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, + inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s fmtp attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_VALUE); + } else { + return (attr_p->attr.fmtp.cpcf); + } +} + +/* Function: sdp_attr_get_fmtp_bpp + * Description: Gets the value of the fmtp attribute- BPP parameter + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * Returns: BPP value. + */ +int32_t sdp_attr_get_fmtp_bpp (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num) +{ + + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, + inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s fmtp attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_VALUE); + } else { + return (attr_p->attr.fmtp.bpp); + } +} + +/* Function: sdp_attr_get_fmtp_hrd + * Description: Gets the value of the fmtp attribute- HRD parameter + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * Returns: HRD value. + */ +int32_t sdp_attr_get_fmtp_hrd (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num) +{ + + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, + inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s fmtp attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_VALUE); + } else { + return (attr_p->attr.fmtp.hrd); + } +} + +/* Function: sdp_attr_get_fmtp_profile + * Description: Gets the value of the fmtp attribute- PROFILE parameter + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * Returns: PROFILE value. + */ +int32_t sdp_attr_get_fmtp_profile (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num) +{ + + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, + inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s fmtp attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_VALUE); + } else { + return (attr_p->attr.fmtp.profile); + } +} + +/* Function: sdp_attr_get_fmtp_level + * Description: Gets the value of the fmtp attribute- LEVEL parameter + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * Returns: LEVEL value. + */ +int32_t sdp_attr_get_fmtp_level (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num) +{ + + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, + inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s fmtp attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_VALUE); + } else { + return (attr_p->attr.fmtp.level); + } +} + +/* Function: sdp_attr_get_fmtp_interlace + * Description: Checks if INTERLACE parameter is set. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * Returns: TRUE if INTERLACE is present and FALSE if INTERLACE is absent. + */ +tinybool sdp_attr_get_fmtp_interlace (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num) +{ + + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, + inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s fmtp attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return FALSE; + } else { + return (attr_p->attr.fmtp.is_interlace); + } +} + +/* Function: sdp_attr_get_fmtp_pack_mode + * Description: Gets the value of the fmtp attribute- packetization-mode parameter for H.264 codec + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * Returns: packetization-mode value in the range 0 - 2. + */ + +sdp_result_e sdp_attr_get_fmtp_pack_mode (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num, uint16_t *val) +{ + + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, + inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s fmtp attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_PARAMETER); + } else { + if (SDP_INVALID_PACKETIZATION_MODE_VALUE == attr_p->attr.fmtp.packetization_mode) { + /* packetization mode unspecified (optional) */ + *val = SDP_DEFAULT_PACKETIZATION_MODE_VALUE; + } else { + *val = attr_p->attr.fmtp.packetization_mode; + } + return (SDP_SUCCESS); + } +} + +/* Function: sdp_attr_get_fmtp_level_asymmetry_allowed + * Description: Gets the value of the fmtp attribute- level-asymmetry-allowed parameter for H.264 codec + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * Returns: level asymmetry allowed value (0 or 1). + */ + +sdp_result_e sdp_attr_get_fmtp_level_asymmetry_allowed (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num, uint16_t *val) +{ + + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, + inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s fmtp attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_PARAMETER); + } else { + *val = attr_p->attr.fmtp.level_asymmetry_allowed; + return (SDP_SUCCESS); + } +} + +/* Function: sdp_attr_get_fmtp_profile_id + * Description: Gets the value of the fmtp attribute- profile-level-id parameter for H.264 codec + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * Returns: profile-level-id value. + */ +const char* sdp_attr_get_fmtp_profile_id (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num) +{ + + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, + inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s fmtp attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (0); + } else { + return (attr_p->attr.fmtp.profile_level_id); + } +} + +/* Function: sdp_attr_get_fmtp_param_sets + * Description: Gets the value of the fmtp attribute- parameter-sets parameter for H.264 codec + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * Returns: parameter-sets value. + */ +const char* sdp_attr_get_fmtp_param_sets (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num) +{ + + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, + inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s fmtp attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (0); + } else { + return (attr_p->attr.fmtp.parameter_sets); + } +} + +/* Function: sdp_attr_get_fmtp_interleaving_depth + * Description: Gets the value of the fmtp attribute- interleaving_depth parameter for H.264 codec + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * Returns: interleaving_depth value + */ + +sdp_result_e sdp_attr_get_fmtp_interleaving_depth (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num, uint16_t* val) +{ + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, + inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s fmtp attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_PARAMETER); + } else { + *val = attr_p->attr.fmtp.interleaving_depth; + return (SDP_SUCCESS); + } +} + +/* Function: sdp_attr_get_fmtp_deint_buf_req + * Description: Gets the value of the fmtp attribute- deint-buf-req parameter for H.264 codec + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * Returns: deint-buf-req value. + */ + +sdp_result_e sdp_attr_get_fmtp_deint_buf_req (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num, + uint32_t *val) +{ + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, + inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s fmtp attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_PARAMETER); + } else { + if (attr_p->attr.fmtp.flag & SDP_DEINT_BUF_REQ_FLAG) { + *val = attr_p->attr.fmtp.deint_buf_req; + return (SDP_SUCCESS); + } else { + return (SDP_FAILURE); + } + } +} + +/* Function: sdp_attr_get_fmtp_max_don_diff + * Description: Gets the value of the fmtp attribute- max-don-diff parameter for H.264 codec + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * Returns: max-don-diff value. + */ +sdp_result_e sdp_attr_get_fmtp_max_don_diff (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num, + uint32_t *val) +{ + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, + inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s fmtp attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_PARAMETER); + } else { + *val = attr_p->attr.fmtp.max_don_diff; + return (SDP_SUCCESS); + } +} + +/* Function: sdp_attr_get_fmtp_init_buf_time + * Description: Gets the value of the fmtp attribute- init-buf-time parameter for H.264 codec + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * Returns: init-buf-time value. + */ +sdp_result_e sdp_attr_get_fmtp_init_buf_time (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num, + uint32_t *val) +{ + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, + inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s fmtp attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_PARAMETER); + } else { + if (attr_p->attr.fmtp.flag & SDP_INIT_BUF_TIME_FLAG) { + *val = attr_p->attr.fmtp.init_buf_time; + return (SDP_SUCCESS); + } else { + return (SDP_FAILURE); + } + } +} + +/* Function: sdp_attr_get_fmtp_max_mbps + * Description: Gets the value of the fmtp attribute- max-mbps parameter for H.264 codec + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * Returns: max-mbps value. + */ + +sdp_result_e sdp_attr_get_fmtp_max_mbps (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num, + uint32_t *val) +{ + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, + inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s fmtp attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_PARAMETER); + } else { + *val = attr_p->attr.fmtp.max_mbps; + return (SDP_SUCCESS); + } +} + +/* Function: sdp_attr_get_fmtp_max_fs + * Description: Gets the value of the fmtp attribute- max-fs parameter for H.264 codec + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * Returns: max-fs value. + */ + +sdp_result_e sdp_attr_get_fmtp_max_fs (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num, uint32_t *val) +{ + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, + inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s fmtp attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_PARAMETER); + } else { + *val = attr_p->attr.fmtp.max_fs; + return (SDP_SUCCESS); + } +} + +/* Function: sdp_attr_get_fmtp_max_fr + * Description: Gets the value of the fmtp attribute- max-fr parameter + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * Returns: max-fr value. + */ + +sdp_result_e sdp_attr_get_fmtp_max_fr (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num, uint32_t *val) +{ + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, + inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s fmtp attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_PARAMETER); + } else { + *val = attr_p->attr.fmtp.max_fr; + return (SDP_SUCCESS); + } +} + +/* Function: sdp_attr_get_fmtp_max_cpb + * Description: Gets the value of the fmtp attribute- max-cpb parameter for H.264 codec + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * Returns: max-cpb value. + */ + +sdp_result_e sdp_attr_get_fmtp_max_cpb (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num, uint32_t *val) +{ + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, + inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s fmtp attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_PARAMETER); + } else { + *val = attr_p->attr.fmtp.max_cpb; + return (SDP_SUCCESS); + } +} + +/* Function: sdp_attr_get_fmtp_max_dpb + * Description: Gets the value of the fmtp attribute- max-dpb parameter for H.264 codec + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * Returns: max-dpb value. + */ + +sdp_result_e sdp_attr_get_fmtp_max_dpb (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num, uint32_t *val) +{ + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, + inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s fmtp attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_PARAMETER); + } else { + *val = attr_p->attr.fmtp.max_dpb; + return (SDP_SUCCESS); + } +} + + +/* Function: sdp_attr_get_fmtp_max_br + * Description: Gets the value of the fmtp attribute- max-br parameter for H.264 codec + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * Returns: max-br value. + */ + +sdp_result_e sdp_attr_get_fmtp_max_br (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num, uint32_t* val) +{ + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, + inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s fmtp attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_PARAMETER); + } else { + *val = attr_p->attr.fmtp.max_br; + return (SDP_SUCCESS); + } +} + +/* Function: sdp_attr_fmtp_is_redundant_pic_cap + * Description: Gets the value of the fmtp attribute- redundant_pic_cap parameter for H.264 codec + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * Returns: redundant-pic-cap value. + */ +tinybool sdp_attr_fmtp_is_redundant_pic_cap (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num) +{ + + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, + inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s fmtp attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (FALSE); + } else { + return (attr_p->attr.fmtp.redundant_pic_cap); + } +} + +/* Function: sdp_attr_get_fmtp_deint_buf_cap + * Description: Gets the value of the fmtp attribute- deint-buf-cap parameter for H.264 codec + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * Returns: deint-buf-cap value. + */ + +sdp_result_e sdp_attr_get_fmtp_deint_buf_cap (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num, + uint32_t *val) +{ + + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, + inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s fmtp attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_PARAMETER); + } else { + if (attr_p->attr.fmtp.flag & SDP_DEINT_BUF_CAP_FLAG) { + *val = attr_p->attr.fmtp.deint_buf_cap; + return (SDP_SUCCESS); + } else { + return (SDP_FAILURE); + } + } +} + +/* Function: sdp_attr_get_fmtp_max_rcmd_nalu_size + * Description: Gets the value of the fmtp attribute- max-rcmd-nalu-size parameter for H.264 codec + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * Returns: max-rcmd-nalu-size value. + */ +sdp_result_e sdp_attr_get_fmtp_max_rcmd_nalu_size (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num, + uint32_t *val) +{ + + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, + inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s fmtp attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_PARAMETER); + } else { + if (attr_p->attr.fmtp.flag & SDP_MAX_RCMD_NALU_SIZE_FLAG) { + *val = attr_p->attr.fmtp.max_rcmd_nalu_size; + return (SDP_SUCCESS); + } else { + return (SDP_FAILURE); + } + } +} + +/* Function: sdp_attr_fmtp_is_parameter_add + * Description: Gets the value of the fmtp attribute- parameter-add for H.264 codec + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * Returns: TRUE/FALSE ( parameter-add is boolean) + */ +tinybool sdp_attr_fmtp_is_parameter_add (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num) +{ + + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, + inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s fmtp attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (FALSE); + } else { + /* Both 1 and SDP_FMTP_UNUSED (parameter not present) should be + * treated as TRUE, per RFC 3984, page 45 */ + return (attr_p->attr.fmtp.parameter_add != 0); + } +} + +/****** Following functions are get routines for Annex values + * For each Annex support, the get routine will return the boolean TRUE/FALSE + * Some Annexures for Video codecs have values defined . In those cases, + * (e.g Annex K, P ) , the return values are not boolean. + * + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * Returns: Annex value + */ + +tinybool sdp_attr_get_fmtp_annex_d (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num) +{ + + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, + inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s fmtp attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (FALSE); + } else { + return (attr_p->attr.fmtp.annex_d); + } +} + +tinybool sdp_attr_get_fmtp_annex_f (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num) +{ + + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, + inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s fmtp attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (FALSE); + } else { + return (attr_p->attr.fmtp.annex_f); + } +} + +tinybool sdp_attr_get_fmtp_annex_i (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num) +{ + + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, + inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s fmtp attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (FALSE); + } else { + return (attr_p->attr.fmtp.annex_i); + } +} + +tinybool sdp_attr_get_fmtp_annex_j (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num) +{ + + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, + inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s fmtp attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (FALSE); + } else { + return (attr_p->attr.fmtp.annex_j); + } +} + +tinybool sdp_attr_get_fmtp_annex_t (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num) +{ + + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, + inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s fmtp attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (FALSE); + } else { + return (attr_p->attr.fmtp.annex_t); + } +} + +int32_t sdp_attr_get_fmtp_annex_k_val (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num) +{ + + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, + inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s fmtp attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_VALUE); + } else { + return (attr_p->attr.fmtp.annex_k_val); + } +} + +int32_t sdp_attr_get_fmtp_annex_n_val (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num) +{ + + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, + inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s fmtp attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_VALUE); + } else { + return (attr_p->attr.fmtp.annex_n_val); + } +} + +int32_t sdp_attr_get_fmtp_annex_p_picture_resize (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num) +{ + + + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, + inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s fmtp attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_VALUE); + } else { + return (attr_p->attr.fmtp.annex_p_val_picture_resize); + } +} + +int32_t sdp_attr_get_fmtp_annex_p_warp (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num) +{ + + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, + inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s fmtp attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_VALUE); + } else { + return (attr_p->attr.fmtp.annex_p_val_warp); + } +} + +/* Function: sdp_attr_fmtp_get_fmtp_format + * Description: Gives the value of the fmtp attribute fmtp_format + * type parameter + * for the given attribute. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * + * + * Returns: Enum type sdp_fmtp_format_type_e + */ +sdp_fmtp_format_type_e sdp_attr_fmtp_get_fmtp_format (sdp_t *sdp_p, + uint16_t level, uint8_t cap_num, + uint16_t inst_num) +{ + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_FMTP, + inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s fmtp attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (SDP_FMTP_UNKNOWN_TYPE); + } else { + return (attr_p->attr.fmtp.fmtp_format); + } +} + +/* Function: sdp_attr_get_pccodec_num_payload_types + * Description: Returns the number of payload types specified for the + * given X-pc-codec attribute. If the given attribute is not + * defined, zero is returned. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * Returns: Number of payload types. + */ +uint16_t sdp_attr_get_pccodec_num_payload_types (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num) +{ + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_X_PC_CODEC, + inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s X-pc-codec attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (0); + } else { + return (attr_p->attr.pccodec.num_payloads); + } +} + +/* Function: sdp_attr_get_pccodec_payload_type + * Description: Returns the value of the specified payload type for the + * given X-pc-codec attribute. If the given attribute is not + * defined, zero is returned. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * payload_num The payload number to get. Range is (1 - + * max num payloads). + * Returns: Payload type. + */ +uint16_t sdp_attr_get_pccodec_payload_type (sdp_t *sdp_p, uint16_t level, uint8_t cap_num, + uint16_t inst_num, uint16_t payload_num) +{ + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_X_PC_CODEC, + inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s X-pc-codec attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (0); + } else { + if ((payload_num < 1) || + (payload_num > attr_p->attr.pccodec.num_payloads)) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s X-pc-codec attribute, level %u instance %u, " + "invalid payload number %u requested.", + sdp_p->debug_str, (unsigned)level, (unsigned)inst_num, (unsigned)payload_num); + } + sdp_p->conf_p->num_invalid_param++; + return (0); + } else { + return (attr_p->attr.pccodec.payload_type[payload_num-1]); + } + } +} + +/* Function: sdp_attr_add_pccodec_payload_type + * Description: Add a new value to the list of payload types specified for + * the given X-pc-codec attribute. The payload type will be + * added to the end of the list so these values should be added + * in the order they will be displayed within the attribute. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * payload_type The payload type to add. + * Returns: SDP_SUCCESS Payload type was added successfully. + * SDP_INVALID_PARAMETER Specified attribute is not defined. + */ +sdp_result_e sdp_attr_add_pccodec_payload_type (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num, + uint16_t payload_type) +{ + uint16_t payload_num; + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_X_PC_CODEC, + inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s X-pc-codec attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_PARAMETER); + } else { + payload_num = attr_p->attr.pccodec.num_payloads++; + attr_p->attr.pccodec.payload_type[payload_num] = payload_type; + return (SDP_SUCCESS); + } +} + +/* Function: sdp_attr_get_xcap_first_cap_num + * Description: Gets the first capability number valid for the specified + * X-cap attribute instance. If the capability is not + * defined, zero is returned. + * Note: cap_num is not specified. It must be zero. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the capability. + * inst_num The X-cap instance number to check. + * Returns: Capability number or zero. + */ +uint16_t sdp_attr_get_xcap_first_cap_num (sdp_t *sdp_p, uint16_t level, uint16_t inst_num) +{ + uint16_t cap_num=1; + uint16_t attr_count=0; + sdp_attr_t *attr_p; + sdp_mca_t *mca_p; + + if (level == SDP_SESSION_LEVEL) { + for (attr_p = sdp_p->sess_attrs_p; attr_p != NULL; + attr_p = attr_p->next_p) { + if (attr_p->type == SDP_ATTR_X_CAP) { + attr_count++; + if (attr_count == inst_num) { + return (cap_num); + } else { + cap_num += attr_p->attr.cap_p->num_payloads; + } + } + } + } else { /* Capability is at a media level */ + mca_p = sdp_find_media_level(sdp_p, level); + if (mca_p == NULL) { + sdp_p->conf_p->num_invalid_param++; + return (0); + } + for (attr_p = mca_p->media_attrs_p; attr_p != NULL; + attr_p = attr_p->next_p) { + if (attr_p->type == SDP_ATTR_X_CAP) { + attr_count++; + if (attr_count == inst_num) { + return (cap_num); + } else { + cap_num += attr_p->attr.cap_p->num_payloads; + } + } + } + } /* Attr is at a media level */ + + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s X-cap attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (0); +} + +/* Function: sdp_attr_get_xcap_media_type + * Description: Returns the media type specified for the given X-cap + * attribute. If the given attribute is not defined, + * SDP_MEDIA_INVALID is returned. + * Note: cap_num is not specified. It must be zero. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * inst_num The attribute instance number to check. + * Returns: Media type or SDP_MEDIA_INVALID. + */ +sdp_media_e sdp_attr_get_xcap_media_type (sdp_t *sdp_p, uint16_t level, + uint16_t inst_num) +{ + sdp_attr_t *attr_p; + sdp_mca_t *cap_p; + + attr_p = sdp_find_attr(sdp_p, level, 0, SDP_ATTR_X_CAP, inst_num); + if ((attr_p == NULL) || (attr_p->attr.cap_p == NULL)) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s X-cap attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (SDP_MEDIA_INVALID); + } else { + cap_p = attr_p->attr.cap_p; + return (cap_p->media); + } +} + +/* Function: sdp_attr_get_xcap_transport_type + * Description: Returns the transport type specified for the given X-cap + * attribute. If the given attribute is not defined, + * SDP_TRANSPORT_INVALID is returned. + * Note: cap_num is not specified. It must be zero. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * inst_num The attribute instance number to check. + * Returns: Media type or SDP_TRANSPORT_INVALID. + */ +sdp_transport_e sdp_attr_get_xcap_transport_type (sdp_t *sdp_p, uint16_t level, + uint16_t inst_num) +{ + sdp_attr_t *attr_p; + sdp_mca_t *cap_p; + + attr_p = sdp_find_attr(sdp_p, level, 0, SDP_ATTR_X_CAP, + inst_num); + if ((attr_p == NULL) || (attr_p->attr.cap_p == NULL)) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s X-cap attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (SDP_TRANSPORT_INVALID); + } else { + cap_p = attr_p->attr.cap_p; + return (cap_p->transport); + } +} + +/* Function: sdp_attr_get_xcap_num_payload_types + * Description: Returns the number of payload types associated with the + * specified X-cap attribute. If the attribute is invalid, + * zero will be returned. Application must validate the + * attribute line before using this routine. + * Note: cap_num is not specified. It must be zero. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * Returns: Number of payload types or zero. + */ +uint16_t sdp_attr_get_xcap_num_payload_types (sdp_t *sdp_p, uint16_t level, + uint16_t inst_num) +{ + sdp_attr_t *attr_p; + sdp_mca_t *cap_p; + + attr_p = sdp_find_attr(sdp_p, level, 0, SDP_ATTR_X_CAP, inst_num); + if ((attr_p == NULL) || (attr_p->attr.cap_p == NULL)) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s X-cap attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (0); + } else { + cap_p = attr_p->attr.cap_p; + return (cap_p->num_payloads); + } +} + +/* Function: sdp_attr_get_xcap_payload_type + * Description: Returns the payload type of the specified payload for the + * X-cap attribute line. If the attr line or payload number is + * invalid, zero will be returned. Application must validate + * the X-cap attr before using this routine. + * Note: cap_num is not specified. It must be zero. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * inst_num The attribute instance number to check. + * payload_num The payload number to retrieve. Range is + * (1 - max num payloads). + * Returns: Payload type or zero. + */ +uint16_t sdp_attr_get_xcap_payload_type (sdp_t *sdp_p, uint16_t level, + uint16_t inst_num, uint16_t payload_num, + sdp_payload_ind_e *indicator) +{ + sdp_attr_t *attr_p; + sdp_mca_t *cap_p; + + attr_p = sdp_find_attr(sdp_p, level, 0, SDP_ATTR_X_CAP, inst_num); + if ((attr_p == NULL) || (attr_p->attr.cap_p == NULL)) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s X-cap attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (0); + } else { + cap_p = attr_p->attr.cap_p; + if ((payload_num < 1) || + (payload_num > cap_p->num_payloads)) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s X-cap attribute, level %u instance %u, " + "payload num %u invalid.", sdp_p->debug_str, + (unsigned)level, (unsigned)inst_num, (unsigned)payload_num); + } + sdp_p->conf_p->num_invalid_param++; + return (0); + } else { + *indicator = cap_p->payload_indicator[payload_num-1]; + return (cap_p->payload_type[payload_num-1]); + } + } +} + + +/* Function: sdp_attr_add_xcap_payload_type + * Description: Add a new payload type for the X-cap attribute line + * specified. The new payload type will be added at the end + * of the payload type list. + * Note: cap_num is not specified. It must be zero. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * inst_num The attribute instance number to check. + * payload_type The new payload type. + * Returns: SDP_SUCCESS or SDP_INVALID_PARAMETER + */ +sdp_result_e sdp_attr_add_xcap_payload_type(sdp_t *sdp_p, uint16_t level, + uint16_t inst_num, uint16_t payload_type, + sdp_payload_ind_e indicator) +{ + sdp_attr_t *attr_p; + sdp_mca_t *cap_p; + + attr_p = sdp_find_attr(sdp_p, level, 0, SDP_ATTR_X_CAP, inst_num); + if ((attr_p == NULL) || (attr_p->attr.cap_p == NULL)) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s X-cap attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_PARAMETER); + } + + cap_p = attr_p->attr.cap_p; + cap_p->payload_indicator[cap_p->num_payloads] = indicator; + cap_p->payload_type[cap_p->num_payloads++] = payload_type; + return (SDP_SUCCESS); +} + +/* Function: sdp_attr_get_cdsc_first_cap_num + * Description: Gets the first capability number valid for the specified + * CDSC attribute instance. If the capability is not + * defined, zero is returned. + * Note: cap_num is not specified. It must be zero. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the capability. + * inst_num The CDSC instance number to check. + * Returns: Capability number or zero. + */ +uint16_t sdp_attr_get_cdsc_first_cap_num(sdp_t *sdp_p, uint16_t level, uint16_t inst_num) +{ + uint16_t cap_num=1; + uint16_t attr_count=0; + sdp_attr_t *attr_p; + sdp_mca_t *mca_p; + + if (level == SDP_SESSION_LEVEL) { + for (attr_p = sdp_p->sess_attrs_p; attr_p != NULL; + attr_p = attr_p->next_p) { + if (attr_p->type == SDP_ATTR_CDSC) { + attr_count++; + if (attr_count == inst_num) { + return (cap_num); + } else { + cap_num += attr_p->attr.cap_p->num_payloads; + } + } + } + } else { /* Capability is at a media level */ + mca_p = sdp_find_media_level(sdp_p, level); + if (mca_p == NULL) { + sdp_p->conf_p->num_invalid_param++; + return (0); + } + for (attr_p = mca_p->media_attrs_p; attr_p != NULL; + attr_p = attr_p->next_p) { + if (attr_p->type == SDP_ATTR_CDSC) { + attr_count++; + if (attr_count == inst_num) { + return (cap_num); + } else { + cap_num += attr_p->attr.cap_p->num_payloads; + } + } + } + } /* Attr is at a media level */ + + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s CDSC attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (0); +} + +/* Function: sdp_attr_get_cdsc_media_type + * Description: Returns the media type specified for the given CDSC + * attribute. If the given attribute is not defined, + * SDP_MEDIA_INVALID is returned. + * Note: cap_num is not specified. It must be zero. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * inst_num The attribute instance number to check. + * Returns: Media type or SDP_MEDIA_INVALID. + */ +sdp_media_e sdp_attr_get_cdsc_media_type(sdp_t *sdp_p, uint16_t level, + uint16_t inst_num) +{ + sdp_attr_t *attr_p; + sdp_mca_t *cdsc_p; + + attr_p = sdp_find_attr(sdp_p, level, 0, SDP_ATTR_CDSC, inst_num); + if ((attr_p == NULL) || (attr_p->attr.cap_p == NULL)) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s CDSC attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (SDP_MEDIA_INVALID); + } else { + cdsc_p = attr_p->attr.cap_p; + return (cdsc_p->media); + } +} + +/* Function: sdp_attr_get_cdsc_transport_type + * Description: Returns the transport type specified for the given CDSC + * attribute. If the given attribute is not defined, + * SDP_TRANSPORT_INVALID is returned. + * Note: cap_num is not specified. It must be zero. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * inst_num The attribute instance number to check. + * Returns: Media type or SDP_TRANSPORT_INVALID. + */ +sdp_transport_e sdp_attr_get_cdsc_transport_type(sdp_t *sdp_p, uint16_t level, + uint16_t inst_num) +{ + sdp_attr_t *attr_p; + sdp_mca_t *cdsc_p; + + attr_p = sdp_find_attr(sdp_p, level, 0, SDP_ATTR_CDSC, + inst_num); + if ((attr_p == NULL) || (attr_p->attr.cap_p == NULL)) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s CDSC attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (SDP_TRANSPORT_INVALID); + } else { + cdsc_p = attr_p->attr.cap_p; + return (cdsc_p->transport); + } +} + +/* Function: sdp_attr_get_cdsc_num_payload_types + * Description: Returns the number of payload types associated with the + * specified CDSC attribute. If the attribute is invalid, + * zero will be returned. Application must validate the + * attribute line before using this routine. + * Note: cap_num is not specified. It must be zero. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * Returns: Number of payload types or zero. + */ +uint16_t sdp_attr_get_cdsc_num_payload_types (sdp_t *sdp_p, uint16_t level, + uint16_t inst_num) +{ + sdp_attr_t *attr_p; + sdp_mca_t *cdsc_p; + + attr_p = sdp_find_attr(sdp_p, level, 0, SDP_ATTR_CDSC, inst_num); + if ((attr_p == NULL) || (attr_p->attr.cap_p == NULL)) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s CDSC attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (0); + } else { + cdsc_p = attr_p->attr.cap_p; + return (cdsc_p->num_payloads); + } +} + +/* Function: sdp_attr_get_cdsc_payload_type + * Description: Returns the payload type of the specified payload for the + * CDSC attribute line. If the attr line or payload number is + * invalid, zero will be returned. Application must validate + * the CDSC attr before using this routine. + * Note: cap_num is not specified. It must be zero. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * inst_num The attribute instance number to check. + * payload_num The payload number to retrieve. Range is + * (1 - max num payloads). + * Returns: Payload type or zero. + */ +uint16_t sdp_attr_get_cdsc_payload_type (sdp_t *sdp_p, uint16_t level, + uint16_t inst_num, uint16_t payload_num, + sdp_payload_ind_e *indicator) +{ + sdp_attr_t *attr_p; + sdp_mca_t *cdsc_p; + + attr_p = sdp_find_attr(sdp_p, level, 0, SDP_ATTR_CDSC, inst_num); + if ((attr_p == NULL) || (attr_p->attr.cap_p == NULL)) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s CDSC attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (0); + } else { + cdsc_p = attr_p->attr.cap_p; + if ((payload_num < 1) || + (payload_num > cdsc_p->num_payloads)) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s CDSC attribute, level %u instance %u, " + "payload num %u invalid.", sdp_p->debug_str, + (unsigned)level, (unsigned)inst_num, (unsigned)payload_num); + } + sdp_p->conf_p->num_invalid_param++; + return (0); + } else { + *indicator = cdsc_p->payload_indicator[payload_num-1]; + return (cdsc_p->payload_type[payload_num-1]); + } + } +} + +/* Function: sdp_attr_add_cdsc_payload_type + * Description: Add a new payload type for the CDSC attribute line + * specified. The new payload type will be added at the end + * of the payload type list. + * Note: cap_num is not specified. It must be zero. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * inst_num The attribute instance number to check. + * payload_type The new payload type. + * Returns: SDP_SUCCESS or SDP_INVALID_PARAMETER + */ +sdp_result_e sdp_attr_add_cdsc_payload_type (sdp_t *sdp_p, uint16_t level, + uint16_t inst_num, uint16_t payload_type, + sdp_payload_ind_e indicator) +{ + sdp_attr_t *attr_p; + sdp_mca_t *cdsc_p; + + attr_p = sdp_find_attr(sdp_p, level, 0, SDP_ATTR_CDSC, inst_num); + if ((attr_p == NULL) || (attr_p->attr.cap_p == NULL)) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s CDSC attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_PARAMETER); + } + + cdsc_p = attr_p->attr.cap_p; + cdsc_p->payload_indicator[cdsc_p->num_payloads] = indicator; + cdsc_p->payload_type[cdsc_p->num_payloads++] = payload_type; + return (SDP_SUCCESS); +} + +/* Function: sdp_media_dynamic_payload_valid + * Description: Checks if the dynamic payload type passed in is defined + * on the media line m_line + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * payload_type Payload type to be checked + * + * Returns: TRUE or FALSE. Returns TRUE if payload type is defined on the + * media line, else returns FALSE + */ + +tinybool sdp_media_dynamic_payload_valid (sdp_t *sdp_p, uint16_t payload_type, + uint16_t m_line) +{ + uint16_t p_type,m_ptype; + ushort num_payload_types; + sdp_payload_ind_e ind; + tinybool payload_matches = FALSE; + tinybool result = TRUE; + + if ((payload_type < SDP_MIN_DYNAMIC_PAYLOAD) || + (payload_type > SDP_MAX_DYNAMIC_PAYLOAD)) { + return FALSE; + } + + num_payload_types = + sdp_get_media_num_payload_types(sdp_p, m_line); + + for(p_type=1; p_type <=num_payload_types;p_type++){ + + m_ptype = (uint16_t)sdp_get_media_payload_type(sdp_p, + m_line, p_type, &ind); + if (payload_type == m_ptype) { + payload_matches = TRUE; + break; + } + + } + + if (!payload_matches) { + return FALSE; + } + + return (result); + +} + +/* Function: sdp_attr_get_rtr_confirm + * Description: Returns the value of the rtr attribute confirm + * parameter specified for the given attribute. Returns TRUE if + * the confirm parameter is specified. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * Returns: Boolean value. + */ +tinybool sdp_attr_get_rtr_confirm (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num) +{ + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_RTR, inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s %s attribute, level %u instance %u " + "not found.", sdp_p->debug_str, + sdp_get_attr_name(SDP_ATTR_RTR), (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (FALSE); + } else { + return (attr_p->attr.rtr.confirm); + } +} + + + +sdp_mediadir_role_e sdp_attr_get_comediadir_role (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num) +{ + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, + SDP_ATTR_DIRECTION, inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s Comediadir role attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (SDP_MEDIADIR_ROLE_UNKNOWN); + } else { + return (attr_p->attr.comediadir.role); + } +} + +/* Function: sdp_attr_get_silencesupp_enabled + * Description: Returns the value of the silencesupp attribute enable + * parameter specified for the given attribute. Returns TRUE if + * the confirm parameter is specified. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * Returns: Boolean value. + */ +tinybool sdp_attr_get_silencesupp_enabled (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num) +{ + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, + SDP_ATTR_SILENCESUPP, inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s silenceSuppEnable attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (FALSE); + } else { + return (attr_p->attr.silencesupp.enabled); + } +} + +/* Function: sdp_attr_get_silencesupp_timer + * Description: Returns the value of the silencesupp attribute timer + * parameter specified for the given attribute. null_ind + * is set to TRUE if no value was specified, but instead the + * null "-" value was specified. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * Returns: 16-bit timer value + * boolean null_ind + */ +uint16_t sdp_attr_get_silencesupp_timer (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num, + tinybool *null_ind) +{ + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, + SDP_ATTR_SILENCESUPP, inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s silenceTimer attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (0); + } else { + *null_ind = attr_p->attr.silencesupp.timer_null; + return (attr_p->attr.silencesupp.timer); + } +} + +/* Function: sdp_attr_get_silencesupp_pref + * Description: Sets the silencesupp supppref value + * If this parameter is TRUE, the confirm parameter will be + * specified when the SDP description is built. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * confirm New qos confirm parameter. + * Returns: SDP_SUCCESS Attribute param was set successfully. + * SDP_INVALID_PARAMETER Specified attribute is not defined. + */ +sdp_silencesupp_pref_e sdp_attr_get_silencesupp_pref (sdp_t *sdp_p, + uint16_t level, uint8_t cap_num, + uint16_t inst_num) +{ + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, + SDP_ATTR_SILENCESUPP, inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s silence suppPref attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (SDP_SILENCESUPP_PREF_UNKNOWN); + } else { + return (attr_p->attr.silencesupp.pref); + } +} + +/* Function: sdp_attr_get_silencesupp_siduse + * Description: Returns the value of the silencesupp attribute siduse + * parameter specified for the given attribute. If the given + * attribute is not defined, SDP_QOS_STRENGTH_UNKNOWN is + * returned. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * Returns: silencesupp siduse enum. + */ +sdp_silencesupp_siduse_e sdp_attr_get_silencesupp_siduse (sdp_t *sdp_p, + uint16_t level, + uint8_t cap_num, + uint16_t inst_num) +{ + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, + SDP_ATTR_SILENCESUPP, inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s silence sidUse attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (SDP_SILENCESUPP_SIDUSE_UNKNOWN); + } else { + return (attr_p->attr.silencesupp.siduse); + } +} + +/* Function: sdp_attr_get_silencesupp_fxnslevel + * Description: Returns the value of the silencesupp attribute fxns + * (fixed noise) parameter specified for the given attribute. + * null_ind is set to TRUE if no value was specified, + * but instead the null "-" value was specified. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * Returns: 7-bit fxns value + * boolean null_ind + */ +uint8_t sdp_attr_get_silencesupp_fxnslevel (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num, + tinybool *null_ind) +{ + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, + SDP_ATTR_SILENCESUPP, inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s silence fxnslevel attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (0); + } else { + *null_ind = attr_p->attr.silencesupp.fxnslevel_null; + return (attr_p->attr.silencesupp.fxnslevel); + } +} + +/* Function: sdp_attr_get_mptime_num_intervals + * Description: Returns the number of intervals specified for the + * given mptime attribute. If the given attribute is not + * defined, zero is returned. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * Returns: Number of intervals. + */ +uint16_t sdp_attr_get_mptime_num_intervals ( + sdp_t *sdp_p, + uint16_t level, + uint8_t cap_num, + uint16_t inst_num) { + + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_MPTIME, inst_num); + if (attr_p != NULL) { + return attr_p->attr.mptime.num_intervals; + } + + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s mptime attribute, level %u instance %u not found.", + sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return 0; +} + +/* Function: sdp_attr_get_mptime_interval + * Description: Returns the value of the specified interval for the + * given mptime attribute. If the given attribute is not + * defined, zero is returned. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * interval_num The interval number to get. Range is (1 - + * max num payloads). + * Returns: Interval. + */ +uint16_t sdp_attr_get_mptime_interval ( + sdp_t *sdp_p, + uint16_t level, + uint8_t cap_num, + uint16_t inst_num, + uint16_t interval_num) { + + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_MPTIME, inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s mptime attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return 0; + } + + if ((interval_num<1) || (interval_num>attr_p->attr.mptime.num_intervals)) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s mptime attribute, level %u instance %u, " + "invalid interval number %u requested.", + sdp_p->debug_str, (unsigned)level, (unsigned)inst_num, (unsigned)interval_num); + } + sdp_p->conf_p->num_invalid_param++; + return 0; + } + + return attr_p->attr.mptime.intervals[interval_num-1]; +} + +/* Function: sdp_attr_add_mptime_interval + * Description: Add a new value to the list of intervals specified for + * the given mptime attribute. The interval will be + * added to the end of the list so these values should be added + * in the order they will be displayed within the attribute. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * mp_interval The interval to add. + * Returns: SDP_SUCCESS Interval was added successfully. + * SDP_INVALID_PARAMETER Specified attribute is not defined. + * SDP_INVALID_SDP_PTR Supplied SDP pointer is invalid + */ +sdp_result_e sdp_attr_add_mptime_interval ( + sdp_t *sdp_p, + uint16_t level, + uint8_t cap_num, + uint16_t inst_num, + uint16_t mp_interval) { + + uint16_t interval_num; + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, SDP_ATTR_MPTIME, inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s mptime attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return SDP_INVALID_PARAMETER; + } + + interval_num = attr_p->attr.mptime.num_intervals; + if (interval_num>=SDP_MAX_PAYLOAD_TYPES) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s mptime attribute, level %u instance %u " + "exceeds maximum length.", + sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return SDP_INVALID_PARAMETER; + } + + attr_p->attr.mptime.intervals[interval_num] = mp_interval; + ++attr_p->attr.mptime.num_intervals; + return SDP_SUCCESS; +} + + + +/* Function: sdp_get_group_attr + * Description: Returns the attribute parameter from the a=group:<> + * line. If no attrib has been set , + * SDP_GROUP_ATTR_UNSUPPORTED will be returned. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level SDP_SESSION_LEVEL + * Returns: Valid attrib value or SDP_GROUP_ATTR_UNSUPPORTED. + */ +sdp_group_attr_e sdp_get_group_attr (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num) +{ + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, + SDP_ATTR_GROUP, inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s Group (a= group line) attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (SDP_GROUP_ATTR_UNSUPPORTED); + } else { + if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) { + SDP_PRINT("%s Stream data group attr field is :%s ", + sdp_p->debug_str, + sdp_get_group_attr_name(attr_p->attr.stream_data.group_attr) ); + } + return (attr_p->attr.stream_data.group_attr); + } +} + +/* Function: sdp_get_group_num_id + * Description: Returns the number of ids from the a=group:<> line. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level SDP_SESSION_LEVEL + * Returns: Num of group ids present or 0 if there is an error. + */ +uint16_t sdp_get_group_num_id (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num) +{ + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, + SDP_ATTR_GROUP, inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s a=group level attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (0); + } else { + if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) { + SDP_PRINT("%s Stream data group attr - num of ids is :%u ", + sdp_p->debug_str, + (unsigned)attr_p->attr.stream_data.num_group_id); + } + } + return (attr_p->attr.stream_data.num_group_id); +} + +/* Function: sdp_get_group_id + * Description: Returns the group id from the a=group:<> line. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level SDP_SESSION_LEVEL + * id_num Number of the id to retrieve. The range is (1 - + * SDP_MAX_GROUP_STREAM_ID) + * Returns: Value of the group id at the index specified or + * NULL if an error + */ +const char* sdp_get_group_id (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num, uint16_t id_num) +{ + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, + SDP_ATTR_GROUP, inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s a=group level attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (NULL); + } else { + if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) { + SDP_PRINT("%s Stream data group attr - num of ids is :%u ", + sdp_p->debug_str, + (unsigned)attr_p->attr.stream_data.num_group_id); + } + if ((id_num < 1) || (id_num > attr_p->attr.stream_data.num_group_id)) { + return (NULL); + } + } + return (attr_p->attr.stream_data.group_ids[id_num-1]); +} + +/* Function: sdp_attr_get_x_sidin + * Description: Returns the attribute parameter from the a=X-sidin:<> + * line. If no attrib has been set NULL will be returned. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level media level index + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * Returns: Pointer to sidin or NULL. + */ +const char* sdp_attr_get_x_sidin (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num) +{ + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, + SDP_ATTR_X_SIDIN, inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s X-sidin attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (NULL); + } else { + if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) { + SDP_PRINT("%s Stream X-sidin attr field is :%s ", + sdp_p->debug_str, + attr_p->attr.stream_data.x_sidin); + } + return (attr_p->attr.stream_data.x_sidin); + } +} + +/* Function: sdp_attr_get_x_sidout + * Description: Returns the attribute parameter from the a=X-sidout:<> + * line. If no attrib has been set NULL will be returned. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level media level index + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * Returns: Pointer to sidout or NULL. + */ +const char* sdp_attr_get_x_sidout (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num) +{ + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, + SDP_ATTR_X_SIDOUT, inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s X-sidout attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (NULL); + } else { + if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) { + SDP_PRINT("%s Stream X-sidout attr field is :%s ", + sdp_p->debug_str, + attr_p->attr.stream_data.x_sidout); + } + return (attr_p->attr.stream_data.x_sidout); + } +} + +/* Function: sdp_attr_get_x_confid + * Description: Returns the attribute parameter from the a=X-confid:<> + * line. If no attrib has been set NULL will be returned. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level media level index + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * Returns: Pointer to confid or NULL. + */ +const char* sdp_attr_get_x_confid (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num) +{ + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, + SDP_ATTR_X_CONFID, inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s X-confid attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (NULL); + } else { + if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) { + SDP_PRINT("%s Stream X-confid attr field is :%s ", + sdp_p->debug_str, + attr_p->attr.stream_data.x_confid); + } + return (attr_p->attr.stream_data.x_confid); + } +} + +/* Function: sdp_get_source_filter_mode + * Description: Gets the filter mode in internal representation + * Parameters: sdp_p The SDP handle which contains the attributes + * level SDP_SESSION_LEVEL/m-line number + * inst_num The attribute instance number + * Returns: Filter mode (incl/excl/not present) + */ +sdp_src_filter_mode_e +sdp_get_source_filter_mode (sdp_t *sdp_p, uint16_t level, uint8_t cap_num, + uint16_t inst_num) +{ + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, + SDP_ATTR_SOURCE_FILTER, inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s Source filter attribute, level %u, " + "instance %u not found", sdp_p->debug_str, + (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (SDP_FILTER_MODE_NOT_PRESENT); + } + return (attr_p->attr.source_filter.mode); +} + +/* Function: sdp_get_filter_destination_attributes + * Description: Gets the destination address parameters + * Parameters: Network type (optional), destination address type + * (optional), and destination address (mandatory) variables + * which gets updated. + * Returns: SDP_SUCCESS or SDP_INVALID_PARAMETER/SDP_INVALID_SDP_PTR + */ +sdp_result_e +sdp_get_filter_destination_attributes (sdp_t *sdp_p, uint16_t level, uint8_t cap_num, + uint16_t inst_num, sdp_nettype_e *nettype, + sdp_addrtype_e *addrtype, + char *dest_addr) +{ + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, + SDP_ATTR_SOURCE_FILTER, inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s Source filter attribute, level %u instance %u " + "not found", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_PARAMETER); + } + if (nettype) { + *nettype = attr_p->attr.source_filter.nettype; + } + if (addrtype) { + *addrtype = attr_p->attr.source_filter.addrtype; + } + sstrncpy(dest_addr, attr_p->attr.source_filter.dest_addr, + SDP_MAX_STRING_LEN+1); + + return (SDP_SUCCESS); +} + +/* Function: sdp_get_filter_source_address_count + * Description: Gets the number of source addresses in the list + * Parameters: sdp_p The SDP handle which contains the attributes + * level SDP_SESSION_LEVEL/m-line number + * inst_num The attribute instance number + * Returns: Source-list count + */ + +int32_t +sdp_get_filter_source_address_count (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num) +{ + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, + SDP_ATTR_SOURCE_FILTER, inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s Source filter attribute, level %u instance %u " + "not found", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_VALUE); + } + return (attr_p->attr.source_filter.num_src_addr); +} + +/* Function: sdp_get_filter_source_address + * Description: Gets one of the source address that is indexed by the user + * Parameters: sdp_p The SDP handle which contains the attributes + * level SDP_SESSION_LEVEL/m-line number + * inst_num The attribute instance number + * src_addr_id User provided index (value in range between + * 0 to (SDP_MAX_SRC_ADDR_LIST-1) which obtains + * the source addr corresponding to it. + * src_addr The user provided variable which gets updated + * with source address corresponding to the index + */ +sdp_result_e +sdp_get_filter_source_address (sdp_t *sdp_p, uint16_t level, uint8_t cap_num, + uint16_t inst_num, uint16_t src_addr_id, + char *src_addr) +{ + sdp_attr_t *attr_p; + + src_addr[0] = '\0'; + + if (src_addr_id >= SDP_MAX_SRC_ADDR_LIST) { + return (SDP_INVALID_PARAMETER); + } + attr_p = sdp_find_attr(sdp_p, level, cap_num, + SDP_ATTR_SOURCE_FILTER, inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s Source filter attribute, level %u instance %u " + "not found", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_PARAMETER); + } + if (src_addr_id >= attr_p->attr.source_filter.num_src_addr) { + return (SDP_INVALID_PARAMETER); + } + sstrncpy(src_addr, attr_p->attr.source_filter.src_list[src_addr_id], + SDP_MAX_STRING_LEN+1); + + return (SDP_SUCCESS); +} + +sdp_rtcp_unicast_mode_e +sdp_get_rtcp_unicast_mode(sdp_t *sdp_p, uint16_t level, uint8_t cap_num, + uint16_t inst_num) +{ + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, + SDP_ATTR_RTCP_UNICAST, inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s RTCP Unicast attribute, level %u, " + "instance %u not found", sdp_p->debug_str, + (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (SDP_RTCP_UNICAST_MODE_NOT_PRESENT); + } + return ((sdp_rtcp_unicast_mode_e)attr_p->attr.u32_val); +} + + +/* Function: sdp_attr_get_sdescriptions_tag + * Description: Returns the value of the sdescriptions tag + * parameter specified for the given attribute. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * Returns: Tag value or SDP_INVALID_VALUE (-2) if error encountered. + */ + +int32_t +sdp_attr_get_sdescriptions_tag (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num) +{ + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, cap_num, + SDP_ATTR_SDESCRIPTIONS, inst_num); + + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s srtp attribute tag, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return SDP_INVALID_VALUE; + } else { + return attr_p->attr.srtp_context.tag; + } +} + +/* Function: sdp_attr_get_sdescriptions_crypto_suite + * Description: Returns the value of the sdescriptions crypto suite + * parameter specified for the given attribute. Note that + * this is a common api for both version 2 and version 9 + * sdescriptions. It has no knowledge which version is being + * used so it will first try to find if a version 2 sdescriptions + * attribute is present. If it is, return the suite. If it's not, + * try to find the version 9. This assumes you cannot have both + * versions in the same SDP. + * + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * Returns: SDP_SRTP_UNKNOWN_CRYPTO_SUITE is returned if an error was + * encountered otherwise the crypto suite is returned. + */ + +sdp_srtp_crypto_suite_t +sdp_attr_get_sdescriptions_crypto_suite (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num) +{ + sdp_attr_t *attr_p; + + + /* Try version 2 first */ + attr_p = sdp_find_attr(sdp_p, level, cap_num, + SDP_ATTR_SRTP_CONTEXT, inst_num); + + if (attr_p == NULL) { + /* There's no version 2 so now try version 9 */ + attr_p = sdp_find_attr(sdp_p, level, cap_num, + SDP_ATTR_SDESCRIPTIONS, inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s srtp attribute suite, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return SDP_SRTP_UNKNOWN_CRYPTO_SUITE; + } + } + + return attr_p->attr.srtp_context.suite; + +} + +/* Function: sdp_attr_get_sdescriptions_key + * Description: Returns the value of the sdescriptions master key + * parameter specified for the given attribute. Note that + * this is a common api for both version 2 and version 9 + * sdescriptions. It has no knowledge which version is being + * used so it will first try to find if a version 2 sdescriptions + * attribute is present. If it is, return the key. If it's not, + * try to find the version 9. This assumes you cannot have both + * versions in the same SDP. + * + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * Returns: NULL if error encountered or master key salt string + */ + +const char* +sdp_attr_get_sdescriptions_key (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num) +{ + sdp_attr_t *attr_p; + + /* Try version 2 first */ + attr_p = sdp_find_attr(sdp_p, level, cap_num, + SDP_ATTR_SRTP_CONTEXT, inst_num); + + if (attr_p == NULL) { + /* Couldn't find version 2 now try version 9 */ + attr_p = sdp_find_attr(sdp_p, level, cap_num, + SDP_ATTR_SDESCRIPTIONS, inst_num); + + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s srtp attribute key, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return NULL; + } + } + + return (char*)attr_p->attr.srtp_context.master_key; +} + + +/* Function: sdp_attr_get_sdescriptions_salt + * Description: Returns the value of the sdescriptions master salt + * parameter specified for the given attribute. Note that + * this is a common api for both version 2 and version 9 + * sdescriptions. It has no knowledge which version is being + * used so it will first try to find if a version 2 sdescriptions + * attribute is present. If it is, return the salt. If it's not, + * try to find the version 9. This assumes you cannot have both + * versions in the same SDP. + * + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * Returns: NULL if error encountered or master key salt string + */ + +const char* +sdp_attr_get_sdescriptions_salt (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num) +{ + sdp_attr_t *attr_p; + + /* Try version 2 first */ + attr_p = sdp_find_attr(sdp_p, level, cap_num, + SDP_ATTR_SRTP_CONTEXT, inst_num); + + if (attr_p == NULL) { + /* Couldn't find version 2 now try version 9 */ + attr_p = sdp_find_attr(sdp_p, level, cap_num, + SDP_ATTR_SDESCRIPTIONS, inst_num); + + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s srtp attribute salt, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return NULL; + } + } + + return (char*) attr_p->attr.srtp_context.master_salt; + +} + + + +/* Function: sdp_attr_get_sdescriptions_lifetime + * Description: Returns the value of the sdescriptions lifetime + * parameter specified for the given attribute.Note that + * this is a common api for both version 2 and version 9 + * sdescriptions. It has no knowledge which version is being + * used so it will first try to find if a version 2 sdescriptions + * attribute is present. If it is, return the lifetime. If it's + * not, try to find the version 9. This assumes you cannot have + * both versions in the same SDP. + * + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * Returns: NULL if error encountered or lifetime string + */ + +const char* +sdp_attr_get_sdescriptions_lifetime (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num) +{ + sdp_attr_t *attr_p; + + /* Try version 2 first. */ + attr_p = sdp_find_attr(sdp_p, level, cap_num, + SDP_ATTR_SRTP_CONTEXT, inst_num); + + if (attr_p == NULL) { + /* Couldn't find version 2 now try version 9 */ + attr_p = sdp_find_attr(sdp_p, level, cap_num, + SDP_ATTR_SDESCRIPTIONS, inst_num); + + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s srtp attribute lifetime, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return NULL; + } + } + + return (char*)attr_p->attr.srtp_context.master_key_lifetime; + +} + +/* Function: sdp_attr_get_sdescriptions_mki + * Description: Returns the value of the sdescriptions MKI value and length + * parameter of the specified attribute instance. Note that + * this is a common api for both version 2 and version 9 + * sdescriptions. It has no knowledge which version is being + * used so it will first try to find if a version 2 sdescriptions + * attribute is present. If it is, return the MKI. If it's + * not, try to find version 9. This assumes you cannot have + * both versions in the same SDP. + * + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * mki_value application provided pointer that on exit + * is set to the MKI value string if one exists. + * mki_length application provided pointer that on exit + * is set to the MKI length if one exists. + * Returns: SDP_SUCCESS no errors encountered otherwise sdp error + * based upon the specific error. + */ + +sdp_result_e +sdp_attr_get_sdescriptions_mki (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num, + const char **mki_value, + uint16_t *mki_length) +{ + sdp_attr_t *attr_p; + + *mki_value = NULL; + *mki_length = 0; + + /* Try version 2 first */ + attr_p = sdp_find_attr(sdp_p, level, cap_num, + SDP_ATTR_SRTP_CONTEXT, inst_num); + + if (attr_p == NULL) { + /* Couldn't find version 2 now try version 9 */ + attr_p = sdp_find_attr(sdp_p, level, cap_num, + SDP_ATTR_SDESCRIPTIONS, inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s srtp attribute MKI, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return SDP_INVALID_PARAMETER; + } + } + + *mki_value = (char*)attr_p->attr.srtp_context.mki; + *mki_length = attr_p->attr.srtp_context.mki_size_bytes; + return SDP_SUCCESS; + +} + + +/* Function: sdp_attr_get_sdescriptions_session_params + * Description: Returns the unparsed session parameters string. Note that + * this is a common api for both version 2 and version 9 + * sdescriptions. It has no knowledge which version is being + * used so it will first try to find if a version 2 sdescriptions + * attribute is present. If it is, return session parameters. If + * it's not, try to find version 9. This assumes you cannot have + * both versions in the same SDP. + * + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * Returns: NULL if no session parameters were received in the sdp, + * otherwise returns a pointer to the start of the session + * parameters string. Note that the calling function should + * not free the returned pointer. + */ + +const char* +sdp_attr_get_sdescriptions_session_params (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num) +{ + sdp_attr_t *attr_p; + + /* Try version 2 first */ + attr_p = sdp_find_attr(sdp_p, level, cap_num, + SDP_ATTR_SRTP_CONTEXT, inst_num); + + if (attr_p == NULL) { + /* Couldn't find version 2 try version 9 */ + attr_p = sdp_find_attr(sdp_p, level, cap_num, + SDP_ATTR_SDESCRIPTIONS, inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s srtp attribute session params, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return NULL; + } + } + + return attr_p->attr.srtp_context.session_parameters; +} + + +/* Function: sdp_attr_get_sdescriptions_key_size + * Description: Returns the master key size. Note that + * this is a common api for both version 2 and version 9 + * sdescriptions. It has no knowledge which version is being + * used so it will first try to find if a version 2 sdescriptions + * attribute is present. If it is, return key size. If + * it's not, try to find version 9. This assumes you cannot have + * both versions in the same SDP. + * + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * Returns: 0 (SDP_SDESCRIPTIONS_KEY_SIZE_UNKNOWN) if error was + * encountered, otherwise key size. + */ + +unsigned char +sdp_attr_get_sdescriptions_key_size (sdp_t *sdp_p, + uint16_t level, + uint8_t cap_num, + uint16_t inst_num) +{ + + sdp_attr_t *attr_p; + + /* Try version 2 first */ + attr_p = sdp_find_attr(sdp_p, level, cap_num, + SDP_ATTR_SRTP_CONTEXT, inst_num); + + if (attr_p == NULL) { + /* Couldn't find version 2 now try version 9 */ + attr_p = sdp_find_attr(sdp_p, level, cap_num, + SDP_ATTR_SDESCRIPTIONS, inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s srtp attribute MKI, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return SDP_SDESCRIPTIONS_KEY_SIZE_UNKNOWN; + } + } + + return attr_p->attr.srtp_context.master_key_size_bytes; + +} + + +/* Function: sdp_attr_get_sdescriptions_salt_size + * Description: Returns the salt key size. Note that + * this is a common api for both version 2 and version 9 + * sdescriptions. It has no knowledge which version is being + * used so it will first try to find if a version 2 sdescriptions + * attribute is present. If it is, return salt size. If + * it's not, try to find version 9. This assumes you cannot have + * both versions in the same SDP. + * + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * Returns: 0 (SDP_SDESCRIPTIONS_KEY_SIZE_UNKNOWN) if error was + * encountered, otherwise salt size. + */ + +unsigned char +sdp_attr_get_sdescriptions_salt_size (sdp_t *sdp_p, + uint16_t level, + uint8_t cap_num, + uint16_t inst_num) +{ + + sdp_attr_t *attr_p; + + /* Try version 2 first */ + attr_p = sdp_find_attr(sdp_p, level, cap_num, + SDP_ATTR_SRTP_CONTEXT, inst_num); + + if (attr_p == NULL) { + /* Couldn't find version 2 now try version 9 */ + attr_p = sdp_find_attr(sdp_p, level, cap_num, + SDP_ATTR_SDESCRIPTIONS, inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s srtp attribute MKI, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return SDP_SDESCRIPTIONS_KEY_SIZE_UNKNOWN; + } + } + + return attr_p->attr.srtp_context.master_salt_size_bytes; + +} + + +/* Function: sdp_attr_get_srtp_crypto_selection_flags + * Description: Returns the selection flags. Note that + * this is a common api for both version 2 and version 9 + * sdescriptions. It has no knowledge which version is being + * used so it will first try to find if a version 2 sdescriptions + * attribute is present. If it is, return selection flags. If + * it's not, try to find version 9. This assumes you cannot have + * both versions in the same SDP. + * Currently only necessary for MGCP. + * + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * cap_num The capability number associated with the + * attribute if any. If none, should be zero. + * inst_num The attribute instance number to check. + * Returns: 0 (SDP_SRTP_CRYPTO_SELECTION_FLAGS_UNKNOWN) if error was + * encountered, otherwise selection flags. + */ + +unsigned long +sdp_attr_get_srtp_crypto_selection_flags (sdp_t *sdp_p, + uint16_t level, + uint8_t cap_num, + uint16_t inst_num) +{ + + + sdp_attr_t *attr_p; + + /* Try version 2 first */ + attr_p = sdp_find_attr(sdp_p, level, cap_num, + SDP_ATTR_SRTP_CONTEXT, inst_num); + + if (attr_p == NULL) { + /* Couldn't find version 2 now try version 9 */ + attr_p = sdp_find_attr(sdp_p, level, cap_num, + SDP_ATTR_SDESCRIPTIONS, inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s srtp attribute MKI, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return SDP_SRTP_CRYPTO_SELECTION_FLAGS_UNKNOWN; + } + } + + return attr_p->attr.srtp_context.selection_flags; + +} + + + +/* Function: sdp_find_rtcp_fb_attr + * Description: Helper to find the nth instance of a rtcp-fb attribute of + * the specified feedback type. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * payload_type The payload to get the attribute for + * fb_type The feedback type to look for. + * inst_num The attribute instance number to check. + * Returns: Pointer to the attribute, or NULL if not found. + */ + +sdp_attr_t * +sdp_find_rtcp_fb_attr (sdp_t *sdp_p, + uint16_t level, + uint16_t payload_type, + sdp_rtcp_fb_type_e fb_type, + uint16_t inst_num) +{ + uint16_t attr_count=0; + sdp_mca_t *mca_p; + sdp_attr_t *attr_p; + + mca_p = sdp_find_media_level(sdp_p, level); + if (!mca_p) { + return (NULL); + } + for (attr_p = mca_p->media_attrs_p; attr_p; attr_p = attr_p->next_p) { + if (attr_p->type == SDP_ATTR_RTCP_FB && + (attr_p->attr.rtcp_fb.payload_num == payload_type || + attr_p->attr.rtcp_fb.payload_num == SDP_ALL_PAYLOADS) && + attr_p->attr.rtcp_fb.feedback_type == fb_type) { + attr_count++; + if (attr_count == inst_num) { + return (attr_p); + } + } + } + return NULL; +} + +/* Function: sdp_attr_get_rtcp_fb_ack + * Description: Returns the value of the rtcp-fb:...ack attribute + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * payload_type The payload to get the attribute for + * inst_num The attribute instance number to check. + * Returns: ACK type (SDP_RTCP_FB_ACK_NOT_FOUND if not present) + */ +sdp_rtcp_fb_ack_type_e +sdp_attr_get_rtcp_fb_ack(sdp_t *sdp_p, uint16_t level, uint16_t payload_type, uint16_t inst) +{ + sdp_attr_t *attr_p; + + attr_p = sdp_find_rtcp_fb_attr(sdp_p, level, payload_type, + SDP_RTCP_FB_ACK, inst); + if (!attr_p) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s rtcp-fb attribute, level %u, pt %u, " + "instance %u not found.", sdp_p->debug_str, (unsigned)level, + (unsigned)payload_type, (unsigned)inst); + } + sdp_p->conf_p->num_invalid_param++; + return SDP_RTCP_FB_ACK_NOT_FOUND; + } + return (attr_p->attr.rtcp_fb.param.ack); +} + +/* Function: sdp_attr_get_rtcp_fb_nack + * Description: Returns the value of the rtcp-fb:...nack attribute + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * payload_type The payload to get the attribute for + * inst_num The attribute instance number to check. + * Returns: NACK type (SDP_RTCP_FB_NACK_NOT_FOUND if not present) + */ +sdp_rtcp_fb_nack_type_e +sdp_attr_get_rtcp_fb_nack(sdp_t *sdp_p, uint16_t level, uint16_t payload_type, uint16_t inst) +{ + sdp_attr_t *attr_p; + + attr_p = sdp_find_rtcp_fb_attr(sdp_p, level, payload_type, + SDP_RTCP_FB_NACK, inst); + if (!attr_p) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s rtcp-fb attribute, level %u, pt %u, " + "instance %u not found.", sdp_p->debug_str, (unsigned)level, + (unsigned)payload_type, (unsigned)inst); + } + sdp_p->conf_p->num_invalid_param++; + return SDP_RTCP_FB_NACK_NOT_FOUND; + } + return (attr_p->attr.rtcp_fb.param.nack); +} + +/* Function: sdp_attr_get_rtcp_fb_trr_int + * Description: Returns the value of the rtcp-fb:...trr-int attribute + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * payload_type The payload to get the attribute for + * inst_num The attribute instance number to check. + * Returns: trr-int interval (0xFFFFFFFF if not found) + */ +uint32_t +sdp_attr_get_rtcp_fb_trr_int(sdp_t *sdp_p, uint16_t level, + uint16_t payload_type, uint16_t inst) +{ + sdp_attr_t *attr_p; + + attr_p = sdp_find_rtcp_fb_attr(sdp_p, level, payload_type, + SDP_RTCP_FB_TRR_INT, inst); + if (!attr_p) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s rtcp-fb attribute, level %u, pt %u, " + "instance %u not found.", sdp_p->debug_str, (unsigned)level, + (unsigned)payload_type, (unsigned)inst); + } + sdp_p->conf_p->num_invalid_param++; + return 0xFFFFFFFF; + } + return (attr_p->attr.rtcp_fb.param.trr_int); +} + +/* Function: sdp_attr_get_rtcp_fb_remb_enabled + * Description: Returns true if rtcp-fb:...goog-remb attribute exists + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * payload_type The payload to get the attribute for + * Returns: true if rtcp-fb:...goog-remb exists + */ +tinybool +sdp_attr_get_rtcp_fb_remb_enabled(sdp_t *sdp_p, + uint16_t level, + uint16_t payload_type) +{ + sdp_attr_t *attr_p; + + attr_p = sdp_find_rtcp_fb_attr(sdp_p, level, payload_type, + SDP_RTCP_FB_REMB, + 1); // always check for 1st instance + return (attr_p? TRUE : FALSE); // either exists or not +} + +/* Function: sdp_attr_get_rtcp_fb_transport_cc_enabled + * Description: Returns true if rtcp-fb:...transport-cc attribute exists + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * payload_type The payload to get the attribute for + * Returns: true if rtcp-fb:...transport-cc exists + */ +tinybool +sdp_attr_get_rtcp_fb_transport_cc_enabled(sdp_t *sdp_p, + uint16_t level, + uint16_t payload_type) +{ + sdp_attr_t *attr_p; + + attr_p = sdp_find_rtcp_fb_attr(sdp_p, level, payload_type, + SDP_RTCP_FB_TRANSPORT_CC, + 1); // always check for 1st instance + return (attr_p? TRUE : FALSE); // either exists or not +} + +/* Function: sdp_attr_get_rtcp_fb_ccm + * Description: Returns the value of the rtcp-fb:...ccm attribute + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * payload_type The payload to get the attribute for + * inst_num The attribute instance number to check. + * Returns: CCM type (SDP_RTCP_FB_CCM_NOT_FOUND if not present) + */ +sdp_rtcp_fb_ccm_type_e +sdp_attr_get_rtcp_fb_ccm(sdp_t *sdp_p, uint16_t level, uint16_t payload_type, uint16_t inst) +{ + sdp_attr_t *attr_p; + + attr_p = sdp_find_rtcp_fb_attr(sdp_p, level, payload_type, + SDP_RTCP_FB_CCM, inst); + if (!attr_p) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s rtcp-fb attribute, level %u, pt %u, " + "instance %u not found.", sdp_p->debug_str, (unsigned)level, + (unsigned)payload_type, (unsigned)inst); + } + sdp_p->conf_p->num_invalid_param++; + return SDP_RTCP_FB_CCM_NOT_FOUND; + } + return (attr_p->attr.rtcp_fb.param.ccm); +} + +/* Function: sdp_attr_set_rtcp_fb_ack + * Description: Sets the value of an rtcp-fb:...ack attribute + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to set the attribute. + * payload_type The value to set the payload type to for + * this attribute. Can be SDP_ALL_PAYLOADS. + * inst_num The attribute instance number to check. + * type The ack type to indicate + * Returns: SDP_SUCCESS Attribute param was set successfully. + * SDP_INVALID_PARAMETER Specified attribute is not defined. + */ +sdp_result_e +sdp_attr_set_rtcp_fb_ack(sdp_t *sdp_p, uint16_t level, uint16_t payload_type, uint16_t inst, + sdp_rtcp_fb_ack_type_e type) +{ + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, 0, SDP_ATTR_RTCP_FB, inst); + if (!attr_p) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s rtcp_fb ack attribute, level %u " + "instance %u not found.", sdp_p->debug_str, (unsigned)level, + (unsigned)inst); + } + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_PARAMETER); + } + + attr_p->attr.rtcp_fb.payload_num = payload_type; + attr_p->attr.rtcp_fb.feedback_type = SDP_RTCP_FB_ACK; + attr_p->attr.rtcp_fb.param.ack = type; + attr_p->attr.rtcp_fb.extra[0] = '\0'; + return (SDP_SUCCESS); +} + + +/* Function: sdp_attr_set_rtcp_fb_nack + * Description: Sets the value of an rtcp-fb:...nack attribute + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to set the attribute. + * payload_type The value to set the payload type to for + * this attribute. Can be SDP_ALL_PAYLOADS. + * inst_num The attribute instance number to check. + * type The nack type to indicate + * Returns: SDP_SUCCESS Attribute param was set successfully. + * SDP_INVALID_PARAMETER Specified attribute is not defined. + */ +sdp_result_e +sdp_attr_set_rtcp_fb_nack(sdp_t *sdp_p, uint16_t level, uint16_t payload_type, uint16_t inst, + sdp_rtcp_fb_nack_type_e type) +{ + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, 0, SDP_ATTR_RTCP_FB, inst); + if (!attr_p) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s rtcp_fb nack attribute, level %u " + "instance %u not found.", sdp_p->debug_str, (unsigned)level, + (unsigned)inst); + } + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_PARAMETER); + } + + attr_p->attr.rtcp_fb.payload_num = payload_type; + attr_p->attr.rtcp_fb.feedback_type = SDP_RTCP_FB_NACK; + attr_p->attr.rtcp_fb.param.nack = type; + attr_p->attr.rtcp_fb.extra[0] = '\0'; + return (SDP_SUCCESS); +} + +/* Function: sdp_attr_set_rtcp_fb_trr_int + * Description: Sets the value of an rtcp-fb:...trr-int attribute + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to set the attribute. + * payload_type The value to set the payload type to for + * this attribute. Can be SDP_ALL_PAYLOADS. + * inst_num The attribute instance number to check. + * interval The interval time to indicate + * Returns: SDP_SUCCESS Attribute param was set successfully. + * SDP_INVALID_PARAMETER Specified attribute is not defined. + */ +sdp_result_e +sdp_attr_set_rtcp_fb_trr_int(sdp_t *sdp_p, uint16_t level, uint16_t payload_type, + uint16_t inst, uint32_t interval) +{ + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, 0, SDP_ATTR_RTCP_FB, inst); + if (!attr_p) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s rtcp_fb trr-int attribute, level %u " + "instance %u not found.", sdp_p->debug_str, (unsigned)level, + (unsigned)inst); + } + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_PARAMETER); + } + + attr_p->attr.rtcp_fb.payload_num = payload_type; + attr_p->attr.rtcp_fb.feedback_type = SDP_RTCP_FB_TRR_INT; + attr_p->attr.rtcp_fb.param.trr_int = interval; + attr_p->attr.rtcp_fb.extra[0] = '\0'; + return (SDP_SUCCESS); +} + +/* Function: sdp_attr_set_rtcp_fb_remb + * Description: Sets the value of an rtcp-fb:...goog-remb attribute + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to set the attribute. + * payload_type The value to set the payload type to for + * this attribute. Can be SDP_ALL_PAYLOADS. + * inst_num The attribute instance number to check. + * Returns: SDP_SUCCESS Attribute param was set successfully. + * SDP_INVALID_PARAMETER Specified attribute is not defined. + */ +sdp_result_e +sdp_attr_set_rtcp_fb_remb(sdp_t *sdp_p, uint16_t level, uint16_t payload_type, + uint16_t inst) +{ + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, 0, SDP_ATTR_RTCP_FB, inst); + if (!attr_p) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s rtcp_fb goog-remb attribute, level %u " + "instance %u not found.", sdp_p->debug_str, (unsigned)level, + (unsigned)inst); + } + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_PARAMETER); + } + + attr_p->attr.rtcp_fb.payload_num = payload_type; + attr_p->attr.rtcp_fb.feedback_type = SDP_RTCP_FB_REMB; + return (SDP_SUCCESS); +} + +/* Function: sdp_attr_set_rtcp_fb_transport_cc + * Description: Sets the value of an rtcp-fb:...transport-cc attribute + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to set the attribute. + * payload_type The value to set the payload type to for + * this attribute. Can be SDP_ALL_PAYLOADS. + * inst_num The attribute instance number to check. + * Returns: SDP_SUCCESS Attribute param was set successfully. + * SDP_INVALID_PARAMETER Specified attribute is not defined. + */ +sdp_result_e +sdp_attr_set_rtcp_fb_transport_cc(sdp_t *sdp_p, uint16_t level, uint16_t payload_type, + uint16_t inst) +{ + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, 0, SDP_ATTR_RTCP_FB, inst); + if (!attr_p) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s rtcp_fb transport-cc attribute, level %u " + "instance %u not found.", sdp_p->debug_str, (unsigned)level, + (unsigned)inst); + } + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_PARAMETER); + } + + attr_p->attr.rtcp_fb.payload_num = payload_type; + attr_p->attr.rtcp_fb.feedback_type = SDP_RTCP_FB_TRANSPORT_CC; + return (SDP_SUCCESS); +} + +/* Function: sdp_attr_set_rtcp_fb_ccm + * Description: Sets the value of an rtcp-fb:...ccm attribute + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to set the attribute. + * payload_type The value to set the payload type to for + * this attribute. Can be SDP_ALL_PAYLOADS. + * inst_num The attribute instance number to check. + * type The ccm type to indicate + * Returns: SDP_SUCCESS Attribute param was set successfully. + * SDP_INVALID_PARAMETER Specified attribute is not defined. + */ +sdp_result_e +sdp_attr_set_rtcp_fb_ccm(sdp_t *sdp_p, uint16_t level, uint16_t payload_type, uint16_t inst, + sdp_rtcp_fb_ccm_type_e type) +{ + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, 0, SDP_ATTR_RTCP_FB, inst); + if (!attr_p) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s rtcp_fb ccm attribute, level %u " + "instance %u not found.", sdp_p->debug_str, (unsigned)level, + (unsigned)inst); + } + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_PARAMETER); + } + attr_p->attr.rtcp_fb.payload_num = payload_type; + attr_p->attr.rtcp_fb.feedback_type = SDP_RTCP_FB_CCM; + attr_p->attr.rtcp_fb.param.ccm = type; + attr_p->attr.rtcp_fb.extra[0] = '\0'; + return (SDP_SUCCESS); +} + +/* Function: sdp_attr_get_extmap_uri + * Description: Returns a pointer to the value of the encoding name + * parameter specified for the given attribute. Value is + * returned as a const ptr and so cannot be modified by the + * application. If the given attribute is not defined, NULL + * will be returned. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * inst_num The attribute instance number to check. + * Returns: Codec value or SDP_CODEC_INVALID. + */ +const char *sdp_attr_get_extmap_uri(sdp_t *sdp_p, uint16_t level, + uint16_t inst_num) +{ + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, 0, SDP_ATTR_EXTMAP, inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s extmap attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return (NULL); + } else { + return (attr_p->attr.extmap.uri); + } +} + +/* Function: sdp_attr_get_extmap_id + * Description: Returns the id of the extmap specified for the given + * attribute. If the given attribute is not defined, 0xFFFF + * will be returned. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to check for the attribute. + * inst_num The attribute instance number to check. + * Returns: The id of the extmap attribute. + */ +uint16_t sdp_attr_get_extmap_id(sdp_t *sdp_p, uint16_t level, + uint16_t inst_num) +{ + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, 0, SDP_ATTR_EXTMAP, inst_num); + if (attr_p == NULL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s extmap attribute, level %u instance %u " + "not found.", sdp_p->debug_str, (unsigned)level, (unsigned)inst_num); + } + sdp_p->conf_p->num_invalid_param++; + return 0xFFFF; + } else { + return (attr_p->attr.extmap.id); + } +} + +/* Function: sdp_attr_set_extmap + * Description: Sets the value of an rtcp-fb:...ccm attribute + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * level The level to set the attribute. + * id The id to set the attribute. + * uri The uri to set the attribute. + * inst The attribute instance number to check. + * Returns: SDP_SUCCESS Attribute param was set successfully. + * SDP_INVALID_PARAMETER Specified attribute is not defined. + */ +sdp_result_e +sdp_attr_set_extmap(sdp_t *sdp_p, uint16_t level, uint16_t id, const char* uri, uint16_t inst) +{ + sdp_attr_t *attr_p; + + attr_p = sdp_find_attr(sdp_p, level, 0, SDP_ATTR_EXTMAP, inst); + if (!attr_p) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s extmap attribute, level %u " + "instance %u not found.", sdp_p->debug_str, (unsigned)level, + (unsigned)inst); + } + sdp_p->conf_p->num_invalid_param++; + return (SDP_INVALID_PARAMETER); + } + + attr_p->attr.extmap.id = id; + sstrncpy(attr_p->attr.extmap.uri, uri, SDP_MAX_STRING_LEN+1); + return (SDP_SUCCESS); +} + +const char *sdp_attr_get_msid_identifier(sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst) +{ + sdp_attr_t *attr_p = sdp_find_attr(sdp_p, level, cap_num, + SDP_ATTR_MSID, inst); + if (!attr_p) { + return NULL; + } + return attr_p->attr.msid.identifier; +} + +const char *sdp_attr_get_msid_appdata(sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst) +{ + sdp_attr_t *attr_p = sdp_find_attr(sdp_p, level, cap_num, + SDP_ATTR_MSID, inst); + if (!attr_p) { + return NULL; + } + return attr_p->attr.msid.appdata; +} diff --git a/third_party/sipcc/sdp_base64.c b/third_party/sipcc/sdp_base64.c new file mode 100644 index 0000000000..80f1eb52da --- /dev/null +++ b/third_party/sipcc/sdp_base64.c @@ -0,0 +1,403 @@ +/* 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 "sdp_base64.h" + +/* + * Local definitions for Base64 to Raw table entries. + */ +#define INVALID_CHAR 0xFF /* Character not in supported Base64 set */ +#define WHITE_SPACE 0xFE /* Space, tab, newline, etc character */ +#define PADDING 0xFD /* The character '=' */ + +#define PAD_CHAR '=' /* The character '=' */ + +/* Maximum length of a base64 encoded line */ +#define MAX_BASE64_LINE_LENGTH 76 + +/* + * base64_result_table + * String table for translating base64 error codes into human + * understanable strings. + */ +char *base64_result_table[BASE64_RESULT_MAX] = +{ + "Base64 successful", + "Base64 Buffer Overrun", + "Base64 Bad Data", + "Base64 Bad Padding", + "Base64 Bad Block Size" +}; + +/* + * base64_to_raw_table + * Heart of the Base64 decoding algorithm. Lookup table to convert + * the Base64 characters into their specified representative values. + * Invalid characters are marked with 0xFF, white space characters + * are marked with 0xFE, and the special pading character is marked + * with 0xFD. + */ +unsigned char base64_to_raw_table[128] = +{ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, /* 0-9 */ + 0xFE, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* 10-19 */ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* 20-29 */ + 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* 30-39 */ + 0xFF, 0xFF, 0xFF, 62, 0xFF, 0xFF, 0xFF, 63, 52, 53, /* 40-49 */ + 54, 55, 56, 57, 58, 59, 60, 61, 0xFF, 0xFF, /* 50-59 */ + 0xFF, 0xFD, 0xFF, 0xFF, 0xFF, 0, 1, 2, 3, 4, /* 60-69 */ + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, /* 70-79 */ + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, /* 80-89 */ + 25, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 26, 27, 28, /* 90-99 */ + 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, /* 100-109 */ + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, /* 110-119 */ + 49, 50, 51, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF /* 120-127 */ +}; + +unsigned char raw_to_base64_table[64] = +{ + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', /* 0-9 */ + 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', /* 10-19 */ + 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', /* 20-29 */ + 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', /* 30-39 */ + 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', /* 40-49 */ + 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', /* 50-59 */ + '8', '9', '+', '/' /* 60-63 */ +}; + +/* + * base64_encode_size_bytes + * + * DESCRIPTION + * Estimates the size of buffer required for holding the result of + * encoding data of size raw_size_bytes. + * + * PARAMETERS + * raw_size_bytes = Estimated size of the un-encoded data in bytes. + * + * RETURN VALUE + * The size of destination buffer to use for encoding in bytes. + */ +int base64_est_encode_size_bytes (int raw_size_bytes) +{ + int length; + + /* + * Find the number of bytes needed to represent the data + * using a 4/3 expansion ratio. That result must be + * rounded to the next higher multiple of four to account + * for padding. Then add in a term to account for any '\n's + * added. + */ + length = ((((raw_size_bytes * 4 + 2)/ 3) + 3) & ~(0x3)) + + raw_size_bytes / MAX_BASE64_LINE_LENGTH; + + return length; +} + +/* + * base64_decode_size_bytes + * + * DESCRIPTION + * Estimates the size of buffer required for holding the result of + * decoding data of size base64_size_bytes. + * + * PARAMETERS + * base64_size_bytes = Estimated size of the Base64 data in bytes. + * + * RETURN VALUE + * The size of destination buffer to use for decoding in bytes. + */ +int base64_est_decode_size_bytes (int base64_size_bytes) +{ + int length; + + length = (base64_size_bytes * 3 + 3) / 4; + return length; +} + +/* + * base64_encode + * + * DESCRIPTION + * Encode data pointed to by src into the buffer pointer to by dest + * using the Base64 algorithm. + * + * NOTE: No trailing '\n' character will be added. + * + * NOTE: As per specification, '\n' will be placed every 76 chars. + * + * PARAMETERS + * src = Pointer to the raw data to base64 encode. + * src_bytes = The number of bytes in the src buffer to encode. + * dest = Pointer to the destination buffer where the converted data + * will reside when complete. + * dest_bytes = Initially holds the size of the destination buffer + * but at completion holds the number of bytes converted. + * + * RETURN VALUE + * base64_success if the buffer was successfully converted, the + * appropriate error code otherwise. + * + * The dest parameter holds the converted data. + * + * The dest_bytes parameter holds the actual number of bytes converted. + */ +base64_result_t base64_encode(unsigned char *src, int src_bytes, unsigned char *dest, int *dest_bytes) +{ + int i, j=0; + int line_count = 0; + unsigned char index; /* index into base64 lookup table */ + int smax = src_bytes-2; /* only do full multiples of 3 */ + int dmax = *dest_bytes; /* destination maximum */ + + *dest_bytes = 0; + + /* Do full groups. Base64 must be done in blocks of 3 src bytes */ + for (i=0; i<smax; i+=3) { + /* Check to see if newline should be injected */ + if (line_count>=MAX_BASE64_LINE_LENGTH) { + if (j<dmax){ + dest[j++] = '\n'; + } else { + return BASE64_BUFFER_OVERRUN; + } + line_count = 0; + } + + line_count += 4; + + if ((j+3) < dmax) { + + /* Find mapping of upper 6 bits */ + index = (src[i] >> 2) & 0x3F; + dest[j++] = raw_to_base64_table[index]; + + /* bottom 2 bits of first word, high 4 bits of second word */ + index = ((src[i] << 4) & 0x30) | ((src[i+1] >> 4) & 0x0F); + dest[j++] = raw_to_base64_table[index]; + + /* bottom 4 bits of second word, high 2 bits of third word */ + index = ((src[i+1] << 2) & 0x3C) | ((src[i+2] >> 6) & 0x03); + dest[j++] = raw_to_base64_table[index]; + + /* bottom 6 bits of third word */ + index = src[i+2] & 0x3F; + dest[j++] = raw_to_base64_table[index]; + } else { + return BASE64_BUFFER_OVERRUN; + } + } + + /* Check to see if any more work must be done */ + if (i<src_bytes) { + + /* Check to see if a newline should be output */ + if (line_count>=MAX_BASE64_LINE_LENGTH) { + if (j<dmax){ + dest[j++] = '\n'; + } else { + return BASE64_BUFFER_OVERRUN; + } + line_count = 0; + } + + line_count += 4; + + /* Must fill another quantum */ + if (j+4>dmax) { + /* No room left in output buffer! */ + return BASE64_BUFFER_OVERRUN; + } + + /* Find mapping of upper 6 bits */ + index = (src[i] >> 2) & 0x3F; + dest[j++] = raw_to_base64_table[index]; + + /* check for another stragler */ + if ((i+1)<src_bytes) { + /* bottom 2 bits of first word, high 4 bits of second word */ + index = ((src[i] << 4) & 0x30) | ((src[i+1] >> 4) & 0x0F); + dest[j++] = raw_to_base64_table[index]; + + /* bottom 4 bits of second word */ + index = (src[i+1] << 2) & 0x3C; + dest[j++] = raw_to_base64_table[index]; + dest[j++] = PAD_CHAR; + } else { + /* bottom 2 bits of first word */ + index = (src[i] << 4) & 0x30; + dest[j++] = raw_to_base64_table[index]; + dest[j++] = PAD_CHAR; + dest[j++] = PAD_CHAR; + } + } + + *dest_bytes = j; + + return BASE64_SUCCESS; +} + +unsigned char base64_decode_get_raw(unsigned char index) +{ + /* only have 128 values, MSB must not be set! */ + if (index >= 128) { + return INVALID_CHAR; + } + return base64_to_raw_table[index]; +} + +/* + * base64_decode + * + * DESCRIPTION + * Decode data pointed to by src into the buffer pointer to by dest + * using the Base64 algorithm. + * + * PARAMETERS + * src = Pointer to the Base64 data to decode. + * src_bytes = The number of bytes in the src buffer to decode. + * dest = Pointer to the destination buffer where the converted data + * will reside when complete. + * dest_bytes = Initially holds the size of the destination buffer + * but at completion holds the number of bytes converted. + * + * RETURN VALUE + * base64_success if the buffer was successfully converted, the + * appropriate error code otherwise. + * + * The dest parameter holds the converted data. + * + * The dest_bytes parameter holds the actual number of bytes converted. + */ +base64_result_t base64_decode(unsigned char *src, int src_bytes, unsigned char *dest, int *dest_bytes) +{ + int i, j = 0; + int sindex = 0; /* Current NON-whitespace source + * index */ + int pad_count=0; /* Number of padding characters + * encountered */ + int dest_size_bytes = *dest_bytes; /* Save size of destination buffer */ + unsigned char cindex; /* The current Base64 character to + * process */ + unsigned char val; /* The value of the current Base64 + * character */ + + *dest_bytes = 0; + + for (i=0; i<src_bytes; i++) { + cindex = src[i]; + + val = base64_decode_get_raw(cindex); + if (val == INVALID_CHAR) { + /* Invalid base64 character */ + return BASE64_BAD_DATA; + } + + if (val == WHITE_SPACE) { + /* Ignore white space */ + continue; + } + + if (val == PADDING) { + /* we must be at the end-finish up */ + pad_count++; + if (++i<src_bytes) { + /* can have up to 2 pad chars */ + if (base64_decode_get_raw(src[i]) != PADDING) { + return BASE64_BAD_PADDING; + } + + if (++i<src_bytes) { + /* should not have any more padding! */ + return BASE64_BAD_PADDING; + } + + pad_count++; + } + + /* DONE! */ + break; + } + + /* Determine which portion of the 3 bytes this data will fill */ + switch (sindex & 0x3) { + case 0: + /* Fill upper 6 bits */ + if (j<dest_size_bytes) { + dest[j] = val << 2; + } else { + return BASE64_BUFFER_OVERRUN; + } + break; + case 1: + /* Fill Bottom 2 bits */ + dest[j++] |= val >> 4; + + if (j<dest_size_bytes) { + /* Fill Top 4 bits */ + dest[j] = (val << 4) & 0xF0; + } else { + /* + * Check to see if there is any more data present. + * Next base64 character MUST be a pad character and + * the rest of this data MUST be zero. + * + * If this is not the end of data then a buffer overrun + * has occurred + */ + if ((val & 0x0F) || + (i+1>=src_bytes) || + (base64_decode_get_raw(src[i+1]) != PADDING)) { + return BASE64_BUFFER_OVERRUN; + } + } + break; + case 2: + /* Fill Bottom 4 bits */ + dest[j++] |= val >> 2; + + if (j<dest_size_bytes) { + /* Fill Top 2 bits */ + dest[j] = (val << 6) & 0xC0; + } else { + /* + * Check to see if there is any more data present. + * Next base64 character MUST be a pad character and + * the rest of this data MUST be zero. + * + * If this is not the end of data then a buffer overrun + * has occurred + */ + if ((val & 0x03) || + (i+1>=src_bytes) || + (base64_decode_get_raw(src[i+1]) != PADDING)) { + return BASE64_BUFFER_OVERRUN; + } + } + break; + case 3: + /* + * No need to check for overrun here since the + * previous case was already checked. If another + * group is present then case 0 will check again. + */ + + /* Fill Bottom 6 bits */ + dest[j++] |= val; + break; + } + sindex++; + } + + /* Check length for multiple of 3 bytes */ + if (((j + pad_count)% 3) != 0) { + return BASE64_BAD_BLOCK_SIZE; + } + + /* Save off the number of bytes converted */ + *dest_bytes = j; + + return BASE64_SUCCESS; +} diff --git a/third_party/sipcc/sdp_base64.h b/third_party/sipcc/sdp_base64.h new file mode 100644 index 0000000000..e264245b72 --- /dev/null +++ b/third_party/sipcc/sdp_base64.h @@ -0,0 +1,42 @@ +/* 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/. */ + +#ifndef _SDP_BASE64_H_ +#define _SDP_BASE64_H_ + +/* + * base64_result_t + * Enumeration of the result codes for Base64 conversion. + */ +typedef enum base64_result_t_ { + BASE64_INVALID=-1, + BASE64_SUCCESS=0, + BASE64_BUFFER_OVERRUN, + BASE64_BAD_DATA, + BASE64_BAD_PADDING, + BASE64_BAD_BLOCK_SIZE, + BASE64_RESULT_MAX +} base64_result_t; + +#define MAX_BASE64_STRING_LEN 60 + +/* Result code string table */ +extern char *base64_result_table[]; + +/* + * BASE64_RESULT_TO_STRING + * Macro to convert a Base64 result code into a human readable string. + */ +#define BASE64_RESULT_TO_STRING(_result) (((_result)>=0 && (_result)<BASE64_RESULT_MAX)?(base64_result_table[_result]):("UNKNOWN Result Code")) + +/* Prototypes */ + +int base64_est_encode_size_bytes(int raw_size_bytes); +int base64_est_decode_size_bytes(int base64_size_bytes); + +base64_result_t base64_encode(unsigned char *src, int src_bytes, unsigned char *dest, int *dest_bytes); + +base64_result_t base64_decode(unsigned char *src, int src_bytes, unsigned char *dest, int *dest_bytes); + +#endif /* _SDP_BASE64_H_ */ diff --git a/third_party/sipcc/sdp_config.c b/third_party/sipcc/sdp_config.c new file mode 100644 index 0000000000..9f28dc2895 --- /dev/null +++ b/third_party/sipcc/sdp_config.c @@ -0,0 +1,241 @@ +/* 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 "sdp_os_defs.h" +#include "sipcc_sdp.h" +#include "sdp_private.h" + +#include "sdp_log.h" + +static const char* logTag = "sdp_config"; + +/* Function: void *sdp_init_config() + * Description: Initialize SDP configuration structure with the + * following defaults: + * All debug levels turned OFF. + * All token lines required per RFC2327. + * No media types supported. + * No network types supported. + * No address types supported. + * No transport types supported. + * Parameters: None. + * Returns: A handle for the configuration as a void ptr. + */ +sdp_conf_options_t *sdp_init_config () +{ + int i; + sdp_conf_options_t *conf_p; + + conf_p = SDP_MALLOC(sizeof(sdp_conf_options_t)); + + if (!conf_p) { + SDPLogError(logTag, "SDP: could not allocate configuration object."); + return NULL; + } + + /* Set default debug flags. */ + conf_p->debug_flag[SDP_DEBUG_TRACE] = FALSE; + conf_p->debug_flag[SDP_DEBUG_WARNINGS] = FALSE; + conf_p->debug_flag[SDP_DEBUG_ERRORS] = FALSE; + + /* Set required lines flags. Note: Only need to set those that */ + /* are questionable. Most lines aren't required by default. */ + conf_p->version_reqd = TRUE; + conf_p->owner_reqd = TRUE; + conf_p->session_name_reqd = TRUE; + conf_p->timespec_reqd = TRUE; + + /* No media types supported by default. */ + for (i=0; i < SDP_MAX_MEDIA_TYPES; i++) { + conf_p->media_supported[i] = FALSE; + } + + /* No network types supported by default. */ + for (i=0; i < SDP_MAX_NETWORK_TYPES; i++) { + conf_p->nettype_supported[i] = FALSE; + } + + /* No address types supported by default. */ + for (i=0; i < SDP_MAX_ADDR_TYPES; i++) { + conf_p->addrtype_supported[i] = FALSE; + } + + /* No transport types supported by default. */ + for (i=0; i < SDP_MAX_TRANSPORT_TYPES; i++) { + conf_p->transport_supported[i] = FALSE; + } + + /* No choose parameters allowed by default. */ + for (i=0; i < SDP_MAX_CHOOSE_PARAMS; i++) { + conf_p->allow_choose[i] = FALSE; + } + + /* Initialize statistics counts */ + conf_p->num_parses = 0; + conf_p->num_builds = 0; + conf_p->num_not_sdp_desc = 0; + conf_p->num_invalid_token_order = 0; + conf_p->num_invalid_param = 0; + conf_p->num_no_resource = 0; + + /* Parse error handler stuff */ + conf_p->error_handler = NULL; + conf_p->error_handler_context = NULL; + + SDPLogInfo(logTag, "SDP: Initialized config pointer: %p", conf_p); + + return (conf_p); +} + +void sdp_free_config(sdp_conf_options_t* conf_p) { + if (conf_p) { + SDP_FREE(conf_p); + } +} + +/* Function: void sdp_appl_debug(sdp_conf_options_t *conf_p, sdp_debug_e debug_type, + * tinybool my_bool); + * Description: Define the default type of debug for the application. + * Valid debug types are ERRORS, WARNINGS, and TRACE. Each + * debug type can be turned on/off individually. The + * default debug level can be redefined at any time. + * Parameters: conf_p The config handle returned by sdp_init_config. + * debug_type Specifies the debug type being enabled/disabled. + * debug_flag Defines whether the debug should be enabled or not. + * Returns: Nothing. + */ +void sdp_appl_debug (sdp_conf_options_t *conf_p, sdp_debug_e debug_type, + tinybool debug_flag) +{ + if (debug_type < SDP_MAX_DEBUG_TYPES) { + conf_p->debug_flag[debug_type] = debug_flag; + } +} + + +/* Functions: void sdp_require_version + * void sdp_require_owner + * void sdp_require_session_name + * void sdp_require_timespec + * Description: These functions allow the application to not require several + * of the tokens that are specifically required by RFC 2327. + * Parameters: conf_p The config handle returned by sdp_init_config. + * version_required TRUE or FALSE whether the token should + * be required. + * Returns: Nothing. + */ +void sdp_require_version (sdp_conf_options_t *conf_p, tinybool version_required) +{ + conf_p->version_reqd = version_required; +} + +void sdp_require_owner (sdp_conf_options_t *conf_p, tinybool owner_required) +{ + conf_p->owner_reqd = owner_required; +} + +void sdp_require_session_name (sdp_conf_options_t *conf_p, tinybool sess_name_required) +{ + conf_p->session_name_reqd = sess_name_required; +} + +void sdp_require_timespec (sdp_conf_options_t *conf_p, tinybool timespec_required) +{ + conf_p->timespec_reqd = timespec_required; +} + + +/* Function: sdp_media_supported + * Description: These functions allow the application to specify which + * media types it supports. The application must set any/all + * as required. No media types are supported by default. + * Parameters: conf_p The config handle returned by sdp_init_config. + * nettype The network type for which support is being set. + * media_supported TRUE or FALSE whether the support is provided. + * Returns: Nothing. + */ +void sdp_media_supported (sdp_conf_options_t *conf_p, sdp_media_e media_type, + tinybool media_supported) +{ + conf_p->media_supported[media_type] = media_supported; +} + + +/* Function: sdp_nettype_supported + * Description: This function allows the application to specify which + * network types it supports. The application must set + * any/all as required. No network types are supported by + * default. + * Parameters: conf_p The config handle returned by sdp_init_config. + * nettype The network type for which support is being set. + * nettype_supported TRUE or FALSE whether the support is + * provided. + * Returns: Nothing. + */ +void sdp_nettype_supported (sdp_conf_options_t *conf_p, sdp_nettype_e nettype, + tinybool nettype_supported) +{ + conf_p->nettype_supported[nettype] = nettype_supported; +} + + +/* Function: sdp_addrtype_supported + * Description: This function allows the application to specify which + * address types it supports. The application must set + * any/all as required. No address types are supported by + * default. + * Parameters: conf_p The config handle returned by sdp_init_config. + * addrtype The address type for which support is being set. + * addrtype_supported TRUE or FALSE whether the support is + * provided. + * Returns: Nothing. + */ +void sdp_addrtype_supported (sdp_conf_options_t *conf_p, sdp_addrtype_e addrtype, + tinybool addrtype_supported) +{ + conf_p->addrtype_supported[addrtype] = addrtype_supported; +} + + +/* Function: sdp_transport_supported + * Description: This function allows the application to specify which + * transport types it supports. The application must set + * any/all as required. No transport types are supported + * by default. + * Parameters: conf_p The config handle returned by sdp_init_config. + * transport The transport type for which support is being set. + * transport_supported TRUE or FALSE whether the support is + * provided. + * Returns: Nothing. + */ +void sdp_transport_supported (sdp_conf_options_t *conf_p, sdp_transport_e transport, + tinybool transport_supported) +{ + conf_p->transport_supported[transport] = transport_supported; +} + + +/* Function: sdp_allow_choose + * Description: These functions allow the CHOOSE parameter `$' to be + * specified in place of certain parameters. + * Parameters: conf_p The config handle returned by sdp_init_config. + * param The param that may or may not be CHOOSE. + * choose_allowed TRUE or FALSE whether the CHOOSE parameter + * should be allowed. + * Returns: Nothing. + */ +void sdp_allow_choose (sdp_conf_options_t *conf_p, sdp_choose_param_e param, tinybool choose_allowed) +{ + if (param < SDP_MAX_CHOOSE_PARAMS) { + conf_p->allow_choose[param] = choose_allowed; + } +} + +void sdp_config_set_error_handler(sdp_conf_options_t *conf_p, + sdp_parse_error_handler handler, + void *context) +{ + conf_p->error_handler = handler; + conf_p->error_handler_context = context; +} diff --git a/third_party/sipcc/sdp_log.h b/third_party/sipcc/sdp_log.h new file mode 100644 index 0000000000..6aeb121529 --- /dev/null +++ b/third_party/sipcc/sdp_log.h @@ -0,0 +1,62 @@ +/* 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/. */ + +/* This is a mirror of CSFLog. The implementations of SDPLog, SDPLogV, and + SDPLogTestLevel must be provided by the user. */ + +#ifndef SDPLOG_H +#define SDPLOG_H + +#include <stdarg.h> + +typedef enum { + SDP_LOG_ERROR = 1, + SDP_LOG_WARNING, + SDP_LOG_INFO, + SDP_LOG_DEBUG, + SDP_LOG_VERBOSE, +} SDPLogLevel; + +#define SDPLogError(tag, format, ...) \ + SDPLog(SDP_LOG_ERROR, __FILE__, __LINE__, tag, format, ##__VA_ARGS__) +#define SDPLogErrorV(tag, format, va_list_arg) \ + SDPLogV(SDP_LOG_ERROR, __FILE__, __LINE__, tag, format, va_list_arg) +#define SDPLogWarn(tag, format, ...) \ + SDPLog(SDP_LOG_WARNING, __FILE__, __LINE__, tag, format, ##__VA_ARGS__) +#define SDPLogWarnV(tag, format, va_list_arg) \ + SDPLogV(SDP_LOG_WARNING, __FILE__, __LINE__, tag, format, va_list_arg) +#define SDPLogInfo(tag, format, ...) \ + SDPLog(SDP_LOG_INFO, __FILE__, __LINE__, tag, format, ##__VA_ARGS__) +#define SDPLogInfoV(tag, format, va_list_arg) \ + SDPLogV(SDP_LOG_INFO, __FILE__, __LINE__, tag, format, va_list_arg) +#define SDPLogDebug(tag, format, ...) \ + SDPLog(SDP_LOG_DEBUG, __FILE__, __LINE__, tag, format, ##__VA_ARGS__) +#define SDPLogDebugV(tag, format, va_list_arg) \ + SDPLogV(SDP_LOG_DEBUG, __FILE__, __LINE__, tag, format, va_list_arg) +#define SDPLogVerbose(tag, format, ...) \ + SDPLog(SDP_LOG_VERBOSE, __FILE__, __LINE__, tag, format, ##__VA_ARGS__) +#define SDPLogVerboseV(tag, format, va_list_arg) \ + SDPLogV(SDP_LOG_VERBOSE, __FILE__, __LINE__, tag, format, va_list_arg) + +#ifdef __cplusplus +extern "C" { +#endif +void SDPLog(SDPLogLevel priority, const char* sourceFile, int sourceLine, + const char* tag, const char* format, ...) + +#ifdef __GNUC__ + __attribute__((format(printf, 5, 6))) +#endif + ; + +void SDPLogV(SDPLogLevel priority, const char* sourceFile, int sourceLine, + const char* tag, const char* format, va_list args); + +int SDPLogTestLevel(SDPLogLevel priority); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/third_party/sipcc/sdp_main.c b/third_party/sipcc/sdp_main.c new file mode 100644 index 0000000000..cdc8bf8e0b --- /dev/null +++ b/third_party/sipcc/sdp_main.c @@ -0,0 +1,1374 @@ +/* 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 "sdp_os_defs.h" +#include "sipcc_sdp.h" +#include "sdp_private.h" + +#include "sdp_log.h" + +static const char* logTag = "sdp_main"; + +/* Note: These *must* be in the same order as the enum types. */ +const sdp_tokenarray_t sdp_token[SDP_MAX_TOKENS] = +{ + {"v=", sdp_parse_version, sdp_build_version }, + {"o=", sdp_parse_owner, sdp_build_owner }, + {"s=", sdp_parse_sessname, sdp_build_sessname }, + {"i=", sdp_parse_sessinfo, sdp_build_sessinfo }, + {"u=", sdp_parse_uri, sdp_build_uri }, + {"e=", sdp_parse_email, sdp_build_email }, + {"p=", sdp_parse_phonenum, sdp_build_phonenum }, + {"c=", sdp_parse_connection, sdp_build_connection }, + {"b=", sdp_parse_bandwidth, sdp_build_bandwidth }, + {"t=", sdp_parse_timespec, sdp_build_timespec }, + {"r=", sdp_parse_repeat_time, sdp_build_repeat_time }, + {"z=", sdp_parse_timezone_adj, sdp_build_timezone_adj }, + {"k=", sdp_parse_encryption, sdp_build_encryption }, + {"a=", sdp_parse_attribute, sdp_build_attribute }, + {"m=", sdp_parse_media, sdp_build_media } +}; + + +/* Note: These *must* be in the same order as the enum types. */ +const sdp_attrarray_t sdp_attr[SDP_MAX_ATTR_TYPES] = +{ + {"bearer", sizeof("bearer"), + sdp_parse_attr_simple_string, sdp_build_attr_simple_string }, + {"called", sizeof("called"), + sdp_parse_attr_simple_string, sdp_build_attr_simple_string }, + {"connection_type", sizeof("connection_type"), + sdp_parse_attr_simple_string, sdp_build_attr_simple_string }, + {"dialed", sizeof("dialed"), + sdp_parse_attr_simple_string, sdp_build_attr_simple_string }, + {"dialing", sizeof("dialing"), + sdp_parse_attr_simple_string, sdp_build_attr_simple_string }, + {"direction", sizeof("direction"), + sdp_parse_attr_comediadir, sdp_build_attr_comediadir }, + {"eecid", sizeof("eecid"), + sdp_parse_attr_simple_u32, sdp_build_attr_simple_u32 }, + {"fmtp", sizeof("fmtp"), + sdp_parse_attr_fmtp, sdp_build_attr_fmtp }, + {"sctpmap", sizeof("sctpmap"), + sdp_parse_attr_sctpmap, sdp_build_attr_sctpmap }, + {"framing", sizeof("framing"), + sdp_parse_attr_simple_string, sdp_build_attr_simple_string }, + {"inactive", sizeof("inactive"), + sdp_parse_attr_direction, sdp_build_attr_direction }, + {"ptime", sizeof("ptime"), + sdp_parse_attr_simple_u32, sdp_build_attr_simple_u32 }, + {"qos", sizeof("qos"), + sdp_parse_attr_qos, sdp_build_attr_qos }, + {"curr", sizeof("curr"), + sdp_parse_attr_curr, sdp_build_attr_curr }, + {"des", sizeof("des"), + sdp_parse_attr_des, sdp_build_attr_des}, + {"conf", sizeof("conf"), + sdp_parse_attr_conf, sdp_build_attr_conf}, + {"recvonly", sizeof("recvonly"), + sdp_parse_attr_direction, sdp_build_attr_direction }, + {"rtpmap", sizeof("rtpmap"), + sdp_parse_attr_transport_map, sdp_build_attr_transport_map }, + {"secure", sizeof("secure"), + sdp_parse_attr_qos, sdp_build_attr_qos }, + {"sendonly", sizeof("sendonly"), + sdp_parse_attr_direction, sdp_build_attr_direction }, + {"sendrecv", sizeof("sendrecv"), + sdp_parse_attr_direction, sdp_build_attr_direction }, + {"subnet", sizeof("subnet"), + sdp_parse_attr_subnet, sdp_build_attr_subnet }, + {"T38FaxVersion", sizeof("T38FaxVersion"), + sdp_parse_attr_simple_u32, sdp_build_attr_simple_u32 }, + {"T38MaxBitRate", sizeof("T38MaxBitRate"), + sdp_parse_attr_simple_u32, sdp_build_attr_simple_u32 }, + {"T38FaxFillBitRemoval", sizeof("T38FaxFillBitRemoval"), + sdp_parse_attr_simple_bool, sdp_build_attr_simple_bool }, + {"T38FaxTranscodingMMR", sizeof("T38FaxTranscodingMMR"), + sdp_parse_attr_simple_bool, sdp_build_attr_simple_bool }, + {"T38FaxTranscodingJBIG", sizeof("T38FaxTranscodingJBIG"), + sdp_parse_attr_simple_bool, sdp_build_attr_simple_bool }, + {"T38FaxRateManagement", sizeof("T38FaxRateManagement"), + sdp_parse_attr_t38_ratemgmt, sdp_build_attr_t38_ratemgmt }, + {"T38FaxMaxBuffer", sizeof("T38FaxMaxBuffer"), + sdp_parse_attr_simple_u32, sdp_build_attr_simple_u32 }, + {"T38FaxMaxDatagram", sizeof("T38FaxMaxDatagram"), + sdp_parse_attr_simple_u32, sdp_build_attr_simple_u32 }, + {"T38FaxUdpEC", sizeof("T38FaxUdpEC"), + sdp_parse_attr_t38_udpec, sdp_build_attr_t38_udpec }, + {"X-cap", sizeof("X-cap"), + sdp_parse_attr_cap, sdp_build_attr_cap }, + {"X-cpar", sizeof("X-cpar"), + sdp_parse_attr_cpar, sdp_build_attr_cpar }, + {"X-pc-codec", sizeof("X-pc-codec"), + sdp_parse_attr_pc_codec, sdp_build_attr_pc_codec }, + {"X-pc-qos", sizeof("X-pc-qos"), + sdp_parse_attr_qos, sdp_build_attr_qos }, + {"X-qos", sizeof("X-qos"), + sdp_parse_attr_qos, sdp_build_attr_qos }, + {"X-sqn", sizeof("X-sqn"), + sdp_parse_attr_simple_u32, sdp_build_attr_simple_u32 }, + {"TMRGwXid", sizeof("TMRGwXid"), + sdp_parse_attr_simple_bool, sdp_build_attr_simple_bool }, + {"TC1PayloadBytes", sizeof("TC1PayloadBytes"), + sdp_parse_attr_simple_u32, sdp_build_attr_simple_u32 }, + {"TC1WindowSize", sizeof("TC1WindowSize"), + sdp_parse_attr_simple_u32, sdp_build_attr_simple_u32 }, + {"TC2PayloadBytes", sizeof("TC2PayloadBytes"), + sdp_parse_attr_simple_u32, sdp_build_attr_simple_u32 }, + {"TC2WindowSize", sizeof("TC2WindowSize"), + sdp_parse_attr_simple_u32, sdp_build_attr_simple_u32 }, + {"rtcp", sizeof("rtcp"), + sdp_parse_attr_rtcp, sdp_build_attr_rtcp }, + {"rtr", sizeof("rtr"), + sdp_parse_attr_rtr, sdp_build_attr_rtr}, + {"silenceSupp", sizeof("silenceSupp"), + sdp_parse_attr_silencesupp, sdp_build_attr_silencesupp }, + {"X-crypto", sizeof("X-crypto"), + sdp_parse_attr_srtpcontext, sdp_build_attr_srtpcontext }, + {"mptime", sizeof("mptime"), + sdp_parse_attr_mptime, sdp_build_attr_mptime }, + {"X-sidin", sizeof("X-sidin"), + sdp_parse_attr_x_sidin, sdp_build_attr_x_sidin }, + {"X-sidout", sizeof("X-sidout"), + sdp_parse_attr_x_sidout, sdp_build_attr_x_sidout }, + {"X-confid", sizeof("X-confid"), + sdp_parse_attr_x_confid, sdp_build_attr_x_confid }, + {"group", sizeof("group"), + sdp_parse_attr_group, sdp_build_attr_group }, + {"mid", sizeof("mid"), + sdp_parse_attr_simple_string, sdp_build_attr_simple_string }, + {"source-filter", sizeof("source-filter"), + sdp_parse_attr_source_filter, sdp_build_source_filter}, + {"rtcp-unicast", sizeof("rtcp-unicast"), + sdp_parse_attr_rtcp_unicast, sdp_build_attr_rtcp_unicast}, + {"maxprate", sizeof("maxprate"), + sdp_parse_attr_maxprate, sdp_build_attr_simple_string}, + {"sqn", sizeof("sqn"), + sdp_parse_attr_simple_u32, sdp_build_attr_simple_u32 }, + {"cdsc", sizeof("cdsc"), + sdp_parse_attr_cap, sdp_build_attr_cap }, + {"cpar", sizeof("cpar"), + sdp_parse_attr_cpar, sdp_build_attr_cpar }, + {"sprtmap", sizeof("sprtmap"), + sdp_parse_attr_transport_map, sdp_build_attr_transport_map }, + {"crypto", sizeof("crypto"), + sdp_parse_attr_sdescriptions, sdp_build_attr_sdescriptions }, + {"label", sizeof("label"), + sdp_parse_attr_simple_string, sdp_build_attr_simple_string }, + {"framerate", sizeof("framerate"), + sdp_parse_attr_simple_u32, sdp_build_attr_simple_u32 }, + {"candidate", sizeof("candidate"), + sdp_parse_attr_ice_attr, sdp_build_attr_ice_attr }, + {"ice-ufrag", sizeof("ice-ufrag"), + sdp_parse_attr_ice_attr, sdp_build_attr_ice_attr }, + {"ice-pwd", sizeof("ice-pwd"), + sdp_parse_attr_ice_attr, sdp_build_attr_ice_attr}, + {"ice-lite", sizeof("ice-lite"), + sdp_parse_attr_simple_flag, sdp_build_attr_simple_flag}, + {"rtcp-mux", sizeof("rtcp-mux"), + sdp_parse_attr_simple_flag, sdp_build_attr_simple_flag}, + {"fingerprint", sizeof("fingerprint"), + sdp_parse_attr_complete_line, sdp_build_attr_simple_string}, + {"maxptime", sizeof("maxptime"), + sdp_parse_attr_simple_u32, sdp_build_attr_simple_u32}, + {"rtcp-fb", sizeof("rtcp-fb"), + sdp_parse_attr_rtcp_fb, sdp_build_attr_rtcp_fb}, + {"setup", sizeof("setup"), + sdp_parse_attr_setup, sdp_build_attr_setup}, + {"connection", sizeof("connection"), + sdp_parse_attr_connection, sdp_build_attr_connection}, + {"extmap", sizeof("extmap"), + sdp_parse_attr_extmap, sdp_build_attr_extmap}, + {"identity", sizeof("identity"), + sdp_parse_attr_long_line, sdp_build_attr_long_line}, + {"msid", sizeof("msid"), + sdp_parse_attr_msid, sdp_build_attr_msid}, + {"msid-semantic", sizeof("msid-semantic"), + sdp_parse_attr_msid_semantic, sdp_build_attr_msid_semantic}, + {"bundle-only", sizeof("bundle-only"), + sdp_parse_attr_simple_flag, sdp_build_attr_simple_flag}, + {"end-of-candidates", sizeof("end-of-candidates"), + sdp_parse_attr_simple_flag, sdp_build_attr_simple_flag}, + {"ice-options", sizeof("ice-options"), + sdp_parse_attr_complete_line, sdp_build_attr_simple_string}, + {"ssrc", sizeof("ssrc"), + sdp_parse_attr_ssrc, sdp_build_attr_ssrc}, + {"imageattr", sizeof("imageattr"), + sdp_parse_attr_complete_line, sdp_build_attr_simple_string}, + {"simulcast", sizeof("simulcast"), + sdp_parse_attr_complete_line, sdp_build_attr_simple_string}, + {"rid", sizeof("rid"), + sdp_parse_attr_complete_line, sdp_build_attr_simple_string}, + {"dtls-message", sizeof("dtls-message"), + sdp_parse_attr_long_line, sdp_build_attr_long_line}, + {"sctp-port", sizeof("sctp-port"), + sdp_parse_attr_simple_u32, sdp_build_attr_simple_u32}, + {"max-message-size", sizeof("max-message-size"), + sdp_parse_attr_simple_u32, sdp_build_attr_simple_u32}, + {"ssrc-group", sizeof("ssrc-group"), sdp_parse_attr_ssrc_group, + sdp_build_attr_ssrc_group}, + {"rtcp-rsize", sizeof("rtcp-rsize"), + sdp_parse_attr_simple_flag, sdp_build_attr_simple_flag}, +}; + +/* Note: These *must* be in the same order as the enum types. */ +const sdp_namearray_t sdp_media[SDP_MAX_MEDIA_TYPES] = +{ + {"audio", sizeof("audio")}, + {"video", sizeof("video")}, + {"application", sizeof("application")}, + {"data", sizeof("data")}, + {"control", sizeof("control")}, + {"nas/radius", sizeof("nas/radius")}, + {"nas/tacacs", sizeof("nas/tacacs")}, + {"nas/diameter", sizeof("nas/diameter")}, + {"nas/l2tp", sizeof("nas/l2tp")}, + {"nas/login", sizeof("nas/login")}, + {"nas/none", sizeof("nas/none")}, + {"image", sizeof("image")}, + {"text", sizeof("text")} +}; + + +/* Note: These *must* be in the same order as the enum types. */ +const sdp_namearray_t sdp_nettype[SDP_MAX_NETWORK_TYPES] = +{ + {"IN", sizeof("IN")}, + {"ATM", sizeof("ATM")}, + {"FR", sizeof("FR")}, + {"LOCAL", sizeof("LOCAL")} +}; + + +/* Note: These *must* be in the same order as the enum types. */ +const sdp_namearray_t sdp_addrtype[SDP_MAX_ADDR_TYPES] = +{ + {"IP4", sizeof("IP4")}, + {"IP6", sizeof("IP6")}, + {"NSAP", sizeof("NSAP")}, + {"EPN", sizeof("EPN")}, + {"E164", sizeof("E164")}, + {"GWID", sizeof("GWID")} +}; + + +/* Note: These *must* be in the same order as the enum type. */ +const sdp_namearray_t sdp_transport[SDP_MAX_TRANSPORT_TYPES] = +{ + {"RTP/AVP", sizeof("RTP/AVP")}, + {"udp", sizeof("udp")}, + {"udptl", sizeof("udptl")}, + {"ces10", sizeof("ces10")}, + {"LOCAL", sizeof("LOCAL")}, + {"AAL2/ITU", sizeof("AAL2/ITU")}, + {"AAL2/ATMF", sizeof("AAL2/ATMF")}, + {"AAL2/custom", sizeof("AAL2/custom")}, + {"AAL1/AVP", sizeof("AAL1/AVP")}, + {"udpsprt", sizeof("udpsprt")}, + {"RTP/SAVP", sizeof("RTP/SAVP")}, + {"tcp", sizeof("tcp")}, + {"RTP/SAVPF", sizeof("RTP/SAVPF")}, + {"DTLS/SCTP", sizeof("DTLS/SCTP")}, + {"RTP/AVPF", sizeof("RTP/AVPF")}, + {"UDP/TLS/RTP/SAVP", sizeof("UDP/TLS/RTP/SAVP")}, + {"UDP/TLS/RTP/SAVPF", sizeof("UDP/TLS/RTP/SAVPF")}, + {"TCP/DTLS/RTP/SAVP", sizeof("TCP/DTLS/RTP/SAVP")}, + {"TCP/DTLS/RTP/SAVPF", sizeof("TCP/DTLS/RTP/SAVPF")}, + {"UDP/DTLS/SCTP", sizeof("UDP/DTLS/SCTP")}, + {"TCP/DTLS/SCTP", sizeof("TCP/DTLS/SCTP")}, +}; + +/* Note: These *must* be in the same order as the enum type. */ +const sdp_namearray_t sdp_encrypt[SDP_MAX_ENCRYPT_TYPES] = +{ + {"clear", sizeof("clear")}, + {"base64", sizeof("base64")}, + {"uri", sizeof("uri")}, + {"prompt", sizeof("prompt")} +}; + +/* Note: These *must* be in the same order as the enum type. */ +const sdp_namearray_t sdp_payload[SDP_MAX_STRING_PAYLOAD_TYPES] = +{ + {"t38", sizeof("t38")}, + {"X-tmr", sizeof("X-tmr")}, + {"T120", sizeof("T120")} +}; + +/* Note: These *must* be in the same order as the enum type. */ +const sdp_namearray_t sdp_t38_rate[SDP_T38_MAX_RATES] = +{ + {"localTCF", sizeof("localTCF")}, + {"transferredTCF", sizeof("transferredTCF")}, + {"unknown", sizeof("unknown")} +}; + +/* Note: These *must* be in the same order as the enum type. */ +const sdp_namearray_t sdp_t38_udpec[SDP_T38_MAX_UDPEC] = +{ + {"t38UDPRedundancy", sizeof("t38UDPRedundancy")}, + {"t38UDPFEC", sizeof("t38UDPFEC")}, + {"unknown", sizeof("unknown")} +}; + +/* Note: These *must* be in the same order as the enum type. */ +const sdp_namearray_t sdp_qos_strength[SDP_MAX_QOS_STRENGTH] = +{ + {"optional", sizeof("optional")}, + {"mandatory", sizeof("mandatory")}, + {"success", sizeof("success")}, + {"failure", sizeof("failure")}, + {"none", sizeof("none")} +}; + +/* Note: These *must* be in the same order as the enum type. */ +const sdp_namearray_t sdp_qos_status_type[SDP_MAX_QOS_STATUS_TYPES] = +{ + {"local", sizeof("local")}, + {"remote", sizeof("remote")}, + {"e2e", sizeof("e2e")} +}; + +/* Note: These *must* be in the same order as the enum type. */ +const sdp_namearray_t sdp_curr_type[SDP_MAX_CURR_TYPES] = +{ + {"qos", sizeof("qos")}, + {"unknown", sizeof("unknown")} +}; + +/* Note: These *must* be in the same order as the enum type. */ +const sdp_namearray_t sdp_des_type[SDP_MAX_DES_TYPES] = +{ + {"qos", sizeof("qos")}, + {"unknown", sizeof("unknown")} +}; + +/* Note: These *must* be in the same order as the enum type. */ +const sdp_namearray_t sdp_conf_type[SDP_MAX_CONF_TYPES] = +{ + {"qos", sizeof("qos")}, + {"unknown", sizeof("unknown")} +}; +/* Note: These *must* be in the same order as the enum type. */ +const sdp_namearray_t sdp_qos_direction[SDP_MAX_QOS_DIR] = +{ + {"send", sizeof("send")}, + {"recv", sizeof("recv")}, + {"sendrecv", sizeof("sendrecv")}, + {"none", sizeof("none")} +}; + +/* Note: These *must* be in the same order as the enum type. */ +const sdp_namearray_t sdp_silencesupp_pref[SDP_MAX_SILENCESUPP_PREF] = { + {"standard", sizeof("standard")}, + {"custom", sizeof("custom")}, + {"-", sizeof("-")} +}; + +/* Note: These *must* be in the same order as the enum type. */ +const sdp_namearray_t sdp_silencesupp_siduse[SDP_MAX_SILENCESUPP_SIDUSE] = { + {"No SID", sizeof("No SID")}, + {"Fixed Noise", sizeof("Fixed Noise")}, + {"Sampled Noise", sizeof("Sampled Noise")}, + {"-", sizeof("-")} +}; + +/* Note: These *must* be in the same order as the enum type. */ +const sdp_namearray_t sdp_mediadir_role[SDP_MAX_MEDIADIR_ROLES] = +{ + {"passive", sizeof("passive")}, + {"active", sizeof("active")}, + {"both", sizeof("both")}, + {"reuse", sizeof("reuse")}, + {"unknown", sizeof("unknown")} +}; + +/* Note: These *must* be in the same order as the enum type. */ +const sdp_namearray_t sdp_fmtp_codec_param[SDP_MAX_FMTP_PARAM] = +{ + {"annexa", sizeof("annexa")}, /* 0 */ + {"annexb", sizeof("annexb")}, /* 1 */ + {"bitrate", sizeof("bitrate")}, /* 2 */ + {"QCIF", sizeof("QCIF")}, /* 3 */ + {"CIF", sizeof("CIF")}, /* 4 */ + {"MAXBR", sizeof("MAXBR")}, /* 5 */ + {"SQCIF", sizeof("SQCIF")}, /* 6 */ + {"CIF4", sizeof("CIF4")}, /* 7 */ + {"CIF16", sizeof("CIF16")}, /* 8 */ + {"CUSTOM", sizeof("CUSTOM")}, /* 9 */ + {"PAR", sizeof("PAR")}, /* 10 */ + {"CPCF", sizeof("CPCF")}, /* 11 */ + {"BPP", sizeof("BPP")}, /* 12 */ + {"HRD", sizeof("HRD")}, /* 13 */ + {"PROFILE", sizeof("PROFILE")}, /* 14 */ + {"LEVEL", sizeof("LEVEL")}, /* 15 */ + {"INTERLACE", sizeof("INTERLACE")}, /* 16 */ + + /* H.264 related */ + {"profile-level-id", sizeof("profile-level-id")}, /* 17 */ + {"sprop-parameter-sets", sizeof("sprop-parameter-sets")}, /* 18 */ + {"packetization-mode", sizeof("packetization-mode")}, /* 19 */ + {"sprop-interleaving-depth", sizeof("sprop-interleaving-depth")}, /* 20 */ + {"sprop-deint-buf-req", sizeof("sprop-deint-buf-req")}, /* 21 */ + {"sprop-max-don-diff", sizeof("sprop-max-don-diff")}, /* 22 */ + {"sprop-init-buf-time", sizeof("sprop-init-buf-time")}, /* 23 */ + + {"max-mbps", sizeof("max-mbps")}, /* 24 */ + {"max-fs", sizeof("max-fs")}, /* 25 */ + {"max-cpb", sizeof("max-cpb")}, /* 26 */ + {"max-dpb", sizeof("max-dpb")}, /* 27 */ + {"max-br", sizeof("max-br")}, /* 28 */ + {"redundant-pic-cap", sizeof("redundant-pic-cap")}, /* 29 */ + {"deint-buf-cap", sizeof("deint-buf-cap")}, /* 30 */ + {"max-rcmd-nalu-size", sizeof("max-rcmd_nali-size")}, /* 31 */ + {"parameter-add", sizeof("parameter-add")}, /* 32 */ + + /* Annexes - require special handling */ + {"D", sizeof("D")}, /* 33 */ + {"F", sizeof("F")}, /* 34 */ + {"I", sizeof("I")}, /* 35 */ + {"J", sizeof("J")}, /* 36 */ + {"T", sizeof("T")}, /* 37 */ + {"K", sizeof("K")}, /* 38 */ + {"N", sizeof("N")}, /* 39 */ + {"P", sizeof("P")}, /* 40 */ + + {"mode", sizeof("mode")}, /* 41 */ + {"level-asymmetry-allowed", sizeof("level-asymmetry-allowed")}, /* 42 */ + {"maxaveragebitrate", sizeof("maxaveragebitrate")}, /* 43 */ + {"usedtx", sizeof("usedtx")}, /* 44 */ + {"stereo", sizeof("stereo")}, /* 45 */ + {"useinbandfec", sizeof("useinbandfec")}, /* 46 */ + {"maxcodedaudiobandwidth", sizeof("maxcodedaudiobandwidth")}, /* 47 */ + {"cbr", sizeof("cbr")}, /* 48 */ + {"max-fr", sizeof("max-fr")}, /* 49 */ + {"maxplaybackrate", sizeof("maxplaybackrate")}, /* 50 */ + {"apt", sizeof("apt")}, /* 51 */ + {"rtx-time", sizeof("rtx-time")} /* 52 */ +} ; + +/* Note: These *must* be in the same order as the enum type. */ +const sdp_namearray_t sdp_fmtp_codec_param_val[SDP_MAX_FMTP_PARAM_VAL] = +{ + {"yes", sizeof("yes")}, + {"no", sizeof("no")} +}; + +const sdp_namearray_t sdp_bw_modifier_val[SDP_MAX_BW_MODIFIER_VAL] = +{ + {"AS", sizeof("AS")}, + {"CT", sizeof("CT")}, + {"TIAS", sizeof("TIAS")} +}; + +const sdp_namearray_t sdp_group_attr_val[SDP_MAX_GROUP_ATTR_VAL] = +{ + {"FID", sizeof("FID")}, + {"LS", sizeof("LS")}, + {"ANAT", sizeof("ANAT")}, + {"BUNDLE", sizeof("BUNDLE")} +}; + +const sdp_namearray_t sdp_ssrc_group_attr_val[SDP_MAX_SSRC_GROUP_ATTR_VAL] = { + {"DUP", sizeof("DUP")}, + {"FEC", sizeof("FEC")}, + {"FEC-FR", sizeof("FEC-FR")}, + {"FID", sizeof("FID")}, + {"SIM", sizeof("SIM")} +}; + +const sdp_namearray_t sdp_srtp_context_crypto_suite[SDP_SRTP_MAX_NUM_CRYPTO_SUITES] = +{ + {"UNKNOWN_CRYPTO_SUITE", sizeof("UNKNOWN_CRYPTO_SUITE")}, + {"AES_CM_128_HMAC_SHA1_32", sizeof("AES_CM_128_HMAC_SHA1_32")}, + {"AES_CM_128_HMAC_SHA1_80", sizeof("AES_CM_128_HMAC_SHA1_80")}, + {"F8_128_HMAC_SHA1_80", sizeof("F8_128_HMAC_SHA1_80")} +}; + +/* Maintain the same order as defined in typedef sdp_src_filter_mode_e */ +const sdp_namearray_t sdp_src_filter_mode_val[SDP_MAX_FILTER_MODE] = +{ + {"incl", sizeof("incl")}, + {"excl", sizeof("excl")} +}; + +/* Maintain the same order as defined in typdef sdp_rtcp_unicast_mode_e */ +const sdp_namearray_t sdp_rtcp_unicast_mode_val[SDP_RTCP_MAX_UNICAST_MODE] = +{ + {"reflection", sizeof("reflection")}, + {"rsi", sizeof("rsi")} +}; + +#define SDP_NAME(x) {x, sizeof(x)} +/* Maintain the same order as defined in typdef sdp_rtcp_fb_type_e */ +const sdp_namearray_t sdp_rtcp_fb_type_val[SDP_MAX_RTCP_FB] = +{ + SDP_NAME("ack"), + SDP_NAME("ccm"), + SDP_NAME("nack"), + SDP_NAME("trr-int"), + SDP_NAME("goog-remb"), + SDP_NAME("transport-cc") +}; + +/* Maintain the same order as defined in typdef sdp_rtcp_fb_nack_type_e */ +const sdp_namearray_t sdp_rtcp_fb_nack_type_val[SDP_MAX_RTCP_FB_NACK] = +{ + SDP_NAME(""), + SDP_NAME("sli"), + SDP_NAME("pli"), + SDP_NAME("rpsi"), + SDP_NAME("app"), + SDP_NAME("rai"), + SDP_NAME("tllei"), + SDP_NAME("pslei"), + SDP_NAME("ecn") +}; + +/* Maintain the same order as defined in typdef sdp_rtcp_fb_ack_type_e */ +const sdp_namearray_t sdp_rtcp_fb_ack_type_val[SDP_MAX_RTCP_FB_ACK] = +{ + SDP_NAME("rpsi"), + SDP_NAME("app") +}; + +/* Maintain the same order as defined in typdef sdp_rtcp_fb_ccm_type_e */ +const sdp_namearray_t sdp_rtcp_fb_ccm_type_val[SDP_MAX_RTCP_FB_CCM] = +{ + SDP_NAME("fir"), + SDP_NAME("tmmbr"), + SDP_NAME("tstr"), + SDP_NAME("vbcm") +}; + +/* Maintain the same order as defined in typedef sdp_setup_type_e */ +const sdp_namearray_t sdp_setup_type_val[SDP_MAX_SETUP] = +{ + SDP_NAME("active"), + SDP_NAME("passive"), + SDP_NAME("actpass"), + SDP_NAME("holdconn") +}; + +/* Maintain the same order as defined in typedef sdp_connection_type_e */ +const sdp_namearray_t sdp_connection_type_val[SDP_MAX_CONNECTION] = +{ + SDP_NAME("new"), + SDP_NAME("existing") +}; + +/* Maintain same order as defined in typedef sdp_srtp_crypto_suite_t */ +const sdp_srtp_crypto_suite_list sdp_srtp_crypto_suite_array[SDP_SRTP_MAX_NUM_CRYPTO_SUITES] = +{ + {SDP_SRTP_UNKNOWN_CRYPTO_SUITE, UNKNOWN_CRYPTO_SUITE, 0, 0}, + {SDP_SRTP_AES_CM_128_HMAC_SHA1_32, AES_CM_128_HMAC_SHA1_32, + SDP_SRTP_AES_CM_128_HMAC_SHA1_32_KEY_BYTES, + SDP_SRTP_AES_CM_128_HMAC_SHA1_32_SALT_BYTES}, + {SDP_SRTP_AES_CM_128_HMAC_SHA1_80, AES_CM_128_HMAC_SHA1_80, + SDP_SRTP_AES_CM_128_HMAC_SHA1_80_KEY_BYTES, + SDP_SRTP_AES_CM_128_HMAC_SHA1_80_SALT_BYTES}, + {SDP_SRTP_F8_128_HMAC_SHA1_80, F8_128_HMAC_SHA1_80, + SDP_SRTP_F8_128_HMAC_SHA1_80_KEY_BYTES, + SDP_SRTP_F8_128_HMAC_SHA1_80_SALT_BYTES} +}; + +const char* sdp_result_name[SDP_MAX_RC] = + {"SDP_SUCCESS", + "SDP_FAILURE", + "SDP_INVALID_SDP_PTR", + "SDP_NOT_SDP_DESCRIPTION", + "SDP_INVALID_TOKEN_ORDERING", + "SDP_INVALID_PARAMETER", + "SDP_INVALID_MEDIA_LEVEL", + "SDP_INVALID_CAPABILITY", + "SDP_NO_RESOURCE", + "SDP_UNRECOGNIZED_TOKEN", + "SDP_NULL_BUF_PTR", + "SDP_POTENTIAL_SDP_OVERFLOW", + "SDP_EMPTY_TOKEN"}; + +const char *sdp_get_result_name ( sdp_result_e rc ) +{ + if (rc >= SDP_MAX_RC) { + return ("Invalid SDP result code"); + } else { + return (sdp_result_name[rc]); + } +} + +const char *sdp_get_attr_name ( sdp_attr_e attr_type ) +{ + if (attr_type >= SDP_MAX_ATTR_TYPES) { + return ("Invalid attribute type"); + } else { + return (sdp_attr[attr_type].name); + } +} + +const char *sdp_get_media_name ( sdp_media_e media_type ) +{ + if (media_type == SDP_MEDIA_UNSUPPORTED) { + return (SDP_UNSUPPORTED); + } else if (media_type >= SDP_MAX_MEDIA_TYPES) { + return ("Invalid media type"); + } else { + return (sdp_media[media_type].name); + } +} + +const char *sdp_get_network_name ( sdp_nettype_e network_type ) +{ + if (network_type == SDP_NT_UNSUPPORTED) { + return (SDP_UNSUPPORTED); + } else if (network_type >= SDP_MAX_NETWORK_TYPES) { + return ("Invalid network type"); + } else { + return (sdp_nettype[network_type].name); + } +} + +const char *sdp_get_address_name ( sdp_addrtype_e addr_type ) +{ + if (addr_type == SDP_AT_UNSUPPORTED) { + return (SDP_UNSUPPORTED); + } else if (addr_type >= SDP_MAX_ADDR_TYPES) { + if (addr_type == SDP_AT_FQDN) { + return ("*"); + } else { + return ("Invalid address type"); + } + } else { + return (sdp_addrtype[addr_type].name); + } +} + +const char *sdp_get_transport_name ( sdp_transport_e transport_type ) +{ + if (transport_type == SDP_TRANSPORT_UNSUPPORTED) { + return (SDP_UNSUPPORTED); + } else if (transport_type >= SDP_MAX_TRANSPORT_TYPES) { + return ("Invalid transport type"); + } else { + return (sdp_transport[transport_type].name); + } +} + +const char *sdp_get_encrypt_name ( sdp_encrypt_type_e encrypt_type ) +{ + if (encrypt_type == SDP_ENCRYPT_UNSUPPORTED) { + return (SDP_UNSUPPORTED); + } else if (encrypt_type >= SDP_MAX_ENCRYPT_TYPES) { + return ("Invalid encryption type"); + } else { + return (sdp_encrypt[encrypt_type].name); + } +} + +const char *sdp_get_payload_name ( sdp_payload_e payload ) +{ + if (payload == SDP_PAYLOAD_UNSUPPORTED) { + return (SDP_UNSUPPORTED); + } else if (payload >= SDP_MAX_STRING_PAYLOAD_TYPES) { + return ("Invalid payload type"); + } else { + return (sdp_payload[payload].name); + } +} + +const char *sdp_get_t38_ratemgmt_name ( sdp_t38_ratemgmt_e rate ) +{ + if (rate >= SDP_T38_MAX_RATES) { + return ("Invalid rate"); + } else { + return (sdp_t38_rate[rate].name); + } +} + +const char *sdp_get_t38_udpec_name ( sdp_t38_udpec_e udpec ) +{ + if (udpec >= SDP_T38_MAX_UDPEC) { + return ("Invalid udpec"); + } else { + return (sdp_t38_udpec[udpec].name); + } +} + +const char *sdp_get_qos_strength_name ( sdp_qos_strength_e strength ) +{ + if (strength >= SDP_MAX_QOS_STRENGTH) { + return ("Invalid qos strength"); + } else { + return (sdp_qos_strength[strength].name); + } +} + +const char *sdp_get_qos_direction_name ( sdp_qos_dir_e direction ) +{ + if (direction >= SDP_MAX_QOS_DIR) { + return ("Invalid qos direction"); + } else { + return (sdp_qos_direction[direction].name); + } +} + +const char *sdp_get_qos_status_type_name ( sdp_qos_status_types_e status_type ) +{ + if (status_type >= SDP_MAX_QOS_STATUS_TYPES) { + return ("Invalid qos status type"); + } else { + return (sdp_qos_status_type[status_type].name); + } +} + +const char *sdp_get_curr_type_name (sdp_curr_type_e curr_type ) +{ + if (curr_type >= SDP_MAX_CURR_TYPES) { + return ("Invalid curr type"); + } else { + return (sdp_curr_type[curr_type].name); + } +} + +const char *sdp_get_des_type_name (sdp_des_type_e des_type ) +{ + if (des_type >= SDP_MAX_DES_TYPES) { + return ("Invalid des type"); + } else { + return (sdp_des_type[des_type].name); + } +} + +const char *sdp_get_conf_type_name (sdp_conf_type_e conf_type ) +{ + if (conf_type >= SDP_MAX_CONF_TYPES) { + return ("Invalid conf type"); + } else { + return (sdp_conf_type[conf_type].name); + } +} + +const char *sdp_get_silencesupp_pref_name (sdp_silencesupp_pref_e pref) +{ + if (pref >= SDP_MAX_SILENCESUPP_PREF) { + return ("Invalid silencesupp pref"); + } else { + return (sdp_silencesupp_pref[pref].name); + } +} + +const char *sdp_get_silencesupp_siduse_name (sdp_silencesupp_siduse_e siduse) +{ + if (siduse >= SDP_MAX_SILENCESUPP_SIDUSE) { + return ("Invalid silencesupp siduse"); + } else { + return (sdp_silencesupp_siduse[siduse].name); + } +} + +const char *sdp_get_mediadir_role_name (sdp_mediadir_role_e role) +{ + if (role >= SDP_MEDIADIR_ROLE_UNKNOWN) { + return ("Invalid media direction role"); + } else { + return (sdp_mediadir_role[role].name); + } +} + + +const char *sdp_get_bw_modifier_name (sdp_bw_modifier_e bw_modifier_type) +{ + if (bw_modifier_type == SDP_BW_MODIFIER_UNSUPPORTED) { + return (SDP_UNSUPPORTED); + } else if (bw_modifier_type < SDP_BW_MODIFIER_AS || + bw_modifier_type >= SDP_MAX_BW_MODIFIER_VAL) { + return ("Invalid bw modifier type"); + } else { + return (sdp_bw_modifier_val[bw_modifier_type].name); + } +} + +const char *sdp_get_group_attr_name (sdp_group_attr_e group_attr_type) +{ + if (group_attr_type == SDP_GROUP_ATTR_UNSUPPORTED) { + return (SDP_UNSUPPORTED); + } else if (group_attr_type >= SDP_MAX_GROUP_ATTR_VAL) { + return ("Invalid a=group: attribute type"); + } else { + return (sdp_group_attr_val[group_attr_type].name); + } +} + +const char *sdp_get_ssrc_group_attr_name( + sdp_ssrc_group_attr_e ssrc_group_attr_type) { + if (ssrc_group_attr_type == SDP_SSRC_GROUP_ATTR_UNSUPPORTED) { + return (SDP_UNSUPPORTED); + } else if (ssrc_group_attr_type >= SDP_MAX_SSRC_GROUP_ATTR_VAL) { + return ("Invalid a=ssrc-group: attribute type"); + } else { + return (sdp_ssrc_group_attr_val[ssrc_group_attr_type].name); + } +} + +const char *sdp_get_src_filter_mode_name (sdp_src_filter_mode_e type) +{ + if (type >= SDP_MAX_FILTER_MODE) { + return ("Invalid source filter mode"); + } else { + return (sdp_src_filter_mode_val[type].name); + } +} + +const char *sdp_get_rtcp_unicast_mode_name (sdp_rtcp_unicast_mode_e type) +{ + if (type >= SDP_RTCP_MAX_UNICAST_MODE) { + return ("Invalid rtcp unicast mode"); + } else { + return (sdp_rtcp_unicast_mode_val[type].name); + } +} + +/* Function: sdp_init_description + * Description: Allocates a new SDP structure that can be used for either + * parsing or building an SDP description. This routine + * saves the config pointer passed in the SDP structure so + * SDP will know how to parse/build based on the options defined. + * An SDP structure must be allocated before parsing or building + * since the handle must be passed to these routines. + * Parameters: config_p The config handle returned by sdp_init_config + * Returns: A handle for a new SDP structure as a void ptr. +*/ +sdp_t *sdp_init_description (sdp_conf_options_t *conf_p) +{ + int i; + sdp_t *sdp_p; + + if (!conf_p) { + return (NULL); + } + + sdp_p = (sdp_t *)SDP_MALLOC(sizeof(sdp_t)); + if (sdp_p == NULL) { + return (NULL); + } + + sdp_p->conf_p = conf_p; + sdp_p->version = SDP_CURRENT_VERSION; + sdp_p->owner_name[0] = '\0'; + sdp_p->owner_sessid[0] = '\0'; + sdp_p->owner_version[0] = '\0'; + sdp_p->owner_network_type = SDP_NT_INVALID; + sdp_p->owner_addr_type = SDP_AT_INVALID; + sdp_p->owner_addr[0] = '\0'; + sdp_p->sessname[0] = '\0'; + sdp_p->sessinfo_found = FALSE; + sdp_p->uri_found = FALSE; + + sdp_p->default_conn.nettype = SDP_NT_INVALID; + sdp_p->default_conn.addrtype = SDP_AT_INVALID; + sdp_p->default_conn.conn_addr[0] = '\0'; + sdp_p->default_conn.is_multicast = FALSE; + sdp_p->default_conn.ttl = 0; + sdp_p->default_conn.num_of_addresses = 0; + + sdp_p->bw.bw_data_count = 0; + sdp_p->bw.bw_data_list = NULL; + + sdp_p->timespec_p = NULL; + sdp_p->sess_attrs_p = NULL; + sdp_p->mca_p = NULL; + sdp_p->mca_count = 0; + + /* Set default debug flags from application config. */ + for (i=0; i < SDP_MAX_DEBUG_TYPES; i++) { + sdp_p->debug_flag[i] = conf_p->debug_flag[i]; + } + + return (sdp_p); +} + + +/* Function: void sdp_debug(sdp_t *sdp_p, sdp_debug_e debug_type, + * tinybool my_bool); + * Description: Define the type of debug for this particular SDP structure. + * By default, each SDP description has the settings that are + * set for the application. + * Valid debug types are ERRORS, WARNINGS, and TRACE. Each + * debug type can be turned on/off individually. The + * debug level can be redefined at any time. + * Parameters: sdp_ptr The SDP handle returned by sdp_init_description. + * debug_type Specifies the debug type being enabled/disabled. + * my_bool Defines whether the debug should be enabled or not. + * Returns: Nothing. + */ +void sdp_debug (sdp_t *sdp_p, sdp_debug_e debug_type, tinybool debug_flag) +{ + if (!sdp_p) { + return; + } + + if (debug_type < SDP_MAX_DEBUG_TYPES) { + sdp_p->debug_flag[debug_type] = debug_flag; + } +} + + +/* Function: void sdp_set_string_debug(sdp_t *sdp_p, char *debug_str) + * Description: Define a string to be associated with all debug output + * for this SDP. The string will be copied into the SDP + * structure and so the library will not be dependent on + * the application's memory for this string. + * Parameters: sdp_p The SDP handle returned by sdp_init_description. + * debug_str Pointer to a string that should be printed out + * with every debug msg. + * Returns: Nothing. + */ +void sdp_set_string_debug (sdp_t *sdp_p, const char *debug_str) +{ + if (!sdp_p) { + return; + } + + sstrncpy(sdp_p->debug_str, debug_str, sizeof(sdp_p->debug_str)); +} + + +/* Function: sdp_validate_sdp + * Description: Validate an SDP structure. + * Parameters: sdp_p The SDP handle of the struct to validate. + * Returns: A result value indicating if the validation was successful. + * If not, what type of error was encountered. + */ +sdp_result_e sdp_validate_sdp (sdp_t *sdp_p) +{ + int i; + uint16_t num_media_levels; + + /* Need to validate c= info is specified at session level or + * at all m= levels. + */ + if (sdp_connection_valid((void *)sdp_p, SDP_SESSION_LEVEL) == FALSE) { + num_media_levels = sdp_get_num_media_lines((void *)sdp_p); + for (i=1; i <= num_media_levels; i++) { + if (sdp_connection_valid((void *)sdp_p, (unsigned short)i) == FALSE) { + sdp_parse_error(sdp_p, + "%s c= connection line not specified for " + "every media level, validation failed.", + sdp_p->debug_str); + return (SDP_FAILURE); + } + } + } + + /* Validate required lines were specified */ + if ((sdp_owner_valid((void *)sdp_p) == FALSE) && + (sdp_p->conf_p->owner_reqd == TRUE)) { + sdp_parse_error(sdp_p, + "%s o= owner line not specified, validation failed.", + sdp_p->debug_str); + return (SDP_FAILURE); + } + + if ((sdp_session_name_valid((void *)sdp_p) == FALSE) && + (sdp_p->conf_p->session_name_reqd == TRUE)) { + sdp_parse_error(sdp_p, + "%s s= session name line not specified, validation failed.", + sdp_p->debug_str); + return (SDP_FAILURE); + } + + if ((sdp_timespec_valid((void *)sdp_p) == FALSE) && + (sdp_p->conf_p->timespec_reqd == TRUE)) { + sdp_parse_error(sdp_p, + "%s t= timespec line not specified, validation failed.", + sdp_p->debug_str); + return (SDP_FAILURE); + } + + return (SDP_SUCCESS); +} + +/* Function: sdp_parse + * Description: Parse an SDP description in the specified buffer. + * Parameters: sdp_p The SDP handle returned by sdp_init_description + * bufp Pointer to the buffer containing the SDP + * description to parse. + * len The length of the buffer. + * Returns: A result value indicating if the parse was successful and + * if not, what type of error was encountered. The + * information from the parse is stored in the sdp_p structure. + */ +sdp_result_e sdp_parse (sdp_t *sdp_p, const char *buf, size_t len) +{ + uint8_t i; + uint16_t cur_level = SDP_SESSION_LEVEL; + const char *ptr; + const char *next_ptr = NULL; + char *line_end; + sdp_token_e last_token = SDP_TOKEN_V; + sdp_result_e result = SDP_SUCCESS; + tinybool parse_done = FALSE; + tinybool end_found = FALSE; + tinybool first_line = TRUE; + tinybool unrec_token = FALSE; + const char **bufp = &buf; + + if (!sdp_p) { + return (SDP_INVALID_SDP_PTR); + } + + if ((bufp == NULL) || (*bufp == NULL)) { + return (SDP_NULL_BUF_PTR); + } + + if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) { + SDP_PRINT("%s Trace SDP Parse:", sdp_p->debug_str); + } + + next_ptr = *bufp; + sdp_p->conf_p->num_parses++; + + /* Initialize the last valid capability instance to zero. Used + * to help in parsing X-cpar attrs. */ + sdp_p->cap_valid = FALSE; + sdp_p->last_cap_inst = 0; + + sdp_p->parse_line = 0; + + /* We want to try to find the end of the SDP description, even if + * we find a parsing error. + */ + while (!end_found) { + /* If the last char of this line goes beyond the end of the buffer, + * we don't parse it. + */ + ptr = next_ptr; + sdp_p->parse_line++; + line_end = sdp_findchar(ptr, "\n"); + if ((line_end >= (*bufp + len)) || + (*line_end == '\0')) { + /* As this does not update the result value the SDP up to this point + * is still accept as valid. So encountering this is not treated as + * an error. + */ + sdp_parse_error(sdp_p, + "%s End of line beyond end of buffer.", + sdp_p->debug_str); + SDPLogError(logTag, "SDP: Invalid SDP, no \\n (len %u): %*s", + (unsigned)len, (int)len, *bufp); + end_found = TRUE; + break; + } + + /* Print the line if we're tracing. */ + if ((parse_done == FALSE) && + (sdp_p->debug_flag[SDP_DEBUG_TRACE])) { + SDP_PRINT("%s ", sdp_p->debug_str); + + SDP_PRINT("%*s", (int)(line_end - ptr), ptr); + + } + + /* Find out which token this line has, if any. */ + for (i=0; i < SDP_MAX_TOKENS; i++) { + if (strncmp(ptr, sdp_token[i].name, SDP_TOKEN_LEN) == 0) { + break; + } + } + if (i == SDP_MAX_TOKENS) { + /* See if the second char on the next line is an '=' char. + * If so, we note this as an unrecognized token line. */ + if (ptr[1] == '=') { + unrec_token = TRUE; + } + if (first_line == TRUE) { + sdp_parse_error(sdp_p, + "%s Attempt to parse text not recognized as " + "SDP text, parse fails.", sdp_p->debug_str); + /* If we haven't already printed out the line we + * were trying to parse, do it now. + */ + if (!sdp_p->debug_flag[SDP_DEBUG_TRACE]) { + SDP_PRINT("%s ", sdp_p->debug_str); + SDP_PRINT("%*s", (int)(line_end - ptr), ptr); + } + sdp_p->conf_p->num_not_sdp_desc++; + return (SDP_NOT_SDP_DESCRIPTION); + } else { + end_found = TRUE; + break; + } + } + + /* This is the beginning of a new SDP description. */ + if ((first_line != TRUE) && (i == SDP_TOKEN_V)) { + end_found = TRUE; + break; + } + + /* Advance the next ptr to one char beyond the end of the line. */ + next_ptr = line_end + 1; + if (next_ptr >= (*bufp + len)) { + end_found = TRUE; + } + + /* If we've finished parsing and are just looking for the end of + * the SDP description, we don't need to do anything else here. + */ + if (parse_done == TRUE) { + continue; + } + + /* Only certain tokens are valid at the media level. */ + if (cur_level != SDP_SESSION_LEVEL) { + if ((i != SDP_TOKEN_I) && (i != SDP_TOKEN_C) && + (i != SDP_TOKEN_B) && (i != SDP_TOKEN_K) && + (i != SDP_TOKEN_A) && (i != SDP_TOKEN_M)) { + sdp_p->conf_p->num_invalid_token_order++; + sdp_parse_error(sdp_p, + "%s Warning: Invalid token %s found at media level", + sdp_p->debug_str, sdp_token[i].name); + continue; + } + } + + /* Verify the token ordering. */ + if (first_line == TRUE) { + if (i != SDP_TOKEN_V) { + if (sdp_p->conf_p->version_reqd == TRUE) { + sdp_parse_error(sdp_p, + "%s First line not v=, parse fails", + sdp_p->debug_str); + sdp_p->conf_p->num_invalid_token_order++; + result = SDP_INVALID_TOKEN_ORDERING; + parse_done = TRUE; + } else { + last_token = (sdp_token_e)i; + } + } else { + last_token = (sdp_token_e)i; + } + first_line = FALSE; + } else { + if (i < last_token) { + sdp_p->conf_p->num_invalid_token_order++; + sdp_parse_error(sdp_p, + "%s Warning: Invalid token ordering detected, " + "token %s found after token %s", sdp_p->debug_str, + sdp_token[i].name, sdp_token[last_token].name); + } + } + + /* Finally parse the line. */ + ptr += SDP_TOKEN_LEN; + result = sdp_token[i].parse_func(sdp_p, cur_level, (const char *)ptr); + last_token = (sdp_token_e)i; + if (last_token == SDP_TOKEN_M) { + if (cur_level == SDP_SESSION_LEVEL) { + cur_level = 1; + } else { + cur_level++; + } + /* The token ordering can start again at i= */ + last_token = (sdp_token_e)(SDP_TOKEN_I - 1); + } + if (result != SDP_SUCCESS) { + parse_done = TRUE; + } + + /* Skip the new line char at the end of this line and see if + * this is the end of the buffer. + */ + if ((line_end + 1) == (*bufp + len)) { + end_found = TRUE; + } + } + + /* If we found no valid lines, return an error. */ + if (first_line == TRUE) { + sdp_p->conf_p->num_not_sdp_desc++; + return (SDP_NOT_SDP_DESCRIPTION); + } + + /* If no errors were found yet, validate the overall sdp. */ + if (result == SDP_SUCCESS) { + result = sdp_validate_sdp(sdp_p); + } + /* Return the pointer where we left off. */ + *bufp = next_ptr; + /* If the SDP is valid, but the next line following was an + * unrecognized <token>= line, indicate this on the return. */ + if ((result == SDP_SUCCESS) && (unrec_token == TRUE)) { + return (SDP_UNRECOGNIZED_TOKEN); + } else { + return (result); + } +} + + +/* Function: sdp_build + * Description: Build an SDP description in the specified buffer based + * on the information in the given SDP structure. + * Parameters: sdp_p The SDP handle returned by sdp_init_description + * fs A flex_string where the SDP description should be built. + * Returns: A result value indicating if the build was successful and + * if not, what type of error was encountered - e.g., + * description was too long for the given buffer. + */ +sdp_result_e sdp_build (sdp_t *sdp_p, flex_string *fs) +{ + int i, j; + sdp_result_e result = SDP_SUCCESS; + + if (!sdp_p) { + return (SDP_INVALID_SDP_PTR); + } + + if (!fs) { + return (SDP_NULL_BUF_PTR); + } + + if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) { + SDP_PRINT("%s Trace SDP Build:", sdp_p->debug_str); + } + + sdp_p->conf_p->num_builds++; + + for (i=0; ((i < SDP_TOKEN_M) && + (result == SDP_SUCCESS)); i++) { + result = sdp_token[i].build_func(sdp_p, SDP_SESSION_LEVEL, fs); + /* ok not to check buffer space (yet) as the if() checks it */ + } + /* If the session level was ok, build the media lines. */ + if (result == SDP_SUCCESS) { + for (i=1; ((i <= sdp_p->mca_count) && + (result == SDP_SUCCESS)); i++) { + result = sdp_token[SDP_TOKEN_M].build_func(sdp_p, (uint16_t)i, fs); + + /* ok not to check buffer space (yet) as the for() checks it */ + for (j=SDP_TOKEN_I; + ((j < SDP_TOKEN_M) && (result == SDP_SUCCESS)); + j++) { + if ((j == SDP_TOKEN_U) || (j == SDP_TOKEN_E) || + (j == SDP_TOKEN_P) || (j == SDP_TOKEN_T) || + (j == SDP_TOKEN_R) || (j == SDP_TOKEN_Z)) { + /* These tokens not valid at media level. */ + continue; + } + result = sdp_token[j].build_func(sdp_p, (uint16_t)i, fs); + /* ok not to check buffer space (yet) as the for() checks it */ + } + } + } + + return (result); +} + +/* Function: sdp_free_description + * Description: Free an SDP description and all memory associated with it. + * Parameters: sdp_p The SDP handle returned by sdp_init_description + * Returns: A result value indicating if the free was successful and + * if not, what type of error was encountered - e.g., sdp_p + * was invalid and didn't point to an SDP structure. +*/ +sdp_result_e sdp_free_description (sdp_t *sdp_p) +{ + sdp_timespec_t *time_p, *next_time_p; + sdp_attr_t *attr_p, *next_attr_p; + sdp_mca_t *mca_p, *next_mca_p; + sdp_bw_t *bw_p; + sdp_bw_data_t *bw_data_p; + + if (!sdp_p) { + return (SDP_INVALID_SDP_PTR); + } + + /* Free the config structure */ + sdp_free_config(sdp_p->conf_p); + + /* Free any timespec structures - should be only one since + * this is all we currently support. + */ + time_p = sdp_p->timespec_p; + while (time_p != NULL) { + next_time_p = time_p->next_p; + SDP_FREE(time_p); + time_p = next_time_p; + } + + bw_p = &(sdp_p->bw); + bw_data_p = bw_p->bw_data_list; + while (bw_data_p != NULL) { + bw_p->bw_data_list = bw_data_p->next_p; + SDP_FREE(bw_data_p); + bw_data_p = bw_p->bw_data_list; + } + + /* Free any session attr structures */ + attr_p = sdp_p->sess_attrs_p; + while (attr_p != NULL) { + next_attr_p = attr_p->next_p; + sdp_free_attr(attr_p); + attr_p = next_attr_p; + } + + /* Free any mca structures */ + mca_p = sdp_p->mca_p; + while (mca_p != NULL) { + next_mca_p = mca_p->next_p; + + /* Free any media attr structures */ + attr_p = mca_p->media_attrs_p; + while (attr_p != NULL) { + next_attr_p = attr_p->next_p; + sdp_free_attr(attr_p); + attr_p = next_attr_p; + } + + /* Free the media profiles struct if allocated. */ + if (mca_p->media_profiles_p != NULL) { + SDP_FREE(mca_p->media_profiles_p); + } + + bw_p = &(mca_p->bw); + bw_data_p = bw_p->bw_data_list; + while (bw_data_p != NULL) { + bw_p->bw_data_list = bw_data_p->next_p; + SDP_FREE(bw_data_p); + bw_data_p = bw_p->bw_data_list; + } + + SDP_FREE(mca_p); + mca_p = next_mca_p; + } + + SDP_FREE(sdp_p); + + return (SDP_SUCCESS); +} + +/* + * sdp_parse_error + * Send SDP parsing errors to log and up to peerconnection + */ +void sdp_parse_error(sdp_t* sdp, const char *format, ...) { + flex_string fs; + va_list ap; + + flex_string_init(&fs); + + va_start(ap, format); + flex_string_vsprintf(&fs, format, ap); + va_end(ap); + + SDPLogError("SDP Parse", "SDP Parse Error %s, line %u", fs.buffer, + sdp->parse_line); + + if (sdp->conf_p->error_handler) { + sdp->conf_p->error_handler(sdp->conf_p->error_handler_context, + sdp->parse_line, + fs.buffer); + } + + flex_string_free(&fs); +} diff --git a/third_party/sipcc/sdp_os_defs.h b/third_party/sipcc/sdp_os_defs.h new file mode 100644 index 0000000000..16c9b33329 --- /dev/null +++ b/third_party/sipcc/sdp_os_defs.h @@ -0,0 +1,27 @@ +/* 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/. */ + +#ifndef _SDP_OS_DEFS_H_ +#define _SDP_OS_DEFS_H_ + +#include <stdlib.h> + +#include "cpr_types.h" +#include "cpr_string.h" + + +#define SDP_PRINT(format, ...) SDPLogError("sdp" , format , ## __VA_ARGS__ ) + +/* Use operating system malloc */ +#define SDP_MALLOC(x) calloc(1, (x)) +#define SDP_FREE free + +typedef uint8_t tinybool; +typedef unsigned short ushort; +typedef unsigned long ulong; +#ifndef __GNUC_STDC_INLINE__ +#define inline +#endif + +#endif /* _SDP_OS_DEFS_H_ */ diff --git a/third_party/sipcc/sdp_private.h b/third_party/sipcc/sdp_private.h new file mode 100644 index 0000000000..8ce871938e --- /dev/null +++ b/third_party/sipcc/sdp_private.h @@ -0,0 +1,365 @@ +/* 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/. */ + +#ifndef _SIPCC_SDP_PRIVATE_H_ +#define _SIPCC_SDP_PRIVATE_H_ + + +#include "sipcc_sdp.h" + +extern const sdp_attrarray_t sdp_attr[]; +extern const sdp_namearray_t sdp_media[]; +extern const sdp_namearray_t sdp_nettype[]; +extern const sdp_namearray_t sdp_addrtype[]; +extern const sdp_namearray_t sdp_transport[]; +extern const sdp_namearray_t sdp_encrypt[]; +extern const sdp_namearray_t sdp_payload[]; +extern const sdp_namearray_t sdp_t38_rate[]; +extern const sdp_namearray_t sdp_t38_udpec[]; +extern const sdp_namearray_t sdp_qos_strength[]; +extern const sdp_namearray_t sdp_qos_direction[]; +extern const sdp_namearray_t sdp_qos_status_type[]; +extern const sdp_namearray_t sdp_curr_type[]; +extern const sdp_namearray_t sdp_des_type[]; +extern const sdp_namearray_t sdp_conf_type[]; +extern const sdp_namearray_t sdp_mediadir_role[]; +extern const sdp_namearray_t sdp_fmtp_codec_param[]; +extern const sdp_namearray_t sdp_fmtp_codec_param_val[]; +extern const sdp_namearray_t sdp_silencesupp_pref[]; +extern const sdp_namearray_t sdp_silencesupp_siduse[]; +extern const sdp_namearray_t sdp_srtp_context_crypto_suite[]; +extern const sdp_namearray_t sdp_bw_modifier_val[]; +extern const sdp_namearray_t sdp_group_attr_val[]; +extern const sdp_namearray_t sdp_ssrc_group_attr_val[]; +extern const sdp_namearray_t sdp_src_filter_mode_val[]; +extern const sdp_namearray_t sdp_rtcp_unicast_mode_val[]; +extern const sdp_namearray_t sdp_rtcp_fb_type_val[]; +extern const sdp_namearray_t sdp_rtcp_fb_nack_type_val[]; +extern const sdp_namearray_t sdp_rtcp_fb_ack_type_val[]; +extern const sdp_namearray_t sdp_rtcp_fb_ccm_type_val[]; +extern const sdp_namearray_t sdp_setup_type_val[]; +extern const sdp_namearray_t sdp_connection_type_val[]; + + +extern const sdp_srtp_crypto_suite_list sdp_srtp_crypto_suite_array[]; +/* Function Prototypes */ + +/* sdp_access.c */ +extern sdp_mca_t *sdp_find_media_level(sdp_t *sdp_p, uint16_t level); +extern sdp_bw_data_t* sdp_find_bw_line (sdp_t *sdp_ptr, uint16_t level, uint16_t inst_num); + +/* sdp_attr.c */ +extern sdp_result_e +sdp_build_attr_fmtp_params (sdp_t *sdp_p, sdp_fmtp_t *attr_p, flex_string *fs); + +extern sdp_result_e sdp_parse_attribute(sdp_t *sdp_p, uint16_t level, + const char *ptr); +extern sdp_result_e sdp_parse_attr_simple_string(sdp_t *sdp_p, + sdp_attr_t *attr_p, const char *ptr); +extern sdp_result_e sdp_build_attr_simple_string(sdp_t *sdp_p, + sdp_attr_t *attr_p, flex_string *fs); +extern sdp_result_e sdp_parse_attr_simple_u32(sdp_t *sdp_p, + sdp_attr_t *attr_p, const char *ptr); +extern sdp_result_e sdp_build_attr_simple_u32(sdp_t *sdp_p, + sdp_attr_t *attr_p, flex_string *fs); +extern sdp_result_e sdp_parse_attr_simple_bool(sdp_t *sdp_p, + sdp_attr_t *attr_p, const char *ptr); +extern sdp_result_e sdp_build_attr_simple_bool(sdp_t *sdp_p, + sdp_attr_t *attr_p, flex_string *fs); +extern sdp_result_e sdp_parse_attr_maxprate(sdp_t *sdp_p, sdp_attr_t *attr_p, + const char *ptr); +extern sdp_result_e sdp_parse_attr_fmtp(sdp_t *sdp_p, sdp_attr_t *attr_p, + const char *ptr); +extern sdp_result_e sdp_build_attr_fmtp(sdp_t *sdp_p, sdp_attr_t *attr_p, + flex_string *fs); +extern sdp_result_e sdp_parse_attr_sctpmap(sdp_t *sdp_p, sdp_attr_t *attr_p, + const char *ptr); +extern sdp_result_e sdp_build_attr_sctpmap(sdp_t *sdp_p, sdp_attr_t *attr_p, + flex_string *fs); +extern sdp_result_e sdp_parse_attr_msid(sdp_t *sdp_p, sdp_attr_t *attr_p, + const char *ptr); +extern sdp_result_e sdp_build_attr_msid(sdp_t *sdp_p, sdp_attr_t *attr_p, + flex_string *fs); +extern sdp_result_e sdp_parse_attr_msid_semantic(sdp_t *sdp_p, + sdp_attr_t *attr_p, + const char *ptr); +extern sdp_result_e sdp_build_attr_msid_semantic(sdp_t *sdp_p, + sdp_attr_t *attr_p, + flex_string *fs); +extern sdp_result_e sdp_parse_attr_ssrc(sdp_t *sdp_p, sdp_attr_t *attr_p, + const char *ptr); +extern sdp_result_e sdp_build_attr_ssrc(sdp_t *sdp_p, sdp_attr_t *attr_p, + flex_string *fs); +extern sdp_result_e sdp_parse_attr_ssrc_group(sdp_t *sdp_p, sdp_attr_t *attr_p, + const char *ptr); +extern sdp_result_e sdp_build_attr_ssrc_group(sdp_t *sdp_p, sdp_attr_t *attr_p, + flex_string *fs); +extern sdp_result_e sdp_parse_attr_direction(sdp_t *sdp_p, sdp_attr_t *attr_p, + const char *ptr); +extern sdp_result_e sdp_build_attr_direction(sdp_t *sdp_p, sdp_attr_t *attr_p, + flex_string *fs); +extern sdp_result_e sdp_parse_attr_qos(sdp_t *sdp_p, sdp_attr_t *attr_p, + const char *ptr); +extern sdp_result_e sdp_build_attr_qos(sdp_t *sdp_p, sdp_attr_t *attr_p, + flex_string *fs); +extern sdp_result_e sdp_parse_attr_curr(sdp_t *sdp_p, sdp_attr_t *attr_p, + const char *ptr); +extern sdp_result_e sdp_build_attr_curr (sdp_t *sdp_p, sdp_attr_t *attr_p, + flex_string *fs); +extern sdp_result_e sdp_parse_attr_des(sdp_t *sdp_p, sdp_attr_t *attr_p, + const char *ptr); +extern sdp_result_e sdp_build_attr_des (sdp_t *sdp_p, sdp_attr_t *attr_p, + flex_string *fs); +extern sdp_result_e sdp_parse_attr_conf(sdp_t *sdp_p, sdp_attr_t *attr_p, + const char *ptr); +extern sdp_result_e sdp_build_attr_conf (sdp_t *sdp_p, sdp_attr_t *attr_p, + flex_string *fs); +extern sdp_result_e sdp_parse_attr_transport_map(sdp_t *sdp_p, + sdp_attr_t *attr_p, const char *ptr); +extern sdp_result_e sdp_build_attr_transport_map(sdp_t *sdp_p, + sdp_attr_t *attr_p, flex_string *fs); +extern sdp_result_e sdp_parse_attr_subnet(sdp_t *sdp_p, sdp_attr_t *attr_p, + const char *ptr); +extern sdp_result_e sdp_build_attr_subnet(sdp_t *sdp_p, sdp_attr_t *attr_p, + flex_string *fs); +extern sdp_result_e sdp_parse_attr_t38_ratemgmt(sdp_t *sdp_p, + sdp_attr_t *attr_p, const char *ptr); +extern sdp_result_e sdp_build_attr_t38_ratemgmt(sdp_t *sdp_p, + sdp_attr_t *attr_p, flex_string *fs); +extern sdp_result_e sdp_parse_attr_t38_udpec(sdp_t *sdp_p, sdp_attr_t *attr_p, + const char *ptr); +extern sdp_result_e sdp_build_attr_t38_udpec(sdp_t *sdp_p, sdp_attr_t *attr_p, + flex_string *fs); +extern sdp_result_e sdp_parse_attr_cap(sdp_t *sdp_p, sdp_attr_t *attr_p, + const char *ptr); +extern sdp_result_e sdp_build_attr_cap(sdp_t *sdp_p, sdp_attr_t *attr_p, + flex_string *fs); +extern sdp_result_e sdp_parse_attr_cpar(sdp_t *sdp_p, sdp_attr_t *attr_p, + const char *ptr); +extern sdp_result_e sdp_build_attr_cpar(sdp_t *sdp_p, sdp_attr_t *attr_p, + flex_string *fs); +extern sdp_result_e sdp_parse_attr_pc_codec(sdp_t *sdp_p, sdp_attr_t *attr_p, + const char *ptr); +extern sdp_result_e sdp_build_attr_pc_codec(sdp_t *sdp_p, sdp_attr_t *attr_p, + flex_string *fs); +extern sdp_result_e sdp_parse_attr_xcap(sdp_t *sdp_p, sdp_attr_t *attr_p, + const char *ptr); +extern sdp_result_e sdp_build_attr_xcap(sdp_t *sdp_p, sdp_attr_t *attr_p, + flex_string *fs); +extern sdp_result_e sdp_parse_attr_xcpar(sdp_t *sdp_p, sdp_attr_t *attr_p, + const char *ptr); +extern sdp_result_e sdp_build_attr_xcpar(sdp_t *sdp_p, sdp_attr_t *attr_p, + flex_string *fs); +extern sdp_result_e sdp_parse_attr_rtcp(sdp_t *sdp_p, sdp_attr_t *attr_p, + const char *ptr); +extern sdp_result_e sdp_build_attr_rtcp(sdp_t *sdp_p, sdp_attr_t *attr_p, + flex_string *fs); +extern sdp_result_e sdp_parse_attr_rtr(sdp_t *sdp_p, sdp_attr_t *attr_p, + const char *ptr); +extern sdp_result_e sdp_build_attr_rtr(sdp_t *sdp_p, sdp_attr_t *attr_p, + flex_string *fs); +extern sdp_result_e sdp_parse_attr_comediadir(sdp_t *sdp_p, sdp_attr_t *attr_p, + const char *ptr); +extern sdp_result_e sdp_build_attr_comediadir(sdp_t *sdp_p, sdp_attr_t *attr_p, + flex_string *fs); +extern sdp_result_e sdp_parse_attr_silencesupp(sdp_t *sdp_p, + sdp_attr_t *attr_p, + const char *ptr); +extern sdp_result_e sdp_build_attr_silencesupp(sdp_t *sdp_p, + sdp_attr_t *attr_p, + flex_string *fs); +extern sdp_result_e sdp_parse_attr_srtpcontext(sdp_t *sdp_p, + sdp_attr_t *attr_p, + const char *ptr); +extern sdp_result_e sdp_build_attr_srtpcontext(sdp_t *sdp_p, + sdp_attr_t *attr_p, + flex_string *fs); +extern sdp_result_e sdp_parse_attr_rtcp_fb(sdp_t *sdp_p, + sdp_attr_t *attr_p, + const char *ptr); +extern sdp_result_e sdp_build_attr_rtcp_fb(sdp_t *sdp_p, + sdp_attr_t *attr_p, + flex_string *fs); +extern sdp_result_e sdp_parse_attr_setup(sdp_t *sdp_p, + sdp_attr_t *attr_p, + const char *ptr); +extern sdp_result_e sdp_build_attr_setup(sdp_t *sdp_p, + sdp_attr_t *attr_p, + flex_string *fs); +extern sdp_result_e sdp_parse_attr_connection(sdp_t *sdp_p, + sdp_attr_t *attr_p, + const char *ptr); +extern sdp_result_e sdp_build_attr_connection(sdp_t *sdp_p, + sdp_attr_t *attr_p, + flex_string *fs); +extern sdp_result_e sdp_parse_attr_extmap(sdp_t *sdp_p, + sdp_attr_t *attr_p, + const char *ptr); +extern sdp_result_e sdp_build_attr_extmap(sdp_t *sdp_p, + sdp_attr_t *attr_p, + flex_string *fs); +extern sdp_result_e sdp_parse_attr_mptime( + sdp_t *sdp_p, sdp_attr_t *attr_p, const char *ptr); +extern sdp_result_e sdp_build_attr_mptime( + sdp_t *sdp_p, sdp_attr_t *attr_p, flex_string *fs); +extern sdp_result_e sdp_parse_attr_x_sidin( + sdp_t *sdp_p, sdp_attr_t *attr_p, const char *ptr); +extern sdp_result_e sdp_build_attr_x_sidin( + sdp_t *sdp_p, sdp_attr_t *attr_p, flex_string *fs); + +extern sdp_result_e sdp_parse_attr_x_sidout( + sdp_t *sdp_p, sdp_attr_t *attr_p, const char *ptr); +extern sdp_result_e sdp_build_attr_x_sidout( + sdp_t *sdp_p, sdp_attr_t *attr_p, flex_string *fs); + +extern sdp_result_e sdp_parse_attr_x_confid( + sdp_t *sdp_p, sdp_attr_t *attr_p, const char *ptr); +extern sdp_result_e sdp_build_attr_x_confid( + sdp_t *sdp_p, sdp_attr_t *attr_p, flex_string *fs); + +extern sdp_result_e sdp_parse_attr_group( + sdp_t *sdp_p, sdp_attr_t *attr_p, const char *ptr); +extern sdp_result_e sdp_build_attr_group( + sdp_t *sdp_p, sdp_attr_t *attr_p, flex_string *fs); + +extern sdp_result_e sdp_parse_attr_source_filter( + sdp_t *sdp_p, sdp_attr_t *attr_p, const char *ptr); +extern sdp_result_e sdp_build_source_filter( + sdp_t *sdp_p, sdp_attr_t *attr_p, flex_string *fs); + +extern sdp_result_e sdp_parse_attr_rtcp_unicast( + sdp_t *sdp_p, sdp_attr_t *attr_p, const char *ptr); +extern sdp_result_e sdp_build_attr_rtcp_unicast( + sdp_t *sdp_p, sdp_attr_t *attr_p, flex_string *fs); + +extern sdp_result_e sdp_build_attr_ice_attr ( + sdp_t *sdp_p, sdp_attr_t *attr_p, flex_string *fs); +extern sdp_result_e sdp_parse_attr_ice_attr ( + sdp_t *sdp_p, sdp_attr_t *attr_p, const char *ptr); + +extern sdp_result_e sdp_build_attr_simple_flag ( + sdp_t *sdp_p, sdp_attr_t *attr_p, flex_string *fs); +extern sdp_result_e sdp_parse_attr_simple_flag ( + sdp_t *sdp_p, sdp_attr_t *attr_p, const char *ptr); + +extern sdp_result_e sdp_parse_attr_complete_line ( + sdp_t *sdp_p, sdp_attr_t *attr_p, const char *ptr); +extern sdp_result_e sdp_parse_attr_long_line(sdp_t *sdp_p, + sdp_attr_t *attr_p, const char *ptr); +extern sdp_result_e sdp_build_attr_long_line(sdp_t *sdp_p, + sdp_attr_t *attr_p, flex_string *fs); + +/* sdp_attr_access.c */ +extern void sdp_free_attr(sdp_attr_t *attr_p); +extern sdp_result_e sdp_find_attr_list(sdp_t *sdp_p, uint16_t level, uint8_t cap_num, + sdp_attr_t **attr_p, char *fname); +extern sdp_attr_t *sdp_find_attr(sdp_t *sdp_p, uint16_t level, uint8_t cap_num, + sdp_attr_e attr_type, uint16_t inst_num); +extern sdp_attr_t *sdp_find_capability(sdp_t *sdp_p, uint16_t level, uint8_t cap_num); + +/* sdp_main.c */ +extern const char *sdp_get_attr_name(sdp_attr_e attr_type); +extern const char *sdp_get_media_name(sdp_media_e media_type); +extern const char *sdp_get_network_name(sdp_nettype_e network_type); +extern const char *sdp_get_address_name(sdp_addrtype_e addr_type); +extern const char *sdp_get_transport_name(sdp_transport_e transport_type); +extern const char *sdp_get_encrypt_name(sdp_encrypt_type_e encrypt_type); +extern const char *sdp_get_payload_name(sdp_payload_e payload); +extern const char *sdp_get_t38_ratemgmt_name(sdp_t38_ratemgmt_e rate); +extern const char *sdp_get_t38_udpec_name(sdp_t38_udpec_e udpec); +extern const char *sdp_get_qos_strength_name(sdp_qos_strength_e strength); +extern const char *sdp_get_qos_direction_name(sdp_qos_dir_e direction); +extern const char *sdp_get_qos_status_type_name(sdp_qos_status_types_e status_type); +extern const char *sdp_get_curr_type_name(sdp_curr_type_e curr_type); +extern const char *sdp_get_des_type_name(sdp_des_type_e des_type); +extern const char *sdp_get_conf_type_name(sdp_conf_type_e conf_type); +extern const char *sdp_get_mediadir_role_name (sdp_mediadir_role_e role); +extern const char *sdp_get_silencesupp_pref_name(sdp_silencesupp_pref_e pref); +extern const char *sdp_get_silencesupp_siduse_name(sdp_silencesupp_siduse_e + siduse); + +extern const char *sdp_get_group_attr_name(sdp_group_attr_e group_attr); +extern const char *sdp_get_ssrc_group_attr_name(sdp_ssrc_group_attr_e group_attr); +extern const char *sdp_get_src_filter_mode_name(sdp_src_filter_mode_e type); +extern const char *sdp_get_rtcp_unicast_mode_name(sdp_rtcp_unicast_mode_e type); + +/* sdp_tokens.c */ +extern sdp_result_e sdp_parse_version(sdp_t *sdp_p, uint16_t token, + const char *ptr); +extern sdp_result_e sdp_build_version(sdp_t *sdp_p, uint16_t token, flex_string *fs); +extern sdp_result_e sdp_parse_owner(sdp_t *sdp_p, uint16_t token, + const char *ptr); +extern sdp_result_e sdp_build_owner(sdp_t *sdp_p, uint16_t token, flex_string *fs); +extern sdp_result_e sdp_parse_sessname(sdp_t *sdp_p, uint16_t token, + const char *ptr); +extern sdp_result_e sdp_build_sessname(sdp_t *sdp_p, uint16_t token, flex_string *fs); +extern sdp_result_e sdp_parse_sessinfo(sdp_t *sdp_p, uint16_t token, + const char *ptr); +extern sdp_result_e sdp_build_sessinfo(sdp_t *sdp_p, uint16_t token, flex_string *fs); +extern sdp_result_e sdp_parse_uri(sdp_t *sdp_p, uint16_t token, const char *ptr); +extern sdp_result_e sdp_build_uri(sdp_t *sdp_p, uint16_t token, flex_string *fs); +extern sdp_result_e sdp_parse_email(sdp_t *sdp_p, uint16_t token, const char *ptr); +extern sdp_result_e sdp_build_email(sdp_t *sdp_p, uint16_t token, flex_string *fs); +extern sdp_result_e sdp_parse_phonenum(sdp_t *sdp_p, uint16_t token, + const char *ptr); +extern sdp_result_e sdp_build_phonenum(sdp_t *sdp_p, uint16_t token, flex_string *fs); +extern sdp_result_e sdp_parse_connection(sdp_t *sdp_p, uint16_t token, + const char *ptr); +extern sdp_result_e sdp_build_connection(sdp_t *sdp_p, uint16_t token, flex_string *fs); +extern sdp_result_e sdp_parse_bandwidth(sdp_t *sdp_p, uint16_t token, + const char *ptr); +extern sdp_result_e sdp_build_bandwidth(sdp_t *sdp_p, uint16_t token, flex_string *fs); +extern sdp_result_e sdp_parse_timespec(sdp_t *sdp_p, uint16_t token, + const char *ptr); +extern sdp_result_e sdp_build_timespec(sdp_t *sdp_p, uint16_t token, flex_string *fs); +extern sdp_result_e sdp_parse_repeat_time(sdp_t *sdp_p, uint16_t token, + const char *ptr); +extern sdp_result_e sdp_build_repeat_time(sdp_t *sdp_p, uint16_t token, flex_string *fs); +extern sdp_result_e sdp_parse_timezone_adj(sdp_t *sdp_p, uint16_t token, + const char *ptr); +extern sdp_result_e sdp_build_timezone_adj(sdp_t *sdp_p, uint16_t token, flex_string *fs); +extern sdp_result_e sdp_parse_encryption(sdp_t *sdp_p, uint16_t token, + const char *ptr); +extern sdp_result_e sdp_build_encryption(sdp_t *sdp_p, uint16_t token, flex_string *fs); +extern sdp_result_e sdp_parse_media(sdp_t *sdp_p, uint16_t token, const char *ptr); +extern sdp_result_e sdp_build_media(sdp_t *sdp_p, uint16_t token, flex_string *fs); +extern sdp_result_e sdp_parse_attribute(sdp_t *sdp_p, uint16_t token, + const char *ptr); +extern sdp_result_e sdp_build_attribute(sdp_t *sdp_p, uint16_t token, flex_string *fs); + +extern void sdp_parse_payload_types(sdp_t *sdp_p, sdp_mca_t *mca_p, + const char *ptr); +extern sdp_result_e +sdp_parse_attr_sdescriptions(sdp_t *sdp_p, sdp_attr_t *attr_p, + const char *ptr); + +extern sdp_result_e +sdp_build_attr_sdescriptions(sdp_t *sdp_p, sdp_attr_t *attr_p, + flex_string *fs); + + +/* sdp_utils.c */ +extern sdp_mca_t *sdp_alloc_mca(uint32_t line); +extern tinybool sdp_validate_maxprate(const char *string_parm); +extern char *sdp_findchar(const char *ptr, char *char_list); +extern const char *sdp_getnextstrtok(const char *str, char *tokenstr, unsigned tokenstr_len, + const char *delim, sdp_result_e *result); +extern uint32_t sdp_getnextnumtok(const char *str, const char **str_end, + const char *delim, sdp_result_e *result); +extern uint32_t sdp_getnextnumtok_or_null(const char *str, const char **str_end, + const char *delim, tinybool *null_ind, + sdp_result_e *result); + +extern +tinybool verify_sdescriptions_mki(char *buf, char *mkiVal, uint16_t *mkiLen); + +extern +tinybool verify_sdescriptions_lifetime(char *buf); + +/* sdp_services_xxx.c */ +extern void sdp_dump_buffer(char *_ptr, int _size_bytes); + +tinybool sdp_checkrange(sdp_t *sdp, char *num, ulong* lval); + +#endif /* _SDP_PRIVATE_H_ */ diff --git a/third_party/sipcc/sdp_services_unix.c b/third_party/sipcc/sdp_services_unix.c new file mode 100644 index 0000000000..85be5b729c --- /dev/null +++ b/third_party/sipcc/sdp_services_unix.c @@ -0,0 +1,41 @@ +/* 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 "sdp_os_defs.h" +#include "sipcc_sdp.h" +#include "sdp_private.h" + +#include "sdp_log.h" + +/******************************************************************/ +/* Required Platform Routines */ +/* */ +/* These routines are called from the common SDP code. */ +/* They must be provided for each platform. */ +/* */ +/******************************************************************/ + +/* + * sdp_dump_buffer + * + * Utility to send _size_bytes of data from the string + * pointed to by _ptr to the buginf function. This may make + * multiple buginf calls if the buffer is too large for buginf. + */ +void sdp_dump_buffer (char * _ptr, int _size_bytes) +{ + SDPLogDebug("sdp", "%s", _ptr); +} + +/******************************************************************/ +/* */ +/* Platform Specific Routines */ +/* */ +/* These routines are only used in this particular platform. */ +/* They are called from the required platform specific */ +/* routines provided below, not from the common SDP code. */ +/* */ +/******************************************************************/ + +/* There are currently no platform specific routines required. */ diff --git a/third_party/sipcc/sdp_services_win32.c b/third_party/sipcc/sdp_services_win32.c new file mode 100644 index 0000000000..3de6812974 --- /dev/null +++ b/third_party/sipcc/sdp_services_win32.c @@ -0,0 +1,41 @@ +/* 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 "sdp_os_defs.h" +#include "sipcc_sdp.h" +#include "sdp_private.h" + +#include "sdp_log.h" + +/******************************************************************/ +/* Required Platform Routines */ +/* */ +/* These routines are called from the common SDP code. */ +/* They must be provided for each platform. */ +/* */ +/******************************************************************/ + +/* + * sdp_dump_buffer + * + * Utility to send _size_bytes of data from the string + * pointed to by _ptr to the buginf function. This may make + * multiple buginf calls if the buffer is too large for buginf. + */ +void sdp_dump_buffer (char * _ptr, int _size_bytes) +{ + SDPLogDebug("sdp", _ptr); +} + +/******************************************************************/ +/* */ +/* Platform Specific Routines */ +/* */ +/* These routines are only used in this particular platform. */ +/* They are called from the required platform specific */ +/* routines provided below, not from the common SDP code. */ +/* */ +/******************************************************************/ + +/* There are currently no platform specific routines required. */ diff --git a/third_party/sipcc/sdp_token.c b/third_party/sipcc/sdp_token.c new file mode 100644 index 0000000000..b570d81690 --- /dev/null +++ b/third_party/sipcc/sdp_token.c @@ -0,0 +1,1686 @@ +/* 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); + } +} + diff --git a/third_party/sipcc/sdp_utils.c b/third_party/sipcc/sdp_utils.c new file mode 100644 index 0000000000..a5b558282e --- /dev/null +++ b/third_party/sipcc/sdp_utils.c @@ -0,0 +1,725 @@ +/* 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 <limits.h> +#include <ctype.h> +#include "sdp_os_defs.h" +#include "sipcc_sdp.h" +#include "sdp_private.h" +#include "sdp_log.h" + +#define MKI_BUF_LEN 4 + +static const char* logTag = "sdp_utils"; + +// Actually checks for ASCII only unlike isdigit() on Windows. +// Also avoids UB issues with isdigit() sign extension when +// char is signed. +int sdp_is_ascii_digit(const char c) { + return '0' <= c && c <= '9'; +} + +sdp_mca_t *sdp_alloc_mca (uint32_t line) { + sdp_mca_t *mca_p; + + /* Allocate resource for new media stream. */ + mca_p = (sdp_mca_t *)SDP_MALLOC(sizeof(sdp_mca_t)); + if (mca_p == NULL) { + return (NULL); + } + /* Initialize mca structure */ + mca_p->media = SDP_MEDIA_INVALID; + mca_p->conn.nettype = SDP_NT_INVALID; + mca_p->conn.addrtype = SDP_AT_INVALID; + mca_p->conn.conn_addr[0] = '\0'; + mca_p->conn.is_multicast = FALSE; + mca_p->conn.ttl = 0; + mca_p->conn.num_of_addresses = 0; + mca_p->transport = SDP_TRANSPORT_INVALID; + mca_p->port = SDP_INVALID_VALUE; + mca_p->num_ports = SDP_INVALID_VALUE; + mca_p->vpi = SDP_INVALID_VALUE; + mca_p->vci = 0; + mca_p->vcci = SDP_INVALID_VALUE; + mca_p->cid = SDP_INVALID_VALUE; + mca_p->num_payloads = 0; + mca_p->sessinfo_found = FALSE; + mca_p->encrypt.encrypt_type = SDP_ENCRYPT_INVALID; + mca_p->media_attrs_p = NULL; + mca_p->next_p = NULL; + mca_p->mid = 0; + mca_p->bw.bw_data_count = 0; + mca_p->bw.bw_data_list = NULL; + mca_p->line_number = line; + mca_p->sctp_fmt = SDP_SCTP_MEDIA_FMT_UNKNOWN; + + return (mca_p); +} + +/* + * next_token + * + * copy token param with chars from str until null, cr, lf, or one of the delimiters is found. + * delimiters at the beginning will be skipped. + * The pointer *string_of_tokens is moved forward to the next token on sucess. + * + */ +static sdp_result_e next_token(const char **string_of_tokens, char *token, unsigned token_max_len, const char *delim) +{ + int flag2moveon = 0; + const char *str; + const char *token_end; + const char *next_delim; + + if (!string_of_tokens || !*string_of_tokens || !token || !delim) { + return SDP_FAILURE; + } + + str = *string_of_tokens; + token_end = token + token_max_len - 1; + + /* Locate front of token, skipping any delimiters */ + for ( ; ((*str != '\0') && (*str != '\n') && (*str != '\r')); str++) { + flag2moveon = 1; /* Default to move on unless we find a delimiter */ + for (next_delim=delim; *next_delim; next_delim++) { + if (*str == *next_delim) { + flag2moveon = 0; + break; + } + } + if( flag2moveon ) { + break; /* We're at the beginning of the token */ + } + } + + /* Make sure there's really a token present. */ + if ((*str == '\0') || (*str == '\n') || (*str == '\r')) { + return SDP_EMPTY_TOKEN; + } + + /* Now locate end of token */ + flag2moveon = 0; + + while ((token < token_end) && + (*str != '\0') && (*str != '\n') && (*str != '\r')) { + for (next_delim=delim; *next_delim; next_delim++) { + if (*str == *next_delim) { + flag2moveon = 1; + break; + } + } + if( flag2moveon ) { + break; + } else { + *token++ = *str++; + } + } + + /* mark end of token */ + *token = '\0'; + + /* set the string of tokens to the next token */ + *string_of_tokens = str; + + return SDP_SUCCESS; +} + +/* + * verify_sdescriptions_mki + * + * Verifies the syntax of the MKI parameter. + * + * mki = mki-value ":" mki-length + * mki-value = 1*DIGIT + * mki-length = 1*3DIGIT ; range 1..128 + * + * Inputs: + * buf - ptr to start of MKI string assumes NULL + * terminated string + * mkiValue - buffer to store the MKI value, assumes calling + * function has provided memory for this. + * mkiLen - integer to store the MKI length + * + * Outputs: + * Returns TRUE if syntax is correct and stores the + * MKI value in mkiVal and stores the length in mkiLen. + * Returns FALSE otherwise. + */ + +tinybool +verify_sdescriptions_mki (char *buf, char *mkiVal, uint16_t *mkiLen) +{ + + char *ptr, + mkiValBuf[SDP_SRTP_MAX_MKI_SIZE_BYTES], + mkiLenBuf[MKI_BUF_LEN]; + int idx = 0; + unsigned long strtoul_result; + char *strtoul_end; + + ptr = buf; + /* MKI must begin with a digit */ + if (!ptr || (!sdp_is_ascii_digit(*ptr))) { + return FALSE; + } + + /* scan until we reach a non-digit or colon */ + while (*ptr) { + if (*ptr == ':') { + /* terminate the MKI value */ + mkiValBuf[idx] = 0; + ptr++; + break; + } else if ((sdp_is_ascii_digit(*ptr) && (idx < SDP_SRTP_MAX_MKI_SIZE_BYTES-1))) { + mkiValBuf[idx++] = *ptr; + } else { + return FALSE; + } + + ptr++; + } + + /* there has to be a mki length */ + if (*ptr == 0) { + return FALSE; + } + + idx = 0; + + /* verify the mki length (max 3 digits) */ + while (*ptr) { + if (sdp_is_ascii_digit(*ptr) && (idx < 3)) { + mkiLenBuf[idx++] = *ptr; + } else { + return FALSE; + } + + ptr++; + } + + mkiLenBuf[idx] = 0; + + errno = 0; + strtoul_result = strtoul(mkiLenBuf, &strtoul_end, 10); + + /* mki len must be between 1..128 */ + if (errno || mkiLenBuf == strtoul_end || strtoul_result < 1 || strtoul_result > 128) { + *mkiLen = 0; + return FALSE; + } + + *mkiLen = (uint16_t) strtoul_result; + sstrncpy(mkiVal, mkiValBuf, MKI_BUF_LEN); + + return TRUE; +} + +/* + * verify_srtp_lifetime + * + * Verifies the Lifetime parameter syntax. + * + * lifetime = ["2^"] 1*(DIGIT) + * + * Inputs: + * buf - pointer to start of lifetime string. Assumes string is + * NULL terminated. + * Outputs: + * Returns TRUE if syntax is correct. Returns FALSE otherwise. + */ + +tinybool +verify_sdescriptions_lifetime (char *buf) +{ + + char *ptr; + tinybool tokenFound = FALSE; + + ptr = buf; + if (!ptr || *ptr == 0) { + return FALSE; + } + + while (*ptr) { + if (*ptr == '^') { + if (tokenFound) { + /* make sure we don't have multiple ^ */ + return FALSE; + } else { + tokenFound = TRUE; + /* Lifetime is in power of 2 format, make sure first and second + * chars are 2^ + */ + + if (buf[0] != '2' || buf[1] != '^') { + return FALSE; + } + } + } else if (!sdp_is_ascii_digit(*ptr)) { + return FALSE; + } + + ptr++; + + } + + /* Make sure if the format is 2^ that there is a number after the ^. */ + if (tokenFound) { + if (strlen(buf) <= 2) { + return FALSE; + } + } + + return TRUE; +} + + +/* + * sdp_validate_maxprate + * + * This function validates that the string passed in is of the form: + * packet-rate = 1*DIGIT ["." 1*DIGIT] + */ +tinybool +sdp_validate_maxprate(const char *string_parm) +{ + tinybool retval = FALSE; + + if (string_parm && (*string_parm)) { + while (sdp_is_ascii_digit(*string_parm)) { + string_parm++; + } + + if (*string_parm == '.') { + string_parm++; + while (sdp_is_ascii_digit(*string_parm)) { + string_parm++; + } + } + + if (*string_parm == '\0') { + retval = TRUE; + } else { + retval = FALSE; + } + } + + return retval; +} + +char *sdp_findchar (const char *ptr, char *char_list) +{ + int i; + + for (;*ptr != '\0'; ptr++) { + for (i=0; char_list[i] != '\0'; i++) { + if (*ptr == char_list[i]) { + return ((char *)ptr); + } + } + } + return ((char *)ptr); +} + +/* Locate the next token in a line. The delim characters are passed in + * as a param. The token also will not go past a new line char or the + * end of the string. Skip any delimiters before the token. + */ +const char *sdp_getnextstrtok (const char *str, char *tokenstr, unsigned tokenstr_len, + const char *delim, sdp_result_e *result) +{ + const char *token_list = str; + + if (!str || !tokenstr || !delim || !result) { + if (result) { + *result = SDP_FAILURE; + } + return str; + } + + *result = next_token(&token_list, tokenstr, tokenstr_len, delim); + + return token_list; +} + + + +/* Locate the next null ("-") or numeric token in a string. The delim + * characters are passed in as a param. The token also will not go past + * a new line char or the end of the string. Skip any delimiters before + * the token. + */ +uint32_t sdp_getnextnumtok_or_null (const char *str, const char **str_end, + const char *delim, tinybool *null_ind, + sdp_result_e *result) +{ + const char *token_list = str; + char temp_token[SDP_MAX_STRING_LEN]; + char *strtoul_end; + unsigned long numval; + + if (null_ind) { + *null_ind = FALSE; + } + + if (!str || !str_end || !delim || !null_ind || !result) { + if (result) { + *result = SDP_FAILURE; + } + return 0; + } + + *result = next_token(&token_list, temp_token, sizeof(temp_token), delim); + + if (*result != SDP_SUCCESS) { + return 0; + } + + /* First see if its the null char ("-") */ + if (temp_token[0] == '-') { + *null_ind = TRUE; + *result = SDP_SUCCESS; + *str_end = str; + return 0; + } + + errno = 0; + numval = strtoul(temp_token, &strtoul_end, 10); + + if (errno || strtoul_end == temp_token || numval > UINT_MAX) { + *result = SDP_FAILURE; + return 0; + } + + *result = SDP_SUCCESS; + *str_end = token_list; + return (uint32_t) numval; +} + + +/* Locate the next numeric token in a string. The delim characters are + * passed in as a param. The token also will not go past a new line char + * or the end of the string. Skip any delimiters before the token. + */ +uint32_t sdp_getnextnumtok (const char *str, const char **str_end, + const char *delim, sdp_result_e *result) +{ + const char *token_list = str; + char temp_token[SDP_MAX_STRING_LEN]; + char *strtoul_end; + unsigned long numval; + + if (!str || !str_end || !delim || !result) { + if (result) { + *result = SDP_FAILURE; + } + return 0; + } + + *result = next_token(&token_list, temp_token, sizeof(temp_token), delim); + + if (*result != SDP_SUCCESS) { + return 0; + } + + errno = 0; + numval = strtoul(temp_token, &strtoul_end, 10); + + if (errno || strtoul_end == temp_token || numval > UINT_MAX) { + *result = SDP_FAILURE; + return 0; + } + + *result = SDP_SUCCESS; + *str_end = token_list; + return (uint32_t) numval; +} + + +/* + * SDP Crypto Utility Functions. + * + * First a few common definitions. + */ + +/* + * Constants + * + * crypto_string = The string used to identify the start of sensative + * crypto data. + * + * inline_string = The string used to identify the start of key/salt + * crypto data. + * + * star_string = The string used to overwrite sensative data. + * + * '*_strlen' = The length of '*_string' in bytes (not including '\0') + */ +static const char crypto_string[] = "X-crypto:"; +static const int crypto_strlen = sizeof(crypto_string) - 1; +static const char inline_string[] = "inline:"; +static const int inline_strlen = sizeof(inline_string) - 1; +/* 40 characters is the current maximum for a Base64 encoded key/salt */ +static const char star_string[] = "****************************************"; +static const int star_strlen = sizeof(star_string) - 1; + +/* + * MIN_CRYPTO_STRING_SIZE_BYTES = This value defines the minimum + * size of a string that could contain a key/salt. This value + * is used to skip out of parsing when there is no reasonable + * assumption that sensative data will be found. The general + * format of a SRTP Key Salt in SDP looks like: + * + * X-crypto:<crypto_suite_name> inline:<master_key_salt>|| + * + * if <crypto_suite_name> and <master_key_salt> is at least + * one character and one space is used before the "inline:", + * then this translates to a size of (aligned by collumn from + * the format shown above): + * + * 9+ 1+ 1+7+ 1+ 2 = 21 + * + */ +#define MIN_CRYPTO_STRING_SIZE_BYTES 21 + +/* + * Utility macros + * + * CHAR_IS_WHITESPACE = macro to determine if the passed _test_char + * is whitespace. + * + * SKIP_WHITESPACE = Macro to advance _cptr to the next non-whitespace + * character. _cptr will not be advanced past _max_cptr. + * + * FIND_WHITESPACE = Macro to advance _cptr until whitespace is found. + * _cptr will not be advanced past _max_cptr. + */ +#define CHAR_IS_WHITESPACE(_test_char) \ + ((((_test_char)==' ')||((_test_char)=='\t'))?1:0) + +#define SKIP_WHITESPACE(_cptr, _max_cptr) \ + while ((_cptr)<=(_max_cptr)) { \ + if (!CHAR_IS_WHITESPACE(*(_cptr))) break; \ + (_cptr)++; \ + } + +#define FIND_WHITESPACE(_cptr, _max_cptr) \ + while ((_cptr)<=(_max_cptr)) { \ + if (CHAR_IS_WHITESPACE(*(_cptr))) break; \ + (_cptr)++; \ + } + +/* Function: sdp_crypto_debug + * Description: Check the passed buffer for sensitive data that should + * not be output (such as SRTP Master Key/Salt) and output + * the buffer as debug. Sensitive data will be replaced + * with the '*' character(s). This function may be used + * to display very large buffers so this function ensures + * that buginf is not overloaded. + * Parameters: buffer pointer to the message buffer to filter. + * length_bytes size of message buffer in bytes. + * Returns: Nothing. + */ +void sdp_crypto_debug (char *buffer, ulong length_bytes) +{ + char *current, *start; + char *last = buffer + length_bytes; + int result; + + /* + * For SRTP Master Key/Salt has the form: + * X-crypto:<crypto_suite_name> inline:<master_key_salt>|| + * Where <master_key_salt> is the data to elide (filter). + */ + for (start=current=buffer; + current<=last-MIN_CRYPTO_STRING_SIZE_BYTES; + current++) { + if ((*current == 'x') || (*current == 'X')) { + result = cpr_strncasecmp(current, crypto_string, crypto_strlen); + if (!result) { + current += crypto_strlen; + if (current > last) break; + + /* Skip over crypto suite name */ + FIND_WHITESPACE(current, last); + + /* Skip over whitespace */ + SKIP_WHITESPACE(current, last); + + /* identify inline keyword */ + result = cpr_strncasecmp(current, inline_string, inline_strlen); + if (!result) { + int star_count = 0; + + current += inline_strlen; + if (current > last) break; + + sdp_dump_buffer(start, current - start); + + /* Hide sensitive key/salt data */ + while (current<=last) { + if (*current == '|' || *current == '\n') { + /* Done, print the stars */ + while (star_count > star_strlen) { + /* + * This code is only for the case where + * too much base64 data was supplied + */ + sdp_dump_buffer((char*)star_string, star_strlen); + star_count -= star_strlen; + } + sdp_dump_buffer((char*)star_string, star_count); + break; + } else { + star_count++; + current++; + } + } + /* Update start pointer */ + start=current; + } + } + } + } + + if (last > start) { + /* Display remainder of buffer */ + sdp_dump_buffer(start, last - start); + } +} + +/* + * sdp_debug_msg_filter + * + * DESCRIPTION + * Check the passed message buffer for sensitive data that should + * not be output (such as SRTP Master Key/Salt). Sensitive data + * will be replaced with the '*' character(s). + * + * PARAMETERS + * buffer: pointer to the message buffer to filter. + * + * length_bytes: size of message buffer in bytes. + * + * RETURN VALUE + * The buffer modified. + */ +char * sdp_debug_msg_filter (char *buffer, ulong length_bytes) +{ + char *current; + char *last = buffer + length_bytes; + int result; + + SDP_PRINT("\n%s:%d: Eliding sensitive data from debug output", + __FILE__, __LINE__); + /* + * For SRTP Master Key/Salt has the form: + * X-crypto:<crypto_suite_name> inline:<master_key_salt>|| + * Where <master_key_salt> is the data to elide (filter). + */ + for (current=buffer; + current<=last-MIN_CRYPTO_STRING_SIZE_BYTES; + current++) { + if ((*current == 'x') || (*current == 'X')) { + result = cpr_strncasecmp(current, crypto_string, crypto_strlen); + if (!result) { + current += crypto_strlen; + if (current > last) break; + + /* Skip over crypto suite name */ + FIND_WHITESPACE(current, last); + + /* Skip over whitespace */ + SKIP_WHITESPACE(current, last); + + /* identify inline keyword */ + result = cpr_strncasecmp(current, inline_string, inline_strlen); + if (!result) { + current += inline_strlen; + if (current > last) break; + + /* Hide sensitive key/salt data */ + while (current<=last) { + if (*current == '|' || *current == '\n') { + /* Done */ + break; + } else { + *current = '*'; + current++; + } + } + } + } + } + } + + return buffer; +} + + +/* Function: sdp_checkrange + * Description: This checks the range of a ulong value to make sure its + * within the range of 0 and 4Gig. stroul cannot be used since + * for values greater greater than 4G, stroul will either wrap + * around or return ULONG_MAX. + * Parameters: sdp_p Pointer to the sdp structure + * num The number to check the range for + * u_val This variable get populated with the ulong value + * if the number is within the range. + * Returns: tinybool - returns TRUE if the number passed is within the + * range, FALSE otherwise + */ +tinybool sdp_checkrange (sdp_t *sdp_p, char *num, ulong *u_val) +{ + ulong l_val; + char *endP = NULL; + *u_val = 0; + + if (!num || !*num) { + return FALSE; + } + + if (*num == '-') { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s ERROR: Parameter value is a negative number: %s", + sdp_p->debug_str, num); + } + return FALSE; + } + + l_val = strtoul(num, &endP, 10); + if (*endP == '\0') { + + if (l_val > 4294967295UL) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s ERROR: Parameter value: %s is greater than 4294967295", + sdp_p->debug_str, num); + } + return FALSE; + } + + if (l_val == 4294967295UL) { + /* + * On certain platforms where ULONG_MAX is equivalent to + * 4294967295, strtoul will return ULONG_MAX even if the the + * value of the string is greater than 4294967295. To detect + * that scenario we make an explicit check here. + */ + if (strcmp("4294967295", num)) { + if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) { + SDPLogError(logTag, "%s ERROR: Parameter value: %s is greater than 4294967295", + sdp_p->debug_str, num); + } + return FALSE; + } + } + } + *u_val = l_val; + return TRUE; +} + +#undef CHAR_IS_WHITESPACE +#undef SKIP_WHITESPACE +#undef FIND_WHITESPACE diff --git a/third_party/sipcc/sipcc_sdp.h b/third_party/sipcc/sipcc_sdp.h new file mode 100644 index 0000000000..b14b9c39ec --- /dev/null +++ b/third_party/sipcc/sipcc_sdp.h @@ -0,0 +1,1835 @@ +/* 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/. */ + +#ifndef _SIPCC_SDP_H_ +#define _SIPCC_SDP_H_ + +#include "sdp_os_defs.h" +#include "ccsdp.h" + +/* SDP Defines */ + +/* The following defines are used to indicate params that are specified + * as the choose parameter or parameters that are invalid. These can + * be used where the value required is really a uint16_t, but is represented + * by an int32_t. + */ +#define SDP_CHOOSE_PARAM (-1) +#define SDP_SESSION_LEVEL 0xFFFF + +#define UNKNOWN_CRYPTO_SUITE "UNKNOWN_CRYPTO_SUITE" +#define AES_CM_128_HMAC_SHA1_32 "AES_CM_128_HMAC_SHA1_32" +#define AES_CM_128_HMAC_SHA1_80 "AES_CM_128_HMAC_SHA1_80" +#define F8_128_HMAC_SHA1_80 "F8_128_HMAC_SHA1_80" + +/* Pulled in from rtp_defs.h. */ +#define GET_DYN_PAYLOAD_TYPE_VALUE(a) ((a & 0XFF00) ? ((a & 0XFF00) >> 8) : a) +#define SET_PAYLOAD_TYPE_WITH_DYNAMIC(a,b) ((a << 8) | b) + +/* + * SDP_SRTP_MAX_KEY_SIZE_BYTES + * Maximum size for a SRTP Master Key in bytes. + */ +#define SDP_SRTP_MAX_KEY_SIZE_BYTES 16 +/* + * SDP_SRTP_MAX_SALT_SIZE_BYTES + * Maximum size for a SRTP Master Salt in bytes. + */ +#define SDP_SRTP_MAX_SALT_SIZE_BYTES 14 +/* + * SDP_SRTP_MAX_MKI_SIZE_BYTES + * Maximum size for a SRTP Master Key Index in bytes. + */ +#define SDP_SRTP_MAX_MKI_SIZE_BYTES 4 + +/* Max number of characters for Lifetime */ +#define SDP_SRTP_MAX_LIFETIME_BYTES 16 + +#define SDP_SDESCRIPTIONS_KEY_SIZE_UNKNOWN 0 +#define SDP_SRTP_CRYPTO_SELECTION_FLAGS_UNKNOWN 0 + +/* Max number of fmtp redundant encodings */ +#define SDP_FMTP_MAX_REDUNDANT_ENCODINGS 128 + +/* + * SRTP_CONTEXT_SET_* + * Set a SRTP Context field flag + */ +#define SDP_SRTP_ENCRYPT_MASK 0x00000001 +#define SDP_SRTP_AUTHENTICATE_MASK 0x00000002 +#define SDP_SRTCP_ENCRYPT_MASK 0x00000004 +#define SDP_SRTCP_SSRC_MASK 0x20000000 +#define SDP_SRTCP_ROC_MASK 0x10000000 +#define SDP_SRTCP_KDR_MASK 0x08000000 +#define SDP_SRTCP_KEY_MASK 0x80000000 +#define SDP_SRTCP_SALT_MASK 0x40000000 + +#define SDP_SRTP_CONTEXT_SET_SSRC(cw) ((cw) |= SDP_SRTCP_SSRC_MASK) +#define SDP_SRTP_CONTEXT_SET_ROC(cw) ((cw) |= SDP_SRTCP_ROC_MASK) +#define SDP_SRTP_CONTEXT_SET_KDR(cw) ((cw) |= SDP_SRTCP_KDR_MASK) +#define SDP_SRTP_CONTEXT_SET_MASTER_KEY(cw) ((cw) |= SDP_SRTCP_KEY_MASK) +#define SDP_SRTP_CONTEXT_SET_MASTER_SALT(cw) ((cw) |= SDP_SRTCP_SALT_MASK) +#define SDP_SRTP_CONTEXT_SET_ENCRYPT_AUTHENTICATE(cw) \ + ((cw) |= (SDP_SRTP_ENCRYPT_MASK | SDP_SRTP_AUTHENTICATE_MASK | \ + SDP_SRTCP_ENCRYPT_MASK)) +#define SDP_SRTP_CONTEXT_RESET_SSRC(cw) ((cw) &= ~(SDP_SRTCP_SSRC_MASK)) +#define SDP_SRTP_CONTEXT_RESET_ROC(cw) ((cw) &= ~(SDP_SRTCP_ROC_MASK)) +#define SDP_SRTP_CONTEXT_RESET_KDR(cw) ((cw) &= ~(SDP_SRTCP_KDR_MASK)) +#define SDP_CONTEXT_RESET_MASTER_KEY(cw) ((cw) &= ~(SDP_SRTCP_KEY_MASK)) +#define SDP_CONTEXT_RESET_MASTER_SALT(cw) ((cw) &= ~(SDP_SRTCP_SALT_MASK)) +#define SDP_EXTMAP_AUDIO_LEVEL "urn:ietf:params:rtp-hdrext:ssrc-audio-level" + +/* SDP Enum Types */ +typedef enum { + SDP_DEBUG_TRACE, + SDP_DEBUG_WARNINGS, + SDP_DEBUG_ERRORS, + SDP_MAX_DEBUG_TYPES +} sdp_debug_e; + +typedef enum { + SDP_CHOOSE_CONN_ADDR, + SDP_CHOOSE_PORTNUM, + SDP_MAX_CHOOSE_PARAMS +} sdp_choose_param_e; + + +/* Token Lines - these must be in the same order they should + * appear in an SDP. + */ +typedef enum { + SDP_TOKEN_V = 0, + SDP_TOKEN_O, + SDP_TOKEN_S, + SDP_TOKEN_I, + SDP_TOKEN_U, + SDP_TOKEN_E, + SDP_TOKEN_P, + SDP_TOKEN_C, + SDP_TOKEN_B, + SDP_TOKEN_T, + SDP_TOKEN_R, + SDP_TOKEN_Z, + SDP_TOKEN_K, + SDP_TOKEN_A, + SDP_TOKEN_M, + SDP_MAX_TOKENS +} sdp_token_e; + +/* Media Types */ +typedef enum { + SDP_MEDIA_AUDIO = 0, + SDP_MEDIA_VIDEO, + SDP_MEDIA_APPLICATION, + SDP_MEDIA_DATA, + SDP_MEDIA_CONTROL, + SDP_MEDIA_NAS_RADIUS, + SDP_MEDIA_NAS_TACACS, + SDP_MEDIA_NAS_DIAMETER, + SDP_MEDIA_NAS_L2TP, + SDP_MEDIA_NAS_LOGIN, + SDP_MEDIA_NAS_NONE, + SDP_MEDIA_TEXT, + SDP_MEDIA_IMAGE, + SDP_MAX_MEDIA_TYPES, + SDP_MEDIA_UNSUPPORTED, + SDP_MEDIA_INVALID +} sdp_media_e; + + +/* Connection Network Type */ +typedef enum { + SDP_NT_INTERNET = 0, /* 0 -> IP - In SDP "IN" is defined */ + /* to mean "Internet" */ + SDP_NT_ATM, /* 1 -> ATM */ + SDP_NT_FR, /* 2 -> FRAME RELAY */ + SDP_NT_LOCAL, /* 3 -> local */ + SDP_MAX_NETWORK_TYPES, + SDP_NT_UNSUPPORTED, + SDP_NT_INVALID +} sdp_nettype_e; + + +/* Address Type */ +typedef enum { + SDP_AT_IP4 = 0, /* 0 -> IP Version 4 (IP4) */ + SDP_AT_IP6, /* 1 -> IP Version 6 (IP6) */ + SDP_AT_NSAP, /* 2 -> 20 byte NSAP address */ + SDP_AT_EPN, /* 3 -> 32 bytes of endpoint name */ + SDP_AT_E164, /* 4 -> 15 digit decimal number addr */ + SDP_AT_GWID, /* 5 -> Private gw id. ASCII string */ + SDP_MAX_ADDR_TYPES, + SDP_AT_UNSUPPORTED, + SDP_AT_FQDN, + SDP_AT_INVALID +} sdp_addrtype_e; + + +/* Transport Types */ + +#define SDP_MAX_PROFILES 3 + +typedef enum { + SDP_TRANSPORT_RTPAVP = 0, + SDP_TRANSPORT_UDP, + SDP_TRANSPORT_UDPTL, + SDP_TRANSPORT_CES10, + SDP_TRANSPORT_LOCAL, + SDP_TRANSPORT_AAL2_ITU, + SDP_TRANSPORT_AAL2_ATMF, + SDP_TRANSPORT_AAL2_CUSTOM, + SDP_TRANSPORT_AAL1AVP, + SDP_TRANSPORT_UDPSPRT, + SDP_TRANSPORT_RTPSAVP, + SDP_TRANSPORT_TCP, + SDP_TRANSPORT_RTPSAVPF, + SDP_TRANSPORT_DTLSSCTP, + SDP_TRANSPORT_RTPAVPF, + SDP_TRANSPORT_UDPTLSRTPSAVP, + SDP_TRANSPORT_UDPTLSRTPSAVPF, + SDP_TRANSPORT_TCPDTLSRTPSAVP, + SDP_TRANSPORT_TCPDTLSRTPSAVPF, + SDP_TRANSPORT_UDPDTLSSCTP, + SDP_TRANSPORT_TCPDTLSSCTP, + SDP_MAX_TRANSPORT_TYPES, + SDP_TRANSPORT_UNSUPPORTED, + SDP_TRANSPORT_INVALID +} sdp_transport_e; + + +/* Encryption KeyType */ +typedef enum { + SDP_ENCRYPT_CLEAR, /* 0 -> Key given in the clear */ + SDP_ENCRYPT_BASE64, /* 1 -> Base64 encoded key */ + SDP_ENCRYPT_URI, /* 2 -> Ptr to URI */ + SDP_ENCRYPT_PROMPT, /* 3 -> No key included, prompt user */ + SDP_MAX_ENCRYPT_TYPES, + SDP_ENCRYPT_UNSUPPORTED, + SDP_ENCRYPT_INVALID +} sdp_encrypt_type_e; + + +/* Known string payload types */ +typedef enum { + SDP_PAYLOAD_T38, + SDP_PAYLOAD_XTMR, + SDP_PAYLOAD_T120, + SDP_MAX_STRING_PAYLOAD_TYPES, + SDP_PAYLOAD_UNSUPPORTED, + SDP_PAYLOAD_INVALID +} sdp_payload_e; + + +/* Payload type indicator */ +typedef enum { + SDP_PAYLOAD_NUMERIC, + SDP_PAYLOAD_ENUM +} sdp_payload_ind_e; + + +/* Image payload types */ +typedef enum { + SDP_PORT_NUM_ONLY, /* <port> or '$' */ + SDP_PORT_NUM_COUNT, /* <port>/<number of ports> */ + SDP_PORT_VPI_VCI, /* <vpi>/<vci> */ + SDP_PORT_VCCI, /* <vcci> */ + SDP_PORT_NUM_VPI_VCI, /* <port>/<vpi>/<vci> */ + SDP_PORT_VCCI_CID, /* <vcci>/<cid> or '$'/'$' */ + SDP_PORT_NUM_VPI_VCI_CID, /* <port>/<vpi>/<vci>/<cid> */ + SDP_MAX_PORT_FORMAT_TYPES, + SDP_PORT_FORMAT_INVALID +} sdp_port_format_e; + + +/* Fmtp attribute format Types */ +typedef enum { + SDP_FMTP_NTE, + SDP_FMTP_CODEC_INFO, + SDP_FMTP_MODE, + SDP_FMTP_DATACHANNEL, + SDP_FMTP_UNKNOWN_TYPE, + SDP_FMTP_MAX_TYPE +} sdp_fmtp_format_type_e; + + +/* T.38 Rate Mgmt Types */ +typedef enum { + SDP_T38_LOCAL_TCF, + SDP_T38_TRANSFERRED_TCF, + SDP_T38_UNKNOWN_RATE, + SDP_T38_MAX_RATES +} sdp_t38_ratemgmt_e; + + +/* T.38 udp EC Types */ +typedef enum { + SDP_T38_UDP_REDUNDANCY, + SDP_T38_UDP_FEC, + SDP_T38_UDPEC_UNKNOWN, + SDP_T38_MAX_UDPEC +} sdp_t38_udpec_e; + +/* Bitmaps for manipulating sdp_direction_e */ +typedef enum { + SDP_DIRECTION_FLAG_SEND=0x01, + SDP_DIRECTION_FLAG_RECV=0x02 +} sdp_direction_flag_e; + +/* Media flow direction */ +typedef enum { + SDP_DIRECTION_INACTIVE = 0, + SDP_DIRECTION_SENDONLY = SDP_DIRECTION_FLAG_SEND, + SDP_DIRECTION_RECVONLY = SDP_DIRECTION_FLAG_RECV, + SDP_DIRECTION_SENDRECV = SDP_DIRECTION_FLAG_SEND | SDP_DIRECTION_FLAG_RECV, + SDP_MAX_QOS_DIRECTIONS +} sdp_direction_e; + +#define SDP_DIRECTION_PRINT(arg) \ + (((sdp_direction_e)(arg)) == SDP_DIRECTION_INACTIVE ? "SDP_DIRECTION_INACTIVE " : \ + ((sdp_direction_e)(arg)) == SDP_DIRECTION_SENDONLY ? "SDP_DIRECTION_SENDONLY": \ + ((sdp_direction_e)(arg)) == SDP_DIRECTION_RECVONLY ? "SDP_DIRECTION_RECVONLY ": \ + ((sdp_direction_e)(arg)) == SDP_DIRECTION_SENDRECV ? " SDP_DIRECTION_SENDRECV": "SDP_MAX_QOS_DIRECTIONS") + + +/* QOS Strength tag */ +typedef enum { + SDP_QOS_STRENGTH_OPT, + SDP_QOS_STRENGTH_MAND, + SDP_QOS_STRENGTH_SUCC, + SDP_QOS_STRENGTH_FAIL, + SDP_QOS_STRENGTH_NONE, + SDP_MAX_QOS_STRENGTH, + SDP_QOS_STRENGTH_UNKNOWN +} sdp_qos_strength_e; + + +/* QOS direction */ +typedef enum { + SDP_QOS_DIR_SEND, + SDP_QOS_DIR_RECV, + SDP_QOS_DIR_SENDRECV, + SDP_QOS_DIR_NONE, + SDP_MAX_QOS_DIR, + SDP_QOS_DIR_UNKNOWN +} sdp_qos_dir_e; + +/* QoS Status types */ +typedef enum { + SDP_QOS_LOCAL, + SDP_QOS_REMOTE, + SDP_QOS_E2E, + SDP_MAX_QOS_STATUS_TYPES, + SDP_QOS_STATUS_TYPE_UNKNOWN +} sdp_qos_status_types_e; + +/* QoS Status types */ +typedef enum { + SDP_CURR_QOS_TYPE, + SDP_CURR_UNKNOWN_TYPE, + SDP_MAX_CURR_TYPES +} sdp_curr_type_e; + +/* QoS Status types */ +typedef enum { + SDP_DES_QOS_TYPE, + SDP_DES_UNKNOWN_TYPE, + SDP_MAX_DES_TYPES +} sdp_des_type_e; + +/* QoS Status types */ +typedef enum { + SDP_CONF_QOS_TYPE, + SDP_CONF_UNKNOWN_TYPE, + SDP_MAX_CONF_TYPES +} sdp_conf_type_e; + + +/* Named event range result values. */ +typedef enum { + SDP_NO_MATCH, + SDP_PARTIAL_MATCH, + SDP_FULL_MATCH +} sdp_ne_res_e; + +/* Fmtp attribute parameters for audio/video codec information */ +typedef enum { + + /* mainly for audio codecs */ + SDP_ANNEX_A, /* 0 */ + SDP_ANNEX_B, + SDP_BITRATE, + + /* for video codecs */ + SDP_QCIF, + SDP_CIF, + SDP_MAXBR, + SDP_SQCIF, + SDP_CIF4, + SDP_CIF16, + SDP_CUSTOM, + SDP_PAR, + SDP_CPCF, + SDP_BPP, + SDP_HRD, + SDP_PROFILE, + SDP_LEVEL, + SDP_INTERLACE, + + /* H.264 related */ + SDP_PROFILE_LEVEL_ID, /* 17 */ + SDP_PARAMETER_SETS, + SDP_PACKETIZATION_MODE, + SDP_INTERLEAVING_DEPTH, + SDP_DEINT_BUF_REQ, + SDP_MAX_DON_DIFF, + SDP_INIT_BUF_TIME, + + SDP_MAX_MBPS, + SDP_MAX_FS, + SDP_MAX_CPB, + SDP_MAX_DPB, + SDP_MAX_BR, + SDP_REDUNDANT_PIC_CAP, + SDP_DEINT_BUF_CAP, + SDP_MAX_RCMD_NALU_SIZE, + + SDP_PARAMETER_ADD, + + /* Annexes - begin */ + /* Some require special handling as they don't have token=token format*/ + SDP_ANNEX_D, + SDP_ANNEX_F, + SDP_ANNEX_I, + SDP_ANNEX_J, + SDP_ANNEX_T, + + /* These annexes have token=token format */ + SDP_ANNEX_K, + SDP_ANNEX_N, + SDP_ANNEX_P, + + SDP_MODE, + SDP_LEVEL_ASYMMETRY_ALLOWED, + SDP_MAX_AVERAGE_BIT_RATE, + SDP_USED_TX, + SDP_STEREO, + SDP_USE_IN_BAND_FEC, + SDP_MAX_CODED_AUDIO_BW, + SDP_CBR, + SDP_MAX_FR, + SDP_MAX_PLAYBACK_RATE, + SDP_APT, + SDP_RTX_TIME, + SDP_MAX_FMTP_PARAM, + SDP_FMTP_PARAM_UNKNOWN +} sdp_fmtp_codec_param_e; + +/* Fmtp attribute parameters values for + fmtp attribute parameters which convey codec + information */ + +typedef enum { + SDP_YES, + SDP_NO, + SDP_MAX_FMTP_PARAM_VAL, + SDP_FMTP_PARAM_UNKNOWN_VAL +} sdp_fmtp_codec_param_val_e; + +/* silenceSupp suppPref */ +typedef enum { + SDP_SILENCESUPP_PREF_STANDARD, + SDP_SILENCESUPP_PREF_CUSTOM, + SDP_SILENCESUPP_PREF_NULL, /* "-" */ + SDP_MAX_SILENCESUPP_PREF, + SDP_SILENCESUPP_PREF_UNKNOWN +} sdp_silencesupp_pref_e; + +/* silenceSupp sidUse */ +typedef enum { + SDP_SILENCESUPP_SIDUSE_NOSID, + SDP_SILENCESUPP_SIDUSE_FIXED, + SDP_SILENCESUPP_SIDUSE_SAMPLED, + SDP_SILENCESUPP_SIDUSE_NULL, /* "-" */ + SDP_MAX_SILENCESUPP_SIDUSE, + SDP_SILENCESUPP_SIDUSE_UNKNOWN +} sdp_silencesupp_siduse_e; + +typedef enum { + SDP_MEDIADIR_ROLE_PASSIVE, + SDP_MEDIADIR_ROLE_ACTIVE, + SDP_MEDIADIR_ROLE_BOTH, + SDP_MEDIADIR_ROLE_REUSE, + SDP_MEDIADIR_ROLE_UNKNOWN, + SDP_MAX_MEDIADIR_ROLES, + SDP_MEDIADIR_ROLE_UNSUPPORTED, + SDP_MEDIADIR_ROLE_INVALID +} sdp_mediadir_role_e; + +typedef enum { + SDP_GROUP_ATTR_FID, + SDP_GROUP_ATTR_LS, + SDP_GROUP_ATTR_ANAT, + SDP_GROUP_ATTR_BUNDLE, + SDP_MAX_GROUP_ATTR_VAL, + SDP_GROUP_ATTR_UNSUPPORTED +} sdp_group_attr_e; + +typedef enum { + SDP_SSRC_GROUP_ATTR_DUP, + SDP_SSRC_GROUP_ATTR_FEC, + SDP_SSRC_GROUP_ATTR_FECFR, + SDP_SSRC_GROUP_ATTR_FID, + SDP_SSRC_GROUP_ATTR_SIM, + SDP_MAX_SSRC_GROUP_ATTR_VAL, + SDP_SSRC_GROUP_ATTR_UNSUPPORTED +} sdp_ssrc_group_attr_e; + +typedef enum { + SDP_SRC_FILTER_INCL, + SDP_SRC_FILTER_EXCL, + SDP_MAX_FILTER_MODE, + SDP_FILTER_MODE_NOT_PRESENT +} sdp_src_filter_mode_e; + +typedef enum { + SDP_RTCP_UNICAST_MODE_REFLECTION, + SDP_RTCP_UNICAST_MODE_RSI, + SDP_RTCP_MAX_UNICAST_MODE, + SDP_RTCP_UNICAST_MODE_NOT_PRESENT +} sdp_rtcp_unicast_mode_e; + +typedef enum { + SDP_CONNECTION_NOT_FOUND = -1, + SDP_CONNECTION_NEW = 0, + SDP_CONNECTION_EXISTING, + SDP_MAX_CONNECTION, + SDP_CONNECTION_UNKNOWN +} sdp_connection_type_e; + +typedef enum { + SDP_SCTP_MEDIA_FMT_WEBRTC_DATACHANNEL, + SDP_SCTP_MEDIA_FMT_UNKNOWN +} sdp_sctp_media_fmt_type_e; + +/* + * sdp_srtp_fec_order_t + * This type defines the order in which to perform FEC + * (Forward Error Correction) and SRTP Encryption/Authentication. + */ +typedef enum sdp_srtp_fec_order_t_ { + SDP_SRTP_THEN_FEC, /* upon sending perform SRTP then FEC */ + SDP_FEC_THEN_SRTP, /* upon sending perform FEC then SRTP */ + SDP_SRTP_FEC_SPLIT /* upon sending perform SRTP Encryption, + * then FEC, the SRTP Authentication */ +} sdp_srtp_fec_order_t; + + +/* + * sdp_srtp_crypto_suite_t + * Enumeration of the crypto suites supported for MGCP SRTP + * package. + */ +typedef enum sdp_srtp_crypto_suite_t_ { + SDP_SRTP_UNKNOWN_CRYPTO_SUITE = 0, + SDP_SRTP_AES_CM_128_HMAC_SHA1_32, + SDP_SRTP_AES_CM_128_HMAC_SHA1_80, + SDP_SRTP_F8_128_HMAC_SHA1_80, + SDP_SRTP_MAX_NUM_CRYPTO_SUITES +} sdp_srtp_crypto_suite_t; + +/* + * SDP SRTP crypto suite definition parameters + * + * SDP_SRTP_<crypto_suite>_KEY_BYTES + * The size of a master key for <crypto_suite> in bytes. + * + * SDP_SRTP_<crypto_suite>_SALT_BYTES + * The size of a master salt for <crypto_suite> in bytes. + */ +#define SDP_SRTP_AES_CM_128_HMAC_SHA1_32_KEY_BYTES 16 +#define SDP_SRTP_AES_CM_128_HMAC_SHA1_32_SALT_BYTES 14 +#define SDP_SRTP_AES_CM_128_HMAC_SHA1_80_KEY_BYTES 16 +#define SDP_SRTP_AES_CM_128_HMAC_SHA1_80_SALT_BYTES 14 +#define SDP_SRTP_F8_128_HMAC_SHA1_80_KEY_BYTES 16 +#define SDP_SRTP_F8_128_HMAC_SHA1_80_SALT_BYTES 14 + +/* SDP Defines */ + +#define SDP_MAX_LONG_STRING_LEN 4096 /* Max len for long SDP strings */ +#define SDP_MAX_STRING_LEN 256 /* Max len for SDP string */ +#define SDP_MAX_SHORT_STRING_LEN 12 /* Max len for a short SDP string */ +#define SDP_MAX_PAYLOAD_TYPES 23 /* Max payload types in m= line */ +#define SDP_TOKEN_LEN 2 /* Len of <token>= */ +#define SDP_CURRENT_VERSION 0 /* Current default SDP version */ +#define SDP_MAX_PORT_PARAMS 4 /* Max m= port params - x/x/x/x */ +#define SDP_MIN_DYNAMIC_PAYLOAD 96 /* Min dynamic payload */ +#define SDP_MAX_DYNAMIC_PAYLOAD 127 /* Max dynamic payload */ +#define SDP_MIN_CIF_VALUE 1 /* applies to all QCIF,CIF,CIF4,CIF16,SQCIF */ +#define SDP_MAX_CIF_VALUE 32 /* applies to all QCIF,CIF,CIF4,CIF16,SQCIF */ +#define SDP_MAX_SRC_ADDR_LIST 1 /* Max source addrs for which filter applies */ + + +#define SDP_DEFAULT_PACKETIZATION_MODE_VALUE 0 /* max packetization mode for H.264 */ +#define SDP_MAX_PACKETIZATION_MODE_VALUE 2 /* max packetization mode for H.264 */ +#define SDP_INVALID_PACKETIZATION_MODE_VALUE 255 + +#define SDP_MAX_LEVEL_ASYMMETRY_ALLOWED_VALUE 1 /* max level asymmetry allowed value for H.264 */ +#define SDP_DEFAULT_LEVEL_ASYMMETRY_ALLOWED_VALUE 0 /* default level asymmetry allowed value for H.264 */ +#define SDP_INVALID_LEVEL_ASYMMETRY_ALLOWED_VALUE 2 /* invalid value for level-asymmetry-allowed param for H.264 */ + + +/* Max number of stream ids that can be grouped together */ +#define SDP_MAX_MEDIA_STREAMS 128 + +#define SDP_UNSUPPORTED "Unsupported" + +#define SDP_MAX_PROFILE_VALUE 10 +#define SDP_MAX_LEVEL_VALUE 100 +#define SDP_MIN_PROFILE_LEVEL_VALUE 0 +#define SDP_MAX_TTL_VALUE 255 +#define SDP_MIN_MCAST_ADDR_HI_BIT_VAL 224 +#define SDP_MAX_MCAST_ADDR_HI_BIT_VAL 239 + +#define SDP_MAX_SSRC_GROUP_SSRCS 32 /* max number of ssrcs allowed in a ssrc-group */ + +/* SDP Enum Types */ + +typedef enum { + SDP_ERR_INVALID_CONF_PTR, + SDP_ERR_INVALID_SDP_PTR, + SDP_ERR_INTERNAL, + SDP_MAX_ERR_TYPES +} sdp_errmsg_e; + +/* SDP Structure Definitions */ + +/* String names of varios tokens */ +typedef struct { + char *name; + uint8_t strlen; +} sdp_namearray_t; + +/* c= line info */ +typedef struct { + sdp_nettype_e nettype; + sdp_addrtype_e addrtype; + char conn_addr[SDP_MAX_STRING_LEN+1]; + tinybool is_multicast; + uint16_t ttl; + uint16_t num_of_addresses; +} sdp_conn_t; + +/* t= line info */ +typedef struct sdp_timespec { + char start_time[SDP_MAX_STRING_LEN+1]; + char stop_time[SDP_MAX_STRING_LEN+1]; + struct sdp_timespec *next_p; +} sdp_timespec_t; + + +/* k= line info */ +typedef struct sdp_encryptspec { + sdp_encrypt_type_e encrypt_type; + char encrypt_key[SDP_MAX_STRING_LEN+1]; +} sdp_encryptspec_t; + + +/* FMTP attribute deals with named events in the range of 0-255 as + * defined in RFC 2833 */ +#define SDP_MIN_NE_VALUE 0 +#define SDP_MAX_NE_VALUES 256 +#define SDP_NE_BITS_PER_WORD ( sizeof(uint32_t) * 8 ) +#define SDP_NE_NUM_BMAP_WORDS ((SDP_MAX_NE_VALUES + SDP_NE_BITS_PER_WORD - 1)/SDP_NE_BITS_PER_WORD ) +#define SDP_NE_BIT_0 ( 0x00000001 ) +#define SDP_NE_ALL_BITS ( 0xFFFFFFFF ) + +#define SDP_DEINT_BUF_REQ_FLAG 0x1 +#define SDP_INIT_BUF_TIME_FLAG 0x2 +#define SDP_MAX_RCMD_NALU_SIZE_FLAG 0x4 +#define SDP_DEINT_BUF_CAP_FLAG 0x8 + +#define SDP_FMTP_UNUSED 0xFFFF + +typedef struct sdp_fmtp { + uint16_t payload_num; + uint32_t maxval; /* maxval optimizes bmap search */ + uint32_t bmap[ SDP_NE_NUM_BMAP_WORDS ]; + sdp_fmtp_format_type_e fmtp_format; /* Gives the format type + for FMTP attribute*/ + tinybool annexb_required; + tinybool annexa_required; + + tinybool annexa; + tinybool annexb; + uint32_t bitrate; + uint32_t mode; + + /* some OPUS specific fmtp params */ + uint32_t maxplaybackrate; + uint32_t maxaveragebitrate; + uint16_t usedtx; + uint16_t stereo; + uint16_t useinbandfec; + char maxcodedaudiobandwidth[SDP_MAX_STRING_LEN+1]; + uint16_t cbr; + + /* BEGIN - All Video related FMTP parameters */ + uint16_t qcif; + uint16_t cif; + uint16_t maxbr; + uint16_t sqcif; + uint16_t cif4; + uint16_t cif16; + + uint16_t custom_x; + uint16_t custom_y; + uint16_t custom_mpi; + /* CUSTOM=360,240,4 implies X-AXIS=360, Y-AXIS=240; MPI=4 */ + uint16_t par_width; + uint16_t par_height; + /* PAR=12:11 implies par_width=12, par_height=11 */ + + /* CPCF should be a float. IOS does not support float and so it is uint16_t */ + /* For portable stack, CPCF should be defined as float and the parsing should + * be modified accordingly */ + uint16_t cpcf; + uint16_t bpp; + uint16_t hrd; + + int16_t profile; + int16_t level; + tinybool is_interlace; + + /* some more H.264 specific fmtp params */ + char profile_level_id[SDP_MAX_STRING_LEN+1]; + char parameter_sets[SDP_MAX_STRING_LEN+1]; + uint16_t packetization_mode; + uint16_t level_asymmetry_allowed; + uint16_t interleaving_depth; + uint32_t deint_buf_req; + uint32_t max_don_diff; + uint32_t init_buf_time; + + uint32_t max_mbps; + uint32_t max_fs; + uint32_t max_fr; + uint32_t max_cpb; + uint32_t max_dpb; + uint32_t max_br; + tinybool redundant_pic_cap; + uint32_t deint_buf_cap; + uint32_t max_rcmd_nalu_size; + uint16_t parameter_add; + + tinybool annex_d; + + tinybool annex_f; + tinybool annex_i; + tinybool annex_j; + tinybool annex_t; + + /* H.263 codec requires annex K,N and P to have values */ + uint16_t annex_k_val; + uint16_t annex_n_val; + + /* RFC 5109 Section 4.2 for specifying redundant encodings */ + uint8_t redundant_encodings[SDP_FMTP_MAX_REDUNDANT_ENCODINGS]; + + /* RFC 2833 Section 3.9 (4733) for specifying support DTMF tones: + The list of values consists of comma-separated elements, which + can be either a single decimal number or two decimal numbers + separated by a hyphen (dash), where the second number is larger + than the first. No whitespace is allowed between numbers or + hyphens. The list does not have to be sorted. + */ + char dtmf_tones[SDP_MAX_STRING_LEN+1]; + + /* Annex P can take one or more values in the range 1-4 . e.g P=1,3 */ + uint16_t annex_p_val_picture_resize; /* 1 = four; 2 = sixteenth */ + uint16_t annex_p_val_warp; /* 3 = half; 4=sixteenth */ + + uint8_t flag; + + /* RTX parameters */ + uint8_t apt; + tinybool has_rtx_time; + uint32_t rtx_time; + + /* END - All Video related FMTP parameters */ + +} sdp_fmtp_t; + +/* a=sctpmap line used for Datachannels */ +typedef struct sdp_sctpmap { + uint16_t port; + uint32_t streams; /* Num streams per Datachannel */ + char protocol[SDP_MAX_STRING_LEN+1]; +} sdp_sctpmap_t; + +#define SDP_MAX_MSID_LEN 64 + +typedef struct sdp_msid { + char identifier[SDP_MAX_MSID_LEN+1]; + char appdata[SDP_MAX_MSID_LEN+1]; +} sdp_msid_t; + +/* a=qos|secure|X-pc-qos|X-qos info */ +typedef struct sdp_qos { + sdp_qos_strength_e strength; + sdp_qos_dir_e direction; + tinybool confirm; + sdp_qos_status_types_e status_type; +} sdp_qos_t; + +/* a=curr:qos status_type direction */ +typedef struct sdp_curr { + sdp_curr_type_e type; + sdp_qos_status_types_e status_type; + sdp_qos_dir_e direction; +} sdp_curr_t; + +/* a=des:qos strength status_type direction */ +typedef struct sdp_des { + sdp_des_type_e type; + sdp_qos_strength_e strength; + sdp_qos_status_types_e status_type; + sdp_qos_dir_e direction; +} sdp_des_t; + +/* a=conf:qos status_type direction */ +typedef struct sdp_conf { + sdp_conf_type_e type; + sdp_qos_status_types_e status_type; + sdp_qos_dir_e direction; +} sdp_conf_t; + + +/* a=rtpmap or a=sprtmap info */ +typedef struct sdp_transport_map { + uint16_t payload_num; + char encname[SDP_MAX_STRING_LEN+1]; + uint32_t clockrate; + uint16_t num_chan; +} sdp_transport_map_t; + + +/* a=rtr info */ +typedef struct sdp_rtr { + tinybool confirm; +} sdp_rtr_t; + +/* a=subnet info */ +typedef struct sdp_subnet { + sdp_nettype_e nettype; + sdp_addrtype_e addrtype; + char addr[SDP_MAX_STRING_LEN+1]; + int32_t prefix; +} sdp_subnet_t; + + +/* a=X-pc-codec info */ +typedef struct sdp_pccodec { + uint16_t num_payloads; + ushort payload_type[SDP_MAX_PAYLOAD_TYPES]; +} sdp_pccodec_t; + +/* a=direction info */ +typedef struct sdp_comediadir { + sdp_mediadir_role_e role; + tinybool conn_info_present; + sdp_conn_t conn_info; + uint32_t src_port; +} sdp_comediadir_t; + + + +/* a=silenceSupp info */ +typedef struct sdp_silencesupp { + tinybool enabled; + tinybool timer_null; + uint16_t timer; + sdp_silencesupp_pref_e pref; + sdp_silencesupp_siduse_e siduse; + tinybool fxnslevel_null; + uint8_t fxnslevel; +} sdp_silencesupp_t; + + +/* + * a=mptime info */ +/* Note that an interval value of zero corresponds to + * the "-" syntax on the a= line. + */ +typedef struct sdp_mptime { + uint16_t num_intervals; + ushort intervals[SDP_MAX_PAYLOAD_TYPES]; +} sdp_mptime_t; + +/* + * a=X-sidin:<val>, a=X-sidout:< val> and a=X-confid: <val> + * Stream Id,ConfID related attributes to be used for audio/video conferencing + * +*/ + +typedef struct sdp_stream_data { + char x_sidin[SDP_MAX_STRING_LEN+1]; + char x_sidout[SDP_MAX_STRING_LEN+1]; + char x_confid[SDP_MAX_STRING_LEN+1]; + sdp_group_attr_e group_attr; /* FID or LS */ + uint16_t num_group_id; + char * group_ids[SDP_MAX_MEDIA_STREAMS]; +} sdp_stream_data_t; + +typedef struct sdp_msid_semantic { + char semantic[SDP_MAX_STRING_LEN+1]; + char * msids[SDP_MAX_MEDIA_STREAMS]; +} sdp_msid_semantic_t; + +/* + * a=source-filter:<filter-mode> <filter-spec> + * <filter-spec> = <nettype> <addrtype> <dest-addr> <src_addr><src_addr>... + * One or more source addresses to apply filter, for one or more connection + * address in unicast/multicast environments + */ +typedef struct sdp_source_filter { + sdp_src_filter_mode_e mode; + sdp_nettype_e nettype; + sdp_addrtype_e addrtype; + char dest_addr[SDP_MAX_STRING_LEN+1]; + uint16_t num_src_addr; + char src_list[SDP_MAX_SRC_ADDR_LIST+1][SDP_MAX_STRING_LEN+1]; +} sdp_source_filter_t; + +/* + * a=rtcp-fb:<payload-type> <feedback-type> [<feedback-parameters>] + * Defines RTCP feedback parameters + */ +#define SDP_ALL_PAYLOADS 0xFFFF +typedef struct sdp_fmtp_fb { + uint16_t payload_num; /* can be SDP_ALL_PAYLOADS */ + sdp_rtcp_fb_type_e feedback_type; + union { + sdp_rtcp_fb_ack_type_e ack; + sdp_rtcp_fb_ccm_type_e ccm; + sdp_rtcp_fb_nack_type_e nack; + uint32_t trr_int; + } param; + char extra[SDP_MAX_STRING_LEN + 1]; /* Holds any trailing information that + cannot be represented by preceding + fields. */ +} sdp_fmtp_fb_t; + +typedef struct sdp_rtcp { + sdp_nettype_e nettype; + sdp_addrtype_e addrtype; + char addr[SDP_MAX_STRING_LEN+1]; + uint16_t port; +} sdp_rtcp_t; + +/* + * b=<bw-modifier>:<val> + * +*/ +typedef struct sdp_bw_data { + struct sdp_bw_data *next_p; + sdp_bw_modifier_e bw_modifier; + int bw_val; +} sdp_bw_data_t; + +/* + * This structure houses a linked list of sdp_bw_data_t instances. Each + * sdp_bw_data_t instance represents one b= line. + */ +typedef struct sdp_bw { + uint16_t bw_data_count; + sdp_bw_data_t *bw_data_list; +} sdp_bw_t; + +/* Media lines for AAL2 may have more than one transport type defined + * each with its own payload type list. These are referred to as + * profile types instead of transport types. This structure is used + * to handle these multiple profile types. Note: One additional profile + * field is needed because of the way parsing is done. This is not an + * error. */ +typedef struct sdp_media_profiles { + uint16_t num_profiles; + sdp_transport_e profile[SDP_MAX_PROFILES+1]; + uint16_t num_payloads[SDP_MAX_PROFILES]; + sdp_payload_ind_e payload_indicator[SDP_MAX_PROFILES][SDP_MAX_PAYLOAD_TYPES]; + uint16_t payload_type[SDP_MAX_PROFILES][SDP_MAX_PAYLOAD_TYPES]; +} sdp_media_profiles_t; +/* + * a=extmap:<value>["/"<direction>] <URI> <extensionattributes> + * + */ +typedef struct sdp_extmap { + uint16_t id; + sdp_direction_e media_direction; + tinybool media_direction_specified; + char uri[SDP_MAX_STRING_LEN+1]; + char extension_attributes[SDP_MAX_STRING_LEN+1]; +} sdp_extmap_t; + +typedef struct sdp_ssrc { + uint32_t ssrc; + char attribute[SDP_MAX_STRING_LEN + 1]; +} sdp_ssrc_t; + +typedef struct sdp_ssrc_group { + sdp_ssrc_group_attr_e semantic; + uint16_t num_ssrcs; + uint32_t ssrcs[SDP_MAX_SSRC_GROUP_SSRCS]; +} sdp_ssrc_group_t; + +/* + * sdp_srtp_crypto_context_t + * This type is used to hold cryptographic context information. + * + */ +typedef struct sdp_srtp_crypto_context_t_ { + int32_t tag; + unsigned long selection_flags; + sdp_srtp_crypto_suite_t suite; + unsigned char master_key[SDP_SRTP_MAX_KEY_SIZE_BYTES]; + unsigned char master_salt[SDP_SRTP_MAX_SALT_SIZE_BYTES]; + unsigned char master_key_size_bytes; + unsigned char master_salt_size_bytes; + unsigned long ssrc; /* not used */ + unsigned long roc; /* not used */ + unsigned long kdr; /* not used */ + unsigned short seq; /* not used */ + sdp_srtp_fec_order_t fec_order; /* not used */ + unsigned char master_key_lifetime[SDP_SRTP_MAX_LIFETIME_BYTES]; + unsigned char mki[SDP_SRTP_MAX_MKI_SIZE_BYTES]; + uint16_t mki_size_bytes; + char* session_parameters; +} sdp_srtp_crypto_context_t; + + +/* m= line info and associated attribute list */ +/* Note: Most of the port parameter values are 16-bit values. We set + * the type to int32_t so we can return either a 16-bit value or the + * choose value. */ +typedef struct sdp_mca { + sdp_media_e media; + sdp_conn_t conn; + sdp_transport_e transport; + sdp_port_format_e port_format; + int32_t port; + int32_t sctpport; + sdp_sctp_media_fmt_type_e sctp_fmt; + int32_t num_ports; + int32_t vpi; + uint32_t vci; /* VCI needs to be 32-bit */ + int32_t vcci; + int32_t cid; + uint16_t num_payloads; + sdp_payload_ind_e payload_indicator[SDP_MAX_PAYLOAD_TYPES]; + uint16_t payload_type[SDP_MAX_PAYLOAD_TYPES]; + sdp_media_profiles_t *media_profiles_p; + tinybool sessinfo_found; + sdp_encryptspec_t encrypt; + sdp_bw_t bw; + sdp_attr_e media_direction; /* Either INACTIVE, SENDONLY, + RECVONLY, or SENDRECV */ + uint32_t mid; + uint32_t line_number; + struct sdp_attr *media_attrs_p; + struct sdp_mca *next_p; +} sdp_mca_t; + + +/* generic a= line info */ +typedef struct sdp_attr { + sdp_attr_e type; + uint32_t line_number; + union { + tinybool boolean_val; + uint32_t u32_val; + char string_val[SDP_MAX_STRING_LEN+1]; + char *stringp; + char ice_attr[SDP_MAX_STRING_LEN+1]; + sdp_fmtp_t fmtp; + sdp_sctpmap_t sctpmap; + sdp_msid_t msid; + sdp_qos_t qos; + sdp_curr_t curr; + sdp_des_t des; + sdp_conf_t conf; + sdp_transport_map_t transport_map; /* A rtpmap or sprtmap */ + sdp_subnet_t subnet; + sdp_t38_ratemgmt_e t38ratemgmt; + sdp_t38_udpec_e t38udpec; + sdp_pccodec_t pccodec; + sdp_silencesupp_t silencesupp; + sdp_mca_t *cap_p; /* A X-CAP or CDSC attribute */ + sdp_rtr_t rtr; + sdp_comediadir_t comediadir; + sdp_srtp_crypto_context_t srtp_context; + sdp_mptime_t mptime; + sdp_stream_data_t stream_data; + sdp_msid_semantic_t msid_semantic; + char unknown[SDP_MAX_STRING_LEN+1]; + sdp_source_filter_t source_filter; + sdp_fmtp_fb_t rtcp_fb; + sdp_rtcp_t rtcp; + sdp_setup_type_e setup; + sdp_connection_type_e connection; + sdp_extmap_t extmap; + sdp_ssrc_t ssrc; + sdp_ssrc_group_t ssrc_group; + } attr; + struct sdp_attr *next_p; +} sdp_attr_t; +typedef struct sdp_srtp_crypto_suite_list_ { + sdp_srtp_crypto_suite_t crypto_suite_val; + char * crypto_suite_str; + unsigned char key_size_bytes; + unsigned char salt_size_bytes; +} sdp_srtp_crypto_suite_list; + +typedef void (*sdp_parse_error_handler)(void *context, + uint32_t line, + const char *message); + +/* Application configuration options */ +typedef struct sdp_conf_options { + tinybool debug_flag[SDP_MAX_DEBUG_TYPES]; + tinybool version_reqd; + tinybool owner_reqd; + tinybool session_name_reqd; + tinybool timespec_reqd; + tinybool media_supported[SDP_MAX_MEDIA_TYPES]; + tinybool nettype_supported[SDP_MAX_NETWORK_TYPES]; + tinybool addrtype_supported[SDP_MAX_ADDR_TYPES]; + tinybool transport_supported[SDP_MAX_TRANSPORT_TYPES]; + tinybool allow_choose[SDP_MAX_CHOOSE_PARAMS]; + /* Statistics counts */ + uint32_t num_builds; + uint32_t num_parses; + uint32_t num_not_sdp_desc; + uint32_t num_invalid_token_order; + uint32_t num_invalid_param; + uint32_t num_no_resource; + struct sdp_conf_options *next_p; + sdp_parse_error_handler error_handler; + void *error_handler_context; +} sdp_conf_options_t; + + +/* Session level SDP info with pointers to media line info. */ +/* Elements here that can only be one of are included directly. Elements */ +/* that can be more than one are pointers. */ +typedef struct { + sdp_conf_options_t *conf_p; + tinybool debug_flag[SDP_MAX_DEBUG_TYPES]; + char debug_str[SDP_MAX_STRING_LEN+1]; + uint32_t debug_id; + int32_t version; /* version is really a uint16_t */ + char owner_name[SDP_MAX_STRING_LEN+1]; + char owner_sessid[SDP_MAX_STRING_LEN+1]; + char owner_version[SDP_MAX_STRING_LEN+1]; + sdp_nettype_e owner_network_type; + sdp_addrtype_e owner_addr_type; + char owner_addr[SDP_MAX_STRING_LEN+1]; + char sessname[SDP_MAX_STRING_LEN+1]; + tinybool sessinfo_found; + tinybool uri_found; + sdp_conn_t default_conn; + sdp_timespec_t *timespec_p; + sdp_encryptspec_t encrypt; + sdp_bw_t bw; + sdp_attr_t *sess_attrs_p; + + /* Info to help with building capability attributes. */ + uint16_t cur_cap_num; + sdp_mca_t *cur_cap_p; + /* Info to help parsing X-cpar attrs. */ + uint16_t cap_valid; + uint16_t last_cap_inst; + /* Info to help building X-cpar/cpar attrs. */ + sdp_attr_e last_cap_type; + + /* Facilitates reporting line number for SDP errors */ + uint32_t parse_line; + + /* MCA - Media, connection, and attributes */ + sdp_mca_t *mca_p; + ushort mca_count; +} sdp_t; + + +/* Token processing table. */ +typedef struct { + char *name; + sdp_result_e (*parse_func)(sdp_t *sdp_p, uint16_t level, const char *ptr); + sdp_result_e (*build_func)(sdp_t *sdp_p, uint16_t level, flex_string *fs); +} sdp_tokenarray_t; + +/* Attribute processing table. */ +typedef struct { + char *name; + uint16_t strlen; + sdp_result_e (*parse_func)(sdp_t *sdp_p, sdp_attr_t *attr_p, + const char *ptr); + sdp_result_e (*build_func)(sdp_t *sdp_p, sdp_attr_t *attr_p, + flex_string *fs); +} sdp_attrarray_t; + + +/* Prototypes */ + +/* sdp_config.c */ +extern sdp_conf_options_t *sdp_init_config(void); +extern void sdp_free_config(sdp_conf_options_t *config_p); +extern void sdp_appl_debug(sdp_conf_options_t *config_p, sdp_debug_e debug_type, + tinybool debug_flag); +extern void sdp_require_version(sdp_conf_options_t *config_p, tinybool version_required); +extern void sdp_require_owner(sdp_conf_options_t *config_p, tinybool owner_required); +extern void sdp_require_session_name(sdp_conf_options_t *config_p, + tinybool sess_name_required); +extern void sdp_require_timespec(sdp_conf_options_t *config_p, tinybool timespec_required); +extern void sdp_media_supported(sdp_conf_options_t *config_p, sdp_media_e media_type, + tinybool media_supported); +extern void sdp_nettype_supported(sdp_conf_options_t *config_p, sdp_nettype_e nettype, + tinybool nettype_supported); +extern void sdp_addrtype_supported(sdp_conf_options_t *config_p, sdp_addrtype_e addrtype, + tinybool addrtype_supported); +extern void sdp_transport_supported(sdp_conf_options_t *config_p, sdp_transport_e transport, + tinybool transport_supported); +extern void sdp_allow_choose(sdp_conf_options_t *config_p, sdp_choose_param_e param, + tinybool choose_allowed); +extern void sdp_config_set_error_handler(sdp_conf_options_t *config_p, + sdp_parse_error_handler handler, + void *context); + +/* sdp_main.c */ +extern sdp_t *sdp_init_description(sdp_conf_options_t *config_p); +extern void sdp_debug(sdp_t *sdp_ptr, sdp_debug_e debug_type, tinybool debug_flag); +extern void sdp_set_string_debug(sdp_t *sdp_ptr, const char *debug_str); +extern sdp_result_e sdp_parse(sdp_t *sdp_ptr, const char *buf, size_t len); +extern sdp_result_e sdp_build(sdp_t *sdp_ptr, flex_string *fs); +extern sdp_result_e sdp_free_description(sdp_t *sdp_ptr); +extern void sdp_parse_error(sdp_t *sdp, const char *format, ...); + +extern const char *sdp_get_result_name(sdp_result_e rc); + + +/* sdp_access.c */ +extern tinybool sdp_version_valid(sdp_t *sdp_p); +extern int32_t sdp_get_version(sdp_t *sdp_p); +extern sdp_result_e sdp_set_version(sdp_t *sdp_p, int32_t version); + +extern tinybool sdp_owner_valid(sdp_t *sdp_p); +extern const char *sdp_get_owner_username(sdp_t *sdp_p); +extern const char *sdp_get_owner_sessionid(sdp_t *sdp_p); +extern const char *sdp_get_owner_version(sdp_t *sdp_p); +extern sdp_nettype_e sdp_get_owner_network_type(sdp_t *sdp_p); +extern sdp_addrtype_e sdp_get_owner_address_type(sdp_t *sdp_p); +extern const char *sdp_get_owner_address(sdp_t *sdp_p); +extern sdp_result_e sdp_set_owner_username(sdp_t *sdp_p, const char *username); +extern sdp_result_e sdp_set_owner_sessionid(sdp_t *sdp_p, const char *sessid); +extern sdp_result_e sdp_set_owner_version(sdp_t *sdp_p, const char *version); +extern sdp_result_e sdp_set_owner_network_type(sdp_t *sdp_p, + sdp_nettype_e network_type); +extern sdp_result_e sdp_set_owner_address_type(sdp_t *sdp_p, + sdp_addrtype_e address_type); +extern sdp_result_e sdp_set_owner_address(sdp_t *sdp_p, const char *address); + +extern tinybool sdp_session_name_valid(sdp_t *sdp_p); +extern const char *sdp_get_session_name(sdp_t *sdp_p); +extern sdp_result_e sdp_set_session_name(sdp_t *sdp_p, const char *sessname); + +extern tinybool sdp_timespec_valid(sdp_t *sdp_ptr); +extern const char *sdp_get_time_start(sdp_t *sdp_ptr); +extern const char *sdp_get_time_stop(sdp_t *sdp_ptr); +sdp_result_e sdp_set_time_start(sdp_t *sdp_p, const char *start_time); +sdp_result_e sdp_set_time_stop(sdp_t *sdp_p, const char *stop_time); + +extern tinybool sdp_encryption_valid(sdp_t *sdp_p, uint16_t level); +extern sdp_encrypt_type_e sdp_get_encryption_method(sdp_t *sdp_p, uint16_t level); +extern const char *sdp_get_encryption_key(sdp_t *sdp_p, uint16_t level); + +extern tinybool sdp_connection_valid(sdp_t *sdp_p, uint16_t level); +extern tinybool sdp_bw_line_exists(sdp_t *sdp_p, uint16_t level, uint16_t inst_num); +extern tinybool sdp_bandwidth_valid(sdp_t *sdp_p, uint16_t level, uint16_t inst_num); +extern sdp_nettype_e sdp_get_conn_nettype(sdp_t *sdp_p, uint16_t level); +extern sdp_addrtype_e sdp_get_conn_addrtype(sdp_t *sdp_p, uint16_t level); +extern const char *sdp_get_conn_address(sdp_t *sdp_p, uint16_t level); + +extern tinybool sdp_is_mcast_addr (sdp_t *sdp_p, uint16_t level); +extern int32_t sdp_get_mcast_ttl(sdp_t *sdp_p, uint16_t level); +extern int32_t sdp_get_mcast_num_of_addresses(sdp_t *sdp_p, uint16_t level); + +extern sdp_result_e sdp_set_conn_nettype(sdp_t *sdp_p, uint16_t level, + sdp_nettype_e nettype); +extern sdp_result_e sdp_set_conn_addrtype(sdp_t *sdp_p, uint16_t level, + sdp_addrtype_e addrtype); +extern sdp_result_e sdp_set_conn_address(sdp_t *sdp_p, uint16_t level, + const char *address); + +extern tinybool sdp_media_line_valid(sdp_t *sdp_p, uint16_t level); +extern uint16_t sdp_get_num_media_lines(sdp_t *sdp_ptr); +extern sdp_media_e sdp_get_media_type(sdp_t *sdp_p, uint16_t level); +extern uint32_t sdp_get_media_line_number(sdp_t *sdp_p, uint16_t level); +extern sdp_port_format_e sdp_get_media_port_format(sdp_t *sdp_p, uint16_t level); +extern int32_t sdp_get_media_portnum(sdp_t *sdp_p, uint16_t level); +extern int32_t sdp_get_media_portcount(sdp_t *sdp_p, uint16_t level); +extern int32_t sdp_get_media_vpi(sdp_t *sdp_p, uint16_t level); +extern uint32_t sdp_get_media_vci(sdp_t *sdp_p, uint16_t level); +extern int32_t sdp_get_media_vcci(sdp_t *sdp_p, uint16_t level); +extern int32_t sdp_get_media_cid(sdp_t *sdp_p, uint16_t level); +extern sdp_transport_e sdp_get_media_transport(sdp_t *sdp_p, uint16_t level); +extern uint16_t sdp_get_media_num_profiles(sdp_t *sdp_p, uint16_t level); +extern sdp_transport_e sdp_get_media_profile(sdp_t *sdp_p, uint16_t level, + uint16_t profile_num); +extern uint16_t sdp_get_media_num_payload_types(sdp_t *sdp_p, uint16_t level); +extern uint16_t sdp_get_media_profile_num_payload_types(sdp_t *sdp_p, uint16_t level, + uint16_t profile_num); +extern rtp_ptype sdp_get_known_payload_type(sdp_t *sdp_p, + uint16_t level, + uint16_t payload_type_raw); +extern uint32_t sdp_get_media_payload_type(sdp_t *sdp_p, uint16_t level, + uint16_t payload_num, sdp_payload_ind_e *indicator); +extern uint32_t sdp_get_media_profile_payload_type(sdp_t *sdp_p, uint16_t level, + uint16_t prof_num, uint16_t payload_num, sdp_payload_ind_e *indicator); +extern sdp_result_e sdp_insert_media_line(sdp_t *sdp_p, uint16_t level); +extern sdp_result_e sdp_set_media_type(sdp_t *sdp_p, uint16_t level, + sdp_media_e media); +extern sdp_result_e sdp_set_media_portnum(sdp_t *sdp_p, uint16_t level, + int32_t portnum, int32_t sctpport); +extern int32_t sdp_get_media_sctp_port(sdp_t *sdp_p, uint16_t level); +extern sdp_sctp_media_fmt_type_e sdp_get_media_sctp_fmt(sdp_t *sdp_p, uint16_t level); +extern sdp_result_e sdp_set_media_transport(sdp_t *sdp_p, uint16_t level, + sdp_transport_e transport); +extern sdp_result_e sdp_add_media_profile(sdp_t *sdp_p, uint16_t level, + sdp_transport_e profile); +extern sdp_result_e sdp_add_media_payload_type(sdp_t *sdp_p, uint16_t level, + uint16_t payload_type, sdp_payload_ind_e indicator); +extern sdp_result_e sdp_add_media_profile_payload_type(sdp_t *sdp_p, + uint16_t level, uint16_t prof_num, uint16_t payload_type, + sdp_payload_ind_e indicator); + +/* sdp_attr_access.c */ +extern sdp_attr_t *sdp_find_attr (sdp_t *sdp_p, uint16_t level, uint8_t cap_num, + sdp_attr_e attr_type, uint16_t inst_num); + +extern int sdp_find_fmtp_inst(sdp_t *sdp_ptr, uint16_t level, uint16_t payload_num); +extern sdp_result_e sdp_add_new_attr(sdp_t *sdp_p, uint16_t level, uint8_t cap_num, + sdp_attr_e attr_type, uint16_t *inst_num); +extern sdp_result_e sdp_attr_num_instances(sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, sdp_attr_e attr_type, uint16_t *num_attr_inst); +extern tinybool sdp_attr_valid(sdp_t *sdp_p, sdp_attr_e attr_type, + uint16_t level, uint8_t cap_num, uint16_t inst_num); +extern uint32_t sdp_attr_line_number(sdp_t *sdp_p, sdp_attr_e attr_type, + uint16_t level, uint8_t cap_num, uint16_t inst_num); +extern const char *sdp_attr_get_simple_string(sdp_t *sdp_p, + sdp_attr_e attr_type, uint16_t level, uint8_t cap_num, uint16_t inst_num); +extern const char *sdp_attr_get_long_string(sdp_t *sdp_p, + sdp_attr_e attr_type, uint16_t level, uint8_t cap_num, uint16_t inst_num); +extern uint32_t sdp_attr_get_simple_u32(sdp_t *sdp_p, sdp_attr_e attr_type, + uint16_t level, uint8_t cap_num, uint16_t inst_num); +extern tinybool sdp_attr_get_simple_boolean(sdp_t *sdp_p, + sdp_attr_e attr_type, uint16_t level, uint8_t cap_num, uint16_t inst_num); +extern tinybool sdp_attr_is_present (sdp_t *sdp_p, sdp_attr_e attr_type, + uint16_t level, uint8_t cap_num); +extern const char* sdp_attr_get_maxprate(sdp_t *sdp_p, uint16_t level, + uint16_t inst_num); +extern sdp_t38_ratemgmt_e sdp_attr_get_t38ratemgmt(sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num); +extern sdp_t38_udpec_e sdp_attr_get_t38udpec(sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num); +extern sdp_direction_e sdp_get_media_direction(sdp_t *sdp_p, uint16_t level, + uint8_t cap_num); +extern sdp_qos_strength_e sdp_attr_get_qos_strength(sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, sdp_attr_e qos_attr, uint16_t inst_num); +extern sdp_qos_status_types_e sdp_attr_get_qos_status_type (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, sdp_attr_e qos_attr, uint16_t inst_num); +extern sdp_qos_dir_e sdp_attr_get_qos_direction(sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, sdp_attr_e qos_attr, uint16_t inst_num); +extern tinybool sdp_attr_get_qos_confirm(sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, sdp_attr_e qos_attr, uint16_t inst_num); +extern sdp_curr_type_e sdp_attr_get_curr_type (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, sdp_attr_e qos_attr, uint16_t inst_num); +extern sdp_des_type_e sdp_attr_get_des_type (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, sdp_attr_e qos_attr, uint16_t inst_num); +extern sdp_conf_type_e sdp_attr_get_conf_type (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, sdp_attr_e qos_attr, uint16_t inst_num); +extern sdp_nettype_e sdp_attr_get_subnet_nettype(sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num); +extern sdp_addrtype_e sdp_attr_get_subnet_addrtype(sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num); +extern const char *sdp_attr_get_subnet_addr(sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num); +extern int32_t sdp_attr_get_subnet_prefix(sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num); +extern rtp_ptype sdp_attr_get_rtpmap_known_codec(sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num); +extern tinybool sdp_attr_rtpmap_payload_valid(sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t *inst_num, uint16_t payload_type); +extern uint16_t sdp_attr_get_rtpmap_payload_type(sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num); +extern const char *sdp_attr_get_rtpmap_encname(sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num); +extern uint32_t sdp_attr_get_rtpmap_clockrate(sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num); +extern uint16_t sdp_attr_get_rtpmap_num_chan(sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num); +extern tinybool sdp_attr_sprtmap_payload_valid(sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t *inst_num, uint16_t payload_type); +extern uint16_t sdp_attr_get_sprtmap_payload_type(sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num); +extern const char *sdp_attr_get_sprtmap_encname(sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num); +extern uint32_t sdp_attr_get_sprtmap_clockrate(sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num); +extern uint16_t sdp_attr_get_sprtmap_num_chan(sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num); +extern tinybool sdp_attr_fmtp_payload_valid(sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t *inst_num, uint16_t payload_type); +extern uint16_t sdp_attr_get_fmtp_payload_type(sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num); +extern sdp_ne_res_e sdp_attr_fmtp_is_range_set(sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num, uint8_t low_val, uint8_t high_val); +extern tinybool sdp_attr_fmtp_valid(sdp_t *sdp_p, uint16_t level, uint8_t cap_num, + uint16_t inst_num, uint16_t appl_maxval, uint32_t* evt_array); +extern sdp_result_e sdp_attr_set_fmtp_payload_type(sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num, + uint16_t payload_num); +extern sdp_result_e sdp_attr_get_fmtp_range(sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num, uint32_t *bmap); +extern sdp_result_e sdp_attr_clear_fmtp_range(sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num, uint8_t low_val, uint8_t high_val); +extern sdp_ne_res_e sdp_attr_compare_fmtp_ranges(sdp_t *src_sdp_ptr, + sdp_t *dst_sdp_ptr, uint16_t src_level, uint16_t dst_level, + uint8_t src_cap_num, uint8_t dst_cap_num, uint16_t src_inst_num, + uint16_t dst_inst_num); +extern sdp_result_e sdp_attr_copy_fmtp_ranges(sdp_t *src_sdp_ptr, + sdp_t *dst_sdp_ptr, uint16_t src_level, uint16_t dst_level, + uint8_t src_cap_num, uint8_t dst_cap_num, uint16_t src_inst_num, + uint16_t dst_inst_num); +extern uint32_t sdp_attr_get_fmtp_mode_for_payload_type (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint32_t payload_type); + +extern sdp_result_e sdp_attr_set_fmtp_max_fs (sdp_t *sdp_p, + uint16_t level, + uint8_t cap_num, + uint16_t inst_num, + uint32_t max_fs); + +extern sdp_result_e sdp_attr_set_fmtp_max_fr (sdp_t *sdp_p, + uint16_t level, + uint8_t cap_num, + uint16_t inst_num, + uint32_t max_fr); + +/* get routines */ +extern int32_t sdp_attr_get_fmtp_bitrate_type (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num); + +extern int32_t sdp_attr_get_fmtp_cif (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num); +extern int32_t sdp_attr_get_fmtp_qcif (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num); +extern int32_t sdp_attr_get_fmtp_sqcif (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num); +extern int32_t sdp_attr_get_fmtp_cif4 (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num); +extern int32_t sdp_attr_get_fmtp_cif16 (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num); +extern int32_t sdp_attr_get_fmtp_maxbr (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num); +extern sdp_result_e sdp_attr_get_fmtp_max_average_bitrate (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num, uint32_t* val); +extern sdp_result_e sdp_attr_get_fmtp_usedtx (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num, tinybool* val); +extern sdp_result_e sdp_attr_get_fmtp_stereo (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num, tinybool* val); +extern sdp_result_e sdp_attr_get_fmtp_useinbandfec (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num, tinybool* val); +extern char* sdp_attr_get_fmtp_maxcodedaudiobandwidth (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num); +extern sdp_result_e sdp_attr_get_fmtp_cbr (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num, tinybool* val); +extern int32_t sdp_attr_get_fmtp_custom_x (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num); +extern int32_t sdp_attr_get_fmtp_custom_y (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num); +extern int32_t sdp_attr_get_fmtp_custom_mpi (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num); +extern int32_t sdp_attr_get_fmtp_par_width (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num); +extern int32_t sdp_attr_get_fmtp_par_height (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num); +extern int32_t sdp_attr_get_fmtp_bpp (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num); +extern int32_t sdp_attr_get_fmtp_hrd (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num); +extern int32_t sdp_attr_get_fmtp_profile (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num); +extern int32_t sdp_attr_get_fmtp_level (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num); +extern tinybool sdp_attr_get_fmtp_interlace (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num); +extern tinybool sdp_attr_get_fmtp_annex_d (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num); +extern tinybool sdp_attr_get_fmtp_annex_f (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num); +extern tinybool sdp_attr_get_fmtp_annex_i (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num); +extern tinybool sdp_attr_get_fmtp_annex_j (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num); +extern tinybool sdp_attr_get_fmtp_annex_t (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num); +extern int32_t sdp_attr_get_fmtp_annex_k_val (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num); +extern int32_t sdp_attr_get_fmtp_annex_n_val (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num); + +extern int32_t sdp_attr_get_fmtp_annex_p_picture_resize (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num); +extern int32_t sdp_attr_get_fmtp_annex_p_warp (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num); + +/* sctpmap params */ +extern uint16_t sdp_attr_get_sctpmap_port(sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num); +extern sdp_result_e sdp_attr_get_sctpmap_protocol (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num, char* protocol); +extern sdp_result_e sdp_attr_get_sctpmap_streams (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num, uint32_t* val); + +extern const char *sdp_attr_get_msid_identifier(sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num); +extern const char *sdp_attr_get_msid_appdata(sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num); + +/* H.264 codec specific params */ + +extern const char *sdp_attr_get_fmtp_profile_id(sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num); +extern const char *sdp_attr_get_fmtp_param_sets(sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num); +extern sdp_result_e sdp_attr_get_fmtp_pack_mode (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num, uint16_t *val); + +extern sdp_result_e sdp_attr_get_fmtp_level_asymmetry_allowed (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num, uint16_t *val); + +extern sdp_result_e sdp_attr_get_fmtp_interleaving_depth (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num, + uint16_t *val); +extern sdp_result_e sdp_attr_get_fmtp_max_don_diff (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num, + uint32_t *val); + +/* The following four H.264 parameters that require special handling as + * the values range from 0 - 4294967295 + */ +extern sdp_result_e sdp_attr_get_fmtp_deint_buf_req (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num, + uint32_t *val); +extern sdp_result_e sdp_attr_get_fmtp_deint_buf_cap (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num, + uint32_t *val); +extern sdp_result_e sdp_attr_get_fmtp_init_buf_time (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num, + uint32_t *val); +extern sdp_result_e sdp_attr_get_fmtp_max_rcmd_nalu_size (sdp_t *sdp_p, + uint16_t level, uint8_t cap_num, + uint16_t inst_num, uint32_t *val); + + +extern sdp_result_e sdp_attr_get_fmtp_max_mbps (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num, uint32_t *val); +extern sdp_result_e sdp_attr_get_fmtp_max_fs (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num, uint32_t *val); +extern sdp_result_e sdp_attr_get_fmtp_max_fr (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num, uint32_t *val); +extern sdp_result_e sdp_attr_get_fmtp_max_cpb (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num, uint32_t *val); +extern sdp_result_e sdp_attr_get_fmtp_max_dpb (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num, uint32_t *val); +extern sdp_result_e sdp_attr_get_fmtp_max_br (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num, uint32_t *val); +extern tinybool sdp_attr_fmtp_is_redundant_pic_cap (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, + uint16_t inst_num); +extern tinybool sdp_attr_fmtp_is_parameter_add (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, + uint16_t inst_num); +extern tinybool sdp_attr_fmtp_is_annexa_set (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, + uint16_t inst_num); + +extern tinybool sdp_attr_fmtp_is_annexb_set (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, + uint16_t inst_num); + +extern sdp_fmtp_format_type_e sdp_attr_fmtp_get_fmtp_format (sdp_t *sdp_p, uint16_t level, uint8_t cap_num, + uint16_t inst_num); + +extern uint16_t sdp_attr_get_pccodec_num_payload_types(sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num); +extern uint16_t sdp_attr_get_pccodec_payload_type(sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num, uint16_t payload_num); +extern sdp_result_e sdp_attr_add_pccodec_payload_type(sdp_t *sdp_p, + uint16_t level, uint8_t cap_num, + uint16_t inst_num, uint16_t payload_type); +extern uint16_t sdp_attr_get_xcap_first_cap_num(sdp_t *sdp_p, uint16_t level, + uint16_t inst_num); +extern sdp_media_e sdp_attr_get_xcap_media_type(sdp_t *sdp_p, uint16_t level, + uint16_t inst_num); +extern sdp_transport_e sdp_attr_get_xcap_transport_type(sdp_t *sdp_p, + uint16_t level, uint16_t inst_num); +extern uint16_t sdp_attr_get_xcap_num_payload_types(sdp_t *sdp_p, uint16_t level, + uint16_t inst_num); +extern uint16_t sdp_attr_get_xcap_payload_type(sdp_t *sdp_p, uint16_t level, + uint16_t inst_num, uint16_t payload_num, + sdp_payload_ind_e *indicator); +extern sdp_result_e sdp_attr_add_xcap_payload_type(sdp_t *sdp_p, uint16_t level, + uint16_t inst_num, uint16_t payload_type, + sdp_payload_ind_e indicator); +extern uint16_t sdp_attr_get_cdsc_first_cap_num(sdp_t *sdp_p, uint16_t level, + uint16_t inst_num); +extern sdp_media_e sdp_attr_get_cdsc_media_type(sdp_t *sdp_p, uint16_t level, + uint16_t inst_num); +extern sdp_transport_e sdp_attr_get_cdsc_transport_type(sdp_t *sdp_p, + uint16_t level, uint16_t inst_num); +extern uint16_t sdp_attr_get_cdsc_num_payload_types(sdp_t *sdp_p, uint16_t level, + uint16_t inst_num); +extern uint16_t sdp_attr_get_cdsc_payload_type(sdp_t *sdp_p, uint16_t level, + uint16_t inst_num, uint16_t payload_num, + sdp_payload_ind_e *indicator); +extern sdp_result_e sdp_attr_add_cdsc_payload_type(sdp_t *sdp_p, uint16_t level, + uint16_t inst_num, uint16_t payload_type, + sdp_payload_ind_e indicator); +extern tinybool sdp_media_dynamic_payload_valid (sdp_t *sdp_p, uint16_t payload_type, + uint16_t m_line); + +extern tinybool sdp_attr_get_rtr_confirm (sdp_t *, uint16_t, uint8_t, uint16_t); + +extern tinybool sdp_attr_get_silencesupp_enabled(sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num); +extern uint16_t sdp_attr_get_silencesupp_timer(sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num, + tinybool *null_ind); +extern sdp_silencesupp_pref_e sdp_attr_get_silencesupp_pref(sdp_t *sdp_p, + uint16_t level, + uint8_t cap_num, + uint16_t inst_num); +extern sdp_silencesupp_siduse_e sdp_attr_get_silencesupp_siduse(sdp_t *sdp_p, + uint16_t level, + uint8_t cap_num, + uint16_t inst_num); +extern uint8_t sdp_attr_get_silencesupp_fxnslevel(sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num, + tinybool *null_ind); +extern sdp_mediadir_role_e sdp_attr_get_comediadir_role(sdp_t *sdp_p, + uint16_t level, uint8_t cap_num, + uint16_t inst_num); + +extern uint16_t sdp_attr_get_mptime_num_intervals( + sdp_t *sdp_p, uint16_t level, uint8_t cap_num, uint16_t inst_num); +extern uint16_t sdp_attr_get_mptime_interval( + sdp_t *sdp_p, uint16_t level, uint8_t cap_num, uint16_t inst_num, uint16_t interval_num); +extern sdp_result_e sdp_attr_add_mptime_interval( + sdp_t *sdp_p, uint16_t level, uint8_t cap_num, uint16_t inst_num, uint16_t interval); + + +extern sdp_result_e sdp_copy_all_bw_lines(sdp_t *src_sdp_ptr, sdp_t *dst_sdp_ptr, + uint16_t src_level, uint16_t dst_level); +extern sdp_bw_modifier_e sdp_get_bw_modifier(sdp_t *sdp_p, uint16_t level, + uint16_t inst_num); +extern const char *sdp_get_bw_modifier_name(sdp_bw_modifier_e bw_modifier); +extern int32_t sdp_get_bw_value(sdp_t *sdp_p, uint16_t level, uint16_t inst_num); +extern int32_t sdp_get_num_bw_lines (sdp_t *sdp_p, uint16_t level); + +extern sdp_result_e sdp_add_new_bw_line(sdp_t *sdp_p, uint16_t level, + sdp_bw_modifier_e bw_modifier, uint16_t *inst_num); + +extern sdp_group_attr_e sdp_get_group_attr(sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num); + +extern const char* sdp_attr_get_x_sidout (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num); + + +extern const char* sdp_attr_get_x_sidin (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num); + +extern const char* sdp_attr_get_x_confid (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num); + +extern uint16_t sdp_get_group_num_id(sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num); + +extern const char* sdp_get_group_id(sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num, uint16_t id_num); + +extern int32_t sdp_get_mid_value(sdp_t *sdp_p, uint16_t level); +extern sdp_result_e sdp_include_new_filter_src_addr(sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num, + const char *src_addr); +extern sdp_src_filter_mode_e sdp_get_source_filter_mode(sdp_t *sdp_p, + uint16_t level, uint8_t cap_num, + uint16_t inst_num); +extern sdp_result_e sdp_get_filter_destination_attributes(sdp_t *sdp_p, + uint16_t level, uint8_t cap_num, + uint16_t inst_num, + sdp_nettype_e *nettype, + sdp_addrtype_e *addrtype, + char *dest_addr); +extern int32_t sdp_get_filter_source_address_count(sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num); +extern sdp_result_e sdp_get_filter_source_address (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num, + uint16_t src_addr_id, + char *src_addr); + +extern sdp_rtcp_unicast_mode_e sdp_get_rtcp_unicast_mode(sdp_t *sdp_p, + uint16_t level, uint8_t cap_num, + uint16_t inst_num); + +void sdp_crypto_debug(char *buffer, ulong length_bytes); +char * sdp_debug_msg_filter(char *buffer, ulong length_bytes); + +extern int32_t +sdp_attr_get_sdescriptions_tag(sdp_t *sdp_p, + uint16_t level, + uint8_t cap_num, + uint16_t inst_num); + +extern sdp_srtp_crypto_suite_t +sdp_attr_get_sdescriptions_crypto_suite(sdp_t *sdp_p, + uint16_t level, + uint8_t cap_num, + uint16_t inst_num); + +extern const char* +sdp_attr_get_sdescriptions_key(sdp_t *sdp_p, + uint16_t level, + uint8_t cap_num, + uint16_t inst_num); + +extern const char* +sdp_attr_get_sdescriptions_salt(sdp_t *sdp_p, + uint16_t level, + uint8_t cap_num, + uint16_t inst_num); + +extern const char* +sdp_attr_get_sdescriptions_lifetime(sdp_t *sdp_p, + uint16_t level, + uint8_t cap_num, + uint16_t inst_num); + +extern sdp_result_e +sdp_attr_get_sdescriptions_mki(sdp_t *sdp_p, + uint16_t level, + uint8_t cap_num, + uint16_t inst_num, + const char **mki_value, + uint16_t *mki_length); + +extern const char* +sdp_attr_get_sdescriptions_session_params(sdp_t *sdp_p, + uint16_t level, + uint8_t cap_num, + uint16_t inst_num); + +extern unsigned char +sdp_attr_get_sdescriptions_key_size(sdp_t *sdp_p, + uint16_t level, + uint8_t cap_num, + uint16_t inst_num); + +extern unsigned char +sdp_attr_get_sdescriptions_salt_size(sdp_t *sdp_p, + uint16_t level, + uint8_t cap_num, + uint16_t inst_num); + +extern unsigned long +sdp_attr_get_srtp_crypto_selection_flags(sdp_t *sdp_p, + uint16_t level, + uint8_t cap_num, + uint16_t inst_num); + +sdp_result_e +sdp_attr_get_ice_attribute (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, sdp_attr_e sdp_attr, uint16_t inst_num, + char **out); + +sdp_result_e +sdp_attr_get_rtcp_mux_attribute (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, sdp_attr_e sdp_attr, uint16_t inst_num, + tinybool *rtcp_mux); + +sdp_result_e +sdp_attr_get_setup_attribute (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num, sdp_setup_type_e *setup_type); + +sdp_result_e +sdp_attr_get_connection_attribute (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, uint16_t inst_num, sdp_connection_type_e *connection_type); + +sdp_result_e +sdp_attr_get_dtls_fingerprint_attribute (sdp_t *sdp_p, uint16_t level, + uint8_t cap_num, sdp_attr_e sdp_attr, uint16_t inst_num, + char **out); + +sdp_rtcp_fb_ack_type_e +sdp_attr_get_rtcp_fb_ack(sdp_t *sdp_p, uint16_t level, uint16_t payload_type, uint16_t inst); + +sdp_rtcp_fb_nack_type_e +sdp_attr_get_rtcp_fb_nack(sdp_t *sdp_p, uint16_t level, uint16_t payload_type, uint16_t inst); + +uint32_t +sdp_attr_get_rtcp_fb_trr_int(sdp_t *sdp_p, uint16_t level, uint16_t payload_type, + uint16_t inst); + +tinybool +sdp_attr_get_rtcp_fb_remb_enabled(sdp_t *sdp_p, uint16_t level, + uint16_t payload_type); + +tinybool +sdp_attr_get_rtcp_fb_transport_cc_enabled(sdp_t *sdp_p, uint16_t level, + uint16_t payload_type); + +sdp_rtcp_fb_ccm_type_e +sdp_attr_get_rtcp_fb_ccm(sdp_t *sdp_p, uint16_t level, uint16_t payload_type, uint16_t inst); + +sdp_result_e +sdp_attr_set_rtcp_fb_ack(sdp_t *sdp_p, uint16_t level, uint16_t payload_type, uint16_t inst, + sdp_rtcp_fb_ack_type_e type); + +sdp_result_e +sdp_attr_set_rtcp_fb_nack(sdp_t *sdp_p, uint16_t level, uint16_t payload_type, uint16_t inst, + sdp_rtcp_fb_nack_type_e); + +sdp_result_e +sdp_attr_set_rtcp_fb_trr_int(sdp_t *sdp_p, uint16_t level, uint16_t payload_type, + uint16_t inst, uint32_t interval); + +sdp_result_e +sdp_attr_set_rtcp_fb_remb(sdp_t *sdp_p, uint16_t level, uint16_t payload_type, + uint16_t inst); +sdp_result_e +sdp_attr_set_rtcp_fb_transport_cc(sdp_t *sdp_p, uint16_t level, uint16_t payload_type, + uint16_t inst); + +sdp_result_e +sdp_attr_set_rtcp_fb_ccm(sdp_t *sdp_p, uint16_t level, uint16_t payload_type, uint16_t inst, + sdp_rtcp_fb_ccm_type_e); +const char * +sdp_attr_get_extmap_uri(sdp_t *sdp_p, uint16_t level, uint16_t inst); + +uint16_t +sdp_attr_get_extmap_id(sdp_t *sdp_p, uint16_t level, uint16_t inst); + +sdp_result_e +sdp_attr_set_extmap(sdp_t *sdp_p, uint16_t level, uint16_t id, const char* uri, uint16_t inst); + +#endif /* _SDP_H_ */ |