We talked a little about the Transaction module and using it for Transaction Stateful SIP Proxy, but it’s worth knowing a bit more about the Transaction Module and the powerful functions it offers.
So today I’ll cover some cool functionality TM offers!
Different Reply Routes
By calling the t_on_reply(); we can specify the reply route to be used for replies in this transaction.
route[RELAY]{
#Use reply route "OurReplyRoute" for responses for this transaction
t_on_reply("OurReplyRoute");
#Relay (aka Forward) the request
t_relay_to_udp("192.168.3.118", "5060");
}
onreply_route[OurReplyRoute] {
#On replies from route[RELAY]
#Check our AVP we set in the initial request
xlog("for $rs response the value of AVP \"state_test_var\" is $avp(state_test_var) ");
#Append a header so we can see this was proxied in the SIP capture
append_hf("X-Proxied: For the reply\r\n");
}
Any responses from the route[RELAY] routing block will go to onreply_route[OurReplyRoute], the beauty of this is it allows you to have multiple reply routes each with their own logic. For example for a call leg to a carrier you may want to preserve CLI, but for a call leg to a customer you may wish to restrict it if that’s the option the user has selected, and you can make these changes / modifications in the reply messages.
Failure Routes
Failure routes allow the transaction module to know to try again if a call fails, for example if no response is received from the destination, send it to a different destination, like a backup.
route[RELAY]{
#Use reply route "OurReplyRoute" for responses for this transaction
t_on_reply("OurReplyRoute");
t_on_failure("OurFailureRoute");
#Relay (aka Forward) the request
t_relay_to_udp("192.168.1.118", "5060");
}
failure_route[OurFailureRoute]{
xlog("At failure route");
t_reply("500", "Remote end never got back to us");
exit;
}
We can build upon this, and try a different destination if the first one fails:
request_route {
#Enable record_routing so we see the BYE / Re-INVITE etc
record_route();
#Handle Registrations in a dumb way so they don't messy our tests
if(is_method("REGISTER")){
sl_reply("200", "ok");
exit;
}
#Append a header so we can see this was proxied in the SIP capture
append_hf("X-Proxied: You betcha\r\n");
if(is_method("INVITE")){
#Createa new AVP called "state_test_var" and set the value to "I remember"
$avp(state_test_var) = "I remember";
}
#Let syslog know we've set the value and check it
xlog("for $rm the value of AVP \"state_test_var\" is $avp(state_test_var) ");
#Send to route[RELAY] routing block
rewritehostport("nonexistentdomain.com");
route(RELAY);
}
route[RELAY]{
#Use reply route "OurReplyRoute" for responses for this transaction
t_on_reply("OurReplyRoute");
t_on_failure("OurFailureRoute");
#Relay (aka Forward) the request
t_relay();
}
failure_route[OurFailureRoute]{
xlog("At failure route");
#t_reply("500", "Remote end never got back to us");
rewritehostport("192.168.3.118");
append_branch();
t_relay();
}
onreply_route[OurReplyRoute] {
#On replies from route[RELAY]
#Check our AVP we set in the initial request
xlog("for $rs response the value of AVP \"state_test_var\" is $avp(state_test_var) ");
#Append a header so we can see this was proxied in the SIP capture
append_hf("X-Proxied: For the reply\r\n");
}
One thing to keep in mind is that there’s lots of definitions of failure, for example if you are sending a call to a carrier and get a 404 response back, you probably want to relay that through to the end user, because that destination isn’t there.
But if you get back a 5xx series response you may consider that to be a failure and select the next carrier for example.
Different conditions / requirements have different definitions of “failures” and so there’s a lot to think about when implementing this, along with timeouts for no replies, TCP session management, etc.
Parallel Forking the Call to Multiple Destinations
Parallel Forking is a fancy way of saying ring multiple destinations at the same time.
/* Main SIP request routing logic
* - processing of any incoming SIP request starts with this route
* - note: this is the same as route { ... } */
request_route {
#Enable record_routing so we see the BYE / Re-INVITE etc
record_route();
#Handle Registrations in a dumb way so they don't messy our tests
if(is_method("REGISTER")){
sl_reply("200", "ok");
exit;
}
#Append a header so we can see this was proxied in the SIP capture
append_hf("X-Proxied: You betcha\r\n");
if(is_method("INVITE")){
#Createa new AVP called "state_test_var" and set the value to "I remember"
$avp(state_test_var) = "I remember";
}
#Let syslog know we've set the value and check it
xlog("for $rm the value of AVP \"state_test_var\" is $avp(state_test_var) ");
#Send to route[RELAY] routing block
route(RELAY);
}
route[RELAY]{
#Use reply route "OurReplyRoute" for responses for this transaction
t_on_reply("OurReplyRoute");
#Append branches for each destination we want to forward to
append_branch("sip:[email protected]");
append_branch("sip:[email protected]");
append_branch("sip:[email protected]");
t_on_failure("OurFailureRoute");
#Relay (aka Forward) the request
t_relay();
}
failure_route[OurFailureRoute]{
xlog("At failure route");
t_reply("500", "All those destinations failed us");
}
onreply_route[OurReplyRoute] {
#On replies from route[RELAY]
#Check our AVP we set in the initial request
xlog("for $rs response the value of AVP \"state_test_var\" is $avp(state_test_var) ");
#Append a header so we can see this was proxied in the SIP capture
append_hf("X-Proxied: For the reply\r\n");
}
Serial Forking / Sequential Forking the calls to Multiple Destinations one after the Other
This could be used to try a series of weighted destinations and only try the next if the preceding one fails:
/* Main SIP request routing logic
* - processing of any incoming SIP request starts with this route
* - note: this is the same as route { ... } */
request_route {
#Enable record_routing so we see the BYE / Re-INVITE etc
record_route();
#Send to route[RELAY] routing block
route(RELAY);
}
route[RELAY]{
#Use reply route "OurReplyRoute" for responses for this transaction
t_on_reply("OurReplyRoute");
append_branch("sip:[email protected]", "0.3");
append_branch("sip:[email protected]", "0.2");
append_branch("sip:[email protected]", "0.1");
t_load_contacts();
t_next_contacts();
t_on_failure("OurFailureRoute");
#Relay (aka Forward) the request
t_relay();
break;
}
failure_route[OurFailureRoute]{
xlog("At failure route - Trying next destination");
t_on_failure("OurFailureRoute");
t_relay();
}
onreply_route[OurReplyRoute] {
#On replies from route[RELAY]
#Append a header so we can see this was proxied in the SIP capture
append_hf("X-Proxied: For the reply\r\n");
}
Again this will try each destination, but one after the other based on the weight we added to each destination in the append_branch()
Hello to you I have been following this tutorial series for a long time on the kamailio SIP server, I would like you to deepen this part on the stateful server and the means of implementing the one with the billing of calls and also an example practical with serial forking
Thanks a lot to you !
Dear Nick,
I followed the way to use serial and parallel fork.
I am using RTPENGINE and the audio doesn’t routed.
Any highlight where the route NATMANAGE needs to be applied ?