Documentation |
Documentation -> Tutorials -> Event InterfaceThis page has been visited 20607 times. Table of Content (hide)
This tutorial is for OpenSIPS trunk/devel version 1. Event InterfaceThe OpenSIPS Event Interface provides an easy way to notify external applications whenever certain events occur inside OpenSIPS. Basically it provides two interfaces: one for the OpenSIPS internal modules and core, that is used to advertise and raise events, and an interface for the external applications, allowing them to register for specific events, and notifying them when those events are triggered by the modules, core, or by the OpenSIPS script. 2. OverviewOpenSIPS can notify an external application using different transport protocols:
In order to receive an event notification, an external application has to subscribe for a specific event to the Event interface. This can be done either using an MI command, or can be done directly from the OpenSIPS script. The subscription command has to specify the event that the external application wants to register to, and a socket where the notification has to be sent. The format of the socket is different, depending on the transport module used (you can find more information about this in the module's documentation page). When an event is triggered, the Event Interface will send to each application that is subscribed for that event a notification, using the desired transport type. The event details are packed differently for each transport module (consult the transport module's documentation page for more details). 3. Event SubscriptionAs mentioned above, an external application can subscribe for an event either using MI, or directly from OpenSIPS script. In the next sections we will describe the use case of each of them. 3.1 MI SubscriptionAn external application should subscribe for an event using MI commands when the subscription nature is very dynamic: it subscribes for a short period, receives notifications, then decides to unsubscribe and so on. The MI function used to subscribe for an event is event_subscribe. For example, to subscribe for the E_PIKE_BLOCKED event for only 1200 seconds, an external application that listens on localhost, UDP port 8888, has to issue the following MI command: $ opensipsctl fifo event_subscribe E_PIKE_BLOCKED udp:127.0.0.1:8888 1200 The first parameter is the name of the event (see here), the second parameter is the listening socket name (the format depends on the transport module used) and the last parameter is the expiration period expressed in seconds. Note that if the last parameter is missing, a default subscription period of 3600s (1h) is assumed. In order to unsubscribe for an event, the external application has to use the same event and socket used at subscription time, but specify an expiration time of 0. The following command unsubscribes the previously registered application. $ opensipsctl fifo event_subscribe E_PIKE_BLOCKED udp:127.0.0.1:8888 0 3.2 Script SubscriptionThe Event Interface allows the script writer to subscribe for an event directly from the OpenSIPS configuration script. This is usually used when a subscription is permanent, that never expires. For example a server that is continuously listening from events from OpenSIPS and process them accordingly. The command used to subscribe for an event from script is subscribe_event. Usually these kind of subscriptions are permanent, therefore they should be registered at when OpenSIPS starts. Therefore this should be done in startup_route, but this is not a requirement, as the function can be used in any route. Here is an example of subscription for the E_PIKE_BLOCKED event at OpenSIPS startup, without any expire time, from the OpenSIPS configuration script: startup_route() { subscribe_event("E_PIKE_BLOCKED", "udp:127.0.0.1:8888"); } If the script writer wants the subscription to expire after 1200 second, the third parameter of the subscribe_event function can be specified: timer_route[event_subscribe,3600] { subscribe_event("E_PIKE_BLOCKED", "udp:127.0.0.1:8888", 1200); } 3.3 SubscribersThe subscribers_list MI function, exported by the OpenSIPS Core, can be used to list all the external applications subscribed. It also allows you to filter the subscribers based on the event they are registered to. For more information consult the functions documentation page. 4. EventsThere are two types of events: static/predefined events, exported by OpenSIPS code and modules, and documented by each module, and dynamic events that can be raised by the script writer directly from the script. A few examples of predefined events:
4.1 Events NameAlthough there is not a strict events naming imposed by the Event Interface, it is a good practice for an event's name to follow the format 4.2 Raising an EventIn order to raise an event from the script, the raise_event function has to be used. The function receives one, two or three parameters, depending on the script writer needs. If the event has no parameters, then only the first parameter is needed - the event's name. If the script writer wants to attach some extra information to the event, then the second and optionally the third parameter has to be used. The extra information has to be stored in an AVP as values, for example: $avp(values) = "value1"; $avp(values) = "value2"; ... If the parameters also have some names, then a new AVP have to store them. Note that the number of values in the first AVP has to be the same as in the one for the attributes: $avp(attributes) = "param1"; $avp(values) = "value1"; $avp(attributes) = "param2"; $avp(values) = "value2"; ... In order to raise the event from the script, the following code has to be used: raise_event("E_SCRIPT_EVENT"); # raises an event without any parameters raise_event("E_SCRIPT_EVENT", $avp(values)); # raises an event that has only values parameters raise_event("E_SCRIPT_EVENT", $avp(attributes), $avp(values)); # raises an event with multiple attribute-value pairs 4.3 Events listThe events_list function can be used to list all the available events. 4.4 ExamplesA practical use case of dynamic events is raising an event from the script when the TCP load is greater than 80%: route[TCP_LOAD_CHECK] { if ($stat(tcp-load) > 80) { # raise the event, specifying the limit and the real load $avp(attrs) = "limit"; $avp(vals) = 80; $avp(attrs) = "load"; $avp(vals) = $stat(tcp-load); raise_event("E_SCRIPT_TCP_LOAD", $avp(attrs), $avp(vals)); } } Dynamic events can also be used for accounting purposes. For example, you could use three types of dynamic events to notify an external application regarding a call status. # this route initializes the accounting variables route[ACC_VARS] { # first cleanup whatever it was there before this $avp(attrs) := NULL; $avp(vals) := NULL; $avp(attrs) = "from"; $avp(vals) = $fU; if (has_totag()) { $avp(attrs) = "to"; $avp(vals) = $rU; } ... $avp(attrs) = "callid"; $avp(vals) = $ci; # populate attrs and vals with whatever extra info you need } route { ... if (!has_totag() && is_method("INVITE"))) { route(ACC_VARS); raise_event("E_SCRIPT_CALL_START", $avp(attrs), $avp(vals)); t_on_reply("acc"); } else if is_method("CANCEL|BYE") { route(ACC_VARS); raise_event("E_SCRIPT_CALL_STOP", $avp(attrs), $avp(vals)); } ... } onreply_route[acc] { ... if (t_check_status("200")) { route(ACC_VARS); raise_event("E_SCRIPT_CALL_ESTABLISHED", $avp(attrs), $avp(vals)); } ... } 5. Transport ModulesThere are several transport modules that can be used to notify an external application. At the time this tutorial was written, the following transport methods were supported: 5.1 Datagram MessagesExternal applications can be notified when OpenSIPS internal events are triggered using either UDP or UNIX datagrams. This allows programmers to write a simple UDP server that receives the notification and process it in the preferred programming language. In order to support this type of communication, the event_datagram module has to be loaded. Consult the module's documentation page for more information about subscription socket and encapsulation format. 5.2 RabbitMQ MessagesOpenSIPS can also communicate with a RabbitMQ server using the AMQP (Advanced Message Queuing Protocol) messages. This type of communication leverages all the features the queuing server has. The event_rabbitmq module provides this functionality. Note that in this case, the "external application" is the RabbitMQ server, so you do not have the possibility to subscribe for events from it. Therefore the programmer should either use a different application to subscribe for the event, or subscribes for it directly from the OpenSIPS script (as discussed here). For more information please visit the module's documentation page. 5.3 XMLRPC CommandsOpenSIPS can also execute a remote XMLRPC command when an event is triggered. The module that handles the communication between the Event Interface and the XMLRPC server is event_xmlrpc. 5.4 JSONRPC CommandsOpenSIPS can also execute a remote JSON-RPC command when an event is triggered. event_jsonrpc can be used to trigger a JSON-RPC call on a server using the JSON-RPC 2.0 specifications. 5.5 RoutesA special implementation of a transport module is the event_route module, which is used to handle events directly from the OpenSIPS script. This allows the script writer to modify OpenSIPS internal variables when an event is triggered, by writing a special route, called event_route. The name of the route specifies the event that is handled by that route. In order to retrieve the parameters of the event, the fetch_event_params function has to be used. It receives a list of parameters names, and the pseudo-variables that they have to be assigned to. For more information consult the event_route documentation page. For example in order to specify a route that handles the E_PIKE_BLOCKED event, and prints the blocked IP, the OpenSIPS script has to contain the following code: event_route[E_PIKE_BLOCKED] { fetch_event_params("ip=$avp(pike-ip)"); xlog("IP $avp(pike-ip) has been blocked\n"); } Note that specifying the event_route will automatically subscribe the route for the event. Therefore there is no need for explicit subscribing (from either external application or script). The subscription never expires, unless otherwise specified using the subscribe_event MI command. |