Hi All,

I have an interesting use-case where I need to place a delay between cancelling branch and retrying next one.

Background:
Running Kamailio 5.6.x

Kamailio routes requests via a freeswitch B2BUA server on select call flows (where B2BUA functionality is required).
Call flow examples:
PSTN --> Kamailio --> Freeswitch --> appserver1
PSTN --> Kamailio --> Freeswitch --> appserver2

On attempt failures, a branch retry is required from appserver1 to appserver2; however freeswitch B2BUA remains the same
Since Freeswitch does not quite follow the RFC 3261 timer K specifications (should be 0 seconds for reliable transports, but FS keeps transactions for T4 (set to 2 seconds));
I have implemented an artificial delay in failure route before retrying (as per recommendation described here: https://freeswitch-users.freeswitch.narkive.com/TsSye66D/482-request-merged-in-serial-forking-solved )

Script config:
onreply_route[MANAGE_REPLY] {
xlog("L_INFO", "reply $T_reply_code received");
if (t_check_status( "1[1-9][0-9]")) {
t_reset_fr();
} else {
t_set_fr(120000);
}
}

route(NATDETECT);
#!ifdef WITH_RTPENGINE
route(RTPMANAGE);
#!endif
}

route[RELAY] {

if (is_method("INVITE|BYE|SUBSCRIBE|UPDATE")) {
if(!t_is_set("branch_route")) t_on_branch("MANAGE_BRANCH");
}

if (is_method("INVITE|SUBSCRIBE|UPDATE")) {
if(!t_is_set("onreply_route")) t_on_reply("MANAGE_REPLY");
}

if(is_method("INVITE|BYE|UPDATE|CANCEL|ACK")) {
setflag(FLT_DLGINFO);
}

if (!t_relay()) {
sl_reply_error();
}

exit;
}

route[TOCARRIER] {
process bunch of things, attach custom headers, generate request URI

t_on_failure("MANAGE_FAILURE_CARRIER");
route(RELAY);
}

failure_route[MANAGE_FAILURE_CARRIER] {
xlog("L_INFO", "reply $T_reply_code received");
if ($avp(inbound_attempt)<=1){
if ($dlg_var(b2bua)=="true"){
usleep(1900000);
}
route("TOCARRIER");

}


Call Flows: 

The above fix works well when an explicit error reply is received back.

error reply SIP exchange:
SBC --> INVITE(branch0) ---> Freeswitch
SBC <-- 503 <-- Freeswitch
failure_route executed (sleep runs here)
SBC --> INVITE(branch1) ---> Freeswitch
call continues as expected.



however does not work when NO reply is received at all and the timer expires.
Current timer expiry SIP exchange:
SBC --> INVITE(branch0) ---> Freeswitch
SBC <-- 100/180 <-- Freeswitch
SBC (timer expires)
failure_route executed (sleep runs here)
SBC --> INVITE(branch1) ---> Freeswitch
SBC <-- 482 Merged  <-- Freeswitch
SBC --> CANCEL(branch0) ---> Freeswitch


I am looking to CANCEL branch0 before the sleep delay runs


Based on source code, t_cancel_branches("this") can only be executed in reply_route;
however the chellenge is that reply_route never sees the "faked 408" on timer expiry(although the failure route does see $T_reply_code 408).



Any suggestions on how to handle this would be greatly appreciated.

TIA