# Save info for TCP connections for unregister on close/timeout/error
loadmodule "htable.so" 
modparam("htable", "htable", "tcpconn=>size=15;autoexpire=7200;")
...
# Handle SIP registrations
route[REGISTRAR] {
...
    save("location");
    route(TRACK_TCP_STATE);
    $var(processed_subscriber) = $fu;
    route(TCP_REGISISTER_CLEANUP); 
...
} 
route[TRACK_TCP_STATE] {
    if (proto == UDP) {
        return;
    }
    xlog("[TRACK_TCP_STATE] Saving state for future disconect track of $fu\n");
    $sht(tcpconn=>$conid) = $fu;
    tcp_enable_closed_event();
}
# Make sure you set up $var(processed_subscriber) before calling this route
route[TCP_REGISISTER_CLEANUP] {
    if ($var(processed_subscriber) == $null) {
        return;
    }
    xlog("[TCP_REGISISTER_CLEANUP] Processing subscriber $var(processed_subscriber)\n");
    # Getting registered endpoints for this AoR
    if (!reg_fetch_contacts("location", "$var(processed_subscriber)", "subscriber")) {
        $var(processed_subscriber) = $null;
        xlog("[TCP_REGISISTER_CLEANUP] No registered contacts for $var(processed_subscriber)\n");
        return;
    }
    $var(i) = 0;
    # Loop through registered endpoints
    while ($var(i) < $(ulc(subscriber=>count))) {
        $var(stored_subscriber_conid) = $(ulc(subscriber=>conid)[$var(i)]);
        # Make sure proto is TCP
        if ($var(stored_subscriber_conid) != $null) {
            # Check if entry is still active TCP connection. Unregister otherwise.
            if ($var(stored_subscriber_conid) == -1 || !tcp_conid_alive("$var(stored_subscriber_conid)")) {
                $var(stored_subscriber_ruid) = $(ulc(subscriber=>ruid)[$var(i)]);
                $var(stored_subscriber_address) = $(ulc(subscriber=>addr)[$var(i)]);
                xlog("[TCP_REGISISTER_CLEANUP]: Unregistering entry $var(i)/$var(stored_subscriber_conid) -> $var(stored_subscriber_address)\n");
                if (!unregister("location", "$var(processed_subscriber)", "$var(stored_subscriber_ruid)")) {
                    xlog("[TCP_REGISISTER_CLEANUP]: Unregistering entry $var(i)/$var(stored_subscriber_conid) -> $var(stored_subscriber_address) FAILED!\n");
                }
            }
        }
        $var(i) = $var(i) + 1;
    }
    $var(processed_subscriber) = $null;
}
event_route[tcp:closed] {
    xlog("[TCP:CLOSED] $proto connection closed conid=$conid\n");
    $var(processed_subscriber) = $sht(tcpconn=>$conid);
    if ($var(processed_subscriber) != $null) {
        route(TCP_REGISISTER_CLEANUP);
        $sht(tcpconn=>$conid) = $null;
    }
}
event_route[tcp:timeout] {
    xlog("[TCP:TIMEOUT] $proto connection timeout conid=$conid\n");
    $var(processed_subscriber) = $sht(tcpconn=>$conid);
    if ($var(processed_subscriber) != $null) {
        route(TCP_REGISISTER_CLEANUP);
        $sht(tcpconn=>$conid) = $null;
    }
}
event_route[tcp:reset] {
    xlog("[TCP:RESET] $proto reset closed conid=$conid\n");
    $var(processed_subscriber) = $sht(tcpconn=>$conid);
    if ($var(processed_subscriber) != $null) {
        route(TCP_REGISISTER_CLEANUP);
        $sht(tcpconn=>$conid) = $null;
    }
}
Simple and efficient solution. Yes, some of "dead" endpoints would be present in table during expiration time, but I'm ok with that.
 
No comments:
Post a Comment