During this year’s annually OpenSIPS Feature Survey, the poll results for the new OpenSIPS 3.2 reflected an emergent need for people to be able to run MI alike commands directly from the script. Initially, we were a bit reluctant from developing this feature due to the fact that (historically speaking), OpenSIPS’s Management Interface has been initially designed to allow interaction between external tools (OpenSIPS CTL, OpenSIPS CLI, OpenSIPS CP, etc.) and OpenSIPS processes, rather than between OpenSIPS and its script (we already have script functions for that). But since the community asks it, we have to make it happen.
Our initial attempt to solve this need was to compile a list of MI functions that make sense to be run from script, and create script functions around them. Although this would be the most safe and normal approach, we quickly realized it had some limitations, such as (A) there was a lot of extra wrapper code to expose the functionality and (B) the list cannot be that exhaustive – people should easily be able to add functions to the list if they need it.
That is why we decided to remove the external requirement for the MI interface and expose the entire commands list in the script. This is what the new MI script module does starting from OpenSIPS 3.2.
This article shows how this new module works, what are its limitations and how people should use it to make the best out of it.
It is important to emphasize that MI commands have been designed to be run from an external and independent application. Therefore one cannot assume anything about the context the command is run into – it will be executed in a completely different, isolated context, just as any other external command would have run.
This means that if, for example, you are trying to get all the values of a profile using the profile_get_values MI function, you will get the values of all the profiles, not only the ones the current dialog is part of. Bottom line is, never assume a context.
All the other MI engines are designed to run commands in a separate, dedicated process, completely isolated from the SIP processing ones. However, due to the fact that the commands are triggered from the SIP processes themselves, the commands are run (inline), by the same process. This might be troublesome, as we will see later.
The input parameters (the MI command to run and along with is arguments) can be provisioned in two different methods:
- the simple way – provide the MI command, along with its parameter, space separated, in the first parameter of the script function, just as you might have done using the opensipsctl/opensips-cli tools. Although the simplest way to use, it is only meant to run simple commands with simple parameters, as it does not do any escaping of the arguments passed to the command – it simply breaks the input by spaces and passes the arguments along to the MI command. Due to the same reason, it does not work with named parameters either – for both complex (escaping) and/or named arguments, you will need to use the second input flavor.
# reload Dynamic Routing module, the extensions partition mi("dr_reload extensions");
- using AVPs – the third and fourth parameters of the mi command can be used to pass along named parameters, as well as escaping needing parameters, to the MI function. The behavior is similar to the one the raise_event function uses. When this mode is used, any argument passed in the first parameter (except the MI command itself) is ignored.
# list first 10 dialogs, paginated $avp(attrs) = "index"; $avp(vals) = "0"; $avp(attrs) = "counter"; $avp(vals) = "10"; mi("dlg_list",,$avp(attrs), $avp(vals));
The result of the MI command is stored in the second parameter, if provided, as a JSON string. The pretty_printing parameter indicates whether the result should be pretty formatted or not. In case of an error, the parameter is populated with the error string. The command returns in the $rc variable the success code as a positive number, or a negative code in case of a failure.
The mi script function comes in both synchronous and asynchronous flavors. On the other hand, the MI commands themselves can be synchronous and asynchronous (i.e. t_uac_dlg, dlg_send_sequential, etc.). Depending on how you use them, the behavior changes as detailed below:
- run synchronous MI command using synchronous mi function – the command will be run inline, in the same process as it has been called from, and the SIP message processing is stopped until the MI command finishes its execution. You should only use this flavor when the command you are running is quickly executed and you need its result to continue processing.
- run asynchronous MI commands using synchronous mi function – the command is run in the same process (as with previous version), but the result might be received in a different process. During this period, the SIP message processing is stopped, as the process is doing blocking I/O to wait for the response. We recommend you to avoid using this behavior.
- running both synchronous and asynchronous MI commands using the asynchronous mi function has a similar behavior- the MI command is executed asynchronously in a free (less loaded) process (might be the same as the SIP processing one), and when it terminates, it resumes the SIP processing in the same process it was triggered from. This is the recommended version to use.
Besides the recommendations presented above, you should also consider the following ideas:
- Try to avoid abusing the new feature – make sure that what you are trying to implement cannot be done with existing script functions/variables (most of them can).
- Whenever possible, run the commands from an external application – do not try to push all the logic in OpenSIPS scripts and put load on its processes.
- Try to avoid as much as possible running the synchronous mi version in favor of the asynchronous one.
- When running time consuming MI commands (such as reloads), run them without attaching them to a SIP context (using the launch statement), unless you really need the result to continue processing.
Running MI commands from script is now possible starting with the new OpenSIPS 3.2. Make sure you are using the right flavor for the right job!
Make sure you are not missing this year’s OpenSIPS Distributed Summit, where you will find out more about this topic, as long as about other new features you will encounter in OpenSIPS 3.2.