SPL (Session Processing Language)
A DSL for IP telephony services

Overview

IP telephony is the ground-breaking consequence of the convergence between telecommunications and computer networks. Telephony services can now be enriched with a host of new functionalities provided by IP network servers that provide resources such as databases, e-mail facilities and Web services. This enrichment critically relies on the development of new services that take advantage of these features. However, developing enriched, real-size services is quite a challenge considering the requirements that must be fulfilled by the service developers. First, developers must have an extensive knowledge on network protocols and distributed systems. Also, they must be familiar with often large and complex platform APIs, targeting in-breath and in-depth access to the platform (e.g., JAIN). Lastly, they must fully understand the signaling protocol (e.g., SIP) to develop services that do not compromise the processing of the calls, nor the platform.
To overcome this challenge, we propose SPL, a high-level DSL for specifying robust Internet telephony services. SPL reconciles programmability and reliability of telephony services, and offers high-level constructs that abstract over intricacies of the underlying protocols and software layers. SPL makes it possible for owners of telephony platforms to deploy third-party services without compromising safety and security. This openness is essential to have a community of service developers that addresses such a wide spectrum of new functionalities.

Detailed description

The SPL project has two main contributions:


SIP Virtual Machine The analysis of the SIP protocol is the starting point of the SPL design. The level of abstraction of the protocol was raised to match the needs of service development. This process resulted in a domain-specific virtual machine, named the SIP VM. This virtual machine is centered around the notion of a session, consisting of a set of events and a state, which structures the development of telephony services.

Session Processing Language. The SIP virtual machine, combined with common programming patterns found in telephony services, forms the main ingredient in the design of SPL. The syntax of an SPL service reflects the SIP VM session structure. Each kind of session is represented by a block containing the declarations of the variables and handlers associated with the session.
SPL semantics have been formally defined, enabling critical properties services to be guaranteed and capturing expertise on the operational behavior of a service.

For instance, when a positive response is received (i.e., a 2xx response code), no additional forwarding of the request is allowed and the response should be returned as the result of the SPL handler. This restriction prevents a service from forwarding a call to someone other than the party who accepted it. We have defined an formal static analysis that ensures that this restriction is satisfied for any program written in SPL.

Another example is how requests and responses are handled by SPL. In SIP, for every request, a response is provided. SPL guarantees this property by design. Indeed, every request handler (except ACK handler) must return a response. This design prevents the telephony system from an inconsistent state.
The compiler parses services and performs the previously mentioned safety verifications. Then, SPL is interpreted by the SIP application server. The interpretation is performed by the SLEE (Service Logic Execution Environment). It is the topmost layer of our application server. Intermediate layers provide abstractions from the JAIN SIP API to the SLEE as illustrated by Figure 1. The abstractions consists of events, which are interpreted requests or platform operations, and sessions, which reflect the SIP philosophy.
Application server architecture
Figure 1. Application server architecture
SPL has three main abstractions: sessions, handlers and branches

Sessions The structure of an SPL service reflects the SIP VM session structure. Each kind of session is represented by a block containing the declarations of the variables and handlers associated with the session. Sessions are organized into a hierarchy, with a service session at the root, the registration sessions created within the service session as its children, and dialog and subscription sessions at the leaves. A session at any level has access to all of the variables of its ancestor sessions.

As an example, Figure 2 shows the SPL service sec_calls, that implements a counter service. This service maintains a counter of the calls that have been forwarded to a secretary, whenever the SIP user associated with the service is unable to take the call. The counter is set to 0 when the user registers, incremented when a call is forwarded to the secretary, and logged when the user unregisters.
Handlers For each event generated by the SIP VM, an SPL service may define a handler to describe how the service should react to the event. In the case of verbatim and refined events, the handler processes a complete SIP transaction from the request to the final response. Platform events do not correspond to a SIP request. Therefore, the handler for such an event only performs non-signaling operations. A handler may be designated as either incoming or outgoing to provide a specific behavior for messages received or emitted by the user associated with the service, respectively. By default, a handler treats both incoming and outgoing requests.

The INVITE handler in Figure 2 (lines 17-24) illustrates SPL transaction processing for incoming INVITE requests. In this example, the forward operation (line 18) is used initially to forward an incoming call to the original recipient. This operation yields control to the SIP VM, which resumes the handler when a response is received. This response is then stored in the variable r and checked in line 19. SPL offers domain-specific abstractions and operations for such processing of SIP responses: Comparing a response to /SUCCESS checks whether the response code of the response is in the range 2xx, while comparing a response to /ERROR checks whether the response code of the response is greater than 300. In the example, if the call was not accepted, the original request is redirected to the secretary (line 21) and the new response is returned to the caller. If the call was accepted, the success response that was stored in r is returned directly (line 23).

As a component of a SIP application server, the SIP VM may receive requests at any time. To simplify SPL programming, the SIP VM never invokes a handler during the execution of another handler. Instead, events are queued by the SIP VM until the handler being executed yields control to the SIP VM, either due to a forward or a return operation. At this point, the SIP VM sends the request or response, respectively, out on the network and treats other pending requests. In the case of a forward, when a response arrives, the SIP VM resumes the handler containing the forward operation. The execution of a handler is thus atomic between two yield points, i.e., two signaling operations.
 1 service sec_calls {
 2   localvoid log (int);
 3
 4  registration {
 5    int cnt;
 6
 7    response outgoing REGISTER() {
 8       cnt = 0;
 9       return forward;
10     }
11
12    void unregister() {
13       log (cnt);
14     }
15
16    dialog {
17      response incoming INVITE() {
18        response r = forward;
19         if (r != /SUCCESS) {
20           cnt++;
21           return forward 'sip:secretary@example.com';
22         } else
23           return r;
24       }
25     }
26   }
27 }
Figure 2. Answered call counter example
Branches The SIP protocol imposes a coarse-grained flow of control within each kind of session. For example, in a dialog, control may flow from INVITE to ACK and to BYE. To enhance expressiveness, SPL allows the programmer to refine the control-flow specification via a branch mechanism that passes control information from one handler to the next. This abstraction permits, e.g., classifying a session as either personal or professional, and then introducing a logical personal or professional sub-thread across the remaining handler invocations of the session. As shown in Figure 3, the classification is done by adding the name of the branch to the return from the current handler (e.g., line 12) and the threads are implemented in each handler using the branch construct (e.g. lines 22-25).
 1 service waiting_queue {
 2  [...]
 3  registration {
 4   [...]
 5   dialog {
 6     [...]
 7     response incoming INVITE() {
 8       response resp = forward;
 9       if (TO == 'sip:secretary@enseirb.fr') {
10         [...]
11         // Session tagged as "secretary"
12         return resp branch secretary;
13       } else {
14         [...]
15         // Session tagged as "private"
16         return resp branch private;
17       }
18       [...]
19     }
20     [...]
21     response incoming ACK() {
22       branch secretary {
23         // Specific treatment for secretary session
24         [...]
25       }
26       branch private {...}
27       [...]
28     }
29     [...]
30 }
Figure 3. Inter-handler control flow
The branch construct is not only convenient for the programmer, it also increases the amount of information that is available to static verifications of SPL programs. Specifically, as the branch mechanism is a built-in language construct, it enables inter-handler control flow information to be determined accurately, before execution time. If this mechanism were not available, the programmer could simulate the same behavior using flags stored in the session state and conditionals in each handler testing the flag values. In this case, however, the control-flow information represented by the branches would not in general be apparent to the verifications associated with SPL, which would result in a less precise analysis.

Use cases

To demonstrate the usability of SPL, we have developed a queuing service of our department secretary. Its goal is to automatically handle incoming call for the telecommunication department. Calls are redirected to the secretary when she is available. If for some reason, she could not answer, the call is placed in a waiting queue. As soon as the secretary becomes available and could take new call, the oldest call in the queue is transfered from the queue to the secretary.

The queuing service example is available here.

Future work

  • Service composition and Feature interaction
  • Graphical representation (VisuCom)
  • Higher-level abstraction with B2B-UA functionality (Pantaxou)

Related Phoenix projects

Pantaxou
VisuCom

Publications

Publications (papers, presentations and Bibtex references) about SPL are available here

Participants

Nicolas Palix
Laurent Burgy
Fabien Latry
Laurent Réveillère
Charles Consel
Julia Lawall

Tools

OCaml (OCamlLex and OCamlYacc)
Java with JAIN SIP API and NIST Reference Implementation