SIP API Developer's Guide

Exit Print View

Updated: July 2014
 
 

Programming with the SIP API

This chapter has specific information about working with the SIP API and examples of use.

Initializing the SIP Stack

The SIP stack must be initialized before performing any other functions. This section discusses the initialization parameters in some detail. The initialization structure is given by the following structure:

typedef struct sip_stack_init_s {
	        int                     sip_version;
	        uint32_t                sip_stack_flags;
	        sip_io_pointers_t       *sip_io_pointers;
	        sip_ulp_pointers_t      *sip_ulp_pointers;
	        sip_header_function_t   *sip_function_table;
	}sip_stack_init_t;
sip_version

This variable must be set to SIP_STACK_VERSION

sip_stack_flags

If the application wants the SIP stack to maintain dialogs, this flag must be set to SIP_STACK_DIALOGS, otherwise this must be set to 0. If SIP_STACK_DIALOGS is not set, the stack does not deal with dialogs at all.

Upper Layer Registrations

The upper layer registrations are callbacks that the stack invokes to deliver processed inbound SIP messages. The stack also invokes the upper layer registrations when certain events occur. The structure is given by the following code:

void (*sip_ulp_recv)(const sip_conn_object_t, sip_msg_t,
                         const sip_dialog_t);

This code is a routine that the application must register for the stack to deliver inbound SIP message after processing. The SIP stack invokes this function with the connection object on which the message arrived the SIP message, and associated dialog, if any. The SIP message will be freed once this function returns. If the application wishes to use the message beyond that, it has to hold a reference to the message by using the sip_hold_msg() and release it by using the sip_free_msg() function after use. Similarly, if the application wishes to cache the dialog, it must increment the reference to the dialog by using the sip_hold_dialog() and release it by using the sip_release_dialog() function after use.

uint_t (*sip_ulp_timeout)(void *, void (*func)(void *),
	                         struct timeval *);
boolean_t (*sip_ulp_untimeout)(uint_t);

An application can register these two routines if it wants to implement its own timer routines for the stack timers. Typically, an application may not provide these and let the stack use its own built-in timer routines. The timer routines implemented by the stack are only for use by the stack. These routines are not available to applications. If the application registers one, then it must also register the other.

int (*sip_ulp_trans_error)(sip_transaction_t, int, void *);

The application can register this routine if it wants to be notified of a transaction error. Typically this error occurs when the transaction layer tries to send a message (could be a retransmission or responding to a retransmitted request or sending an ACK request for a non-2xx final response) using a cached connection object which fails. If this routine is not registered, on such a failure, the transaction is terminated. The final argument is for future use, it is always set to NULL.

void (*sip_ulp_dlg_del)(sip_dialog_t, sip_msg_t, void *);

An application can register this routine if it wants to be notified when a dialog is deleted. The dialog that is going to be deleted is passed along with the SIP message, that caused the dialog to be deleted. The final argument is for future use and is always set to NULL.

void (*sip_ulp_trans_state_cb)(sip_transaction_t, sip_msg_t, int, int);
void (*sip_ulp_dlg_state_cb)(sip_dialog_t, sip_msg_t, int, int);

These two callback routines, if registered, are invoked by the stack when a transaction (sip_ulp_trans_state_cb) or a dialog (sip_ulp_dlg_state_cb) changes states. The message causing the transition is passed along with the transaction/dialog and also the old (before transition) and current (after transition) states.

Connection Manager Interfaces

The following interfaces must be registered by the application to provide I/O related functionalities to the stack. The interfaces act on a connection object that is defined by the application and transparent to the stack. The application registers these interfaces for the stack to work with the connection object. The connection object is application defined, but the stack requires that the first member of the connection object is a void *, which is used by the stack to store connection object specific information that is private to the stack.

int (*sip_conn_send)(const sip_conn_object_t, char *, int);

This function will be invoked by the stack after processing an outbound SIP message. This function will actually send the SIP message to the remote endpoint. A return of 0 indicates success. The SIP message is passed to this function a string along with the length information.

void (*sip_hold_conn_object)(sip_conn_object_t);
void (*sip_hold_conn_object)(sip_conn_object_t);

The application provides mechanism for the stack to indicate that a connection object is in use by the stack and must not be freed. The stack calls the sip_hold_conn_object() function to increment the reference count on a connection object and the sip_hold_conn_object() function to release it after use. The stack expects that the application won't free the connection object if the application increments the references to that connection object.

boolean_t (*sip_conn_is_stream)(sip_conn_object_t);
boolean_t (*sip_conn_is_reliable)(sip_conn_object_t);

These interfaces are used by the stack to obtain attributes of the connection object. The sip_conn_is_stream() function states if the connection object is byte-stream oriented (TCP) or not (SCTP and UDP) and the sip_conn_is_reliable() function indicates if the transport is reliable (TCP and SCTP) or not (UDP).

int (*sip_conn_local_address)(sip_conn_object_t, struct sockaddr *,
	    socklen_t *);
int (*sip_conn_remote_address)(sip_conn_object_t, struct sockaddr *,
	    socklen_t *);

These two interfaces are used by the stack to obtain endpoint information for a connection object. The sip_conn_local_address() function provides the local address/port information while the sip_conn_remote_address() function provides the peer's address/port information. The caller allocates the buffer and passes its associated length along with it. On return the length is updated to reflect the actual length.

int (*sip_conn_transport)(sip_conn_object_t);

This interface is used to obtain the transport used by a connection object (TCP, SCTP or UDP).

int (*sip_conn_timer1)(sip_conn_object_t);
int (*sip_conn_timer2)(sip_conn_object_t);
int (*sip_conn_timer4)(sip_conn_object_t);
int (*sip_conn_timerd)(sip_conn_object_t);

These four interfaces may be registered by an application to provide connection object specific timer information. If these are not registered the stack uses default values. The interfaces provide the timer values for Timer 1 (RTT estimate - default 500 msec, Timer 2 (maximum retransmit interval for non-INVITE request and INVITE response - default 4 secs), Timer 4 (maximum duration a message will remain in the network - default 5 secs) and Timer D (wait time for response retransmit interval - default 32 secs).

Custom SIP Headers

An application can optionally provide a table of custom headers and associated parsing functions. The table is an array with an entry for each header. The table contains the following for each header:

char *header_name

The full name of the header. The application must take care that this does not conflict with existing headers. If the same header name is present in the application registered function table and the one maintained by the stack, the one registered by the application takes precedence.

char *header_short_name

Compact name, if any, for the header.

int (*header_parse_func)(struct sip_header *,
		    struct sip_parsed_header **);

The parsing function for the header. The parser will set the second argument to the parsed structure. A return value of 0 indicates success.

void (*header_free)(struct sip_parsed_header *);

The function that will free the parsed header.

boolean_t (*header_check_compliance)(struct sip_parsed_header *);

An application can optionally provide this function that will check if the header is compliant or not. The compliance for a custom header will be defined by the application.

boolean_t (*header_is_equal)(struct sip_parsed_header *,
           struct sip_parsed_header *);

An application can optionally provide this function to check if the two input headers are equivalent. The equivalence criteria is defined by the application.