|
@@ -0,0 +1,428 @@
|
|
|
+#
|
|
|
+# $Id: ser-oob-RTPPROXY.cfg.inc,v 1.46 2008/09/15 15:51:44 tirpi Exp $
|
|
|
+#
|
|
|
+# BEGIN: RTP proxy include section
|
|
|
+#
|
|
|
+# INSTALLATION:
|
|
|
+# 1) apply patch ser-oob-RTPPROXY.cfg.patch to ser-oob.cfg
|
|
|
+# 2) add content of this file in ser-oob.cfg
|
|
|
+# 3) modify parameters
|
|
|
+#
|
|
|
+# Problem when forking and early media are received. In this case we should create for each branch extra dialog_id,
|
|
|
+# record-route it and call route[RTPPROXY_PROCESS_REQUEST] for each branch. But it's limited by
|
|
|
+# ser lump system.
|
|
|
+# Important: t_newtran() must be executed before RTPPROXY_PROCESS_REQUEST is executed to eat retransmissions
|
|
|
+#
|
|
|
+# global script flags/AVPs used:
|
|
|
+# FLAG_INIT_DLG ... if dialog initialize request
|
|
|
+# FLAG_NAT ... test when RTP proxy will be applied
|
|
|
+# $dialog_id ... unique dialog id
|
|
|
+#
|
|
|
+# local to RTP proxy AVPs (rtp_dlg_* are dialog AVPs)
|
|
|
+# $rtp_dlg_sess_ids ... list of confirmed (INVITE/200OK/ACK, INVITE/180/PRACK, UPDATE/200OK ) RTP sessions
|
|
|
+# $rtp_dlg_sess_ids2 ... list of non-confirmed sessions
|
|
|
+# $rtp_method_flag ... request method passed to onreply/failure
|
|
|
+#
|
|
|
+# rtpproxy.* configuration params
|
|
|
+#
|
|
|
+# Note: INVITE w/o offer, 200OK w/offer, PRACK/ACK w/answer (RFC3262) not supported.
|
|
|
+
|
|
|
+# RTP Proxy options
|
|
|
+# if RTP stream uses a different interface as SIP we can define sip-ip to find switchboard according received and next hop address
|
|
|
+loadmodule "iptrtpproxy"
|
|
|
+#loadmodule "modules/iptrtpproxy-v2/iptrtpproxy.so"
|
|
|
+
|
|
|
+modparam("iptrtpproxy", "config", "/etc/iptrtpproxy.cfg");
|
|
|
+
|
|
|
+#DEBCONF-RTTPPROXY-START
|
|
|
+modparam("iptrtpproxy", "switchboard", "name=*;sip-addr=213.192.59.91"); ## TODO change back to .75
|
|
|
+#modparam("iptrtpproxy", "switchboard", "name=gate_a;sip-addr=1.2.3.4;aggregation=AA")
|
|
|
+#modparam("iptrtpproxy", "switchboard", "name=gate_b;aggregation=A")
|
|
|
+modparam("iptrtpproxy", "codec_set", "name=any;media_type=*;rights=0;codecs=*;max_streams=9999");
|
|
|
+modparam("iptrtpproxy", "codec_set", "name=audio_only;media_type=*;rights=0;codecs=*;max_streams=0;media_type=audio;max_streams=9999");
|
|
|
+modparam("iptrtpproxy", "codec_set", "name=PCMU_PCMA_only;media_type=*;rights=1;codecs=*;rights=0;codecs=PCMU,PCMA");
|
|
|
+modparam("iptrtpproxy", "codec_set", "name=parityfec_only;media_type=*;rights=1;codecs=*;rights=0;codecs=parityfec");
|
|
|
+#DEBCONF-RTTPPROXY-END
|
|
|
+
|
|
|
+avpflags
|
|
|
+ rtpproxy_dlg; # extra attributes
|
|
|
+
|
|
|
+modparam("avp_db", "attr_group", "id=rtp_dlg,flag=rtpproxy_dlg,table=rtpproxy_attrs");
|
|
|
+
|
|
|
+#
|
|
|
+# Whether to enable or disable the rtp proxy. Possible values are:
|
|
|
+# "0" -- always disable
|
|
|
+# "1" -- always enable regardless of whether UAC or UAS is behind NAT
|
|
|
+# "detect" -- detect whether the UAC or the UAS is behind NAT,
|
|
|
+# and enable the rtp proxy when necessary
|
|
|
+# "compare" -- Check whether the inbound and outbound interfaces
|
|
|
+# differ. If not, do not enable rtp proxy.
|
|
|
+#
|
|
|
+#DEBCONF-RTP_ENABLE-START
|
|
|
+rtp_proxy.enabled = "detect" desc "indicates whether the RTP Proxy is enabled or not (0/1/detect)"
|
|
|
+rtp_proxy.learning_timeout = "20" desc "RTP proxy learning timeout (sec)"
|
|
|
+rtp_proxy.ringing_timeout = "90" desc "RTP proxy ringing timeout (sec)"
|
|
|
+rtp_proxy.expiration_timeout = "30" desc "RTP proxy expiration timeout (sec)"
|
|
|
+rtp_proxy.always_learn = "0" desc "RTP proxy always learn (0/1)"
|
|
|
+rtp_proxy.hide_o_addr = "" desc "Fake address to hide original address provided at SDP o= line"
|
|
|
+rtp_proxy.codec_set = "any" desc "Codec authorization set"
|
|
|
+# throttled packets are MARKed and need be removed by a netfilter rule in FORWARD chain
|
|
|
+rtp_proxy.throttle_mark = "1" desc "Netfilter MARK of packets being throttled"
|
|
|
+rtp_proxy.throttle_rtp_max_bytes = "0" desc "Max. RTP bytes per sec rate"
|
|
|
+rtp_proxy.throttle_rtcp_max_bytes = "0" desc "Max. RTCP bytes per sec rate"
|
|
|
+rtp_proxy.throttle_rtp_max_packets = "0" desc "Max. RTP packets per sec rate"
|
|
|
+rtp_proxy.throttle_rtcp_max_packets = "0" desc "Max. RTCP packets per sec rate"
|
|
|
+#DEBCONF-RTP_ENABLE-END
|
|
|
+
|
|
|
+route[RTPPROXY_PROCESS_REQUEST] {
|
|
|
+ if (method != "INVITE" && method != "UPDATE" && method != "BYE" && method != "ACK" && method != "PRACK") {
|
|
|
+ # we are interested in INVITE/BYE dialog related requests only
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ if (!defined $dialog_id) { # AVP loaded from route cookie
|
|
|
+ if (@method != "ACK")
|
|
|
+ t_reply("400", "Missing cookie"); # 500 (=our bug) in case of init request because it'd been generated by ourselves
|
|
|
+ xlog("L_EDEBUG", "RTPPROXY_PROCESS_REQUEST: missing cookie: %@hf_value.route[0]\n");
|
|
|
+ drop;
|
|
|
+ }
|
|
|
+ xlog("L_EDEBUG", "RTPPROXY_PROCESS_REQUEST:\n%mb");
|
|
|
+ if (isflagset(FLAG_INIT_DLG)) {
|
|
|
+ # if init request then test RTP proxy is to by applied
|
|
|
+ if (@cfg_get.rtp_proxy.enabled == "0") {
|
|
|
+ # RTP Proxy is disabled
|
|
|
+ break;
|
|
|
+ } else if (@cfg_get.rtp_proxy.enabled == "detect") {
|
|
|
+ if (!isflagset(FLAG_NAT)) {
|
|
|
+ # If no NAT is involved we don't have to do here anything.
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ } else if (@cfg_get.rtp_proxy.enabled != "1") {
|
|
|
+ # This is not a valid setting
|
|
|
+ xlog("L_ERR", "RTPPROXY_PROCESS_REQUEST: Unknown option for rtp_proxy.enabled: %@cfg_get.rtp_proxy.enabled\n");
|
|
|
+ return;
|
|
|
+ } # else rtp proxy is permanently enabled
|
|
|
+ if (isflagset(FLAG_RTP_PROXY)) {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ xlog("L_EDEBUG", "RTPPROXY_PROCESS_REQUEST: routing '%@received.ip'->'%@next_hop.src_ip', src_ip:%@src.ip\n");
|
|
|
+ if (@src.ip == @received.ip) {
|
|
|
+ # it's case when ser forwards message to itself, if the second pass would
|
|
|
+ # have added rtpproxy it'd rtpproxy twice through local chain, there is a problem
|
|
|
+ # in netfilter
|
|
|
+ xlog("L_EDEBUG", "RTPPROXY_PROCESS_REQUEST: do not add RTPPROXY because srcip=receivedip\n");
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (method != "INVITE" || strempty(@msg.body)) { # limitation, initial INVITE must provide SDP to allocate session
|
|
|
+ xlog("L_EDEBUG", "RTPPROXY_PROCESS_REQUEST: initial INVITE without body\n");
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ if ((@cfg_get.rtp_proxy.enabled == "compare") && (@received.ip == @next_hop.src_ip)) {
|
|
|
+ # Inbound and outbound interfaces are the same,
|
|
|
+ # do not proxy.
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if ((method == "INVITE" || method == "UPDATE") && @msg.body!="") {
|
|
|
+ if (@iptrtpproxy.active_media_num == "0") break;
|
|
|
+ iptrtpproxy_set_param("codec_set", "@cfg_get.rtp_proxy.codec_set");
|
|
|
+ iptrtpproxy_set_param("remove_codec_mask", "1");
|
|
|
+ if (!iptrtpproxy_authorize_media()) {
|
|
|
+ xlog("L_EDEBUG", "RTPPROXY_PROCESS_REQUEST: cannot authorize media\n");
|
|
|
+ t_reply("415", "Cannot authorize media");
|
|
|
+ drop;
|
|
|
+ }
|
|
|
+ if (@iptrtpproxy.active_media_num == "0") {
|
|
|
+ xlog("L_EDEBUG", "RTPPROXY_PROCESS_REQUEST: no acceptable codec\n");
|
|
|
+ t_reply("488", "Not acceptable here");
|
|
|
+ drop;
|
|
|
+ }
|
|
|
+
|
|
|
+ # if RTP stream uses the same interface as SIP we can find switchboard according received and next hop address
|
|
|
+ # It's always needed for dialog init requests but sometimes may be needed also for
|
|
|
+ # re-INVITEs in case that switchboards could not be obtained from $rtp_dlg_sess_ids2, i.e. reused existing sesssions
|
|
|
+ xlog("L_EDEBUG", "RTPPROXY_PROCESS_REQUEST: find switchboard-a for '%@received.ip'\n");
|
|
|
+ if (!iptrtpproxy_set_param("switchboard_by_sip_ip_a", "@received.ip")) {
|
|
|
+ xlog("L_ERR", "RTPPROXY_PROCESS_REQUEST: Cannot find switchboard-a for routing '%@received.ip'\n");
|
|
|
+ t_reply("500", "RTP proxy error");
|
|
|
+ drop;
|
|
|
+ }
|
|
|
+ eval_push("x:%@next_hop.src_ip");
|
|
|
+ if (@eval.get[-1] == @received.ip) {
|
|
|
+ iptrtpproxy_set_param("switchboard_b", "@iptrtpproxy.switchboard_a");
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ xlog("L_EDEBUG", "RTPPROXY_PROCESS_REQUEST: find switchboard-b for '%@eval.get[-1]'\n");
|
|
|
+ if (!iptrtpproxy_set_param("switchboard_by_sip_ip_b", "@eval.get[-1]")) {
|
|
|
+ xlog("L_ERR", "RTPPROXY_PROCESS_REQUEST: Cannot find switchboard for routing '%@eval.get[-1]'\n");
|
|
|
+ t_reply("500", "RTP proxy error");
|
|
|
+ drop;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ eval_remove(-1, 1);
|
|
|
+ xlog("L_EDEBUG", "RTPPROXY_PROCESS_REQUEST: INVITE: %@iptrtpproxy.switchboard_a->%@iptrtpproxy.switchboard_b, learning-timeout: %@iptrtpproxy.learning_timeout, expiration-timeout: %@iptrtpproxy.expiration_timeout, always-learn: %@iptrtpproxy.always_learn\n");
|
|
|
+
|
|
|
+ # you can call a custom procedure to find switchboards and override default behaviour here
|
|
|
+ if (strempty(@iptrtpproxy.switchboard_a) || strempty(@iptrtpproxy.switchboard_b)) { # do not use proxy
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ # no "uncontrolled" break bellow this line !!!
|
|
|
+ if (isflagset(FLAG_INIT_DLG)) { # INVITE && !to.tag
|
|
|
+ route("RTPPROXY_REMOVE_ATTRS");
|
|
|
+ iptrtpproxy_set_param("learning_timeout", "@cfg_get.rtp_proxy.ringing_timeout");
|
|
|
+
|
|
|
+ } else {
|
|
|
+ # remove any non-confirmed
|
|
|
+ route("RTPPROXY_LOAD_ATTRS");
|
|
|
+ if ($rtp_dlg_sess_ids2!="") {
|
|
|
+ # there is a non confirmed request in progress, wait till is confirmed
|
|
|
+ t_reply("491", "Pending request");
|
|
|
+ drop;
|
|
|
+ }
|
|
|
+ if (strempty($rtp_dlg_sess_ids)) {
|
|
|
+ # limitation, initial INVITE must provide SDP to allocate session
|
|
|
+ break; # possible because $rtp_dlg_* are null
|
|
|
+ }
|
|
|
+ iptrtpproxy_set_param("protected_session_ids", "$rtp_dlg_sess_ids");
|
|
|
+ iptrtpproxy_delete("$rtp_dlg_sess_ids2");
|
|
|
+ del_attr("$rtp_dlg_sess_ids2");
|
|
|
+ iptrtpproxy_set_param("learning_timeout", "@cfg_get.rtp_proxy.learning_timeout");
|
|
|
+ }
|
|
|
+
|
|
|
+ if (@cfg_get.rtp_proxy.hide_o_addr != "") {
|
|
|
+ xlog("L_EDEBUG", "RTPPROXY_PROCESS_REQUEST: INVITE: rewrite o_addr='%@cfg_get.rtp_proxy.hide_o_addr'\n");
|
|
|
+ iptrtpproxy_set_param("o_addr", "@cfg_get.rtp_proxy.hide_o_addr");
|
|
|
+ }
|
|
|
+ # we are optimistic and do not expect callee will change stream ip:port when caller has not done it.
|
|
|
+ # If we want to be fully RFC3264 compliant we'd alloc completely new RTP session set for all
|
|
|
+ # streams provided in caller's SDP regardless a change detected since last confirmed INVITE.
|
|
|
+ # This solution has two drawbacks, the 1st it may lead to RTP session exhastion, the 2nd there are
|
|
|
+ # non re-INVITE compliant phones which does not like IP:port change in SDP
|
|
|
+ iptrtpproxy_set_param("protected_session_ids", "$rtp_dlg_sess_ids");
|
|
|
+
|
|
|
+ # throttling stuff
|
|
|
+ iptrtpproxy_set_param("throttle_mark", "@cfg_get.rtp_proxy.throttle_mark");
|
|
|
+ iptrtpproxy_set_param("throttle_rtp_max_bytes", "@cfg_get.rtp_proxy.throttle_rtp_max_bytes");
|
|
|
+ iptrtpproxy_set_param("throttle_rtcp_max_bytes", "@cfg_get.rtp_proxy.throttle_rtcp_max_bytes");
|
|
|
+ iptrtpproxy_set_param("throttle_rtp_max_packets", "@cfg_get.rtp_proxy.throttle_rtp_max_packets");
|
|
|
+ iptrtpproxy_set_param("throttle_rtcp_max_packets", "@cfg_get.rtp_proxy.throttle_rtcp_max_packets");
|
|
|
+
|
|
|
+ if (isflagset(FLAG_REVERSE_DIR)) {
|
|
|
+ eval_push("0"); # callee -> caller
|
|
|
+ } else {
|
|
|
+ eval_push("1"); # caller -> callee
|
|
|
+ }
|
|
|
+ if (!iptrtpproxy_alloc("@eval.pop[-1]")) {
|
|
|
+ t_reply("500", "RTP proxy error");
|
|
|
+ drop;
|
|
|
+ }
|
|
|
+ # we need save in dialog as non-confirmed sess_ids (not only in transaction) because
|
|
|
+ # UPDATE in non-confirmed INVITE and ACK to 200OK are considered as separate transactions.
|
|
|
+ if (@iptrtpproxy.session_ids != "")
|
|
|
+ $rtp_dlg_sess_ids2 = @iptrtpproxy.session_ids;
|
|
|
+ else
|
|
|
+ del_attr("$rtp_dlg_sess_ids2");
|
|
|
+
|
|
|
+ xlog("L_EDEBUG", "RTPPROXY_PROCESS_REQUEST: allocated ids2=%$rtp_dlg_sess_ids2\n");
|
|
|
+ # session_ids are stored in AVP to let commit (on_reply) or rollback (on_failure) allocated sessions
|
|
|
+ $rtp_method_flag = @method;
|
|
|
+
|
|
|
+ append_hf("X-RTP-Proxy: YES\r\n");
|
|
|
+ setflag("FLAG_RTP_PROXY");
|
|
|
+ route("RTPPROXY_SAVE_ATTRS");
|
|
|
+ }
|
|
|
+ else if (method == "ACK" || method == "PRACK") {
|
|
|
+ # ACK after 200OK is considered as separate transaction
|
|
|
+ # we'll accept RTP sessions, in case of re-INVITE
|
|
|
+ # we cannot do it in 200OK because old and new streams must
|
|
|
+ # be traversed till ACK
|
|
|
+ # save non-confirmed as confirmed
|
|
|
+ route("RTPPROXY_LOAD_ATTRS");
|
|
|
+ xlog("L_EDEBUG", "RTPPROXY_PROCESS_REQUEST: %@method, delete(ids=%$rtp_dlg_sess_ids), protect(ids2=%$rtp_dlg_sess_ids2)\n");
|
|
|
+ if (strempty($rtp_dlg_sess_ids2)) {
|
|
|
+ break; /* do not save, non SDP related re-INVITE or retrasmission which is not eaten by tm module, SDP in ACK is not supported */
|
|
|
+ }
|
|
|
+ iptrtpproxy_set_param("protected_session_ids", "$rtp_dlg_sess_ids2");
|
|
|
+ iptrtpproxy_delete("$rtp_dlg_sess_ids");
|
|
|
+ $rtp_dlg_sess_ids = $rtp_dlg_sess_ids2;
|
|
|
+ del_attr("$rtp_dlg_sess_ids2");
|
|
|
+ route("RTPPROXY_SAVE_ATTRS");
|
|
|
+ }
|
|
|
+ else if (method == "BYE") { # CANCEL ???
|
|
|
+ # we must delete rtp session in BYE request, otherwise we risk problem of lost 200OK to BYE
|
|
|
+ route("RTPPROXY_LOAD_ATTRS");
|
|
|
+ xlog("L_EDEBUG", "RTPPROXY_PROCESS_REQUEST: %@method delete(ids=%$rtp_dlg_sess_ids, ids2=%$rtp_dlg_sess_ids2)\n");
|
|
|
+ iptrtpproxy_set_param("protected_session_ids", "");
|
|
|
+ iptrtpproxy_delete("$rtp_dlg_sess_ids");
|
|
|
+ iptrtpproxy_delete("$rtp_dlg_sess_ids2");
|
|
|
+ route("RTPPROXY_REMOVE_ATTRS");
|
|
|
+
|
|
|
+ # $rtp_method_flag = @method; # nothing to do in onreply to BYE
|
|
|
+ }
|
|
|
+ # rtp_dlg_* have been removed to save memory
|
|
|
+}
|
|
|
+
|
|
|
+route[RTPPROXY_PROCESS_REPLY] {
|
|
|
+ if (!defined $dialog_id || strempty($rtp_method_flag) || strempty(@msg.body)) break;
|
|
|
+ xlog("L_EDEBUG", "RTPPROXY_PROCESS_REPLY:\n%mb\n");
|
|
|
+
|
|
|
+ if ($rtp_method_flag == "INVITE" && (status=~"18[0-9]" || status=~"2[0-9][0-9]")) {
|
|
|
+ # If RTP proxy was activated and this is a 18x or 2xx reply with a
|
|
|
+ # body, inform RTP proxy.
|
|
|
+
|
|
|
+ # onreply route is called for EACH retransmission, tm does NOT eat anything
|
|
|
+ if (strempty($rtp_last_code) || $rtp_last_code != @msg.res.code) {
|
|
|
+ if (@iptrtpproxy.active_media_num == "0") break;
|
|
|
+ iptrtpproxy_set_param("codec_set", "@cfg_get.rtp_proxy.codec_set");
|
|
|
+ iptrtpproxy_set_param("remove_codec_mask", "1");
|
|
|
+ if (!iptrtpproxy_authorize_media()) {
|
|
|
+ xlog("L_EDEBUG", "RTPPROXY_PROCESS_REPLY: cannot authorize media\n");
|
|
|
+ drop;
|
|
|
+ }
|
|
|
+ if (@iptrtpproxy.active_media_num == "0") {
|
|
|
+ xlog("L_EDEBUG", "RTPPROXY_PROCESS_REPLY: no acceptable codec\n");
|
|
|
+ drop;
|
|
|
+ }
|
|
|
+
|
|
|
+ # (probably) no retransmission
|
|
|
+ route("RTPPROXY_LOAD_ATTRS");
|
|
|
+ $rtp_last_code = @msg.res.code;
|
|
|
+ if (isflagset(FLAG_INIT_DLG) && status=~"18[0-9]") {
|
|
|
+ iptrtpproxy_set_param("learning_timeout", "@cfg_get.rtp_proxy.ringing_timeout");
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ iptrtpproxy_set_param("learning_timeout", "@cfg_get.rtp_proxy.learning_timeout");
|
|
|
+ }
|
|
|
+ iptrtpproxy_set_param("expiration_timeout", "@cfg_get.rtp_proxy.expiration_timeout");
|
|
|
+ iptrtpproxy_set_param("always_learn", "@cfg_get.rtp_proxy.always_learn");
|
|
|
+ xlog("L_EDEBUG", "RTPPROXY_PROCESS_REPLY: update(ids2=%$rtp_dlg_sess_ids2, learning-timeout: %@iptrtpproxy.learning_timeout) protect(ids=%$rtp_dlg_sess_ids)\n");
|
|
|
+ if (@cfg_get.rtp_proxy.hide_o_addr != "") {
|
|
|
+ xlog("L_EDEBUG", "RTPPROXY_PROCESS_REPLY: INVITE: rewrite o_addr='%@cfg_get.rtp_proxy.hide_o_addr'\n");
|
|
|
+ iptrtpproxy_set_param("o_addr", "@cfg_get.rtp_proxy.hide_o_addr");
|
|
|
+ }
|
|
|
+ if (!isflagset(FLAG_REVERSE_DIR)) { # revert direction
|
|
|
+ eval_push("0"); # callee -> caller
|
|
|
+ } else {
|
|
|
+ eval_push("1"); # caller -> callee
|
|
|
+ }
|
|
|
+ iptrtpproxy_set_param("protected_session_ids", "$rtp_dlg_sess_ids");
|
|
|
+ # throttling stuff
|
|
|
+ iptrtpproxy_set_param("throttle_mark", "@cfg_get.rtp_proxy.throttle_mark");
|
|
|
+ iptrtpproxy_set_param("throttle_rtp_max_bytes", "@cfg_get.rtp_proxy.throttle_rtp_max_bytes");
|
|
|
+ iptrtpproxy_set_param("throttle_rtcp_max_bytes", "@cfg_get.rtp_proxy.throttle_rtcp_max_bytes");
|
|
|
+ iptrtpproxy_set_param("throttle_rtp_max_packets", "@cfg_get.rtp_proxy.throttle_rtp_max_packets");
|
|
|
+ iptrtpproxy_set_param("throttle_rtcp_max_packets", "@cfg_get.rtp_proxy.throttle_rtcp_max_packets");
|
|
|
+ if (iptrtpproxy_update("@eval.pop[-1]", "$rtp_dlg_sess_ids2")) {
|
|
|
+ if (status=~"2[0-9][0-9]") {
|
|
|
+ if (isflagset(FLAG_INIT_DLG)) {
|
|
|
+ xlog("L_EDEBUG", "RTPPROXY_PROCESS_REPLY: adjust timeout(ids2=%$rtp_dlg_sess_ids2)\n");
|
|
|
+ if (isflagset(FLAG_REVERSE_DIR)) {
|
|
|
+ eval_push("0"); # callee -> caller
|
|
|
+ } else {
|
|
|
+ eval_push("1"); # caller -> callee
|
|
|
+ }
|
|
|
+ iptrtpproxy_adjust_timeout("@eval.pop[-1]", "$rtp_dlg_sess_ids2"); # decrease ringing-timeout, a to b direction
|
|
|
+ }
|
|
|
+ # the confirmed session will be adjusted in ACK, because old media (re-INVITE) should be traversed
|
|
|
+ }
|
|
|
+ if (@iptrtpproxy.session_ids != "") {
|
|
|
+ $rtp_dlg_sess_ids2 = @iptrtpproxy.session_ids;
|
|
|
+ $rtp_last_sess_ids2 = @iptrtpproxy.session_ids; # keep it in transaction
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ del_attr("$rtp_dlg_sess_ids2");
|
|
|
+ del_attr("$rtp_last_sess_ids2");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ ;
|
|
|
+ # drop; ???
|
|
|
+ }
|
|
|
+ route("RTPPROXY_SAVE_ATTRS");
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ # we MUST do the same message modifications as in first reply
|
|
|
+ xlog("L_EDEBUG", "RTPPROXY_PROCESS_REPLY: update-retransmission(ids2=%$rtp_last_sess_ids2)\n");
|
|
|
+ if (@cfg_get.rtp_proxy.hide_o_addr != "") {
|
|
|
+ xlog("L_EDEBUG", "RTPPROXY_PROCESS_REPLY: INVITE: retrasmission rewrite o_addr='%@cfg_get.rtp_proxy.hide_o_addr'\n");
|
|
|
+ iptrtpproxy_set_param("o_addr", "@cfg_get.rtp_proxy.hide_o_addr");
|
|
|
+ }
|
|
|
+ if (!isflagset(FLAG_REVERSE_DIR)) { # set update SDP only flag & revert direction
|
|
|
+ eval_push("2"); # callee -> caller (bin=10)
|
|
|
+ } else {
|
|
|
+ eval_push("3"); # caller -> callee (bin=11)
|
|
|
+ }
|
|
|
+ iptrtpproxy_update("@eval.pop[-1]", "$rtp_last_sess_ids2"); # TODO flag to update SDP only
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else if ($rtp_method_flag == "UPDATE" && status=~"2[0-9][0-9]" && $rtp_dlg_sess_ids2!="") {
|
|
|
+ # confirm pending offer (UPDATE is not followed by ACK/PRACK)
|
|
|
+ route("RTPPROXY_LOAD_ATTRS");
|
|
|
+ xlog("L_EDEBUG", "RTPPROXY_PROCESS_REPLY: %@method, delete(ids=%$rtp_dlg_sess_ids), protect(ids2=%$rtp_dlg_sess_ids2)\n");
|
|
|
+ iptrtpproxy_set_param("protected_session_ids", "$rtp_dlg_sess_ids2");
|
|
|
+ iptrtpproxy_delete("$rtp_dlg_sess_ids");
|
|
|
+ $rtp_dlg_sess_ids = $rtp_dlg_sess_ids2;
|
|
|
+ del_attr("$rtp_dlg_sess_ids2");
|
|
|
+ route("RTPPROXY_SAVE_ATTRS");
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+route[RTPPROXY_PROCESS_FAILURE] {
|
|
|
+ if (!defined $dialog_id || strempty($rtp_method_flag)) break;
|
|
|
+
|
|
|
+ xlog("L_EDEBUG", "RTPPROXY_PROCESS_FAILURE:\n%mb\n");
|
|
|
+
|
|
|
+ if (isflagset(FLAG_INIT_DLG) && $rtp_method_flag == "INVITE") {
|
|
|
+ route("RTPPROXY_LOAD_ATTRS");
|
|
|
+ #remove all sessions
|
|
|
+ xlog("L_EDEBUG", "RTPPROXY_PROCESS_FAILURE: %@method delete(ids=%$rtp_dlg_sess_ids, ids2=%$rtp_dlg_sess_ids2)\n");
|
|
|
+ iptrtpproxy_set_param("protected_session_ids", "");
|
|
|
+ iptrtpproxy_delete("$rtp_dlg_sess_ids"); # early media are considered as confirmed
|
|
|
+ iptrtpproxy_delete("$rtp_dlg_sess_ids2");
|
|
|
+ route("RTPPROXY_REMOVE_ATTRS");
|
|
|
+ } else if ($rtp_method_flag == "INVITE" || $rtp_method_flag == "UPDATE") {
|
|
|
+ route("RTPPROXY_LOAD_ATTRS");
|
|
|
+ #remove only unconfirmed sessiosn
|
|
|
+ xlog("L_EDEBUG", "RTPPROXY_PROCESS_FAILURE: %@method, delete(ids2=%$rtp_dlg_sess_ids2), protect(ids=%$rtp_dlg_sess_ids)\n");
|
|
|
+ iptrtpproxy_set_param("protected_session_ids", "$rtp_dlg_sess_ids");
|
|
|
+ iptrtpproxy_delete("$rtp_dlg_sess_ids2");
|
|
|
+ del_attr("$rtp_dlg_sess_ids2");
|
|
|
+ route("RTPPROXY_SAVE_ATTRS");
|
|
|
+ }
|
|
|
+
|
|
|
+ if ($rtp_dlg_sess_ids2!="") { # ????? never TODO: retest
|
|
|
+ # do it if request really failed
|
|
|
+ # if flexroute forwards call in CAPM-PP callback then request is dropped
|
|
|
+ iptrtpproxy_set_param("protected_session_ids", "");
|
|
|
+ iptrtpproxy_delete("$rtp_dlg_sess_ids2");
|
|
|
+ del_attr("$rtp_dlg_sess_ids2");
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+route[RTPPROXY_LOAD_ATTRS] {
|
|
|
+ del_attr("$rtp_dlg_sess_ids");
|
|
|
+ del_attr("$rtp_dlg_sess_ids2");
|
|
|
+ load_extra_attrs("rtp_dlg", "$dialog_id");
|
|
|
+ xlog("L_EDEBUG", "RTPPROXY_LOAD_ATTRS: dialog_id=%$dialog_id, method/flag='%@method'/'%$rtp_method_flag', ids=%$rtp_dlg_sess_ids, ids2=%$rtp_dlg_sess_ids2\n");
|
|
|
+}
|
|
|
+
|
|
|
+route[RTPPROXY_SAVE_ATTRS] {
|
|
|
+ xlog("L_EDEBUG", "RTPPROXY_SAVE_ATTRS: dialog_id=%$dialog_id, method='%@method', ids=%$rtp_dlg_sess_ids, ids2=%$rtp_dlg_sess_ids2\n");
|
|
|
+ setavpflag("$f.rtp_dlg_sess_ids", "rtpproxy_dlg");
|
|
|
+ setavpflag("$f.rtp_dlg_sess_ids2", "rtpproxy_dlg");
|
|
|
+ save_extra_attrs("rtp_dlg", "$dialog_id");
|
|
|
+ del_attr("$rtp_dlg_sess_ids");
|
|
|
+ del_attr("$rtp_dlg_sess_ids2");
|
|
|
+}
|
|
|
+
|
|
|
+route[RTPPROXY_REMOVE_ATTRS] {
|
|
|
+ xlog("L_EDEBUG", "RTPPROXY_REMOVE_ATTRS: dialog_id=%$dialog_id, method='%@method'\n");
|
|
|
+ del_attr("$rtp_dlg_sess_ids");
|
|
|
+ del_attr("$rtp_dlg_sess_ids2");
|
|
|
+ remove_extra_attrs("rtp_dlg", "$dialog_id");
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+# END: RTP proxy include section
|