Wednesday, March 6, 2019

SIP/Kamaiio not-reachable endpoints and timers.

According to RFC3261 we have following mechanism of reliability:
(3 next blocks are taken from this book)


For non-INVITE transactions, a SIP timer, T1, is started by a UAC or a stateful proxy server when a new request is generated or sent. If no response to the request (as identified by a response containing the identical local tag, remote tag, Call-ID, and CSeq) is received when T1 expires, the request is resent. After a request is retransmitted, the next timer period is doubled until T2 is reached. 
If a provisional (informational class 1xx) response is received, the UAC or stateful proxy server immediately switches to timer T2. After that, the remaining retrans- missions occur at T2 intervals. This capped exponential backoff process is continued until a 64*T1, after which the request is declared dead. 


For an INVITE transaction, the retransmission scheme is slightly different. INVITEs are retransmitted starting at T1, and then the timer is doubled after each retransmission. The INVITE is retransmitted until 64*T1 after which the request is declared dead. After a provisional (1xx) response is received, the INVITE is never retransmitted. A stateful proxy must store a forwarded request or generated response message for 32 seconds. 

Suggested default values for T1 and T2 are 500 ms and 4 seconds, respectively. Timer T1 is supposed to be an estimate of the roundtrip time (RTT) in the network.

Main problem here is if remote side is dead, that we can get it after only 32 seconds. Which is too big, especially when we have some conditions like forward on not reachable. So, normally, decision is taken after not receiving provisional (1xx) response after 5 (or less) seconds. 

Kamailio has a fr_timer to control these type of behavior. By default, it's fully compatible with RFC. But it's not what we need. So, idea is to have fr_timer small initially and then - restore it on receiving provisional reply.

...
route[ON_START_TRANSACTION] {
    t_set_fr(INVITE_TIMEOUT, 2000);
    route(REAY);
}
...
reply_route {
   ...
    if(status =~ "1[0-9][0-9]") {
        # Not set INVITE TIMEOUT here to prevent possible custom values
        t_set_fr(0, 30000);
    }
   ...
}

failure_route {
    ....
    # Restore timers if was reset.
    t_set_fr(INVITE_TIMEOUT, 2000);
    ....
    route(TRY_NEXT_DESTINATION);
}
...

No comments:

Post a Comment