The Module Function Interface Rework in OpenSIPS 3.0

Image result for coffee keyboard monitor"

As you begin to write or migrate to OpenSIPS 3.x configuration files, you will notice some major changes in the way module functions are invoked. These changes are part of an ongoing effort to improve the experience of writing opensips.cfg code, and in this article we’re going to take a closer look at how this has materialized in 3.0.

Script Development

Inexplicable Asymmetries

As the years went on and more opensips.cfg files were written, we noticed a constant flow of questions on the users mailing list resembling:

  • why can ds_select_dst() take either integers or integer variables as 1st parameter, but nat_uac_test() only takes integers?
  • why does rl_check() also accept a formatted string as 1st parameter, yet save() only lets me pass a string as the “aor” parameter?

Until 3.x, the default answer was: “OK, let me push a commit which specifically fixes nat_uac_test() to also accept integer variables as 1st param, not just integers.”. This is because the module function interface, as inherited from the SER project, was simply not powerful enough: each module function had to be carefully customized, down to both the type of each parameter, the exact types of values it can take, as well as manually deducing the parameter’s value at runtime. A tedious amount of work, and almost impossible to fully get right.

With over 150 modules, each exporting roughly 5 functions with 2 parameters each… the function API had lead to a good amount of code which was well below “still manageable”. Not to mention that all OpenSIPS users and developers could benefit from not having to deal with these kind of parameter typing problems to begin with.

Over-Complicated Conventions

While reworking the interface to meet the above needs, we noticed that the module function calling convention could also benefit from several improvements. Some example questions, typically asked by people new to opensips.cfg:

  • why do I have to quote integers when calling: ds_select_dst(“1”, “4”)?
  • why do I have to quote the variable when calling: ds_select_dst(“$var(group)”, “4”)?

These syntactical quirks may not seem that much once you get used to them, but wouldn’t the opensips.cfg language be even better if we adjusted it so new users could pick it up even faster, by adhering to the principle of least astonishment?

The New and Improved Syntax

Starting with OpenSIPS 3.0, all of the above issues have been taken care of. The individual restrictions at function parameter level are now gone and have been abstracted into an internal interface, so you can now freely call any function with any parameter type. For example:

  • save(“location”, , “sip:$var(user)@$var(domain)”)
  • nat_uac_test($var(nat_tests))
  • ds_select_dst(1, $var(algorithm))

… along with any other combinations(1) you might think of. All calls will just work, and you won’t have to put up a feature request anymore, just so you can get a function to also accept the variable input that you want to pass to it.

Also, notice how both integer and variable values are now passed to module functions in an unquoted fashion, as part of the new function calling conventions, available in the updated script syntax chapter for OpenSIPS 3.0.

1) with some rare, non-disruptive exceptions, due to performance optimizations. For example, save(“location”) will still only take static strings as 1st parameter.

Module Development

Internally, on the C development side of OpenSIPS modules, the new module interface brings about several benefits:

Faster Development

Simply put: there is less code to write now when developing new modules, as programmers are spared of the minutious task of extracting and converting the value of each function parameter. Regardless if it’s a static value or one resulted from a variable, the module function interface will take care of computing the value and passing it to your module’s function.

This, in turn, will give OpenSIPS module developers more time to focus on their actual logic and not on function parameter bells and whistles.

Simplified Maintenance

An interesting effect of the rework is that it helped cut down on over 10K lines of boiler-plate C code! This can be highlighted by diffing the first and final commits of the function rework branch. By running git diff 2fd7713d1 b5557bdcb --stat on the 3.0 branch, we can glance at a summary of the entire effort:

393 files changed, 11000 insertions(+), 21444 deletions(-)

Credits

On the execution side, although the plan was put together by the entire team of developers at OpenSIPS Solutions, both the interface rework and a major chunk of the module conversion work (over 75% of the modules) were solely done by Vlad Patrascu, while us remaining slackers ported the leftover modules, so Vlad would not be completely sleep deprived!

Summary

Starting with version 3.0, OpenSIPS benefits from a major rework of the module function interface, thus making the opensips.cfg syntax more intuitive and easier to pick up, thanks to the improved function calling conventions.

Enjoy the improved syntax and function calling flexibility in 3.0,
The OpenSIPS developers

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s