#
# $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.75");   ## 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");
	xlog("L_EDEBUG", "RTPPROXY_PROCESS_REQUEST: SDP\n%@msg.content.sdp\n");
	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");
	xlog("L_EDEBUG", "RTPPROXY_PROCESS_REPLY: SDP\n%@msg.content.sdp\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");
	xlog("L_EDEBUG", "RTPPROXY_PROCESS_FAILURE: SDP\n%@msg.content.sdp\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