#include "call_flags.h" #include "str.h" #include "control_ng_flags_parser.h" bool trust_address_def; bool dtls_passive_def; INLINE int call_ng_flags_prefix(str *s_ori, const char *prefix, const char *(*cb)(str *, unsigned int, helper_arg), helper_arg); static const char *call_ng_flags_str_ht(str *s, unsigned int, helper_arg); static const char *call_ng_flags_str_q_multi(str *s, unsigned int, helper_arg); static const char *call_ng_flags_str_list(const ng_parser_t *, parser_arg list, const char *(*callback)(str *, unsigned int, helper_arg), helper_arg); static const char *call_ng_flags_list(const ng_parser_t *, parser_arg list, const char *(*str_callback)(str *, unsigned int, helper_arg), const char *(*item_callback)(const ng_parser_t *, parser_arg, helper_arg), helper_arg); static const char *call_ng_flags_esc_str_list(str *s, unsigned int, helper_arg); static str *str_dup_escape(const str *s); static const char *ng_sdes_option(str *s, unsigned int idx, helper_arg arg) { sdp_ng_flags *out = arg.flags; /* Accept only certain individual crypto suites */ if (call_ng_flags_prefix(s, "only-", call_ng_flags_str_ht, &out->sdes_only)) return NULL; /* Exclude individual crypto suites */ if (call_ng_flags_prefix(s, "no-", call_ng_flags_str_ht, &out->sdes_no)) return NULL; /* Order individual crypto suites */ if (call_ng_flags_prefix(s, "order:", call_ng_flags_str_q_multi, &out->sdes_order)) return NULL; /* Crypto suite preferences for the offerer */ if (call_ng_flags_prefix(s, "offerer_pref:", call_ng_flags_str_q_multi, &out->sdes_offerer_pref)) return NULL; switch (__csh_lookup(s)) { case CSH_LOOKUP("no"): case CSH_LOOKUP("off"): case CSH_LOOKUP("disabled"): case CSH_LOOKUP("disable"): out->sdes_off = true; break; case CSH_LOOKUP("unencrypted_srtp"): case CSH_LOOKUP("UNENCRYPTED_SRTP"): out->sdes_unencrypted_srtp = true; break; case CSH_LOOKUP("unencrypted_srtcp"): case CSH_LOOKUP("UNENCRYPTED_SRTCP"): out->sdes_unencrypted_srtcp = true; break; case CSH_LOOKUP("unauthenticated_srtp"): case CSH_LOOKUP("UNAUTHENTICATED_SRTP"): out->sdes_unauthenticated_srtp = true; break; case CSH_LOOKUP("encrypted_srtp"): case CSH_LOOKUP("ENCRYPTED_SRTP"): out->sdes_encrypted_srtp = true; break; case CSH_LOOKUP("encrypted_srtcp"): case CSH_LOOKUP("ENCRYPTED_SRTCP"): out->sdes_encrypted_srtcp = true; break; case CSH_LOOKUP("authenticated_srtp"): case CSH_LOOKUP("AUTHENTICATED_SRTP"): out->sdes_authenticated_srtp = true; break; case CSH_LOOKUP("lifetime"): out->sdes_lifetime = true; break; case CSH_LOOKUP("pad"): out->sdes_pad = true; break; case CSH_LOOKUP("static"): out->sdes_static = true; break; case CSH_LOOKUP("nonew"): out->sdes_nonew = true; break; case CSH_LOOKUP("prefer"): case CSH_LOOKUP("priority"): out->sdes_prefer = true; break; default: ilog(LOG_WARN, "Unknown 'SDES' flag encountered: '"STR_FORMAT"'", STR_FMT(s)); } return NULL; } static const char *ng_osrtp_option(str *s, unsigned int idx, helper_arg arg) { sdp_ng_flags *out = arg.flags; switch (__csh_lookup(s)) { case CSH_LOOKUP("accept-rfc"): case CSH_LOOKUP("accept-RFC"): out->osrtp_accept_rfc = true; break; case CSH_LOOKUP("accept-legacy"): out->osrtp_accept_legacy = true; break; case CSH_LOOKUP("accept"): out->osrtp_accept_rfc = true; out->osrtp_accept_legacy = true; break; case CSH_LOOKUP("offer-legacy"): out->osrtp_offer_legacy = true; break; case CSH_LOOKUP("offer"): case CSH_LOOKUP("offer-RFC"): case CSH_LOOKUP("offer-rfc"): out->osrtp_offer = true; break; default: ilog(LOG_WARN, "Unknown 'OSRTP' flag encountered: '" STR_FORMAT "'", STR_FMT(s)); } return NULL; } static const char *call_ng_flags_str_pair_ht(str *s, unsigned int idx, helper_arg arg) { str *s_copy = str_dup_escape(s); str token; if (!str_token(&token, s_copy, '>')) { ilog(LOG_WARN, "SDP manipulations: Ignoring invalid token '" STR_FORMAT "'", STR_FMT(s)); free(s_copy); return NULL; // return error? } str_case_value_ht *ht = arg.svt; if (!t_hash_table_is_set(*ht)) *ht = str_case_value_ht_new(); t_hash_table_replace(*ht, str_dup(&token), s_copy); return NULL; } static const char *call_ng_flags_item_pair_ht_iter(str *key, unsigned int idx, helper_arg arg) { str *from_to = arg.strs; if (from_to[0].len == 0) from_to[0] = *key; else if (from_to[1].len == 0) from_to[1] = *key; return NULL; } static const char *call_ng_flags_item_pair_ht(const ng_parser_t *parser, parser_arg it, helper_arg arg) { str from_to[2] = {0}; if (!parser->is_list(it)) goto err; parser->list_iter(parser, it, call_ng_flags_item_pair_ht_iter, NULL, from_to); if (from_to[0].len == 0 || from_to[1].len == 0) goto err; str *s_copy_from = str_dup_escape(&from_to[0]); str *s_copy_to = str_dup_escape(&from_to[1]); str_case_value_ht *ht = arg.svt; if (!t_hash_table_is_set(*ht)) *ht = str_case_value_ht_new(); t_hash_table_replace(*ht, s_copy_from, s_copy_to); return NULL; err: ilog(LOG_WARN, "SDP manipulations: Ignoring invalid contents of string-pair list"); return NULL; } /** * SDP attribute manipulation praser helpers. */ static const char *ng_sdp_attr_media_iter(const ng_parser_t *parser, str *command_type, parser_arg command_value, helper_arg arg) { struct sdp_manipulations *sm = arg.sm; switch (__csh_lookup(command_type)) { case CSH_LOOKUP("substitute"): call_ng_flags_list(parser, command_value, call_ng_flags_str_pair_ht, call_ng_flags_item_pair_ht, &sm->subst_commands); break; case CSH_LOOKUP("add"): return call_ng_flags_str_list(parser, command_value, call_ng_flags_esc_str_list, &sm->add_commands); case CSH_LOOKUP("remove"): return call_ng_flags_str_list(parser, command_value, call_ng_flags_str_ht, &sm->rem_commands); default: ilog(LOG_WARN, "SDP manipulations: Unknown SDP manipulation command type."); } return NULL; } static const char *ng_sdp_attr_manipulations_iter(const ng_parser_t *parser, str *media_type, parser_arg command_action, helper_arg arg) { struct sdp_manipulations *sm = sdp_manipulations_get_by_name(arg.flags->sdp_manipulations, media_type); if (!sm) { ilog(LOG_WARN, "SDP manipulations: unsupported SDP section '" STR_FORMAT "' targeted.", STR_FMT(media_type)); return NULL; } if (!parser->is_dict(command_action)) { ilog(LOG_WARN, "SDP manipulations: Wrong content for SDP section."); return NULL; } return parser->dict_iter(parser, command_action, ng_sdp_attr_media_iter, sm); } INLINE const char *ng_sdp_attr_manipulations(const ng_parser_t *parser, sdp_ng_flags *flags, parser_arg value) { if (!parser->is_dict(value)) ilog(LOG_WARN, "SDP manipulations: Wrong type for this type of command."); return parser->dict_iter(parser, value, ng_sdp_attr_manipulations_iter, flags); } /** * SDP media section manipulation parser helpers. */ static const char *ng_sdp_media_remove_iter(str *media_type, unsigned int i, helper_arg arg) { enum media_type id = codec_get_type(media_type); if (id == MT_UNKNOWN || (id == MT_OTHER && str_cmp(media_type, "other"))) { ilog(LOG_WARN, "SDP manipulations: unsupported SDP section '" STR_FORMAT "' targeted.", STR_FMT(media_type)); /* only known media types are supported */ return NULL; // return error? } arg.flags->sdp_media_remove[id] = true; return NULL; } INLINE void ng_sdp_media_remove(const ng_parser_t *parser, sdp_ng_flags *flags, parser_arg value) { if (!parser->is_list(value)) return; parser->list_iter(parser, value, ng_sdp_media_remove_iter, NULL, flags); } static const char *ng_el_option(str *s, unsigned int idx, helper_arg arg) { sdp_ng_flags *out = arg.flags; switch (__csh_lookup(s)) { case CSH_LOOKUP("off"): out->el_option = EL_OFF; break; case CSH_LOOKUP("immediate"): out->el_option = EL_IMMEDIATE; break; case CSH_LOOKUP("delayed"): out->el_option = EL_DELAYED; break; case CSH_LOOKUP("heuristic"): out->el_option = EL_HEURISTIC; break; default: ilog(LOG_WARN, "Unknown 'endpoint-learning' flag encountered: '" STR_FORMAT "'", STR_FMT(s)); } return NULL; } #ifdef WITH_TRANSCODING static const char *ng_t38_option(str *s, unsigned int idx, helper_arg arg) { sdp_ng_flags *out = arg.flags; switch (__csh_lookup(s)) { case CSH_LOOKUP("decode"): out->t38_decode = true; break; case CSH_LOOKUP("force"): out->t38_force = true; break; case CSH_LOOKUP("stop"): out->t38_stop = true; break; case CSH_LOOKUP("no-ecm"): case CSH_LOOKUP("no-ECM"): case CSH_LOOKUP("no ecm"): case CSH_LOOKUP("no ECM"): out->t38_no_ecm = true; break; case CSH_LOOKUP("no-V17"): case CSH_LOOKUP("no-V.17"): case CSH_LOOKUP("no-v17"): case CSH_LOOKUP("no-v.17"): case CSH_LOOKUP("no V17"): case CSH_LOOKUP("no V.17"): case CSH_LOOKUP("no v17"): case CSH_LOOKUP("no v.17"): out->t38_no_v17 = true; break; case CSH_LOOKUP("no-V.27ter"): case CSH_LOOKUP("no-V27ter"): case CSH_LOOKUP("no-v.27ter"): case CSH_LOOKUP("no-v27ter"): case CSH_LOOKUP("no V.27ter"): case CSH_LOOKUP("no V27ter"): case CSH_LOOKUP("no v.27ter"): case CSH_LOOKUP("no v27ter"): out->t38_no_v27ter = true; break; case CSH_LOOKUP("no-V29"): case CSH_LOOKUP("no-V.29"): case CSH_LOOKUP("no-v29"): case CSH_LOOKUP("no-v.29"): case CSH_LOOKUP("no V29"): case CSH_LOOKUP("no V.29"): case CSH_LOOKUP("no v29"): case CSH_LOOKUP("no v.29"): out->t38_no_v29 = true; break; case CSH_LOOKUP("no-V34"): case CSH_LOOKUP("no-V.34"): case CSH_LOOKUP("no-v34"): case CSH_LOOKUP("no-v.34"): case CSH_LOOKUP("no V34"): case CSH_LOOKUP("no V.34"): case CSH_LOOKUP("no v34"): case CSH_LOOKUP("no v.34"): out->t38_no_v34 = true; break; case CSH_LOOKUP("no-IAF"): case CSH_LOOKUP("no-iaf"): case CSH_LOOKUP("no IAF"): case CSH_LOOKUP("no iaf"): out->t38_no_iaf = true; break; case CSH_LOOKUP("FEC"): case CSH_LOOKUP("fec"): out->t38_fec = true; break; default: ilog(LOG_WARN, "Unknown 'T.38' flag encountered: '" STR_FORMAT "'", STR_FMT(s)); } return NULL; } #endif static const char *call_ng_flags_list(const ng_parser_t *parser, parser_arg list, const char *(*str_callback)(str *, unsigned int, helper_arg), const char *(*item_callback)(const ng_parser_t *, parser_arg, helper_arg), helper_arg arg) { str s; if (!parser->is_list(list)) { if (parser->get_str(list, &s)) { str token; while (str_token_sep(&token, &s, ',')) { const char *err = str_callback(&token, 0, arg); if (err) return err; } } else ilog(LOG_DEBUG, "Ignoring non-list non-string value"); return NULL; } parser->list_iter(parser, list, str_callback, item_callback, arg); return NULL; } static const char *call_ng_flags_str_list(const ng_parser_t *parser, parser_arg list, const char *(*callback)(str *, unsigned int, helper_arg), helper_arg arg) { return call_ng_flags_list(parser, list, callback, NULL, arg); } static const char *call_ng_flags_rtcp_mux(str *s, unsigned int idx, helper_arg arg) { sdp_ng_flags *out = arg.flags; switch (__csh_lookup(s)) { case CSH_LOOKUP("accept"): out->rtcp_mux_accept = true; break; case CSH_LOOKUP("demux"): out->rtcp_mux_demux = true; break; case CSH_LOOKUP("offer"): out->rtcp_mux_offer = true; break; case CSH_LOOKUP("reject"): out->rtcp_mux_reject = true; break; case CSH_LOOKUP("require"): out->rtcp_mux_offer = true; out->rtcp_mux_require = true; break; default: ilog(LOG_WARN, "Unknown 'rtcp-mux' flag encountered: '" STR_FORMAT "'", STR_FMT(s)); } return NULL; } static const char *call_ng_flags_bundle(str *s, unsigned int idx, helper_arg arg) { sdp_ng_flags *out = arg.flags; switch (__csh_lookup(s)) { case CSH_LOOKUP("accept"): out->bundle_accept = true; break; case CSH_LOOKUP("offer"): out->bundle_offer = true; out->generate_mid = true; break; case CSH_LOOKUP("reject"): out->bundle_reject = true; break; case CSH_LOOKUP("require"): out->bundle_offer = true; out->bundle_require = true; out->generate_mid = true; break; case CSH_LOOKUP("strict"): out->bundle_offer = true; out->bundle_require = true; out->bundle_strict = true; out->generate_mid = true; break; default: ilog(LOG_WARN, "Unknown 'BUNDLE' flag encountered: '" STR_FORMAT "'", STR_FMT(s)); } return NULL; } static const char *call_ng_flags_moh(const ng_parser_t *parser, str *key, parser_arg value, helper_arg arg) { sdp_ng_flags *out = arg.flags; switch (__csh_lookup(key)) { case CSH_LOOKUP("db-id"): out->moh_db_id = parser->get_int_str(value, out->moh_db_id); break; case CSH_LOOKUP("blob"): parser->get_str(value, &out->moh_blob); break; case CSH_LOOKUP("file"): parser->get_str(value, &out->moh_file); break; case CSH_LOOKUP("connection"):; str connection = STR_NULL; parser->get_str(value, &connection); if (!str_cmp(&connection, "zero")) out->moh_zero_connection = true; break; case CSH_LOOKUP("mode"):; str mode = STR_NULL; parser->get_str(value, &mode); if (!str_cmp(&mode, "sendrecv")) out->moh_sendrecv = true; else if (!str_cmp(&mode, "reflect")) out->moh_reflect = true; break; default: ilog(LOG_WARN, "Unknown 'moh' flag encountered: '" STR_FORMAT "'", STR_FMT(key)); } return NULL; } static const char *call_ng_flags_replace(str *s, unsigned int idx, helper_arg arg) { sdp_ng_flags *out = arg.flags; switch (__csh_lookup(s)) { case CSH_LOOKUP("force-increment-sdp-ver"): case CSH_LOOKUP("force-increment-SDP-ver"): case CSH_LOOKUP("force increment sdp ver"): case CSH_LOOKUP("force increment SDP ver"): out->force_inc_sdp_ver = true; break; case CSH_LOOKUP("origin"): out->replace_origin = true; break; case CSH_LOOKUP("origin full"): case CSH_LOOKUP("origin-full"): case CSH_LOOKUP("origin_full"): out->replace_origin_full = true; break; case CSH_LOOKUP("sdp-version"): case CSH_LOOKUP("SDP-version"): case CSH_LOOKUP("sdp version"): case CSH_LOOKUP("SDP version"): out->replace_sdp_version = true; break; /* TODO: after a while remove silent support for this flag */ case CSH_LOOKUP("session-connection"): case CSH_LOOKUP("session connection"): ilog(LOG_INFO, "replace-session-connection flag encountered, but not supported anymore."); break; case CSH_LOOKUP("session-name"): case CSH_LOOKUP("session name"): out->replace_sess_name = true; break; case CSH_LOOKUP("username"): out->replace_username = true; break; case CSH_LOOKUP("zero-address"): case CSH_LOOKUP("zero address"): out->replace_zero_address = true; break; default: ilog(LOG_WARN, "Unknown 'replace' flag encountered: '" STR_FORMAT "'", STR_FMT(s)); } return NULL; } static const char *call_ng_flags_supports(str *s, unsigned int idx, helper_arg arg) { sdp_ng_flags *out = arg.flags; if (!str_cmp(s, "load limit")) out->supports_load_limit = true; else ilog(LOG_INFO | LOG_FLAG_LIMIT, "Optional feature '" STR_FORMAT "' not supported", STR_FMT(s)); return NULL; } static str *str_dup_escape(const str *s) { str *ret = str_dup(s); int i; while ((i = str_str(ret, "--")) >= 0) { ret->s[i] = '='; memmove(&ret->s[i + 1], &ret->s[i + 2], ret->len - i - 2); ret->len--; } while ((i = str_str(ret, "..")) >= 0) { ret->s[i] = ' '; memmove(&ret->s[i + 1], &ret->s[i + 2], ret->len - i - 2); ret->len--; } return ret; } static const char *call_ng_flags_esc_str_list(str *s, unsigned int idx, helper_arg arg) { str *s_copy = str_dup_escape(s); t_queue_push_tail(arg.q, s_copy); return NULL; } /** * Stores flag's value in the given GhashTable. */ static const char *call_ng_flags_str_ht(str *s, unsigned int idx, helper_arg arg) { str *s_copy = str_dup_escape(s); str_case_ht *ht = arg.sct; if (!t_hash_table_is_set(*ht)) *ht = str_case_ht_new(); t_hash_table_replace(*ht, s_copy, s_copy); return NULL; } /** * Parses one-row flags separated by 'delimiter'. * Stores parsed flag's values then in the given GQueue. */ static const char *call_ng_flags_str_q_multi(str *s, unsigned int idx, helper_arg arg) { str *s_copy = str_dup_escape(s); str token; str_q *q = arg.q; if (s_copy->len == 0) ilog(LOG_DEBUG, "Hm, nothing to parse."); while (str_token_sep(&token, s_copy, ';')) { str * ret = str_dup(&token); t_queue_push_tail(q, ret); } free(s_copy); return NULL; } #ifdef WITH_TRANSCODING static const char *call_ng_flags_str_ht_split(str *s, unsigned int idx, helper_arg arg) { str_case_value_ht *ht = arg.svt; if (!t_hash_table_is_set(*ht)) *ht = str_case_value_ht_new(); str splitter = *s; while (1) { t_hash_table_replace(*ht, str_dup_escape(&splitter), str_dup_escape(s)); char *c = memrchr(splitter.s, '/', splitter.len); if (!c) break; splitter.len = c - splitter.s; } return NULL; } #endif static struct sdp_manipulations *call_ng_flags_sdp_attr_helper(str *s, sdp_ng_flags *flags) { // get media type str token; if (!str_token(&token, s, '-')) return NULL; struct sdp_manipulations *sm = sdp_manipulations_get_by_name(flags->sdp_manipulations, &token); if (!sm) { ilog(LOG_WARN, "SDP manipulations: unsupported SDP section '" STR_FORMAT "' targeted.", STR_FMT(&token)); return NULL; } return sm; } static const char *call_ng_flags_sdp_attr_helper_add(str *s, unsigned int idx, helper_arg arg) { struct sdp_manipulations *sm = call_ng_flags_sdp_attr_helper(s, arg.flags); if (sm) call_ng_flags_esc_str_list(s, idx, &sm->add_commands); return NULL; } static const char *call_ng_flags_sdp_attr_helper_remove(str *s, unsigned int idx, helper_arg arg) { struct sdp_manipulations *sm = call_ng_flags_sdp_attr_helper(s, arg.flags); if (sm) call_ng_flags_str_ht(s, idx, &sm->rem_commands); return NULL; } static const char *call_ng_flags_sdp_attr_helper_subst(str *s, unsigned int idx, helper_arg arg) { struct sdp_manipulations *sm = call_ng_flags_sdp_attr_helper(s, arg.flags); if (sm) call_ng_flags_str_pair_ht(s, idx, &sm->subst_commands); return NULL; } // helper to alias values from other dictionaries into the "flags" dictionary INLINE int call_ng_flags_prefix(str *s_ori, const char *prefix, const char *(*cb)(str *, unsigned int, helper_arg), helper_arg arg) { size_t len = strlen(prefix); str s = *s_ori; if (len > 0) if (str_shift_cmp(&s, prefix)) return 0; cb(&s, 0, arg); return 1; } const char *call_ng_flags_flags(str *s, unsigned int idx, helper_arg arg) { sdp_ng_flags *out = arg.flags; switch (__csh_lookup(s)) { case CSH_LOOKUP("all"): out->all = ALL_ALL; break; case CSH_LOOKUP("allow-asymmetric-codecs"): case CSH_LOOKUP("allow-asymmetric-codec"): case CSH_LOOKUP("allow asymmetric codecs"): case CSH_LOOKUP("allow asymmetric codec"): out->allow_asymmetric_codecs = true; break; case CSH_LOOKUP("allow-no-codec-media"): case CSH_LOOKUP("allow-no-codec-medias"): case CSH_LOOKUP("allow-empty-codec-media"): case CSH_LOOKUP("allow-empty-codec-medias"): case CSH_LOOKUP("allow no codec media"): case CSH_LOOKUP("allow no codec medias"): case CSH_LOOKUP("allow empty codec media"): case CSH_LOOKUP("allow empty codec medias"): out->allow_no_codec_media = true; break; case CSH_LOOKUP("allow-transcoding"): case CSH_LOOKUP("allow transcoding"): out->allow_transcoding = true; break; case CSH_LOOKUP("force-transcoding"): case CSH_LOOKUP("force transcoding"): out->force_transcoding = true; break; case CSH_LOOKUP("always-transcode"): case CSH_LOOKUP("always transcode"):; static const str str_all = STR_CONST("all"); call_ng_flags_esc_str_list((str *) &str_all, 0, &out->codec_accept); break; case CSH_LOOKUP("asymmetric"): out->asymmetric = true; break; case CSH_LOOKUP("asymmetric-codecs"): case CSH_LOOKUP("asymmetric codecs"): ilog(LOG_INFO, "Ignoring obsolete flag `asymmetric-codecs`"); break; case CSH_LOOKUP("audio-player"): case CSH_LOOKUP("audio player"): case CSH_LOOKUP("player"): out->audio_player = AP_TRANSCODING; break; case CSH_LOOKUP("bidirectional"): out->bidirectional = true; break; case CSH_LOOKUP("block-dtmf"): case CSH_LOOKUP("block-DTMF"): case CSH_LOOKUP("block dtmf"): case CSH_LOOKUP("block DTMF"): out->block_dtmf = true; break; case CSH_LOOKUP("block-egress"): case CSH_LOOKUP("block egress"): out->block_egress = true; break; case CSH_LOOKUP("block-short"): case CSH_LOOKUP("block-shorts"): case CSH_LOOKUP("block-short-packets"): case CSH_LOOKUP("block short"): case CSH_LOOKUP("block shorts"): case CSH_LOOKUP("block short packets"): out->block_short = true; break; case CSH_LOOKUP("debug"): case CSH_LOOKUP("debugging"): out->debug = true; break; case CSH_LOOKUP("detect-DTMF"): case CSH_LOOKUP("detect-dtmf"): case CSH_LOOKUP("detect DTMF"): case CSH_LOOKUP("detect dtmf"): out->detect_dtmf = true; break; case CSH_LOOKUP("directional"): out->directional = true; break; case CSH_LOOKUP("discard-recording"): case CSH_LOOKUP("discard recording"): out->discard_recording = true; break; case CSH_LOOKUP("early-media"): case CSH_LOOKUP("early media"): out->early_media = true; break; case CSH_LOOKUP("egress"): out->egress = true; break; case CSH_LOOKUP("exclude-recording"): case CSH_LOOKUP("exclude recording"): out->exclude_recording = true; break; case CSH_LOOKUP("fatal"): out->fatal = true; break; case CSH_LOOKUP("fragment"): out->fragment = true; break; case CSH_LOOKUP("full-rtcp-attribute"): case CSH_LOOKUP("full-RTCP-attribute"): case CSH_LOOKUP("full rtcp attribute"): case CSH_LOOKUP("full RTCP attribute"): out->full_rtcp_attr = true; break; case CSH_LOOKUP("generate-mid"): case CSH_LOOKUP("generate mid"): out->generate_mid = true; break; case CSH_LOOKUP("generate-RTCP"): case CSH_LOOKUP("generate-rtcp"): case CSH_LOOKUP("generate RTCP"): case CSH_LOOKUP("generate rtcp"): out->generate_rtcp = true; break; case CSH_LOOKUP("ICE-reject"): case CSH_LOOKUP("ice-reject"): case CSH_LOOKUP("reject-ice"): case CSH_LOOKUP("reject-ICE"): case CSH_LOOKUP("ICE reject"): case CSH_LOOKUP("ice reject"): case CSH_LOOKUP("reject ice"): case CSH_LOOKUP("reject ICE"): out->ice_reject = true; break; case CSH_LOOKUP("inactive"): out->inactive = true; break; case CSH_LOOKUP("inject-DTMF"): case CSH_LOOKUP("inject-dtmf"): case CSH_LOOKUP("inject DTMF"): case CSH_LOOKUP("inject dtmf"): out->inject_dtmf = true; break; case CSH_LOOKUP("loop-protect"): case CSH_LOOKUP("loop protect"): out->loop_protect = true; break; case CSH_LOOKUP("media-handover"): case CSH_LOOKUP("media handover"): out->media_handover = true; break; case CSH_LOOKUP("mirror-RTCP"): case CSH_LOOKUP("mirror-rtcp"): case CSH_LOOKUP("RTCP-mirror"): case CSH_LOOKUP("rtcp-mirror"): case CSH_LOOKUP("mirror RTCP"): case CSH_LOOKUP("mirror rtcp"): case CSH_LOOKUP("RTCP mirror"): case CSH_LOOKUP("rtcp mirror"): out->rtcp_mirror = true; break; case CSH_LOOKUP("mix"): case CSH_LOOKUP("mixed"): out->mix = true; break; case CSH_LOOKUP("NAT-wait"): case CSH_LOOKUP("nat-wait"): case CSH_LOOKUP("NAT wait"): case CSH_LOOKUP("nat wait"): out->nat_wait = true; break; case CSH_LOOKUP("new-branch"): case CSH_LOOKUP("new branch"): out->new_branch = true; break; case CSH_LOOKUP("no-codec-renegotiation"): case CSH_LOOKUP("reuse-codecs"): case CSH_LOOKUP("no codec renegotiation"): case CSH_LOOKUP("reuse codecs"): out->reuse_codec = true; break; case CSH_LOOKUP("no-passthrough"): case CSH_LOOKUP("no passthrough"): out->passthrough_off = true; break; case CSH_LOOKUP("no-player"): case CSH_LOOKUP("no-audio-player"): case CSH_LOOKUP("no player"): case CSH_LOOKUP("no audio player"): out->audio_player = AP_OFF; break; case CSH_LOOKUP("no-port-latching"): case CSH_LOOKUP("no port latching"): out->no_port_latching = true; break; case CSH_LOOKUP("no-redis-update"): case CSH_LOOKUP("no redis update"): out->no_redis_update = true; break; case CSH_LOOKUP("no-rtcp-attribute"): case CSH_LOOKUP("no-RTCP-attribute"): case CSH_LOOKUP("no rtcp attribute"): case CSH_LOOKUP("no RTCP attribute"): out->no_rtcp_attr = true; break; case CSH_LOOKUP("no-tls-id"): case CSH_LOOKUP("no tls id"): out->no_tls_id = true; break; case CSH_LOOKUP("no-jitter-buffer"): case CSH_LOOKUP("no jitter buffer"): out->disable_jb = true; break; case CSH_LOOKUP("original-sendrecv"): case CSH_LOOKUP("original sendrecv"): out->original_sendrecv = true; break; case CSH_LOOKUP("pad-crypto"): case CSH_LOOKUP("pad crypto"): out->sdes_pad = true; break; case CSH_LOOKUP("passthrough"): out->passthrough_on = true; break; case CSH_LOOKUP("pierce-NAT"): case CSH_LOOKUP("pierce-nat"): case CSH_LOOKUP("pierce NAT"): case CSH_LOOKUP("pierce nat"): out->pierce_nat = true; break; case CSH_LOOKUP("port-latching"): case CSH_LOOKUP("port latching"): out->port_latching = true; break; case CSH_LOOKUP("provisional"): out->provisional = true; break; case CSH_LOOKUP("record-call"): case CSH_LOOKUP("record call"): out->record_call = true; break; case CSH_LOOKUP("recording-vsc"): case CSH_LOOKUP("recording-VSC"): case CSH_LOOKUP("recording vsc"): case CSH_LOOKUP("recording VSC"): out->recording_vsc = true; break; case CSH_LOOKUP("recording-announcement"): case CSH_LOOKUP("recording announcement"): out->recording_announcement = true; break; case CSH_LOOKUP("recrypt"): out->recrypt = true; break; case CSH_LOOKUP("reorder-codecs"): case CSH_LOOKUP("reorder codecs"): ilog(LOG_INFO, "Ignoring obsolete flag `reorder-codecs`"); break; case CSH_LOOKUP("reset"): out->reset = true; break; case CSH_LOOKUP("single-codec"): case CSH_LOOKUP("single codec"): out->single_codec = true; break; case CSH_LOOKUP("SIP-source-address"): case CSH_LOOKUP("sip-source-address"): case CSH_LOOKUP("SIP source address"): case CSH_LOOKUP("sip source address"): out->trust_address = 0; break; case CSH_LOOKUP("SIPREC"): case CSH_LOOKUP("siprec"): out->siprec = true; break; case CSH_LOOKUP("skip-recording-db"): case CSH_LOOKUP("skip-recording-database"): case CSH_LOOKUP("skip recording db"): case CSH_LOOKUP("skip recording database"): out->skip_recording_db = true; break; case CSH_LOOKUP("static-codec"): case CSH_LOOKUP("static-codecs"): case CSH_LOOKUP("static codec"): case CSH_LOOKUP("static codecs"): out->static_codecs = true; break; case CSH_LOOKUP("strict-source"): case CSH_LOOKUP("strict source"): out->strict_source = true; break; case CSH_LOOKUP("strip-extmap"): case CSH_LOOKUP("strip extmap"): return call_ng_flags_str_ht(STR_PTR("all"), 0, &out->rtpext_strip); case CSH_LOOKUP("symmetric-codecs"): case CSH_LOOKUP("symmetric codecs"): ilog(LOG_INFO, "Ignoring obsolete flag `symmetric-codecs`"); break; case CSH_LOOKUP("to tag"): case CSH_LOOKUP("to-tag"): case CSH_LOOKUP("to_tag"): /* including the “To” tag in the “delete” message allows to be more selective * about monologues within a dialog to be torn down. */ out->to_tag_flag = true; break; case CSH_LOOKUP("trickle-ICE"): case CSH_LOOKUP("trickle-ice"): case CSH_LOOKUP("trickle ICE"): case CSH_LOOKUP("trickle ice"): out->trickle_ice = true; break; case CSH_LOOKUP("trust-address"): case CSH_LOOKUP("trust address"): out->trust_address = true; break; case CSH_LOOKUP("unidirectional"): out->unidirectional = true; break; case CSH_LOOKUP("unsubscribe"): out->unsubscribe = true; break; case CSH_LOOKUP("webrtc"): case CSH_LOOKUP("webRTC"): case CSH_LOOKUP("WebRTC"): case CSH_LOOKUP("WebRtc"): ng_flags_webrtc(out); break; default: /* handle values aliases from other dictionaries */ if (call_ng_flags_prefix(s, "endpoint-learning-", ng_el_option, out)) return NULL; if (call_ng_flags_prefix(s, "from-tags-", call_ng_flags_esc_str_list, &out->from_tags)) return NULL; /* OSRTP */ if (call_ng_flags_prefix(s, "OSRTP-", ng_osrtp_option, out)) return NULL; /* replacing SDP body parts */ if (call_ng_flags_prefix(s, "replace-", call_ng_flags_replace, out)) return NULL; /* rtcp-mux */ if (call_ng_flags_prefix(s, "rtcp-mux-", call_ng_flags_rtcp_mux, out)) return NULL; /* group:BUNDLE */ if (call_ng_flags_prefix(s, "BUNDLE-", call_ng_flags_bundle, out)) return NULL; /* codec manipulations */ { if (call_ng_flags_prefix(s, "codec-except-", call_ng_flags_str_ht, &out->codec_except)) return NULL; if (call_ng_flags_prefix(s, "codec-offer-", call_ng_flags_esc_str_list, &out->codec_offer)) return NULL; if (call_ng_flags_prefix(s, "codec-strip-", call_ng_flags_esc_str_list, &out->codec_strip)) return NULL; if (call_ng_flags_prefix(s, "codec-ignore-", call_ng_flags_esc_str_list, &out->codec_ignore)) return NULL; } /* SDES */ { if (call_ng_flags_prefix(s, "SDES-", ng_sdes_option, out)) return NULL; if (call_ng_flags_prefix(s, "SDES-offerer_pref:", call_ng_flags_str_q_multi, &out->sdes_offerer_pref)) return NULL; if (call_ng_flags_prefix(s, "SDES-no-", call_ng_flags_str_ht, &out->sdes_no)) return NULL; if (call_ng_flags_prefix(s, "SDES-only-", call_ng_flags_str_ht, &out->sdes_only)) return NULL; if (call_ng_flags_prefix(s, "SDES-order:", call_ng_flags_str_q_multi, &out->sdes_order)) return NULL; } /* SDP attributes manipulations */ { if (call_ng_flags_prefix(s, "sdp-attr-add-", call_ng_flags_sdp_attr_helper_add, out)) return NULL; if (call_ng_flags_prefix(s, "sdp-attr-remove-", call_ng_flags_sdp_attr_helper_remove, out)) return NULL; if (call_ng_flags_prefix(s, "sdp-attr-substitute-", call_ng_flags_sdp_attr_helper_subst, out)) return NULL; } #ifdef WITH_TRANSCODING /* transcoding */ { if (out->opmode == OP_OFFER || out->opmode == OP_SUBSCRIBE_REQ || out->opmode == OP_PUBLISH) { if (call_ng_flags_prefix(s, "transcode-", call_ng_flags_esc_str_list, &out->codec_transcode)) return NULL; if (call_ng_flags_prefix(s, "codec-transcode-", call_ng_flags_esc_str_list, &out->codec_transcode)) return NULL; if (call_ng_flags_prefix(s, "codec-mask-", call_ng_flags_esc_str_list, &out->codec_mask)) return NULL; if (call_ng_flags_prefix(s, "T38-", ng_t38_option, out)) return NULL; if (call_ng_flags_prefix(s, "T.38-", ng_t38_option, out)) return NULL; } if (call_ng_flags_prefix(s, "codec-accept-", call_ng_flags_esc_str_list, &out->codec_accept)) return NULL; if (call_ng_flags_prefix(s, "codec-consume-", call_ng_flags_esc_str_list, &out->codec_consume)) return NULL; if (call_ng_flags_prefix(s, "codec-set-", call_ng_flags_str_ht_split, &out->codec_set)) return NULL; } #endif ilog(LOG_WARN, "Unknown flag encountered: '" STR_FORMAT "'", STR_FMT(s)); } return NULL; } void call_ng_flags_init(sdp_ng_flags *out, enum ng_opmode opmode) { ZERO(*out); out->opmode = opmode; out->trust_address = trust_address_def; out->dtls_passive = dtls_passive_def; out->dtls_reverse_passive = dtls_passive_def; out->el_option = rtpe_config.endpoint_learning; out->tos = 256; out->delay_buffer = -1; out->delete_delay = -1; out->volume = 9999; out->digit = -1; out->repeat_duration = -1; out->frequencies = g_array_new(false, false, sizeof(int)); for (int i = 0; i < __MT_MAX; ++i) out->sdp_media_remove[i] = false; out->t38_version = -1; } static const char *call_ng_direction_flag_iter(str *s, unsigned int i, helper_arg arg) { if (i < 2) arg.flags->direction[i] = *s; return NULL; } static const char *call_ng_direction_flag(const ng_parser_t *parser, sdp_ng_flags *flags, parser_arg value) { if (!parser->is_list(value)) return NULL; return parser->list_iter(parser, value, call_ng_direction_flag_iter, NULL, flags); } const char *call_ng_codec_flags(const ng_parser_t *parser, str *key, parser_arg value, helper_arg arg) { sdp_ng_flags *out = arg.flags; switch (__csh_lookup(key)) { case CSH_LOOKUP("except"): return call_ng_flags_str_list(parser, value, call_ng_flags_str_ht, &out->codec_except); case CSH_LOOKUP("offer"): return call_ng_flags_str_list(parser, value, call_ng_flags_esc_str_list, &out->codec_offer); case CSH_LOOKUP("strip"): return call_ng_flags_str_list(parser, value, call_ng_flags_esc_str_list, &out->codec_strip); case CSH_LOOKUP("ignore"): return call_ng_flags_str_list(parser, value, call_ng_flags_esc_str_list, &out->codec_ignore); } #ifdef WITH_TRANSCODING if (out->opmode == OP_OFFER || out->opmode == OP_SUBSCRIBE_REQ || out->opmode == OP_PUBLISH || out->opmode == OP_PLAY_MEDIA) { switch (__csh_lookup(key)) { case CSH_LOOKUP("accept"): return call_ng_flags_str_list(parser, value, call_ng_flags_esc_str_list, &out->codec_accept); case CSH_LOOKUP("consume"): return call_ng_flags_str_list(parser, value, call_ng_flags_esc_str_list, &out->codec_consume); case CSH_LOOKUP("mask"): return call_ng_flags_str_list(parser, value, call_ng_flags_esc_str_list, &out->codec_mask); case CSH_LOOKUP("set"): return call_ng_flags_str_list(parser, value, call_ng_flags_str_ht_split, &out->codec_set); case CSH_LOOKUP("transcode"): return call_ng_flags_str_list(parser, value, call_ng_flags_esc_str_list, &out->codec_transcode); } } else { // silence warnings switch (__csh_lookup(key)) { case CSH_LOOKUP("accept"): case CSH_LOOKUP("consume"): case CSH_LOOKUP("mask"): case CSH_LOOKUP("set"): case CSH_LOOKUP("transcode"): return NULL; } } #endif ilog(LOG_WARN, "Unknown 'codec' operation encountered: '" STR_FORMAT "'", STR_FMT(key)); return NULL; } static const char *call_ng_extmap_flags(const ng_parser_t *parser, str *key, parser_arg value, helper_arg arg) { sdp_ng_flags *out = arg.flags; switch (__csh_lookup(key)) { case CSH_LOOKUP("strip"): return call_ng_flags_str_list(parser, value, call_ng_flags_str_ht, &out->rtpext_strip); case CSH_LOOKUP("mask"): return call_ng_flags_str_list(parser, value, call_ng_flags_str_ht, &out->rtpext_mask); } return NULL; } #ifdef WITH_TRANSCODING static void call_ng_parse_block_mode(str *s, enum block_dtmf_mode *output) { switch (__csh_lookup(s)) { case CSH_LOOKUP("drop"): *output = BLOCK_DTMF_DROP; break; case CSH_LOOKUP("DTMF"): case CSH_LOOKUP("dtmf"): *output = BLOCK_DTMF_DTMF; break; case CSH_LOOKUP("off"): *output = BLOCK_DTMF_OFF; break; case CSH_LOOKUP("random"): *output = BLOCK_DTMF_RANDOM; break; case CSH_LOOKUP("silence"): *output = BLOCK_DTMF_SILENCE; break; case CSH_LOOKUP("tone"): *output = BLOCK_DTMF_TONE; break; case CSH_LOOKUP("zero"): *output = BLOCK_DTMF_ZERO; break; default: ilog(LOG_WARN, "Unknown DTMF block mode encountered: '" STR_FORMAT "'", STR_FMT(s)); } } #endif static void call_ng_flags_freqs(const ng_parser_t *parser, parser_arg value, sdp_ng_flags *out); static const char *call_ng_flags_freqs_iter(const ng_parser_t *parser, parser_arg item, helper_arg arg) { call_ng_flags_freqs(parser, item, arg.flags); return NULL; } static void call_ng_flags_freqs(const ng_parser_t *parser, parser_arg value, sdp_ng_flags *out) { unsigned int val; if (parser->is_int(value)) { val = parser->get_int(value); g_array_append_val(out->frequencies, val); } else if (parser->is_list(value)) parser->list_iter(parser, value, NULL, call_ng_flags_freqs_iter, out); else { val = parser->get_int_str(value, 0); if (val) g_array_append_val(out->frequencies, val); else ilog(LOG_WARN, "Invalid content type in `frequencies` list"); } } static void call_ng_flags_peer_address(const str *peer_ip, str *direction, const char *direction_text) { const str *resolved = resolve_interface_from_peer_ip(peer_ip); if (resolved) { *direction = *resolved; ilog(LOG_DEBUG, "%s peer " STR_FORMAT " resolved to interface " STR_FORMAT, direction_text, STR_FMT(peer_ip), STR_FMT(resolved)); } else ilog(LOG_WARN, "Failed to resolve %s peer address " STR_FORMAT, direction_text, STR_FMT(peer_ip)); } static void call_ng_received_from_string(sdp_ng_flags *flags, str *s) { flags->received_from_family = STR_NULL; flags->received_from_address = *s; } static const char *call_ng_received_from_iter(str *key, unsigned int i, helper_arg arg) { switch (i) { case 0: arg.flags->received_from_family = *key; break; case 1: arg.flags->received_from_address = *key; break; } return NULL; } static const char *call_ng_payload_type(const ng_parser_t *parser, str *key, parser_arg value, struct rtp_payload_type *pt) { str s = STR_NULL; parser->get_str(value, &s); switch (__csh_lookup(key)) { case CSH_LOOKUP("codec"): pt->encoding = s; break; case CSH_LOOKUP("payload type"): pt->payload_type = parser->get_int_str(value, -1); break; case CSH_LOOKUP("clock rate"): pt->clock_rate = parser->get_int_str(value, 0); break; case CSH_LOOKUP("channels"): pt->channels = parser->get_int_str(value, 0); break; case CSH_LOOKUP("format"): pt->format_parameters = s; break; case CSH_LOOKUP("options"): pt->codec_opts = s; break; default: ilog(LOG_WARN, "Unknown payload type key '" STR_FORMAT "'", STR_FMT(key)); } return NULL; } static const char *call_ng_codec(const ng_parser_t *parser, str *key, parser_arg value, struct ng_codec *codec) { switch (__csh_lookup(key)) { case CSH_LOOKUP("input"): return parser->dict_iter(parser, value, call_ng_payload_type, &codec->input); case CSH_LOOKUP("output"): return parser->dict_iter(parser, value, call_ng_payload_type, &codec->output); default: ilog(LOG_WARN, "Unknown codec key '" STR_FORMAT "'", STR_FMT(key)); } return NULL; } static const char *call_ng_codec_iter(const ng_parser_t *parser, parser_arg item, struct ng_media *media) { // we support two types here: // the "transform" method supplies an extended list of codecs, as a list of dicts // the "create" method uses a list of strings, similar to codec->offer if (!parser->is_dict(item)) { str s; parser->get_str(item, &s); call_ng_flags_esc_str_list(&s, 0, &media->codec_list); return NULL; } __auto_type codec = g_new0(struct ng_codec, 1); t_queue_push_tail(&media->codecs, codec); codec->input.payload_type = -1; codec->output.payload_type = -1; parser->dict_iter(parser, item, call_ng_codec, codec); if (codec->input.payload_type == -1 || codec->output.payload_type == -1) ilog(LOG_WARN, "Incomplete codec definition"); return NULL; } static const char *call_ng_endpoint(const ng_parser_t *parser, str *key, parser_arg value, struct ng_media *media) { str s = STR_NULL; parser->get_str(value, &s); switch (__csh_lookup(key)) { case CSH_LOOKUP("address"): media->destination_address = s; break; case CSH_LOOKUP("family"): case CSH_LOOKUP("address-family"): case CSH_LOOKUP("address family"): media->destination.address.family = get_socket_family_rfc(&s); break; case CSH_LOOKUP("port"): media->destination.port = parser->get_int_str(value, 0); break; default: ilog(LOG_WARN, "Unknown endpoint key '" STR_FORMAT "'", STR_FMT(key)); } return NULL; } static const char *call_ng_media(const ng_parser_t *parser, str *key, parser_arg value, struct ng_media *media) { str s = STR_NULL; parser->get_str(value, &s); switch (__csh_lookup(key)) { case CSH_LOOKUP("codec"): case CSH_LOOKUP("codecs"): return parser->list_iter(parser, value, NULL, call_ng_codec_iter, media); case CSH_LOOKUP("destination"):; const char *err = parser->dict_iter(parser, value, call_ng_endpoint, media); if (err) return err; if (!media->destination.address.family) return "Destination address without family specified"; if (!sockaddr_parse_str(&media->destination.address, media->destination.address.family, &media->destination_address)) return "Failed to parse destination address"; // XXX add address to string break; case CSH_LOOKUP("id"): media->id = s; break; case CSH_LOOKUP("type"): media->type = s; break; default: ilog(LOG_WARN, "Unknown media key '" STR_FORMAT "'", STR_FMT(key)); } return NULL; } static const char *call_ng_media_iter(const ng_parser_t *parser, parser_arg item, sdp_ng_flags *out) { __auto_type media = g_new0(struct ng_media, 1); t_queue_push_tail(&out->medias, media); return parser->dict_iter(parser, item, call_ng_media, media); } static const char *call_ng_tag(const ng_parser_t *parser, str *key, parser_arg value, struct ng_tag *tag) { str s = STR_NULL; parser->get_str(value, &s); switch (__csh_lookup(key)) { case CSH_LOOKUP("from"): tag->from = s; break; case CSH_LOOKUP("to"): return call_ng_flags_str_list(parser, value, call_ng_flags_esc_str_list, &tag->to); } return NULL; } static const char *call_ng_tags_iter(const ng_parser_t *parser, parser_arg item, sdp_ng_flags *out) { __auto_type tag = g_new0(struct ng_tag, 1); t_queue_push_tail(&out->tags, tag); const char *err = parser->dict_iter(parser, item, call_ng_tag, tag); if (err) return err; if (!tag->from.len) return "Empty/missing from-tag"; return NULL; } const char *call_ng_main_flags(const ng_parser_t *parser, str *key, parser_arg value, helper_arg arg) { str s = STR_NULL; sdp_ng_flags *out = arg.flags; parser->get_str(value, &s); switch (__csh_lookup(key)) { case CSH_LOOKUP("address"): out->address = s; break; case CSH_LOOKUP("address family"): case CSH_LOOKUP("address-family"): if (s.s) { out->address_family_str = s; out->address_family = get_socket_family_rfc(&out->address_family_str); } break; case CSH_LOOKUP("all"): switch (__csh_lookup_n(1, &s)) { case CSH_LOOKUP_N(1, "all"): out->all = ALL_ALL; break; case CSH_LOOKUP_N(1, "none"): out->all = ALL_NONE; break; case CSH_LOOKUP_N(1, "offer-answer"): out->all = ALL_OFFER_ANSWER; break; case CSH_LOOKUP_N(1, "not-offer-answer"): case CSH_LOOKUP_N(1, "non-offer-answer"): case CSH_LOOKUP_N(1, "except-offer-answer"): out->all = ALL_NON_OFFER_ANSWER; break; case CSH_LOOKUP_N(1, "flows"): out->all = ALL_FLOWS; break; default: ilog(LOG_WARN, "Unknown 'all' flag encountered: '" STR_FORMAT "'", STR_FMT(&s)); } break; case CSH_LOOKUP("alias-key"): switch (__csh_lookup_n(1, &s)) { case CSH_LOOKUP_N(1, "none"): case CSH_LOOKUP_N(1, "off"): case CSH_LOOKUP_N(1, "no"): out->alias_key = AK_NONE; break; case CSH_LOOKUP_N(1, "sdp"): case CSH_LOOKUP_N(1, "SDP"): out->alias_key = AK_SDP; break; case CSH_LOOKUP_N(1, "address"): case CSH_LOOKUP_N(1, "endpoint"): out->alias_key = AK_ADDRESS; break; default: ilog(LOG_WARN, "Unknown 'alias-key' flag encountered: '" STR_FORMAT "'", STR_FMT(&s)); } break; case CSH_LOOKUP("audio-player"): case CSH_LOOKUP("audio player"): case CSH_LOOKUP("player"): switch (__csh_lookup_n(1, &s)) { case CSH_LOOKUP_N(1, "default"): out->audio_player = AP_DEFAULT; break; case CSH_LOOKUP_N(1, "on"): case CSH_LOOKUP_N(1, "yes"): case CSH_LOOKUP_N(1, "enable"): case CSH_LOOKUP_N(1, "enabled"): case CSH_LOOKUP_N(1, "transcode"): case CSH_LOOKUP_N(1, "transcoding"): out->audio_player = AP_TRANSCODING; break; case CSH_LOOKUP_N(1, "no"): case CSH_LOOKUP_N(1, "off"): case CSH_LOOKUP_N(1, "disable"): case CSH_LOOKUP_N(1, "disabled"): out->audio_player = AP_OFF; break; case CSH_LOOKUP_N(1, "force"): case CSH_LOOKUP_N(1, "forced"): case CSH_LOOKUP_N(1, "always"): case CSH_LOOKUP_N(1, "everything"): out->audio_player = AP_FORCE; break; default: ilog(LOG_WARN, "Unknown 'audio-player' flag encountered: '" STR_FORMAT "'", STR_FMT(&s)); } break; case CSH_LOOKUP("blob"): out->blob = s; break; case CSH_LOOKUP("bundle"): case CSH_LOOKUP("BUNDLE"): return call_ng_flags_str_list(parser, value, call_ng_flags_bundle, out); case CSH_LOOKUP("call-id"): case CSH_LOOKUP("call-ID"): case CSH_LOOKUP("call id"): case CSH_LOOKUP("call ID"): out->call_id = s; break; case CSH_LOOKUP("calls"): call_ng_flags_str_list(parser, value, call_ng_flags_esc_str_list, &out->calls); break; case CSH_LOOKUP("code"): case CSH_LOOKUP("digit"): out->digit = parser->get_int_str(value, out->digit); if (s.len == 1) out->digit = s.s[0]; break; case CSH_LOOKUP("codec"): return parser->dict_iter(parser, value, call_ng_codec_flags, out); case CSH_LOOKUP("command"): break; case CSH_LOOKUP("db-id"): out->db_id = parser->get_int_str(value, out->db_id); break; case CSH_LOOKUP("delete delay"): case CSH_LOOKUP("delete-delay"): case CSH_LOOKUP("delete_delay"): out->delete_delay = parser->get_int_str(value, out->delete_delay); break; case CSH_LOOKUP("direction"): return call_ng_direction_flag(parser, out, value); case CSH_LOOKUP("drop-traffic"): case CSH_LOOKUP("drop traffic"): switch (__csh_lookup_n(1, &s)) { case CSH_LOOKUP_N(1, "start"): out->drop_traffic_start = true; break; case CSH_LOOKUP_N(1, "stop"): out->drop_traffic_stop = true; break; default: ilog(LOG_WARN, "Unknown 'drop-traffic' flag encountered: '" STR_FORMAT "'", STR_FMT(&s)); } break; case CSH_LOOKUP("DTLS"): case CSH_LOOKUP("dtls"): switch (__csh_lookup_n(1, &s)) { case CSH_LOOKUP_N(1, "passive"): out->dtls_passive = true; break; case CSH_LOOKUP_N(1, "active"): out->dtls_passive = 0; break; case CSH_LOOKUP_N(1, "no"): case CSH_LOOKUP_N(1, "off"): case CSH_LOOKUP_N(1, "disabled"): case CSH_LOOKUP_N(1, "disable"): out->dtls_off = true; break; default: ilog(LOG_WARN, "Unknown 'DTLS' flag encountered: '" STR_FORMAT "'", STR_FMT(&s)); } break; case CSH_LOOKUP("DTLS fingerprint"): case CSH_LOOKUP("DTLS-fingerprint"): case CSH_LOOKUP("dtls fingerprint"): case CSH_LOOKUP("dtls-fingerprint"): out->dtls_fingerprint = s; break; case CSH_LOOKUP("DTLS-reverse"): case CSH_LOOKUP("dtls-reverse"): case CSH_LOOKUP("DTLS reverse"): case CSH_LOOKUP("dtls reverse"): switch (__csh_lookup_n(1, &s)) { case CSH_LOOKUP_N(1, "passive"): out->dtls_reverse_passive = true; break; case CSH_LOOKUP_N(1, "active"): out->dtls_reverse_passive = 0; break; default: ilog(LOG_WARN, "Unknown 'DTLS-reverse' flag encountered: '" STR_FORMAT "'", STR_FMT(&s)); } break; case CSH_LOOKUP("DTMF-delay"): case CSH_LOOKUP("DTMF delay"): case CSH_LOOKUP("dtmf-delay"): case CSH_LOOKUP("dtmf delay"): out->dtmf_delay = parser->get_int_str(value, out->dtmf_delay); break; case CSH_LOOKUP("dtmf-log-dest"): case CSH_LOOKUP("DTMF-log-dest"): case CSH_LOOKUP("dtmf-log-destination"): case CSH_LOOKUP("DTMF-log-destination"): if (!endpoint_parse_any_str(&out->dtmf_log_dest, &s)) ilog(LOG_WARN, "Failed to parse 'dtmf-log-dest' address '" STR_FORMAT "'", STR_FMT(&s)); break; case CSH_LOOKUP("duration"): out->duration = parser->get_int_str(value, out->duration); break; #ifdef WITH_TRANSCODING case CSH_LOOKUP("DTMF-security"): case CSH_LOOKUP("dtmf-security"): case CSH_LOOKUP("DTMF security"): case CSH_LOOKUP("dtmf security"): call_ng_parse_block_mode(&s, &out->block_dtmf_mode); break; case CSH_LOOKUP("DTMF-security-trigger"): case CSH_LOOKUP("dtmf-security-trigger"): case CSH_LOOKUP("DTMF security trigger"): case CSH_LOOKUP("dtmf security trigger"): call_ng_parse_block_mode(&s, &out->block_dtmf_mode_trigger); break; case CSH_LOOKUP("DTMF-security-trigger-end"): case CSH_LOOKUP("dtmf-security-trigger-end"): case CSH_LOOKUP("DTMF security trigger end"): case CSH_LOOKUP("dtmf security trigger end"): call_ng_parse_block_mode(&s, &out->block_dtmf_mode_trigger_end); break; case CSH_LOOKUP("delay-buffer"): case CSH_LOOKUP("delay buffer"): out->delay_buffer = parser->get_int_str(value, out->delay_buffer); break; #endif case CSH_LOOKUP("endpoint-learning"): case CSH_LOOKUP("endpoint learning"): return call_ng_flags_str_list(parser, value, ng_el_option, out); case CSH_LOOKUP("extmap"): return parser->dict_iter(parser, value, call_ng_extmap_flags, out); case CSH_LOOKUP("file"): out->file = s; break; case CSH_LOOKUP("frequency"): case CSH_LOOKUP("frequencies"): call_ng_flags_freqs(parser, value, out); break; case CSH_LOOKUP("from-interface"): case CSH_LOOKUP("from interface"): out->direction[0] = s; break; case CSH_LOOKUP("from-label"): case CSH_LOOKUP("from label"): case CSH_LOOKUP("label"): out->label = s; break; case CSH_LOOKUP("from-tag"): case CSH_LOOKUP("from tag"): out->from_tag = s; break; case CSH_LOOKUP("from-tags"): case CSH_LOOKUP("from tags"): return call_ng_flags_str_list(parser, value, call_ng_flags_esc_str_list, &out->from_tags); case CSH_LOOKUP("flags"): return call_ng_flags_str_list(parser, value, call_ng_flags_flags, out); case CSH_LOOKUP("generate RTCP"): case CSH_LOOKUP("generate-RTCP"): case CSH_LOOKUP("generate rtcp"): case CSH_LOOKUP("generate-rtcp"): if (!str_cmp(&s, "on")) out->generate_rtcp = true; else if (!str_cmp(&s, "off")) out->generate_rtcp_off = true; break; case CSH_LOOKUP("ICE"): case CSH_LOOKUP("ice"): switch (__csh_lookup_n(1, &s)) { case CSH_LOOKUP_N(1, "remove"): out->ice_option = ICE_REMOVE; break; case CSH_LOOKUP_N(1, "force"): out->ice_option = ICE_FORCE; break; case CSH_LOOKUP_N(1, "default"): out->ice_option = ICE_DEFAULT; break; case CSH_LOOKUP_N(1, "optional"): out->ice_option = ICE_OPTIONAL; break; case CSH_LOOKUP_N(1, "force_relay"): case CSH_LOOKUP_N(1, "force-relay"): case CSH_LOOKUP_N(1, "force relay"): out->ice_option = ICE_FORCE_RELAY; break; default: ilog(LOG_WARN, "Unknown 'ICE' flag encountered: '" STR_FORMAT "'", STR_FMT(&s)); } break; case CSH_LOOKUP("ICE-lite"): case CSH_LOOKUP("ice-lite"): case CSH_LOOKUP("ICE lite"): case CSH_LOOKUP("ice lite"): switch (__csh_lookup_n(1, &s)) { case CSH_LOOKUP_N(1, "off"): case CSH_LOOKUP_N(1, "none"): case CSH_LOOKUP_N(1, "no"): out->ice_lite_option = ICE_LITE_OFF; break; case CSH_LOOKUP_N(1, "forward"): case CSH_LOOKUP_N(1, "offer"): case CSH_LOOKUP_N(1, "fwd"): case CSH_LOOKUP_N(1, "fw"): out->ice_lite_option = ICE_LITE_FWD; break; case CSH_LOOKUP_N(1, "backward"): case CSH_LOOKUP_N(1, "backwards"): case CSH_LOOKUP_N(1, "reverse"): case CSH_LOOKUP_N(1, "answer"): case CSH_LOOKUP_N(1, "back"): case CSH_LOOKUP_N(1, "bkw"): case CSH_LOOKUP_N(1, "bk"): out->ice_lite_option = ICE_LITE_BKW; break; case CSH_LOOKUP_N(1, "both"): out->ice_lite_option = ICE_LITE_BOTH; break; default: ilog(LOG_WARN, "Unknown 'ICE-lite' flag encountered: '" STR_FORMAT "'", STR_FMT(&s)); } break; case CSH_LOOKUP("inbound-peer"): case CSH_LOOKUP("inbound peer"): call_ng_flags_peer_address(&s, &out->direction[0], "Inbound"); break; case CSH_LOOKUP("interface"): out->interface = s; break; case CSH_LOOKUP("peer"): call_ng_flags_peer_address(&s, &out->interface, "Interface"); break; case CSH_LOOKUP("instance"): out->instance = s; break; case CSH_LOOKUP("media address"): case CSH_LOOKUP("media-address"): if (!sockaddr_parse_any_str(&out->media_address, &s)) ilog(LOG_WARN, "Could not parse 'media-address'"); break; case CSH_LOOKUP("media"): case CSH_LOOKUP("medias"): parser->list_iter(parser, value, NULL, call_ng_media_iter, out); break; case CSH_LOOKUP("media echo"): case CSH_LOOKUP("media-echo"): switch (__csh_lookup_n(1, &s)) { case CSH_LOOKUP_N(1, "blackhole"): case CSH_LOOKUP_N(1, "sinkhole"): out->media_echo = MEO_BLACKHOLE; break; case CSH_LOOKUP_N(1, "forward"): case CSH_LOOKUP_N(1, "fwd"): case CSH_LOOKUP_N(1, "fw"): out->media_echo = MEO_FWD; break; case CSH_LOOKUP_N(1, "backward"): case CSH_LOOKUP_N(1, "backwards"): case CSH_LOOKUP_N(1, "reverse"): case CSH_LOOKUP_N(1, "back"): case CSH_LOOKUP_N(1, "bkw"): case CSH_LOOKUP_N(1, "bk"): out->media_echo = MEO_BKW; break; case CSH_LOOKUP_N(1, "both"): out->media_echo = MEO_BOTH; break; default: ilog(LOG_WARN, "Unknown 'media-echo' flag encountered: '" STR_FORMAT "'", STR_FMT(&s)); } break; case CSH_LOOKUP("metadata"): out->metadata = s; break; case CSH_LOOKUP("moh"): case CSH_LOOKUP("MoH"): case CSH_LOOKUP("MOH"): return parser->dict_iter(parser, value, call_ng_flags_moh, out); case CSH_LOOKUP("OSRTP"): case CSH_LOOKUP("osrtp"): return call_ng_flags_str_list(parser, value, ng_osrtp_option, out); case CSH_LOOKUP("outbound-peer"): case CSH_LOOKUP("outbound peer"): call_ng_flags_peer_address(&s, &out->direction[1], "Outbound"); break; case CSH_LOOKUP("output-destination"): case CSH_LOOKUP("output-dest"): case CSH_LOOKUP("output-file"): case CSH_LOOKUP("recording-destination"): case CSH_LOOKUP("recording-dest"): case CSH_LOOKUP("recording-file"): case CSH_LOOKUP("output destination"): case CSH_LOOKUP("output dest"): case CSH_LOOKUP("output file"): case CSH_LOOKUP("recording destination"): case CSH_LOOKUP("recording dest"): case CSH_LOOKUP("recording file"): out->recording_file = s; break; case CSH_LOOKUP("recording-media-slot-offer"): // This needs to be > 0 //out->media_rec_slot_offer = bencode_get_integer_str(value, out->media_rec_slot_offer); out->media_rec_slot_offer = parser->get_int_str(value, out->media_rec_slot_offer); break; case CSH_LOOKUP("recording-media-slot-answer"): // This needs to be > 0 out->media_rec_slot_answer = parser->get_int_str(value, out->media_rec_slot_answer); break; case CSH_LOOKUP("recording-media-slots"): out->media_rec_slots = parser->get_int_str(value, out->media_rec_slots); break; case CSH_LOOKUP("passthrough"): case CSH_LOOKUP("passthru"): switch (__csh_lookup_n(1, &s)) { case CSH_LOOKUP_N(1, "on"): case CSH_LOOKUP_N(1, "yes"): case CSH_LOOKUP_N(1, "enable"): case CSH_LOOKUP_N(1, "enabled"): out->passthrough_on = true; break; case CSH_LOOKUP_N(1, "no"): case CSH_LOOKUP_N(1, "off"): case CSH_LOOKUP_N(1, "disable"): case CSH_LOOKUP_N(1, "disabled"): out->passthrough_off = true; break; default: ilog(LOG_WARN, "Unknown 'passthrough' flag encountered: '" STR_FORMAT "'", STR_FMT(&s)); } break; case CSH_LOOKUP("pause"): out->pause = parser->get_int_str(value, out->pause); break; case CSH_LOOKUP("ptime"): if (out->opmode == OP_OFFER) out->ptime = parser->get_int_str(value, 0); break; case CSH_LOOKUP("ptime-reverse"): case CSH_LOOKUP("ptime reverse"): case CSH_LOOKUP("reverse ptime"): case CSH_LOOKUP("reverse-ptime"): if (out->opmode == OP_OFFER) out->rev_ptime = parser->get_int_str(value, 0); break; case CSH_LOOKUP("received from"): case CSH_LOOKUP("received-from"): if (!parser->is_list(value)) { call_ng_received_from_string(out, &s); break; } parser->list_iter(parser, value, call_ng_received_from_iter, NULL, out); break; case CSH_LOOKUP("record call"): case CSH_LOOKUP("record-call"): out->record_call_str = s; break; case CSH_LOOKUP("recording path"): case CSH_LOOKUP("recording dir"): case CSH_LOOKUP("recording directory"): case CSH_LOOKUP("recording folder"): case CSH_LOOKUP("output path"): case CSH_LOOKUP("output dir"): case CSH_LOOKUP("output directory"): case CSH_LOOKUP("output folder"): case CSH_LOOKUP("recording-path"): case CSH_LOOKUP("recording-dir"): case CSH_LOOKUP("recording-directory"): case CSH_LOOKUP("recording-folder"): case CSH_LOOKUP("output-path"): case CSH_LOOKUP("output-dir"): case CSH_LOOKUP("output-directory"): case CSH_LOOKUP("output-folder"): out->recording_path = s; break; case CSH_LOOKUP("recording pattern"): case CSH_LOOKUP("recording-pattern"): case CSH_LOOKUP("output pattern"): case CSH_LOOKUP("output-pattern"): out->recording_pattern = s; break; case CSH_LOOKUP("repeat-times"): case CSH_LOOKUP("repeat times"): out->repeat_times = parser->get_int_str(value, out->repeat_times); break; case CSH_LOOKUP("repeat-duration"): case CSH_LOOKUP("repeat duration"): out->repeat_duration = parser->get_int_str(value, out->repeat_duration); break; case CSH_LOOKUP("replace"): return call_ng_flags_str_list(parser, value, call_ng_flags_replace, out); case CSH_LOOKUP("rtcp-mux"): case CSH_LOOKUP("RTCP-mux"): case CSH_LOOKUP("rtcp mux"): case CSH_LOOKUP("RTCP mux"): return call_ng_flags_str_list(parser, value, call_ng_flags_rtcp_mux, out); case CSH_LOOKUP("rtpp-flags"): case CSH_LOOKUP("rtpp_flags"):; case CSH_LOOKUP("rtpp flags"):; /* s - list of rtpp flags */ out->rtpp_flags = true; parse_rtpp_flags(&s, out); break; case CSH_LOOKUP("SDES"): case CSH_LOOKUP("sdes"): return call_ng_flags_str_list(parser, value, ng_sdes_option, out); case CSH_LOOKUP("SDP"): case CSH_LOOKUP("sdp"): out->sdp = s; break; case CSH_LOOKUP("sdp-attr"): case CSH_LOOKUP("SDP-attr"): case CSH_LOOKUP("sdp attr"): case CSH_LOOKUP("SDP attr"): ng_sdp_attr_manipulations(parser, out, value); break; case CSH_LOOKUP("sdp-media-remove"): case CSH_LOOKUP("SDP-media-remove"): case CSH_LOOKUP("sdp_media_remove"): case CSH_LOOKUP("SDP_media_remove"): case CSH_LOOKUP("sdp media remove"): case CSH_LOOKUP("SDP media remove"): ng_sdp_media_remove(parser, out, value); break; case CSH_LOOKUP("set-label"): case CSH_LOOKUP("set label"): out->set_label = s; break; case CSH_LOOKUP("sip-code"): case CSH_LOOKUP("sip_code"): case CSH_LOOKUP("SIP-code"): case CSH_LOOKUP("SIP_code"): case CSH_LOOKUP("sip-response-code"): case CSH_LOOKUP("sip_response_code"): case CSH_LOOKUP("SIP-response-code"): case CSH_LOOKUP("SIP_response_code"): case CSH_LOOKUP("sip code"): case CSH_LOOKUP("SIP code"): case CSH_LOOKUP("sip response code"): case CSH_LOOKUP("SIP response code"): out->code = parser->get_int_str(value, out->code); break; case CSH_LOOKUP("sip-message-type"): case CSH_LOOKUP("sip_message_type"): case CSH_LOOKUP("SIP-message-type"): case CSH_LOOKUP("SIP_message_type"): case CSH_LOOKUP("sip message type"): case CSH_LOOKUP("SIP message type"): switch (__csh_lookup_n(1, &s)) { case CSH_LOOKUP_N(1, "request"): case CSH_LOOKUP_N(1, "sip-request"): case CSH_LOOKUP_N(1, "sip_request"): case CSH_LOOKUP_N(1, "SIP-request"): case CSH_LOOKUP_N(1, "SIP_request"): case CSH_LOOKUP_N(1, "sip request"): case CSH_LOOKUP_N(1, "SIP request"): out->message_type = SIP_REQUEST; break; case CSH_LOOKUP_N(1, "reply"): case CSH_LOOKUP_N(1, "sip-response"): case CSH_LOOKUP_N(1, "sip_response"): case CSH_LOOKUP_N(1, "SIP-response"): case CSH_LOOKUP_N(1, "SIP_response"): case CSH_LOOKUP_N(1, "sip-reply"): case CSH_LOOKUP_N(1, "sip_reply"): case CSH_LOOKUP_N(1, "SIP-reply"): case CSH_LOOKUP_N(1, "SIP_reply"): case CSH_LOOKUP_N(1, "sip response"): case CSH_LOOKUP_N(1, "SIP response"): case CSH_LOOKUP_N(1, "sip reply"): case CSH_LOOKUP_N(1, "SIP reply"): out->message_type = SIP_REPLY; break; default: ilog(LOG_WARN, "Unknown 'sip-message-type' flag encountered: '" STR_FORMAT "'", STR_FMT(&s)); } break; case CSH_LOOKUP("source-tag"): case CSH_LOOKUP("source tag"): out->source_tag = s; break; case CSH_LOOKUP("source-call-id"): case CSH_LOOKUP("source call id"): case CSH_LOOKUP("source-call-ID"): case CSH_LOOKUP("source call ID"): out->source_call_id = s; break; case CSH_LOOKUP("start-pos"): case CSH_LOOKUP("start pos"): out->start_pos = parser->get_int_str(value, out->start_pos); break; case CSH_LOOKUP("supports"): return call_ng_flags_str_list(parser, value, call_ng_flags_supports, out); #ifdef WITH_TRANSCODING case CSH_LOOKUP("T38"): case CSH_LOOKUP("T.38"): case CSH_LOOKUP("t38"): case CSH_LOOKUP("t.38"): return call_ng_flags_str_list(parser, value, ng_t38_option, out); case CSH_LOOKUP("T38-version"): case CSH_LOOKUP("T.38-version"): case CSH_LOOKUP("t38-version"): case CSH_LOOKUP("t.38-version"): case CSH_LOOKUP("T38 version"): case CSH_LOOKUP("T.38 version"): case CSH_LOOKUP("t38 version"): case CSH_LOOKUP("t.38 version"): out->t38_version = parser->get_int_str(value, out->t38_version); break; #endif case CSH_LOOKUP("tags"): return parser->list_iter(parser, value, NULL, call_ng_tags_iter, out); case CSH_LOOKUP("template"):; str *tplate = t_hash_table_lookup(rtpe_signalling_templates, &s); if (!tplate) { ilog(LOG_WARN, "Templates for signalling flags '" STR_FORMAT "' not found", STR_FMT(&s)); break; } // naive approach: just parse them out every time // TODO: improve this by pre-parsing the flags at startup parse_rtpp_flags(tplate, out); break; case CSH_LOOKUP("to-interface"): case CSH_LOOKUP("to interface"): out->direction[1] = s; break; case CSH_LOOKUP("to-label"): case CSH_LOOKUP("to label"): out->to_label = s; break; case CSH_LOOKUP("to-call-id"): case CSH_LOOKUP("to call id"): out->to_call_id = s; break; case CSH_LOOKUP("to-tag"): case CSH_LOOKUP("to_tag"): case CSH_LOOKUP("to tag"): out->to_tag = s; break; case CSH_LOOKUP("TOS"): case CSH_LOOKUP("tos"): out->tos = parser->get_int_str(value, out->tos); break; case CSH_LOOKUP("transport protocol"): case CSH_LOOKUP("transport-protocol"): if (!str_cmp(&s, "accept")) out->protocol_accept = true; else out->transport_protocol = transport_protocol(&s); break; case CSH_LOOKUP("trigger"): out->trigger = s; break; case CSH_LOOKUP("trigger-end"): case CSH_LOOKUP("trigger end"): case CSH_LOOKUP("end trigger"): case CSH_LOOKUP("end-trigger"): out->trigger_end = s; break; case CSH_LOOKUP("trigger-end-time"): case CSH_LOOKUP("trigger end time"): case CSH_LOOKUP("end-trigger-time"): case CSH_LOOKUP("end trigger time"): out->trigger_end_ms = parser->get_int_str(value, out->trigger_end_ms); break; case CSH_LOOKUP("trigger-end-digits"): case CSH_LOOKUP("trigger end digits"): case CSH_LOOKUP("end-trigger-digits"): case CSH_LOOKUP("end trigger digits"): out->trigger_end_digits = parser->get_int_str(value, out->trigger_end_digits); break; case CSH_LOOKUP("via-branch"): out->via_branch = s; break; case CSH_LOOKUP("volume"): out->volume = parser->get_int_str(value, out->volume); break; case CSH_LOOKUP("vsc-pause-rec"): case CSH_LOOKUP("VSC-pause-rec"): case CSH_LOOKUP("vsc-pause-recording"): case CSH_LOOKUP("VSC-pause-recording"): out->vsc_pause_rec = s; break; case CSH_LOOKUP("vsc-pause-resume-rec"): case CSH_LOOKUP("VSC-pause-resume-rec"): case CSH_LOOKUP("vsc-pause-resume-recording"): case CSH_LOOKUP("VSC-pause-resume-recording"): out->vsc_pause_resume_rec = s; break; case CSH_LOOKUP("vsc-start-pause-resume-rec"): case CSH_LOOKUP("VSC-start-pause-resume-rec"): case CSH_LOOKUP("vsc-start-pause-resume-recording"): case CSH_LOOKUP("VSC-start-pause-resume-recording"): out->vsc_start_pause_resume_rec = s; break; case CSH_LOOKUP("vsc-start-rec"): case CSH_LOOKUP("VSC-start-rec"): case CSH_LOOKUP("vsc-start-recording"): case CSH_LOOKUP("VSC-start-recording"): out->vsc_start_rec = s; break; case CSH_LOOKUP("vsc-start-stop-rec"): case CSH_LOOKUP("VSC-start-stop-rec"): case CSH_LOOKUP("vsc-start-stop-recording"): case CSH_LOOKUP("VSC-start-stop-recording"): out->vsc_start_stop_rec = s; break; case CSH_LOOKUP("vsc-stop-rec"): case CSH_LOOKUP("VSC-stop-rec"): case CSH_LOOKUP("vsc-stop-recording"): case CSH_LOOKUP("VSC-stop-recording"): out->vsc_stop_rec = s; break; case CSH_LOOKUP("xmlrpc-callback"): case CSH_LOOKUP("XMLRPC-callback"): out->xmlrpc_callback = s; break; default: ilog(LOG_WARN, "Unknown dictionary key encountered: '" STR_FORMAT "'", STR_FMT(key)); } return NULL; } const char *call_ng_process_flags(sdp_ng_flags *out, ng_command_ctx_t *ctx) { const ng_parser_t *parser = ctx->parser_ctx.parser; call_ng_flags_init(out, ctx->opmode); ctx->flags = out; // check for default templates, "default" first if (rtpe_default_signalling_templates[OP_OTHER].len) parse_rtpp_flags(&rtpe_default_signalling_templates[OP_OTHER], out); // and then one matching the current command if (ctx->opmode != OP_OTHER && rtpe_default_signalling_templates[ctx->opmode].len) parse_rtpp_flags(&rtpe_default_signalling_templates[ctx->opmode], out); return parser->dict_iter(parser, ctx->req, call_ng_main_flags, out); } static void ng_sdp_attr_manipulations_free(struct sdp_manipulations * array[__MT_MAX]) { for (int i = 0; i < __MT_MAX; i++) { struct sdp_manipulations *sdp_manipulations = array[i]; if (!sdp_manipulations) continue; str_case_ht_destroy_ptr(&sdp_manipulations->rem_commands); str_case_value_ht_destroy_ptr(&sdp_manipulations->subst_commands); t_queue_clear_full(&sdp_manipulations->add_commands, str_free); g_free(sdp_manipulations); array[i] = NULL; } } static void ng_codecs_free(struct ng_codec *c) { g_free(c); } static void ng_media_free(struct ng_media *m) { t_queue_clear_full(&m->codecs, ng_codecs_free); t_queue_clear_full(&m->codec_list, str_free); g_free(m); } static void ng_tag_free(struct ng_tag *tag) { t_queue_clear_full(&tag->to, str_free); g_free(tag); } void call_ng_free_flags(sdp_ng_flags *flags) { str_case_value_ht_destroy_ptr(&flags->codec_set); if (flags->frequencies) g_array_free(flags->frequencies, true); #define X(x) t_queue_clear_full(&flags->x, str_free); RTPE_NG_FLAGS_STR_Q_PARAMS #undef X #define X(x) t_queue_clear_full(&flags->x, sdp_attr_free); RTPE_NG_FLAGS_SDP_ATTR_Q_PARAMS #undef X #define X(x) str_case_ht_destroy_ptr(&flags->x); RTPE_NG_FLAGS_STR_CASE_HT_PARAMS #undef X str_ht_destroy_ptr(&flags->bundles); ng_sdp_attr_manipulations_free(flags->sdp_manipulations); t_queue_clear_full(&flags->medias, ng_media_free); t_queue_clear(&flags->groups_other); t_queue_clear_full(&flags->tags, ng_tag_free); }