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".


Table of Contents
1. The SIP protocol
SIP is independent of media
SIP is independent of the transport layer
SIP is extensible
SIP and end-user services
2. SIP overview
SIP syntax
SIP transactions
SIP sessions
Server behavior
3. The oSIP Library
The goals
The development level
The parser
The state machines
The parser
The transaction manager
Who will benefit from oSIP
Available ports
4. The oSIP parser
files
SIP-URL
Definition and purpose
API for SIP-URL
API for url_param_t and url_header_t
SIP headers
Definition and purpose
Common API for all implemented header.
Specific API for "To" header
API for generic param
SIP messages
definition and purpose
API for SIP message
MACROs
The parser HOW-TO.
Initialise the parser
Allocate a structure
create a URL and a Request-URI.
Add headers in a message
make a string from a structure
free resource in a structure
How to improve the parser performance
5. The oSIP state machines
files
Transaction and events
Definition and purpose of transaction
Definition and purpose of osip_event
API
The callbacks.
Useful MACROs.
The finite state machines HOW-TO
Initialise the osip stack
Allocate and initialize an osip_t element
Send events to control transaction
Notes for proxy implementation
Build your own architecture
Bibliography

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 , 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.