Kamailio Private Variables

I’ve stated elsewhere why private variables are probably not the variables you want to use, but it’s probably good to put some specific examples on WHY this is the case. Let’s look at a (very) simplified Kamailio config:

This configuration creates two child processes. The artificial sleep is added to ensure that the first processes doesn’t clear before sending another message and that we do get messages processed by both children. Running sipp -sn uac -m 8 localhost will send 8 INVITE messages to the server which produces the following output: in the Kamailio log:

 2(8) INFO: <script>: Process id [8] $vn(foo) is uninitialized [<null>]
 1(7) INFO: <script>: Process id [7] $vn(foo) is uninitialized [<null>]
 2(8) INFO: <script>: Process id [8] $vn(foo) is [1]
 1(7) INFO: <script>: Process id [7] $vn(foo) is [1]
 2(8) INFO: <script>: Process id [8] $vn(foo) is [1]
 1(7) INFO: <script>: Process id [7] $vn(foo) is [1]
 2(8) INFO: <script>: Process id [8] $vn(foo) is [1]
 1(7) INFO: <script>: Process id [7] $vn(foo) is [1]

As can be seen here only the first request to each child process is undefined. If someone is expecting it to be $null at the start of request processing, they’d have a problem.

Storing values in transactions

Suppose that we have a value that we want to set in request processing and then access it when handling the response. Private variables will not work for this for two reasons:

  1. There is no guarantee that the process that handled the request will be the same process that handles the response.
  2. Even if the same process handles the response, there is no guarantee that the process has not handled another request in the meantime and overwritten the private variable with a new value.

The config below illustrates this by using both private variables, and (for comparison) an AVP. It’s simply storing the SIP Call-ID in both a private variable ($vn(pp)) as well as an AVP ($avp(pp)). The response handling prints the call-id from the message, as well as both of these variables

##!KAMAILIO

loadmodule "pv"
loadmodule "tm"
loadmodule "sl"
loadmodule "xlog"
loadmodule "textops"
loadmodule "ctl"
loadmodule "cfgutils"

children = 4

request_route {
    $du = "sip:kamailio2";
    $vn(ci)  = $ci;
    $avp(ci) = $ci;
    t_on_reply("RPLY");
    t_relay();
}

onreply_route[RPLY] {
    xinfo("$$ci: [$ci] $$vn(ci): [$vn(ci)] $$avp(ci): [$avp(ci)]\n");
}

Sending a series of messages resulted in this:

6(12) INFO: <script>: $ci: [1-24@172.18.0.3] $vn(ci): [1-24@172.18.0.3] $avp(ci): [1-24@172.18.0.3]
7(13) INFO: <script>: $ci: [2-24@172.18.0.3] $vn(ci): [3-24@172.18.0.3] $avp(ci): [2-24@172.18.0.3]
7(13) INFO: <script>: $ci: [3-24@172.18.0.3] $vn(ci): [3-24@172.18.0.3] $avp(ci): [3-24@172.18.0.3]
6(12) INFO: <script>: $ci: [4-24@172.18.0.3] $vn(ci): [5-24@172.18.0.3] $avp(ci): [4-24@172.18.0.3]
6(12) INFO: <script>: $ci: [5-24@172.18.0.3] $vn(ci): [5-24@172.18.0.3] $avp(ci): [5-24@172.18.0.3]
7(13) INFO: <script>: $ci: [6-24@172.18.0.3] $vn(ci): [7-24@172.18.0.3] $avp(ci): [6-24@172.18.0.3]
7(13) INFO: <script>: $ci: [7-24@172.18.0.3] $vn(ci): [7-24@172.18.0.3] $avp(ci): [7-24@172.18.0.3]
6(12) INFO: <script>: $ci: [8-24@172.18.0.3] $vn(ci): [9-24@172.18.0.3] $avp(ci): [8-24@172.18.0.3]
7(13) INFO: <script>: $ci: [9-24@172.18.0.3] $vn(ci): [7-24@172.18.0.3] $avp(ci): [9-24@172.18.0.3]
6(12) INFO: <script>: $ci: [10-24@172.18.0.3] $vn(ci): [9-24@172.18.0.3] $avp(ci): [10-24@172.18.0.3]

The private variable SOMETIMES is the current message call-id, but frequently it is not. This shows why it’s usually not what’s wanted.

Why use private variables?

The question then becomes “Why ever use private variables?” The advantage of private variables is that they are faster. Which is not to say that AVPs are slow, but sometimes, on a busy system, tuning does matter. First, if you have a situation where you are intending to track something according to the process, then it makes sense. There’s not many situations where this arises, but it can be possible. If you have a situation where it’s clear that the value is going to always be set and used in the same process, then it can make sense. An example where I commonly do this is when using variables for storing a long string for formatting purposes. For example, a SQL query can get difficult to read if it’s all written on a single line. I find this solution makes it much more readable:

$vn(query) = "SELECT customer_id, caller_id, account_id "
           + "cnam_dip, concurrent_call_limit "
           + "FROM dids "
           + "WHERE did = " + $(rU{sql.val.str});

sql_query("ca", "$vn(query)", "ra");

There will be a slight cost associated with using a variable here, but it’s less intensive than creating it for every transaction, which would be unnecessary.

Conclusion

I hope this clears up some of the things about private variables that aren’t immediately obvious to programmers new to Kamailio. Especially as it relates to transaction processing, which is inherently asynchronous. I’m not saying to “avoid private variables at all costs”, but simply to make sure when you are using them that you’re not doing it as the default.

2 responses to “Kamailio Private Variables”

  1. […] variables are scoped to the private variable in which they are declared. As I’ve written in another post, these are probably not the variables you want to use. Syntactically, they are they always have an identifier in the […]

    Like

  2. […] no guarantee that the PID handling the request and the pid handling the reply will be the same, so private variables will not have the value retained between […]

    Like

Leave a comment

Design a site like this with WordPress.com
Get started