Thursday, August 9, 2012

How to setup failover for multiple SIP Trunks?

 

Problem Statement:
Note: ITSP stands for Internet Telephony Service Provider
Inbound call stands for call coming from ITSP to Asterisk
Outboud call stands for call from Asterisk to ITSP
ServerA and ServerB stands for Asterisk server at location A and B.
I have also made an assumption that you know how to install asterisk and configure SIP Peers/Trunks. 

I have two SIP Trunks (Trunk_A and Trunk_B) from ITSP coming into two Asterisk servers at different physical location.

Inbound call is not an issue. ITSP periodically checks if servers are available. If ServerA dies, incoming call comes only to serverB. If ITSP sees that serverA is alive, ITSP starts sending call to ServerA. [Note: No manual intervention involved here]

I would like to achieve something similar to above in Asterisk for outbound calls. I want Asterisk to periodically check if trunks are alive or not. If TrunkA fails, it shouldn't send the call to TrunkA. Once TrunkA is alive, it should start sending call to it. 

Problem Solution:

I did the following to address my problem

SIP configuration in ServerA

file: /etc/asterisk/sip.conf
----
-----
-----
[sip_trunkA-out]
type = peer
fromdomain = serverA_IP_address
host = ITSP_A_IP_address
qualify=yes
qualifyfreq=30 ; Qualification: How often to check for the host to be up in seconds
; and reported in milliseconds with sip show settings.
; Set to low value if you use low timeout for NAT of UDP sessions
qualifygap=60 ; Number of milliseconds between each group of peers being qualified



Dial plan in ServerA

file:/etc/asterisk/extensions.conf

exten => _XXXXXXXXXX,1,Verbose(1,--- Dialing out from Trunk A)
  same => n,Set(NETWORKSTATUS=${SIPPEER(sip_trunkA-out,status)})
  same => n,Gotoif($[NETWORKSTATUS=UNREACHABLE]?trunkB:trunkA)
  same => n(trunkA),Dial(SIP/sip_trunkA-out/${EXTEN:1})
  same => n,Hangup
  same => n(trunkB),Dial(SIP/ServerB/${EXTEN})
  same => n,Hangup



Do the similar SIP configuration and dialplan on ServerB.

Dialplan Logic: If TrunkA is unreachable from ServerA, use TrunkB through ServerB. Similarly if TrunkB is unreachable from ServerB, use TrunkA through ServerA. SIPPEER() function is used to retrieve the status of SIP Trunk/Peer.
Please also note that you might have to customize the dialplan to meet your requirement

I have posted this solution at asterisk.org forum as well.

Monday, March 19, 2012

How to set the concurrent calls limit on SIP trunk in Asterisk?

Have you ever wanted to setup the concurrent calls limit on SIP trunk in Asterisk System? Ok, then you are in the right place to find your answers.


Scenario:

Suppose Server2 is from third party and we don't have a control over it. So, it can send any amount of calls to Server1. Our job is to limit the number of concurrent calls from Server2 to Server1. Thus, we will be working on Server1 to achieve our goal.


Method1:

If you are using Asterisk system, you might have already known that SIP Peer is also know as SIP trunk.
There is an easy way to set it up in SIP trunk/peer configuration using call-limit parameter.  (Warning!! This parameter is deprecated and Asterisk strongly discourages to use it)

#vi sip.conf
   context=mydefaultContext

   [SIPTrunkFORserver2]
   type=peer
   fromdomain=server1_IP_add
   host=server2_IP_add
   outboundproxy=server2_IP_add
   call-limit=100    
;Here I am limiting to 100 max concurrent calls thru' this trunk 
   context=FromServer2Trunk   
;Call from this trunk lands to [FromServer2Trunk] context

Pros: It's easy to implement
Cons: It's deprecated parameter, so it may not be available in future versions of Asterisk. (Luckily it is available in 1.8). I found that it requires Asterisk Restart when you want to remove call-limit parameter.


Method2 (preferred):

Looking at cons of using call-limit, I decided not to use it even though I found it to be really easy implementation. Similar goal can be achieved via the use of GROUP() and GROUP-COUNT() functions available in Asterisk Dialplan. You don't have to make any adjustments on SIP Trunk configuration for call limit (which  is good thing).

GROUP() function defines the trunk group
GROUP_COUNT() function returns the number of concurrent calls on the given trunk group


#vi sip.conf
#SIP configuration on Server1
   context=mydefaultContext

   [SIPTrunkFORserver2]
   type=peer
   fromdomain=server1_IP_add
   host=server2_IP_add
   outboundproxy=server2_IP_add
   call-limit=100    
   context=FromServer2Trunk   
;Call from this trunk lands to [FromServer2Trunk] context
 We are directing the call from server2 to [FromServer2Trunk] context in our dialplan.

#vi extensions.conf
#Asterisk dialplan on Server1

   [FromServer2Trunk]
   exten => _X.,1,Verbose(1,***** Server2  dialing ${EXTEN} *******)
        same => n,Set(GROUP()=server2Trunkgroup)
        same => n,Verbose(1,**** Number of concurrent calls are ${GROUP_COUNT(server2Trunkgroup)})
        same => n,GotoIf($[${GROUP_COUNT(server2Trunkgroup)} > 100]?999)
        same => n,Dial(SIP/telco/${EXTEN})

        same => 999,Verbose(1,***Number of concurrent calls are ${GROUP_COUNT(server2Trunkgroup)}  over limit)
        same => n,Set(DIALSTATUS=CHANUNAVAIL)

Since we are directing only the calls from Server2 to [FromServer2Trunk] context in our dialplan in Server1, we can safely use GROUP() function to define the name of the trunk group associated with the incoming calls from Server2. I named it as server2Trunkgroup

Now we can use GROUP_COUNT(server2Trunkgroup) to count the number of concurrent-calls flowing in to Server1 from Server2. We can use GotoIf statement to compare the concurrent calls with threshold value (say 100 in my case). If number of concurrent calls are less than threshold value, accept the call, otherwise drop the call with channel status: CHANUNAVAIL. 

You can implement more sophisticated logic to achieve your goal. 
I hope this helped you. Good Luck!