Tag Archives: TM

Kamailio Bytes – Transaction Module

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");

}

Bit of a mess but here we see the initial INVITE being branched to the 3 destinations at the same time (Parallel forking)

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()

Here we see each destination being tried sequentially