# oSIP user Manual

## A guide to implement SIP agents with the oSIP stack.

### Aymeric Moizard

jacK@atosc.org

Abstract

"The Session Initiation Protocol (SIP) is an application-layer control (signaling) protocol for creating, modifying and terminating sessions with one or more participants. These sessions include Internet multimedia conferences, Internet telephone calls and multimedia distribution. Members in a session can communicate via multicast or via a mesh of unicast relations, or a combination of these."

### IETF - rfc 3261

Copyright (c) 2001,2002,2003,2004,2005 Aymeric MOIZARD. Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.1 or any later version published by the Free Software Foundation; with the Invariant Sections being LIST THEIR TITLES, with the Front-Cover Texts being LIST, and with the Back-Cover Texts being LIST. A copy of the license is included in the section entitled "GNU Free Documentation License".

# Chapter 1. The SIP protocol

SIP is a signaling protocol used to initiate and control multimedia sessions. It is already published by IETF (www.ietf.org) as the rfc3261.

SIP is part of the IETF effort to bring telephony on the IP network. It is about to become the standard used by the emerging IP telephony industry. As simple as the mail protocol, it may become as popular...

# SIP is independent of media

The traditional telephony was based on one media. Now, it's over. Your phone will be able to connect to a TV, to a camera, to others phones with different qualities and different codecs. Hopefully, SIP is independent of any media used by the applications. SIP is able to negotiate media used within sessions. Any multimedia application (games, distance learning application) can use SIP to set up sessions.

# SIP is independent of the transport layer

SIP is not tight to any transport protocol. This aspect will minimize efforts to interoperate with new third generation networks. Wireless phones are also concerned. A SIP stack perfectly fits the signaling needs of the new cellulars' generation.

# SIP is extensible

The rfc3261 defines 6 types of transaction (INVITE, BYE, CANCEL...). Those transactions are used to negotiate media, set up, modify and terminate calls. Many services are already provided this way but SIP is designed for extensibility and the transactional model can be reused (transparently for servers) by new type of transaction to create some supplementary services. Here is a list of possible services:

MESSAGE for instant messaging
SUBSCRIBE/NOTIFY for presence management
REFER for call-transfer management

# SIP and end-user services

"SIP transparently supports name mapping and redirection services, allowing the implementation of ISDN and Intelligent Network telephony subscriber services. These facilities also enable personal mobility."

rfc3261.txt (Section 1.1)

SIP servers are used to locate users and distribute location (through urls) on demand. This way, end user agents have very minimal requirements and still have access to a wide variety of services.

Many extensions are already available as draft. Your can also add your personal phone capabilities and remain interoperable with existing servers.

# Chapter 2. SIP overview

This section does not intend to fully describe the RFC. It is a fast and incomplete overview of the protocol syntax and behavior.

# SIP syntax

SIP is a text protocol based on utf8 encoding. (making it more readable and easier to debug) SIP describes a syntax for SIP requests, URL, responses and their headers. The full syntax is available in the rfc3261 in an augmented BNF form.

The syntax is borrowed from the MAIL and HTTP syntax. 6 types of requests are defined by SIP. The basic available methods are:

INVITE
ACK
CANCEL
BYE
INFO
OPTIONS

As you can see in the BNF definition of request (see rfc3261.txt section 3), SIP is not limited to this short list of methods and includes in its definition the extension-method token. Any other request can be handled by oSIP. NOTIFY and SUBSCRIBE are good examples of new possible methods. These ones are used specifically to provide presence capabilities to your SIP phone without much effort.

Example 2-1. INVITE request

INVITE requests are used to initiate and modify sessions. Here, cha from sipworld.net is calling jack at domain atosc.org. This request should be sent to the proxy server managing atosc.org, it will forward the call to jack at his real IP address.

    INVITE sip:jacK@atosc.org SIP/2.0
    Via: SIP/2.0/UDP home.sipworld.org;branch=z9hG4bK776asdhds
    Max-Forwards: 70
    To: sip:jacK@atosc.org
    From: sip:cha@sipworld.org
    Call-ID: 35778645354@home.sipworld.org
    CSeq: 1 INVITE
    Contact: sip:cha@home.sipworld.org
    Content-type: application/sdp
    Content-length: 267

    v=0
    o=user1 53655765 2353687637 IN IP4 128.3.4.5
    s=Mbone Audio
    i=Discussion of Mbone Engineering Issues
    e=mbone@somewhere.com
    c=IN IP4 128.3.4.5
    t=0 0
    m=audio 3456 RTP/AVP 0
    a=rtpmap:0 PCMU/8000

# SIP transactions

In order to control sessions, SIP uses transactions. Transactions (INVITE, CANCEL, BYE...) usually result in a modification of a current session. Some other transactions (SUBSCRIBE, NOTIFY...) are not bound to a session. A transaction is composed of one request and its responses (many informational responses and one final response). The following headers: To, From, Call-ID and CSeq are used to identify messages within a transaction.

Since the rfc3261, The "branch" parameter from the "Via" header provides a unique string to match requests and responses within a transactions.

As SIP often use unreliable transport protocol (UDP is recommended but TCP or TLS can be prefered), SIP also defines retransmission rules for messages within a transaction.

Example 2-2. INVITE transaction

This is the most basic call flow showing the initiation of a session. Only two SIP User Agents (UAC/UAS) are involved. (retransmissions are hidden)

    	          UAC1               UAS2

    	  jacks    |   INVITE         |
    	initiate a |----------------->|
    	  call     |                  |
    	           |       100 Trying |
    	           |<-----------------|   Bob's
    	           |       180 Ringing|  Phone starts
    	           |<-----------------|   ringing
    	           |                  |
            	   |                  |
    	           |           200 OK |
    	           |<-----------------|
    	           |   ACK            |
    	           |----------------->|

# SIP sessions

Transactions are used by user agent as means to control sessions. A session is always initiated by an INVITE. SIP defines a large set of answer codes. A proxy may answer you the well known "404 User Not found" as for an HTTP error. Errors have different levels. A transaction can fail but still proposes new locations to try. Responses from class 3xx are used to redirect calls. 4xx, 5xx and 6xx responses are respectively reserved for client error, server error and global failure.

Example 2-3. A complete session

First, both user agents must send a REGISTER to a registrar. In the following example, the proxy also support registration.

This session is initiated with an INVITE transaction to join jack at home.net. A redirection to jack's office is made by the redirect server of home.net. UA1 understands the redirection and sends a new INVITE towards the real User Agent (UA2) currently used by jack at office.atosc.org. UA2 first rings and jack accepts the call with a 200 OK response. After several minutes, jack and bob want to use their new cameras. The session is modified with an INVITE sent by jack to negotiate new parameters for video. The session is finally ended by bob.

             BOB           home.net    Jack (office.home.net)
             UA1            PROXY            UA2
              | REGISTER      |               .
              |-------------->|               .
              |        200 OK |               .
              |<--------------|               .
              .               .               .
    later...  .               .               .
              .               .               .
              .               |      REGISTER |
              .               |<--------------|
              .               | 200 OK        |
              .               |-------------->|
              .               .               .
    later...  .               .               .
              | INVITE jack@home.net          .
              |-------------->|               .
              |302 Moved temporarily            .
              |<--------------|               .
              | ACK           |               .
              |-------------->|               .
              | INVITE jack@office.home.net   |
              | audio                         |
              |------------------------------>|
              |                  100 Trying   |
              |<------------------------------|
              |                  180 Ringing  |
              |<------------------------------|
              |                       200 OK  |
              |<------------------------------|
              | ACK jack@office.home.net      |
              |------------------------------>|
              .                               .
    later     .                               .
              .                               .
              |      INVITE bob@bob.home.net  |
              |      audio + video            |
              |<------------------------------|
              |    200 OK                     |
              |------------------------------>|
              |     ACK bob@bob.home.org      |
              |<------------------------------|
              .                               .
    later     .                               .
              .                               .
              | BYE jack@office.home.net      |
              |------------------------------>|
              |                       200 OK  |
              |<------------------------------|
              |                               |

# Server behavior

SIP defines behaviors for proxy and registrar server. For complete information, please read the RFC...

Usually, a user agent sends its requests to an outbound proxy. As users do not know the current location of their correspondent, they use for the sip url a username and a domain. The outbound proxy (where firewall capabilities can be inserted) uses DNS SRV RECORDS to find servers belonging to the requested domain. Once the server is found, the request is forwarded. This server is the inbound proxy of the correspondent. If the user is available, its application must have registered its location before, so the proxy is now able to forward the request to the real user location. On local network, other standards may be used to find user. (finger,...)

# Chapter 3. The oSIP Library

Having a good knowledge of SIP is recommended for this section. If you plan to use SIP, you should read more carefully the rfc3261 from ietf.org.

# The goals

The oSIP project has started in July 2000. The first official and public release (0.5.0) was published in May 2001.

The oSIP library is at first a free software project. In the context of the third generation network, more and more telecom operators will use IP technology, the favorite land of Linux. One aspect of this evolution is that the future of Linux is highly dependent on the multimedia tools that will be available. oSIP, as a SIP implementation, will allow building interoperable registrar, user-agent (software phones), and proxy thus giving more chance to Linux to be part of the next generation telephony products.

But oSIP is not only targeted towards PC applications. oSIP is enough flexible and tiny to be used on small OS with low requirements. From the 0.7.0 release, the thread support is now optional and the design of the application is entirely chosen by the end-developer. oSIP will now perfectly fit cellulars or any embeded systems. oSIP is known to run on the real time OS VxWorks and other ports should be simple.

Around 2002, the API has been totally refined and osip2 was first release. The code and API is now much more readable and heavy work has been previously done to update from rfc3543 to rfc3261.

# The development level

## The parser

oSIP should be provide a fully compliant SIP parser. If you ever see something missing or not correct, please report bugs to `<osip@atosc.org>`, I'll fix them.

To get more information, see next section

## The state machines

The 4 finite state machines have been tested during weeks and have also been tested with around 30 products at the 8th SIPit in Cardiff (SIP Interoperability tests). They appear to be stable.

# The parser

oSIP contains a parser which is able to read and write any SIP message as described in the RFC. Currently oSIP is able to parse only a minimal set of headers such as Via, Call-ID, To, From, Contact, CSeq, Route, Record-Route, mime-version, Content-Type, and Content-Length. All other headers are stored as strings so that you can access it with the API for generic headers.

By now, the SIP parser supports multiple attachments through the MIME format. (this part has not been tested a lot, reports bugs)

oSIP may alter Incoming SIP messages when messages contains:

the order of header
the presence of multiple headers on the same line
the presence of extra SPACEs between tokens
the presence of LWS (internal CRLF)
the presence of bracket in to,from,contact... headers

# The transaction manager

oSIP presents an easy to use interface. Transactions are modeled through 4 finite state machines which is the core of the oSIP library. Each transaction uses a separate FIFO filled by external modules. Events are processed on demand by user. A set of dynamic callback registered by user allow the application to be informed of each transaction's evolution.

Building an application on the top of oSIP will require to build several modules. First, you'll have to build a module to manage the transport protocole (send and rcv methods). This way, oSIP is independent from any transport layer. Then, you'll be required to build a module for transaction management where a few methods of osip must be regularly called so that osip can run the finite state machines events. The third required module is the biggest part of the multimedia application. This modules will have to maintain and update the state of SIP sessions over transactions.

The transaction manager has been heavily tested and is already stable. Also, oSIP does not require much memory and runs fast. Since release 0.7.0, the library can be used either in multi-threaded mode or not!

# Who will benefit from oSIP

oSIP offers a low level interface to build any SIP applications (proxy, Endpoint, Server or gateway). Also, oSIP is not tight to any kind of OSs. If you want to implement a proxy, please read "notes for proxy implementation" in the chapter called "the transaction manager".

# Available ports

The library has been built with portability in mind and should be quickly usable on most posix systems. It has already been built under Solaris, HP unix and the RT OS VxWorks. GNU/Linux (2.2.16 and 2.4.7) has been used for initial developments.

# Chapter 4. The oSIP parser

# files

`./libosip-x.x.x/src/osipparser2`

is the source directory for the SIP parser.

`-losipparser2`

is the library containing the SIP parser

`#include <osipparser2/osip_parser.h>`

is the include file describing the external SIP parser API

# SIP-URL

## Definition and purpose

URL are used to describe entirely a SIP entity: user, registrar, proxy have their own urls. oSIP uses the osip_uri_t type definition in the request-uri and in the following headers: "to", "from", "contact", "route", and "record-route".

type definition of osip_uri_t.

    typedef struct osip_uri {
      char *scheme;
      char *username;
      char *password;
      char *host;
      char *port;
      list_t *url_params;
      list_t *url_headers;
    } osip_uri_t ;

## API for SIP-URL

    #include <osipparser2/osip_uri.h>

# osip_uri_init

## Name

osip_uri_init -- Allocate and initialize the `url` element.

## Description

``int osip_uri_init`(osip_uri_t **url);`

on success, return 0.

# osip_uri_free

## Name

osip_uri_free -- free resources contained in `url`

## Description

``void osip_uri_free`(osip_uri_t ** url);`

# osip_uri_parse

## Name

osip_uri_parse -- Parse `field_value` and store results in `url`.

## Description

``int osip_uri_parse`(osip_uri_t * url, char * field_value);`

on success, return 0.

# osip_uri_to_str

## Name

osip_uri_to_str -- Allocate a string in `field_value` with the information stored in the `url` parameter.

## Description

``int osip_uri_to_str`(osip_uri_t *url char **field_value);`

on success, return 0.

# osip_uri_clone

## Name

osip_uri_clone -- duplicate the `url` element in a new dest element.

## Description

``int osip_uri_clone`(osip_uri_t *url, osip_uri_t **dest);`

on success, return 0.

# osip_uri_uparam_add

## Name

osip_uri_uparam_add -- allocate and add a new url parameter in the `url` element.

## Description

``int osip_uri_uparam_add`(osip_uri_t *url, char *pname char *pvalue);`

on success, return 0.

# osip_uri_uheader_add

## Name

osip_uri_uheader_add -- allocate and add a new url header element in the `url` element.

## Description

``int osip_uri_uheader_add`(osip_uri_t *url char *hname char *hvalue);`

on success, return 0.

# osip_uri_uparam_get_byname

## Name

osip_uri_uparam_get_byname -- Find a url parameter with `pname` in the `url` element.

## Description

``int osip_uri_uparam_get_byname`(osip_uri_t *url char *pname osip_uri_param_t **osip_uri_param);`

on success, return 0.

## API for osip_uri_param_t and osip_uri_header_t

osip_uri_param_t and osip_uri_header_t are data types used inside a SIP-URL. Methods are provided to allocate, free or clone resources.

> Important: The API is the same for url parameters and header parameters. You just have to replace "_param_" with "_header_".

Example 4-1. type definitions of osip_uri_param_t and header_param_t.

      typedef struct osip_uri_param {
        char *pname;
        char *pvalue;
      } osip_uri_param_t;

      typedef osip_uri_param_t osip_uri_header_t;

# osip_uri_param_init

## Name

osip_uri_param_init -- Allocate and initialize the `osip_uri_param` element.

## Description

``int osip_uri_param_init`(osip_uri_param_t **osip_uri_param);`

on success, return 0.

# osip_uri_param_free

## Name

osip_uri_param_free -- free resources contained in `osip_uri_param`

## Description

``void osip_uri_param_free`(osip_uri_param_t **osip_uri_param);`

# osip_uri_param_set

## Name

osip_uri_param_set -- Set `name` and `value` in the `osip_uri_param` element.

## Description

``void osip_uri_param_set`(osip_uri_param_t *osip_uri_param, char *pname, char *pvalue);`

on success, return 0.

# osip_uri_param_freelist

## Name

osip_uri_param_freelist -- free resources contained in the list `osip_uri_params` elements.

## Description

``void osip_uri_param_freelist`(list_t *osip_uri_params);`

# osip_uri_param_add

## Name

osip_uri_param_add -- add `osip_uri_param` in the list `osip_uri_params`.

## Description

``void osip_uri_param_add`(list_t *osip_uri_params, char *pname, char *pvalue);`

on success, return 0.

# osip_uri_param_get_byname

## Name

osip_uri_param_get_byname -- Find the `osip_uri_param` with `name` in the list `osip_uri_params`.

## Description

``void osip_uri_param_get_byname`(list_t *osip_uri_params, char *pname, osip_uri_param_t **osip_uri_param);`

on success, return 0.

# SIP headers

## Definition and purpose

The rfc3261 defines around 40 headers. SIP Messages are mainly composed of a list of headers. This first part documents the API to create, allocate, parse and print the SIP headers elements. The second one shows that headers also have a extended API only applicable for one type of header. The extended API presented below is for the "To" header. Nevertheless, the extended API for the "To" header is also valid for the "From", "Contact", "Route" and "Record-Route" headers.

Example 4-2. type definition of to_t

    typedef struct osip_to_t {
      char *displayname;
      osip_uri_t *url;
      list_t *gen_params;
    } osip_to_t;

## Common API for all implemented header.

The SIP parser can parse entirely a few headers such as: Via, To, From, CSeq, Call-Id, Contact, Route, Record-Route, Content-Type, Content-length, Mime-Version (see API for a complete list of headers API). The other headers are accessible as strings through a special API.

> Important: This API presented below is applicable for all known headers: Simply replace "osip_to_" by one of the following list: "osip_via_", "osip_from_", "osip_contact", "osip_route_", "osip_record_route_", "osip_content_type_", "osip_content_length_", "osip_mime_version_", "osip_cseq_", "osip_call_id_" (see API for a complete list of headers API)

If you are interested in developing new headers, you just have to re-use the API proposed below. Contributions are welcomed. Be aware that only patch that do not break the compatibility will be accepted. DONT CHANGE THE OSIP_MESSAGE_T TYPEDEF.

As an example, the following methods concern the API to manipulate a osip_to_t structure.

    #include <osipparser2/osip_parser.h>

# osip_to_init

## Name

osip_to_init -- Allocate and initialize the structure `to`

## Description

``int osip_to_init`(osip_to_t **to);`

on success, return 0.

# osip_to_free

## Name

osip_to_free -- free resources contained in `to`

## Description

``void osip_to_free`(osip_to_t **to);`

# osip_to_parse

## Name

osip_to_parse -- Parse `field_value` and store results in `to`.

## Description

``int osip_to_parse`(osip_to_t *to, char *field_value);`

on success, return 0.

# osip_to_to_str

## Name

osip_to_to_str -- Allocate a string in `field_value` with the information stored in the `to` parameter.

## Description

``int osip_to_to_str`(osip_to_t *to, char **field_value);`

on success, return 0.

# osip_to_clone

## Name

osip_to_clone -- duplicate the `to` element in a new dest element.

## Description

``int osip_to_clone`(osip_to_t *to, osip_to_t **dest);`

on success, return 0.

## Specific API for "To" header

In addition to the common API shared by all known implemented header, there is a specific API valid only for each header. The following methods concern the "To" header.

# osip_to_set_displayname

## Name

osip_to_set_displayname -- set the display name in the `to` element.

## Description

``void osip_to_set_displayname`(osip_to_t *to, char *value);`

# osip_to_get_displayname

## Name

osip_to_get_displayname -- return the display name from the `to` element.

## Description

``char *osip_to_get_displayname`(osip_to_t *to);`

# osip_to_set_url

## Name

osip_to_set_url -- set the `url` in the `to` element.

## Description

``void osip_to_set_url`(osip_to_t *to, osip_uri_t *url);`

# osip_to_get_url

## Name

osip_to_get_url -- return the `url` from the `to` element.

## Description

``osip_uri_t *osip_to_get_url`(osip_to_t *to);`

# osip_to_param_add

## Name

osip_to_param_add -- add a `gen_param` in the `to` element.

## Description

``int osip_to_param_add`(osip_to_t *to, char *name, char *value);`

on success, return 0.

# osip_to_param_get

## Name

osip_to_param_get -- return the `param` at index `pos` from the `to` element.

## Description

``int osip_to_param_get`(osip_to_t *to, int pos, generic_param_t **gp);`

# osip_to_get_tag

## Name

osip_to_get_tag -- return the value associated with the tag parameter from the `to`.

## Description

``void osip_to_get_tag`(osip_to_t *to, generic_param_t **dest);`

# osip_to_set_tag

## Name

osip_to_set_tag -- set the `tag` parameter int the `to` element.

## Description

``void osip_to_set_tag`(osip_to_t *to, char *tag);`

# osip_to_param_get_byname

## Name

osip_to_param_get_byname -- get the parameter with `pname` from the `to` element.

## Description

``int osip_to_param_get_byname`(osip_to_t *to, char *pname, generic_param_t **dest);`

on success, return 0.

## API for generic param

Generic parameter are components of many headers such as To, From, Contact, Route, Record-Route, and Content-Type.

Example 4-3. The To header has a list of generic_param_t

      typedef struct _generic_param_t {
          char *pname;
          char *pvalue;
      } generic_param_t;

      /* to, from and contact headers are defined as below */
      typedef struct _osip_to_t {
          char *displayname;
          osip_uri_t *url;
          list_t *gen_params;
      }

Example 4-4. A To header with the "tag" parameter

      to: "jack" <sip:atosc.org>;tag=ae56fr-dz-23

# generic_param_init

## Name

generic_param_init -- Allocate and initialize the structure `gen_param`.

## Description

``int generic_param_init`(generic_param_t * gen_param);`

on success, return 0.

# generic_param_free

## Name

generic_param_free -- free resources contained in the structure `gen_param`.

## Description

``void generic_param_free`(generic_param_t *gen_param);`

# generic_param_set

## Name

generic_param_set -- Set `name` and `value` in the `gen_param` element.

## Description

``void generic_param_set`(generic_param_t *gen_param, char *pname, char *pvalue);`

# generic_param_get_name

## Name

generic_param_get_name -- Get `name` from the `gen_param` element.

## Description

``char *generic_param_get_name`(generic_param_t *gen_param);`

on error, return NULL.

# generic_param_setname

## Name

generic_param_setname -- set `name` in the `gen_param` element.

## Description

``void generic_param_setname`(generic_param_t *gen_param, char *pname);`

# generic_param_get_value

## Name

generic_param_get_value -- Get `value` from the `gen_param` element.

## Description

``char *generic_param_get_value`(generic_param_t *gen_param);`

on error, return NULL.

# generic_param_setvalue

## Name

generic_param_setvalue -- set `value` in the `gen_param` element.

## Description

``void generic_param_setvalue`(generic_param_t *gen_param char *pvalue);`

# generic_param_add

## Name

generic_param_add -- Allocate a new generic param with `name` and `value` and add the element in the list `gen_params`.

## Description

``int generic_param_add`(list_t *gen_params char *name char *value);`

on success, return 0.

# generic_param_get_byname

## Name

generic_param_get_byname -- find element containing `name` from the list `gen_params` and return it in `gen_param` .

## Description

``int generic_param_get_byname`(list_t *gen_params char *name generic_param_t **gen_param);`

on success, return 0.

# generic_param_freelist

## Name

generic_param_freelist -- free resources contained in the list `gen_params` elements.

## Description

``void generic_param_freelist`(list_t *gen_params);`

# SIP messages

## definition and purpose

The messages are based at this level on three parts. The first line is either the request-uri for requests or the status code for responses. This first line corresponds to the first attribute of oSIP: startline_t. The second valuable part of a SIP message is a list of headers. The last attribute (list of body) is a possible list of attachments found in the message.

Currently this structure sip_t is not complete. All other header than "From", "To", "Call-Id", "CSeq", "via", "contact", "route", "record-route", mime-version", "content-type" and "content-length" are stored as string in a list of generic headers. This structure will be completed while improving the parser capabilities.

Example 4-5. type definition for sip_t.

     typedef struct osip_message
      {
        char *sip_version;                /**< SIP version (SIP request only) */
        osip_uri_t *req_uri;              /**< Request-Uri (SIP request only) */
        char *sip_method;                 /**< METHOD (SIP request only) */

        int status_code;                  /**< Status Code (SIP answer only) */
        char *reason_phrase;              /**< Reason Phrase (SIP answer only) */

        osip_list_t *accepts;             /**< Accept headers */
        osip_list_t *accept_encodings;    /**< Accept-Encoding headers */
        osip_list_t *accept_languages;    /**< Accept-Language headers */
        osip_list_t *alert_infos;         /**< Alert-Info headers */
        osip_list_t *allows;              /**< Allows headers */
        osip_list_t *authentication_infos;/**< authentication_info headers */
        osip_list_t *authorizations;      /**< Authorizations headers */
        osip_call_id_t *call_id;          /**< Call-ID header */
        osip_list_t *call_infos;          /**< Call-Infos header */
        osip_list_t *contacts;            /**< Contacts headers */
        osip_list_t *content_dispositions;/**< Content-Dispositions headers */
        osip_list_t *content_encodings;   /**< Content-Encodings headers */
        osip_content_length_t *content_length;   /**< Content-Length header */
        osip_content_type_t *content_type;       /**< Content-Type header */
        osip_cseq_t *cseq;                /**< CSeq header */
        osip_list_t *error_infos;         /**< Error-Info headers */
        osip_from_t *from;                /**< From header */
        osip_mime_version_t *mime_version;/**< Mime-Version header */
        osip_list_t *proxy_authenticates; /**< Proxy-Authenticate headers */
        osip_list_t *proxy_authentication_infos; /**< P-Authentication-Info headers */
        osip_list_t *proxy_authorizations;/**< Proxy-authorization headers */
        osip_list_t *record_routes;       /**< Record-Route headers */
        osip_list_t *routes;              /**< Route headers */
        osip_to_t *to;                    /**< To header */
        osip_list_t *vias;                /**< Vias headers */
        osip_list_t *www_authenticates;   /**< WWW-Authenticate headers */

        osip_list_t *headers;             /**< Other headers */

        osip_list_t *bodies;              /**< List of attachements */

        /*
           1: structure and buffer "message" are identical.
           2: buffer "message" is not up to date with the structure info (call osip_message_to_str to update it).
         */
        int message_property;             /**@internal */
        char *message;                    /**@internal */
        size_t message_length;            /**@internal */

        void *application_data;           /**can be used by upper layer*/
      } osip_message_t;

## API for SIP message

    #include <osipparser2/osip_parser.h>

# osip_message_init

## Name

osip_message_init -- Allocate and initialize the structure `msg`

## Description

``int osip_message_init`(osip_message_t **msg);`

on success, return 0.

# osip_message_free

## Name

osip_message_free -- free resources contained in `msg`

## Description

``void osip_message_free`(osip_message_t **msg);`

# osip_message_parse

## Name

osip_message_parse -- Parse `field_value` and store results in `msg`.

## Description

``int osip_message_parse`(osip_message_t *msg, char *field_value);`

on success, return 0.

# osip_message_to_str

## Name

osip_message_to_str -- Allocate a string in `field_value` with the information stored in the `msg` parameter.

## Description

``int osip_message_to_str`(osip_message_t *msg, char **field_value);`

on success, return 0.

# osip_message_clone

## Name

osip_message_clone -- duplicate the `msg` element in a new dest element.

## Description

``int osip_message_clone`(osip_message_t *msg, osip_message_t **dest);`

on success, return 0.

# osip_message_set_header

## Name

osip_message_set_header -- Parse `hvalue`, allocate and add a new header in `sip` element.

## Description

``int osip_message_set_header`(osip_message_t *sip, char *hname, char *hvalue);`

on success, return 0.

# osip_message_get_header

## Name

osip_message_get_header -- set in `dest` the header at index `pos` from the `sip` element.

## Description

``int osip_message_get_header`(osip_message_t *sip, int pos, header_t **header);`

on success, return 0.

# osip_message_header_get_byname

## Name

osip_message_header_get_byname -- find the first header (after index `pos`) with `hname` from the list of header in the `sip` element.

## Description

``int osip_message_header_get_byname`(char *hname, osip_message_t *sip, int pos, header_t **dest);`

on success, return 0.

# osip_message_set_call_id

## Name

osip_message_set_call_id -- Parse `hvalue`, allocate and set the call_id attribute of the `sip` element.

## Description

``int osip_message_set_call_id`(osip_message_t *sip, char *hvalue);`

on success, return 0.

# osip_message_get_call_id

## Name

osip_message_get_call_id -- return the call_id attribute from the `sip` element.

## Description

``osip_call_id_t *osip_message_get_call_id`(osip_message_t *sip);`

on success, return 0.

# osip_message_set_cseq

## Name

osip_message_set_cseq -- Parse `hvalue`, allocate and set the cseq attribute of the `sip` element.

## Description

``int osip_message_set_cseq`(osip_message_t *sip, char *hvalue);`

on success, return 0.

# osip_message_get_cseq

## Name

osip_message_get_cseq -- return the cseq attribute from the `sip` element.

## Description

``osip_cseq_t *osip_message_get_cseq`(osip_message_t *sip);`

on success, return 0.

# osip_message_set_contact

## Name

osip_message_set_contact -- Parse `hvalue`, allocate and add a new contact attribute in the `sip` element.

## Description

``int osip_message_set_contact`(osip_message_t *sip, char *hvalue);`

on success, return 0.

# osip_message_get_contact

## Name

osip_message_get_contact -- set in `dest` the contact at index `pos` from the `sip` element.

## Description

``int osip_message_get_contact`(osip_message_t *sip, int pos, contact_t **contact);`

on success, return 0.

# osip_message_set_from

## Name

osip_message_set_from -- Parse `hvalue`, allocate and set the from attribute of the `sip` element.

## Description

``int osip_message_set_from`(osip_message_t *sip, char *hvalue);`

on success, return 0.

# osip_message_get_from

## Name

osip_message_get_from -- return the from attribute from the `sip` element.

## Description

``osip_from_t *osip_message_get_from`(osip_message_t *sip);`

on success, return 0.

# osip_message_set_to

## Name

osip_message_set_to -- Parse `hvalue`, allocate and set the to attribute of the `sip` element.

## Description

``int osip_message_set_to`(osip_message_t *sip, char *hvalue);`

on success, return 0.

# osip_message_get_to

## Name

osip_message_get_to -- return the `to` attribute from the `sip` element.

## Description

``osip_to_t *osip_message_get_to`(osip_message_t *sip);`

on success, return 0.

# osip_message_set_via

## Name

osip_message_set_via -- Parse `hvalue`, allocate and add a new via in `sip` element.

## Description

``int osip_message_set_via`(osip_message_t *sip, char *hvalue);`

on success, return 0.

# osip_message_get_via

## Name

osip_message_get_via -- set in `dest` the via at index `pos` from the `sip` element.

## Description

``int osip_message_get_via`(osip_message_t *sip, int pos, osip_via_t **via);`

on success, return 0.

# osip_message_set_record_route

## Name

osip_message_set_record_route -- Parse `hvalue`, allocate and add a new record_route in the `sip` element.

## Description

``int osip_message_set_record_route`(osip_message_t *sip, char *hvalue);`

on success, return 0.

# osip_message_get_record_route

## Name

osip_message_get_record_route -- set in `dest` the record_route at index `pos` from the `sip` element.

## Description

``int osip_message_get_record_route`(osip_message_t *sip, int pos, record_route_t **record_route);`

on success, return 0.

# osip_message_set_route

## Name

osip_message_set_route -- Parse `hvalue`, allocate and add a new route in the `sip` element.

## Description

``int osip_message_set_route`(osip_message_t *sip, char *hvalue);`

on success, return 0.

# osip_message_get_route

## Name

osip_message_get_route -- set in `dest` the route at index `pos` from the `sip` element.

## Description

``int osip_message_get_route`(osip_message_t *sip, int pos, route_t **route);`

on success, return 0.

# osip_message_set_content_length

## Name

osip_message_set_content_length -- Parse `hvalue`, allocate and set the content_length attribute of the `sip` element.

## Description

``int osip_message_set_content_length`(osip_message_t *sip, char *hvalue);`

on success, return 0.

# osip_message_get_content_length

## Name

osip_message_get_content_length -- return the content_length attribute from the `sip` element.

## Description

``content_length_t * osip_message_get_content_length`(osip_message_t *sip);`

# osip_message_set_content_type

## Name

osip_message_set_content_type -- Parse `hvalue`, allocate and set the content_type attribute of the `sip` element.

## Description

``int osip_message_set_content_type`(osip_message_t *sip, char *hvalue);`

on success, return 0.

# osip_message_get_content_type

## Name

osip_message_get_content_type -- return the content_type attribute from the `sip` element.

## Description

``content_type_t * osip_message_get_content_type`(osip_message_t *sip);`

# osip_message_set_mime_version

## Name

osip_message_set_mime_version -- Parse `hvalue`, allocate and set the mime_version attribute of the `sip` element.

## Description

``int osip_message_set_mime_version`(osip_message_t *sip, char *hvalue);`

on success, return 0.

# osip_message_get_mime_version

## Name

osip_message_get_mime_version -- return the mime_version attribute from the `sip` element.

## Description

``mime_version_t * osip_message_get_mime_version`(osip_message_t *sip);`

## MACROs

Other helpful MACROs are defined. They are used to test characteristics of messages such as the type of a message, the method of a request and the status code of a response.

Example 4-6. List of MACROs

    /* a few MACROS to ease readability of code */
     MSG_IS_RESPONSE(resp)
     MSG_IS_REQUEST(req)

     MSG_IS_INVITE(msg)
     MSG_IS_ACK(msg)
     MSG_IS_BYE(msg)
     MSG_IS_REGISTER(msg)
     MSG_IS_CANCEL(msg)
     MSG_IS_OPTIONS(msg)
     MSG_IS_INFO(msg)
     MSG_IS_PRACK(msg)

     MSG_IS_STATUS_1XX(msg)
     MSG_IS_STATUS_2XX(msg)
     MSG_IS_STATUS_3XX(msg)
     MSG_IS_STATUS_4XX(msg)
     MSG_IS_STATUS_5XX(msg)
     MSG_IS_STATUS_6XX(msg)

     MSG_TEST_CODE(resp, code)
     MSG_IS_RESPONSEFOR(resp,requestname)

# The parser HOW-TO.

Building a message is not a complex task and does not require to be a C expert. Nevertheless, it requires you to be a SIP expert! The document describing SIP (rfc3261.txt) provides all you need to build correct requests and response. You will have to know which header MUST be included ("To", "From", "Call-ID", "Cseq" are the most common...), which header MUST NOT be included, and which header MAY appear in the message.

## Initialise the parser

The oSIP parser need to be initialised at run time. This is done by first calling the following method before using the oSIP parser. (This method MUST only be called once.)

int parser_init();

## Allocate a structure

oSIP has a standard approach to request allocation of structures. For each SIP related one, (like osip_message_t, or osip_from_t) a method "osip_xxxx_init()" exists and MUST be used to request allocation. It must be used along with "osip_xxxx_free()".

Example 4-7. allocation of osip_message_t and osip_uri_t.

     osip_message_t *msg;
     osip_message_init(&msg);
     osip_message_free(msg);

     osip_uri_t *url;
     osip_uri_init(&url);
     osip_uri_free(url);

## create a URL and a Request-URI.

The following code is used to build a request line for an INVITE message. This line will be: "INVITE sip:jack@atosc.org SIP/2.0".

     /* make a request line. */
     osip_uri_t  *uri;
     osip_uri_init(&uri);
     osip_uri_set_scheme(url,osip_strdup("sip"));
     osip_uri_set_username(url,osip_strdup("jack"));
     osip_uri_set_host(url,osip_strdup("atosc.org"));

     osip_message_set_method(msg,osip_strdup("INVITE"));
     osip_message_set_uri(msg,uri);
     osip_message_set_version(msg,osip_strdup("2.0"));

## Add headers in a message

This example shows the code required to allocate headers and add each of them in the sip_t structure. You should take a look at the RFC when building messages.

For INVITE requests,the following headers are mandatory:

Via
CSeq
Call-Id
To
From
Contact
Content-length (mandatory for TCP, recommended for ALL)
Content-Type (if a body is attached)

Example 4-8. Add header

     {
      osip_uri_t    *url;
      osip_to_t     *to;
      osip_uri_init(&url);
      osip_uri_set_username(url,osip_strdup("jack"));
      osip_uri_set_host(url,osip_strdup("atosc.org"));

      osip_to_init(&to);
      osip_to_set_url(to,url);
      osip_to_set_displayname(to,osip_strdup("Aymeric MOIZARD"));

      osip_message_set_to(msg, to);
     }

      /* the same API is available for the osip_from_t structure */
     {
      osip_from_t   *from;
      /* allocate a osip_uri_t */
      osip_uri_init(&url);
      osip_uri_set_username(url,osip_strdup("cha"));
      osip_uri_set_host(url,osip_strdup("anywhere.org"));

      /* allocate a osip_from_t */
      osip_from_init(&from);
      osip_from_set_url(from,url);
      osip_from_set_displayname(from,osip_strdup("My love"));
      osip_from_set_tag(from,osip_strdup("a48a"));

      osip_message_set_from(msg, from);
     }

     {
      osip_via_t    *via;
      osip_via_init(&via);

      osip_via_set_version(via,osip_strdup("2.0"));
      osip_via_set_protocol(via,osip_strdup("UDP"));
      osip_via_set_host(via,osip_strdup("137.137.137.137"));
      osip_via_set_branch(via,osip_strdup("branch"),osip_strdup("z9hG4bK776asdhds.1"));

      osip_message_set_via(msg, via);
     }

     {
      osip_cseq_t   *cseq;
      cseq_init(&cseq);
      ...

      osip_message_set_cseq(msg, cseq);
     }

     {
      osip_call_id_t *callid;
      osip_call_id_init(&callid);

      osip_callid_set_number(callid,osip_strdup("f81d4"));
      osip_callid_set_host(callid,osip_strdup("foo.atosc.org"));

      osip_message_set_callid(msg, callid);
     }

     /* this API can also be used, but it is much more time consuming! */
     osip_message_set_contact(msg,"sip:jacK@office.atosc.org");

     /* Let's add some headers */
     osip_message_set_header(msg,osip_strdup("SuBjecT"),osip_strdup("Need support for oSIP!"));

     /* add a body */
     osip_message_set_body(msg,"v=0\r\no=user1 53655765 2353687637 IN IP4 128.3.4.5\r\ns=Mbone Audio\r\ni=Discussion of Mbone Engineering Issues\r\ne=mbone@somewhere.com\r\nc=IN IP4 128.3.4.5\r\nt=0 0\r\nm=audio 3456 RTP/AVP 0\r\na=rtpmap:0 PCMU/8000\r\n");

## make a string from a structure

For osip_message_t like for the structure used for the headers (osip_to_t, osip_from_t, osip_call_id_t...), a method exist to retrieve printed version of the element.

Example 4-9. Method xxxx_to_str

      char *astring = NULL;
      int length;
      i = osip_message_to_str(msg, &astring, &length);
      if (i!=0)
         return -1;
      osip_free(astring);

## free resource in a structure

Example 4-10. Method xxxx_free

This is how you must free all memory.

     osip_messagefree(msg);

The parser may sometimes be too much tolerant. It will accept silently some of your mistakes. As an example, the parser should accept a display name (for a "To" header) with a comma inside. The developer MUST enclose the string between quotes. To keep the application interoperable, please always keep an eye on the rfc and control every characters you put in SIP message.

# How to improve the parser performance

To improve stack performance, you can configure the parser at link time by choosing which headers must ALWAYS be completely decoded. (It could also be possible at run time with minimal work!). You may find this useful in terms of performance when implementing proxies.

# Chapter 5. The oSIP state machines

# files

`./libosip-x.x.x/src/osip2` is the source directory for the SIP finite state machines.

`-losip2` is the library containing the SIP finite state machines

`#include <osip2/osip.h>` is the include file describing the external SIP parser API

# Transaction and events

## Definition and purpose of transaction

Transactions are used to store the context of one "SIP transactions" as defined in the rfc3261. oSIP uses the osip_transaction_t internally so you probably don't need to understand each attribute.

Example 5-1. oSIP model for transactions

Managing a transaction consists in building modules that can send events to control the transaction

           User module
            +------------+
            |            |
            +------------+
                |        msg to send
                +--------------------+        Transaction
           Timer module              |         contexts
            +------------+           |
            |            |           |        +----------+
            +------------+           +------->| TRANSAC. |
                |        timeout evt |        |    1     |
                +--------------------+        +----------+
           Transport module          |
            +------------+           |        +----------+
            |            |           +------->| TRANSAC. |
            +------------+           |        |    2     |
                |      incoming msg  |        +----------+
                +--------------------+

The attribute `your_instance` is not used by oSIP. You can use it to store a pointer on your own context.

You can use the `transactionid` as a unique id for the transaction.

`transactionff` is a FIFO used to receive all events (osip_event_t) which concern this transaction.

Example 5-2. type definition of osip_transaction_t.

    typedef struct osip__transaction {
        void *your_instance;        /**< User Defined Pointer. */
        int transactionid;          /**< Internal Transaction Identifier. */
        osip_fifo_t *transactionff; /**< events must be added in this fifo */

        osip_via_t *topvia;         /**< CALL-LEG definition (Top Via) */
        osip_from_t *from;          /**< CALL-LEG definition (From)    */
        osip_to_t *to;              /**< CALL-LEG definition (To)      */
        osip_call_id_t *callid;     /**< CALL-LEG definition (Call-ID) */
        osip_cseq_t *cseq;          /**< CALL-LEG definition (CSeq)    */

        osip_message_t *orig_request;  /**< Initial request            */
        osip_message_t *last_response; /**< Last response              */
        osip_message_t *ack;           /**< ack request sent           */

        state_t state;              /**< Current state of the transaction */

        time_t birth_time;          /**< birth date of transaction        */
        time_t completed_time;      /**< end   date of transaction        */

        int in_socket;              /**< Optional socket for incoming message */
        int out_socket;             /**< Optional place for outgoing message */

        void *config;               /**@internal transaction is managed by osip_t  */

        osip_fsm_type_t ctx_type;   /**< Type of the transaction */
        osip_ict_t *ict_context;    /**@internal */
        osip_ist_t *ist_context;    /**@internal */
        osip_nict_t *nict_context;  /**@internal */
        osip_nist_t *nist_context;  /**@internal */

    } osip_transaction_t;

## Definition and purpose of osip_event

osip_events objects are used to control the context of one "SIP transaction" element. There is 3 types of SIP events for the finite state machines:

incoming SIP messages. (requests and responses)
outgoing SIP messages. (requests and responses)
timers events. (retransmissions and context removal)

The attribute `type` always contains the type of the event.

`transactionid` is now for internal use.

When the event is a SIP message, `sip` is the parsed message.

Example 5-3. type definition of osip_event_t.

    typedef struct osip_event {
      type_t type;
      int transactionid;
      osip_message_t *sip;
    } osip_event_t;

## API

    #include <osip2/osip.h>

# osip_init

## Name

osip_init -- Allocate and initialize the `osip` element.

## Description

``int osip_init`(osip_t **osip);`

on success, return 0.

# osip_free

## Name

osip_free -- free resources contained in `osip`

## Description

``void osip_free`(osip_t *osip);`

# osip_execute

## Name

osip_execute -- consumes all SIP events from the list of transactions contained in `osip.`

## Description

``int osip_execute`(osip_t *osip);`

# osip_find_transaction_and_add_event

## Name

osip_find_transaction_and_add_event -- distribute a SIP event (message) in the right FIFO of `osip` This method has to be used for incoming message.

## Description

``osip_transaction_t *osip_find_transaction_and_add_event`(osip_t *osip, osip_event_t *se);`

# osip_parse

## Name

osip_parse -- parse `buf` and create an SIP incoming message event.

## Description

``osip_event_t *osip_parse`(char *buf, size_t length);`

# osip_new_event

## Name

osip_new_event -- create a new SIP event with attributes type and transactionid. (This method is used by the timer module)

## Description

``osip_event_t *osip_new_event`(type_t type int transactionid);`

# osip_new_incoming_event

## Name

osip_new_incoming_event -- create a new SIP event for an incoming SIP message.

## Description

``osip_event_t *osip_new_incoming_event`(osip_message_t *sip);`

# osip_new_outgoing_event

## Name

osip_new_outgoing_event -- create a new SIP event for an outgoing SIP message.

## Description

``osip_event_t *osip_new_outgoing_event`(osip_message_t *sip);`

# osip_transaction_init

## Name

osip_transaction_init -- Allocate and initialize the `transaction` element.

## Description

``int osip_transaction_init`(osip_transaction_t **transaction);`

# osip_transaction_free

## Name

osip_transaction_free -- free resources contained in `transaction`

## Description

``void osip_transaction_free`(osip_transaction_t *transaction);`

# osip_transaction_execute

## Name

osip_transaction_execute -- consume osip_event in the context of `transaction`.

## Description

``int osip_transaction_execute`(osip_transaction_t *transaction);`

## The callbacks.

oSIP uses a set of callbacks to announce the evolution of SIP transactions. For example, when receiving an INVITE request, the method registered by "osip_setcb_rcvinvite(...)" will be called by the stack and used by the developer to create a provisional response and start actions to build a final one.

The following methods allow you to register, on initialization of the osip stack, the methods that will be used to handle transactions. Some of those methods are mandatory (announcements of requests, and final responses) and some are optional (announcements of provisional responses and retransmissions).

      typedef void (*osip_message_cb_t) (int type, osip_transaction_t *,
                                         osip_message_t *);
        OSIP_ICT_INVITE_SENT = 0,               /**< INVITE MESSAGE SENT */
        OSIP_ICT_INVITE_SENT_AGAIN,             /**< INVITE MESSAGE RETRANSMITTED */
        OSIP_ICT_ACK_SENT,                      /**< ACK MESSAGE SENT */
        OSIP_ICT_ACK_SENT_AGAIN,                /**< ACK MESSAGE RETRANSMITTED */
        OSIP_ICT_STATUS_1XX_RECEIVED,           /**< 1XX FOR INVITE RECEIVED */
        OSIP_ICT_STATUS_2XX_RECEIVED,           /**< 2XX FOR INVITE RECEIVED */
        OSIP_ICT_STATUS_2XX_RECEIVED_AGAIN,     /**< 2XX FOR INVITE RECEIVED AGAIN */
        OSIP_ICT_STATUS_3XX_RECEIVED,           /**< 3XX FOR INVITE RECEIVED */
        OSIP_ICT_STATUS_4XX_RECEIVED,           /**< 4XX FOR INVITE RECEIVED */
        OSIP_ICT_STATUS_5XX_RECEIVED,           /**< 5XX FOR INVITE RECEIVED */
        OSIP_ICT_STATUS_6XX_RECEIVED,           /**< 6XX FOR INVITE RECEIVED */
        OSIP_ICT_STATUS_3456XX_RECEIVED_AGAIN,  /**< RESPONSE RECEIVED AGAIN */

        OSIP_IST_INVITE_RECEIVED,               /**< INVITE MESSAGE RECEIVED */
        OSIP_IST_INVITE_RECEIVED_AGAIN,         /**< INVITE MESSAGE RECEIVED AGAN */
        OSIP_IST_ACK_RECEIVED,                  /**< ACK MESSAGE RECEIVED */
        OSIP_IST_ACK_RECEIVED_AGAIN,            /**< ACK MESSAGE RECEIVED AGAIN */
        OSIP_IST_STATUS_1XX_SENT,               /**< 1XX FOR INVITE SENT */
        OSIP_IST_STATUS_2XX_SENT,               /**< 2XX FOR INVITE SENT */
        OSIP_IST_STATUS_2XX_SENT_AGAIN,         /**< 2XX FOR INVITE RETRANSMITTED */
        OSIP_IST_STATUS_3XX_SENT,               /**< 3XX FOR INVITE SENT */
        OSIP_IST_STATUS_4XX_SENT,               /**< 4XX FOR INVITE SENT */
        OSIP_IST_STATUS_5XX_SENT,               /**< 5XX FOR INVITE SENT */
        OSIP_IST_STATUS_6XX_SENT,               /**< 6XX FOR INVITE SENT */
        OSIP_IST_STATUS_3456XX_SENT_AGAIN,      /**< RESPONSE RETRANSMITTED */

        OSIP_NICT_REGISTER_SENT,                /**< REGISTER MESSAGE SENT */
        OSIP_NICT_BYE_SENT,                     /**< BYE MESSAGE SENT */
        OSIP_NICT_OPTIONS_SENT,                 /**< OPTIONS MESSAGE SENT */
        OSIP_NICT_INFO_SENT,                    /**< INFO MESSAGE SENT */
        OSIP_NICT_CANCEL_SENT,                  /**< CANCEL MESSAGE SENT */
        OSIP_NICT_NOTIFY_SENT,                  /**< NOTIFY MESSAGE SENT */
        OSIP_NICT_SUBSCRIBE_SENT,               /**< SUBSCRIBE MESSAGE SENT */
        OSIP_NICT_UNKNOWN_REQUEST_SENT,         /**< UNKNOWN REQUEST MESSAGE SENT */
        OSIP_NICT_REQUEST_SENT_AGAIN,           /**< REQUEST MESSAGE RETRANMITTED */
        OSIP_NICT_STATUS_1XX_RECEIVED,          /**< 1XX FOR MESSAGE RECEIVED */
        OSIP_NICT_STATUS_2XX_RECEIVED,          /**< 2XX FOR MESSAGE RECEIVED */
        OSIP_NICT_STATUS_2XX_RECEIVED_AGAIN,    /**< 2XX FOR MESSAGE RECEIVED AGAIN */
        OSIP_NICT_STATUS_3XX_RECEIVED,          /**< 3XX FOR MESSAGE RECEIVED */
        OSIP_NICT_STATUS_4XX_RECEIVED,          /**< 4XX FOR MESSAGE RECEIVED */
        OSIP_NICT_STATUS_5XX_RECEIVED,          /**< 5XX FOR MESSAGE RECEIVED */
        OSIP_NICT_STATUS_6XX_RECEIVED,          /**< 6XX FOR MESSAGE RECEIVED */
        OSIP_NICT_STATUS_3456XX_RECEIVED_AGAIN, /**< RESPONSE RECEIVED AGAIN */

        OSIP_NIST_REGISTER_RECEIVED,            /**< REGISTER RECEIVED */
        OSIP_NIST_BYE_RECEIVED,                 /**< BYE RECEIVED */
        OSIP_NIST_OPTIONS_RECEIVED,             /**< OPTIONS RECEIVED */
        OSIP_NIST_INFO_RECEIVED,                /**< INFO RECEIVED */
        OSIP_NIST_CANCEL_RECEIVED,              /**< CANCEL RECEIVED */
        OSIP_NIST_NOTIFY_RECEIVED,              /**< NOTIFY RECEIVED */
        OSIP_NIST_SUBSCRIBE_RECEIVED,           /**< SUBSCRIBE RECEIVED */

        OSIP_NIST_UNKNOWN_REQUEST_RECEIVED,     /**< UNKNWON REQUEST RECEIVED */
        OSIP_NIST_REQUEST_RECEIVED_AGAIN,       /**< UNKNWON REQUEST RECEIVED AGAIN */
        OSIP_NIST_STATUS_1XX_SENT,              /**< 1XX FOR MESSAGE SENT */
        OSIP_NIST_STATUS_2XX_SENT,              /**< 2XX FOR MESSAGE SENT */
        OSIP_NIST_STATUS_2XX_SENT_AGAIN,        /**< 2XX FOR MESSAGE RETRANSMITTED */
        OSIP_NIST_STATUS_3XX_SENT,              /**< 3XX FOR MESSAGE SENT */
        OSIP_NIST_STATUS_4XX_SENT,              /**< 4XX FOR MESSAGE SENT */
        OSIP_NIST_STATUS_5XX_SENT,              /**< 5XX FOR MESSAGE SENT */
        OSIP_NIST_STATUS_6XX_SENT,              /**< 6XX FOR MESSAGE SENT */
        OSIP_NIST_STATUS_3456XX_SENT_AGAIN,     /**< RESPONSE RETRANSMITTED */

      int osip_set_message_callback (osip_t *osip, int type, osip_message_cb_t cb);

      typedef void (*osip_kill_transaction_cb_t) (int type, osip_transaction_t *);
        OSIP_ICT_KILL_TRANSACTION,      /**< end of Client INVITE transaction */
        OSIP_IST_KILL_TRANSACTION,      /**< end of Server INVITE transaction */
        OSIP_NICT_KILL_TRANSACTION,     /**< end of Client Non-INVITE transaction */
        OSIP_NIST_KILL_TRANSACTION,     /**< end of Server Non-INVITE transaction */
      int osip_set_kill_transaction_callback (osip_t *osip, int type,
                                              osip_kill_transaction_cb_t cb);

      typedef void (*osip_transport_error_cb_t) (int type, osip_transaction_t *,
                                                 int error);
        OSIP_ICT_TRANSPORT_ERROR,             /**< transport error for ICT */
        OSIP_IST_TRANSPORT_ERROR,             /**< transport error for IST */
        OSIP_NICT_TRANSPORT_ERROR,            /**< transport error for NICT */
        OSIP_NIST_TRANSPORT_ERROR,            /**< transport error for NIST */
      int osip_set_transport_error_callback (osip_t *osip, int type,
                                             osip_transport_error_cb_t cb);

## Useful MACROs.

You can also use the following list of MACROs. It is recommended to use them if you want your application to keep full compatibility over oSIP releases.

    /* FOR INCOMING TRANSACTION */
    #define EVT_IS_RCV_INVITE(event)
    #define EVT_IS_RCV_ACK(event)
    #define EVT_IS_RCV_REQUEST(event)
    #define EVT_IS_RCV_STATUS_1XX(event)
    #define EVT_IS_RCV_STATUS_23456XX(event)

    /* FOR OUTGOING TRANSACTION */
    #define EVT_IS_SND_INVITE(event)
    #define EVT_IS_SND_ACK(event)
    #define EVT_IS_SND_REQUEST(event)
    #define EVT_IS_SND_STATUS_1XX(event)
    #define EVT_IS_SND_STATUS_23456XX(event)

    >

# The finite state machines HOW-TO

oSIP contains 4 finite state machines. SIP defines 2 kinds of transactions. INVITE and other than INVITE transactions differs slightly. INVITE transactions must be followed by an ACK which is not always part of the state machine for INVITE (only the ACK for final answer are above 299 are handled by the invite transactions: watch out the rfc3261). Also, different rules apply for retransmission mechanism.

A finite state machine is an ideal way to implement the transaction layer. Threads are waiting for events. Events come from the user layer, transport layer or the timer management facility. The stack always provides information about the state of the transaction to the application layer. This is done through the set of dynamic callbacks.

Example 5-4. SIP events are distributed to fifo.

                                                        Transaction
              User Layer                                  contexts
            +------------+                             +-----------+
            |            |    events          +--------|           |
            |            |-----+------------->| FIFO 1 |     1     |
            +------------+     |              +--------|           |
                               |                       +-----------+
                               |
                               |                       +-----------+
                               |              +--------|           |
                               +------------->| FIFO N |     N     |
                                              +--------|           |
                                                       +-----------+

## Initialise the osip stack

The oSIP stack needs to be initialised at run time. This is done by first calling the following method before using the oSIP stack. (This method MUST only be called once). Calling this method also initialise the parser.

int osip_global_init();

## Allocate and initialize an osip_t element

The osip_t structure is a container for a list of transactions. This element represents an instance of a SIP agent. osip_t can be used for UAS/UAC, registrar and redirect server.

The following code is used to build a complete osip_t element. First, you have to register a set of mandatory and optional callbacks. You can also configure the stack to use a proxy for all outgoing requests.

      osip_t  *osip;

      if (-1==osip_init(&osip))
        return -1; /* mutex is not initialized properly */

      osip_set_kill_transaction_callback(osip ,OSIP_ICT_KILL_TRANSACTION,
                                     &cb_ict_kill_transaction);
      osip_set_kill_transaction_callback(osip ,OSIP_NIST_KILL_TRANSACTION,
                                     &cb_ist_kill_transaction);
      osip_set_kill_transaction_callback(osip ,OSIP_NICT_KILL_TRANSACTION,
                                     &cb_nict_kill_transaction);
      osip_set_kill_transaction_callback(osip ,OSIP_NIST_KILL_TRANSACTION,
                                     &cb_nist_kill_transaction);

      osip_set_message_callback(osip ,OSIP_ICT_STATUS_2XX_RECEIVED_AGAIN,
                            &cb_rcvresp_retransmission);
      osip_set_message_callback(osip ,OSIP_ICT_STATUS_3456XX_RECEIVED_AGAIN,
                            &cb_rcvresp_retransmission);
      osip_set_message_callback(osip ,OSIP_ICT_INVITE_SENT_AGAIN,
                            &cb_sndreq_retransmission);
      osip_set_message_callback(osip ,OSIP_IST_STATUS_2XX_SENT_AGAIN,
                            &cb_sndresp_retransmission);
      osip_set_message_callback(osip ,OSIP_IST_STATUS_3456XX_SENT_AGAIN,
                            &cb_sndresp_retransmission);
      osip_set_message_callback(osip ,OSIP_IST_INVITE_RECEIVED_AGAIN,
                            &cb_rcvreq_retransmission);
      osip_set_message_callback(osip ,OSIP_NICT_STATUS_2XX_RECEIVED_AGAIN,
                            &cb_rcvresp_retransmission);
      osip_set_message_callback(osip ,OSIP_NICT_STATUS_3456XX_RECEIVED_AGAIN,
                            &cb_rcvresp_retransmission);
      osip_set_message_callback(osip ,OSIP_NICT_REQUEST_SENT_AGAIN,
                            &cb_sndreq_retransmission);
      osip_set_message_callback(osip ,OSIP_NIST_STATUS_2XX_SENT_AGAIN,
                            &cb_sndresp_retransmission);
      osip_set_message_callback(osip ,OSIP_NIST_STATUS_3456XX_SENT_AGAIN,
                            &cb_sndresp_retransmission);
      osip_set_message_callback(osip ,OSIP_NIST_REQUEST_RECEIVED_AGAIN,
                            &cb_rcvreq_retransmission);

      osip_set_message_callback(osip ,OSIP_ICT_INVITE_SENT,     &cb_sndinvite);
      osip_set_message_callback(osip ,OSIP_ICT_ACK_SENT,        &cb_sndack);
      osip_set_message_callback(osip ,OSIP_NICT_REGISTER_SENT,  &cb_sndregister);
      osip_set_message_callback(osip ,OSIP_NICT_BYE_SENT,       &cb_sndbye);
      osip_set_message_callback(osip ,OSIP_NICT_CANCEL_SENT,    &cb_sndcancel);
      osip_set_message_callback(osip ,OSIP_NICT_INFO_SENT,      &cb_sndinfo);
      osip_set_message_callback(osip ,OSIP_NICT_OPTIONS_SENT,   &cb_sndoptions);
      osip_set_message_callback(osip ,OSIP_NICT_SUBSCRIBE_SENT, &cb_sndsubscribe);
      osip_set_message_callback(osip ,OSIP_NICT_NOTIFY_SENT,    &cb_sndnotify);
      /*  osip_set_cb_nict_sndprack   (osip,&cb_sndprack); */
      osip_set_message_callback(osip ,OSIP_NICT_UNKNOWN_REQUEST_SENT, &cb_sndunkrequest);

      osip_set_message_callback(osip ,OSIP_ICT_STATUS_1XX_RECEIVED, &cb_rcv1xx);
      osip_set_message_callback(osip ,OSIP_ICT_STATUS_2XX_RECEIVED, &cb_rcv2xx);
      osip_set_message_callback(osip ,OSIP_ICT_STATUS_3XX_RECEIVED, &cb_rcv3xx);
      osip_set_message_callback(osip ,OSIP_ICT_STATUS_4XX_RECEIVED, &cb_rcv4xx);
      osip_set_message_callback(osip ,OSIP_ICT_STATUS_5XX_RECEIVED, &cb_rcv5xx);
      osip_set_message_callback(osip ,OSIP_ICT_STATUS_6XX_RECEIVED, &cb_rcv6xx);

      osip_set_message_callback(osip ,OSIP_IST_STATUS_1XX_SENT, &cb_snd1xx);
      osip_set_message_callback(osip ,OSIP_IST_STATUS_2XX_SENT, &cb_snd2xx);
      osip_set_message_callback(osip ,OSIP_IST_STATUS_3XX_SENT, &cb_snd3xx);
      osip_set_message_callback(osip ,OSIP_IST_STATUS_4XX_SENT, &cb_snd4xx);
      osip_set_message_callback(osip ,OSIP_IST_STATUS_5XX_SENT, &cb_snd5xx);
      osip_set_message_callback(osip ,OSIP_IST_STATUS_6XX_SENT, &cb_snd6xx);

      osip_set_message_callback(osip ,OSIP_NICT_STATUS_1XX_RECEIVED, &cb_rcv1xx);
      osip_set_message_callback(osip ,OSIP_NICT_STATUS_2XX_RECEIVED, &cb_rcv2xx);
      osip_set_message_callback(osip ,OSIP_NICT_STATUS_3XX_RECEIVED, &cb_rcv3xx);
      osip_set_message_callback(osip ,OSIP_NICT_STATUS_4XX_RECEIVED, &cb_rcv4xx);
      osip_set_message_callback(osip ,OSIP_NICT_STATUS_5XX_RECEIVED, &cb_rcv5xx);
      osip_set_message_callback(osip ,OSIP_NICT_STATUS_6XX_RECEIVED, &cb_rcv6xx);

      osip_set_message_callback(osip ,OSIP_NIST_STATUS_1XX_SENT, &cb_snd1xx);
      osip_set_message_callback(osip ,OSIP_NIST_STATUS_2XX_SENT, &cb_snd2xx);
      osip_set_message_callback(osip ,OSIP_NIST_STATUS_3XX_SENT, &cb_snd3xx);
      osip_set_message_callback(osip ,OSIP_NIST_STATUS_4XX_SENT, &cb_snd4xx);
      osip_set_message_callback(osip ,OSIP_NIST_STATUS_5XX_SENT, &cb_snd5xx);
      osip_set_message_callback(osip ,OSIP_NIST_STATUS_6XX_SENT, &cb_snd6xx);

      osip_set_message_callback(osip ,OSIP_IST_INVITE_RECEIVED,     &cb_rcvinvite);
      osip_set_message_callback(osip ,OSIP_IST_ACK_RECEIVED,        &cb_rcvack);
      osip_set_message_callback(osip ,OSIP_IST_ACK_RECEIVED_AGAIN,  &cb_rcvack2);
      osip_set_message_callback(osip ,OSIP_NIST_REGISTER_RECEIVED,  &cb_rcvregister);
      osip_set_message_callback(osip ,OSIP_NIST_BYE_RECEIVED,       &cb_rcvbye);
      osip_set_message_callback(osip ,OSIP_NIST_CANCEL_RECEIVED,    &cb_rcvcancel);
      osip_set_message_callback(osip ,OSIP_NIST_INFO_RECEIVED,      &cb_rcvinfo);
      osip_set_message_callback(osip ,OSIP_NIST_OPTIONS_RECEIVED,   &cb_rcvoptions);
      osip_set_message_callback(osip ,OSIP_NIST_SUBSCRIBE_RECEIVED, &cb_rcvsubscribe);
      osip_set_message_callback(osip ,OSIP_NIST_NOTIFY_RECEIVED,    &cb_rcvnotify);
      osip_set_message_callback(osip ,OSIP_NIST_UNKNOWN_REQUEST_RECEIVED, &cb_rcvunkrequest);

## Send events to control transaction

Here is a sample to initiate a transaction. The initial event sent to the FIFO contains the first INVITE request. The creation of the message is not shown here.

    int
    create_session(osip_t *osip)
    {
      osip_message_t  *invite;
      osip_transaction_t   *transaction;

      /* You must create your own SIP message. */
      osip_message_init (&invite);
      your_own_method_to_setup_messages(invite);

      /* When it is the first invite, allocate    */
      /* and start a new transaction (prepare the
      /* context and start a thread.)             */
      osip_transaction_init(&transaction,
    	   osip,
    	   invite->to,
    	   invite->from,
    	   invite->callid,
    	   invite->cseq);

      /* The thread is now waiting on its FIFO  */
      /* The following method allocate an event */
      /* and send it to the transaction.        */
      osip_sendmsg(transaction,invite);
    }

    int
    osip_sendmsg(osip_transaction_t *transaction,osip_message_t *msg)
    {
        osip_event_t *evt;

        evt = osip_new_outgoing_sipmessage(msg);

    /* depending on your application model, you can choose */
    /* either to consume the event are add it in the fifo  */
    /* and delay the operations */

        osip_fifo_add(transaction->transactionff,evt);
        osip_transaction_execute(transaction,evt);

        return 0;
    }

## Notes for proxy implementation

The transaction layer provided for oSIP is usable by user agents, registrar, redirect server and some type of conference server.

For stateless proxy, no state machine is required.

# Build your own architecture

Since release 0.7.0, the stack can be used without semaphore and thread support. The design is completely up to you. You have to choose a design that fit the type of application. Here are the different aspect that you need to take care of:

Read all the rfc about SIP!.
implement the transport layer (UDP, TCP, TLS?)
choose a multi thread design or not.
choose how to start timers.

If your application wants to access a database and make IP address resolution, this could leave your application in a blocked state for a while. In this case, a multi threaded application could be very useful and avoid some issues. It worth to say that performance of your application will heavily rely on how you will deal with those issue.

# Bibliography

SIP, Session Initiation Protocole - rfc3261.txt, ietf.

SDP, Session Description Protocole - rfc2327.txt, ietf.