Seas Module

Elias Baixas

   VozTelecom Sistemas
   www.wesip.eu

   Ronda Can Fatjo, 9, 1p Parc Tecnologic del Valles Cerdanyola, 08520 (SP
   AIN)
     Phone:+34 933968800
     www.voztele.com
     <elias.baixas@voztele.com>

   Copyright © 2006 VozTelecom Sistemas
     __________________________________________________________________

   Table of Contents

   1. The Sip Express Application Server User's Guide

        1. Application Servers

              1.1. Sip Express Application Server module overview
              1.2. Application Servers
              1.3. Dependencies

                    1.3.1. Kamailio Modules
                    1.3.2. External Applications

              1.4. Parameters

                    1.4.1. listen_sockets (string)

              1.5. Functions

                    1.5.1. as_relay_t(String name)

                          1.5.1.1. Return value

        2. WeSIP Application Server

              2.1. The Servlet programming paradigm: Sip/Http Servlets

                    2.1.1. Converged Http/Sip Servlet Containers

              2.2. Configuring WeSIP to work with SEAS

                    2.2.1. Server
                    2.2.2. Service
                    2.2.3. Connector
                    2.2.4. Engine
                    2.2.5. Mapper
                    2.2.6. Realm
                    2.2.7. Host
                    2.2.8. Mapper

              2.3. Configuration Examples

                    2.3.1. kamailio.cfg in standalone
                    2.3.2. kamailio.cfg working as WeSIP front-end
                    2.3.3. Server.xml

   2. Developer Guide

        1. Internals
        2. SEAS Protocol

              2.1. The SEAS protocol
              2.2. General codification of a header

                    2.2.1. Codification of a generic URI
                    2.2.2. Codification of To and From headers
                    2.2.3. Codification of Contact
                    2.2.4. Codification of Route and Record Route headers
                    2.2.5. Codification of Accept and Content-Type headers
                    2.2.6. Codification of Authorization headers
                    2.2.7. Codification of Allow headers
                    2.2.8. Codification of Content-Disposition headers
                    2.2.9. Codification of Content-Length header
                    2.2.10. Codification of Cseq header
                    2.2.11. Codification of Expires header
                    2.2.12. Codification of a SIP message

                          2.2.12.1. The general message information
                                  section

                          2.2.12.2. The headers index section

   List of Figures

   1.1. SipServlet UML diagram
   2.1. Overview of Seas Event Dispatcher process operation
   2.2. SIP Messages and control flow within SER
   2.3. General codification of a SIP header in SEAS protocol
   2.4. Example of a from header SEAS-protocol codification
   2.5. SEAS-codification of a SIP URI (byte meanings are shown)
   2.6. Example of a SEAS SIP URI codification
   2.7. SEAS codification of From and To headers
   2.8. SEAS codification of a Contact header
   2.9. SEAS codification of a Route Header
   2.10. SEAS codification of Authentication/Authorization headers
   2.11. SEAS codification of a SIP First Line
   2.12. SEAS Headers Index section overview
   2.13. SEAS SIP-Message codification
   2.14. Different kinds of SEAS codified Events and Actions

   List of Examples

   1.1. Set listen_sockets parameter
   1.2. as_relay_t usage
   1.3. Typical example of an HttpServlet
   1.4. Typical Sip Servlet Example
   1.5. Server
   1.6. Service

Chapter 1. The Sip Express Application Server User's Guide

   Table of Contents

   1. Application Servers

        1.1. Sip Express Application Server module overview
        1.2. Application Servers
        1.3. Dependencies

              1.3.1. Kamailio Modules
              1.3.2. External Applications

        1.4. Parameters

              1.4.1. listen_sockets (string)

        1.5. Functions

              1.5.1. as_relay_t(String name)

                    1.5.1.1. Return value

   2. WeSIP Application Server

        2.1. The Servlet programming paradigm: Sip/Http Servlets

              2.1.1. Converged Http/Sip Servlet Containers

        2.2. Configuring WeSIP to work with SEAS

              2.2.1. Server
              2.2.2. Service
              2.2.3. Connector
              2.2.4. Engine
              2.2.5. Mapper
              2.2.6. Realm
              2.2.7. Host
              2.2.8. Mapper

        2.3. Configuration Examples

              2.3.1. kamailio.cfg in standalone
              2.3.2. kamailio.cfg working as WeSIP front-end
              2.3.3. Server.xml

1. Application Servers

   1.1. Sip Express Application Server module overview
   1.2. Application Servers
   1.3. Dependencies

        1.3.1. Kamailio Modules
        1.3.2. External Applications

   1.4. Parameters

        1.4.1. listen_sockets (string)

   1.5. Functions

        1.5.1. as_relay_t(String name)

              1.5.1.1. Return value

1.1. Sip Express Application Server module overview

   SEAS module enables Kamailio to transfer the execution logic control of
   a sip message to a given external entity, called the Application
   Server. When the Kamailio script is being executed on an incoming SIP
   message, invocation of the as_relay_t() function makes this module send
   the message along with some transaction information to the specified
   Application Server. The Application Server then executes some
   call-control logic code, and tells Kamailio to take some actions, ie.
   forward the message downstream, or respond to the message with a SIP
   repy, etc.

   The module acts implements a network protocol acting as the interface
   between Kamailio internal API and the external Application Server
   entity.

   There's only one relevant function, as_relay_t, exported by this
   module. This function receives as a parameter the name of the
   application server to which the message should be relaied. Every
   message relaied to an Application Server is automatically associated to
   a SIP transaction (a transaction is created for it). Just after the
   message is relaied to the Application Server, the script stops its
   execution on the message, because the control of message-processing is
   now in the Application Server.

   In the context of SEAS module, relaying a message to an App Server, is
   _not_ done in SIP protocol, but in a special protocol by means of which
   the SEAS module and the Application Server comunicate efficiently and
   seamlessly. This procotol is specially designed so that a message
   doesn't need to be parsed again once it arrives at the Application
   Server. This protocol carries information regarding the internal
   structure of the SIP message (to avoid reparsing) and also information
   about the associated transaction (recall that invoking as_relay_t
   indirectly calls t_newtran). This way, all the SIP-Transaction
   machinery, and the SIP-Message parsing, is handled at the Kamailio
   core, while the execution of the Application Logic is carried in the
   Application Server.

   The SEAS module and protocol provide a means by which an external
   entity can utilize Kamailio as a transaction-stateful SIP-stack to act
   on behalf of it. This means that this external entity (which we call
   the Application Server) is notified whenever a SIP-Request enters
   Kamailio, and this external entity can then order Kamailio to execute
   some actions, either replying the request, or generating new UAC
   transactions.

   This version of SEAS works with VozTelecom's WeSIP Application Server.
   This Application Server is a SipServlet JAVA Container.

1.2. Application Servers

   When Kamailio starts and SEAS module is loaded, a new process is spawn
   which listens on a server-socket (IP and port are specified as a
   parameter in the config script). From then on, the Application Servers
   can connect to that socket so that Kamailio can relay messages to them.
   When an Application Server connects to the socket, it sends its name
   through the socket, so every App Server is identified with a name.
   Within the Kamailio script, invoking as_relay_t() receives a string as
   a parameter, which specifies the name of an application server to which
   the message has to be sent. If that concrete application server hasn't
   already connected to the module, the function returns a negative value,
   otherwise (the Application Server is connected), the message is relaied
   to it.

1.3. Dependencies

1.3.1. Kamailio Modules

   SEAS module relies on the Transaction Module (TM module) for operation.

1.3.2. External Applications

   Using the SEAS module requires to have an Application Server running
   and connected to a particular instance of Kamailio.

   At the moment, the only Application Server that works with SEAS is
   WeSIP Application Server, which can be downloaded from www.wesip.eu,
   and used freely for non-comercial purposes.

1.4. Parameters

1.4.1. listen_sockets (string)

   The listen_sockets string tells SEAS where to listen for incoming
   connections of Application Servers. It has the form: "ip:port". SEAS
   will open two server-sockets on that IP, at the specified port, and
   another at port+1. Application Servers must be configured to connect to
   that port.

   In case this parameter is ommited, SEAS listens on the default IP which
   Kamailio is using, and opens the ports 5080 and 5081 to listen for
   Application Servers.

   Example 1.1. Set listen_sockets parameter
...
modparam("seas", "listen_sockets","127.0.0.1:5080")
...

1.5. Functions

1.5.1. as_relay_t(String name)

   Creates a new transaction (if it isn't already created) and sends the
   SIP Request and transaction information to the Application Server
   specified in the parameter. Every Application Server connected to
   Kamailio through the SEAS module, must be identified with a different
   name.

   This function can be used within REQUEST_ROUTE.

   Example 1.2. as_relay_t usage
...
if (!as_relay_t("app_server_1")) {
log("Error sending to app server");
t_reply("500","App Server not connected");
}
...

1.5.1.1. Return value

   In case the Application Server is connected to Kamailio, the function
   does _not_ return, the Application Server is now in charge of
   processing the request, and it may then reply to the request, initiate
   new transactions, or whatever the application being executed wants.

   In case the Application Server identified by the string parameter
   passed to as_relay_t() is not connected to Kamailio, the function
   returns 0, so that the script can continue processing the request.

2. WeSIP Application Server

   2.1. The Servlet programming paradigm: Sip/Http Servlets

        2.1.1. Converged Http/Sip Servlet Containers

   2.2. Configuring WeSIP to work with SEAS

        2.2.1. Server
        2.2.2. Service
        2.2.3. Connector
        2.2.4. Engine
        2.2.5. Mapper
        2.2.6. Realm
        2.2.7. Host
        2.2.8. Mapper

   2.3. Configuration Examples

        2.3.1. kamailio.cfg in standalone
        2.3.2. kamailio.cfg working as WeSIP front-end
        2.3.3. Server.xml

   At the moment, the only Application Server known to work with SEAS is
   WeSIP. You can download a copy from www.wesip.eu.

   WeSIP is a converged Sip/Http Servlet Container.

2.1. The Servlet programming paradigm: Sip/Http Servlets

   Servlets are pieces of code that encapsulate the logic of an
   application. Servlets are deployed into an Application Server. Whenever
   a user requests service, the Application Server processes the request,
   and passes control to the servlet. The servlet then executes some
   logic, may it be a query to a database, the execution of a business
   process, the creation of customized content for the user, or whatever
   the service programmer could imagine. When the servlet finishes the
   execution, it creates a response and gives it back to the Application
   Server, which is in charge of making it reach back to the user. The
   Application Server implements the network protocol, it takes care of
   everything needed for a proper communication between user and server,
   so the servlet doesn’t have to care about these things. The servlet
   uses a set of resources from the Application Server, such as Session
   management, service routing or chaining, and request/response header
   composition.

   In HttpServlets, a service programmer has to implement a method in a
   JAVA class, which could be called doGet() or doPost(). Whenever an HTTP
   request arrived at the server, one of these functions was called with
   the request as a parameter, so the logic of the application was
   executed over that particular request.

   HttpServlet has been extensively used over the past years, in all kinds
   of business and web services.

   This is how a typical HttpServlet looks like:

   Example 1.3. Typical example of an HttpServlet
public final class Hello extends HttpServlet {
protected void doGet(HttpServletRequest request,HttpServletResponse response)
      throws IOException, ServletException
    {
response.setContentType("text/html");
PrintWriter writer = response.getWriter();
writer.println("<html>");
writer.println("<head>");
writer.println("<title>Sample Application Servlet</title>");
writer.println("</head>");
writer.println("<body bgcolor=white>");
writer.println("<table border=\"0\" width=\"100%\">");
Enumeration names = request.getHeaderNames();
while (names.hasMoreElements()) {
    String name = (String) names.nextElement();
    writer.println("<tr>");
    writer.println("<th align=\"right\">"+name+":</th>");
    writer.println("<td>"+request.getHeader(name)+"</td>");
    writer.println("</tr>");
}
writer.println("</table>");
writer.println("</body>");
writer.println("</html>");
    }
}

   The successor of HttpServlet for SIP networks, is the SipServlet API.
   Making most of the success of HttpServlet, the SipServlet API follows
   the same programming paradigm, so that SIP application programmers can
   reuse their knowledge in the field.

   SipServlet API works the same way as HttpServlet: an Application Server
   implements a SIP Stack and executes all the complex protocol logic. It
   receives and pre-processes the requests from the network, and at the
   right moment, passes control to the servlet doXxx() method, where the
   programmer implemented the application logic. Depending on what kind of
   SIP Message it was, a method or another will be executed. For example,
   if an INVITE is received, the doInvite() method will be invoked in the
   servlet.

   The application can then access all the parts of the request and do its
   work. When the service has been executed, it passes control back to the
   Application Server with a response, so that it can be forwarded to the
   user, and the service be satisfied.

   Sip Servlets can be used to implement basic SIP network functionalities
   (such as Proxy or Registrar servers), but their true power emerges in
   the implementation of value-added services, which greatly surpasses the
   basic service functionality of plain SIP servers.

   Examples of value-added services, are Virtual PBX or IPCentrex,
   Attended call forwarding, Instant Messaging, etc.

   This is the appearance a typical SipServlet:

   Example 1.4. Typical Sip Servlet Example
public class ProxyServlet extends SipServlet {
    protected void doInvite(SipServletRequest req) throws
ServletException, IOException
    {
        if (req.isInitial()) {
            Proxy proxy = req.getProxy();
            proxy.setRecordRoute(false);
            proxy.setParallel(parallel);
            proxy.setSupervised(supervised);
            SipURI rrURI = proxy.getRecordRouteURI();
            rrURI.setParameter("foo", "bar");
            req.setContent("Method is INVITE", "text/plain");
            proxy.proxyTo(uris);
        } else {
            log("re-INVITE");
        }
    }
    protected void doAck(SipServletRequest req) throws
ServletException, IOException
    {
        log("doAck " + req.getRequestURI());
        if (req.isInitial()) {
            throw new ServletException("unexpectedly got initial ACK");

   The servlet programming API is event-ridden: every time a request comes
   into the Application Server (may it be an Http or SIP one), the
   specific servlet is executed and the service provided within it.

   It is a very straightforward way of programming services, and the
   Servlet API provides very easy and powerful means to access information
   about the SIP-session or Http-session, about the request or response,
   about the state of the dialog, or whatever it is needed.

   The application programmer has a rich framework of resources that allow
   him to focus only on the service logic, without having to worry about
   the underlying protocol specifics (SIP or HTTP).

   Figure 1.1. SipServlet UML diagram
   SipServlet UML diagram

   The Servlet programming language is JAVA, which offers a wide spectrum
   of programming API’s dealing with all kinds of techniques, tools and
   resources, which also are available seamlessly from the Servlet
   context.

   This makes the SipServlet API very desirable for all kinds application
   developers.

   SipServlet allows a rapid SIP application development and deployment,
   and also provides a reliable and secure framework of service execution
   (the JAVA sandbox and the Application Server execution environment).

2.1.1. Converged Http/Sip Servlet Containers

   SipServlets achieve the most of it when they can be deployed along with
   HttpServlets, in the same Application Server (also known as Servlet
   Container). This environment truly realizes the power of converged
   voice/data networks: Http protocol represents one of the most powerful
   data transmission protocols used in modern networks (think of the SOAP
   web-services protocol), and SIP is the protocol of choice in most of
   the modern and future voice over IP (VoIP) networks for the signaling
   part. So an Application Server capable of combining and leveraging the
   power of these two APIs will be the most successful.

   Convergence of SIP and HTTP protocols into the same Application Server
   offers, amongst others, the following key advantages:

   -It doesn’t require to have 2 different servers (Http and Sip) so it
   relieves from maintenance problems, and eases user and configuration
   provisioning.

   -It offers great convenience to the application programmer to have all
   the classes related to the different protocols handled within the same
   code.

   -As it eases development of interactive and multimedia services,
   realizing the power of well-known web-services and intermixing them
   with new voice services.

   These are some simple, but suggestive examples of services that could
   be developed within a converged Http/Sip servlet:

   -IP Centrex: through the use of the Web-interface, users could have a
   layout of the office in a web page, and see what phones were ringing at
   a given moment, so they could pick-up a call ringing in another phone
   in their own desktop. Or they could forward a call to another party by
   clicking on the web page and selecting which of the office phones it
   had to be transferred to.

   -Voicemail: users could upload an audio file to the server through a
   web-page, to be used as the automatic answering message, and then also
   download their voicemail through the web-page, or organize the messages
   and remove the old ones.

   -Instant Messaging: users could continue a voice call by starting or
   joining a new Instant Messaging session carried over a web-page.

   -Click-to-dial: users could initiate SIP sessions only by clicking a
   link on a web page, without the need of the Web-Browser being SIP-aware
   nor needing even a SIP phone: the server could handle all the logic so
   the user who clicked could receive a call from the server’s SIP
   network.

2.2. Configuring WeSIP to work with SEAS

   The WeSIP Application Server configuration file is based on the Apache
   Tomcat configuration system: It is an XML-formatted file, in which the
   different components of the server are specified.

   The default config file that comes with the WeSIP distribution package
   should be suitable for most of the deployment configurations.

2.2.1. Server

   The topmost element in the XML configuration file is the "server" which
   has 2 xml attributes, called "port" and "shutdown". The former
   specifies a port on which the WeSIP AS will listen for the shutdown
   command, and the latter is the magic word that will make the server
   shutdown.

   Example 1.5. Server
<Server port="8005" shutdown="SHUTDOWN" >

   if you send the magic word "SHUTDOWN" to the port 8005 of the
   localhost, the server will stop cleanly.

2.2.2. Service

   Nested within the Server element, must be a "Service" element, with an
   attribute called "name" which specifies the name for the service. This
   attribute is not very relevant, you can call it whatever you like.

   Example 1.6. Service

   <Service name="WeSIP-Standalone">

   Within the Service element must be two or more elements: the connectors
   and the engines. A connector is the instance that will receive messages
   from the network. You can specify HTTP connectors and/or SIP
   connectors. Every connector needs an attribute called "className" which
   specifies which class will be responsible for receiving the messages
   from the network. For HTTP connectors, the classname must be
   "org.apache.catalina.connector.http.HttpConnector" and for SIP
   connectors "com.voztele.sipservlet.connector.SipConnector".

2.2.3. Connector

   The SIP Connector uses 4 attributes:
className="com.voztele.sipservlet.connector.SipConnector"

   specifies the classname of the connector.
minProcessors="5"

   specifies the minimum number of SIPprocessor instances (and threads in
   the pool) to process incoming SIP messages. More processors should
   allow more load to be processed. This is the minimum number of
   instances, even if they are spare and not working.
maxProcessors="10"

   specifies the maximum number of SIP processors used (a negative value
   specifies that there is no limit).
addresses="localhost:5060"

   Specifies the SIP address and port in which the Application Server from
   which the Application Server will process the SIP messages. This Addres
   is where Kamailio listens for the messages, so in fact, Kamailio is
   listening on them, but Kamailio passes the messages to WeSIP, so WeSIP
   must be aware of this IP/port.

Warning

   this attribute MUST match one of the listening points declared within
   Kamailio in the "listen" parameters.

   For example in kamailio.cfg:
listen = tcp:localhost:5060
listen = udp:localhost:5060

   Within the SIP Connector element there must be an ExtraProperties
   element, containing nestes Property elements. Each property element
   specifies a parameter for the SIP Stack. Each property is specified by
   a key and a value. The most significant keys are:
     * com.voztele.javax.sip.SER_ADDRESS
       This specifies the IP and port in which the Kamailio is listening
       for Application Servers to connect and register.This specifies the
       IP and port in which the Kamailio is listening for Application
       Servers to connect and register.

Warning
       This needs to match the listen_sockets seas module parameter within
       the Kamailio configuration file. Ie.:
modparam("seas", "listen_sockets","127.0.0.1:5080")
     * javax.sip.STACK_NAME
       Specifies the name identifying this instance of the Application
       Server.

Warning
       This is the name you will set in the Kamailio configuration script
       when you invoke the WeSIP Application Server, by calling the
       as_relay_t function. This is the name you pass as the parameter of
       the function. If you have different WeSIP instances all connecting
       to the same Kamailio, they must each one have a different
       STACK_NAME", and within Kamailio you can call each of them by
       invoking as_relay_t() with a different name. Example:
<Property key="javax.sip.STACK_NAME" value="app_server_one" />
     * com.voztele.javax.sip.THREAD_POOL_SIZE (integer)
       Specifies the number of threads there must be in the pool to
       process incoming SIP messages. If unspecificed, the default is
       "infinity".
     * com.voztele.javax.sip.SPIRAL_HDR
       This property tells WeSIP and SEAS that every SipRequest and UAC
       transaction generated from WeSIP, must spiral through SER, and will
       be added a special Header called "X-WeSIP-SPIRAL: true" this will
       make all the outgoing messages pass again through the Kamailio
       script, so that they can be accounted or whatever the configurator
       wants. For example, the configuration script could go:
route{
        if(is_present_hf("X-WeSIP-SPIRAL")){
 /* account, log, register, or whatever */
                t_relay();
        }else{
                as_relay_t("app_server_1");
        }
}

2.2.4. Engine

   The Engine must also be nested within the Server element, along with
   the Connectors. It must have a "name" attribute with whatever name you
   feel like. It needs to have another attribute called "defaultHost"
   which will be the default host to which to pass the incoming request
   (in HTTP/1.0 the requests dont have a Host header, so they will be
   passed to this default host, in SIP, this attribute doesn't have a
   meaning.). In order to have this Engine handling also SIP messages, the
   "className" attribute of the Engine must be
   "com.voztele.sipservlet.core.ConvergedEngine".

   Within the Engine, there can be one or more Hosts, each one specified
   within a "Host" element nested in the engine.

2.2.5. Mapper

   A mapper is used to map an incoming request to one or another SIP or
   HTTP host. In case it is a SIP request, the mapping is done based on
   the sip.xml deployment descriptor rules. The classname of the SIP
   mapper MUST BE "com.voztele.sipservlet.core.EngineSipMapper". The
   "mapper" element must also have a "protocol" attribute, specifying
   which protocol this mapper handles. In case of the SIP mapper it must
   be "SIP/2.0". The HTTP mapper's classname must be
   "org.apache.catalina.core.StandardEngineMapper" and the protocol
   attribute "HTTP/1.1"

2.2.6. Realm

   The authentication in HTTP is performed in Apache-Tomcat through
   Realms. The memory realm is (textual copy from the Apache-Tomcat
   javadoc"): "Simple implementation of Realm that reads an XML file to
   configure the valid users, passwords, and roles."

   The classname must be "org.apache.catalina.realm.MemoryRealm"

   A "pathname" attribute can be specified to tell the Realm which file
   contains the usernames, passwords and roles. If not specified, it is
   "conf/wesip-users.xml"

2.2.7. Host

   A Host represents a VirtualHost in HTTP/1.1 servers, so the requests
   will be dispatched to one or another virtual host depending on the
   Host: header. In SIP this doesn't make much sense, because there's no
   such Host: header, and virtual hosting is not done in this way. Every
   host must have a "name" attribute which specifies the name of the
   virtual host, it must also have a "nameSip" attribute which MUST MATCH
   the IP or hostname _and_ port" specified in Kamailio listen parameters
   and in the Sip Connector the hostname and the port must be separated
   with an underscore. for example: nameSip="localhost_5060" or
   nameSip="192.168.1.1_5060" The next important attribute that must have
   the Host element is "appBase" which declares the directory where the
   WEB and SIP applications reside. It usually is a directory called apps
   in the directory from which the server runs. The attribute "unpackWARs"
   says the WeSIP Application Server to unpack the Web or Sip Application
   Archives (.war or .sar extensions) found inside the appBase directory.
   It should usually be set to "true". The "port" attribute specifies the
   port where this host is going to receive SIP messages . This only has
   to do with the SIP protocol, not with HTTP. It must be the same as the
   port specified in Kamailio parameter "listen_sockets" (for the seas
   module). The "autoDeploy" attribute tells the host to monitor the
   "appBase" directory for new application archives (.sar or .war) so they
   can automatically be deployed. This parameter should be set to "true".
   The "className" used for the Host _must_be_
   "com.voztele.sipservlet.core.ConvergedHost"

2.2.8. Mapper

   Hosts must also have a nested Mapper element, but when the mapper is
   inside a Host (and not in an Engine) the classnames must be
   "com.voztele.sipservlet.core.SipHostMapper" for the "SIP/2.0" protocol
   and "org.apache.catalina.core.HttpHostMapper" for the "HTTP/1.1"
   protocol. (2 mappers must be nested inside the Host).

2.3. Configuration Examples

   In general, you can configure WeSIP to work with your Kamailio in two
   ways: have 2 Kamailio instances, the first acting as
   Proxy/Registrar/Redirect and the second cooperating with WeSIP to act
   as the Application Server. This is the preferred deployment layout, as
   the first Kamailio works as usual, and the requests that need special
   services are relaied to another Kamailio which acts on behalf of the
   WeSIP AS. This configuration profile distributes load (call-routing
   logic in one instance, and Application Services in the other), and is
   also more fault-tolerant. On the other hand, you can have all your
   call-routing logic and Application Server on the same Kamailio, having
   one script handle all the logic, and then invoking the App Server at
   any point.

2.3.1. kamailio.cfg in standalone

debug=3            # debug level (cmd line: -dddddddddd)
fork=yes
log_stderror=no    # (cmd line: -E)
check_via=no    # (cmd. line: -v)
dns=no          # (cmd. line: -r)
rev_dns=no      # (cmd. line: -R)
port=5060
children=4
loadmodule "/usr/local/lib/kamailio/modules/sl.so"
loadmodule "/usr/local/lib/kamailio/modules/tm.so"
loadmodule "/usr/local/lib/kamailio/modules/rr.so"
loadmodule "/usr/local/lib/kamailio/modules/maxfwd.so"
loadmodule "/usr/local/lib/kamailio/modules/usrloc.so"
loadmodule "/usr/local/lib/kamailio/modules/registrar.so"
loadmodule "/usr/local/lib/kamailio/modules/textops.so"
loadmodule "/usr/local/lib/kamailio/modules/seas.so"
loadmodule "/usr/local/lib/kamailio/modules/mi_fifo.so"

modparam("mi_fifo", "fifo_name", "/tmp/openser_fifo")
modparam("usrloc", "db_mode",   0)
modparam("rr", "enable_full_lr", 1)
modparam("seas", "listen_sockets", "127.0.0.1:5080");

route{
       if (!mf_process_maxfwd_header("10")) {
               sl_send_reply("483","Too Many Hops");
               exit;
       };
       if (msg:len >=  2048 ) {
               sl_send_reply("513", "Message too big");
               exit;
       };
       if (!method=="REGISTER")
               record_route();
       if (loose_route()) {
               append_hf("P-hint: rr-enforced\r\n");
               route(1);
       };
       if (uri==myself) {
               if (method=="REGISTER") {
                       save("location");
                       exit;
               };
               lookup("aliases");
               if (!uri==myself) {
                       append_hf("P-hint: outbound alias\r\n");
                       route(1);
               };
               if (!lookup("location")) {
                       sl_send_reply("404", "Not Found");
                       exit;
               };
               append_hf("P-hint: usrloc applied\r\n");
       };
       route(1);
}
route[1] {
                if(!as_relay_t("app_server_one")){
                       t_reply("500","Application Server error");
               }
}

2.3.2. kamailio.cfg working as WeSIP front-end

debug=9            # debug level (cmd line: -dddddddddd)
fork=yes
log_stderror=yes    # (cmd line: -E)

check_via=no    # (cmd. line: -v)
dns=no          # (cmd. line: -r)
rev_dns=no      # (cmd. line: -R)
port=5060
children=4

reply_to_via=1
listen = tcp:localhost:5060
listen = udp:localhost:5060

mpath="/home/elias/src/sipservlet/seas"

loadmodule "modules/tm/tm.so"
loadmodule "modules/seas/seas.so"
loadmodule "modules/mi_fifo/mi_fifo.so"

modparam("mi_fifo", "fifo_name", "/tmp/openser_fifo")
modparam("seas", "listen_sockets","127.0.0.1:5080")

route{
                if(!as_relay_t("app_server_1")){
                        t_reply("500","Application Server error");
                }

}

2.3.3. Server.xml

<Server port="8005" shutdown="SHUTDOWN" debug="0">
  <Service name="WeSIP-Standalone">
    <Connector className="org.apache.catalina.connector.http.HttpConnector"
        port="8080" minProcessors="5" maxProcessors="75"
        enableLookups="true" address="localhost" acceptCount="10" debug="10" />
        <Connector className="com.voztele.sipservlet.connector.SipConnector"
        minProcessors="5" maxProcessors="75"
        addresses="localhost:5060" >
               <ExtraProperties>
                       <Property key="com.voztele.javax.sip.SER_ADDRESS" value="
127.0.0.1:5080" />
                       <Property key="javax.sip.STACK_NAME" value="app_server_on
e" />
                       <Property key="com.voztele.javax.sip.THREAD_POOL_SIZE" va
lue="10" />
               </ExtraProperties>
       </Connector>
    <Engine name="Standalone" defaultHost="localhost" debug="10"
       className="com.voztele.sipservlet.core.ConvergedEngine">

        <Logger className="org.apache.catalina.logger.SystemOutLogger"
           timestamp="true"/>
        <Mapper className="org.apache.catalina.core.StandardEngineMapper" protoc
ol="HTTP/1.1"/>
        <Mapper className="com.voztele.sipservlet.core.EngineSipMapper" protocol
="SIP/2.0"/>
        <Realm  className="org.apache.catalina.realm.MemoryRealm" />
        <Host name="localhost" nameSip="localhost_5060" debug="10" appBase="weba
pps" unpackWARs="true"
        port="5060" autoDeploy="true" className="com.voztele.sipservlet.core.Con
vergedHost">
               <Mapper className="com.voztele.sipservlet.core.SipHostMapper" pro
tocol="SIP/2.0"/>
               <Mapper className="org.apache.catalina.core.HttpHostMapper" proto
col="HTTP/1.1"/>
     </Host>
  </Engine>
</Service>
</Server>

Chapter 2. Developer Guide

   Table of Contents

   1. Internals
   2. SEAS Protocol

        2.1. The SEAS protocol
        2.2. General codification of a header

              2.2.1. Codification of a generic URI
              2.2.2. Codification of To and From headers
              2.2.3. Codification of Contact
              2.2.4. Codification of Route and Record Route headers
              2.2.5. Codification of Accept and Content-Type headers
              2.2.6. Codification of Authorization headers
              2.2.7. Codification of Allow headers
              2.2.8. Codification of Content-Disposition headers
              2.2.9. Codification of Content-Length header
              2.2.10. Codification of Cseq header
              2.2.11. Codification of Expires header
              2.2.12. Codification of a SIP message

                    2.2.12.1. The general message information section
                    2.2.12.2. The headers index section

1. Internals

   The SEAS module runs within the Open Sip Express Router aka. Kamailio.
   Kamailio uses a pool of processes to execute the script logic on every
   new message received. These are called the worker processes. One of
   these processes will be selected to process the script, and at some
   point it will find a function invoking the relay of the SIP message to
   one of the Application Servers registered. This function has been
   called as_relay_t, which stands for Application Server relay (the _t
   stands for TransactionStatefully), and receives as the only parameter
   the name of the application server to be invoked.

   The process will execute the as_relay_t function, which looks up in a
   table if there is a registered Application Server with that name. If
   there is one, the process will craft the SEAS header for the SIP
   message being handled, put it in a shared memory segment, and write the
   address of that segment to a pipe (4 bytes pointer in IA32).

   This way, we will have all the Kamailio processes composing the SEAS
   header along with the SIP message, and putting its shared memory
   address into that pipe. This technique of inter-process communication
   avoids race conditions because writing to a pipe is granted to be an
   atomic operation if the data to write is less than _POSIX_PIPE_BUF,
   which usually is 512 bytes.

   At the initialization of Kamailio, the SEAS module creates the
   discussed pipe, so that all the Kamailio worker processes inherit the
   file descriptor associated to the pipe. Then it spawns a new process,
   which will be the one to open two server sockets, and wait for the
   Application Servers to connect and register.

   Each Application Server wishing to receive events from Kamailio, will
   have to open a socket to the module (the port and IP of the socket are
   defined at start time in the script). After connection, it has to print
   its identification name. The SEAS process (from now on, called event
   dispatcher) will then register it in its internal structures, so that
   the Kamailio processes can push events for it. The following picture,
   shows the internals of the SEAS Event dispatcher process:

   Figure 2.1. Overview of Seas Event Dispatcher process operation
   Overview of Seas Event Dispatcher process operation

   Within the SER server, the flowing of SIP Messages and control flow, is
   depicted in the following diagram:

   Figure 2.2. SIP Messages and control flow within SER
   SIP Messages and control flow within SER

2. SEAS Protocol

   2.1. The SEAS protocol
   2.2. General codification of a header

        2.2.1. Codification of a generic URI
        2.2.2. Codification of To and From headers
        2.2.3. Codification of Contact
        2.2.4. Codification of Route and Record Route headers
        2.2.5. Codification of Accept and Content-Type headers
        2.2.6. Codification of Authorization headers
        2.2.7. Codification of Allow headers
        2.2.8. Codification of Content-Disposition headers
        2.2.9. Codification of Content-Length header
        2.2.10. Codification of Cseq header
        2.2.11. Codification of Expires header
        2.2.12. Codification of a SIP message

              2.2.12.1. The general message information section
              2.2.12.2. The headers index section

   SIP is a very flexible protocol. It can be very easily extended with
   new features, and SIP entities have a high level of freedom in
   composing the SIP messages, for example setting IPs or hostnames in
   URIs, reordering header fields, folding headers, aggregating/scattering
   headers, etc.

   This flexibility, though, makes it difficult to implement efficiently,
   because parsing of text headers requires a lot of state.

   Kamailio implements a very efficient parsing mechanism and
   SIP-transaction machinery. The goal of the SEAS protocol is to keep all
   this information that has been already extracted at Kamailio, so that
   it can be reused at the Application Server.

2.1. The SEAS protocol

   The SEAS protocol is a layer of information regarding the internal
   structure of a SIP message that is added whenever SEAS sends a SIP
   event to the Application Servers. The protocol is used for
   communication between Kamailio and the Application Servers.

   Once an incoming SIP message has reached the worker process within
   Kamailio, it copies its content into a private memory area (which is, a
   memory chunk not shared across processes). In this point, the message
   first line is parsed to know whether it is a SIP request or response.

   Kamailio uses a technique called lazy-parsing, which consists in
   delaying the parse of headers until some piece of the code requires it.

   As the SIP message goes traversing functions and the script code, a
   function called parse_msg() gets called again and again, and the SIP
   message gets parsed further and further. Each call to parse_msg passes
   an integer value argument (32 bits) in which every bit signals a header
   to be parsed, if they are already parsed (because a previous invocation
   of parse_msg), the function returns immediately, otherwise, the SIP
   message is scanned and parsed until all the headers requested get
   parsed.

   In each call to parse_msg, different parts of the message are analyzed,
   and different SIP header-specific structures get filled. Each one of
   this structures, give quick access to each of the parts of a SIP
   message header.

   For example, a Via header struct is called via_body, and has these
   members: name, version, transport, host, proto, port, port_str, params,
   comment, received, rport, etc. each of these members gives quick access
   to each of the parts of the header. For example, a via header like
   this: “Via: SIP/2.0/UDP 192.168.1.64:5070;branch=z9hG4bK-c02c60cc”
   would have the member proto pointing to the “U” of “UDP”, and a length
   of 3, the host member would be pointing to “192.168.1.64” and have a
   length of 12, the branch member would be pointing to “z9hG4bK-c02c60cc”
   and a length of 16, and so on.

   This structure is the result of the parsing. All this meta-information
   regarding the SIP message structure, is stored in a sip_msg structure,
   using dynamically-allocated memory segments.

   Kamailio defines different structure types describing different SIP
   headers, such as via_body, to_body, cseq_body, via_param, and so on.
   These structures are generally composed of another kind of structure
   called str.

   The str structure is a key component of Kamailio's high performance. In
   the C programming language, a string's length is known because a '0'
   (null-character) is found at the end of it. This forces each of the
   string manipulation functions to keep looking for a '0' in the byte
   stream, which is quite processor consuming. Instead of this, Kamailio
   defines a structure composed of a char pointer and an integer. The char
   points to the start of a string, and the integer gives its length, thus
   avoiding the '0' lookup problem, and giving a significant performance
   boost.

   This structure has been quite useful to the design of the SEAS
   protocol, because it enables the description of the SIP message anatomy
   by giving pointers to each of its fields, and integers describing each
   of its lengths.

   Knowing that a SIP header does not usually occupy more than a few
   characters (always less than 256), the pointer in the structure has
   been relativized to the beginning of the SIP message or the beginning
   of the SIP header, and the integer giving the length, has been casted
   to an unsigned byte (256 values, so 256 characters maximum length).

   When messages get transferred from Kamailio to the Application Server,
   it is optimum to keep this worthy meta-information regarding the SIP
   message, so that it can be used at the AS part. For this to be
   possible, it is needed to store the pointers to each of the syntactic
   structures and their length.

   In general, pointers are variables that point to a region in the memory
   of a computer. The region of the memory is counted from the 0x00000000
   address in IA32 architectures (from the beginning).

   C provides functionality to do any kind of arithmetic operations over
   pointers (add, subtract, multiply and divide), so that the euclidean
   distance over the one-dimension address space can be calculated just by
   subtracting a base address from another pointer.

   These pointers will have to be transmitted through the network, along
   with the SIP message, so for the pointers to keep their meaning, they
   need to be relativized to a known point, and the most meaningful known
   point in a SIP message is its start.

   So making the pointers relative to the message start, gives two
   important features: first, it makes the pointers still valid when they
   arrive at another computer (because they are relative to the beginning
   of the message), and they occupy far less memory, because from a 4-byte
   pointer (in IA32) it gets translated to a 1 or 2 byte index, because an
   important amount of redundant information is elicited (we already know
   that each of the parts of the message belong to the message, so why
   carry the message begin address in each of the pointers ?).

   The SIP messages are composed of protocol headers and a payload. The
   headers section don't usually surpass the 1500 byte limit, amongst
   other reasons, because the usual Maximum Transmission Unit in Ethernet
   networks is 1500 bytes and the protocol was initially designed to work
   on UDP. For that reason, 11 bits should be enough to address a
   particular region within the SIP message, because it yields 2048
   positions. The closest greater value to 11 bits multiple of a byte (the
   basic TCP network transport unit) is 16 bits, or 2 bytes, which makes
   it possible to address 65536 positions from the beginning.

   For the SEAS protocol to be extensible and platform-independent, all
   the 2-byte pointers or indexes to each of the message regions are sent
   in network-byte-order, or big endian. This is also useful in the JAVA
   part to retrieve the indexes, because the JAVA natively uses a
   big-endian representation of integers, regardless the architecture on
   which it runs.

   For each kind of standard SIP header (this is, the headers referred to
   in the SIP specification) there is a code specification, regarding the
   composition of the header. Each one of its parts points to one the
   several components of the header. For example, a From header always has
   a SipURI and may have several parameters, amongst others, a tag. Then,
   the From header code has a field indicating where the URI starts, a
   codification of the URI, and several pointers that point to each one of
   the parameter names and values. This is the codification of the From
   header. All the other headers have a similar codification.

2.2. General codification of a header

   Every header codification, regardless it is known to the server or not,
   begins with a 2-byte unsigned integer, which points to the beginning of
   that header counted from the SIP message begin (a SIP message start
   based pointer to the header). Following these two bytes is another byte
   giving the length of the name, and another byte giving the length of
   the entire header (including name and value).

   Figure 2.3. General codification of a SIP header in SEAS protocol
   General codification of a SIP header in SEAS protocol

   For example:

   Figure 2.4. Example of a from header SEAS-protocol codification
   Example of a from header SEAS-protocol codification

2.2.1. Codification of a generic URI

   As the SIP URI is one of the most used types in a SIP message, a
   special structure has been defined to describe the contents of it. A
   URI is always included inside a SIP header, or may be in the first line
   of a SIP Request (as the request URI).

   The codification of any URI is as follows:

   Figure 2.5. SEAS-codification of a SIP URI (byte meanings are shown)
   SEAS-codification of a SIP URI (byte meanings are shown)

   What follows is an example of a SIP URI codification with the SEAS
   protocol.

   Figure 2.6. Example of a SEAS SIP URI codification
   Example of a SEAS SIP URI codification

   The first byte in the encoded-URI structure, gives the index where the
   URI starts, counting from the beginning of the SIP header where it
   appears. The next two bytes are flags indicating known fields present
   in the URI (such as port, host, user, etc.).

   All the following bytes are uri-start based pointers to the fields that
   are present in the URI, as specified by the flags. They must appear in
   the same order shown in the flags, and only appear if the flag was set
   to 1.

   The end of the field, will be the place where the following pointer
   points to, minus one (note that all the fields present in a URI are
   preceded by 1 character, ie
   sip[:user][:passwod][@host][:port][;param1=x][;param2=y][?hdr1=a][&hdr2
   =b]) it will also be necessary to have a pointer at the end, pointing
   two past the end of the URI, so that the length of the last header can
   be computed.

   The reason to have the “other parameters” and headers flags at the
   beginning (just after the strictly URI stuff), is that it will be
   necessary to know the length of the parameters section and the headers
   section. The parameters can appear in an arbitrary order, they won't be
   following the convention of transport-ttl-user-method-maddr-lr, so we
   can't rely on the next pointer to compute the length of the previous
   pointer field, as the ttl parameter can appear before the transport
   parameter. So the parameter pointers must have 2 bytes: pointer+length.

2.2.2. Codification of To and From headers

   To and From headers follow the same structure, so the same codification
   structure has been used to describe both. The structure is depicted in
   the drawing:

   Figure 2.7. SEAS codification of From and To headers
   SEAS codification of From and To headers

2.2.3. Codification of Contact

   The contact header is one of those SIP headers that can be combined,
   which means that if several headers of the same type are present in the
   message, they can be aggregated in a single header, having the header
   values separated by a comma. Thus, a single Contact header can contain
   more than one contact-value. For this reason, the Contact codification
   is composed of a several Contact codifications concatenated, and a byte
   at the beginning telling how much Contact codifications are present.
   The code is depicted in the following drawing:

   Figure 2.8. SEAS codification of a Contact header
   SEAS codification of a Contact header

2.2.4. Codification of Route and Record Route headers

   Both Route and Record-Route headers follow an identical structure, and
   it is also permitted to combine several headers into one, with their
   bodies (or header values) separated by commas. In this case, both kinds
   of headers follow the same structure, defined as follows:

   Figure 2.9. SEAS codification of a Route Header
   SEAS codification of a Route Header

2.2.5. Codification of Accept and Content-Type headers

   These two kinds of headers carry mime type and subtype definitions in
   the form “type/subtype” (ie. text/xml, application/sdp or whatever).
   For internal handling of this headers, SER codifies the known types and
   subtypes into a single 32 bit integer, with the highest two bytes
   giving the mime type, and the lowest two bytes giving the subtype.

   The difference is that Accept header can also be combined, carrying
   more than one header value in a single header row. Thus the Accept
   header has a leading byte giving the number of mime type/subtype
   integers present, while the Content-Type only uses 4 bytes (a 32-bit
   integer) giving the type/subtype.

2.2.6. Codification of Authorization headers

   SIP has inherited the authentication scheme from HTTP, which is based
   on a digest scheme. There are several headers regarding these
   authorization scheme, namely Proxy-Authenticate, WWW-Authenticate,
   Authorization and Proxy-Authorization. All of them can be codified
   using the same schema, which is as follows:

   Figure 2.10. SEAS codification of Authentication/Authorization headers
   SEAS codification of Authentication/Authorization headers

   For each field present, there are 2 bytes, one pointing the place where
   it starts, the next giving how long this field is. The URI is a special
   case, and is composed of 1 byte telling how long is the URI structure,
   and then the encoded URI structure.

2.2.7. Codification of Allow headers

   Allow headers carry request methods that a user agent or proxy
   understands or is willing to accept. In SER, request methods are
   codified into a 32-bit integer, each of its bits signals a different
   kind of header. The Allow header is codified copying that integer into
   the payload of the header.

2.2.8. Codification of Content-Disposition headers

   The content-disposition is encoded within 2 bytes: the first is a
   header-start based pointer to where the content-disposition value
   starts, and the second is its length. If there are parameters present,
   each of them uses 1 byte pointing to where the parameter name starts,
   and 1 byte pointing to where the parameter value starts. From these two
   values, the parameter name and value lengths can be inferred.

2.2.9. Codification of Content-Length header

   The content length header is codified as a 4-byte unsigned integer, in
   network byte order.

2.2.10. Codification of Cseq header

   The Cseq header is codified using 9 bytes. The first one is a number
   corresponding to the internal value that SER assigns to that request
   method (the method ID). The following 4 bytes are an unsigned 32-bit
   integer according to the Cseq number. The next two bytes are the header
   based pointer to the beginning of the Cseq number and its length, and
   two more bytes pointing to the beginning of the method name and its
   length.

2.2.11. Codification of Expires header

   The expires header is composed of 6 bytes. The first four bytes are an
   unsigned 32-bit integer with the parsed value of the header (which is
   the number of seconds before a request expires). Then follows 1 byte
   pointing to the beginning of the header value (the expires value as a
   string) and a byte giving the length of the value.

2.2.12. Codification of a SIP message

2.2.12.1. The general message information section

   In SER, not only the headers are parsed with a high degree of
   optimization, but also the first line is. So for the SEAS protocol to
   realize this improvement, a codification for the first line of every
   SIP messages has also been defined.

   The first two bytes of the codification are a 2-byte unsigned integer.
   If its value is equal or greater than 100, then this is a response, and
   the integer represents its status code. If its value is smaller than
   100, then it is a request, and the integer represents the method of the
   request being transported.

   Figure 2.11. SEAS codification of a SIP First Line
   SEAS codification of a SIP First Line

   The next two bytes are an unsigned integer which is a pointer to where
   the actual SIP message starts, beginning from the start of the codified
   payload.

   The next two bytes are also an unsigned integer giving the SIP message
   length.

   The next bytes differ on the meaning depending on whether the message
   is a SIP Request or Response.

   In case it is a Request:

   The next two bytes, are a SIP-message-start based pointer to where the
   method begins, and the method length.

   The next two bytes, are a SIP-message-start based pointer to where the
   Request URI begins, and the request URI length.

   The next two bytes, are a SIP-message-start based pointer to where the
   version identifier begins, and the version identifier length.

   In case it was a Response:

   The next two bytes, are a SIP-message-start based pointer to where the
   response code begins, and the response code length.

   The next two bytes, are a SIP-message-start based pointer to where the
   reason phrase begins, and the reason phrase length.

   The next two bytes, are a SIP-message-start based pointer to where the
   version identifier begins, and the version identifier length.

   In case the message is a SIP response, the following bytes correspond
   to the Request URI codification. The first byte is the length of the
   URI codification, followed by the URI code.

   The last byte in this set, is the number of headers present in the SIP
   message. After this byte, goes a section, called the Message Headers
   Index, which gives quick access to each of the headers and their
   codifications present in the message.

2.2.12.2. The headers index section

   As it has been already discussed, the aim of SEAS project is to achieve
   as high a performance as possible. One of the techniques enabling high
   performance in text-based servers is the so called lazy parsing. To
   enable the laziest possible parsing at the Application Server endpoint,
   a mechanism has been used so that access to a requested SIP header can
   be delayed until the application requests it, and the access can be
   direct to that header, without parsing the former headers present in
   the SIP message. Recall that one of the performance drawbacks of the
   SIP protocol is that headers of any type can be spread all along the
   header section, not having the constraint of putting the most critical
   sip-specific headers at the beginning and ordered (which would be, in
   fact, very desirable).

   For this to be possible, there is a section right after the beginning
   of the payload (the general message information section) which is a
   kind of hash table, giving quick access to the codes (as explained in
   the previous sections) of each of the headers present in the message.

   This sort of hash table, is composed of triplets of bytes. The first
   byte of each three is a code indicating which kind of header it points
   to (whether it is a From, To, Call-ID, Route header, etc). Then follows
   a 2 byte network-byte-order integer that points to a section in the
   codified-header where the body of this header is more specifically
   described.

   This gives really fast access to any of the headers. For example, if
   all the Route Headers were requested by the application, then a lookup
   in this table would be necessary, looking for the value '9'
   (corresponding to the Route header) in each of the positions multiple
   of 3 (0,3,6,9,12, etc). This can be done in a extremely fast and easy
   way, as this snipped of pseudo code explains:

   for(int j=0,int i=0;i<table_length;i+=3){

   if(payload[i]==9)

   results[j++]=i;

   }

   this would let in the “results” array all the indexes in the headers
   table that refer to a Route header. Then, the Route codification for
   each of the headers could be reached thanks to the two-byte unsigned
   integer that follows each of the header identifiers.

   Figure 2.12. SEAS Headers Index section overview
   SEAS Headers Index section overview

   So a SIP message codified by the SEAS protocol, has the following
   layout:

   Figure 2.13. SEAS SIP-Message codification
   SEAS SIP-Message codification

   SIP Messages are a fundamental part of the protocol, but they are not
   the only one. Transaction play a very important role in the SIP
   protocol, within SER and in any JAIN-SIP implementation. For this
   reason, the SEAS protocol also needs to define and implement some
   semantics regarding transaction handling. The events related to a
   transaction are: Incoming Request, Outgoing Request, Incoming Response,
   Outgoing Response, Timeout and Transport Error.

   So the SEAS protocol defines a specific format for each one of these
   events. Internally, SER stores the transactions in a hash table. This
   hash table generates an integer for each transaction applying a hash
   function to its Via branch parameter, this integer is the hash index,
   and it identifies in which slot within the hash table the transaction
   is stored. The transaction table usually uses 65536 entries, so the
   hash collision is pretty unlikely. Anyway, every hash entry is in
   reality a linked list of transactions, so in the case a hash collision
   (two transactions being assigned to the same hash slot) the
   transactions are added to the same slot, each one being identified by
   another integer called the label. The label within a hash slot, is
   initially generated randomly, and then increased by one each time a
   transaction falls in the same slot. So every transaction is identified
   by a hash index and a label.

   For incoming SIP requests, a transaction is generated at SER, and the
   SEAS module gets that transaction identifier (hash index + label), then
   grabs the source and destination IP, port and transport from every
   message, and crafts a SEAS RequestIn event. This kind of event carries
   all this information within it.

   In order to send Responses out for the Server Transactions, JAIN can
   send a type of Action messages, that order SER to send them to the
   network. These messages follow a structure very similar to that of
   RequestIn events: they start with the Action length in bytes, then
   follows a byte giving the type of action, then follows the Hash Index
   and the Label associated with the transaction that is being replied,
   and finally the SIP Message in raw format. It doesn’t use the SEAS
   codification described above, because SER can easily parse the JAIN
   provided Response to process it and send it out, so the pre-parsing is
   not needed in that direction.

   In order to generate Client Transactions, that is, sending SIP Requests
   out, JAIN utilizes another kind of action called Seas Request Action.
   In this case, when JAIN generates the Request to be sent out, it
   doesn’t have any means to know the transaction identifier (hash index
   and label) that will be assigned to it by SER, so a new mechanism has
   bee implemented to correlate JAIN requests to SER transactions.
   Basically, JAIN-SIP assigns a unique identifier (an integer) that is
   incremented by one for each new Client Transaction generated. This
   identifier is passed to SER along with the SIP Request, so when a SIP
   Response arrives to SER regarding that transaction, SER sends a
   ResponseIn event to the JAIN stack, containing both the initial integer
   identifying the transaction at JAIN and the hash index and label that
   have been assigned to the transaction. This way, JAIN can correlate its
   own identifiers with the identifiers used within SER.

   Figure 2.14. Different kinds of SEAS codified Events and Actions
   Different kinds of SEAS codified Events and Actions

   In case there is a Transaction Timeout, it is notified to the JAIN SIP
   Stack by passing it a Seas Incoming Response with a flag called Faked
   Reply, and a Response code number 408 (Request Timeout).