Unified branches, or SIP branches before and after SIP relaying

SIP branching is particular to SIP forking scenarios – serial and parallel forking. The parallel forking is particular challenging as multiple branches must be managed in the same time. From life cycle perspective, we have two types of branches in OpenSIPS. Each type describe a different stage in a branch life cycle:

  • message branches – this is the preparation stage, before any SIP signalling. We do process the incoming request and we work out / build the destinations/branches were we want to send the request out.
  • transaction branches – this is the signalling stage, after the branches were sent out (via SIP). The completion or failure of the branches will lead to setting up (or not) of the SIP session. The transaction branches are specific to the call setup stage (early stage).

The message branches are consumed and transformed into transaction branches by the t_relay function – whatever message branches were prepared, they are sent out via SIP signaling.

Up to the 3.6 version, there were couple of problems / issue in regards to the branch management in OpenSIPS:

  • even if the message and transaction branches are one-2-one correlated, from script level there is no direct correlation between branches before and after t_relay()
  • there is no possibility to add custom information to the branches, in the way that whatever you attach to a message branch will be inherited by the corresponding transaction branch.
  • at script level, there is no possibility to access information attached to another branch, different than the currently processed branch (like in “onreply” route, when receiving a reply for branch 1, you want to check information related to branch 3.

So, how OpenSIPS 3.6 addressed these issues?

Unified branch format

In order to offer an unified user experience when comes to operating with the message and transaction branches, OpenSIPS 3.6 introduces two new set of similar variables:

Message branch related variables:

  • $msg.branch.uri
  • $msg.branch.duri
  • $msg.branch.path
  • $msg.branch.q
  • $msg.branch.flags
  • $msg.branch.socket
  • $msg.branch.flag(name)
  • $msg.branch.attr(name)

These variables allow a complex management of message branches. Once created, the message branches may be updated to the last bit and field, thanks to the indexing.

In a similar way, we have the transaction branch related variables:

  • $tm.branch.uri
  • $tm.branch.duri
  • $tm.branch.path
  • $tm.branch.q
  • $tm.branch.flags
  • $tm.branch.socket
  • $tm.branch.flag(name)
  • $tm.branch.attr(name)

You can see the perfect correlation between the message branches and the transaction branches – this makes the branch management (pre and post t_relay()) very easy, even in complex parallel forking scenarios.

Custom branch data – attributes and flags

With the new concept of per-branch attributes, together with the per-branch flags, OpenSIPS 3.6 becomes truly powerful when comes to forking.

You may add any kind of custom data (as attribute or flag) to a message branch (so when preparing the forking) and you will see this custom data later in the corresponding transaction branch, in branch, onreply and failure routes.

So, you can easily pass any custom info from the branch preparation stage to the actual signalling stage, which is very useful when comes to controlling the whole SIP forking process. For example, when preparing the branch (as message branch) I can add to it information that later may control/impact the SIP signaling of that branch (like how to act upon rejection, what media processing to be done, what script services are engaged for that branches, etc).

{
...
# set preferred codec for RURI branch
$msg.branch.attr(pref_codec) = "PCMU";
xlog("branch $msg.branch.last_idx has preferred codec $msg.branch.attr(pref_codec)\n");
# add a new branch (first additional one)
append_msg_branch("sip:dest2@sip.com");
# now we operate in the context of this new branch
$msg.branch.attr(pref_codec) = "G722";
xlog("branch $msg.branch.last_idx has preferred codec $msg.branch.attr(pref_codec)\n");
...
t_on_branch("info");
t_relay();
# the above t_relay() consumed the message branches and converted them into transaction branches
}

branch_route[info]
{
xlog("branch $T_branch_idx has preferred codec $tm.branch.attr(pref_codec)\n");
}

Inter-branch data access

Once the forking is ongoing (after the t_relay()), we have to deal with multiple branches in the same time (in the parallel forking scenario). And there are quite often scenarios where the handling of a branch may depend of what happened with another branch. Shortly, we need to access information from another branch, other than the current one.

For this purpose, OpenSIPS 3.6 provides complex indexing support for all the transaction branch related variables.

The indexing of the transaction branches starts from 0, giving access to all branches (past and active) of the transaction. Nevertheless the indexing supports two optional suffixes, to simplify the scripting:

  • /active” – the indexing starts also from 0, but it is relative to the last set of branches the parallel branches created by the last “t_relay()”-ing. So you can index only the branches involved in the last parallel forking, ignoring all previously completed branches (as a previous serial forking)
  • /all” – similar to “no suffix” case, meaning it is an absolute index, covering all the branches of the transactions (resulted from all “t_relay()“s performed over the transaction).

If no index is specified, the current branch used. This depends on the scripting context. Like in onreply route, the current branch is the branch the reply came for; in branch route, the current branch is the branch to be sent out; in failure route, the current branch is the winning branch.

# the "foo" attribute of the second branch of this transaction
$(tm.branch.attr(foo)[2])
# the "foo" attribute of the second branch involved in this parallel forking step
$(tm.branch.attr(foo)[2/active])

Using such indexing, from the onreply or failure route you can can dig into the data of any other branch.

As a step forward, for even more complex case, a “branch search” function was added. You can search the index of a transaction branch based on the attributes attached to the branches, using the t_get_branch_idx_by_attr():

# search for a branch which has the "name" attribute with string value "pstn"
if (t_get_branch_idx_by_attr("name", "pstn", , $var(idx))) {
	xlog("found branch has index $var(idx)\n");
}

All the above 3.6 specific additions unlock many possibilities when comes to complex forking scenarios.

Join us to OpenSIPS Summit 2025 in Amsterdam and learn more about OpenSIPS 3.6 major release.

Leave a comment