sbc: RTP relay: symmetric RTP implementation

sayer/1.4-spce2.6
Stefan Sayer 16 years ago committed by Raphael Coeffic
parent 1cb0bace17
commit 4bd9cd2025

@ -26,7 +26,6 @@
/*
SBC - feature-wishlist
- accounting (MySQL DB, cassandra DB)
- RTP forwarding mode (bridging)
- RTP transcoding mode (bridging)
- overload handling (parallel call to target thresholds)
- call distribution
@ -547,6 +546,38 @@ void SBCDialog::onInvite(const AmSipRequest& req)
}
}
if (call_profile.rtprelay_enabled) {
DBG("Enabling RTP relay mode\n");
rtp_relay_enabled = true;
// force symmetric RTP?
if (!call_profile.force_symmetric_rtp.empty()) {
string force_symmetric_rtp =
replaceParameters(call_profile.force_symmetric_rtp, "force_symmetric_rtp",
REPLACE_VALS);
if (!force_symmetric_rtp.empty() && force_symmetric_rtp != "no"
&& force_symmetric_rtp != "0") {
DBG("forcing symmetric RTP (passive mode)\n");
rtp_relay_force_symmetric_rtp = true;
}
}
// enable symmetric RTP by P-MsgFlags?
if (!rtp_relay_force_symmetric_rtp) {
if (call_profile.msgflags_symmetric_rtp) {
string str_msg_flags = getHeader(req.hdrs,"P-MsgFlags", true);
unsigned int msg_flags = 0;
if(reverse_hex2int(str_msg_flags,msg_flags)){
ERROR("while parsing 'P-MsgFlags' header\n");
msg_flags = 0;
}
if (msg_flags & FL_FORCE_ACTIVE) {
DBG("P-MsgFlags indicates forced symmetric RTP (passive mode)");
rtp_relay_force_symmetric_rtp = true;
}
}
}
}
m_state = BB_Dialing;
invite_req = req;
@ -583,11 +614,6 @@ void SBCDialog::onInvite(const AmSipRequest& req)
replaceParameters(call_profile.auth_credentials.pwd, "auth_pwd", REPLACE_VALS);
}
if (call_profile.rtprelay_enabled) {
DBG("Enabling RTP relay mode\n");
rtp_relay_enabled = true;
}
// get timer
if (call_profile.call_timer_enabled || call_profile.prepaid_enabled) {
if (!timersSupported()) {

@ -174,6 +174,8 @@ bool SBCCallProfile::readFromConfiguration(const string& name,
refuse_with = cfg.getParameter("refuse_with");
rtprelay_enabled = cfg.getParameter("enable_rtprelay") == "yes";
force_symmetric_rtp = cfg.getParameter("rtprelay_force_symmetric_rtp");
msgflags_symmetric_rtp = cfg.getParameter("rtprelay_msgflags_symmetric_rtp") == "yes";
md5hash = "<unknown>";
if (!cfg.getMD5(profile_file_name, md5hash)){
@ -212,6 +214,15 @@ bool SBCCallProfile::readFromConfiguration(const string& name,
sdpfilter_list.size());
INFO("SBC: RTP relay %sabled\n", rtprelay_enabled?"en":"dis");
if (rtprelay_enabled) {
if (!force_symmetric_rtp.empty()) {
INFO("SBC: RTP force symmetric RTP: %s\n",
force_symmetric_rtp.c_str());
}
if (msgflags_symmetric_rtp) {
INFO("SBC: P-MsgFlags symmetric RTP detection enabled\n");
}
}
INFO("SBC: SST %sabled\n", sst_enabled?"en":"dis");
INFO("SBC: SIP auth %sabled\n", auth_enabled?"en":"dis");
@ -266,7 +277,10 @@ bool SBCCallProfile::operator==(const SBCCallProfile& rhs) const {
prepaid_enabled == rhs.prepaid_enabled &&
reply_translations == rhs.reply_translations &&
append_headers == rhs.append_headers &&
refuse_with == rhs.refuse_with;
refuse_with == rhs.refuse_with &&
rtprelay_enabled == rhs.rtprelay_enabled &&
force_symmetric_rtp == rhs.force_symmetric_rtp &&
msgflags_symmetric_rtp == rhs.msgflags_symmetric_rtp;
if (sdpfilter_enabled) {
res = res &&
@ -331,6 +345,9 @@ string SBCCallProfile::print() const {
res += "prepaid_uuid: " + prepaid_uuid + "\n";
res += "prepaid_acc_dest: " + prepaid_acc_dest + "\n";
res += "rtprelay_enabled: " + string(rtprelay_enabled?"true":"false") + "\n";
res += "force_symmetric_rtp: " + force_symmetric_rtp;
res += "msgflags_symmetric_rtp: " + string(msgflags_symmetric_rtp?"true":"false") + "\n";
if (reply_translations.size()) {
string reply_trans_codes;

@ -89,6 +89,8 @@ struct SBCCallProfile {
string refuse_with;
bool rtprelay_enabled;
string force_symmetric_rtp;
bool msgflags_symmetric_rtp;
// todo: RTP transcoding mode

@ -0,0 +1,18 @@
# symmetricrtp SBC profile
#
# This implements a transparent B2BUA which relays RTP and forces
# symmetric RTP on both sides - thus being able to bridge between
# two NATed clients
# RURI/From/To defaults: transparent
#RURI=$r
#From=$f
#To=$t
## RTP relay
# enable RTP relaying (bridging):
enable_rtprelay=yes
# force symmetric RTP (start with passive mode):
rtprelay_force_symmetric_rtp=yes
# use symmetric RTP indication from P-MsgFlags flag 2
#rtprelay_msgflags_symmetric_rtp=yes

@ -21,6 +21,14 @@
# use next_hop for replies, too?
#next_hop_for_replies=yes
## RTP relay
# enable RTP relaying (bridging):
#enable_rtprelay=yes
# force symmetric RTP (start with passive mode):
#rtprelay_force_symmetric_rtp=yes
# use symmetric RTP indication from P-MsgFlags flag 2
#rtprelay_msgflags_symmetric_rtp=yes
## filters:
#header_filter=blacklist
#header_list=P-App-Param,P-App-Name

@ -41,7 +41,8 @@
AmB2BSession::AmB2BSession()
: sip_relay_only(true),
b2b_mode(B2BMode_Transparent),
rtp_relay_enabled(false)
rtp_relay_enabled(false),
rtp_relay_force_symmetric_rtp(false)
{
for (unsigned int i=0; i<MAX_RELAY_STREAMS; i++)
other_stream_fds[i] = 0;
@ -50,7 +51,8 @@ AmB2BSession::AmB2BSession()
AmB2BSession::AmB2BSession(const string& other_local_tag)
: other_id(other_local_tag),
sip_relay_only(true),
rtp_relay_enabled(false)
rtp_relay_enabled(false),
rtp_relay_force_symmetric_rtp(false)
{
for (unsigned int i=0; i<MAX_RELAY_STREAMS; i++)
other_stream_fds[i] = 0;
@ -254,8 +256,17 @@ void AmB2BSession::updateRelayStreams(const string& content_type, const string&
DBG("initializing RTP relay stream %u with remote <%s:%u>\n",
media_index, r_addr.c_str(), it->port);
relay_rtp_streams[media_index].setRAddr(r_addr, it->port);
if (sdp.remote_active || rtp_relay_force_symmetric_rtp) {
relay_rtp_streams[media_index].setPassiveMode(true);
}
media_index ++;
}
if (rtp_relay_force_symmetric_rtp) {
DBG("Symmetric RTP: forced passive mode\n");
} else if (sdp.remote_active) {
DBG("Symmetric RTP: remote NATed, RTP stream set to passive mode\n");
}
}
bool AmB2BSession::replaceConnectionAddress(const string& content_type,
@ -924,6 +935,8 @@ AmB2BCalleeSession::AmB2BCalleeSession(const AmB2BCallerSession* caller)
{
a_leg = false;
b2b_mode = caller->getB2BMode();
rtp_relay_enabled = caller->getRtpRelayEnabled();
rtp_relay_force_symmetric_rtp = caller->getRtpRelayForceSymmetricRtp();
}
AmB2BCalleeSession::~AmB2BCalleeSession() {

@ -217,6 +217,9 @@ class AmB2BSession: public AmSession
/** flag to enable RTP relay mode */
bool rtp_relay_enabled;
/** force symmetric RTP */
bool rtp_relay_force_symmetric_rtp;
/** RTP streams which receive from our side and are used
for relaying RTP from the other side */
AmRtpStream relay_rtp_streams[MAX_RELAY_STREAMS];
@ -242,6 +245,8 @@ class AmB2BSession: public AmSession
void disableRtpRelay();
/** link RTP streams of other_session to our streams */
void setupRelayStreams(AmB2BSession* from_session);
bool getRtpRelayEnabled() const { return rtp_relay_enabled; }
bool getRtpRelayForceSymmetricRtp() const { return rtp_relay_force_symmetric_rtp; }
};
class AmB2BCalleeSession;

@ -342,7 +342,6 @@ int AmRtpStream::send_raw( char* packet, unsigned int length )
return length;
}
// returns
// @param ts [out] timestamp of the received packet,
// in audio buffer relative time
@ -360,31 +359,7 @@ int AmRtpStream::receive( unsigned char* buffer, unsigned int size,
if (!rp)
return 0;
#ifndef SUPPORT_IPV6
if(passive) {
// #ifdef SUPPORT_IPV6
// struct sockaddr_storage recv_addr;
// #else
struct sockaddr_in recv_addr;
rp->getAddr(&recv_addr);
// symmetric RTP
if ((recv_addr.sin_port != r_saddr.sin_port)
|| (recv_addr.sin_addr.s_addr
!= r_saddr.sin_addr.s_addr)) {
string addr_str = get_addr_str(recv_addr.sin_addr);
int port = ntohs(recv_addr.sin_port);
setRAddr(addr_str,port);
DBG("Symmetric RTP: setting new remote address: %s:%i\n",
addr_str.c_str(),port);
// avoid comparing each time sender address
} else {
DBG("Symmetric RTP: remote end sends RTP from advertised address. Leaving passive mode.\n");
}
passive = false;
}
#endif
handleSymmetricRtp(rp);
/* do we have a new talk spurt? */
begin_talk = ((last_payload == 13) || rp->marker);
@ -534,6 +509,33 @@ void AmRtpStream::setRAddr(const string& addr, unsigned short port)
#endif
}
void AmRtpStream::handleSymmetricRtp(AmRtpPacket* rp) {
#ifndef SUPPORT_IPV6
if(passive) {
// #ifdef SUPPORT_IPV6
// struct sockaddr_storage recv_addr;
// #else
struct sockaddr_in recv_addr;
rp->getAddr(&recv_addr);
// symmetric RTP
if ((recv_addr.sin_port != r_saddr.sin_port)
|| (recv_addr.sin_addr.s_addr != r_saddr.sin_addr.s_addr)) {
string addr_str = get_addr_str(recv_addr.sin_addr);
int port = ntohs(recv_addr.sin_port);
setRAddr(addr_str,port);
DBG("Symmetric RTP: setting new remote address: %s:%i\n",
addr_str.c_str(),port);
} else {
DBG("Symmetric RTP: remote end sends RTP from advertised address."
" Leaving passive mode.\n");
}
// avoid comparing each time sender address
passive = false;
}
#endif
}
void AmRtpStream::init(const vector<SdpPayload*>& sdp_payloads)
{
if (sdp_payloads.empty()) {
@ -590,6 +592,8 @@ void AmRtpStream::bufferPacket(AmRtpPacket* p)
}
if (relay_enabled) {
handleSymmetricRtp(p);
if (NULL != relay_stream) {
relay_stream->relay(p);
}

@ -165,6 +165,9 @@ protected:
unsigned int current_send_dtmf_ts;
int send_dtmf_end_repeat;
/** handle symmetric RTP - if in passive mode, update raddr from rp */
void handleSymmetricRtp(AmRtpPacket* rp);
void relay(AmRtpPacket* p);
public:

@ -7,8 +7,8 @@ Overview
The SBC application is a highly flexible high-performance Back-to-Back
User Agent (B2BUA). It can be employed for a variety of uses, for example
topology hiding, From/To modification, enforcing SIP Session Timers,
identity change, SIP authentication. Future uses include accounting,
RTP call bridging, transcoding, call distribution.
identity change, SIP authentication, RTP relaying. Future uses include
accounting, transcoding, call distribution.
Features
--------
@ -16,6 +16,7 @@ Features
o flexible call profile based configuration
o online reload of call profiles
o From, To, RURI, Call-ID update
o RTP bridging
o Header and message filter
o adding arbitrary headers
o reply code translation
@ -24,6 +25,7 @@ Features
o call timer
o prepaid accounting
SBC Profiles
------------
All features are set in an SBC profile, which is configured in a separate
@ -273,6 +275,32 @@ set to transparent, the SDP is parsed and reconstructed (SDP sanity check).
Codecs may be filtered out by their payload names in whitelist or blacklist
modes. The payload names in the list are case-insensitive (PCMU==pcmu).
RTP relay
---------
RTP can be bridged through the SBC. Where without rtprelay, A call would go only
with the signaling through the SBC, in rtprelay mode, the connection address in
SDP messages will be replaced to the one of SEMS, such that caller and callee
send RTP media to SEMS. SEMS then relays the RTP packets between the two sides.
RTP relay can be enabled by setting
enable_rtprelay=yes
The SBC detects if UAs indicate that they are behind NAT by setting a:direction=active
in SDP, and goes into passive mode until it receives the first packet from the NATed
client, from which it learns the remote address. This mechanism is called "symmetric
RTP".
Symmetric RTP (starting in passive mode) can also be forced by setting the
rtprelay_force_symmetric_rtp=yes
sbc profile option. Symmetric RTP is enabled if rtprelay_force_symmetric_rtp
evaluates to anything other than "" (empty string), "0" or "no".
Some ser/sip-router/kamailio/*ser configurations add flag 2 in a header P-MsgFlags
header to the INVITE to indicate forcing of symmetric RTP. With the sbc profile
option
rtprelay_msgflags_symmetric_rtp=yes
the SBC honors this and sets symmetric RTP accordingly.
Adding headers
--------------
Additional headers can be added to the outgoing initial INVITE by using the
@ -388,6 +416,7 @@ Example profiles
codecfilter - let only some low bitrate codecs pass
replytranslate - swap 603 and 488 response code in replies
refuse - refuse all calls with 403 Forbidden
symmetricrtp - RTP relay with symmetric RTP for NAT handling
Dependencies
------------
@ -406,12 +435,12 @@ x SIP authentication
x session timers
x maximum call duration timer
- accounting (MySQL DB, cassandra DB)
- RTP forwarding mode (bridging)
x RTP forwarding mode (bridging)
- RTP transcoding mode (bridging)
- overload handling (parallel call to target thresholds)
- call distribution
- select profile on monitoring in-mem DB record
- fallback profile
x fallback profile
x add headers
- bridging between interfaces
- rel1xx in non-transparent mode

Loading…
Cancel
Save