diff options
Diffstat (limited to 'third_party/sipcc/sdp_main.c')
-rw-r--r-- | third_party/sipcc/sdp_main.c | 1374 |
1 files changed, 1374 insertions, 0 deletions
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); +} |