[SR-Users] Accounting only the 2nd branch of missed serial forked call

Ozren Lapcevic ozren.lapcevic at gmail.com
Mon Sep 5 14:41:14 CEST 2011


Hi,

I'm having some problems accounting missed serial forked calls to mysql
database.

I have following setup. Each user can have up to two contacts: telephone
number (routed to asterisk) and SIP URI. Users can specify which contact has
higher priority - which one should ring first. There is also SEMS voicemail
which is forked as 3rd serial call leg if there is no answer at first two
contacts.

For example, I have two users: oz at abc.hr and pero at abc.hr. pero at abc.hr also
has set telephone number as alternative number if he is not reachable at
sip:pero at abc.hr. Moreover, pero at abc.hr has voicemail turned on. When
oz at abc.hr calls pero at abc.hr, first pero at abc.hr's SIP client rings, then if
there is no answer and after the timeout telephone number rings and finally,
if there is no answer at telephone and after the timeout INVITE is forked to
SEMS.

There are two interesting scenarios accounting-wise which can happened:
1. oz at abc.hr calls pero at abc.hr, there are no answers and call is forked to
voicemail.
2. oz at abc.hr calls pero at abc.hr, there is no answer at SIP client, but pero
answers call at telephone.

When scenario 1 happens, I want to have only one log (row) in missed_calls
table.

When scenario 2 happens, I don't want to have a log in missed_calls table.

To accomplish this,* I want to log only the 2nd branch of the forked call.
However, there is either a bug in acc module or I'm doing something wrong,
and I can't get Kamailio to log only the 2nd branch*. I think that I am
setting the FLT_ACCMISSED flag correctly - after the 2nd branch is handled
and prior to calling the RELAY route. Logs show that FLT_ACCMISSED flag is
set prior to calling t_relay(), and there are no errors in debug log. I am
using $ru = "something" to rewrite URI prior to forking request.

I can easily set up logging of every call (two missed calls for serially
forked call to two locations) by setting FLT_ACCMISSED flag for each INVITE.
I can set up logging of every call's 1st branch, by reseting FLT_ACCMISSED
flag when handling 2nd branch of the call. Interestingly, logging of only
the 2nd branch of the serial forked call works when there is no forking to
voicemail!

Any ideas how to solve this problem?

Bellow are important parts of my config file. I'm running kamailio 3.1.4.

Cheers
Ozren


# ----- acc params -----
/* what special events should be accounted ? */
modparam("acc", "early_media", 0)
modparam("acc", "report_ack", 1)
modparam("acc", "report_cancels", 0)
modparam("acc", "detect_direction", 0)
/* account triggers (flags) */
modparam("acc", "log_flag", FLT_ACC)
modparam("acc", "log_missed_flag", FLT_ACCMISSED)
modparam("acc", "failed_transaction_flag", FLT_ACCFAILED)
modparam("acc",
"log_extra","src_user=$fU;src_domain=$fd;dst_ouser=$tU;dst_user=$rU;dst_domain=$rd")
/* enhanced DB accounting */
#!ifdef WITH_ACCDB
modparam("acc", "db_flag", FLT_ACC)
modparam("acc", "db_missed_flag", FLT_ACCMISSED)
modparam("acc", "db_url", DBURL)
modparam("acc", "db_extra",
"src_user=$fU;src_domain=$fd;dst_user=$tU;dst_domain=$td;src_ip=$si")
#!endif

...


# Main SIP request routing logic
# - processing of any incoming SIP request starts with this route
route {

        # per request initial checks
        route(REQINIT);

        if (src_ip != ****) {
                # 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);

        if ( is_method("INVITE") ) {
                route(DBALIASES);
                #check for user defined forking priorities and timers
                route(FORK);
        }

        # user location service
        route(LOCATION);

        route(RELAY);
}



#check for user defined forking priorities and timers
route[FORK]{
        sql_query("con", "select * from usr_pref_custom where uuid='$tu'",
"pref");

        $avp(uuid)=$dbr(pref=>[0,0]);
        $avp(email)=$dbr(pref=>[0,1]);
        $avp(prio1)=$dbr(pref=>[0,2]);
        $avp(prio2)=$dbr(pref=>[0,3]);
        $avp(timer1)=$dbr(pref=>[0,5]);
        $avp(timer2)=$dbr(pref=>[0,6]);

        if (strlen($avp(prio1))>5) {

                # user has multiple contacts, do serial forking
                setflag(FLT_USRPREF);

                # set counter
                if (!$avp(prio)) {
                        $avp(prio) = 1;
                }

                # overwrite request URI with highest priority contact
                if ($avp(prio1) =~ "^sip:00") {
                        $ru = $avp(prio1) + "@host";
                        xlog("L_INFO","PRIO 1 is tel number, RURI set:
$ru");
                }
                else {
                        $ru = $avp(prio1);
                        xlog("L_INFO","PRIO 1 is SIP URI, RURI set: $ru");
                }
        }
}


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

        /* example how to enable some additional event routes */
        if (is_method("INVITE")) {

                t_on_reply("REPLY_ONE");
                t_on_failure("FAIL_ONE");

                #if users have priorities set, use FAIL_FORK failure route
                if ( isflagset(FLT_USRPREF) ) {
                        t_on_failure("FAIL_FORK");
                }
        }

        if (isflagset(FLT_ACCMISSED)) xlog("L_INFO","RELAY, $rm $ru,
ACCMISSED FLAG IS SET");
        else xlog("L_INFO","RELAY, $rm $ru, ACCMISSED FLAG IS NOT SET");
        if (!t_relay()) {
                sl_reply_error();
        }
        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()) {
                        xlog("L_INFO","WITHINDLG, loose_route()");
                        if (is_method("BYE")) {
                                xlog("L_INFO","WITHINDLG, BYE, DO
ACCOUNTING");
                                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;
        }
}


# USER location service
route[LOCATION] {

  #skip if $ru is telephone number
        if ($ru =~ "^sip:00") {
                xlog("L_INFO","SKIP lookup...");
        }
        else {
                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, but only if
user doesn't have prios set
        if ( is_method("INVITE") && !(isflagset(FLT_USRPREF))) {
                setflag(FLT_ACCMISSED);
        }
}


# Failure route for forked calls
failure_route[FAIL_FORK] {
#!ifdef WITH_NAT
        if (is_method("INVITE") && (isbflagset(FLB_NATB) ||
isflagset(FLT_NATS))) {
                unforce_rtp_proxy();
        }
#!endif

        if ($avp(prio) >= 1) {
                $avp(prio) = $avp(prio) + 1;

                # handle 2nd branch
                if ( ($avp(prio) == 2) && ( isflagset(FLT_USRPREF) )) {
                        t_on_failure("FAIL_FORK");

                        if ($avp(prio2) =~ "^sip:00") {
                                xlog("L_INFO","FAIL FORK, PRIO 2 is tel
number");
                                $ru = $avp(prio2) + "@host";
                        }
                        else {
                                xlog("L_INFO","FAIL FORK, PRIO 2 is SIP
URI");
                                $ru = $avp(prio2);
                                route(LOCATION);
                        }
                        setflag(FLT_ACCMISSED);
                }

                else {
                        $avp(prio) = 0;
                        $ru = $(avp(uuid));
                        rewritehostport("host:port");
                        xlog("L_INFO","FAIL FORK, VOICEMAIL
email:$avp(email), ru:$ru, br: $br");
                        append_hf("P-App-Name: voicemail\r\n");
                        append_hf("P-App-Param:
Email-Address=$avp(email)\r\n");
                }
                route(RELAY);
        }

        if (t_is_canceled()) {
                exit;
        }
}
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.sip-router.org/pipermail/sr-users/attachments/20110905/9a545cf5/attachment-0001.htm>


More information about the sr-users mailing list