Hello Danial,

 

Thanks once again for your reply and sorry for late reply from my side.

 

>From below point No. 2, I just want to understand that "Is Kamailio process
DTMF or not".

 

Now we are working on a modal where Kamailio will be used as Proxy and
Freeswitch as Media server. I am able to route calls from Kamailio to
Freeswitch but my next requirement is that how to route call from Kamailio
to Freeswitch only when call is getting answered in Kamailio. Now what is
happening all the invite routing directly from Kamailio to Freeswitch.

 

What I have done is attached in mail. I have added *# Freeswitch routing
blocks* in Kamailio.cfg.

 

Any help would be appreciated.

 

 

Thanks,

Amit Sharma

 

From: Daniel-Constantin Mierla <mico...@gmail.com> 
Sent: Thursday, August 6, 2020 11:25 PM
To: amitsha...@coraltele.com; 'Kamailio (SER) - Users Mailing List'
<sr-users@lists.kamailio.org>
Subject: Re: [SR-Users] Call in Progress Recovery in Redundancy

 

Hello,

On 06.08.20 16:26, amitsha...@coraltele.com
<mailto:amitsha...@coraltele.com>  wrote:

Hello Daniel,

 

Thank a lot for such an elaborative reply, it will really help in many ways.
It is clear that in case of big system the Progress call transition may not
be possible.

 

I want to know two more things : 

 

1.      Can we built Re-Homing around Kamailio (Move call from Kamailio to
Freeswitch). Is there any possibility of doing it.

 

Both applications are open source and you can develop extensions in both of
them to share call data and maybe you will get what you want. But from the
SIP specification, there is no mechanism to migrate a server from a proxy
(like Kamailio) to an endpoint/b2bua like FreeSwitch. Therefore at this
moment is no option to do that.

As I mentioned, another kamailio can route just fine requests belonging to a
call initiated via another Kamailio. FreeSwitch (or other B2BUA/endpoint)
can do re-INVITE and recover the call after a crash and restart on the same
system or on another system, but that because it was part of the call and it
is allowed to change its contact/IP address 

 

2.      How can capture sip-info from Kamailio to Freeswitch. Means DTMP
pressed.

I do not understand this one, maybe you can elaborate more.

Cheers,
Daniel

3.       

 

Thanks in advance.

 

Amit Sharma

 

From: Daniel-Constantin Mierla  <mailto:mico...@gmail.com>
<mico...@gmail.com> 
Sent: Wednesday, August 5, 2020 6:33 PM
To: Kamailio (SER) - Users Mailing List
<mailto:sr-users@lists.kamailio.org> <sr-users@lists.kamailio.org>;
amitsha...@coraltele.com <mailto:amitsha...@coraltele.com> 
Subject: Re: [SR-Users] Call in Progress Recovery in Redundancy

 

Hello,

first we need to clarify that it seems you are actually not looking for
redundancy of active transactions, which I tried to focus on the answer
during the ClueCon session last evening.

My answer there related to htable was about the ability to route CANCEL
requests where the INVITE was forwarded.

Like Julien replied on another email, SIP has couple of mechanism to
"recover" or "go through" in case of transaction states being lost. For
example, with UDP if the proxy is restarted after receiving the INVITE and
not sending any reply, then there is a retranmission of the INVITE for
couple of times (can be up to 30seconds or more, depending on UA settings).
So the INVITE comes again to the proxy, which can handle it (assuming a fast
enough restart). Then, if the INVITE was forwarded, the responses to it can
be routed without any problem, using the Via headers.

Considering that the SIP transaction is about keeping the states of routing
the request until a final response is sent out, one of the main benefits is
the ability to re-route the request to a new address if the first selected
destination doesn't answer (aka, serial forking). But if you have one-to-one
routing policy (like receiving from the phone and sending to a freeswitch),
then you can also do stateless forwarding. In such case, if you migrate the
ip to another Kamailio node, it can route the replies even when the request
was routed by previous active node.

As far as I can remember from some demos at past cluecon events, the
FreeSwitch call recovery was based on re-INVITEs, which means the call has
to be established to know where to send the re-INVITE, be aware of
caller/callee contact addresses, codecs, routing headers, ... Recovering a
progress call from a B2BUA like FreeSwitch can be as difficult as for a
proxy, if you want to cover over possible scenarios related to serial and
parallel forking, branches added on the fly when a new registration comes
in, different retransmission timers per branches, storage of most relevant
replies for branches, etc ... just to enumerate from the impact on the SIP
specification, but each application has a lot of event callbacks, structures
and parameters associated with a transaction (e.g., for accounting, message
logging, ...), ... so the eco-system around a SIP transaction is very fluid,
shifting to another node could be impossible.

For example, consider that first retransmission has to be done in 500ms,
followed by 1sec, 2sec, 4sec -- in a case of a shared IP active-standby
system, detection that node is done typically takes a few seconds itself, so
retransmission steps can be lost for sure.

Kamailio itself is not a B2BUA so it cannot re-INVITE inside a call, but
many Kamailio systems can route SIP requests/replies from the same call
(e.g., INVITE routed by Kamailio A and the BYE by Kamailio B), it is a
matter of what you set in Record-Route headers, or do anycast routing to a
cluster of Kamailio nodes. When you hear about getting out of the call, is
about RTP (audio/video) streams, because from signaling point of view, a
B2BUA is an endpoint in each of the two legs of the calls, it can do
re-INVITE to move RTP streams to be end-to-end, but it has to stay in the
signaling path. An endpoint can get out of the call via a transfer to
another endpoint, but then it cannot transfer the call back to it.

Also, let's say the call is completed without going to freeswitch with the
initial INVITE, afterward you cannot hand it over to Freeswitch. But you can
route initial INVITE to Kamailio, do not do record-routing, and send it to
freeswitch. By not doing record-routing, requests within dialog (re-INVITE,
BYE, etc..) and not coming to Kamailio, they go directly to FreeSwitch. But
you have to be careful with natted devices, typically they can get messages
back only from the box where they sent the initial INVITE.

The discussion can be long here, as I tried to say, if you have the very
simple scenario of one-to-one routing rule, then even going
(sip-transaction-)stateless can work, but to cover all cases with
parallel/serial forking and multiple active branches at different stages of
processing is not working.

My feeling is that you were thinking from your experience with
freeswitch/b2bua systems, where when you restart the b2bua in a ringing
state the call does not complete. But if use Kamailio to route the call from
Alice to Bob, it gets to ringing state, then you can restart kamailio and
call gets completed (the answer -- the 200ok response -- is routed by
Kamailio correctly). Of course, depending on what other modules you use,
some specific processing may be lost for such calls, but case by case, there
can be solutions.

Cheers,
Daniel

On 05.08.20 12:36, amitsha...@coraltele.com
<mailto:amitsha...@coraltele.com>  wrote:

Dear Daniel/Team,

 

I had raised one question in "Workshop 3 - Kamailio" at Cluecon 2020(Last
Night), i.e. Can Progress Call(Ringing Calls) be recovered in case of
redundancy with Kamailio. You were told me that straight way it is not
possible but try with hash table once. I had tried following link
https://wazo-platform.org/blog/kamailio-ha-dispatcher-and-dmq and able to
recover Call in progress within 2-3 nodes.

 

1.      My one question is that either this approach will work in production
or not.
2.      I have been using Freeswitch for last 6-7 years but "Call in
Progress Recovery in Redundancy" is not possible there in "Freeswitch", So I
tried Kamailio and got success. My Second question is that can it be
possible that Call established on Kamailio and after call set up Kamailio
leave that call and handed over it to Freeswitch for further processing(Like
Re-homing available in OpenSIPS). This will save years of time that I have
invested building features around Freeswitch.

 

Please suggest me the best way possible to achieve this.

 

 

 

Thanks & Regards,

Amit Sharma

(Sr. Team Leader)

 

 


(An ISO 9001:2008 company)

 

Mobile:  <tel:9891612004> tel:9891612004

PH:  +91 120 2595870

Ext.:  <tel:870> tel:870

Email :  <mailto:amitsha...@coraltele.com> amitsha...@coraltele.com

Web :  <blocked::http://www.coraltele.com> www.coraltele.com

 



 






_______________________________________________
Kamailio (SER) - Users Mailing List
sr-users@lists.kamailio.org <mailto:sr-users@lists.kamailio.org> 
https://lists.kamailio.org/cgi-bin/mailman/listinfo/sr-users

-- 
Daniel-Constantin Mierla -- www.asipto.com <http://www.asipto.com> 
www.twitter.com/miconda <http://www.twitter.com/miconda>  --
www.linkedin.com/in/miconda <http://www.linkedin.com/in/miconda> 
Funding: https://www.paypal.me/dcmierla

-- 
Daniel-Constantin Mierla -- www.asipto.com <http://www.asipto.com> 
www.twitter.com/miconda <http://www.twitter.com/miconda>  --
www.linkedin.com/in/miconda <http://www.linkedin.com/in/miconda> 
Funding: https://www.paypal.me/dcmierla
        ####### Routing Logic ########
/* Main SIP request routing logic
 * - processing of any incoming SIP request starts with this route
 * - note: this is the same as route { ... } */
request_route {
        # per request initial checks
        route(REQINIT);
        # NAT detection
        route(NAT);
        
        # handle requests within SIP dialogs    
        route(WITHINDLG);       
        ### only initial requests (no To tag)   
        # CANCEL processing     
        if (is_method("CANCEL"))        
        {       
                if (t_check_trans())    
                        t_relay();      
                exit;   
        }

        t_check_trans();        
        # authentication        
        route(AUTH);    
        # record routing for dialog forming requests (in case they are routed)  
        # - remove preloaded route headers      
        remove_hf("Route");     
        if (is_method("INVITE|SUBSCRIBE"))      
                record_route(); 
# account only INVITEs  
        if (is_method("INVITE"))        
        {       
                setflag(FLT_ACC); # do accounting       
        }       
        # dispatch requests to foreign domains  
        route(SIPOUT);  
        ### requests for my local domains       
        # handle presence related requests      
        route(PRESENCE);        
        # handle registrations  
        route(REGISTRAR);       
        if ($rU==$null) 
        {       
                # request with no Username in RURI      
                sl_send_reply("484","Address Incomplete");      
                exit;   
        }       
        # dispatch destinations to PSTN 
        route(PSTN);    
        #!ifdef WITH_FREESWITCH 
        # save callee ID        
        $avp(callee) = $rU;     
        route(FSDISPATCH);      
        #!endif 
        # user location service 
        route(LOCATION);        
        route(RELAY);   
}       

route[RELAY] {  
#!ifdef WITH_NAT        
        if (check_route_param("nat=yes")) {     
                setbflag(FLB_NATB);     
        }       
        if (isflagset(FLT_NATS) || isbflagset(FLB_NATB)) {      
                route(RTPPROXY);        
        }       
#!endif

#!ifdef WITH_CFGSAMPLES 
        /* example how to enable some additional event routes */        
        if (is_method("INVITE")) {      
                #t_on_branch("BRANCH_ONE");     
                t_on_reply("REPLY_ONE");        
                t_on_failure("FAIL_ONE");       
        }       
#!endif

if (!t_relay()) {       
                sl_reply_error();       
        }       
        exit;   
}       
# Per SIP request initial checks        
route[REQINIT] {
#!ifdef WITH_ANTIFLOOD  
        # flood dection from same IP and traffic ban for a while        
        # be sure you exclude checking trusted peers, such as pstn gateways     
        # - local host excluded (e.g., loop to self)    
        if(src_ip!=myself)      
        {       
                if($sht(ipban=>$si)!=$null)     
                {       
                        # ip is already blocked 
                        xdbg("request from blocked IP - $rm from $fu 
(IP:$si:$sp)\n");  
                        exit;   
                }       
                if (!pike_check_req())  
                {       
                        xlog("L_ALERT","ALERT: pike blocking $rm from $fu 
(IP:$si:$sp)\n");     
                        $sht(ipban=>$si) = 1;   
                        exit;   
                }       
        }       
#!endif

if (!mf_process_maxfwd_header("10")) {  
                sl_send_reply("483","Too Many Hops");   
                exit;   
        }       
        if(!sanity_check("1511", "7"))  
        {       
                xlog("Malformed SIP message from $si:$sp\n");   
                exit;   
        }       
}

# Handle requests within SIP dialogs    
route[WITHINDLG] {      
        if (has_totag()) {      
                # sequential request withing a dialog should    
                # take the path determined by record-routing    
                if (loose_route()) {    
                        if (is_method("BYE")) { 
                                setflag(FLT_ACC); # do accounting ...   
                                setflag(FLT_ACCFAILED); # ... even if the 
transaction fails     
                        }
                        route(RELAY);   
                } else {        
                        if (is_method("SUBSCRIBE") && uri == myself) {  
                                # in-dialog subscribe requests  
                                route(PRESENCE);        
                                exit;   
                        }       
                        if ( is_method("ACK") ) {       
                                if ( t_check_trans() ) {        
                                        # no loose-route, but stateful ACK;     
                                        # must be an ACK after a 487    
                                        # or e.g. 404 from upstream server      
                                        t_relay();      
                                        exit;   
                                } else {        
                                        # ACK without matching transaction ... 
ignore and discard       
                                        exit;   
                                }       
                        }       
                        sl_send_reply("404","Not here");        
                }       
                exit;   
        }       
}

# Handle SIP registrations      
route[REGISTRAR] {      
        if (is_method("REGISTER"))      
        {       
                if(isflagset(FLT_NATS)) 
                {       
                        setbflag(FLB_NATB);     
                        # uncomment next line to do SIP NAT pinging     
                        ## setbflag(FLB_NATSIPPING);    
                }       
                if (!save("location"))  
                        sl_reply_error();       
                exit;   
        }       
}

# USER location service 
route[LOCATION] {       
#!ifdef WITH_ALIASDB    
        # search in DB-based aliases    
        alias_db_lookup("dbaliases");   
#!endif 
        if (!lookup("location")) {      
                switch ($rc) {  
                        case -1:        
                        case -3:        
                                t_newtran();    
                                t_reply("404", "Not Found");    
                                exit;   
                        case -2:        
                                sl_send_reply("405", "Method Not Allowed");     
                                exit;   
                }       
        }       
        # when routing via usrloc, log the missed calls also    
        if (is_method("INVITE"))        
        {       
                setflag(FLT_ACCMISSED); 
        }       
}

# Presence server route 
route[PRESENCE] {       
        if(!is_method("PUBLISH|SUBSCRIBE"))     
                return; 
#!ifdef WITH_PRESENCE   
        if (!t_newtran())       
        {       
                sl_reply_error();       
                exit;   
        };      
        if(is_method("PUBLISH"))        
        {       
                handle_publish();       
                t_release();    
        }       
        else    
        if( is_method("SUBSCRIBE"))     
        {       
                handle_subscribe();     
                t_release();    
        }       
        exit;   
#!endif 
        # if presence enabled, this part will not be executed   
        if (is_method("PUBLISH") || $rU==$null) 
        {       
                sl_send_reply("404", "Not here");       
                exit;   
        }       
        return; 
}

        # Authentication route  
route[AUTH] {   
#!ifdef WITH_AUTH       
        if (is_method("REGISTER"))      
        {       
                # authenticate the REGISTER requests (uncomment to enable auth) 
                if (!www_authorize("$td", "subscriber"))        
                {       
                        www_challenge("$td", "0");      
                        exit;   
                }       
                if ($au!=$tU)   
                {       
                        sl_send_reply("403","Forbidden auth ID");       
                        exit;   
                }       
        } else {        
#!ifdef WITH_FREESWITCH 
        if(route(FSINBOUND))    
                return; 
#!endif 
#!ifdef WITH_IPAUTH     
                if(allow_source_address())      
                {       
                        # source IP allowed     
                        return; 
                }       
#!endif 

# authenticate if from local subscriber 
                if (from_uri==myself)   
                {       
                        if (!proxy_authorize("$fd", "subscriber")) {    
                                proxy_challenge("$fd", "0");    
                                exit;   
                        }       
                        if (is_method("PUBLISH"))       
                        {       
                                if ($au!=$tU) { 
                                        sl_send_reply("403","Forbidden auth 
ID");       
                                        exit;   
                                }       
                        } else {        
                                if ($au!=$fU) { 
                                        sl_send_reply("403","Forbidden auth 
ID");       
                                        exit;   
                                }       
                        }       
                        consume_credentials();  
                        # caller authenticated  
                } else {        
                        # caller is not local subscriber, then check if it 
calls        
                        # a local destination, otherwise deny, not an open 
relay here   
                        if (!uri==myself)       
                        {       
                                sl_send_reply("403","Not relaying");    
                                exit;   
                        }       
                }       
        }       
#!endif 
        return; 
}       
# Caller NAT detection route    
route[NAT] {    
#!ifdef WITH_NAT        
        force_rport();  
        if (nat_uac_test("19")) {       
                if (method=="REGISTER") {       
                        fix_nated_register();   
                } else {        
                        fix_nated_contact();    
                }       
                setflag(FLT_NATS);      
        }       
#!endif 
        return; 
}       
# RTPProxy control      
route[RTPPROXY] {       
#!ifdef WITH_NAT        
        if (is_method("BYE")) { 
                unforce_rtp_proxy();    
        } else if (is_method("INVITE")){        
                force_rtp_proxy();      
        }       
        if (!has_totag()) add_rr_param(";nat=yes");     
#!endif 
        return; 
}       
# Routing to foreign domains    
route[SIPOUT] { 
        if (!uri==myself)       
        {       
                append_hf("P-hint: outbound\r\n");      
                route(RELAY);   
        }       
}       
# PSTN GW routing       
route[PSTN] {   
#!ifdef WITH_PSTN       
        # check if PSTN GW IP is defined        
        if (strempty($sel(cfg_get.pstn.gw_ip))) {       
                xlog("SCRIPT: PSTN rotuing enabled but pstn.gw_ip not 
defined\n");      
                return; 
        }       
        # route to PSTN dialed numbers starting with '+' or '00'        
        #     (international format)    
        # - update the condition to match your dialing rules for PSTN routing   
        if(!($rU=~"^(\+|00)[1-9][0-9]{3,20}$")) 
                return; 
        # only local users allowed to call      
        if(from_uri!=myself) {  
                sl_send_reply("403", "Not Allowed");    
                exit;   
        }       
        $ru = "sip:" + $rU + "@" + $sel(cfg_get.pstn.gw_ip);    
        route(RELAY);   
        exit;   
#!endif 
        return; 
}

# JSONRPC over HTTP(S) routing
#!ifdef WITH_JSONRPC
event_route[xhttp:request] {
        set_reply_close();
        set_reply_no_connect();
        if(src_ip!=127.0.0.1) {
                xhttp_reply("403", "Forbidden", "text/html",
                                "<html><body>Not allowed from 
$si</body></html>");
                exit;
        }
        if ($hu =~ "^/RPC") {
                jsonrpc_dispatch();
                exit;
        }
        xhttp_reply("200", "OK", "text/html",
                                "<html><body>Wrong URL $hu</body></html>");
    exit;
}
#!endif

#!ifdef WITH_FREESWITCH 
# FreeSWITCH routing blocks     
route[FSINBOUND] {      
        if($si== $sel(cfg_get.freeswitch.bindip)        
                        && $sp==$sel(cfg_get.freeswitch.bindport))      
                return 1;       
        return -1;      
}       
route[FSDISPATCH] {     
        if(!is_method("INVITE"))        
                return; 
        if(route(FSINBOUND))    
                return; 
        # dial number selection 
        switch($rU) {   
                case /"^41$":   
                        # 41 - voicebox menu    
                        # allow only authenticated users        
                        if($au==$null)  
                        {       
                                sl_send_reply("403", "Not allowed");    
                                exit;   
                        }       
                        $rU = "vm-" + $au;      
                break;  
                case /"^441[0-9][0-9]$":        
                        # starting with 44 folowed by 1XY - direct call to 
voice box    
                        strip(2);       
                        route(FSVBOX);  
                break;  
                case /"^433[01][0-9][0-9]$":    
                        # starting with 433 folowed by (0|1)XY - conference     
                        strip(2);       
                break;  
                case /"^45[0-9]+$":     
                        strip(2);       
                break;  
                default:        
                        # offline - send to voicebox    
                        if (!registered("location"))    
                        {       
                                route(FSVBOX);  
                                exit;   
                        }       
                        # online - do bridging  
                        prefix("kb-");  
                        if(is_method("INVITE")) 
                        {       
                                # in case of failure - re-route to FreeSWITCH 
VoiceMail 
                                t_on_failure("FAIL_FSVBOX");    
                        }       
        }       
        route(FSRELAY); 
        exit;   
}       
route[FSVBOX] { 
        if(!($rU=~"^1[0-9][0-9]+$"))    
                return; 
        prefix("vb-");  
        route(FSRELAY); 
}       
# Send to FreeSWITCH    
route[FSRELAY] {        
        $du = "sip:" + $sel(cfg_get.freeswitch.bindip) + ":"    
                        + $sel(cfg_get.freeswitch.bindport);    
        if($var(newbranch)==1)  
        {       
                append_branch();        
                $var(newbranch) = 0;    
        }       
        route(RELAY);   
        exit;   
}       
#!endif 
# Sample branch router  
branch_route[BRANCH_ONE] {      
        xdbg("new branch at $ru\n");    
}       
# Sample onreply route  
onreply_route[REPLY_ONE] {      
        xdbg("incoming reply\n");       
#!ifdef WITH_NAT        
        if ((isflagset(FLT_NATS) || isbflagset(FLB_NATB))       
                        && status=~"(183)|(2[0-9][0-9])") {     
                force_rtp_proxy();      
        }       
        if (isbflagset("6")) {  
                fix_nated_contact();    
        }       
#!endif 
}


# Sample failure route  
failure_route[FAIL_ONE] {       
#!ifdef WITH_NAT        
        if (is_method("INVITE") 
                        && (isbflagset(FLB_NATB) || isflagset(FLT_NATS))) {     
                unforce_rtp_proxy();    
        }       
#!endif 
        if (t_is_canceled()) {  
                exit;   
        }       
        # uncomment the following lines if you want to block client     
        # redirect based on 3xx replies.        
        ##if (t_check_status("3[0-9][0-9]")) {  
        ##t_reply("404","Not found");   
        ##      exit;   
        ##}     
        # uncomment the following lines if you want to redirect the failed      
        # calls to a different new destination  
        ##if (t_check_status("486|408")) {      
        ##      sethostport("192.168.2.100:5060");      
        ##      append_branch();        
        ##      # do not set the missed call flag again 
        ##      t_relay();      
        ##}     
}       
#!ifdef WITH_FREESWITCH 
failure_route[FAIL_FSVBOX] {    
#!ifdef WITH_NAT        
        if (is_method("INVITE") 
                        && (isbflagset(FLB_NATB) || isflagset(FLT_NATS))) {     
                unforce_rtp_proxy();    
        }       
#!endif 
        if (t_is_canceled()) {  
                exit;   
        }       
        if (t_check_status("486|408")) {        
                # re-route to FreeSWITCH VoiceMail      
                $rU = $avp(callee);     
                $var(newbranch) = 1;    
                route(FSVBOX);  
        }       
}       
#!endif 
_______________________________________________
Kamailio (SER) - Users Mailing List
sr-users@lists.kamailio.org
https://lists.kamailio.org/cgi-bin/mailman/listinfo/sr-users

Reply via email to