With reference to my older posts in which I talked about increasing VoIP services capacity (with failover for load-balanced media-servers), then I tested the whole scenario using Kamailio and RTPproxy.This post, however, is replica of the above scenario but using OpenSIPS and RTPproxy.
in Global Parameters, This will tell opensips that server has multiple interfaces to send/receive and relay traffic in-between subnets, so modify headers wisely and accordingly.
Then parameters for each modules:
In my case, since using Virt.Environment, I consider 172.16.31.102 to be
my Public IP and transform into the internal Private subnet
192.168.30.x.
Now main routing logic:
If that user is offline, or the dialed string don't matches any user it sends "404 Not Found" back to the caller.
Now, What I'm doing over here is that once I find out that a user is offline,or is not a defined user then route the call to route(3) which is where I'll call in Load-Balancer and select a LB'd destination Media-Server and record a VoiceMail or do some other call routing.
Just after route(3); I've called route(1);. Route[1] is the default route already defined which only relays the call towards the destination. So here are these routes: Add these lines just after your main route ends.
If results in True I engage RTPproxy using flags sequence IE, if not and call is coming in from my Media-Servers to outside use RTPproxy flags in EI sequence.
See this post for more information on making RTPproxy work for you.
Now, in route[1] I added the following Highlighted code and RTPproxy started working for me.
Quit MySQL, now you can use the following commands to reload Load-balancer servers list in opensips on the fly and see the status of each FS server in opensips.
I wanted to use MediaProxy instead
of RTPprxoy but media-Proxy unfortunately is not used for bridging RTPs
from Public Internet to Private subnets and vice-versa [For details: See this forum discussion]
Following is the topology I wanted to achieve.
![]() |
OpenSIPS+RTPproxy in Action |
I used FreeSWITCH as my Media-Server layer. Asterisk servers can be used alternatively as well.
Now moving quickly to the opensips.cfg file changes required in order to make this work.
Now moving quickly to the opensips.cfg file changes required in order to make this work.
First add,
mhomed=yes
in Global Parameters, This will tell opensips that server has multiple interfaces to send/receive and relay traffic in-between subnets, so modify headers wisely and accordingly.
Then following modules needs to be declared.
(click on underlined modules to read their documentation)
loadmodule "rtpproxy.so"
loadmodule "nathelper.so"
loadmodule "dialog.so"
loadmodule "load_balancer.so"
loadmodule "avpops.so"
# ------ RTP-proxy Parameters
#RTPproxy instance to be used: 9901
#172.16.31.102<<=Transform=>> 192.168.30.3
modparam("rtpproxy", "rtpproxy_sock", "udp:127.0.0.1:9901")
NOTE[1]: My assumption of 172.16.31.102 as
Public IP has serious complications, as I understand, because the
NAT-HELPER functions will always consider traffic from this subnet as
Private rather public and this may've effect on OpenSIPS behavior, if
used in production.
NOTE[2]: Please reply back in case if there is any discrepancy or suggestion in the configurations. This is a work in progress, so I apologize in case if you find anything incorrect. Changes and Suggestions are always welcome.
NOTE[2]: Please reply back in case if there is any discrepancy or suggestion in the configurations. This is a work in progress, so I apologize in case if you find anything incorrect. Changes and Suggestions are always welcome.
# ------ AVPOPS params --------
modparam("avpops","db_url", "mysql://opensips:opensipsrw@localhost/opensips")
modparam("avpops","avp_table","usr_preferences")
modparam("avpops","use_domain",1)
# ------ NAT-Helper params ------
modparam("nathelper", "ping_nated_only", 1)
modparam("nathelper", "received_avp", "$avp(i:42)")
modparam("nathelper", "sipping_bflag", 7)
modparam("nathelper", "sipping_from", "sip:pinger@saevolgo.com")
# ----- LOAD BALANCER MODULE -----
modparam("load_balancer", "probing_interval", 30)
modparam("load_balancer", "probing_reply_codes", "501, 404")
modparam("load_balancer", "probing_from","sip:opensips@saevolgo.com")
modparam("load_balancer", "db_url","mysql://opensips:opensipsrw@localhost/opensips")
Now main routing logic:
Add Highlighted NAT test just at the start of main route. I put that just under the Max-FWD header validation check.
if (!mf_process_maxfwd_header("10")) { sl_send_reply("483","Too Many Hops"); exit; } if (nat_uac_test("19")) { xlog("L_INFO","[$pr:$fU@$si:$sp]: NAT Detection Test-19 Passed Now Fixing-Nat for '$rm' \n"); if (is_method("REGISTER")) { fix_nated_register(); } else { fix_nated_contact(); }
xlog("L_INFO","[$pr:$fU@$si:$sp]: NAT Fixed for '$rm' \n"); setflag(5); };Soon after this I could see code Logic for "BYE" method. There I need to tell (on call hangup) RTPproxy to dis-engage its ports for this particular call. if (loose_route()) {
if (is_method("BYE")) { setflag(1); # do accounting ... setflag(3); # ... even if the transaction fails unforce_rtp_proxy();Then scrolling down at the end of the main route I could see this piece of code.
I added the highlighted lines. Basically at this point the opensips default configuration searches its online sip users and if the dialed destination string is an online user it sends the call out to that user.# do lookup with method filtering
xlog("L_NOTICE","[$pr:$fU@$si:$sp]: Call from '$fu' to '$ru' LOOKUP in 'Location' table\n"); if (!lookup("location","m")) { switch ($retcode) { case -1: case -3: t_newtran(); #t_reply("404", "Not Found"); xlog("L_NOTICE","[$pr:$fU@$si:$sp]: Call from '$fu' to '$ru' User Not Found - try Dialing Media-Server\n"); route(3); route(1); case -2: sl_send_reply("405", "Method Not Allowed"); exit; } }
If that user is offline, or the dialed string don't matches any user it sends "404 Not Found" back to the caller.
Now, What I'm doing over here is that once I find out that a user is offline,or is not a defined user then route the call to route(3) which is where I'll call in Load-Balancer and select a LB'd destination Media-Server and record a VoiceMail or do some other call routing.
Just after route(3); I've called route(1);. Route[1] is the default route already defined which only relays the call towards the destination. So here are these routes: Add these lines just after your main route ends.
# Media-Server Route, Engage Load-Balancer and Select Server here.
See as simple as this to use Load-Balancer. But the real game for RTPproxy is handled in route[1] where I test if the selected destination of this call is one of my Media-Server defined in loadbalancer DB-table or not.route[3] { xlog("L_NOTICE","[$pr:$fU@$si:$sp]: This is Media-Server Route Use Load-balancer NOW!!\n"); if (!load_balance("1","calls")) { sl_send_reply("500","Service full"); exit; } xlog("L_NOTICE","[$pr:$fU@$si:$sp]: Selected destination Media-Server : $du\n"); }
If results in True I engage RTPproxy using flags sequence IE, if not and call is coming in from my Media-Servers to outside use RTPproxy flags in EI sequence.
See this post for more information on making RTPproxy work for you.
Now, in route[1] I added the following Highlighted code and RTPproxy started working for me.
route[1]{ # for INVITEs enable some additional helper routes xlog("L_INFO","[$pr:$fU@$si:$sp]: SET flags for '$rm' & Relay the Message\n"); if (is_method("INVITE")) { t_on_branch("2"); t_on_reply("2"); t_on_failure("1"); if (isflagset(5)) { xlog("L_NOTICE","[$pr:$fU@$si:$sp]: Engage Media-Proxy here\n"); xlog("L_NOTICE","[$pr:$fU@$si:$sp]: InBound-OR-OutBound Call Check!!\n"); if(avp_db_query("select dst_uri from load_balancer where dst_uri like '%$dd%'")){ #INCOMING CALL NEEDS TO GOTO PRIVATE-IP FreeSWITCH USE - IE engage_rtp_proxy("rie"); } else if(avp_db_query("select dst_uri from load_balancer where dst_uri='sip:$si:$sp'")){ #INCOMING CALL FROM PRIVATE-IP FreeSWITCH USE - EI engage_rtp_proxy("rei"); } else { engage_rtp_proxy("r"); } } }Now opensips.cfg is all done. Don;t forget to add FreeSWITCH server IPs in the loadbalancer table.
# mysql -uopensips -popensipsrw opensips
mysql>INSERT INTO load_balancer (group_id,dst_uri,resources,probe_mode,description) VALUES (1,'sip:192.168.30.4:5090','calls=50',2,'FreeSWITCH-B Server');
mysql>INSERT INTO load_balancer (group_id,dst_uri,resources,probe_mode,description) VALUES (1,'sip:192.168.30.4','calls=100',2,'FreeSWITCH-B Server');
Quit MySQL, now you can use the following commands to reload Load-balancer servers list in opensips on the fly and see the status of each FS server in opensips.
This is not all done!!
#opensipsctl fifo lb_reload
#opensipsctl fifo lb_list
FreeSWITCH SIDE CONFIGURATIONS
You need to define a gateway for OpenSIPS in your FreeSWITCH external or itnernal profile per your settings.FreeSWITCH-A:~# cd /usr/local/freeswitch/conf/sip_profiles/external/
FreeSWITCH-A:~# vim opensips.xml
Insert these Lines in this file:Reload Sofia files in FreeSWITCH. I did a whole sofia module reload.<include> <gateway name="OpenSIPS"> <param name="username" value="192.168.30.3"/> <param name="from-user" value="192.168.30.3"/> <param name="password" value="2007"/> <param name="proxy" value="192.168.30.3"/> <param name="register" value="false"/> <param name="retry-seconds" value="10"/> <param name="caller-id-in-from" value="true"/> <param name="extension-in-contact" value="true"/> <param name="ping" value="25"/> <param name="inbound-late-negotiation" value="true"/> <param name="context" value="default"/> </gateway> </include>
freeswitch@internal> reload mod_sofia
I also had to tell FreeSWITCH to allow my LAN IPs in acl.conf.xml located at
/usr/local/freeswitch/conf/autoload_configs/acl.conf.xml
<list name="lan" default="allow"> <node type="deny" cidr="192.168.30.0/24"/> </list>
Save changes in that file and reload acl.freeswitch@internal> reloadacl
Now make calls and see that calls are landing in your Public context,
there take control of your incoming calls and land to your own
context/xml files.
Thats all folks ! Hope you guys were really bored uptill here ;)
Comments