PJSIPDeveloper’s Guide
Version 0.5.4

PJSIP Developer’s Guide

ABOUT PJSIPPJSIP is small-footprint and high-performance SIP stack written in C.
PJSIP is distributed under GNU General Public License (GPL). Alternative
licensing is available.
Please visit http://www.pjproject.net for more details.

ABOUT THIS DOCUMENT
Copyright ©2005-2006 Benny Prijono
This is a free document distributed under GNU Free Documentation License
version 1.2. Everyone is permitted to copy and distribute verbatim copies of thisdocument, but changing it is not allowed.

Page 2PJSIP Developer’s Guide
DOCUMENT REVISION HISTORY
Ver

Date

By

0.5.4

07 Mar2006

bennylp

Changes

Added dlg_terminate(), inv_terminate() et all.



Review the evsub API, added few more words.



Added IM and iscomposing chapter.



Added PJSUA abstraction chapter.

0.5.2

25 Feb2006

bennylp

Added event framework, presence, and refer
event package.

0.5.1

15 Feb2006

bennylp•

Application needs to call pjsip_tsx_recv_msg()
after creating UAS transaction.

0.5.0

27 Jan2006

bennylp•

added generic capabilities management to
endpoint.

•changed module interface (removed supported
methods).

•

no more stateless operations in dialogs.

•

introducing dialog set.

0.5-pre10 Jan2006

bennylp

0.5-pre19 Dec2005

bennylp

Updated according to changes in module andtransaction API.
Initial revision

Page 3PJSIP Developer’s Guide

Table of Contents
TABLE OF CONTENTS....................................................................................................................... 4
TABLE OF FIGURES............................................................................................................................ 8
TABLE OF CODES................................................................................................................................ 8
CHAPTER 1: GENERAL DESIGN.....................................................................................................11
1.1 ARCHITECTURE..................................................................................................................................11
1.1.1 Communication Diagram...................................................................................................... 11
1.1.2 Class Diagram....................................................................................................................... 11
1.2 THE ENDPOINT..................................................................................................................................121.2.1 Pool Allocations and Deallocations...................................................................................... 12
1.2.2 Timer Management................................................................................................................ 12
1.2.3 Polling the Stack.................................................................................................................... 13
1.3 THREAD SAFETY AND THREAD COMPLICATIONS..................................................................................... 13
1.3.1 Thread Safety......................................................................................................................... 13
1.3.2 The Complications................................................................................................................. 13
1.3.3 The Relief............................................................................................................................... 14
CHAPTER 2: MODULE....................................................................................................................... 15
2.1.1 Module Declaration............................................................................................................... 15
2.1.2 Module Priorities................................................................................................................... 16
2.1.3 Incoming Message Processing by Modules........................................................................... 17
2.1.4 Outgoing Message Processing by Modules........................................................................... 17
2.1.5 Transaction User and State Callback.................................................................................... 18
2.1.6 Module Specific Data............................................................................................................ 18
2.1.7 Callback Summary................................................................................................................. 19
2.1.8 Sample Callback Diagrams................................................................................................... 20
2.2 MODULE MANAGEMENT..................................................................................................................... 21
2.2.1 Module Management API...................................................................................................... 21
2.2.2 Module Capabilities.............................................................................................................. 21
CHAPTER 3: MESSAGE ELEMENTS.............................................................................................. 23
3.1 UNIFORM RESOURCE INDICATOR (URI)............................................................................................... 23
3.1.1 URI “Class Diagram”........................................................................................................... 23
3.1.2 URI Context........................................................................................................................... 23
3.1.3 Base URI................................................................................................................................ 24
3.1.4 SIP and SIPS URI.................................................................................................................. 25
3.1.5 Tel URI.................................................................................................................................. 25
3.1.6 Name Address........................................................................................................................ 26
3.1.7 Sample URI Manipulation Program......................................................................................26
3.2 SIP METHODS.................................................................................................................................. 27
3.2.1 SIP Method Representation (pjsip_method).......................................................................... 27
3.2.2 SIP Method API..................................................................................................................... 28
3.3 HEADER FIELDS................................................................................................................................ 29
3.3.1 Header “Class Diagram”..................................................................................................... 29
3.3.2 Header Structure................................................................................................................... 29
3.3.3 Common Header Functions................................................................................................... 30
3.3.4 Supported Header Fields....................................................................................................... 31
3.3.5 Header Array Elements......................................................................................................... 31
3.4 MESSAGE BODY (PJSIP_MSG_BODY).....................................................................................................32
3.5 MESSAGE (PJSIP_MSG)....................................................................................................................... 33
3.6 SIP STATUS CODES...........................................................................................................................34
3.7 NON-STANDARD PARAMETER ELEMENTS.............................................................................................. 35
3.7.1 Data Structure Representation (pjsip_param)...................................................................... 36
3.7.2 Non-Standard Parameter Manipulation................................................................................ 36
3.8 ESCAPEMENT RULES.......................................................................................................................... 36
Page 4PJSIP Developer’s Guide
CHAPTER 4: PARSER......................................................................................................................... 38
4.1 FEATURES.........................................................................................................................................38
4.2 FUNCTIONS....................................................................................................................................... 39
4.2.1 Message Parsing....................................................................................................................39
4.2.2 URI Parsing........................................................................................................................... 39
4.2.3 Header Parsing......................................................................................................................39
4.3 EXTENDING PARSER........................................................................................................................... 40
CHAPTER 5: MESSAGE BUFFERS.................................................................................................. 41
5.1 RECEIVE DATA BUFFER..................................................................................................................... 41
5.1.1 Receive Data Buffer Structure............................................................................................... 41
5.2 TRANSMIT DATA BUFFER (PJSIP_TX_DATA).......................................................................................... 42
CHAPTER 6: TRANSPORT LAYER................................................................................................. 43
6.1 TRANSPORT LAYER DESIGN................................................................................................................ 43
6.1.1 “Class Diagram”.................................................................................................................. 43
6.1.2 Transport Manager................................................................................................................43
6.1.3 Transport Factory..................................................................................................................44
6.1.4 Transport .............................................................................................................................. 44
6.2 USING TRANSPORTS........................................................................................................................... 46
6.2.1 Function Reference................................................................................................................ 46
6.3 EXTENDING TRANSPORTS.................................................................................................................... 46
6.4 INITIALIZING TRANSPORTS...................................................................................................................46
6.4.1 UDP Transport Initialization................................................................................................ 47
6.4.2 TCP Transport Initialization................................................................................................. 47
6.4.3 TLS Transport Initialization.................................................................................................. 47
6.4.4 SCTP Transport Initialization............................................................................................... 47
CHAPTER 7: SENDING MESSAGES................................................................................................ 48
7.1 SENDING MESSAGES OVERVIEW.......................................................................................................... 48
7.1.1 Creating Messages................................................................................................................ 48
7.1.2 Sending Messages.................................................................................................................. 48
7.2 FUNCTION REFERENCE........................................................................................................................49
7.2.1 Sending Response.................................................................................................................. 49
7.2.2 Sending Request..................................................................................................................... 50
7.2.3 Stateless Proxy Forwarding.................................................................................................. 52
7.3 EXAMPLES........................................................................................................................................ 53
7.3.1 Sending Responses................................................................................................................. 53
7.3.2 Sending Requests................................................................................................................... 54
7.3.3 Stateless Forwarding............................................................................................................. 55
CHAPTER 8: TRANSACTIONS......................................................................................................... 56
8.1 DESIGN............................................................................................................................................ 56
8.1.1 Introduction........................................................................................................................... 56
8.1.2 Timers and Retransmissions.................................................................................................. 56
8.1.3 INVITE Final Response and ACK Request............................................................................56
8.1.4 Incoming ACK Request.......................................................................................................... 57
8.1.5 Server Resolution and Transports......................................................................................... 57
8.1.6 Via Header............................................................................................................................. 58
8.2 REFERENCE.......................................................................................................................................58
8.2.1 Base Functions...................................................................................................................... 58
8.2.2 Composite Functions............................................................................................................. 59
8.3 SENDING STATEFULL RESPONSES......................................................................................................... 60
8.3.1 Usage Examples.................................................................................................................... 60
8.4 SENDING STATEFULL REQUEST............................................................................................................ 60
8.4.1 Usage Examples.................................................................................................................... 61
8.5 STATEFULL PROXY FORWARDING......................................................................................................... 61
8.5.1 Usage Examples.................................................................................................................... 61
CHAPTER 9: AUTHENTICATION FRAMEWORK.......................................................................63
Page 5PJSIP Developer’s Guide
9.1 CLIENT AUTHENTICATION FRAMEWORK................................................................................................ 63
9.1.1 Client Authentication Framework Reference........................................................................ 63
9.1.2 Examples................................................................................................................................ 64
9.2 SERVER AUTHORIZATION FRAMEWORK................................................................................................. 65
9.2.1 Server Authorization Reference............................................................................................. 65
9.3 EXTENDING AUTHENTICATION FRAMEWORK.......................................................................................... 67
CHAPTER 10: BASIC USER AGENT LAYER (UA)....................................................................... 68
10.1 BASIC DIALOG CONCEPT.................................................................................................................. 68
10.1.1 Dialog Sessions....................................................................................................................68
10.1.2 Dialog Usages..................................................................................................................... 68
10.1.3 Dialog Set............................................................................................................................ 69
10.1.4 Client Authentication........................................................................................................... 69
10.1.5 Class Diagram..................................................................................................................... 69
10.1.6 Forking................................................................................................................................ 70
10.1.7 CSeq Sequencing................................................................................................................. 72
10.1.8 Transactions........................................................................................................................ 72
10.2 BASIC UA API REFERENCE............................................................................................................. 73
10.2.1 User Agent Module API....................................................................................................... 73
10.2.2 Dialog Structure.................................................................................................................. 73
10.2.3 Dialog Creation API............................................................................................................ 74
10.2.4 Dialog Termination............................................................................................................. 74
10.2.5 Dialog Session Management API........................................................................................ 75
10.2.6 Dialog Usages API.............................................................................................................. 75
10.2.7 Dialog Request and Response API...................................................................................... 75
10.2.8 Dialog Auxiliary API........................................................................................................... 76
10.3 EXAMPLES...................................................................................................................................... 78
10.3.1 Invite UAS Dialog................................................................................................................ 78
10.3.2 Outgoing Invite Dialog........................................................................................................ 80
10.3.3 Terminating Dialog............................................................................................................. 82
CHAPTER 11: SDP OFFER/ANSWER FRAMEWORK................................................................. 83
11.1 SDP NEGOTIATOR STRUCTURE......................................................................................................... 83
11.2 SDP NEGOTIATOR SESSION.............................................................................................................. 84
11.3 SDP NEGOTIATION FUNCTION.......................................................................................................... 85
CHAPTER 12: DIALOG INVITE SESSION AND USAGE............................................................. 86
12.1 INTRODUCTION................................................................................................................................ 86
12.1.1 Terms................................................................................................................................... 86
12.1.2 Features............................................................................................................................... 86
12.1.3 Invite Session State.............................................................................................................. 86
12.1.4 Invite Session Creation........................................................................................................ 87
12.1.5 Messages Handling..............................................................................................................88
12.1.6 Extending the Dialog........................................................................................................... 88
12.1.7 Extending the Invite Session................................................................................................ 88
12.2 REFERENCE.....................................................................................................................................89
12.2.1 Data Structure..................................................................................................................... 89
12.2.2 Invite Usage Module............................................................................................................ 89
12.2.3 Session Callback.................................................................................................................. 90
12.2.4 Session Creation and Termination...................................................................................... 91
12.2.5 Session Operations.............................................................................................................. 92
12.2.6 Auxiliary API....................................................................................................................... 93
CHAPTER 13: SIP-SPECIFIC EVENT NOTIFICATION.............................................................. 95
13.1 INTRODUCTION................................................................................................................................ 95
13.1.1 Basic Concept...................................................................................................................... 95
13.1.2 Event Package..................................................................................................................... 95
13.1.3 Header Fields...................................................................................................................... 96
13.2 BASIC OPERATION........................................................................................................................... 96
13.2.1 Client Initiating Subscription.............................................................................................. 96
13.2.2 Server Receiving Incoming Subscription............................................................................. 97
Page 6PJSIP Developer’s Guide
13.2.3 Server Activating Subscription (Sending NOTIFY)............................................................. 98
13.2.4 Client Receiving NOTIFY Requests..................................................................................... 98
13.2.5 Server Terminating Subscription......................................................................................... 99
13.2.6 Client Receiving Subscription Termination....................................................................... 100
13.2.7 Client Refreshing Subscription.......................................................................................... 100
13.2.8 Server Detecting Refresh Timeout..................................................................................... 100
13.3 REFERENCE...................................................................................................................................101
13.3.1 Module Management......................................................................................................... 101
13.3.2 Event Package Management............................................................................................. 101
13.3.3 Event Subscription State.................................................................................................... 101
13.3.4 Event Subscription Session................................................................................................ 102
13.3.5 Generic Event Subscription Callback................................................................................102
13.3.6 Event Subscription API...................................................................................................... 104
13.3.7 Auxiliary API..................................................................................................................... 106
CHAPTER 14: PRESENCE EVENT PACKAGE............................................................................107
14.1 INTRODUCTION.............................................................................................................................. 107
14.2 REFERENCE...................................................................................................................................107
CHAPTER 15: REFER EVENT PACKAGE................................................................................... 108
CHAPTER 16: INSTANT MESSAGING......................................................................................... 109
16.1 INSTANT MESSAGING..................................................................................................................... 109
16.1.1 Sending MESSAGE............................................................................................................ 109
16.1.2 Receiving MESSAGE......................................................................................................... 110
16.2 MESSAGE COMPOSITION INDICATION................................................................................................ 110
CHAPTER 17: PJSUA ABSTRACTION.......................................................................................... 112

Page 7PJSIP Developer’s Guide

Table of Figures
FIGURE 1 COLLABORATION DIAGRAM..................................................................................... 11
FIGURE 2 CLASS DIAGRAM............................................................................................................ 11
FIGURE 3 MODULE STATE DIAGRAM......................................................................................... 15
FIGURE 4 CASCADE MODULE CALLBACK................................................................................ 17
FIGURE 5 CALLBACK SUMMARY................................................................................................. 19
FIGURE 6 PROCESSING OF INCOMING MESSAGE OUTSIDE TRANSACTION/DIALOG..................................................................................................................................................................20
FIGURE 7 PROCESSING OF INCOMING MESSAGE INSIDE TRANSACTION.....................20
FIGURE 8 PROCESSING OF INCOMING MESSAGE INSIDE DIALOG BUT OUTSIDE
TRANSACTION.................................................................................................................................... 21
FIGURE 9 URI “CLASS DIAGRAM”................................................................................................23
FIGURE 10 HEADER “CLASS DIAGRAM”.................................................................................... 29
FIGURE 11 TRANSPORT LAYER "CLASS DIAGRAM"............................................................. 43
FIGURE 12 AUTHENTICATION FRAMEWORK.......................................................................... 63
FIGURE 13 CLIENT AUTHENTICATION DATA STRUCTURE................................................ 64
FIGURE 14 BASIC USER AGENT CLASS DIAGRAM.................................................................. 70
FIGURE 15 SDP NEGOTIATOR "CLASS DIAGRAM".................................................................83
FIGURE 16 SDP OFFER/ANSWER SESSION STATE DIAGRAM.............................................. 84
FIGURE 17 INVITE SESSION STATE DIAGRAM.........................................................................87
FIGURE 18 INVITE SESSION STATE DESCRIPTION................................................................. 87
FIGURE 19 CLIENT INITIATING SUBSCRIPTION..................................................................... 96
FIGURE 20 SERVER CREATING SUBSCRIPTION...................................................................... 97
FIGURE 21 SERVER ACTIVATING SUBSCRIPTION..................................................................98
FIGURE 22 CLIENT RECEIVING NOTIFY.................................................................................... 99
FIGURE 23 SERVER TERMINATING SUBSCRIPTION.............................................................. 99
FIGURE 24 CLIENT RECEIVING SUBSCRIPTION TERMINATION..................................... 100
FIGURE 25 CLIENT REFRESHING SUBSCRIPTION................................................................ 100
FIGURE 26 SERVER DETECTING SUBSCRIPTION TIMEOUT............................................. 101

Table of Codes
CODE 1 LOCKING DIALOG PROBLEM........................................................................................ 14
CODE 2 CORRECT WAY TO LOCK A DIALOG...........................................................................14
CODE 3 MODULE DECLARATION................................................................................................. 15
CODE 4 MODULE PRIORITIES....................................................................................................... 16
CODE 5 MODULE SPECIFIC DATA................................................................................................ 18
CODE 6 ACCESSING MODULE SPECIFIC DATA........................................................................19
CODE 7 URI CONTEXT...................................................................................................................... 23
Page 8PJSIP Developer’s Guide
CODE 8 GENERIC URI DECLARATION........................................................................................ 24
CODE 9 URI VIRTUAL FUNCTION TABLE.................................................................................. 24
CODE 10 SIP URI DECLARATION.................................................................................................. 25
CODE 11 TEL URI DECLARATION.................................................................................................26
CODE 12 NAME ADDRESS DECLARATION................................................................................. 26
CODE 13 SAMPLE URI MANIPULATION PROGRAM................................................................27
CODE 14 SIP METHOD DECLARATION........................................................................................28
CODE 15 SIP METHOD ID................................................................................................................. 28
CODE 16 GENERIC HEADER DECLARATION............................................................................ 30
CODE 17 GENERIC HEADER DECLARATION............................................................................ 30
CODE 18 HEADER VIRTUAL FUNCTION TABLE.......................................................................30
CODE 19 MESSAGE BODY DECLARATION................................................................................. 32
CODE 20 SIP MESSAGE DECLARATION...................................................................................... 33
CODE 21 SIP STATUS CODE CONSTANTS................................................................................... 35
CODE 22 NON-STANDARD PARAMETER DECLARATION......................................................36
CODE 23 RECEIVE DATA BUFFER DECLARATION................................................................. 41
CODE 24 TRANSMIT DATA BUFFER DECLARATION.............................................................. 42
CODE 25 TRANSPORT OBJECT DECLARATION....................................................................... 45
CODE 26 SAMPLE: STATELESS RESPONSE................................................................................ 53
CODE 27 SAMPLE: STATELESS RESPONSE................................................................................ 53
CODE 28 STATELESS REDIRECTION........................................................................................... 54
CODE 29 SENDING STATELESS REQUEST..................................................................................54
CODE 30 STATELESS FORWARDING........................................................................................... 55
CODE 31 SENDING STATEFULL RESPONSE............................................................................... 60
CODE 32 SENDING STATEFULL RESPONSE............................................................................... 60
CODE 33 SENDING REQUEST STATEFULLY.............................................................................. 61
CODE 34 STATEFULL FORWARDING...........................................................................................62
CODE 35 CLIENT ATHORIZATION EXAMPLE...........................................................................65
CODE 36 DIALOG STRUCTURE...................................................................................................... 73
CODE 37 CREATING DIALOG FOR INCOMING INVITE..........................................................78
CODE 38 ANSWERING DIALOG......................................................................................................79
CODE 39 PROCESSING CANCEL REQUEST................................................................................ 80
CODE 40 PROCESSING ACK REQUEST........................................................................................ 80
CODE 41 CREATING OUTGOING DIALOG..................................................................................81
CODE 42 RECEIVING RESPONSE IN DIALOG............................................................................ 81
CODE 43 SENDING ACK REQUEST................................................................................................82
CODE 44 INVITE SESSION DATA STRUCTURE.......................................................................... 89
CODE 45 INVITE SESSION OPTIONS............................................................................................. 89
CODE 46 EVENT SUBSCRIPTION STATE................................................................................... 102
CODE 47 EVENT SUBSCRIPTION CALLBACK..........................................................................103
Page 9PJSIP Developer’s Guide
CODE 48 SENDING IM OUTSIDE DIALOG................................................................................. 109
CODE 49 SENDING IM INSIDE DIALOG..................................................................................... 110

Page 10PJSIP Developer’s Guide

Chapter 1:General Design
1.1 Architecture
1.1.1 Communication Diagram
The following diagram shows how (SIP) messages are passed back and forthamong PJSIP components.
MODULEAPPLICATIONMODULEUA Layeruser_agent, dialog

DialogHash Table

LEGEND:
Message Flow

MODULE
Transaction Layer
sip_transaction.c

Transaction
Hash Table

ENDPOINT
sip_endoint.c
Global Timer

GlobalI/O Queue

PARSER
sip_parser.c

ParserPluginTRANSPORT MANAGER
sip_transport.c

ParserPluginTRANSPORT(pjsip_transport)

TRANSPORT(pjsip_transport)

PJLIB I/O Queue

Figure 1 Collaboration Diagram

1.1.2 Class Diagram
The following diagram shows the “class diagram”.
UA Module
sip_ua.c
Dialogsip_dialog.c
DialogHash Table

Transaction Module
sip_transaction.c

Transaction
sip_transaction.c
Transaction
Hash Table

APPLICATIONMODULEn

ENDPOINT
sip_endoint.c

1

1

PARSER
sip_parser.c

TRANSPORT MANAGER
sip_transport.cnHeaderParsern
TRANSPORT
sip_transport.cn
URI
ParserUDP TRANSPORT
sip_transport_udp.c

TCP TRANSPORT
sip_transport_tcp.c...

Figure 2 Class Diagram

Page 11PJSIP Developer’s Guide

1.2 The EndpointAt the heart of the SIP stack is the SIP endpoint, which is represented with
opaque type pjsip_endpoint. The endpoint has the following properties andresponsibilities:

It has pool factory, and allocates pools for all SIP components.



It has timer heap instance, and schedules timers for all SIP components.



It has the transport manager instance. The transport manager has SIP
transports and controls message parsing and printing.

It owns a single instance of PJLIB’s ioqueue. The ioqueue is a proactor
pattern to dispatch network events.



It provides a thread safe polling function, to which application’s threads
can poll for timer and socket events (PJSIP does not create any threads byitself).

It manages PJSIP modules. PJSIP module is the primary means forextending the stack beyond message parsing and transport.



It receives incoming SIP messages from transport manager and distributes
the message to modules.

Some of the basic functionalities will be described in the following sections, andthe other will be described in next chapters.

1.2.1 Pool Allocations and Deallocations
All memory allocations for the SIP components will be done via the endpoint, toguarantee thread safety and to enforce consistent policies throughout the entire
application. An example of policy that can be used is pool caching, where unused
memory pools are kept for future use instead of destroyed.
The endpoint provides these functions to allocate and release memory pools:
pjsip_endpt_create_pool(),



pjsip_endpt_release_pool().

When the endpoint is created (pjsip_endpt_create()), application MUST specify
the pool factory that will be used by the endpoint. Endpoint keeps this poolfactory pointer throughout its lifetime, and will use this to create and releasememory pools.

1.2.2 Timer Management
The endpoint keeps a single timer heap instance to manage timers, and all timer
creation and scheduling by all SIP components will be done via the endpoint.
The endpoint provides these functions to manage timers:

pjsip_endpt_schedule_timer(),

pjsip_endpt_cancel_timer().

The endpoint checks for timer’s expiration when the endpoint polling function iscalled.

Page 12PJSIP Developer’s Guide

1.2.3 Polling the Stack
The endpoint provides a single function call (pjsip_endpt_handle_events()) tocheck the occurrence of timer and network events. Application can specify how
long it is prepared to wait for the occurrence of such events.
PJSIP stack never creates threads. All execution throughout the stack runs onbehalf of application’s created thread, either when an API is called or whenapplication calls the polling function.
The polling function is also able to optimize the waiting time based on the timer
heap’s contents. For example, if it knows at a timer will expire in the next 5 ms, itwill not wait for socket events for longer than this; doing so will unnecessarily
make the application wait for longer than it should when there is no network
events occurs. The precision of the timer will of course vary across platforms.

1.3 Thread Safety and Thread Complications
1.3.1 Thread Safety
Thread safety is rather a complicated matter to discuss. But, rather fortunately,
the following design principle is applied consistently throghout the stack:Objects MUST BE thread safe, while data structure MUST NOT BE
thread safe.
With regard to this topic, and by nature, the difference between object andsimple data structure is not exactly clear. But few examples may give you an
idea.
Examples of data structures are:

PJLIB’s data structures, such as lists, arrays, hash tables, strings, andmemory pools.



SIP messaging elements such as URIs, header fields, and SIP messages.

These data structures are not thread safe; the thread safety to these data
structures will be guaranteed by the object that contains them. If data structures
were made thread safe, it will seriously affect the performance of the stack anddrains the operating system’s resources.
In contrast, SIP objects MUST be thread safe. Examples of what we call objectsare:

PJLIB objects, such as ioqueue.



PJSIP objects, such as endpoint, transactions, dialogs, dialog usages, etc.

1.3.2 The Complications
To make matters rather worse, some of these objects have their declaration
exposed in the header files (e.g. pjsip_transaction and pjsip_dialog). Although the
API explosed by these objects are guaranteed to be thread safe, application
MUST obtain the appropriate lock before accessing these data structures in theapplication’s code, for example by calling pj_mutex_lock() to the object’s mutex.
To make matters even worse, a dialog expose different API to lock the dialog.
Instead of calling pj_mutex_lock() and pj_mutex_unlock(), application SHOULD
call pjsip_dlg_inc_lock() and pjsip_dlg_dec_lock() instead. The difference
Page 13PJSIP Developer’s Guide
between the two approaches are, the dialog inc/dec lock guarantees that the
dialog will not be destroyed in the function call, causing pj_mutex_unlock() tocrash because the dialog has been destroyed.
Consider the following example.

1
2
3

pj_mutex_lock(dlg->mutex);
pjsip_dlg_end_session(dlg, ...);
pj_mutex_unlock(dlg->mutex);
Code 1 Locking Dialog Problem

In the previous (imaginary) example, the application MAY crash in line 3, because
pjsip_dlg_end_session() may destroy the dialog in certain cases, e.g. when
outgoing initial INVITE transaction has not been answered with any responses,
thus the transaction can be destroyed immediately, causing the dialog to be
destroyed immediately. The dialog’s inc/dec lock prevents this problem bytemporarily increase dialog’s session counter, so that the dialog won’t get
destroyed on end_session() function. The dialog MAY be destroyed in the
dec_lock() function. So the sequence to properly lock a dialog should be like this:1
2
3

pjsip_dlg_inc_lock(dlg);
pjsip_dlg_end_session(dlg, ...);
pjsip_dlg_dec_lock(dlg);
Code 2 Correct Way to Lock a Dialog

And finally, to make matters REALLY worse, the sequence of locking must be
done in correct order, or otherwise a deadlock will occur. For example, if
application wants to lock both a dialog and a transaction inside the dialog,
application MUST acquire the dialog mutex first before transaction mutex, orotherwise deadlock will occur when other thread is currently acquiring the same
dialog and transaction in the reverse order!

1.3.3 The Relief
Fortunately, it is quite rare that application needs to acquire object’s mutex
directly, so above problems should be quite rare to occur.
Application should use the object’s API to access the object, where available. The
APIs guarantee the correctness of the locking to avoid deadlocks and crashbecause object has been deleted.
And when application callbacks are called by an object (e.g. transactions or
dialogs), these callbacks are normally called while the object’s lock has beenacquired. So application can safely access the object’s data strucure without
needed to acquire the object’s lock.

Page 14PJSIP Developer’s Guide

Chapter 2:Module
Module framework is the main means for distributing SIP messages among
software components in PJSIP application. All software components in PJSIP,
including the transaction layer and dialog layer, are implemented as module.
Without modules, the core stack (pjsip_endpoint and transport) simply wouldn’tknow how to handle SIP messages.
The module framework is based on a simple but yet powerfull interface
abstraction. For incoming messages, the endpoint (pjsip_endpoint) distributes themessage to all modules starting from module with highest priority, until one ofthem says that it has processed the message. For outgoing messages, theendpoint distributes the outgoing messages before they are transmitted to thewire, to allow modules to put last modification on the message if they wish.

2.1.1 Module Declaration
Module interface is declared in <pjsip/sip_module.h> as follows.
struct pjsip_module{
PJ_DECL_LIST_MEMBER(struct pjsip_module);
pj_str_t
name;
int
id;
int
priority;// For internal list mgmt.
// Module name.
// Module ID, set by endpt// Priority

pj_status_t (*load)(pjsip_endpoint *endpt);
pj_status_t (*start)(void);
pj_status_t (*stop)(void);
pj_status_t (*unload)(void);
pj_bool_t(*on_rx_request) (pjsip_rx_data *rdata);
pj_bool_t(*on_rx_response)(pjsip_rx_data *rdata);
pj_status_t (*on_tx_request) (pjsip_tx_data *tdata);
pj_status_t (*on_tx_response)(pjsip_tx_data *tdata);
void(*on_tsx_state) (pjsip_transaction *tsx,
pjsip_event *event);// Called to load the mod.
// Called to start.
// Called top stop.
// Called before unload// Called on rx request// Called on rx response// Called on tx request// Called on tx request// Called on transaction// state changed};
Code 3 Module Declaration

All function pointers are optional; if they’re not specified, they’ll be treated as if
they have returned successfully.
The four function pointers load, start, stop, and unload are called by endpoint tocontrol the module state. The following diagram shows the module’s state
lifetime.
load()NULL STATE

start()LOADED

unload()STARTEDstop()

Figure 3 Module State Diagram

Page 15PJSIP Developer’s Guide
The on_rx_request() and on_rx_response() function pointers are the primarymeans for the module to receive SIP messages from endpoint (pjsip_endpt) orfrom other modules. The return value of these callbacks is important. If a callback
has returned non-zero (i.e. true condition), it semantically means that the module
has taken care the message; in this case, the endpoint will stop distributing themessage to other modules. Section 2.1.3 Incoming Message Processing byModules will describe this in more detail.
The on_tx_request() and on_tx_response() function pointers are called bytransport manager before a message is transmitted. This gives an opportunity forsome types of modules (e.g. sigcomp, message signing) chance to make lastmodification to the message. All modules MUST return PJ_SUCCESS (i.e. zerostatus), or otherwise the transmission will be cancelled. Section 2.1.4 Outgoing
Message Processing by Modules will describe this in more detail.
The on_tsx_state() function pointer is used to receive notification every time atransaction state has changed, which can be caused by receipt of message,transmission of message, timer events, or transport error event. Moreinformation about this callback will be described in next section 2.1.5“Transaction User and State Callback”.

2.1.2 Module Priorities
Module priority specifies the order of which modules are called first to process the
callback. Module with higher priority (i.e. lower priority number) will have theiron_rx_request() and on_rx_response() called first, and on_tx_request() and
on_tx_response() called last.
The values below are the standard to set module priority.
enum pjsip_module_priority{
PJSIP_MOD_PRIORITY_TRANSPORT_LAYERPJSIP_MOD_PRIORITY_TSX_LAYERPJSIP_MOD_PRIORITY_UA_PROXY_LAYERPJSIP_MOD_PRIORITY_DIALOG_USAGEPJSIP_MOD_PRIORITY_APPLICATION};= 8, // Transport= 16, // Transaction layer.
= 32, // UA or proxy layer= 48, // Invite usage, event subscr. framework.
= 64, // Application has lowest priority.

Code 4 Module Priorities

Note: remember that lower priority number means higher priority!
The priority PJSIP_MOD_PRIORITY_TRANSPORT_LAYER is the priority used bytransport manager. This priority currently is only used to control message
transmission, i.e. module with lower priority than this (that means higher priority
number!) will have the on_tx_request()/on_tx_response() called before themessage is processed by transport layer (e.g. destination is calculated, message
is printed to contiguous buffer), while module with higher priority than this will
have the callback called after the message has been processed by transportlayer. Please see 2.1.4Outgoing Message Processing by Modules for more
information.
PJSIP_MOD_PRIORITY_TSX_LAYER is the priority used by transaction layer
module. The transaction layer absorbs all incoming messages that belong to atransaction.
PJSIP_MOD_PRIORITY_UA_PROXY_LAYER is the priority used by UA layer (i.e.
dialog framework) or proxy layer. The UA layer absorbs all incoming messages
that belong to a dialog set (this means forked responses as well).
Page 16PJSIP Developer’s Guide
PJSIP_MOD_PRIORITY_DIALOG_USAGE is for dialog usages. Currently PJSIP
implements two types of dialog usages: invite sesssion and event subscription
session (including REFER subscription). The dialog usage absorbs messages inside
a dialog that belong to particular session.
PJSIP_MOD_PRIORITY_APPLICATION is the appropriate value for typicalapplication modules, when they want to utilize transactions, dialogs, and dialog
usages.

2.1.3 Incoming Message Processing by Modules
When incoming message arrives, it is represented as receive message buffer(struct pjsip_rx_data, see section 5.1 “Receive Data Buffer”). Transportmanager parses the message, put the parsed data structures in the receive
message buffer, and passes the message to the endpoint.
The endpoint distributes the receive message buffer to each registered module bycalling on_rx_request() or on_rx_response() callback, starting from module withhighest priority (i.e. lowest priority number) until one of them returns non-zero.
When one of the module has returned non-zero, endpoint stops distributing themessage to the remaining of the modules, because it assumes that the module
has taken care about the processing of the message.
The module which returns non-zero on the callback itself may further distributethe message to other modules. For example, the transaction module, uponreceiving matching message, will process the message then distributes themessage to its transaction user, which in itself must be a module too. The
transaction passes the message to the transaction user (i.e. a module) by calling
on_rx_request() or on_rx_response() callback of that module, after setting thetransaction field in the receive message buffer so that the transaction user
module can distinguish between messages that are outside transactions andmessages that are inside a transaction.
The following diagram shows an example of how modules may cascadely callother modules.

MODULE

ENDPOINT

rdata

TRANSACTION

MODULErdata

DIALOG

MODULE
rdata

Event Subscriptn.
(SIMPLE)

MODULErdata

APPLICATION

Figure 4 Cascade Module Callback

2.1.4 Outgoing Message Processing by Modules
An outgoing request or response message is represented by a transmit data
buffer (pjsip_tx_data), which among other things, contains the message
structure itself, memory pool, contiguous buffer, and transport info.
When pjsip_transport_send() is called to send a message, transport manager
calls on_tx_request() or on_tx_response() for all modules, starting with modules
with lowest priority (i.e. highest priority number). When these callbacks arecalled, the message may have or have not been processed by the transport layer.
The transport layer is responsible for managing these information inside atransmit buffer:transport info, and

printing the message structure to contiguous buffer.

Modules with priority lower than PJSIP_MOD_PRIORITY_TRANSPORT_LAYER (i.e.
has higher priority number) will receive the message before these information
Page 17PJSIP Developer’s Guide
are obtained. That means the destination address has not been calculated, andmessage has not been printed to contiguous buffer.
If modules want to modify the message structure before it is printed to buffer,then it must set its priority number higher than transport layer priority. If
modules want to see the actual packet bytes as they are transmitted to the wire(e.g. for logging purpose), then it should set its priority number to lower thantransport layer.
A practical case where a module wants to set its priority higher than transport layer (i.e. has lower
priority number) is the logging module, where it wants to print outgoing message after it has been
printed to contiguous buffer and destination address has been calculated.

In all cases, modules MUST return PJ_SUCCESS for the return value of thesecallbacks. If a module returns other error codes, the transmission will becancelled and the error code is returned back to pjsip_transport_send() caller.

2.1.5 Transaction User and State Callback
A special callback in the module definition (on_tsx_state) is used to receive
notification from a particular transaction when transaction state has changed.
This callback is unique because transaction state may change because of nonmessage related events (e.g. timer timeout and transport error).
This callback will only be called after the module has been registered astransaction user for a particular transaction. Only one transaction user is allowed
per transaction. Transaction user can be set to transaction on per transaction
basis.
For transactions created within a dialog, the transaction user is set to the UA
layer module on behalf of a particular dialog. When applications creates thetransaction manually, they may set themselves as the transaction user.
The on_tsx_state() callback will not be called upon receipt of request or response
retransmissions. Note that transmission or receipt of provisional responses are
not considered as retransmissions, which means that receipt or transmission ofprovisional responses will always caused this callback to be called.

2.1.6 Module Specific Data
Some PJSIP components have a container where modules can put module specificdata in that component. This container is named as mod_data by convention, andis an array of pointer to void, which is indexed by the module ID.
For example, an incoming packet buffer (pjsip_rx_data) has the following
declaration for module specific data container:
struct pjsip_rx_data{...
struct {void *mod_data[PJSIP_MAX_MODULE];} endpt_info;};
Code 5 Module Specific Data

The mod_data array is indexed by module ID. The module ID is determined whenthe module is registered to endpoint.
Page 18PJSIP Developer’s Guide
When an incoming packet buffer (pjsip_rx_data) is passed around to modules, amodule can put module specific data in the appropriate index in mod_data, so thatthe value can be picked up later by that module or by application. For example,
the transaction layer will put the matching transaction instance in the mod_data,
and user agent layer will put the matching dialog instance in the mod_data too.
Application can retrieve the value calling pjsip_rdata_get_tsx() or
pjsip_rdata_get_dlg(), which is a simple array lookup function as follows:// This code can be found in sip_transaction.cstatic pjsip_module mod_tsx_layer;
pjsip_transaction *pjsip_rdata_get_tsx(pjsip_rx_data *rdata){
return rdata->endpt_info.mod_data[mod_tsx_layer.id];}
Code 6 Accessing Module Specific Data

2.1.7 Callback Summary
The following table summarizes the occurrence of an event and the triggering ofparticular callbacks. The on_tsx_state() callback will of course only be called
when application has chosen to process a request statefully.
on_rx_request() or
on_rx_response()

on_tsx_state()

Receipt of new requests or responses

CalledCalledReceipt retransmissions of requests or
responses.

Called ONLY whenpriority number is lower
than transaction layer1

Not Called

Transmission of new requests or responses.

Not Called

CalledRetransmissions of requests or responses.

Not Called

Not Called

Transaction timeout

Not Called

CalledOther transaction failure events (e.g. DNS
query failure, transport failure)

Not Called

CalledEvent

Figure 5 Callback Summary

This is because the matching transaction prevents the message from being distributed further (byreturning PJ_TRUE) and it also does NOT call TU callback upon receiving retransmissions.
1Page 19PJSIP Developer’s Guide

2.1.8 Sample Callback Diagrams
Incoming Message Outside Transaction and Outside Dialog
The processing is as follows:
APPLICATION

1)Transport manager (pjsip_tpmgr) passes
all received messages to endpoint (afterparsing the message).

2)

Endpoint (pjsip_endpt) distributes themessage to all registered callbacks. Firstin the callback list is transaction layer.
Transaction layer looks up the message
in transaction table, and couldn’t find amatching transaction.

3)

Endpoint distributes the message to next
callback in the list, which is user agent.

4)

User agent looks up the message indialog’s hash table and couldn’t findmatching dialog set.

5)

Endpoint continues distributing themessage to next registered callbacks
until it reaches application. Application
processes the message (e.g. respondstatelessly, create UAS transaction, or
proxy the request, or create dialog, etc.)

on_rx_xxx()

DialogHash Table

DIALOG(4) lookup /not found

USER AGENT
on_rx_xxx()(5) rdata
TRANSACTION
Transaction
Hash Table(3) rdata(2) lookup /not found

ENDPOINT

endpt_transport_callback()(1) rdata
TRANSPORT MANAGER
Figure 6 Processing of Incoming Message
Outside Transaction/Dialog

Incoming Message Inside Transaction
The processing is as follows:
1)

Transport manager (pjsip_tpmgr) passes
all received messages to endpoint (afterparsing the message).

2)

Endpoint (pjsip_endpt) distributes themessage to all registered callbacks. Firstin the callback list is transaction layer.
Transaction layer looks up the message
in transaction table, and found amatching transaction.

3)

Because transaction’s callback returns
PJ_TRUE, endpoint does not distributethe message further.

4)

The transaction processes the response(e.g. updates the FSM). If the message isa retransmission, the processing stops
here. Otherwise transaction then passes
the message to it’s transaction user (TU),
which can be a dialog or application.

5)

If the TU is a dialog, the dialog processes
the response then pass the response toit’s dialog user (DU, e.g. application).

6)

If the arrival of the message has changedtransaction’s state, transaction will notify
it’s TU about the new state.

7)

If TU is a dialog, it may further notify
application about dialog’s state changed.

(5) rdata +tsx +dlg
(7) notify dialog state
DIALOG/APPLICATION
on_rx_xxx() on_tsx_state()

DialogHash Table

USER AGENT(6) notify state(4) rdata +tsx
TRANSACTION
Transaction
Hash Table(2) lookup /found !

on_rx_xxx()(3) rdata
ENDPOINT

endpt_transport_callback()(1) rdata
TRANSPORT MANAGER

Figure 7 Processing of Incoming Message
Inside Transaction

Page 20PJSIP Developer’s Guide
Incoming Message Inside Dialog but Outside Transaction
The processing is as follows:
APPLICATION

1)Transport manager (pjsip_tpmgr) passes
all received messages to endpoint (afterparsing the message).

2)

Endpoint (pjsip_endpt) distributes themessage to all registered callbacks. Firstin the callback list is transaction layer.
Transaction layer looks up the message
in transaction table, and couldn’t find amatching transaction.

3)

Endpoint distributes the message to next
modules in the list, until it reaches useragent module.

4)

The user agent module looks-up theowning of the message in dialog’s hashtable and found a matching dialog.

5)

The user agent module passes themessage to the appropriate dialog.

6)

The dialog always creates transaction forincoming request, then distribute therequest by calling on_rx_request() AND
on_tsx_state() of its dialog usages.

on_rx_xxx()(6) msg
DIALOG

DialogHash Table(4) lookup /found !

(5) msg
USER AGENT
on_rx_xxx()

TRANSACTION
Transaction
Hash Table(2) lookup /not found(3) msg
ENDPOINT

endpt_transport_callback()(1) msg
TRANSPORT MANAGER

Figure 8 Processing of Incoming Message
Inside Dialog but Outside Transaction

2.2 Module Management
Modules are managed by PJSIP’s endpoint (pjsip_endpoint). Application MUST
register each module manually to endpoint so that it can be recognized by thestack.

2.2.1 Module Management API
The module management API are declared in <pjsip/sip_endpt.h>.
pj_status_t pjsip_endpt_register_module(

pjsip_endpoint *endpt,
pjsip_module *module );Register a module to the endpoint. The endpoint will then call the load andstart function in the module to properly initialize the module, and assign aunique module ID for the module.
pj_status_t pjsip_endpt_unregister_module( pjsip_endpoint *endpt,
pjsip_module *module );Unregister a module from the endpoint. The endpoint will then call thestop and unload function in the module to properly shutdown the module.

2.2.2 Module Capabilities
Module MAY declare new capabilities to the endpoint. Currently the endpoint
manages these capabilities:
Page 21PJSIP Developer’s Guide

allowed SIP methods (Allow header field),

supported SIP extensions (Supported header field).



supported content type (Accept header field).

These header fields will be added to outgoing requests or responses
automatically, where appropriate.
A module declares new capability by calling pjsip_endpt_add_capability()
function.
pj_status_t pjsip_endpt_add_capability( pjsip_endpoint *endpt,
pjsip_module *mod,int htype,
const pj_str_t *hname,unsigned count,
const pj_str_t tags[]);Register new capabilities to the endpoint. The htype argument specifies
which header to add the capabilities to, and such as PJSIP_H_ACCEPT,PJSIP_H_ALLOW, and PJSIP_H_SUPPORTED. The hname argument is
optional; it is used only to specify capabilities in header fields that are notrecognized by the core stack. The count and tags arguments specifies
array of string tags to be added to the header field.

const pjsip_hdr* pjsip_endpt_get_capability(

pjsip_endpoint *endpt,
int htype,
const pj_str_t *hname);

Get a capability header field, which contains all capabilities that have beenregistered to the endpoint for the specified header field.

Page 22PJSIP Developer’s Guide

Chapter 3:Message Elements
3.1 Uniform Resource Indicator (URI)The Uniform Resource Indicator (URI) in PJSIP is modeled pretty much in object
oriented manner (or some may argue it’s object based, not object oriented).
Because of this, URI can be treated uniformly by the stack, and new types URI
can be introduced quite easily.

3.1.1 URI “Class Diagram”
The following diagram shows show the URI objects are designed.
pjsip_uri
Attributes:
Operations:const pj_str_t pjsip_uri_get_scheme(uri);pjsip_uri* pjsip_uri_get_uri(uri);pj_status_t pjsip_uri_cmp(uri1, uri2);
int pjsip_uri_print(context, uri, buf, maxlen);pjsip_uri *pjsip_uri_clone(uri);

New types of URI can be defined

pjsip_sip_uri

pjsip_tel_uri

Attributes:
user, passwd, host, port, user_param,
method_param, transport_param, ttl_param,
lr_param, maddr_param, other_param,
header_param

Attributes:
number, context, ext_param, isub_param,
other_param

Operations:pjsip_sip_uri *pjsip_sip_uri_create(pool,secure);
void pjsip_sip_uri_init(uri, secure);
void pjsip_sip_uri_assign(pool, dst_uri, src_uri);

Operations:pjsip_tel_uri *pjsip_tel_uri_create(pool);pjsip_name_addr
Attributes:
uri, display
Operations:pjsip_name_addr *pjsip_name_addr_create(pool);Figure 9 URI “Class Diagram”

More information on each objects will be described in next sections.

3.1.2 URI Context
URI context specifies where the URI is being used (e.g. in request line, in
From/To header, etc.). The context specifies what URI elements are allowed toappear in that context. For example, transport parameter is not allowed to appear
in From/To header, etc.
In PJSIP, the context must be specified when printing the URI to a buffer andwhen comparing two URIs. In this case, the parts of URI that is not allowed toappear in the specified context will be ignored during printing and comparison
process.
enum pjsip_uri_context_e{
PJSIP_URI_IN_REQ_URI,PJSIP_URI_IN_FROMTO_HDR,
PJSIP_URI_IN_CONTACT_HDR,
PJSIP_URI_IN_ROUTING_HDR,
PJSIP_URI_IN_OTHER,};// The URI is in Request URI.
// The URI is in From/To header.
// The URI is in Contact header.
// The URI is in Route/Record-Route header.
// Other context (web page, business card, etc.)
Code 7 URI Context

Page 23PJSIP Developer’s Guide

3.1.3 Base URIThe pjsip_uri structure contains property that is shared by all types of URI.
Because of this, all types of URI can be type-casted to pjsip_uri and manipulated
uniformly.
struct pjsip_uri{
pjsip_uri_vptr *vptr;};
Code 8 Generic URI Declaration

The pjsip_uri_vptr specifies “virtual” function table, which members will bedefined by each type of URI. Application is discouraged from calling thesefunction pointers directly; instead it is recommended to use the URI API because
they are more readable (and it saves some typings too).
struct pjsip_uri_vptr{
const pj_str_t* (*p_get_scheme)
pjsip_uri*(*p_get_uri)
int(*p_print)

pj_status_t(*p_compare)pjsip_uri *(*p_clone)( const pjsip_uri *uri);( pjsip_uri *uri);( pjsip_uri_context_e context,
const pjsip_uri *uri,
char *buf, pj_size_t size);( pjsip_uri_context_e context,
const pjsip_uri *uri1, const pjsip_uri *uri2);( pj_pool_t *pool, const pjsip_uri *uri);};
Code 9 URI Virtual Function Table

The URI functions below can be applied for all types of URI objects. These
functions normally are implemented as inline functions which call thecorresponding function pointer in virtual function table of the URI.
const pj_str_t* pjsip_uri_get_scheme( const pjsip_uri *uri );Get the URI scheme string (e.g. “sip”, “sips”, “tel”, etc.).

pjsip_uri* pjsip_uri_get_uri( pjsip_uri *uri );Get the URI object. Normally all URI objects will return itself except nameaddress which will return the URI inside the name address object.

pj_status_t pjsip_uri_cmp( pjsip_uri_context_e context,
const pjsip_uri *uri1,
const pjsip_uri *uri2);

Compare uri1 and uri2 according to the specified context. Parameterswhich are not allowed to appear in the specified context will be ignored in
the comparison. It will return PJ_SUCCESS is both URIs are equal.
int pjsip_uri_print(

pjsip_uri_context_e context,
const pjsip_uri *uri,
char *buffer,pj_size_t max_size);

Print uri to the specified buffer according to the specified context.
Parameters which are not allowed to appear in the specified context will
not be included in the printing.
Page 24PJSIP Developer’s Guide

pjsip_uri* pjsip_uri_clone( pj_pool_t *pool, const pjsip_uri *uri );Create a deep clone of uri using the specified pool.

3.1.4 SIP and SIPS URIThe structure pjsip_sip_uri represents SIP and SIPS URI scheme. It is declaredin <pjsip/sip_uri.h>.
struct pjsip_sip_uri{
pjsip_uri_vptr *vptr;
pj_str_tuser;
pj_str_t
passwd;pj_str_t
host;
int
port;
pj_str_t
user_param;
pj_str_t
method_param;
pj_str_ttransport_param;
int
ttl_param;
int
lr_param;
pj_str_t
maddr_param;
pjsip_paramother_param;
pjsip_param
header_param;};// Pointer to virtual function table.
// Optional user part.
// Optional password part.
// Host part, always exists.
// Optional port number, or zero.
// Optional user parameter// Optional method parameter.
// Optional transport parameter.
// Optional TTL param, or -1.
// Optional loose routing param, or 0// Optional maddr param// Other parameters as list.
// Optional header parameters as list.

Code 10 SIP URI Declaration

The following functions are specific to SIP/SIPS URI objects. In addition to thesefunctions, application can also use the base URI functions described in previous
section to manipulate SIP and SIPS URI too.
pjsip_sip_uri* pjsip_sip_uri_create( pj_pool_t *pool, pj_bool_t secure );Create a new SIP URL using the specified pool. If the secure flag is set tonon-zero, then SIPS URL will be created. This function will set vptr
member of the URL to SIP or SIPS vptr and set all other members to blankvalue.

void pjsip_sip_uri_init( pjsip_sip_uri *url, pj_bool_t secure );Initialize a SIP URL structure.
void pjsip_sip_uri_assign( pj_pool_t *pool,
pjsip_sip_uri *url,
const pjsip_sip_uri *rhs );Perform deep copy of rhs to url.

3.1.5 Tel URI
The structure pjsip_tel_uri represents tel: URL. It is declared in<pjsip/sip_tel_uri.h>.

struct pjsip_tel_uri{
pjsip_uri_vptr *vptr;
pj_str_t
number;// Pointer to virtual function table.
// Global or local phone number

Page 25PJSIP Developer’s Guide
pj_str_t
pj_str_t
pj_str_t
pjsip_paramcontext;
ext_param;
isub_param;
other_param;// Phone context (for local number).
// Extension param.
// ISDN sub-address param.
// Other parameters.

};
Code 11 TEL URI Declaration

The functions below are specific to TEL URI. In addition to these functions,application can also use the base URI functions described in previous section for
TEL URI too.
pjsip_tel_uri* pjsip_tel_uri_create( pj_pool_t *pool );Create a new tel: URI.
int pjsip_tel_nb_cmp( const pj_str_t *nb1, const pj_str_t *nb2 );This utility function compares two telephone numbers for equality,
according to rules specified in RFC 3966 (about tel: URI). It recognizes
global and local numbers, and it ignores visual separators during thecomparison.

3.1.6 Name Address
A name address (pjsip_name_addr) does not really define a new type of URI, butrather encapsulates existing URI (e.g. SIP URI) and adds display name.
struct pjsip_name_addr{
pjsip_uri_vptr *vptr;
pj_str_t
display;
pjsip_uri*uri;};// Pointer to virtual function table.
// Display name.
// The URI.

Code 12 Name Address Declaration

The following functions are specific to name address URI object. In addition tothese functions, application can also use the base URI functions described before
for name address object too.
pjsip_name_addr* pjsip_name_addr_create( pj_pool_t *pool );Create a new name address. This will set initialize the virtual function table
pointer, set blank display name and set the uri member to NULL.

void pjsip_name_addr_assign(

Copy rhs to name_addr.

pj_pool_t *pool,
pjsip_name_addr *name_addr,
const pjsip_name_addr *rhs );3.1.7 Sample URI Manipulation Program#include <pjlib.h>#include <pjsip_core.h>#include <stdlib.h>// exit()static pj_caching_pool cp;

Page 26PJSIP Developer’s Guide
static void my_error_exit(const char *title, pj_status_t errcode){char errbuf[80];pjsip_strerror(errcode, errbuf, sizeof(errbuf));
PJ_LOG(3,(“main”, “%s: %s”, title, errbuf));exit(1);}static void my_init_pjlib(void){
pj_status_t status;// Init PJLIB
status = pj_init();if (status != PJ_SUCCESS) my_error_exit(“pj_init() error”, status);// Init caching pool factory.
pj_caching_pool_init( &cp, &pj_pool_factory_default_policy, 0);}
static void my_print_uri( const char *title, pjsip_uri *uri ){char buf[80];int len;len = pjsip_uri_print( PJSIP_URI_IN_OTHER, uri, buf, sizeof(buf)-1);
if (len < 0)
my_error_exit(“Not enough buffer to print URI”, -1);
buf[len] = ‘\0’;
PJ_LOG(3, (“main”, “%s: %s”, title, buf));}
int main(){pj_pool_t *pool;
pjsip_name_addr *name_addr;
pjsip_sip_uri *sip_uri;// Init PJLIB
my_init_pjlib();// Create pool to allocate memory
pool = pj_pool_create(&cp.factory, “mypool”, 4000, 4000, NULL);
if (!pool) my_error_exit(“Unable to create pool”, PJ_ENOMEM);// Create and initialize a SIP URI instance
sip_uri = pjsip_sip_uri_create(pool, PJ_FALSE);
sip_uri->user = pj_str(“alice”);
sip_uri->host = pj_str(“sip.example.com”);
my_print_uri(“The SIP URI is”, (pjsip_uri*)sip_uri);// Create a name address to put the SIP URI
name_addr = pjsip_name_addr_create(pool);
name_addr->uri = (pjsip_uri*) sip_uri;
name_addr->display = “Alice Cooper”;
my_print_uri(“The name address is”, (pjsip_uri*)name_addr);// Done}Code 13 Sample URI Manipulation Program

3.2 SIP Methods
3.2.1 SIP Method Representation (pjsip_method)
The SIP method representation in PJSIP is also extensible; it can support new
methods without needing to recompile the library.
Page 27PJSIP Developer’s Guide

struct pjsip_method{
pjsip_method_e id;
pj_str_t
name;};// Method ID, from pjsip_method_e.
// Method name, which will always contain the method string.

Code 14 SIP Method Declaration

PJSIP core library declares only methods that are specified in core SIP standard(RFC 3261). For these core methods, the id field of pjsip_method will contain theappropriate value from the following enumeration:enum pjsip_method_e{
PJSIP_INVITE_METHOD,PJSIP_CANCEL_METHOD,PJSIP_ACK_METHOD,PJSIP_BYE_METHOD,PJSIP_REGISTER_METHOD,PJSIP_OPTIONS_METHOD,PJSIP_OTHER_METHOD,};
Code 15 SIP Method ID

For methods not specified in the enumeration, the id field of pjsip_method willcontain PJSIP_OTHER_METHOD value. In this case, application must inspect the namefield of pjsip_method to know the actual method.

3.2.2 SIP Method API
The following functions can be used to manipulate PJSIP’s SIP method objects.
void pjsip_method_init(

pjsip_method *method, pj_pool_t *pool,const pj_str_t *method_name );Initialize method from string. This will initialize the id of the method field

to the correct value.

void pjsip_method_init_np( pjsip_method *method,
pj_str_t *method_name );Initialize method from method_name string without duplicating the string(np stands for no pool). The id field will be initialize accordingly.
void pjsip_method_set( pjsip_method *method,
pjsip_method_id_e method_id );Initialize method from the method ID enumeration. The name field will be
initialized accordingly.
void pjsip_method_copy(

pj_pool_t *pool,
pjsip_method *method,
const pjsip_method *rhs );Copy rhs to method.
int pjsip_method_cmp(

const pjsip_method *method1,
const pjsip_method *method2 );Compare method1 to method2 for equality. This function returns zero if
both methods are equal, and (-1) or (+1) if method1 is less or greaterthan method2 respectively.
Page 28PJSIP Developer’s Guide

3.3 Header Fields
All header fields in PJSIP share common header properties such as header type,name, short name, and virtual function table. Because of this, all header fields
can be treated uniformly by the stack.

3.3.1 Header “Class Diagram”
The following diagram shows the snippet of PJSIP header “class diagram”. There
are more headers than the ones shown in the diagram; PJSIP library implements
ALL headers that are specified in the core SIP specification (RFC 3261). Other
headers will be implemented in the corresponding PJSIP extension module.

pjsip_hdr
Attributes:
pjsip_hdr *next, *prev,
pjsip_hdr_e type;
pj_str_t name, sname
Operations:pjsip_hdr *pjsip_hdr_clone(pool, hdr);
pjsip_hdr *pjsip_hdr_shallow_clone(pool, hdr);
int pjsip_hdr_print_on(hdr, buf, maxlen);pjsip_via_hdr

pjsip_fromto_hdr

Attributes:
transport, sent_by, ttl_param,
rport_param, maddr_param,
recvd_param, branch_param,
other_param, comment
Operations:pjsip_via_hdr *pjsip_via_hdr_create(pool);pjsip_generic_int_hdr

Attributes:
uri, tag, other_param

Attributes:
ivalueOperations:Operations:pjsip_from_hdr

pjsip_max_forwards_hdr

pjsip_generic_string_hdr

Attributes:

Attributes:

Attributes:
hvalueOperations:pjsip_from_hdr *pjsip_from_hdr_create(pool);

Operations:pjsip_max_fowards_hdr *pjsip_max_forwards_hdr_create(pool);

Operations:pjsip_to_hdr
pjsip_generic_array_hdr
Attributes:
hvalueOperations:pjsip_accept_hdr, pjsip_allow_hdr,
pjsip_require_hdr,
pjsip_supported_hdr,
pjsip_unsupported_hdr, ...

pjsip_expires_hdr

Attributes:

Attributes:

Operations:pjsip_to_hdr *pjsip_to_hdr_create(pool);

Operations:pjsip_expires_hdr *pjsip_expires_hdr_create(pool);pjsip_accept_encoding_hdr,
pjsip_accept_lang_hdr,
pjsip_alert_info_hdr,
pjsip_auth_info_hdr,
pjsip_call_info_hdr,
pjsip_content_disposition_hdr,
pjsip_content_encoding_hdr, ...

pjsip_min_expires_hdr,
pjsip_retry_after_hdr,

Figure 10 Header “Class Diagram”

As seen in the “class diagram”, each of the specific header normaly only provide
one function that is specific for that particular header, i.e. function to create theinstance of the header.

3.3.2 Header Structure
To make sure that header fields contain common header properties and those
properties are in the correct and same memory layout, the header declarationmust call PJSIP_DECL_HDR_MEMBER macro as the first member field of the header,
specifying the header name as argument to the macro.
#define PJSIP_DECL_HDR_MEMBER(hdr)/** List members. */PJ_DECL_LIST_MEMBER(hdr);\\\

Page 29PJSIP Developer’s Guide/** Header type */\pjsip_hdr_e type;\/** Header name. */\pj_str_t name;\/** Header short name version. */ \pj_str_t sname;\/** Virtual function table. */\pjsip_hdr_vptr *vptr
Code 16 Generic Header Declaration

PJSIP defines pjsip_hdr structure, which contains common properties shared by
all header fields. Because of this, all header fields can be typecasted to pjsip_hdr
so that they can be manipulated uniformly.
struct pjsip_hdr{
PJSIP_DECL_HDR_MEMBER(struct pjsip_hdr);};
Code 17 Generic Header Declaration

3.3.3 Common Header Functions
The pjsip_hdr_vptr specifies “virtual” function table, which implementation isprovided by each header types. The table contains pointer to functions as follows:
struct pjsip_hdr_vptr{
pjsip_hdr *(*clone)( pj_pool_t *pool, const pjsip_hdr *hdr );pjsip_hdr *(*shallow_clone)( pj_pool_t *pool, const pjsip_hdr *hdr );int(*print_on)( pjsip_hdr *hdr, char *buf, pj_size_t len );};Code 18 Header Virtual Function Table

Although application can freely call the function pointers in the pjsip_hdr_vptr
directly, it is recommended that it uses the following header APIs instead,because they will make the program more readable.
pjsip_hdr *pjsip_hdr_clone(

pj_pool_t *pool,const pjsip_hdr *hdr );Perform deep clone of hdr header.
pjsip_hdr *pjsip_hdr_shallow_clone(

pj_pool_t *pool,const pjsip_hdr *hdr );Perform shallow clone of hdr header. A shallow cloning creates a new
exact copy of the specified header field, however most of its value will still
point to the values in the original header. Normally shallow clone is just a
simple memcpy() from the original header to a new header, therefore it’s
expected that this operation is faster than deep cloning.
However, care must be taken when shallow cloning headers. It must be
understood that the new header still shares common pointers to thevalues in the old header. Therefore, when the pool containing the original
header is destroyed, the new header will be rendered invalid too although
the new header was shallow-cloned using different memory pool. Or if
some values in the original header was modified, then the corresponding
values in the shallow-cloned header will be modified too.
Despite of this, shallow cloning is used widely in the library. For example,
a dialog has some headers which values are more or less persistent during
Page 30PJSIP Developer’s Guide
the session (e.g. From, To, Call-Id, Route, and Contact). When creating arequest, the dialog can just shallow-clone these headers (instead of
performing full cloning) and put them in the request message.
int pjsip_hdr_print_on( pjsip_hdr *hdr,
char *buf,
pj_size_t max_size);

Print the specified header to a buffer (e.g. before transmission). Thisfunction returns the number of bytes printed to the buffer, or –1 when thebuffer is overflow.

3.3.4 Supported Header Fields
The “standard” PJSIP header fields are declared in <pjsip/sip_msg.h>. Other
header fields may be declared in header files that implement specificfunctionalities or SIP extensions (e.g. headers used by SIMPLE extension, etc.).
Each header field normally only defines one specific API for manipulating them,i.e. the function to create that specific header field. Other APIs are exported
through the virtual function table.
The APIs to create individual header fields are by convention named after theheader field name and followed by _create() suffix. For example, call function
pjsip_via_hdr_create() to create an instance of pjsip_via_hdr header.
Please refer to <pjsip/sip_msg.h> for complete list of header fields defined by
PJSIP core.

3.3.5 Header Array Elements
A lot of SIP headers (e.g. Require, Contact, Via, etc.) can be grouped together asa single header field and separated by comma. Example:
Contact: <sip:alice@sip.example.com>;q=1.0, <tel:+442081234567>;q=0.5
Via: SIP/2.0/UDP proxy1.example.com;branch=z9hG4bK87asdks7, SIP/2.0/UDP
proxy2.example.com;branch=z9hG4bK77asjd
NOTE: PJSIP does not support representing array elements in a header for complex header types(e.g. Contact, Via, Route, Record-Route). Simple string array however is supported (e.g. Require,Supported, etc.).

When the parser encounters such arrays in headers, it will split the array into
individual headers while maintaining their order of appearance. So for theexample above, the parser will modify the message to:Contact: <sip:alice@sip.example.com>;q=1.0
Contact: <tel:+442081234567>;q=0.5
Via: SIP/2.0/UDP proxy1.example.com;branch=z9hG4bK87asdks7
Via: SIP/2.0/UDP proxy2.example.com;branch=z9hG4bK77asjd

The SIP standard specifies that there should NOT be any difference in theprocessing of message containing either kind of header representations. So webelieve that the removal of header array support will not limit the functionality of
PJSIP at all.
The reason why we impose this limitation is because based on our experience,
the removal of header array support greatly simplifies processing of headers. If
header array were supported, then application not only must inspect all headers,it also has to inspect some headers to see if they contain arrays. With thePage 31PJSIP Developer’s Guide
removal of array support, application only has to inspect the main header list in
the message.

3.4 Message Body (pjsip_msg_body)
SIP message body is represented with pjsip_msg_body structure in PJSIP. This
structure is declared in <pjsip/sip_msg.h>.
struct pjsip_msg_body{/** MIME content type.
* For incoming messages, the parser will fill in this member with the* content type found in Content-Type header.
** For outgoing messages, application must fill in this member with* appropriate value, because the stack will generate Content-Type header* based on the value specified here.
*/
pjsip_media_type content_type;/** Pointer to buffer which holds the message body data.
* For incoming messages, the parser will fill in this member with the* pointer to the body string.
** When sending outgoing message, this member doesn't need to point to the* actual message body string. It can be assigned with arbitrary pointer,* because the value will only need to be understood by the print_body()* function. The stack itself will not try to interpret this value, but* instead will always call the print_body() whenever it needs to get the* actual body string.
*/
void *data;/** The length of the data.
* For incoming messages, the parser will fill in this member with the* actual length of message body.
** When sending outgoing message, again just like the "data" member, the* "len" member doesn't need to point to the actual length of the body* string.
*/
unsigned len;/** Pointer to function to print this message body.
* Application must set a proper function here when sending outgoing* message.
** @param msg_body
This structure itself.
* @param buf
The buffer.
* @param size
The buffer size.
** @returnThe length of the string printed, or -1 if there is*
not enough space in the buffer to print the whole*message body.
*/int (*print_body)( struct pjsip_msg_body *msg_body,char *buf, pj_size_t size );/** Pointer to function to clone the data in this message body.
*/
void* (*clone_data)( pj_pool_t *pool, const void *data, unsigned len );};Code 19 Message Body Declaration

The following are APIs that are provided for manipulating SIP message objects.
Page 32PJSIP Developer’s Guide

pj_status_t pjsip_msg_body_clone( pj_pool_t *pool,
pjsip_msg_body *dst_body,
const pjsip_msg_body *src_body);

Clone the message body in src_body to the dst_body. This will duplicate
the contents of the message body using the clone_data member of thesource message body.

3.5 Message (pjsip_msg)
Both request and response message in PJSIP are represented with pjsip_msg
structure in <pjsip/sip_msg.h>. The following code snippet shows the declarationof pjsip_mg along with other supporting structures.
enum pjsip_msg_type_e{
PJSIP_REQUEST_MSG,
PJSIP_RESPONSE_MSG,};
struct pjsip_request_line{
pjsip_method method;
pjsip_uri*uri;};struct pjsip_status_line
{
int
code;
pj_str_t
reason;};// Indicates request message.
// Indicates response message.

// Method for this request line.
// URI for this request line.

// Status code.
// Reason string.

struct pjsip_msg{/** Message type (ie request or response). */pjsip_msg_type_e type;/** The first line of the message can be either request line for request* messages, or status line for response messages. It is represented here
* as a union.
*/
union
{
/** Request Line. */struct pjsip_request_line
req;/** Status Line. */struct pjsip_status_line

status;} line;/** List of message headers. */pjsip_hdr hdr;/** Pointer to message body, or NULL if no message body is attached to* this mesage.
*/
pjsip_msg_body *body;};
Code 20 SIP Message Declaration

The following are APIs that are provided for manipulating SIP message objects.
pjsip_msg* pjsip_msg_create(

pj_pool_t *pool,

Page 33PJSIP Developer’s Guide
pjsip_msg_type_e type);

Create a request or response message according to the type.
pjsip_hdr* pjsip_msg_find_hdr(

pjsip_msg *msg,
pjsip_hdr_e hdr_type,pjsip_hdr *start);

Find header in the msg which has the specified type, searching from (andincluding) the specified start position in the header list. If start is NULL,
then the function searches from the first header in the message. Returns
NULL when no more header at and after the specified position can befound.
pjsip_hdr* pjsip_msg_find_hdr_by_name(pjsip_msg *msg,
const pj_str_t *name,pjsip_hdr *start);

Find header in the msg which has the specified name, searching both longand short name version of the header from the specified start position in
the header list. If start is NULL, then the function searches from the firstheader in the message. Returns NULL when no more headers at and after
the specified position can be found.
void pjsip_msg_add_hdr(

pjsip_msg *msg,
pjsip_hdr *hdr);

Add hdr as the last header in the msg.
void pjsip_msg_insert_first_hdr( pjsip_msg *msg,
pjsip_hdr *hdr);

Add hdr as the first header in the msg.
pj_ssize_t pjsip_msg_print(

pjsip_msg *msg,
char *buf,
pj_size_t size );Print the whole contents of msg to the specified buffer. The function
returns the number of bytes written, or –1 if buffer is overflow.

3.6 SIP Status Codes
SIP status codes that are defined by the core SIP specification (RFC 3261) isrepresented by pjsip_status_code enumeration in <pjsip/sip_msg.h>. In
addition, the default reason text can be obtained by calling
pjsip_get_status_text() function.
The following snippet shows the declaration of the status code in PJSIP.

enum pjsip_status_code{
PJSIP_SC_TRYING = 100,PJSIP_SC_RINGING = 180,PJSIP_SC_CALL_BEING_FORWARDED = 181,PJSIP_SC_QUEUED = 182,
PJSIP_SC_PROGRESS = 183,
PJSIP_SC_OK = 200,PJSIP_SC_MULTIPLE_CHOICES = 300,PJSIP_SC_MOVED_PERMANENTLY = 301,
PJSIP_SC_MOVED_TEMPORARILY = 302,PJSIP_SC_USE_PROXY = 305,
PJSIP_SC_ALTERNATIVE_SERVICE = 380,PJSIP_SC_BAD_REQUEST = 400,PJSIP_SC_UNAUTHORIZED = 401,

Page 34PJSIP Developer’s Guide
PJSIP_SC_PAYMENT_REQUIRED = 402,
PJSIP_SC_FORBIDDEN = 403,
PJSIP_SC_NOT_FOUND = 404,PJSIP_SC_METHOD_NOT_ALLOWED = 405,PJSIP_SC_NOT_ACCEPTABLE = 406,
PJSIP_SC_PROXY_AUTHENTICATION_REQUIRED = 407,PJSIP_SC_REQUEST_TIMEOUT = 408,
PJSIP_SC_GONE = 410,
PJSIP_SC_REQUEST_ENTITY_TOO_LARGE = 413,
PJSIP_SC_REQUEST_URI_TOO_LONG = 414,PJSIP_SC_UNSUPPORTED_MEDIA_TYPE = 415,
PJSIP_SC_UNSUPPORTED_URI_SCHEME = 416,
PJSIP_SC_BAD_EXTENSION = 420,
PJSIP_SC_EXTENSION_REQUIRED = 421,
PJSIP_SC_INTERVAL_TOO_BRIEF = 423,
PJSIP_SC_TEMPORARILY_UNAVAILABLE = 480,
PJSIP_SC_CALL_TSX_DOES_NOT_EXIST = 481,
PJSIP_SC_LOOP_DETECTED = 482,
PJSIP_SC_TOO_MANY_HOPS = 483,
PJSIP_SC_ADDRESS_INCOMPLETE = 484,PJSIP_AC_AMBIGUOUS = 485,
PJSIP_SC_BUSY_HERE = 486,
PJSIP_SC_REQUEST_TERMINATED = 487,PJSIP_SC_NOT_ACCEPTABLE_HERE = 488,
PJSIP_SC_REQUEST_PENDING = 491,
PJSIP_SC_UNDECIPHERABLE = 493,
PJSIP_SC_INTERNAL_SERVER_ERROR = 500,
PJSIP_SC_NOT_IMPLEMENTED = 501,PJSIP_SC_BAD_GATEWAY = 502,
PJSIP_SC_SERVICE_UNAVAILABLE = 503,
PJSIP_SC_SERVER_TIMEOUT = 504,PJSIP_SC_VERSION_NOT_SUPPORTED = 505,PJSIP_SC_MESSAGE_TOO_LARGE = 513,
PJSIP_SC_BUSY_EVERYWHERE = 600,PJSIP_SC_DECLINE = 603,
PJSIP_SC_DOES_NOT_EXIST_ANYWHERE = 604,PJSIP_SC_NOT_ACCEPTABLE_ANYWHERE = 606,
PJSIP_SC_TSX_TIMEOUT = 701,
PJSIP_SC_TSX_RESOLVE_ERROR = 702,
PJSIP_SC_TSX_TRANSPORT_ERROR = 703,};/* Get the default status text for the status code. */const pj_str_t* pjsip_get_status_text(int status_code);
Code 21 SIP Status Code Constants

PJSIP also defines new status class (i.e. 7xx) for fatal error status during
message processing (e.g. transport error, DNS error, etc). This class however isonly used internally; it will not go out on the wire.

3.7 Non-Standard Parameter Elements
In PJSIP, known or “standard” parameters (e.g. URI parameters, header fieldparameters) will normally be represented as individual attributes/fields of thecorresponding structure. Parameters that are not “standard” will be put in a list ofparameters, with each parameter is represented as pjsip_param structure. Nonstandard parameter normally is declared as other_param field in the owning
structure.

Page 35PJSIP Developer’s Guide

3.7.1 Data Structure Representation (pjsip_param)This structure describes each individual parameter in a list.
struct pjsip_param{
PJ_DECL_LIST_MEMBER(struct pjsip_param);
pj_str_t
name;pj_str_t
value;};// Generic list member.
// Param/header name.
// Param/header value.

Code 22 Non-Standard Parameter Declaration

For example of its usage, please see other_param and header_param fields in the
declaration of pjsip_sip_uri (see previous section 3.1.4 “SIP and SIPS URI”) or
other_param field in the declaration of pjsip_tel_uri (see previous section 3.1.5“Tel URI”).

3.7.2 Non-Standard Parameter Manipulation
Some functions are provided to assist manipulation of non-standard parametersin parameter list.
pjsip_param* pjsip_param_find(const pjsip_param *param_list,
const pj_str_t *name );This function will perform case-insensitive search for the specified
parameter name.
void pjsip_param_clone( pj_pool_t *pool,
pjsip_param *dst_list,
const pjsip_param *src_list);

Perform full/deep clone of parameter list.
void pjsip_param_shallow_clone(

pj_pool_t *pool,
pjsip_param *dst_list,
const pjsip_param *src_list);

Perform shallow clone of parameter list.

pj_ssize_t pjsip_param_print_on( const pjsip_param *param_list,
char *buf,
pj_size_t max_size,
const pj_cis_t *pname_unres,
const pj_cis_t *pvalue_unres,int sep);

Print the parameter list to the specified buffer. The pname_unres andpvalue_unres is the specification of which characters are allowed to appear
unescaped in pname and pvalue respectively; any characters outside these
specifications will be escaped by the function. The argument sep specifies
separator character to be used between parameters (normally it issemicolon (‘;’) character for normal parameter or comma (‘,’) when theparameter list is a header parameter).

3.8 Escapement Rules
PJSIP provides automatic un-escapement during parsing and escapement during
printing ONLY for the following message elements:
Page 36PJSIP Developer’s Guideo

all types of URI and their elements are automatically escaped and unescaped according to their individual escapement rule.

oparameters appearing in all message elements (e.g. in URL, in header
fields, etc.) are automatically escaped and un-escaped.

Other message elements will be passed un-interpreted by the stack.

Page 37PJSIP Developer’s Guide

Chapter 4:Parser
4.1 Features
Some features of the PJSIP parser:oIt’s a top-down, handwritten parser. It uses PJLIB’s scanner, which ispretty fast and reduces the complexity of the parser, which make theparser readable.

oAs said above, it’s pretty fast. On a single P4/2.6GHz machine, it’s able toparse more than 68K of typical 800 bytes SIP message or 860K of 80
bytes URLs in one second. Note that your mileage may vary, and different
PJSIP versions may have different performance.

oIt’s reentrant, which will make it scalable on machine with multiprocessors.

oIt’s extensible. Modules can plug-in new types of header or URI to theparser.

The parser features almost a lot of tricks thinkable to achieve the highest
performance, such as:oit uses zero-copy for all message elements; i.e., when an element, e.g. apvalue, is parsed, the parser does not copy the pvalue contents to theappropriate field in the message; instead it will just put the pointer andlength to the appropriate field in the message. This is only possible
because PJSIP uses pj_str_t all the way throughout the library, which does
not require strings to be NULL terminated.

o

it uses PJLIB’s memory pool (pj_pool_t) for memory allocation for themessage structures, which provides multiple times speed-up overtraditional malloc() function.

oit uses zero synchronization. The parser is completely reentrant so that no
synchronization function is required.

o

it uses PJLIB’s try/catch exception framework, which not only greatly
simplifies the parser and make it readable, but also saves tedious error
checking in the parsers. With an exception framework, only one exception
handler needs to be installed at the top-most function of the parser.

One feature that PJSIP parser doesn’t implement is lazy parsing, which a lot of
people probably brag about its usability. In early stage of the design, we decided
not to implement lazy parsing, because of the following reasons:oit complicates things, especially error handling. With lazy parsing, basicallyall parts of the program must be prepared to handle error condition whenparsing failed at later stage when application needs to access a particularmessage element.

oat the end of the day, we believe that PJSIP parser is very fast anywaythat it doesn’t need lazy parsing. Although having said that, there will besome switches that can be turned-on in PJSIP parser to ignore parsing ofsome headers for some type of applications (e.g. proxies, which only
needs to inspect few header types).

Page 38PJSIP Developer’s Guide

4.2 Functions
The main PJSIP parser is declared in <pjsip/sip_parser.h> and defined in<pjsip/sip_parser.c>. Other parts of the library may provide other parsing
functionalities and extend the parser (e.g. <pjsip/sip_tel_uri.c> provides function
to parse TEL URI and registers this function to the main parser).

4.2.1 Message Parsing
pj_status_t pjsip_find_msg(

const char *buf,
pj_size_t size,
pj_bool_t is_datagram,
pj_size_t *msg_size);

Checks that an incoming packet in buf contains a valid SIP message. Whena valid SIP message is detected, the size of the message will be indicatedin msg_size. If is_datagram is specified, this function will always return
PJ_SUCCESS.
Note that the function expects the buffer in buf to be NULL terminated.
pjsip_msg* pjsip_parse_msg(

pj_pool_t *pool,char *buf, pj_size_t size,
pjsip_parser_err_report *err_list);

Parse a buffer in buf into SIP message. The parser will return the message
if at least SIP request/status line has been successfully parsed. Any error
encountered during parsing will be reported in err_list if this parameter is
not NULL.
Note that the function expects the buffer in buf to be NULL terminated.
pjsip_msg* pjsip_parse_rdata( char *buf, pj_size_t size,
pjsip_rx_data *rdata );Parse a buffer in buf into SIP message. The parser will return the message
if at least SIP request/status line has been successfully parsed. In
addition, this function updates various pointer to headers in msg_info
portion of the rdata.
Note that the function expects the buffer in buf to be NULL terminated.

4.2.2 URI Parsing
pjsip_uri* pjsip_parse_uri(

pj_pool_t *pool,char *buf, pj_size_t size,
unsigned option);

Parse a buffer in buf into SIP URI. If PJSIP_PARSE_URI_AS_NAMEADDR is
specified in the option, the function will always “wrap” the URI as nameaddress. If PJSIP_PARSE_URI_IN_FROM_TO_HDR is specified in theoption, the function will not parse the parameters after the URI if the URI
is not enclosed in brackets (because they will be treated as header
parameters, not URI parameters).
This function is able to parse any types of URI that are recognized by thelibrary, and return the correct instance of the URI depending on thescheme.
Note that the function expects the buffer in buf to be NULL terminated.

4.2.3 Header Parsing
void* pjsip_parse_hdr( pj_pool_t *pool, const pj_str_t *hname,char *line, pj_size_t size,
int *parsed_len);Page 39PJSIP Developer’s Guide
Parse the content of a header in line (i.e. part of header after the colon
character) according to the header type hname. It returns the appropriate
instance of the header.
Note that the function expects the buffer in buf to be NULL terminated.
pj_status_t pjsip_parse_headers( pj_pool_t *pool,char *input, pj_size_t size,
pj_list *hdr_list );Parse multiple headers found in input buffer and put the results in hdr_list.
The function expects the header to be separated either by a newline (as in
SIP message) or ampersand character (as in URI). The separator is
optional for the last header.
Note that the function expects the buffer in buf to be NULL terminated.

4.3 Extending Parser
The parser can be extended by registering function pointers to parse new types ofheaders or new types of URI.
typedef pjsip_hdr* (pjsip_parse_hdr_func)(pjsip_parse_ctx *context);
pj_status_t pjsip_register_hdr_parser( const char *hname,const char *hshortname,pjsip_parse_hdr_func *fptr);

Register new function to parse new type of SIP message header.
typedef void* (pjsip_parse_uri_func)(pj_scanner *scanner, pj_pool_t *pool,
pj_bool_t parse_params);
pj_status_t pjsip_register_uri_parser( char *scheme,
pjsip_parse_uri_func *func);

Register new function to parse new type of SIP URI scheme.

Page 40PJSIP Developer’s Guide

Chapter 5:Message Buffers
5.1 Receive Data Buffer
A SIP message received by PJSIP will be passed around to different PJSIP
software components as pjsip_rx_data instead of a plain message. This structure
contains all information describing the received message.
Receive and transmit data buffers are declared in <pjsip/sip_transport.h>.

5.1.1 Receive Data Buffer Structure
struct pjsip_rx_data{// This part contains static info about the buffer.
struct{pj_pool_t*pool;// Pool owned by this buffer
pjsip_transport*transport;// The transport that received the msg.
pjsip_rx_data_op_key
op_key;// Ioqueue’s operation key} tp_info;// This part contains information about the packet
struct{pj_time_val
timestamp;char
packet[PJSIP_MAX_PKT_LEN];
pj_uint32_t
zero;
int
len;
pj_sockaddr
addr;
int
addr_len;} pkt_info;// Packet arrival time// The packet buffer// Zero padding.
// Packet length// Source address// Address length.

// This part describes the message and message elements after parsing.
struct{char*msg_buf;// Pointer to start of msg in the buf.
intlen;// Message length.
pjsip_msg*msg;// The parsed message.
// Shortcut to important headers:
pj_str_t
pjsip_from_hdr
pjsip_to_hdr
pjsip_via_hdr
pjsip_cseq_hdr
pjsip_max_forwards_hdr
pjsip_route_hdr
pjsip_rr_hdr
pjsip_ctype_hdr
pjsip_clen_hdr
pjsip_require_hdr
pjsip_parser_err_report} msg_info;

call_id;// Call-ID string.
*from;// From header.
*to;// To header.
*via;// First Via header.
*cseq;// CSeq header.
*max_fwd;// Max-Forwards header.
*route;// First Route header.
*record_route; // First Record-Route header.
*ctype;// Content-Type header.
*clen;// Content-Length header.
*require;// The first Require header.
parse_err;// List of parser errors.

// This part is updated after the rx_data reaches endpoint.
struct{pj_str_t
key;// Transaction key.
void
*mod_data[PJSIP_MAX_MODULE]; // Module specific data.
} endpt_info;};
Code 23 Receive Data Buffer Declaration

Page 41PJSIP Developer’s Guide

5.2 Transmit Data Buffer (pjsip_tx_data)
When PJSIP application wants to send outgoing message, it must create atransmit data buffer. The transmit data buffer provides memory pool from which
all message fields pertaining for the message must be allocated from, a reference
counter, lock protection, and other information that are needed by the transportlayer to process the message.

struct pjsip_tx_data{/** This is for transmission queue; it's managed by transports. */PJ_DECL_LIST_MEMBER(struct pjsip_tx_data);/** Memory pool for this buffer. */pj_pool_t*pool;/** A name to identify this buffer. */char
obj_name[PJ_MAX_OBJ_NAME];/** Time of the rx request; set by pjsip_endpt_create_response(). */pj_time_val
rx_timestamp;/** The transport manager for this buffer. */pjsip_tpmgr*mgr;/** Ioqueue asynchronous operation key. */pjsip_tx_data_op_key
op_key;/** Lock object. */pj_lock_t*lock;/** The message in this buffer. */pjsip_msg*msg;/** Contigous buffer containing the packet. */pjsip_buffer
buf;/** Reference counter. */pj_atomic_t*ref_cnt;/** Being processed by transport? */int
is_pending;/** Transport manager internal. */void*token;void(*cb)(void*, pjsip_tx_data*, pj_ssize_t);/** Transport info, only valid during on_tx_request() and on_tx_response() */struct {pjsip_transport*transport;/**< Transport being used.
*/
pj_sockaddr
dst_addr;/**< Destination address.
*/
int
dst_addr_len; /**< Length of address.
*/char
dst_name[16]; /**< Destination address.
*/int
dst_port;/**< Destination port.
*/} tp_info;};
Code 24 Transmit Data Buffer Declaration

Page 42PJSIP Developer’s Guide

Chapter 6:Transport Layer
Transports are used to send/receive messages across the network. PJSIP
transport framework is extensible, which means application can register its own
means to transport messages.

6.1 Transport Layer Design
6.1.1 “Class Diagram”
The following diagram shows the relationship between instances in the transportlayer.
pjsip_endpoint
Attributes:
Operations:pj_status_t pjsip_endpt_acquire_transport(...);

pjsip_tpmgr
Attributes:
Operations:pj_status_t pjsip_tpmgr_create(...);
pj_status_t pjsip_tpmgr_destroy(...);
pj_status_t pjsip_tpmgr_register_tpfactory(...);
pj_status_t pjsip_tpmgr_unregister_tpfactory(...);
pj_status_t pjsip_transport_register(...);
pj_status_t pjsip_transport_unregister(...);
pj_status_t pjsip_tpmgr_receive_packet(...);
pj_status_t pjsip_tpmgr_acquire_transport();pjsip_transport
Attributes:pool, ref_cnt, lock, type,
local_addr, remote_addr,
public_addr

pjsip_tpfactory
Attributes:
Operations:pj_status_t create_transport(...);

Operations:pj_status_t pjsip_transport_send(...);
pj_status_t pjsip_transport_add_ref(...);
pj_status_t pjsip_transport_dec_ref(...);

Figure 11 Transport Layer "Class Diagram"

6.1.2 Transport Manager
The transport manager (pjsip_tpmgr) manages all transport objects and factories.
It provides the following functionalities:•

Manages transports life-time by using transport’s reference counter andidle timer.

•

Manages transport factories.

•

Receives packet from transport, parse the packet, and deliver the SIP
message to endpoint.
Page 43PJSIP Developer’s Guide•

Find matching transport to send SIP message to particular destination
based on the transport type and remote address.

•

Create new transports dynamically when no existing transport is available
to send SIP message to a new destination.

There is only one transport manager per endpoint. Transport manager is normallynot visible to applications; applications should use the functions provided byendpoint.

6.1.3 Transport Factory
The transport factory (pjsip_tpfactory) is used to create dynamic connection toremote endpoint. An example of this type of connection is TCP transport, where
one TCP transport needs to be created for each destination.
When transport manager detects that it need to create new transport to the newdestination, it finds the transport factory with matching specification (i.e.
transport type) and ask the factory to create the connection.
A transport factory object is declared as follows.

6.1.4 Transport
Transport object is represented with pjsip_transport structure. Each instance of
this structure normally represents one socket handle (e.g. UDP, TCP), although
the transport layer supports non-socket transport as well.
General Transport Operations
From the framework’s point of view, transport object is an active object. The
framework doesn’t have mechanism to poll the transport objects; instead, thetransport objects must find their own way to receive packets from network anddeliver the packets to transport manager for further processing.
The recommended way to achieve this is to register the transport’s socket handle
to endpoint’s I/O queue (pj_ioqueue_t), so that when the endpoint polls the I/Oqueue, packets from the network will be received by the transport object.
Once a packet has been received by the transport object, it must deliver the
packet to transport manager by calling pjsip_tpmgr_receive_packet() function, sothat it can be parsed and distributed to the rest of the stack. The transport object
must initialize both tp_info and pkt_info member of receive data buffer(pjsip_rx_data).
Each transport object has a pointer to function to send messages to the network(i.e. send_msg() attribute of the transport object). Application (or the stack) sends
messages to the network by calling pjsip_transport_send() function, which
eventually will reach the transport object, and send_msg() will be called. The
sending of packet may complete asynchronously; if so, transport must return
PJ_EPENDING status in send_msg() and call the callback that is specified inargument when the message has been sent to destination.
Transport Object Declaration
The following code shows the declaration of a transport object.

Page 44PJSIP Developer’s Guide
struct pjsip_transport{char

obj_name[PJ_MAX_OBJ_NAME];// Name.

pj_pool_t
pj_atomic_t
pj_lock_t
int*pool;*ref_cnt;*lock;
tracing;// Pool used by transport.
// Reference counter.
// Lock object.
// Tracing enabled?

pjsip_transport_type_echar
unsigned

type;// Transport type.
type_name[8]; // Type name.
flag;// See #pjsip_transport_flags_e

pj_sockaddr
pjsip_host_port
pj_sockaddr

local_addr;
addr_name;rem_addr;// Bound address.
// Published name (e.g. STUN address).
// Remote addr (zero for UDP)

pjsip_endpoint
pjsip_tpmgr
pj_timer_entry*endpt;*tpmgr;idle_timer;// Endpoint instance.
// Transport manager.
// Timer when ref cnt is zero.

/* Function to be called by transport manager to send SIP messages. */pj_status_t(*send_msg)( pjsip_transport *transport,
pjsip_tx_data *tdata,
const pj_sockaddr_in *rem_addr,
void *token,
void (*callback)( pjsip_transport*,
void *token,
pj_ssize_t sent));/* Called to destroy this transport. */pj_status_t(*destroy)( pjsip_transport *transport );/* Application may extend this structure. */};Code 25 Transport Object Declaration

Transport Management
Transports are registered to transport manager by pjsip_transport_register().
Before this function is called, all members of the transport structure must be
initialized.
Transport’s life-time is managed automatically by transport manager. Each timereference counter of the transport reaches zero, an idle timer will start. When theidle timer expires and the reference counter is still zero, transport manager will
destroy the transport by calling pjsip_transport_unregister(). This function
unregisters the transport from transport manager’s hash table and eventuallydestroy the transport.
Some transports need to exist forever even when nobody is using the transport(for example, UDP transport, which is a singleton instance). To prevent thattransport from being deleted, it must set the reference counter to one initially, sothat reference counter will never reach zero.
Transport Error Handling
Any errors in the transport (such as failure to send packet or connection reset)
are handled by transport user. Transport object doesn’t need to handle such
errors, other than reporting the error in the function’s return value. In particular,
it must not try to reconnect a failed/closed connection.

Page 45PJSIP Developer’s Guide

6.2 Using Transports
6.2.1 Function Reference
pj_status_t
pjsip_endpt_acquire_transport(

pjsip_endpoint *endpt,
pjsip_transport_type_e t_type,
const pj_sockaddr_t *remote_addr,
int addrlen,
pjsip_transport **p_transport);

Acquire transport of type t_type to be used to send message todestination remote_addr. Note that if transport is successfully acquired,
the transport’s reference counter will be incremented.
pj_status_t pjsip_transport_add_ref( pjsip_transport *transport );Add reference counter of the transport. This function will prevent thetransport from being destoyed, and it also cancels idle timer if such timer
is active.

pj_status_t pjsip_transport_dec_ref( pjsip_transport *transport );Decrement reference counter of the transport. When transport’s reference
counter reaches zero, an idle timer will be started and transport will be
destroyed by transport manager when the timer has elapsed andreference counter is still zero.
pj_status_t pjsip_transport_send( pjsip_transport *transport,
pjsip_tx_data *tdata,
const pj_sockaddr_t *remote_addr,
int addrlen,
void *token,
void (*cb)(void *token,
pjsip_tx_data *tdata,
pj_ssize_t bytes_sent));

Send the message in tdata to remote_addr using transport transport. If
the function completes immediately and data has been sent, the function
returns PJ_SUCCESS. If the function completes immediately with error, anon-zero error code will be returned. In both cases, the callback will not
be called.
If the function can not complete immediately (e.g. when the underlying
socket buffer is full), the function will return PJ_EPENDING, and caller will
be notified about the completion via the callback cb. If the pending send
operation completes with error, the error code will be indicated as
negative value of the error code, in the bytes_sent argument of thecallback (to get the error code, use “pj_status_t status = -bytes_sent”).
This function sends the message as is; it doesn’t perform any validation to
the message. The Via header is also not modified by this function either.

6.3 Extending Transports
PJSIP transport can be extended to use custom defined transports. Theoretically
any types of transport, not limited to TCP/IP, can be plugged into the transportmanager’s framework. Please see the header file <pjsip/sip_transport.h> andalso sip_transport_udp.[hc] for more details.

6.4 Initializing Transports
PJSIP doesn’t start any transports by default (not even the built-in transports); it
is the responsibility of the application to initialize and start any transports that it
wishes to use.
Page 46PJSIP Developer’s Guide
Below are the initialization functions for the built-in UDP and TCP transports.

6.4.1 UDP Transport Initialization
PJSIP provides two choices to initialize and start UDP transports. These functions
are declared in <pjsip/sip_transport_udp.h>.
pj_status_t pjsip_udp_transport_start(

pjsip_endpoint *endpt,
const pj_sockaddr_in *local_addr,
const pj_sockaddr_in *pub_addr,
unsigned async_cnt,
pjsip_transport **p_transport );Create, initialize, register, and start a new UDP transport. The UDP socket
will be bound to local_addr. If the endpoint is located behind firewall/NATor other port-forwarding devices, then pub_addr can be used as theaddress that is advertised for this transport; otherwise pub_addr shouldbe the same as local_addr. The argument async_cnt specifies how many
simultaneous operations are allowed for this transport, and for maximum
performance, the value should be equal to the number of processors in thenode.
If transport is successfully started, the function returns PJ_SUCCESS andthe transport is returned in p_transport argument, should the application
want to use the transport immediately. Application doesn’t need toregister the transport to transport manager; this function has done thatwhen the function returns successfully.
Upon error, the function returns a non-zero error code.
pj_status_t pjsip_udp_transport_attach( pjsip_endpoint *endpt,
pj_sock_t sock,const pj_sockaddr_in *pub_addr,
unsigned async_cnt,
pjsip_transport **p_transport);

Use this function to create, initialize, register, and start a new UDP
transport when the UDP socket is already available. This is useful for
example when application has just resolved the public address of thesocket with STUN, and instead of closing the socket and re-create it, theapplication can just reuse the same socket for the SIP transport.

6.4.2 TCP Transport Initialization
TODO.

6.4.3 TLS Transport Initialization
TODO.

6.4.4 SCTP Transport Initialization
TODO.

Page 47PJSIP Developer’s Guide

Chapter 7:Sending Messages
The core operations in SIP applications are of course sending and receiving
message. Receiving incoming message is handled in on_rx_request() andon_rx_response() callback of each module, as described in 1 General Design.
This chapter will describe about the basic way to send outgoing messages, i.e.
without using transaction or dialog.
The next chapter Transactions describes about how to handle request statefully(both incoming and outgoing requests).

7.1 Sending Messages Overview
7.1.1 Creating Messages
PJSIP provides rich API to create request or response messages. There arevarious ways to create messages:•

for response messages, the easiest way is to use
pjsip_endpt_create_response() function.

•

for request messages, you can use pjsip_endpt_create_request(),•proxies can create request or response messages based on incoming
message to be forwarded by calling pjsip_endpt_create_request_fwd() andpjsip_endpt_create_response_fwd().

•

alternatively you may create request or response messages manually bycreating the transmit buffer with pjsip_endpt_create_tdata(), creating themessage with pjsip_msg_create(), adding header fields to the message
with pjsip_msg_add_hdr() or pjsip_msg_insert_first_hdr(), set themessage body, etc.

•

higher layer module may provide more specific way to create message(e.g. dialog layer). This will be described in the individual module’s
documentation.

pjsip_endpt_create_request_from_hdr(), pjsip_endpt_create_ack(), or
pjsip_endpt_create_cancel().

All message creating API (except the low-level pjsip_endpt_create_tdata()) sets
the reference counter of the transmit buffer (pjsip_tx_data) to one, which meansthat at some point application (or stack) must decrement the reference counter todestroy the transmit buffer.
All message sending API will decrement transmit buffer’s reference counter.
Which means that as long as application doesn’t do anything with the transmit
buffer’s reference counter, the buffer will be destroyed after it is sent.

7.1.2 Sending Messages
The most basic way to send message is to call pjsip_endpt_acquire_transport()
and pjsip_transport_send() functions. For this to work, however, you must know
the destination address (i.e. sockaddr, not just hostname) to send the message.
Since there can be several steps from having the message and getting the exact
socket address (e.g. determining which address to use, performing RFC 3263
lookup, etc.), practically this function is too low-level to be used directly.
Page 48PJSIP Developer’s Guide
The core API to send messages are pjsip_endpt_send_request_stateless() andpjsip_endpt_send_response() functions. These two are very powerfull functions inthe sense that it handles transport layer automatically, and are the basic
building-blocks used by upper layer modules (e.g. transactions).
The pjsip_endpt_send_request_stateless() function are for sending request
messages, and it performs the following procedures:•

Determine which destination to contact based on the Request-URI andparameters in Route headers,•

Resolve the destination server using procedures in RFC 3263 (Locating SIP
Servers),•

Select and establish transport to be used to contact the server,•

Modify sent-by in Via header to reflect current transport being used,•

Send the message using current transport,•

Fail-over to next server/transport if server can not be contacted using
current transport

The pjsip_endpt_send_response() function are for sending response messages,
and it performs the following procedures:•

Follow the procedures in Section 18.2.2 of RFC 3261 to select whichtransport to use and which address to send response to,•Additionally conform to RFC 3581 about rport parameter,•

Send the response using the selected transport,•

Fail-over to next address when response failed to be sent using theselected transport, resolving the server according to RFC 3263 whennecessary.

Since messages may be sent asynchronously (e.g. after TCP has beenconnected), both functions provides callback to notify application about the statusof the transmission. This callback also inform the application that fail-over will
happen (or not), and application has the chance to override the behavior.

7.2 Function Reference
7.2.1 Sending Response
Base Functions
pj_status_t pjsip_endpt_create_response(

pjsip_endpoint *endpt,
pjsip_rx_data *rdata,
int st_code,
const char *st_text,
pjsip_tx_data **tdata);

Create a standard response message for the request in rdata with status
code st_code and status text st_text. If st_text is NULL, default status text
will be used.
pj_status_t pjsip_get_response_addr( pj_pool_t *pool,
pjsip_rx_data *rdata,
pjsip_response_addr *res_addr);

Determine which address (and transport) to use to send response
message based on the received request in rdata. This function follows the
specification in section 18.2.2 of RFC 3261 and RFC 3581 for calculating
the destination address and transport. The address and transport
information about destination to send the response will be returned in
res_addr argument.
Page 49PJSIP Developer’s Guide
pj_status_t pjsip_endpt_send_response(

pjsip_endpoint *endpt,
pjsip_response_addr *res_addr,
pjsip_tx_data *response,
void *token,
void (*cb)( pjsip_send_state*,
pj_ssize_t sent,
pj_bool_t *cont));

Send response in response statelessly, using the destination address andtransport in res_addr. The response address information (res_addr) is
normally initialized by calling pjsip_get_response_addr().
The definite status of the transmission will be reported when callback cb iscalled, along with other information (including the original token) which
will be stored in pjsip_send_state. If message was successfully sent, thesent argument of the callback will be a non-zero positive number. If there
is failure, the sent argument will be negative value, and the error code is
the positive part of the value (i.e. status=-sent). If cont argument value is
non-zero, it means the function will try other addresses to send themessage (i.e. fail-over). Application can choose not to try other addresses
by setting this argument to zero upon exiting the callback.
If application doesn’t specify callback cb, then the function will not failover to next address in case the selected transport fails to deliver themessage.
The function returns PJ_SUCCESS if the message is valid, or a non-zeroerror code. However, even when it returns PJ_SUCCESS, there is no
guarantee that the response has been successfully sent.
Note that callback MAY be called before the function returns.
Composite Functions
pj_status_t pjsip_endpt_respond_stateless( pjsip_endpoint *endpt,
pjsip_rx_data *rdata,
int st_code,
const char *st_text,
const pjsip_hdr *hdr_list,
const pjsip_msg_body *body);

This function creates and sends a response to an incoming request. In
addition, caller may specify message body and additional headers to be
put in the response message in the hdr_list and body argument. If there isno additional header or body, to be sent, the arguments should be NULL.
The function returns PJ_SUCCESS if response has been successfully
created and send to transport layer, or a non-zero error code. However,even when it returns PJ_SUCCESS, there is no guarantee that the
response has been successfully sent.

7.2.2 Sending Request
pj_status_t pjsip_endpt_create_tdata(

pjsip_endpoint *endpt,
pjsip_tx_data **tdata);

Create a new, blank transmit data.
pj_status_t pjsip_endpt_create_request( pjsip_endpoint *endpt,
const pjsip_method *method,
const pj_str_t *target,
const pj_str_t *from,const pj_str_t *to,const pj_str_t *contact,
const pj_str_t *call_id,
int cseq,
const pj_str_t *text,

Page 50PJSIP Developer’s Guide
pjsip_tx_data **p_tdata);

Create a new request message of the specified method for the specified
target URI, from, to, and contact. The call_id and cseq are optional. If text
is specified, then a “text/plain” body is added. The request message has
initial reference counter set to 1, and is then returned to sender in
p_tdata.
pj_status_t pjsip_endpt_create_request_from_hdr(pjsip_endpoint *endpt,
const pjsip_method *method,
const pjsip_uri *target,
const pjsip_from_hdr *from,const pjsip_to_hdr *to,const pjsip_contact_hdr *ch,const pjsip_cid_hdr *call_id,
int cseq,
const pj_str_t *text,
pjsip_tx_data **p_tdata);

Create a new request header by shallow-cloning the headers from thespecified arguments.

pj_status_t pjsip_endpt_create_ack(

pjsip_endpoint *endpt,
const pjsip_tx_data *tdata,
const pjsip_rx_data *rdata,
pjsip_tx_data **ack );Create ACK request message from the original request in tdata based on
the received response in rdata. This function is normally used bytransaction when it receives non-successful response to INVITE. An ACK
request for successful INVITE response is normally generated by dialog’s
create request function.
pj_status_t pjsip_endpt_create_cancel(

pjsip_endpoint *endpt,
const pjsip_tx_data *tdata,
pjsip_tx_data **p_tdata);

Create CANCEL request based on the previously sent request in tdata. This
will create a new transmit data buffer in p_tdata.
pj_status_t pjsip_endpt_send_request_stateless(pjsip_endpoint *endpt,
pjsip_tx_data *tdata,
void *token,
void (*cb)(pjsip_send_state*,
pj_ssize_t sent,
pj_bool_t *cont));

Send request in tdata statelessly. The function will take care of which
destination and transport to use based on the information in the message,
taking care of URI in the request line and Route header. There are several
steps will be performed by this function:-

determine which host to contact based on Request-URI and Routeheaders (pjsip_get_request_addr()),-

resolve the destination host (pjsip_endpt_resolve()),-

acquire transport to be used (pjsip_endpt_acquire_transport()).

-

send the message (pjsip_transport_send()).

-

fail-over to next address/transport if necessary.

The definite status of the transmission will be reported when callback cb iscalled, along with other information (including the original token) which
will be stored in pjsip_send_state. If message was successfully sent, thesent argument of the callback will be a non-zero positive number. If there
is failure, the sent argument will be negative value, and the error code is
the positive part of the value (i.e. status=-sent). If cont argument value is
non-zero, it means the function will try other addresses to send themessage (i.e. fail-over). Application can choose not to try other addresses
by setting this argument to zero upon exiting the callback.
Page 51PJSIP Developer’s Guide
If application doesn’t specify callback cb, then the function will not failover to next address in case the selected transport fails to deliver themessage.
The function returns PJ_SUCCESS if the message is valid, or a non-zeroerror code. However, even when it returns PJ_SUCCESS, there is no
guarantee that the request has been successfully sent.
Note that callback MAY be called before the function returns.

7.2.3 Stateless Proxy Forwarding
Proxy may choose to forward a request statelessly. When doing so however, it
must strictly follow guidelines in section 16.11 Stateless Proxy of RFC 3261.
pj_status_t pjsip_endpt_create_request_fwd( pjsip_endpoint *endpt,
pjsip_rx_data *rdata,
const pjsip_uri *uri,
const pj_str_t *branch,
unsigned options,pjsip_tx_data **tdata);

Create new request message to be forwarded upstream to new destination
URI uri. The new request is a full/deep clone of the request received inrdata, unless if other copy mechanism is specified in the options. The
branch parameter, if not NULL, will be used as the branch-param in the
Via header. If it is NULL, then a unique branch parameter will be used.

pj_status_t pjsip_endpt_create_response_fwd(

pjsip_endpoint *endpt,
pjsip_rx_data *rdata,
unsigned options,pjsip_tx_data **tdata);

Create new response message to be forwarded downstream by the proxyfrom the response message found in rdata. Note that this function
practically will clone the response as is, i.e. without checking the validityof the response or removing top most Via header. This function will
perform full/deep clone of the response, unless other copy mechanism isused in the options.
pj_str_t pjsip_calculate_branch_id(

pjsip_rx_data *rdata );Create a globally unique branch parameter based on the information in theincoming request message. This function guarantees that subsequent
retransmissions of the same request will generate the same branch id.
This function can also be used in the loop detection process. If the same
request arrives back in the proxy with the same URL, it will calculate into
the same branch id.
Note that the returned string was allocated from rdata’s pool.

Page 52PJSIP Developer’s Guide

7.3 Examples
7.3.1 Sending Responses
Sending Account Not Found Response Statelessly
static pj_bool_t on_rx_request(pjsip_rx_data *rdata ){pjsip_account *acc;
pj_status_t status;// Find account referred to in the request.
acc = ...
// Respond statelessly if account can not be found.
if (!acc) {status = pjsip_endpt_respond_stateless( endpt, rdata, 404, NULL /*Not Found*/,
NULL, NULL, NULL);
return PJ_TRUE;}// Process the account...
return PJ_TRUE;}
Code 26 Sample: Stateless Response

Handling Authentication Failures Statelessly
Another (longer) way to send stateless response:
static pj_bool_t on_rx_request( pjsip_rx_data *rdata ){pjsip_account *acc;// Lookup acc.
acc = ...;// Check authorization and handle failure statelessly
if (!pjsip_auth_authorize( acc, rdata->msg )) {pjsip_proxy_authenticate_hdr *auth_hdr;
status = pjsip_endpt_create_response(

endpt, rdata,
407, NULL /* Proxy Auth Required */,&tdata);// Add Proxy-Authenticate header.
status = pjsip_auth_create_challenge( tdata->pool, ..., &auth_hdr);
pjsip_msg_add_hdr( &tdata->msg, auth_hdr );// Send response statelessly
status = pjsip_endpt_send_response( endpt, tdata, NULL);
return PJ_TRUE;}// Authorization success. Proceed to next stage..
...
return PJ_TRUE;}
Code 27 Sample: Stateless Response

Page 53PJSIP Developer’s Guide
Stateless Redirection
static pj_bool_t on_rx_request( pjsip_rx_data *rdata ){pjsip_account *acc;
pj_status_t status;// Find the account referred to in the request.
acc = ...
if (!acc) {status = pjsip_endpt_respond_stateless( endpt, rdata, 404, NULL /*Not Found*/,
NULL, NULL, NULL );return PJ_TRUE;}//// Send 301/Redirect message, specifying the Contact details in the response//
status = pjsip_endpt_respond_stateless(endpt, rdata,
301, NULL /*Moved Temporarily*/,&acc->contact_list, NULL, NULL);
return PJ_TRUE;}
Code 28 Stateless Redirection

7.3.2 Sending Requests
Sending Request Statelessly
void my_send_request(){
pj_status_t status;
pjsip_tx_data *tdata;// Create the request.
// Actually the function takes pj_str_t* argument instead of char*.
status = pjsip_endpt_create_request( endpt,// endpoint
method,// method“sip:bob@example.com”,// target URI“sip:alice@thishost.com”, // From:“sip:bob@example.com”,// To:“sip:alice@thishost.com”, // Contact:
NULL,// Call-Id
0,// CSeq#
NULL,// body&tdata );// output// You may modify the message before sending it.
...
// Send the request statelessly (for whatever reason...)status = pjsip_endpt_send_request_stateless( endpt, tdata, NULL);}
Code 29 Sending Stateless Request

Page 54PJSIP Developer’s Guide

7.3.3 Stateless Forwarding
Stateless Forwarding
static pj_bool_t on_rx_request( pjsip_rx_data *rdata ){pjsip_account *acc;
pjsip_tx_data *tdata;
pj_str_t branch_id;
pj_status_t status;// Find the account specified in the request.
acc = ...
// Generate unique branch ID for the request.
branch_id = pjsip_calculate_branch_id( rdata );// Create new request to be forwarded to new destination.
status = pjsip_endpt_create_request_fwd( endpt, rdata, dest, &branch_id, 0,&tdata );// The new request is good to send, but you may modify it if necessary// (e.g. adding/replacing/removing headers, etc.)...
// Send the request downstream
status = pjsip_endpt_send_request_stateless( endpt, tdata, NULL );return PJ_TRUE;}//// Forward response upstream//
static pj_bool_t on_rx_response(pjsip_rx_data *rdata){
pjsip_tx_data *tdata;
pj_status_t status;// Check that topmost Via is ours, strip top-most Via, etc.
...
// Create new tdata for the response.
status = pjsip_endpt_create_response_fwd( endpt, rdata, 0, &tdata );// Send the response upstream
status = pjsip_endpt_send_response( endpt, tdata, NULL);
return PJ_TRUE;}
Code 30 Stateless Forwarding

Page 55PJSIP Developer’s Guide

Chapter 8:Transactions
8.1 Design
8.1.1 Introduction
Transaction in PJSIP is represented with pjsip_transaction structure in header
file <pjsip/sip_transaction.h>. Transaction’s lifetime normally follows these steps:oCreated by pjsip_tsx_endpt_create_uac() / pjsip_tsx_create_uas().

oAfter initializing UAS transaction, application needs to call
pjsip_tsx_recv_msg() to pass in the initial request message so thattransaction state can move from NULL to TRYING. Subsequent request
retransmissions will be absorbed by the transaction.

oWhen application wants to send request or response message using thetransaction, it will call pjsip_tsx_send_msg().

oTransaction state automatically changes as messages are passed to it(either by endpoint for incoming message or by transaction user foroutgoing message) or timer elapses, and transaction user is notified via
on_tsx_state() callback.

oTransaction will be automatically destroyed once it the state has reached
PJSIP_TSX_STATE_TERMINATED. Application can also forcely terminate
the transaction by calling pjsip_tsx_terminate().

8.1.2 Timers and Retransmissions
Transaction only has two types of timers: retransmission timer and timeout timer.
The value of both timer types are automatically set by the transaction according
to the transaction type (UAS or UAC), transport (reliable or non-reliable), andmethod (INVITE or non-INVITE).
Application can change the interval value of timers only on a global basis(perhaps even only during compilation).
A transaction handles both incoming and outgoing retransmissions. Incoming
retransmissions are silently absorbed and ignored by transaction; there is no
notification about incoming retransmissions emitted by transaction. Outgoingmessages are automatically retransmitted by transactions where necessary;
again there will be no notification emitted by transaction on outgoingretransmissions.

8.1.3 INVITE Final Response and ACK Request
Failed INVITE Request
The transaction behaves exactly according to RFC 3261 for failed INVITE request.

Client transaction: when a client INVITE transaction receives 300-699 final
response to INVITE, it will automatically emit ACK request to the response. The
transaction then wait for timer D interval before it is terminated, during which
any incoming 300-699 response retransmissions will be automatically answeredwith ACK request.
Page 56PJSIP Developer’s Guide
Server transaction: when a server INVITE transaction is asked to transmit 300699 final response, it will transmit the response and keep retransmitting the
response until an ACK request is received or timer H interval has elapsed. During
this interval, when ACK request is received, transaction will move to Confirmed
state and will be destroyed after timer I interval has elapsed. When timer H
elapsed without receving a valid ACK request, transaction will be destroyed.
Successfull INVITE Request
Client transaction: when a client INVITE transaction receives 2xx final response
to INVITE, it will destroy itself automatically after it passes the response to its
transaction user (can be a dialog or application). Subsequent incoming 2xx
response retransmission will be passed directly to dialog or application.
In any case, application MUST send ACK request manually upon receiving 2xx
final response to INVITE.
Server transaction: when a server INVITE transaction is asked to transmit 2xx
final response, it will transmit the response and keep retransmitting the
response until ACK is received or transaction is terminated by application withpjsip_tsx_terminate().
For simplicity in the implementation, a typical UAS dialog normally will let thetransaction handle the retransmission of the 2xx INVITE response. But proxyapplication MUST destroy the UAS transaction as soon as it receives and sends
the 2xx response, to allow the 2xx retransmission to be handled by end-to-end
user agents.
This behavior of INVITE server transaction is different than RFC 3261 for successfull INVITE
request, which says that INVITE server transaction MUST be destroyed once 2xx response is sent.
The PJSIP transaction behavior allows more simplicity in the dialog implementation, while
maintaining the flexibility to be compliant with RFC 3261 for proxy applications.

The default behavior of the INVITE server transaction can be overridden by
setting transaction->handle_200resp to zero (default is non-zero) after
transaction is created. In this case, UAS INVITE transaction will be destroyed assoon as 2xx response to INVITE is sent.

8.1.4 Incoming ACK Request
When the server INVITE transaction was completed with non-successful final
response, the ACK request will be absorbed by transaction; transaction user
WILL NOT be notified about the incoming ACK request.
When the server INVITE transaction was completed with 2xx final response, thefirst ACK request will be notified to transaction user. Subsequent receipt of ACK
retransmission WILL NOT be notified to transaction user.

8.1.5 Server Resolution and Transports
Transaction uses the core API pjsip_endpt_send_request_stateless() andpjsip_endpt_send_response() to send outgoing messages. These functions provide
server resolution and transport establishment to send the message, and fail overto alternate transport when a failure is detected. The transaction uses the
callbacks provided by these functions to monitor the progress of the transmission
and track the transport being used.
The transaction adds reference counter to the transport it currently uses.
Page 57PJSIP Developer’s Guide

TCP Connection Closure
A TCP connection closure will not automatically cause the transaction to fail. In
fact, the transaction will not even detect the failure until it tries to send amessage. When it does, it follows the normal procedure to send the message
using alternative transport.

8.1.6 Via Header
Branch Parameter
UAC transaction automatically generates a unique branch parameter in the Via
header when one is not present. If branch parameter is already present, thetransaction will used it as its key, complying to rules set by both RFC 3261 andRFC 2543.
Via Sent-By
Via sent-by is always put by pjsip_endpt_send_request_stateless() andpjsip_endpt_send_response().

8.2 Reference
8.2.1 Base Functions
pj_status_t pjsip_tsx_layer_init_module(

pjsip_endpoint *endpt );Initialize and register the transaction layer module to the specified
endpoint.

pjsip_module *pjsip_tsx_layer_instance(void);

Get the instance of transaction layer module.

pj_status_t pjsip_tsx_layer_destroy(void);

Shutdown the transaction layer module and unregister it from theendpoint where it currently registered.
pj_status_t pjsip_tsx_create_uac (pjsip_module *tsx_user,
pjsip_tx_data *tdata,
pjsip_transaction **p_tsx );Create a new UAC transaction for the outgoing request in tdata with thetransaction user set to tsx_user. The transaction is automatically initialized
and registered to the transaction table. Note that after calling thisfunction, applications normally would call pjsip_tsx_send_msg() to actuallysend the request.
pj_status_t pjsip_tsx_create_uas (pjsip_module *tsx_user,
pjsip_rx_data *rdata,
pjsip_transaction **p_tsx );Create a new UAS transaction for the incoming request in rdata with thetransaction user set to tsx_user. The transaction is automatically initialized
and registered to endpoint’s transaction table.
void pjsip_tsx_recv_msg(

pjsip_transaction *tsx,
pjsip_rx_data *rdata );Application MUST call this function after UAS transaction is created,passing the initial request message, so that transaction state can movefrom NULL to TRYING. The transaction user’s on_tsx_state() is called.
pj_status_t pjsip_tsx_send_msg(

pjsip_transaction *tsx,
pjsip_tx_data *tdata );Page 58PJSIP Developer’s Guide
Send message through the transaction. If tdata is NULL, the last message
or the message that was specified during creation will be retransmitted.
When the function returns PJ_SUCCESS, the tdata reference counter will
be decremented.
pj_status_t pjsip_tsx_create_key( pj_pool_t *pool,
pj_str_t *out_key,
pjsip_role_e role,
const pjsip_method *method,
const pjsip_rx_data *rdata);

Create a transaction key from an incoming request or response message,
taking into consideration whether the message is compliant with RFC 3261
or RFC 2543. The key can be used to find the transaction in endpoint’s
transaction table.
The function returns the key in out_key parameter. The role parameter isused to find either UAC or UAS transaction, and the method parametercontains the method of the message.
pjsip_transaction* pjsip_tsx_layer_find_tsx(

const pj_str_t *key,
pj_bool_t lock );Find transaction with the specified key in transaction table. If lockparameter is non-zero, this function will also lock the transaction before
returning the transaction, so that other threads are not able to delete thetransaction. Caller then is responsible to unlock the transaction when it’sfinished using the transaction, using pj_mutex_unlock().
pj_status_t pjsip_tsx_terminate( pjsip_transaction *tsx,
int st_code );Forcefully terminate the transaction tsx with the specified status code
st_code. Normally application doesn’t need to call this function, sincetransactions will terminate and destroy themselves according to their statemachine.
This function is used for example when 200/OK response to INVITE issent/received and the UA layer wants to handle retransmission of 200/OK
response manually.
The transaction will emit transaction state changed event (state changed
to PJSIP_TSX_STATE_TERMINATED), then it will be unregistered anddestroyed immediately by this function.
pjsip_transaction* pjsip_rdata_get_tsx (pjsip_rx_data *rdata );Get the transaction object in an incoming message.

8.2.2 Composite Functions
pj_status_t pjsip_endpt_respond( pjsip_endpoint *endpt,
pjsip_module *tsx_user,
pjsip_rx_data *rdata,
int st_code,
const char *st_text,
const pjsip_hdr *hdr_list,
const pjsip_msg_body *body,
pjsip_transaction **p_tsx)

Send respond by creating a new UAS transaction for the incoming request.
pj_status_t pjsip_endpt_send_request(pjsip_endpoint *endpt,
pjsip_tx_data *tdata,
int timeout,void *token,
void (*cb)(void*, pjsip_event*))

Page 59PJSIP Developer’s Guide
Send the request by using an UAC transaction, and optionally request
callback to be called when the transaction completes.

8.3 Sending Statefull Responses
8.3.1 Usage Examples
Sending Response Statefully (The Hard Way)static pj_bool_t on_rx_request( pjsip_rx_data *rdata ){pj_status_t status;
pjsip_transaction *tsx;
pjsip_tx_data *tdata;// Create and initialize transaction.
status = pjsip_tsx_create_uas ( endpt, NULL, rdata, &tsx );// Pass in the initial request message.
pjsip_tsx_recv_msg(tsx, rdata);// Create response
status = pjsip_endpt_create_response( endpt, rdata, 200, NULL /*OK*/, &tdata);// The response message is good to send, but you may modify it before// sending the response.
...
// Send response with the specified transaction.
pjsip_tsx_send_msg( tsx, tdata );return PJ_TRUE;}
Code 31 Sending Statefull Response

Sending Response Statefully (The Easy Way)static pj_bool_t on_rx_request( pjsip_rx_data *rdata ){pj_status_t status;// Respond to the request statefully
status = pjsip_endpt_respond( endpt, NULL, rdata,
200, NULL /* OK */, NULL, NULL, NULL);
return PJ_TRUE;}
Code 32 Sending Statefull Response

8.4 Sending Statefull Request
Two ways to send statefull request:•

use pjsip_endpt_send_request()•

using transaction manually.

Page 60PJSIP Developer’s Guide

8.4.1 Usage Examples
Sending Request with Transaction
extern pjsip_module app_module;
void my_send_request(){
pj_status_t status;
pjsip_tx_data *tdata;
pjsip_transaction *tsx;// Create the request.
status = pjsip_endpt_create_request(

endpt, ..., &tdata );// You may modify the message before sending it.
...
// Create transaction.
status = pjsip_endpt_create_uac_tsx( endpt, &app_module, tdata, &tsx );// Send the request.
status = pjsip_tsx_send_msg( tsx, tdata /*or NULL*/);}static void on_tsx_state( pjsip_transaction *tsx, pjsip_event *event ){pj_assert(event->type == PJSIP_EVENT_TSX_STATE);
PJ_LOG(3,(“app”, “Transaction %s: state changed to %s”,
tsx->obj_name, pjsip_tsx_state_str(tsx->state)));}Code 33 Sending Request Statefully

8.5 Statefull Proxy Forwarding
8.5.1 Usage Examples
Statefull Forwarding
The following code shows a sample statefull forwarding proxy. The code creates
UAS and UAC transaction (one for each side), forward the request to the UAC
side, and forward all responses from the UAC side to UAS side. It also handles
transaction timeout or other error in the UAC side and sends response to the UAS
side.
One that it doesn’t handle is receiving CANCEL request in the UAC side.
// This is our proxy module.
extern pjsip_module proxy_module;
static pj_bool_t on_rx_request( pjsip_rx_data *rdata ){pjsip_account *acc;
pjsip_uri *dest;
pjsip_transaction *uas_tsx, *uac_tsx;
pjsip_tx_data *tdata;
pj_status_t status;// Find the account specified in the request.
acc = ...
// Respond statelessly with 404/Not Found if account can not be found.
if (!acc) {...
return PJ_TRUE;}

Page 61PJSIP Developer’s Guide// Set destination URI from account’s contact list that has highest priority.
dest = ...
// Create UAS transaction
status = pjsip_endpt_create_uas_tsx( endpt, &proxy_module, rdata, &uas_tsx);// Copy request to new tdata with new target URI.
status = pjsip_endpt_create_request_fwd( endpt, rdata, dest, NULL, 0, &tdata);// Create new UAC transaction.
status = pjsip_endpt_create_uac_tsx( endpt, &proxy_module, tdata, &uac_tsx );// “Associate” UAS and UAC transaction
uac_tsx->mod_data[proxy_module.id] = (void*)uas_tsx;
uas_tsx->mod_data[proxy_module.id] = (void*)uac_tsx;// Forward message to UAC sidestatus = pjsip_tsx_send_msg( uac_tsx, tdata );return PJ_TRUE;}
static pj_bool_t on_rx_response( pjsip_rx_data *rdata ){pjsip_transaction *tsx;
pjsip_tx_data *tdata;
pj_status_t status;// Get transaction object in rdata.
tsx = pjsip_rdata_get_tsx( rdata );// Check that this transaction was created by the proxyif (tsx->tsx_user == &proxy_module) {// Get the peer UAC transaction.
pjsip_transaction *uas_tsx;
uas_tsx = (pjsip_transaction*) tsx->mod_data[proxy_module.id];// Check top-most Via is ours...
// Strip top-most Via// Note that after this code, rdata->msg_info.via is invalid.
pj_list_erase(rdata->msg_info.via);// Code above is equal to:// pjsip_hdr *via = pjsip_msg_find_hdr(rdata->msg, PJSIP_H_VIA);// pj_list_erase(via);// Copy the response msg.
status = pjsip_endpt_create_response_fwd( endpt, rdata, 0, &tdata);// Forward the response upstream.
pjsip_tsx_send_msg( uas_tsx, tdata );return PJ_TRUE;}...
}
Code 34 Statefull Forwarding

Page 62PJSIP Developer’s Guide

Chapter 9:Authentication Framework
PJSIP provides framework for performing both client and server authentication.
The authentication framework supports HTTP digest authentication by default, butother authentication schemes may be added to the framework.
The following diagram illustrates the framework’s “class diagram”.
pjsip_auth_srv

pjsip_auth_srv_sess

pjsip_auth_clt_sess

Attributes:

Attributes:

Attributes:

Operations:int pjsip_auth_srv_init(ser,..);
int pjsip_auth_srv_verify(ser,..);
int pjsip_auth_srv_challenge(ser,..);

Operations:int pjsip_auth_srv_init_sess(ser,..);

Operations:int pjsip_auth_clt_init_sess(sess);
int pjsip_auth_clt_set_credentials();
int pjsip_auth_clt_init_req(...);
int pjsip_auth_clt_reinit_req(,...);

pjsip_acc_lookup
Attributes:
Callbacks:
pj_status_t lookup_cred(realm, acc, &cred);pjsip_cred_info

pjsip_cached_authAttributes:
realm, scheme, username,
data_type, data

Attributes:
realm, is_proxy, qop_value,nc, cnonce, last_chal, cached_hdr

Operations:Operations:Figure 12 Authentication Framework

9.1 Client Authentication Framework
The client authentication framework manages authentication process by client toall downstream servers. It can respond to server’s challenge with the correct
credential (when such credential is supplied), cache the authorization info, andinitialize subsequent requests with the cached authorization info.

9.1.1 Client Authentication Framework Reference
The authentication APIs are declared in <pjsip/sip_auth.h>. Below are thedocumentation reference for authentication data structures and functions.
Data Structure Reference
Structure

pjsip_cred_info

Description
This structure describes the credential to be used toauthenticate against a specific realm. A client canhave multiple credentials to use for the duration of a
dialog or registration; each one of the credential
contains information needed to authenticate against aparticular downstream proxy or server.
For example, client needs one credential toauthenticate against its outbound proxy, and anothercredential to authenticate against the end server.

pjsip_cached_authpjsip_auth_clt_sess

This structure keeps the last challenge received froma particular server. It is needed so that client caninitialize next request with the last challenge.
This structure describes the client authentication
session. Client would normally keep this structure forPage 63PJSIP Developer’s Guide
the duration of a dialog or client registration.
Figure 13 Client Authentication Data Structure

Function Reference
pj_status_t pjsip_auth_clt_init( pjsip_auth_clt_sess *sess,
pj_pool_t *pool, unsigned options);

Initialize client authentication session data structure, and set the session
to use pool for its subsequent memory allocation. The argument options
should be set to zero for this PJSIP version.
pj_status_t pjsip_auth_clt_set_credentials(

pjsip_auth_clt_sess *s,
int cred_cnt,
const pjsip_cred_info cred[]);Set the credentials to be used during the session. This will duplicate thespecified credentials using client authentication’s pool.
pj_status_t pjsip_auth_clt_init_req( pjsip_auth_clt_sess *sess,
pjsip_tx_data *tdata );This function add all relevant authorization headers to a new outgoing
request tdata according to the cached information in the session. The
request line in the request message must be valid before calling thisfunction.

pj_status_t pjsip_auth_clt_reinit_req(

pjsip_auth_clt_session *sess,
pjsip_endpoint *endpt,
const pjsip_rx_data *rdata,
pjsip_tx_data *old_request,
pjsip_tx_data **new_request );Call this function to re-initialize a request upon receiving failed
authentication status (401/407 response). This function will recreate
new_request according to old_request, and add appropriate Authorization
and Proxy-Authorization headers according to the challenges found in
rdata response. In addition, this function also put the relevant informationin the session.
This function will return failure if there is a missing credential for thechallenge. Note that this function may reuse the old request instead ofcreating a fresh one.

9.1.2 Examples
Client Transaction Authentication
The following example illustrates how to initialize outgoing request withauthorization information and how to handle challenge received from the server.
For brevity, error handling is not shown in the example. A real application should
be prepared to handle error situation in all stages.
pjsip_auth_client_session auth_sess;// Initialize client authentication session with some credentials.
void init_auth(pj_pool_t *session_pool){
pjsip_cred_info cred;
pj_status_t status;
cred.realm = pj_str(“sip.example.com”);
cred.scheme = pj_str(“digest”);
cred.username = pj_str(“alice”);
cred.data_type = PJSIP_CRED_DATA_PLAIN_PASSWD;
cred.data = pj_str(“secretpassword”);

Page 64PJSIP Developer’s Guide
status = pjsip_auth_client_init( &auth_sess, session_pool, 0);status = pjsip_auth_set_credentials( &auth_sess, 1, &cred );}// Initialize outgoing request with authorization information and// send the request statefully.
void send_request(pjsip_tx_data *tdata){
pj_status_t status;
status = pjsip_auth_client_init_req( &auth_sess, tdata );status = pjsip_endpt_send_request( endpt, tdata, -1, NULL, &on_complete);}// Callback when the transaction completes.
static void on_complete( void *token, pjsip_event *event ){int code;
pj_assert(event->type == PJSIP_EVENT_TSX_STATE);
code = event->body.tsx_state.tsx->status_code;
if (code == 401 || code == 407) {pj_status_t status;
pjsip_tx_data *new_request;
status = pjsip_auth_client_reinit_req( &auth_sess, endpt,
event->body.tsx_state.src.rdata,tsx->last_tx,&new_request);
if (status == PJ_SUCCESS)
status = pjsip_endpt_send_request( endpt, new_request, -1, NULL,&on_complete);else
PJ_LOG(3,(“app”,”Authentication failed!!!”));}}
Code 35 Client Athorization Example

9.2 Server Authorization Framework
The server authorization framework provides two types of server authorization
mechanisms:osession-less server authorization, which provides general API for
authenticating clients. This API provides global server authorization
mechanism on request-per-request basis, and is normally used for proxyapplication when it doesn’t do call statefull.

oserver authorization session, which provides API for authenticating
requests inside a particular dialog or registration session. One server
authorization session instance needs to be created for each server side
dialog or registration session. A server auth session will have exactly one
credential which is setup initially, and this credential must be used byclient throughout the duration of the dialog/registration session.

The server authorization session currently is not implemented. Only global,
session-less server authorization framework is available.

9.2.1 Server Authorization Reference
Data Types Reference
typedef pj_status_t pjsip_auth_lookup_cred( pj_pool_t *pool,const pj_str_t *realm,

Page 65PJSIP Developer’s Guide
const pj_str_t *acc_name,pjsip_cred_info *cred_info );Type of function to be registered to authorization server to lookup for credential
information for the specified acc_name in the specified realm. When credential
information is successfully retrieved, the function must fill in the cred_info withthe credentials and return PJ_SUCCESS. Otherwise it should return one of thefollowing error code:o

PJSIP_EAUTHACCNOTFOUND: account not found for the specified realm,o

PJSIP_EAUTHACCDISABLED: account was found but disabled,

Functions Reference
pj_status_t pjsip_auth_srv_init( pj_pool_t *pool,
pjsip_auth_srv *auth_srv,
const pj_str_t *realm,
pjsip_auth_lookup_cred *lookup_func,
unsigned options );Initialize server authorization session data structure to serve the specified
realm and to use lookup_func function to look for the credential info. The
argument options is bitmask combination of the following values:o

PJSIP_AUTH_SRV_IS_PROXY: to specify that the server will
authorize clients as a proxy server (instead of as UAS), whichmeans that Proxy-Authenticate will be used instead of WWWAuthenticate.

pj_status_t pjsip_auth_srv_verify(

pjsip_auth_srv *auth_srv,
pjsip_rx_data *rdata,
int *status_code );Request the authorization server framework to verify the authorization
information in the specified request in rdata. If status_code is not NULL, it
will be filled with suitable status for the response (401/407/etc.).
This function will return PJ_SUCCESS if the authorization information
found in the request can be accepted, or the following error whenauthorization failed:o

PJSIP_EAUTHNOAUTH: no authorization header is specified in therequest.

o

PJSIP_EINVALIDAUTHSCHEME: invalid/unsupported authorization
scheme (only digest is supported at present).

o

PJSIP_EAUTHACCNOTFOUND or PJSIP_EAUTHACCDISABLED are
the error codes returned by the lookup function.

o

PJSIP_EAUTHINVALIDDIGEST: invalid digest,oother non-zero values may be returned to indicate system error.

pj_status_t pjsip_auth_srv_challenge(

pjsip_auth_srv *auth_srv,
const pj_str_t *qop,
const pj_str_t *nonce,
const pj_str_t *opaque,pj_bool_t stale,
pjsip_tx_data *tdata);

Add authentication challenge headers to the outgoing response in tdata. If
qop is specified, then it will be put in the challenge. Application may also
specify its customized nonce and opaque for the challenge, or can leave
the value to NULL to make the function fills them in with randomcharacters.

Page 66PJSIP Developer’s Guide

9.3 Extending Authentication Framework
The authentication framework can be extended to support authentication
framework other than HTTP digest (e.g. PGP, etc.).
TODO.

Page 67PJSIP Developer’s Guide

Chapter 10:Basic User Agent Layer (UA)10.1 Basic Dialog Concept
The basic UA dialog provides basic facilities for managing SIP dialogs and dialog
usages, such as basic dialog state, session counter, Call-ID, From, To, andContact headers, sequencing of CSeq in transactions, and route-set.
The basic UA dialog is agnostic/skeptical of what kind of sessions it is being usedto (e.g. INVITE session, SUBSCRIBE/NOTIFY sessions, REFER/NOTIFY sessions,etc.), and it can be used to establish multiple and different types of sessions
simultaneously in a single dialog.
A PJSIP dialog can be considered just as a passive data structure to hold common
dialog attributes. You must not confuse dialog with an INVITE session. An INVITE
session is a session (also commonly known as dialog usage) “inside” a dialog.
There can be other sessions/usages in the same dialog; all of them sharecommon dialog properties (although there can only be one INVITE session perdialog).
For more information about dialog-usage concept, please refer to draft-sparks-sippingdialogusage-01.txt. The document identifies two dialog-usages, i.e. invite usage and subscribe
usage.

PJSIP dialog does not know the state of its sessions. It doesn’t know whether the
INVITE session has been established or disconnected. In fact, PJSIP dialog does
not even know what kind of sessions are there in the dialog. All it cares is how
many active sessions are there in the dialog. The dialog is started with one active
session, and when the session counter reaches zero and the last transaction is
terminated, the dialog will be destroyed.
It will be the responsibility of each dialog usages to increment and decrement the
dialog’s session counter.

10.1.1 Dialog Sessions
Dialog sessions in PJSIP dialog framework is just represented with a reference
counter. This reference counter is incremented and decremented by dialog usage
module everytime it creates/destroys a session in that particular dialog.
Dialog’s sessions are created by dialog usages. In one particular dialog, one
dialog usage can create more than one sessions (except invite usage, which can
only create one invite session in a single dialog).
The exact representation of “session” will be defined by the dialog usage module.
As stated previously, the basic dialog only cares about the number of sessions
currently active in the dialog.

10.1.2 Dialog Usages
Dialog usages are PJSIP modules that are registered to the dialog to receive
dialog’s events. Multiple modules can be registered to one dialog, hence thedialog can have multiple usages. Each dialog usage module is responsible tohandle a specific session. For example, the subscribe usage module will create a
new subscribe session each time it receives new SUBSCRIBE request (andPage 68PJSIP Developer’s Guide
increment dialog’s session counter), and decrement the session counter when thesubscribe session has terminated.
The processing of dialog usages by a dialog is similar to the processing ofmodules by endpoint; on each on_rx_request() and on_rx_response() event, thedialog passes the event to each dialog usages starting from the higher priority
module (i.e. the one with lower priority number) until one of the module returns
true (i.e. non-zero), which in this case the dialog will stop the distribution of theevent further. The on_tsx_state() notification will be distributed to all dialog
usages. Each dialog usage should filter out the transaction events that don’t
belong to it.
In its most basic (i.e. low-level) use, the application manages the dialog directly,
and it is the only “usage” (or user) of the dialog. In this case, the application is
responsible for managing the sessions inside the dialog, which means handling
ALL requests and responses and establishing/tearing down sessions manually.
In later chapters, we will learn about high-level APIs that can be used to manage
sessions. These high-level APIs are PJSIP modules that are registered to the
dialog as dialog usages, and they will handle/react to different types of SIP
messages that are specific to each type of sessions (e.g. an invite usage module
will handle INVITE, PRACK, CANCEL, ACK, BYE, UPDATE and INFO, a subscribe
usage module will handle REFER, SUBSCRIBE, and NOTIFY, etc.). These highlevel APIs provide high-level callbacks according to the session’s specification.
In this chapter however, we’ll only lean about basic, low-level dialog usage.

10.1.3 Dialog Set
Each dialog is a member of a dialog set. A dialog set is identified by common local
tag (i.e. From tag). Normally a dialog set only has one dialog as a member. The
only time when a dialog set contains multiple dialog is when outgoing INVITE
forks, which in this case each response message received with different To tag
will create a new dialog in the same dialog set.
A dialog set is defined in PJSIP as an opaque type (i.e. void*). A dialog structure(pjsip_dialog) has a member called dlg_set to identify the dialog set that it
belongs. Application can use linked list API to retrieve the siblings of a dialog (inthe same dialog set).
For more information about dialog set, please refer to subsequent section
10.1.6Forking.

10.1.4 Client Authentication
A dialog maintains a client authentication session (pjsip_auth_clt_sess), to be
used to authenticate requests within the dialog against all downstream servers.
The basic dialog initializes each outgoing request with appropriate authentication
headers, if they are available. However, authentication challenges MUST be
handled by dialog usages; e.g. the basic dialog does not automatically retry arequest when it is failed with 401/407 response.

10.1.5 Class Diagram
The following diagram illustrates user agent layer and basic dialog framework.

Page 69PJSIP Developer’s Guide
pjsip_user_agent

dlg_set (opaque)
Hash table

Attributes:
local_info+tag, local_contact,
call_id
Operations:pj_status_t pjsip_ua_init(endpt, param);
pj_status_t pjsip_ua_destroy(void);
pjsip_module* pjsip_ua_instance(void);
pjsip_endpoint* pjsip_ua_get_endpt(ua);Attributes:

pjsip_dialog
Attributes:
state, session_counter, initial_cseq, local_cseq, remote_cseq, route_set,
local_info+tag, local_contact, remote_info+tag, remote_contact, next_set
Operations:pj_status_t pjsip_dlg_create_uac(ua, local_uri, contact, ...);
pj_status_t pjsip_dlg_create_uas(ua, rdata, contact, &dlg);
pj_status_t pjsip_dlg_fork(old_dlg,rdata,&dlg);
pj_status_t pjsip_dlg_set_route_set(dlg, route_set);
pj_status_t pjsip_dlg_inc_session(dlg);
pj_status_t pjsip_dlg_dec_session(dlg);
pj_status_t pjsip_dlg_add_usage(dlg, mod);pj_status_t pjsip_dlg_create_request(dlg,method,cseq,&tdata);
pj_status_t pjsip_dlg_send_request(dlg,tdata,&tsx);
pj_status_t pjsip_dlg_create_response(dlg,rdata,code,txt,&tdata);
pj_status_t pjsip_dlg_modify_response(dlg,tdata,code,txt);
pj_status_t pjsip_dlg_send_response(dlg,tsx,tdata);
pj_status_t pjsip_dlg_send_msg(dlg,tdata);
pjsip_dialog* pjsip_tsx_get_dlg(tsx);
pjsip_dialog* pjsip_rdata_get_dlg(rdata);

dialog usages
Basic UA Application

pjsip_module
Attributes: name, id, priority, ...

INVITE Dialog Usage

Subscription Usage

Callbacks:
pj_bool_t on_rx_request(rdata);
pj_bool_t on_rx_response(rdata);
void on_tsx_state(tsx,event);

Figure 14 Basic User Agent Class Diagram

The diagram shows the relationship between dialog and its usages. In the mostbasic/low-level scenario, the application module is the only usage of the dialog. In
more high-level scenario, some high-level modules (e.g. pjsip_invite_usage andpjsip_subscribe_usage) can be registered to a dialog as dialog’s usages, and theapplication will receive events from these usages instead instead of directly fromthe dialog.
The diagram also shows PJSIP user agent module (pjsip_user_agent). The useragent module is the “owner” of all dialogs; the user agent module maintains ahash table of all dialog sets currently active.

10.1.6 Forking
Handling Forking Condition
The user agent module provides a callback that can be registered by application
when the user agent detects forked response from the downstream proxy. A
forked response in defined as a response (can be provisional or 2xx response)
within a dialog that has To tag that is different from any of existing dialogs. Whensuch responses are received, the user agent will call on_dlg_forked() callback,passing the received response and the original dialog (the dialog that application
created originally) as the arguments.

It is the complete responsibility of the application to handle forking condition!

Upon receiving a forked provisional response, application can:Page 70PJSIP Developer’s Guideoignore the provisional response (perhaps waiting until a final, forked 2xx
response is received); orocreate a new dialog (by calling pjsip_dlg_fork()). In this case, subsequent
responses received from this particular call leg will go to this new dialog.

Upon receiving a forked 2xx response, application can:odecide to terminate this particular call leg. In this case, the application
would construct ACK request from the response, send the ACK, thenconstruct a BYE transaction and send it to the call-leg. Application MUST
construct Route headers manually for both ACK and BYE requests
according to the Record-Route headers found in the response before
sending them to the transaction/transport layer.

ocreate a dialog for this particular call leg (by calling pjsip_dlg_fork()).
Application then constructs and sends ACK request to the call leg toestablish the dialog. After dialog is established, application may terminate
the dialog by sending BYE request.

Application MUST NOT ignore a forked 2xx responses.
Creating Forked Dialog
Application creates a forked dialog by calling pjsip_dlg_fork() function. Thisfunction creates a dialog and performs the following:o

Copy all attributes of the original dialog (including authorization client
session) to the new dialog.

oAssign different remote tag value, according to the tag found in the To
header in the response.

oRegister the new dialog to user agent’s dialog set.

o

If the original dialog has an application timer, it will copy the timer andupdate the timer of the new dialog.

Note that the function WILL NOT copy the dialog usages (i.e. modules) from theoriginal dialog.
The reason why the function pjsip_dlg_fork() doesn’t copy the dialog usages from theoriginal dialog is because each usage will normally have dialog specific data that can not be
copied without knowing the semantic of the data.

After the new dialog has been created, the application then MUST re-registereach dialog usages with the new dialog, by calling pjsip_dlg_add_usage().
The new dialog then MUST be returned as return value of the callback function.
This will cause the user agent to dispatch the message to the new dialog, causing
dialog usages (e.g. application) to receive on_rx_response() notification on thebehalf of the new dialog.
Using Timer to Handle Failed Forked Dialog
Application can schedule application specific timer with the dialog by calling
pjsip_dlg_start_app_timer() function. For timer associated with a dialog, thistimer is preferable than general purpose timer because this timer will be
automatically deleted when the dialog is destroyed.
Page 71PJSIP Developer’s Guide
Timer is important to handle failed forked dialog. A forked early dialog may notcomplete with a final response at all, because forking proxy will not forward 300699 if it receives 2xx response. So the only way to terminate these dangling early
dialogs is by setting a timer on these dialogs.
The best way to use dialog’s application timer to handle failed forked early dialog,
is to start the timer on the other forked dialogs the first time when it receives 2xx
response on one of the dialog in the dialog set. When the timer expires and no2xx response is received, the dialog should be terminated.

10.1.7 CSeq Sequencing
The local cseq of the dialog is updated when the request is sent (as opposed towhen the request is created). When CSeq header is present in the request, thevalue may be updated as the request is sent within the dialog.
The remote cseq of the dialog is updated when a request is received. Whendialog’s remote cseq is empty, the first request received will set the dialog’s
remote cseq. For subsequent requests, when dialog receives request with cseq
lower than dialog’s recorded cseq, this request would be automaticallyanswered statelessly by the dialog with a 500 response (Internal Server Error).
When the request’s cseq is greater than dialog’s recorded cseq, the dialog would
update the remote’s cseq automatically (including when the request’s cseq isgreater by more than one).
This behavior is compliant with SIP specification RFC 3261 Section 12.2.2.

10.1.8 Transactions
Dialog always acts statefully. It automatically creates UAS transaction whenincoming request arrives, and it creates UAC transaction when it is asked to sendoutgoing request.
The only time when dialog acts statelessly is when it receives incoming request
with CSeq lower then current CSeq, which in this case it would answer therequest with 500 (Internal Server Error) response.
When a transaction is created on behalf of a dialog (via dialog API, for both UAS
and UAC transactions), the transaction user (TU) of the transaction is set to useragent instance, and the dialog instance will be put in the transaction’s mod_data in
the appropriate index. The index is the user agent’s module ID. When events or
message arrives, the transaction reports the events to user agent module, which
will lookup the dialog and pass the event to the dialog.

Page 72PJSIP Developer’s Guide

10.2 Basic UA API Reference
10.2.1 User Agent Module API
typedef pjsip_module pjsip_user_agent;

User agent type.
pj_status_t pjsip_ua_init_module(pjsip_endpoint *endpt,
const pjsip_ua_init_param *prm);
pjsip_user_agent* pjsip_ua_instance(void);

Get the instance of the user agent.

pj_status_t pjsip_ua_destroy(void);

Destroy the user agent module.

10.2.2 Dialog Structure
The dialog structure and its API are declared in <pjsip/sip_dialog.h>. The
following code shows the declaration of pjsip_dialog.
// This structure is used to describe dialog's participants, local and remote party.
struct pjsip_dlg_party{
pjsip_fromto_hdr*info;// From/To header, inc tag
pj_uint32_t
tag_hval;// Hashed value of the tag
pjsip_contact_hdr*contact;// Contact header.
pj_int32_t
first_cseq;// First CSeq seen.
pj_int32_t
cseq;// Next sequence number.
};// This structure describes basic dialog.
struct pjsip_dialog{
PJ_DECL_LIST_MEMBER(pjsip_dialog);// Static properties:char
pj_pool_t
pj_mutex_t
pjsip_user_agent
void// List node in dialog set.

obj_name[PJ_MAX_OBJ_NAME];*pool;*mutex;*ua;*dlg_set;// Log identification// Dialog’s memory pool.
// Dialog's mutex.
// User agent instance.
// The dialog set.

// Dialog session properties.
pjsip_uri*target;pjsip_dlg_party
local;
pjsip_dlg_party
remote;pjsip_role_erole;
pj_bool_t
secure;pjsip_cid_hdr*call_id;
pjsip_route_hdr
route_set;
pjsip_auth_clt_sessauth_sess;// Current target.
// Local party info.
// Remote party info.
// Initial role.
// Use secure transport?
// Call-ID header.
// Route set list.
// Client authentication session.

// Session Management
int
int

sess_count;tsx_count;// Session counter.
// Active transaction counter.

// Dialog usages
unsigned
pjsip_module

usage_cnt;// Number of registered usages.
*usage[PJSIP_MAX_MODULE]; // Usages, priority sorted// Module specific data.
void*mod_data[PJSIP_MAX_MODULE];};
Code 36 Dialog Structure

Page 73PJSIP Developer’s Guide

10.2.3 Dialog Creation API
A dialog can be created by calling one of the following functions.
pj_status_t pjsip_dlg_create_uac(

pjsip_user_agent *ua,
const pj_str_t *local_uri,const pj_str_t *local_contact_uri,const pj_str_t *remote_uri,const pj_str_t *target,
pjsip_dialog **p_dlg);

Create a new dialog and return the instance in p_dlg parameter. After
creating the dialog, application can add modules as dialog usages bycalling pjsip_dlg_add_usage().
Note that initially, the session count in the dialog will be initialized to zero.
pj_status_t pjsip_dlg_create_uas(

pjsip_user_agent *ua,
pjsip_rx_data *rdata,
const pj_str_t *contact,
pjsip_dialog **p_dlg);

Initialize UAS dialog from the information found in the incoming requestthat creates a dialog (such as INVITE, REFER, or SUBSCRIBE), and set the
local Contact to contact. If contact is not specified, the local contact isinitialized from the URI in the To header in the request.
If the request has To tag parameter, dialog’s local tag will be initialized
from this value. Otherwise a globally unique id generator will be invokedto create dialog’s local tag.
This function also initializes the dialog’s route set based on the RecordRoute header in the request, if present.
Note that initially, the session count in the dialog will be initialized to zero.
pj_status_t pjsip_dlg_fork(

pjsip_dialog *original_dlg,
pjsip_rx_data *rdata,
pjsip_dialog **new_dlg );Create a new (forked) dialog on receipt on forked response in rdata. Thisfunction clones a new dialog from original_dlg (including authentication
session), but the new dialog will have new remote tag as copied from the
To header in the response. Upon return, the new_dlg will have beenregistered to the user agent. Applications just need to add modules as
dialog’s usages.
Note that initially, the session count in the dialog will be initialized to zero.

10.2.4 Dialog Termination
Dialogs are normally destroyed automatically, once the session counter has
reached zero and all pending transactions have been terminated. However, there
are certain cases when dialog usage needs to destroy dialog prematurely, e.g.
when the initialization has failed.
The pjsip_dlg_terminate() function is used to destroy dialog prematurely. Thisfunction normally is called by dialog usage. Application should use the appropriate
higher level session API such as pjsip_inv_terminate() which will destroy thesession as well as the dialog.
pj_status_t pjsip_dlg_terminate( pjsip_dialog *original_dlg );Destroy the dialog and unregister from UA module’s hash table. Thisfunction can only be called when the session counter is zero.

Page 74PJSIP Developer’s Guide

10.2.5 Dialog Session Management API
The following functions are used to manage dialog’s session counter.
pj_status_t pjsip_dlg_inc_session(

pjsip_dialog *dlg );Increment the number of sessions in the dialog. Note that initially (after
created) the dialog already has the session counter set to one.
pj_status_t pjsip_dlg_dec_session(

pjsip_dialog *dlg );Decrement the number of sessions in the dialog. Once the session counterreach zero and there is no pending transaction, the dialog will be
destroyed. Note that this function may destroy the dialog immediately ifthere is no pending transaction when this function is called.

10.2.6 Dialog Usages API
The following functions are used to manage dialog usages in a dialog.
pj_status_t pjsip_dlg_add_usage( pjsip_dialog *dlg,
pjsip_module *module,
void *mod_data );Add a module as dialog usage, and optionally set the module specific data.

pj_status_t pjsip_dlg_set_mod_data(

pjsip_dialog *dlg,
int module_id,void *data );Attach module specific data to the dialog.
void* pjsip_dlg_get_mod_data( pjsip_dialog *dlg,
int module_id);

Get module specific data previously attached to the dialog. Application canalso get value directly by accessing dlg->mod_data[module_id].

10.2.7 Dialog Request and Response API
pj_status_t pjsip_dlg_create_request(

pjsip_dialog *dlg,
const pjsip_method *method,
int cseq,
pjsip_tx_data **tdata);

Create a basic/generic request with the specified method and optionallyspecify the cseq. Use value –1 for cseq to have the dialog automaticallyput next cseq number for the request. Otherwise for some requests, e.q.
CANCEL and ACK, application must put the CSeq in the original INVITE
request as the parameter. This function will also put Contact header whereappropriate.
pj_status_t pjsip_dlg_send_request ( pjsip_dialog *dlg,
pjsip_tx_data *tdata,
pjsip_transaction **p_tsx );Send request message to remote peer. If the request is not an ACK
request, the dialog will send the request statefully, by creating an UAC
transaction and send the request with the transaction. Also when therequest is not ACK or CANCEL, the dialog will increment its local cseq
number and update the cseq in the request according to dialog’s cseq.
Note that on_tsx_state callback of the dialog usages may be called before
this function returns.
If p_tsx is not null, this argument will be set with the transaction instancethat was used to send the request.
Page 75PJSIP Developer’s Guide
This function decrements the transmit data's reference counter regardlessthe status of the operation.
pj_status_t pjsip_dlg_create_response(

pjsip_dialog *dlg,
pjsip_rx_data *rdata,
int st_code,
const pj_str_t *st_text,
pjsip_tx_data **tdata);

Create a response message for the incoming request in rdata with status
code st_code and optional status text st_text. This function is different
than endpoint’s API pjsip_endpt_create_response() in that the dialog
function adds Contact header and Record-Route headers in the response
where appropriate.
pj_status_t pjsip_dlg_modify_response(

pjsip_dialog *dlg,
pjsip_tx_data *tdata,
int st_code,
const pj_str_t *st_text);

Modify previously sent response with other status code. Contact header
will be added when appropriate.
pj_status_t pjsip_dlg_send_response( pjsip_dialog *dlg,
pjsip_transaction *tsx,
pjsip_tx_data *tdata);

Send response message statefully. The transaction instance MUST be thetransaction that was reported on on_rx_request() callback.
This function decrements the transmit data's reference counter regardlessthe status of the operation.

10.2.8 Dialog Auxiliary API
pj_status_t pjsip_dlg_set_route_set( pjsip_dialog *dlg,
const pjsip_route_hdr *route_set );Set dialog's initial route set to route_set list. This can only be called for
UAC dialog, before any request is sent. After dialog has been established,
the route set can not be changed.
For UAS dialog,the route set will be initialized in pjsip_dlg_create_uas()from the Record-Route headers in the incoming request.
The route_set argument is standard list of Route headers (i.e. withsentinel).
pj_status_t pjsip_dlg_start_app_timer(

pjsip_dialog *dlg,
int app_id,
const pj_time_val *interval,
void (*cb)(pjsip_dialog*,int));

Start application timer with this dialog with application specific id in app_id
and callback to be called in cb. Application can only set one application
timer per dialog. This timer is more usefull for dialog specific timer,
because it will be automatically destroyed once the dialog is destroyed.
Note that timer will also be copied to the forked dialog.
pj_status_t pjsip_dlg_stop_app_timer(

pjsip_dialog *dlg );Stop application specific timer if exists.
pjsip_dialog* pjsip_rdata_get_dlg(

pjsip_rx_data *rdata );Get the dialog instance in the incoming rdata. If an incoming message
matches an existing dialog, the user agent must have put the matching
dialog instance in the rdata, or otherwise this function will return NULL if
the message didn’t match any existing dialog.
Page 76PJSIP Developer’s Guide
pjsip_dialog* pjsip_tsx_get_dlg( pjsip_transaction *tsx );Get the dialog instance in the specified transaction.

Page 77PJSIP Developer’s Guide

10.3 Examples
10.3.1 Invite UAS Dialog
The following examples uses basic/low-level dialog API to process an incoming
dialog. The examples show how to:ocreate and initialize incoming dialog,ocreate UAS transaction to process the incoming INVITE request andtransmit 1xx responses,otransmit 2xx response to INVITE reliably,oprocess the incoming ACK.

As usual, most error handlings are omited for brevity. Real-world application
should be prepare to handle error conditions in all stages of the processing.
Creating Initial Invite Dialog
In this example we’ll learn how to create a dialog for an incoming INVITE request
and respond the dialog with 180/Ringing provisional response.
pj_bool_t on_rx_request(pjsip_rx_data *rdata){
if (rdata->msg->line.request.method.id == PJSIP_INVITE_METHOD &&pjsip_rdata_get_dlg(rdata) == NULL){// Process incoming INVITE!
pjsip_dialog *dlg;
pjsip_transaction *tsx;
pjsip_tx_data *tdata;
struct app_dialog *app_dlg;// Create, initialize, and register new dialog for incoming INVITE.
// This also implicitly create UAS transaction for rdata.
status = pjsip_dlg_create_uas( pjsip_ua_instance(), rdata, NULL, &dlg);// Register application as the only dialog usage
status = pjsip_dlg_add_usage( dlg, &app_module, NULL );// Increment session.
pjsip_dlg_inc_session(dlg);// Create 180/Ringing response
status = pjsip_dlg_create_response( dlg, rdata, 180, NULL /*Ringing*/, &tdata);// Send 180 response statefully. A transaction will be created in &tsx.
status = pjsip_dlg_send_response( dlg, pjsip_rdata_get_tsx(rdata), tdata);// As in real application, normally we will send 200/OK later,// when the user press the “Answer” button. In this example, we’ll send// 200/OK in answer_dlg() function which will be explained later. In order// to do so, we must “save” the INVITE transaction. We do this by putting// the transaction instance in dialog’s module data at index application// module’s ID.
//
dlg->mod_data[app_module.id] = pjsip_rdata_get_tsx(rdata);// Done processing INVITE request
return PJ_TRUE;}// Process other requests...
}
Code 37 Creating Dialog for Incoming Invite

Page 78PJSIP Developer’s Guide
Answering Dialog
In this example we will learn how to send 200/OK response to establish thedialog.
static void answer_dlg(pjsip_dlg *dlg){
pjsip_transaction *invite_tsx;
pjsip_tx_data *tdata;
invite_tsx = dlg->mod_data[app_module.id];// Modify previously sent (provisional) response to 200/OK response.
// The previously sent message is found in tsx->last_tx.
tdata = invite_tsx->last_tx;
status = pjsip_dlg_modify_response( dlg, tdata, 200, NULL /*OK*/ );// You may modify the response before it’s sent// (e.g. add msg body etc).
...
// Send the 200 response using previous transaction.
// Transaction will take care of the retransmission.
status = pjsip_dlg_send_response( dlg, invite_tsx, tdata);// We don’t need to keep pending invite tsx anymore.
dlg->mod_data[app_module.id] = NULL;}
Code 38 Answering Dialog

Processing CANCEL Request
In this example we will learn how to handle incoming CANCEL request.
pj_bool_t on_rx_request(pjsip_rx_data *rdata){...
if (rdata->msg->line.request.method.id == PJSIP_CANCEL_METHOD){// See if we have pending INVITE transaction.
pjsip_dialog *dlg;
pjsip_transaction *invite_tsx;// All requests within a dialog will have the dialog instance// recorded in rdata.
dlg = pjsip_rdata_get_dlg(rdata);
if (!dlg) {// Not associated with any dialog. Respond statelessly with 481.
status = pjsip_endpt_respond_stateless( endpt, rdata, 481, NULL, NULL,
NULL, NULL);
return PJ_TRUE;}
invite_tsx = dlg->mod_data[app_module.id];
if (invite_tsx) {pjsip_tx_data *tdata;// Transaction found. Respond CANCEL (statefully!) with 200 regardless// whether the INVITE transaction has completed or not.
status = pjsip_dlg_respond( dlg, rdata, 200, NULL /*OK*/);// Respond the INVITE transaction with 487/Request Terminated// only when INVITE transaction has not send final response.
if (invite_tsx->status_code < 200) {tdata = invite_tsx->last_tx;

Page 79PJSIP Developer’s Guide
status = pjsip_dlg_modify_response( dlg, tdata, 487, NULL);// Send the 487 response.
status = pjsip_dlg_send_response( dlg, invite_tsx, tdata);
dlg->mod_data[app_module.id] = NULL;// Decrement session!
pjsip_dlg_dec_session(dlg);}} else {// Transaction not found, respond CANCEL with 481 (statefully!)
status = pjsip_dlg_respond ( dlg, rdata, 481, NULL );}// Done processing CANCEL request
return PJ_TRUE;}// Process other requests...
}

Code 39 Processing CANCEL Request

Processing ACK Request
In this example we will learn how to handle incoming ACK request.
pj_bool_t on_rx_request(pjsip_rx_data *rdata){...
if (rdata->msg->line.request.method.id == PJSIP_ACK_METHOD &&pjsip_rdata_get_dlg(rdata) != NULL){// Process the ACK request
pjsip_dialog *dlg = pjsip_rdata_get_dlg(rdata);...
return PJ_TRUE;}...
}
Code 40 Processing ACK Request

10.3.2 Outgoing Invite Dialog
The following sets of example demonstrate how to work with outgoing INVITE
dialog.
Creating Initial Dialog
static pj_status_t make_call( const pj_str_t *local_info, const pj_str_t *remote_info){
pjsip_dialog *dlg;
pjsip_tx_data *tdata;// Create and initialize dialog.
status = pjsip_dlg_create_uac( user_agent, local_info, local_info,
remote_info, remote_info, &dlg );// Register application as the only dialog usage.
status = pjsip_dlg_add_usage( dlg, &app_module, NULL);

Page 80PJSIP Developer’s Guide// Add session.
pjsip_dlg_inc_session(dlg);// Send initial INVITE.
status = pjsip_dlg_create_request( dlg, &pjsip_invite_method, -1, &tdata);// Modify the INVITE (e.g. add message body etc.. )...
// Send the INVITE request.
status = pjsip_dlg_send_request( dlg, tdata, NULL);// Done.
// Further responses will be received in on_rx_response.
return status;}
Code 41 Creating Outgoing Dialog

Receiving Response
static pj_bool_t on_rx_response( pjsip_rx_data *rdata ){pjsip_dialog *dlg;
dlg = pjsip_rdata_get_dlg( rdata );if (dlg != NULL ) {pjsip_transaction *tsx = pjsip_rdata_get_tsx( rdata );if ( tsx != NULL && tsx->method.id == PJSIP_INVITE_METHOD) {if (tsx->status_code < 200) {PJ_LOG(3,(“app”, “Received provisional response %d”, tsx->status_code));} else if (tsx->status_code >= 300) {PJ_LOG(3,(“app”, “Dialog failed with status %d”, tsx->status_code));pjsip_dlg_dec_session(dlg);// ACK for non-2xx final response is sent by transaction.
} else {PJ_LOG(3,(“app”, “Received OK response %d!”, tsx->status_code));send_ack( dlg, rdata );}}else if (tsx == NULL && rdata->msg_info.cseq->method.id == PJSIP_INVITE_METHOD&& rdata->msg_info.msg->line.status.code/100 == 2){// Process 200/OK response retransmission.
send_ack( dlg, rdata );}return PJ_TRUE;}
else// Process other responses not belonging to any dialog...
}
Code 42 Receiving Response in Dialog

Sending ACK
static void send_ack( pjsip_dialog *dlg, pjsip_rx_data *rdata ){pjsip_tx_data *tdata;// Create ACK request
status = pjsip_dlg_create_request( dlg, &pjsip_ack_method,rdata->msg_info.cseq->cseq, &tdata );// Add message body

Page 81PJSIP Developer’s Guide...
// Send the request.
status = pjsip_dlg_send_request ( dlg, tdata, NULL );}Code 43 Sending ACK Request

10.3.3 Terminating Dialog
The following sample shows one way to terminate INVITE dialog, e.g. by sending
BYE.
static void send_bye( pjsip_dialog *dlg{
pjsip_tx_data *tdata;)// Create BYE request
status = pjsip_dlg_create_request( dlg, &pjsip_bye_method, -1, &tdata );// Send the request.
status = pjsip_dlg_send_request ( dlg, tdata, NULL );// Decrement session.
// Dialog will be destroyed once the BYE transaction terminates.
pjsip_dlg_dec_session(dlg);}

Page 82PJSIP Developer’s Guide

Chapter 11:SDP Offer/Answer Framework
The SDP offer/answer framework in PJSIP is based on RFC 3264 “An Offer/Answer
Model with the Session Descriptor Protocol (SDP)”. The main function of theframework is to facilitate the negotiating of media capabilities between local andremote parties, and to get agreement on which set of media to be used in one
invite session.
Note that although it is mainly used by invite session, the framework itself isbased on a generic SDP negotiation framework (pjmedia_sdp_neg), so it should be
able to be used by other types of applications. The dialog invite session provides
integration of SDP offer/answer framework with SIP protocol; it correctly interpretthe message bodies in relevant messages (e.g. INVITE, ACK, PRACK, UPDATE)
and translates them to SDP offer/answer negotiation.
This chapter describes the low level SDP negotiator framework, which is declaredin <pjmedia/sdp_neg.h> header file.

11.1 SDP Negotiator Structure
The pjmedia_sdp_neg structure represents generic SDP offer/answer session, andis used to negotiate local’s and remote’s SDP.

pjmedia_sdp_session
Attributes:
origin, name, time, conn, attr, media
Operations:pj_status_t pjmedia_sdp_parse(...);
int pjmedia_sdp_print(...);

pjmedia_sdp_media
Attributes:
net_type, addr_type, addr

pjmedia_sdp_neg

capability,
active_local_sdp,
active_remote_sdp,
neg_local_sdp,
neg_remote_sdp

Attributes:
state
Operations:status pjmedia_sdp_neg_init_w_local_offer(pool,neg,local);status pjmedia_sdp_neg_init_w_remote_offer(neg,loc,rmt);
status pjmedia_sdp_neg_modify_local_offer(neg,local);status pjmedia_sdp_neg_negotiate(neg);
sdp* pjmedia_sdp_neg_tx_local_offer(neg);
sdp* pjmedia_sdp_neg_rx_remote_offer(neg,remote);
sdp* pjmedia_sdp_neg_rx_remote_answer(neg,remote);
sdp* pjmedia_sdp_neg_get_local(neg);
sdp* pjmedia_sdp_neg_get_remote(neg);

Operations:pjmedia_sdp_conn
Attributes:
net_type, addr_type, addr
Operations:Figure 15 SDP Negotiator "Class Diagram"

The pjmedia_sdp_neg structure keeps three SDP structures:oinitial_sdp: which is the initial capability of local endpoint. This SDP isoactive_local_sdp: contains local SDP after it has been negotiated withpassed to the negotiator during creation, and the contents generally will
not be changed throughout the session (even after negotiation). The
negotiator uses this SDP in the negotiation when it receives new offer fromremote (as opposed to receiving updated SDP from remote).
remote. The dialog MUST use this to start its local media instead of theinitial SDP.

oactive_remote_sdp: contains the SDP currently used by peer/remote.

Page 83PJSIP Developer’s Guide
The negotiator also has two other SDP variables which are only used internallyduring negotiation process, namely neg_local_sdp and neg_remote_sdp. These aretemporary SDP description, and application MUST NOT refer to these variables.

11.2 SDP Negotiator Session
The general state transition of SDP offer/answer session is shown in the following
diagram.

create_w_local_offer()

LOCAL OFFER

tx_local_offer(), modify_local_offer(), reinit_local_offer()

rx_remote_answer()

NULL

create_w_remote_offer()

WAIT NEGO

negotiate()

NEGOTIATING

done

DONE

rx_remote_offer()

Figure 16 SDP Offer/Answer Session State Diagram

The negotiation session starts with PJMEDIA_SDP_NEG_STATE_NULL. If the dialog has
a local media description ready and want to offer the media to remote (normallythis is the case when the dialog is acting as UAC), it creates the SDP negotiatorby passing the local SDP to the function pjmedia_sdp_neg_create_w_local_offer().
This function will set the initial capability of local endpoint, and set thenegotiation session state to PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER. The initial SDP
then can be sent to remote party in the outgoing INVITE request. Once dialog hasreceived remote’s SDP, it must call pjmedia_sdp_neg_rx_remote_answer() with
providing the remote’s SDP. The negotiation function can then be called.
If the dialog already has remote media description in hand (normally this is thecase when dialog is acting as UAS), it can create the SDP negotiator session bypassing both local and remote SDP to pjmedia_sdp_neg_create_w_remote_offer().
After this, the negotiation function can be called.
After the session has been established, both local and remote party may modify
the session. The negotiator can handle one of these two situations:oThe dialog has received SDP from remote. In this case, the dialog will call
pjmedia_sdp_neg_rx_remote_offer() and passing the remote’s SDP to thisfunction. After this the negotiation function can be called. The negotiation
function’s return value determines whether there is modification needed in
the local media.

o

The local party wants to send SDP to remote. Dialog can further choose
one of the following actions:•

If it just wants to send currently active local SDP without
modification, it should call pjmedia_sdp_neg_tx_local_offer() toget the active local SDP, send the SDP, then wait for the
remote’s answer.

•

If it wants to modify currently active local media (e.g. changing
stream direction, change active codec, etc), it should get theactive local media with pjmedia_sdp_neg_get_local(), modify it,
call pjmedia_sdp_neg_modify_local_offer() to update the offer,send the local SDP, then wait for the remote’s answer.
Page 84PJSIP Developer’s Guide•

The dialog may want to completely change the local media (e.g.
changing IP address, changing codec set, adding new medialine). This is different than updating current media describedabove because it will change initial_sdp, so that futurenegotiation will be based on this new SDP. If the dialog wants
to do this, it calls pjmedia_sdp_neg_reinit_local_offer() with
the new local SDP, send the SDP, then wait for remote’s
answer.

After the dialog has sent offer to remote party, it should receive answer backfrom the remote party. The dialog must provide the remote’s SDP to thenegotiator so that the negotiation function can be called. The dialog provides the
remote’s answer by calling pjsip_sdp_neg_rx_remote_answer().
If remote has rejected local’s offer (e.g. returning 488/”Not Acceptable Here”
response), dialog MUST still call pjsip_sdp_neg_rx_remote_answer() with providing
NULL in remote’s SDP argument, and call the negotiation function so that thenegotiator session can revert back to previously active session descriptions, ifany.

11.3 SDP Negotiation Function
The dialog calls pjmedia_sdp_neg_negotiate() to negotiate the offer and theanswer, after it has provided both local’s and remote’s SDP to be used for thenegotiation (i.e. negotiator state is PJMEDIA_SDP_NEG_STATE_WAIT_NEGO). Thisfunction may return one of the following result:o

PJ_SUCCESS, (i.e. zero) if it has successfully established an agreement

between local and remote SDP. In this case, both local’s and remote’s
active SDP will be stored in the session for future reference, andapplication can query these active SDPs to start the local media.
o

PJMEDIA_ESDPNOCHANGE, if it found out that there is no modification neededin currently used SDPs (both local and remote). In this case, thepreviously agreed SDP sessions will not be modified either.
o

PJMEDIA_ESDPFAIL, if it couldn’t find agreement on local and remoteo

PJMEDIA_ESDPNOOFFER, if negotiator has not sent/received any offer yet.

o

PJMEDIA_ESDPNOANSWER, if negotiator has not received remote’s answer yet.

oor other non-zero value to indicate other errors.

capabilities. In this case, if the session is keeping a previously agreed SDP,
these SDP (local and remote) will not be modified. If dialog is acting as
UAS for this session, it should respond the request with 488/Not
Acceptable Here response to the offer.

In all cases, the negotiation function will set the negotiator’s state to
PJMEDIA_SDP_NEG_STATE_DONE.

Page 85PJSIP Developer’s Guide

Chapter 12:Dialog Invite Session and Usage
12.1 Introduction
The dialog invite session is a high level invite session management, which can beused by application to manage invite session (including SDP management). The
invite session is designed to completely abstract the basic dialog, so application
should not need to use basic dialog API when it is using the invite session API.
A dialog invite session can be created by application on per dialog basis. The
dialog invite session is managed by dialog invite usage, which is a PJSIP module.
The dialog invite usage performs dispatching of events from the dialog to thecorresponding invite session, and also handles forked dialog.
The dialog invite session and usage is implemented in a separate static library,i.e. pjsip-ua library. Application MUST include <pjsip-ua/sip_inv.h> to use thedialog invite session/usage functionality. Alternatively, applications can include asingle header file <pjsip-ua.h> to get all the functionalities in pjsip-ua library.

12.1.1 Terms
Dialog invite session is an invite session inside a dialog. If application decides to
use the high level invite session management, it needs to create one and only
one instance of dialog invite session for each dialog.
Dialog invite usage is a PJSIP module, registered to PJSIP endpoint. When adialog has dialog invite session, this module needs to be registered to theparticular dialog as the dialog usage. This will be achieved automatically duringinvite session creation.

12.1.2 Features
The dialog invite session provides the following features for the application:oSession progress reporting (e.g. session progressing, connected,
confirmed, disconnected),oAutomatic authentication handling (e.g. retry the request on receipt of
401/407 response),o

SDP offer and answer handling,oHigh-level forking handler,oSession timeout (i.e. Expires header),oSession extensions, such as session timer, and reliable provisional
response.

12.1.3 Invite Session StateThe dialog invite usage provides callback to notify application about session
progress. This is particularly usefull for telephony applications, where thesession’s state is normally associated with telephony call state.
The progress of an invite session is shown in the following state transition
diagram.

Page 86PJSIP Developer’s Guide

CALLING
Rx 300-699, errors
Tx INVITE

Rx 1xxEARLY

NULL
Rx INVITE

Tx/Rx
2xx

Tx 1xxRx 2xxCONNECTING
Tx 2xxTx/Rx
ACK

CONFIRMED

Tx/Rx
BYE

DISCONNECTED
Timer

Tx 300-699, errors

INCOMINGTERMINATED

Figure 17 Invite Session State Diagram

The description of each state is as follows:
PJSIP_INV_STATE_NULL

This is the state of the session when it was firstcreated. No messages have been sent/received
at this point.

PJSIP_INV_STATE_CALLING

The session state after the first INVITE
message is sent, but before any provisional
response is received.

PJSIP_INV_STATE_INCOMING

The session state after the first INVITE
message is received, but before any provisional
response is sent.

PJSIP_INV_STATE_EARLY

The session state after dialog has sent or
received provisional response messages for the
INVITE request, only when To tag is present.

PJSIP_INV_STATE_CONNECTING

The session state after a final 2xx response has
been sent or received.

PJSIP_INV_STATE_CONFIRMED

The session state after ACK request has been
sent or received.

PJSIP_INV_STATE_DISCONNECTED

The session state when the session has been
disconnected, either because of non-successful
final response to INVITE or BYE request.

Figure 18 Invite Session State Description

12.1.4 Invite Session Creation
For outgoing dialog (i.e. caller), application needs to create an UAC dialog withpjsip_dlg_create_uac(). Application then creates the invite session for the dialog
by calling pjsip_inv_create_uac(), passing the UAC dialog instance as one of theparameter. Application MUST NOT send the INVITE request before invite sesion
has been created, or otherwise the invite session will loose some events.
For incoming dialog, application can first verify if the request can be accepted bycalling pjsip_inv_verify_request(). This function verifies the Supported, Require,
and the request body to make sure that it can accept the request. Should therequest can not be accepted, it will create the appropriate rejection response. If
the request can be accepted, the application creates the UAS dialog by calling
pjsip_dlg_create_uas() function. Application then creates the invite session forthis dialog by calling pjsip_inv_create_uas(), passing the UAS dialog instance as
one of the parameter. Application MUST NOT send any responses before thePage 87PJSIP Developer’s Guide
invite sesion has been created, or otherwise the invite session will loose someevents.
When an outgoing dialog forked, and if an invite session exists in the “original”
dialog, the invite usage will module automatically create the invite session for thenew (forked) dialog. Application will be notified about the creation of the new
session via a callback.
The invite session creation functions (i.e. pjsip_inv_create_uac() andpjsip_inv_create_uas() functions) automatically registers the invite session usage
to the dialog. Application does not need to call pjsip_dlg_add_usage() to register
the invite usage module to the dialog.

12.1.5 Messages Handling
The invite session handles all SIP methods that may change the state of theinvite session. For this version of PJSIP, the invite session handles INVITE, BYE,
ACK, CANCEL, UPDATE, and PRACK methods.
Application MUST use invite session API to create and send request and response
messages with above methods. This is necessary to ensure that the request andresponse message is handled correctly and it contains the appropriate features
being used by the session (e.g. reliable provisional response).
Application can still use the base dialog API to create and send request andresponse message for methods other than above. For example, application can
use the base dialog API to create and send MESSAGE request inside the dialog.

12.1.6 Extending the Dialog
As stated previously, the invite session handles INVITE, BYE, ACK, CANCEL,
UPDATE, and PRACK messages that occurs in a dialog. When application wants
to support or handle other types of messages, it must register itself to the dialog
as dialog usage. This will enable the application to process incoming requests thatare “unhandled” by existing dialog’s uages.
It is important that application set its application module’s priority correctly.
Application priority should be set to to PJSIP_MOD_PRIORITY_APPLICATION. The
invite usage has module priority set to (PJSIP_MOD_PRIORITY_APPLICATION-1).
This would ensure that the invite usage is able to inspect the incoming requests
first before application.

12.1.7 Extending the Invite Session
In the future, the invite session may be extended to support more SIP
extensions, such as call transfer, dialog targetting, etc. At present, application
should be able to perform these features by constructing the messages manually.

Page 88

PJSIP Developer’s Guide

12.2 Reference
12.2.1 Data Structure
The invite session functionalities are declared in header file <pjsip-ua/sip_inv.h>.
enum pjsip_inv_state{
PJSIP_INV_STATE_NULL,PJSIP_INV_STATE_CALLING,
PJSIP_INV_STATE_INCOMING,PJSIP_INV_STATE_EARLY,PJSIP_INV_STATE_CONNECTING,PJSIP_INV_STATE_CONFIRMED,PJSIP_INV_STATE_DISCONNECTED,PJSIP_INV_STATE_TERMINATED,};
struct pjsip_inv_session{
pjsip_inv_state
pjsip_dialog
pjmedia_sdp_neg
pj_uint32_t};// Before INVITE is sent or received.
// After INVITE is sent.
// After INVITE is received// After response with To tag is sent/received.
// After 2xx response is sent/received.
// After ACK is sent/received.
// Session is terminated// Session will be destroyed.

state;*dlg;*neg;
options;// Session state.
// The base dialog.
// SDP negotiator.
// Options in use, see pjsip_inv_option

Code 44 Invite Session Data Structure

The following code shows various options that can be applied to a session. The
bitmask combination of these options need to be specified when creating asession. After the dialog is established (including early), the options member of
pjsip_inv_session shows which capabilities are common in both endpoints.

enum pjsip_inv_option{
PJSIP_INV_SUPPORT_100RELPJSIP_INV_SUPPORT_TIMERPJSIP_INV_SUPPORT_UPDATEPJSIP_INV_REQUIRE_100RELPJSIP_INV_REQUIRE_TIMER= 1, // Indicate support for 100rel extension= 2, // Indicate support for session timer extension.
= 4, // Indicate support for UPDATE method.
= 32, // Require 100rel extension.
= 64, // Require session timer extension.

};

Code 45 Invite Session Options

12.2.2 Invite Usage Module
The invite usage module MUST be initialized before any invite session can becreated.
pj_status_t pjsip_inv_usage_init(

pjsip_endpoint *endpt,
pjsip_module *app_module,
const pjsip_inv_callback *callback);

Initialize the invite usage module and register it to the endpoint. The
callback argument contains pointer to functions to be called on occurencesof events in invite sessions.
pjsip_module* pjsip_inv_usage_instance(void);

Page 89PJSIP Developer’s Guide
Get the instance of the invite usage module.

12.2.3 Session Callback
The structure pjsip_inv_callback contains pointer to functions will can beregistered by application to invite usage module to receive notification about
invite session events.
The functions in the callback are as follows.
void on_state_changed( pjsip_inv_session *inv_ses,
pjsip_event *e);

This callback is called when the invite sesion state has changed.
Application should inspect the session state (inv_sess->state) to get thecurrent state.
This callback is mandatory.
void on_new_session(

pjsip_inv_session *inv_ses,
pjsip_event *e);

This callback is called when the invite usage module has created a new
dialog and invite because of forked outgoing request.
This callback is mandatory.
void on_tsx_state_changed( pjsip_inv_session *inv_ses,
pjsip_transaction *tsx,
pjsip_event *e );This callback is called whenever any transactions within the session haschanged their state. Application MAY implement this callback, e.g. tomonitor the progress of an outgoing request.
This callback is optional.

void on_rx_offer(pjsip_inv_session *inv_ses,const pjmedia_sdp_session *offer );This callback is called when the invite session has received new offer frompeer. Application set local answer by calling pjsip_inv_set_sdp_answer().
This function will not send outgoing message. It just keeps the answer for
SDP negotiation process, and will be included in subsequent response orrequest sent.
This callback is optional. When it’s not specified, the default behavior is tonegotiate remote offer with session’s initial capability.
void on_media_update(pjsip_inv_session *inv_ses, pj_status_t status );This callback is called after SDP offer/answer session has completed. The
status argument specifies the status of the offer/answer, as returned by
pjmedia_sdp_neg_negotiate().
This callback is optional (from the point of view of the framework), but all
useful applications normally need to implement this callback.

Page 90PJSIP Developer’s Guide

12.2.4 Session Creation and Termination
pj_status_t pjsip_inv_create_uac(

pjsip_dialog *dlg,
const pjmedia_sdp_session *local_sdp,
unsigned options,pjsip_inv_session **inv_sess);

Create UAC invite session for the specified dialog in dlg. If application has
determined its media capability, it can specify the SDP in local_sdp.
Otherwise it can leave this to NULL, to let remote UAS specifies an offer.
The options argument is bitmask combination of SIP features inpjsip_inv_options enumeration.
On successful return, the invite session will be put in inv_sess argument
and the function will return PJ_SUCCESS. Otherwise the appropriate error
status will be returned on failure.
pj_status_t pjsip_inv_verify_request(pjsip_rx_data *rdata,
unsigned *options,const pjmedia_sdp_session *local_sdp,
pjsip_dialog *dlg,
pjsip_endpoint *endpt,
pjsip_tx_data **tdata);

Application SHOULD call this function upon receiving the initial INVITE
request in rdata before creating the invite session (or even dialog), toverify that the invite session can handle the INVITE request. This function
verifies that local endpoint is capable to handle required SIP extensions in
the request (i.e. Require header field) and also the media, if media
description is present in the request.
Upon calling this function, the options argument SHOULD contain thedesired SIP extensions to be applied to the session. Upon return, thisargument will contain the SIP extension that will be applied to the session,
after considering the Supported, Require, and Allow headers in therequest.
If local media capability has been determined, and if application wishes toverify that it can handle the media offer in the incoming INVITE request, it
SHOULD specify its local media capability in local_sdp argument. If it is
not specified, media verification will not be performed by this function.
If everything has been negotiated successfully, the function will return
PJ_SUCCESS. Otherwise it will return the reason of the failure.
This function is capable to create the appropriate response message whenthe verification has failed. If tdata is specified, then a non-2xx final
response will be created and put in this argument upon return, when theverification has failed. If a dialog has been created prior to calling thisfunction, then it MUST be specified in dlg argument. Otherwise application
MUST specify the endpt argument (this is useful e.g. when application
wants to send the response statelessly).

pj_status_t pjsip_inv_create_uas(

pjsip_dialog *dlg,
pjsip_rx_data *rdata,
const pjmedia_sdp_session *local_sdp,
unsigned options,pjsip_inv_session **inv_sess);

Create UAS invite session for the specified dialog in dlg. Application MUST
specify the received INVITE request in rdata. The invite session needs toinspect the received request to see if the request contains features that itsupports.
Page 91PJSIP Developer’s Guide
Application SHOULD call the verification function before calling thisfunction, to ensure that it can create the session successfully.
If application has determined its media capability, it can specify thiscapability in local_sdp. If SDP is received in the initial INVITE, the UAS
capability specified in local_sdp doesn’t have to match the received offer;
the SDP negotiator is able to rearrange the media lines in the answer sothat it matches the offer.
The options argument is bitmask combination of SIP features inpjsip_inv_options enumeration.
On successful return, the invite session will be put in inv_sess argument
and the function will return PJ_SUCCESS. Otherwise the appropriate error
status will be returned on failure.
pj_status_t pjsip_inv_terminate( pjsip_inv_session *inv,
int st_code,
pj_bool_t notify );Terminate the INVITE session prematurely and destroy the underlying
dialog (if the dialog has no other usage). This function should only becalled when INVITE session initialization has failed. For normal cases,
application MUST terminate the INVITE session by calling
pjsip_inv_end_session().
The st_code argument specifies the SIP status code to be put as thedisconnect cause. If notify is true, the application callback will be called.

12.2.5 Session Operations
pj_status_t pjsip_inv_invite( pjsip_inv_session *inv,
pjsip_tx_data **tdata );Create the initial INVITE request for this session. This function can only becalled for UAC session. The initial INVITE request will be put in tdata
argument if it can be created successfully.
If local media capability is specified when the invite session was created,then this function will put an SDP offer in the outgoing INVITE request.
Otherwise the outgoing request will not contain SDP body.

pj_status_t pjsip_inv_answer( pjsip_inv_session *inv,
int st_code,
const pj_str_t *st_text,
const pjmedia_sdp_session *local_sdp,
pjsip_tx_data **tdata );Create a response message to the initial INVITE request. The st_code
contains the status code to be sent, which may be a provisional or final
response. If custom status text is desired, application can specify the text
in st_text; otherwise if this argument is NULL, default status text will beused.
If application has specified its media capability during creation of UAS
invite session, the local_sdp argument MUST be NULL. This is because
application can not perform more than one SDP offer/answer session in asingle INVITE transaction.
If application has not specified its media capability during creation of UAS
invite session, it MAY or MUST specify its capability in local_sdp argument,
depending whether st_code indicates a 2xx final response.
Page 92PJSIP Developer’s Guide
pj_status_t pjsip_inv_end_session(

pjsip_inv_session *inv,
int st_code,
const pj_str_t *st_text,
pjsip_tx_data **tdata );Create a SIP message to initiate invite session termination. Depending on
the state of the session, this function may return CANCEL request, a non2xx final response, or a BYE request. If the session has not answered theincoming INVITE, this function creates the non-2xx final response with thespecified status code in st_code and optional status text in st_text.
pj_status_t pjsip_inv_reinvite(

pjsip_inv_session *inv,
const pj_str_t *new_contact,
const pjmedia_sdp_session *new_offer,pjsip_tx_data **tdata );Create a re-INVITE request. If application wants to update its local contact
and inform peer to perform target refresh with a new contact, it can
specify the new contact in new_contact argument; otherwise thisargument must be NULL.
Application MAY initiate a new SDP offer/answer session in the request
when there is no pending answer to be sent or received. It can detect thiscondition by observing the state of the SDP negotiator of the invite
session. If new offer should be sent to remote, the offer must be specified
in new_offer, otherwise this argument must be NULL.
pj_status_t pjsip_inv_update (pjsip_inv_session *inv,
const pj_str_t *new_contact,
const pjmedia_sdp_session *new_offer,pjsip_tx_data **tdata );Create an UPDATE request. If application wants to update its local contact
and inform peer to perform target refresh with a new contact, it can
specify the new contact in new_contact argument; otherwise thisargument must be NULL.
Application MAY initiate a new SDP offer/answer session in the request
when there is no pending answer to be sent or received. It can detect thiscondition by observing the state of the SDP negotiator of the invite
session. If new offer should be sent to remote, the offer must be specified
in new_offer, otherwise this argument must be NULL.
pj_status_t pjsip_inv_send_msg(

pjsip_inv_session *inv,
pjsip_tx_data *tdata,
void *token );Send request or response message in tdata. The token is an arbitrary
application data that will be put in the transaction’s mod_data array, atapplication module’s index.

12.2.6 Auxiliary API
pjsip_inv_session* pjsip_dlg_get_inv_session(

pjsip_dialog *dlg );pjsip_inv_session* pjsip_tsx_get_inv_session(

pjsip_transaction *tsx );Get the invite session instance associated with dialog dlg, or NULL.

Get the invite session instance associated with transaction tsx, or NULL.
Page 93PJSIP Developer’s Guide

Page 94PJSIP Developer’s Guide

Chapter 13:SIP-Specific Event Notification
13.1 Introduction
SIP event specific notification is described in RFC 3265 “Session Initiation Protocol(SIP)-Specific Event Notification”. The core protocol definies two SIP methods forestablishing event subscription, i.e. SUBSCRIBE and NOTIFY, although othermethods may be defined to establish subscription (e.g. REFER).
This chapter describes the PJSIP design and implementation to create basic andgeneric event notification framework on top of basic dialog framework, and canbe used to implement higher layer event packages such as presence and calltransfer (with REFER).
The PJSIP implementation of event notification framework is packaged as a static
library pjsip-simple, under pjsip directory. To use its functionalities, application
should include header file <pjsip_simple.h> and link with pjsip-simple static
library.
This chapter describes basic event subscription framework. Presence and calltransfer will be described in the next chapters.

13.1.1 Basic Concept
All types of PJSIP event notification session are represented with pjsip_evsub
object. This object manages the subscription life-time, and translates incoming
requests and responses to appropriate callback calls.
The PJSIP event notification session uses the basic dialog framework (see 10
Basic User Agent Layer (UA)) for managing the underlying dialog and to maintaindialog properties (such as request target, CSeq sequencing, etc.). Because thedesign of the basic dialog framework allows the dialog to be shared by multiple
sessions, multiple event subscription sessions may use the same dialog, and it
can also share the dialog with invite session as well.
To subscribe for an event notification, application needs to create an event
subscription object, specifying the underlying dialog and callback to receive
subscription events.
Incoming subscription requests (such as SUBSCRIBE or REFER) will come to a
dialog or application, depending on whether the request is inside or outside
dialog. Application MUST inspect the Event id in the request, then use theappropriate package’s API to handle subscription. For example, when theincoming request is REFER, application creates the server subscription by calling
pjsip_xfer_create_uas(), and when the Event id in the incoming SUBSCRIBE
request is “presence”, application creates the server subscription by calling
pjsip_pres_create_uas().

13.1.2 Event Package
Event package describes the semantic of the event subscription. In PJSIP, event
package must be registered to the event framework first before subscription
sessions with the specified event ID can be created. Event packages areregistered to the framework by calling pjsip_evsub_register_pkg(). This function
call normally is done when the PJSIP module implementing the event package isinitialized.
Page 95PJSIP Developer’s Guide
The event package is responsible mainly for providing message body to NOTIFY
requests. For example, PJSIP presence event package creates message body with
content type “application/pidf+xml” or “application/xpidf+xml” for all outgoing
NOTIFY requests.

13.1.3 Header Fields
The event framework manages the content of Accept, Allow-Events, Event,
Expires, and Subscription-State header fields for outgoing requests, based on
information provided by event packages when the packages were registered. It
also inspects the content of Expires and Subscription-State header fields in theincoming requests, and updates its state accordingly.
All other header fields (and header fields outside the scope of dialog) MUST be
handled either by the event package or application. For example, the refer event
package manages Refer-To header field for outgoing REFER request.

13.2 Basic Operation
This section describes how to use the core PJSIP event subscription framework.
As you will see in later chapters, the operations for higher layer event package(such as presence and call transfer) will be similar to the operations in the core
event framework.
Note: to save space, the diagrams omit “pjsip_” prefix in the API call, which should be specified
in the real program. For example, when the diagram says dlg_create_uac() andevsub_create_uac(), the real function names are pjsip_dlg_create_uac() andpjsip_evsub_create_uac().

13.2.1 Client Initiating Subscription
Client initiates subscription by constructing and sending SUBSCRIBE request to
establish dialog. Client SHOULD put the appropriate credentials in the dialog sothat authentication challenges can be handled automatically by the evsub
module. Client SHOULD also set the appropriate route set in the dialog.
APPLICATIONEVENT MODULE

1adlg_create_uac()

1b

evsub_create_uac()

dlg_add_usage(),
dlg_inc_session(),2a

evsub_initiate()

dlg_create_request()

2b

evsub_send_request()

dlg_send_request()

3

on_evsub_state()(state=SENT)

4

on_tsx_state (401)

REMOTE
ENDPOINTDIALOG

SUBSCRIBE

rized)401 (Unautho
on_tsx_state (401)dlg_send_request()

SUBSCRIBE
200 (OK)5

on_evsub_state()(state=ACCEPTED)

on_tsx_state (200)Figure 19 Client Initiating Subscription

Page 96PJSIP Developer’s Guide
Description:
1. Application (or event package) initiates client subscription by first creating
an UAC dialog (1a) then creates the client subscription session (1b).
Application MAY set dialog credentials and route set between step 1a and
1b.
2. Application sends initial SUBSCRIBE (or other method that establishes
subscription, such as REFER) by creating the request (2a) and send therequest (2b).
3. The sending of SUBSCRIBE request in step 2 above will trigger
on_evsub_state() callback to be called. This will happen even before
evsub_send_request() function returns.
4. Application receives any transaction state progress in on_tsx_state()
callback in step 4. This callback is OPTIONAL, and only serves for
informational purpose only. If the request is challenged, AND credentials
have been set in the dialog, the event framework will resubmit the request
with proper credential.
5. When 2xx response to initial SUBSCRIBE request (or other request that
establishes subscription) is received, on_evsub_state() callback is called.
Application can retrieve the subscription state by calling
pjsip_evsub_get_state() function, which should return
PJSIP_EVSUB_STATE_ACCEPTED when 2xx response is received. If non-2xx
final response is received, the subscription state will be set to
PJSIP_EVSUB_STATE_TERMINATED.

13.2.2 Server Receiving Incoming Subscription
REMOTE
ENDPOINTDIALOGEVENT MODULEAPPLICATIONSUBSCRIBE
on_rx_request(SUBSCRIBE)

401 (Unauthorized)

1aendpt_respond(401)

SUBSCRIBE
on_rx_request(SUBSCRIBE)

dlg_create_response()

200 (OK)

dlg_create_uas()

2a

evsub_create_uas()

2b

evsub_accept(200)3

on_evsub_state()state=ACCEPTED

41bdlg_send_response()

Figure 20 Server Creating Subscription

Description:
1. Incoming requests outside any dialogs will always come to application, which
ultimately decides how to handle the request. For incoming SUBSCRIBE
request, if application wants to authenticate the request, it can respond therequest with 401/407 response (step 1a), statefully or statelessly. This MUST
be done before any dialog or server subscription instance is created. When
Page 97PJSIP Developer’s Guide
application is happy with the request (step 1b), it can then create the server
subscription instance (step 2a and 2b).
If the request comes within a dialog (e.g. REFER request), application receives
the request in on_tsx_state() callback of the dialog. In this case steps 1 to 2aare not required, and application proceeds direcly to step 2b.
2. The server side event subscription needs a dialog instance for it to operate.
Application MAY create a new UAS dialog for the subscription (step 2a), or
MAY use existing dialog (for example to handle incoming REFER request inside
a dialog). Application then creates the server side event subscription (step2b), passing the dialog instance.
3. Application calls pjsip_evsub_accept() to send response to the subscription
request (step 3), passing a status code to be put in the response. The status
code MUST be a 2xx class status.
4. The sending of 2xx response in step 3 above will trigger on_evsub_state()
callback to be called (step 4).
Server then MUST send initial NOTIFY request immediately, which will be
described below.

13.2.3 Server Activating Subscription (Sending NOTIFY)
Server activates the server subscription by sending NOTIFY request (see step 5
below). If server expects the NOTIFY request to be authenticated, then it MUST
set the credentials in the dialog when it created the UAS dialog. If the NOTIFY
request is challenged, then as long as there is a correct credential in the dialog,
the evsub module will automatically resubmit the NOTIFY request with theappropriate credential (step 6).
REMOTE
ENDPOINTDIALOGNOTIFY(state=active)

EVENT MODULEAPPLICATION

dlg_create_request()

evsub_notify()
state=active

5adlg_send_request()

evsub_send_request()

5b

on_tsx_state(401)on_tsx_state(401)6

on_evsub_state()state=ACTIVE

7401 (U
nauthorized)NOTIFY(state=active)

dlg_send_request()

200 (OK)
on_tsx_state(200)Figure 21 Server Activating Subscription

13.2.4 Client Receiving NOTIFY Requests
When incoming NOTIFY request is received, application MAY challenge therequest by returning 401 in on_rx_notify() callback (see step 5 below). Client
then wait for immediate submission of the NOTIFY request. By default, thesubscription framework waits for 5 seconds for the NOTIFY resubmission (withthe credential), after which it will terminate the subscription by sending
SUBCRIBE with zero Expires value if NOTIFY is not received.
Page 98PJSIP Developer’s Guide
The on_rx_notify() callback is OPTIONAL. The default behavior is to respondincoming NOTIFY with 200 response.
Note that the event framework only update its state (according to state in theincoming NOTIFY request) if application answer the NOTIFY request with 2xx
response.

APPLICATIONEVENT MODULE

REMOTE
ENDPOINTDIALOG=active)
NOTIFY (state5

on_rx_notify()

on_tsx_state ()401 (Unauthorized)

dlg_create_response()

401 (Unauthorized)

dlg_send_response()=active)
NOTIFY (state6

on_rx_notify()

on_tsx_state ()200 (OK)

dlg_create_response()

200 (OK)

dlg_send_response()7

on_evsub_state()state=active

Figure 22 Client Receiving NOTIFY

13.2.5 Server Terminating Subscription
Server terminates subscription by sending NOTIFY with Subscription-State set toterminated (step 8 below). Server MAY send NOTIFY requests anytime after it
receives the initial request that established the session.
In particular, server SHOULD send NOTIFY with state set to terminated when thesubscription has timed out.
REMOTE
ENDPOINTDIALOGNOTIFY)(state=terminated

EVENT MODULEAPPLICATION

dlg_create_request()

evsub_notify()
state=terminated8adlg_send_request()

evsub_send_request()

8b

on_evsub_state()state=TERMINATED

9200 (OK)
on_tsx_state(200)Figure 23 Server Terminating Subscription

The sending of NOTIFY request with Subscription-State set to terminated will
trigger on_evsub_state() callback to be called (step 8b), regardless of the
response of the NOTIFY request. However, when the NOTIFY request ischallenged, the framework will correctly respond the challenge by resending therequest with proper credential, if it has one.

Note: in addition, the receipt of 481 (Call/Transaction Does Not Exist), 408 (Request Timeout),transaction timeout, or transport error events on any outgoing NOTIFY requests will also

Page 99

PJSIP Developer’s Guide
terminate the server subscription, and on_evsub_state() callback will be called.

13.2.6 Client Receiving Subscription Termination
When NOTIFY request with Subscription-State set to terminated is received, theevsub_on_state() callback will be called (step 9 below), only if client set the
response to the NOTIFY request with 2xx code (step 8 below).

APPLICATION

8EVENT MODULE

terminated)
NOTIFY (state=on_rx_notify(),
returns 200

on_tsx_state ()200 (OK)

dlg_create_response()

200 (OK)

dlg_send_response()

9

REMOTE
ENDPOINTDIALOG

on_evsub_state()state=terminateddlg_dec_session()

Figure 24 Client Receiving Subscription Termination

13.2.7 Client Refreshing Subscription
The event framework emits on_client_refresh() callback when it is time torefresh the subscription (step 10 below). Application MUST refresh subscription
by calling pjsip_evsub_initiate() function to create the request andpjsip_evsub_send_request() to send the request (see step 11a and 11b).
When PJSIP event package implementation such presence or refer is being used,
these packages provide default implementation for this callback. The default
implementation is to refresh the subscription using the last Expires value. Thus if
application is using these packages, it doesn’t have to implement this callback.

APPLICATIONEVENT MODULE

REMOTE
ENDPOINTDIALOG10

on_client_refresh()11a

evsub_initiate()

dlg_create_request()

11b

evsub_send_request()

dlg_send_request()

timer

SUBSCRIBE

Figure 25 Client Refreshing Subscription

13.2.8 Server Detecting Refresh Timeout
When the subscription interval expires without receiving subscription refresh,
server subscription emits on_server_timeout() callback. Application MUST
terminate subscription by sending NOTIFY with terminated state.
Page 100PJSIP Developer’s Guide
When PJSIP event package implementation such presence or refer is being used,
these packages provide default implementation for this callback. The default
implementation is to terminate the subscription by sending NOTIFY with state set
to terminated, and the last message body. Thus if application is using thesepackages, it doesn’t have to implement this callback.

REMOTE
ENDPOINTDIALOGEVENT MODULE

on_server_timeout()

10

dlg_create_request()

evsub_notify()
state=terminated11adlg_send_request()

evsub_send_request()

11b

timer

NOTIFYd)(state=terminate

APPLICATION

on_evsub_state()state=TERMINATED

200 (OK)
on_tsx_state(200)Figure 26 Server Detecting Subscription Timeout

13.3 Reference
13.3.1 Module Management
pj_status_t pjsip_evsub_init_module( pjsip_endpoint *endpt );Initialize the event notify module and register the module to the specified
endpoint. This function MUST be called before any other event subscriptionfunctions.
pjsip_module* pjsip_evsub_instance(void);

Get the event notify module instance.

13.3.2 Event Package Management
pj_status_t pjsip_evsub_register_pkg(

pjsip_module *pkg_mod,
const pj_str_t *event_name,unsigned expires,
unsigned accept_cnt,
const pj_str_t accept[]);Register event package to the event subscription framework. The
pkg_mod argument specifies the module that implements the event
package being registered.. The event_name specifies event package
name, such as “presence” (RFC 3856). The accept_cnt and accept
arguments specifies array of tokens that describes media types that will be
acceptable. Examples of these media types for presence event package
are “application/pidf+xml” and “application/xpidf+xml”.

13.3.3 Event Subscription State
The state of the event subscription is identified by pjsip_evsub_state
enumeration, which is declared in <pjsip-simple/evsub.h> as follows.

enum pjsip_evsub_state

Page 101PJSIP Developer’s Guide{
PJSIP_EVSUB_STATE_NULL,// State is NULLPJSIP_EVSUB_STATE_SENT,// Client has sent SUBSCRIBE requestPJSIP_EVSUB_STATE_ACCEPTED,// 2xx response to SUBSCRIBE has been sent/received
PJSIP_EVSUB_STATE_PENDING,// Subscription is pending
PJSIP_EVSUB_STATE_ACTIVE,// Subscription is active
PJSIP_EVSUB_STATE_TERMINATED, // Subscription is terminated
PJSIP_EVSUB_STATE_UNKNOWN,// Subscription state can not be determined (i.e.
// server is using non-standard state names).
// Application can query the state by// calling pjsip_evsub_get_state_name()};
Code 46 Event Subscription State

Notes:•

When the state has reached PJSIP_EVSUB_STATE_TERMINATED,
application MUST release application’s resources associated to thesubscription, because after this the subscription will be destroyed andthere will be no further notification from the event subscription.

•

The PJSIP_EVSUB_STATE_UNKNOWN occurs when server sends
unrecognized state in the Subscription-State header.

13.3.4 Event Subscription Session
The event notification session in PJSIP is represented with opaque pjsip_evsub
structure. There are few functions to query some of the structure’s attributes.
pjsip_evsub_state pjsip_evsub_get_state(pjsip_evsub *sub);Get the event subscription state.
const char* pjsip_evsub_get_state_name(pjsip_evsub *sub);Return the string representation of the state, or when the state is
PJSIP_EVSUB_STATE_UNKNOWN, return the state string sent by server.
void pjsip_evsub_set_mod_data(

pjsip_evsub *sub,
unsigned mod_id,void *mod_data);

Put a user defined data mod_data at mod_id index.
void* pjsip_evsub_get_mod_data(

pjsip_evsub *sub,
unsigned mod_id);

Retrieve previously set user defined data at mod_id index.

13.3.5 Generic Event Subscription Callback
The generic event subscription user contains function callbacks that are used toreceive notifications from the event framework or from the event package that isbeing used.
When application is using a package implementation, application normallyregisters the callback for that package, instead of registering callback to theevent framework.
Page 102PJSIP Developer’s Guide
The generic event subscription callback is declared as follows.
struct pjsip_evsub_user{
void (*on_evsub_state)void (*on_tsx_state)void (*on_rx_refresh)

void (*on_rx_notify)

void (*on_client_refresh)
void (*on_server_timeout)(pjsip_evsub *sub, pjsip_event *event);(pjsip_evsub *sub, pjsip_transaction *tsx,
pjsip_event *event);(pjsip_evsub *sub,
pjsip_rx_data *rdata,
int *p_st_code,
pj_str_t **p_st_text,
pjsip_hdr *res_hdr,
pjsip_msg_body **p_body);(pjsip_evsub *sub,
pjsip_rx_data *rdata,
int *p_st_code,
pj_str_t **p_st_text,
pjsip_hdr *res_hdr,
pjsip_msg_body **p_body);(pjsip_evsub *sub);(pjsip_evsub *sub);};Code 47 Event Subscription Callback

The description of each of the callback functions is as follows.
void on_evsub_state( pjsip_evsub *sub, pjsip_event *event );This callback is called when subscription state has changed. Application
MUST be prepared to receive NULL event and events with type other than
PJSIP_EVENT_TSX_STATE.
This callback is optional, although normally application will definitely want
to implement this callback.

void on_tsx_state(pjsip_evsub *sub,
pjsip_transaction *tsx,
pjsip_event *event);

This callback is called when transaction state has changed, for transactions
that belong to this subscription (i.e. the request with method that createsthe subscription, and NOTIFY transactions).
This callback is OPTIONAL, as it only servers informational purpose only.
void on_rx_refresh( pjsip_evsub *sub,
pjsip_rx_data *rdata,
int *p_st_code,
pj_str_t **p_st_text,
pjsip_hdr *res_hdr,
pjsip_msg_body **p_body);

This callback is called when incoming SUBSCRIBE (or any method that
establishes the subscription in the first place) is received. It allows
application to specify what response should be sent to remote, along withadditional headers and message body to be put in the response, if any.
This callback is OPTIONAL when application is using PJSIP’s event package
such as presence or call transfer; the package’s default implementation
will send 200 (OK) and NOTIFY containing current subscription state.
However, if application implements this callback (i.e. the value of thecallback is not NULL), it MUST send NOTIFY request upon receiving thisPage 103PJSIP Developer’s Guide
callback. The suggested behavior is to call pjsip_evsub_last_notify() tocreate the NOTIFY request, since this function takes care about
unsubscription request and calculates the appropriate expiration interval.
void on_rx_notify(

pjsip_evsub *sub,
pjsip_rx_data *rdata,
int *p_st_code,
pj_str_t **p_st_text,
pjsip_hdr *res_hdr,
pjsip_msg_body **p_body);

This callback is called when client/subscriber received incoming NOTIFY
request. It allows the application to specify what response should be sent
to remote, along with additional headers and message body to be put inthe response, if any.
This callback is OPTIONAL. When it is not implemented, the default
behavior is to respond incoming NOTIFY request with 200 (OK) response.
void on_client_refresh( pjsip_evsub *sub );This callback is called when it is time for the client to refresh thesubscription.
This callback is OPTIONAL when PJSIP package such as presence or referis used; the event package will refresh subscription by sending
SUBSCRIBE with the interval set to current/last interval.
However, if application implements this callback (i.e. the value of thecallback is not NULL), it MUST send the refresh subscription itself.

void on_server_timeout( pjsip_evsub *sub );This callback is called when server doesn't receive subscription refresh
after the specified subscription interval.
This callback is OPTIONAL when PJSIP package such as presence or referis used; the event package send NOTIFY to terminate the subscription.
However, if application implements this callback (i.e. the value of thecallback is not NULL), it MUST handle the timeout itself, and the suggested
behaviour is to send NOTIFY with state set to terminated.

13.3.6 Event Subscription API
pj_status_t pjsip_evsub_create_uac(

pjsip_dialog *dlg,
const pjsip_evsub_user *user_cb,
const pj_str_t *event,unsigned option,
pjsip_evsub **p_evsub);Create client subscription session, using dlg as the underlying dialog. The
event argument specifies the event package to be used, and this musthave been registered previously to the event framework. The option
Page 104PJSIP Developer’s Guide
argument currently is only used for refer subscription, and it should bezero for other type of packages.
pj_status_t pjsip_evsub_create_uas(

pjsip_dialog *dlg,
const pjsip_evsub_user *user_cb,
pjsip_rx_data *rdata,
unsigned option,
pjsip_evsub **p_evsub);Create server subscription session, using dlg as the underlying dialog. The
rdata argument specifies the incoming request. The option argument
currently is only used for refer subscription, and it should be zero for othertype of packages.
pj_status_t pjsip_evsub_terminate(pjsip_evsub *sub,pj_bool_t notify );Forcefully destroy the event subscription. This function should only be becalled on special condition when initialization has failed. For normal
situation, the subscription will be destroyed automatically whensubscription is terminated.
This function MAY destroy the underlying dialog when the dialog has noother usages.
pj_status_) pjsip_evsub_initiate( pjsip_evsub *sub,const pjsip_method *method,
pj_int32_t expires,pjsip_tx_data **p_tdata);

Call this function to create request to initiate subscription, to refreshsubcription, or to request subscription termination. The method argument
must be the method that establishes the subscription, such as SUBSCRIBE
or REFER. If this argument is NULL, then SUBSCRIBE will be used. The
expires argument will be put as Expires header in the request. If the value
is set to zero, this will request unsubscription. If the value is negative,
default expiration as defined by the package will be used.
Application then MUST call pjsip_evsub_send_request() to send thesubscription request.

pj_status_t pjsip_evsub_accept(

pjsip_evsub *sub,
pjsip_rx_data *rdata,
int st_code,
const pjsip_hdr *hdr_list );Accept the incoming subscription request by sending 2xx response toincoming SUBSCRIBE or REFER request. The st_code argument MUST
specify 2xx code. The hdr_list is optional list of headers to be put in the
response.
pj_status_t pjsip_evsub_notify(

pjsip_evsub *sub,
pjsip_evsub_state state,
const pj_str_t *state_str,
const pj_str_t *reason,
pjsip_tx_data **p_tdata);

For notifier, set the state of the subscription and create NOTIFY request to
subscriber. The state_str argument is optional, it is only used when thestate is set to PJSIP_EVSUB_STATE_UNKNOWN. The reason argument
MUST be set when subscription state is set to
PJSIP_EVSUB_STATE_TERMINATED. Application SHOULD use the values
Page 105PJSIP Developer’s Guide
defined in RFC 3265, such as “noresource”, “timeout”, “giveup”,“rejected”, “probation”, and “deactivated”. PJSIP does not interpret thevalue of the reason string, it will just put the string in the outgoing NOTIFY
request.
Note that the state of the subscription will actually be set when the
NOTIFY request is sent.
pj_status_t pjsip_evsub_current_notify( pjsip_evsub *sub,
pjsip_tx_data **p_tdata );For notifier, create a NOTIFY request that reflects current subscription
status. This function normally is used by package implementors, notdirectly by the application.

pj_status_t pjsip_event_sub_send_request(

pjsip_event_sub *sub,
pjsip_tx_data *tdata);

Send the previously created outgoing request message in tdata.

13.3.7 Auxiliary API
pjsip_evsub* pjsip_tsx_get_evsub( pjsip_transaction *tsx);

Get the event subscription instance associated with the specified
transaction.

Page 106PJSIP Developer’s Guide

Chapter 14:Presence Event Package
14.1 Introduction
The SIP for presence is described in RFC 3856 “A Presence Event Package for
the Session Initiation Protocol (SIP)”. The presence event package allows an
endpoint to subscribe for presence status of an URI (e.g. buddy).
This chapter describes the PJSIP design and implementation of presence event
package. The implementation uses PJSIP’s generic event subscription framework,and registers an event package with event name “presence”.
The PJSIP implementation of presence is packaged as a static library pjsipsimple, under pjsip directory. To use its functionalities, application should include
header file <pjsip_simple.h> and link with pjsip-simple static library.

14.2 Reference
The presence API is very much identical to the core event API, and the behavior
is also identical. Please refer to header file <pjsip-simple/presence.h> for moredetails.
Application MUST call pjsip_pres_init_module() before using any presence
functionalities. This function registers the presence module endpoint, and also
register event package “presence” to event framework.

Page 107PJSIP Developer’s Guide

Chapter 15:Refer Event Package
The refer event package is declared in <pjsip-ua/sip_xfer.h>. Application MUST
call pjsip_xfer_init_module() before it can use its functionalities. This function
registers mod-xfer module to the endpoint, and registers refer event package tothe event framework.
The refer event package API is similar to the core event package API.

Page 108PJSIP Developer’s Guide

Chapter 16:Instant Messaging
PJSIP can be used to facilitate pager based instant messaging, as described in
RFC 3428 (Session Initiation Protocol (SIP) Extension for Instant Messaging).
In addition, PJSIP supports message composition indication as described in RFC
3994 (Indication of Message Composition for Instant Messaging).

16.1 Instant Messaging
Application sends instant messages by constructing a MESSAGE requests. PJSIP
does not define a special API for composing MESSAGE requests, since basicly theprocess is identical to creating other types of requests and the MESSAGE request
does not require special processing.
Application can choose to send the MESSAGE request inside or outside a dialog
context. For example, when an INVITE session has been established for voicecommunication, MESSAGE requests may be exchanged within that dialog context.
However, RFC 3428 explicitly says that implementations SHOULD NOT create
dialogs for the primary purpose of associating MESSAGE requests with one
another.

16.1.1 Sending MESSAGE
Outside Dialog
To send MESSAGE request outside dialog, application constructs a new request as
usual, by calling pjsip_endpt_create_request(). This function can accept a“text/plain” message body. Application then call pjsip_endpt_send_request() tosend the request statefully.
The code snippet below shows how to achieve this.

pj_status_t send_im(const pj_str_t *from, const pj_str_t *to, const pj_str_t *text){
pjsip_method message_method = { PJSIP_OTHER_METHOD, {“MESSAGE”, 7}};
pjsip_tx_data *tdata;
pj_status_t status;
status = pjsip_endpt_create_request( endpt, &message_method, to, from, to,
NULL /*Contact*/, NULL /*Call-ID */,-1 /*CSeq*/, text /*Text body*/&tdata);status = pjsip_endpt_send_request( endpt, tdata, -1 /*Timeout*/,
NULL /*Callback data*/, NULL /*Callback*/);}Code 48 Sending IM Outside Dialog

Inside Dialog
To send MESSAGE request inside dialog, application constructs a new request
within dialog as usual, by calling pjsip_dlg_create_request().Application thenattached a “text/plain” message body to the request, and call
pjsip_dlg_send_request() to send the request.
Page 109PJSIP Developer’s Guide
The following code snippet shows how to create MESSAGE request inside a dialog.

pj_status_t send_im_in_dlg( pjsip_dialog *dlg, const pj_str_t *text){
pjsip_method message_method = { PJSIP_OTHER_METHOD, {“MESSAGE”, 7}};
const pj_str_t STR_TEXT = pj_str(“text”);
const pj_str_t STR_PLAIN = pj_str(“plain”);
pjsip_tx_data *tdata;
pj_status_t status;/* Must lock dialog. */pjsip_dlg_inc_lock(dlg);/* Create the MESSAGE request. */status = pjsip_dlg_create_request( dlg, &message_method,-1 /*CSeq*/, &tdata);/* Attach “text/plain” body. */tdata->msg->body = pjsip_msg_body_create( tdata->pool, &STR_TEXT, &STR_PLAIN,
text );/* Send the request. */status = pjsip_dlg_send_request( dlg, tdata, NULL /*Ptr. to receive tsx*/ );/* Done */pjsip_dlg_dec_lock(dlg);}
Code 49 Sending IM Inside Dialog

16.1.2 Receiving MESSAGE
Incoming MESSAGE requests outside any dialogs will be received by application
module.
Incoming MESSAGE requests inside a dialog will be notified to dialog usage via
on_tsx_state() callback of the dialog.

16.2 Message Composition Indication
PJSIP SIMPLE static library provides helper to compose and parse message
composition indication body. The message composition indication helper functions
are declared in <pjsip-simple/iscomposing.h> header. Application can include thisheader file, or alternatively includes <pjsip_simple.h> to include all SIMPLE
functionalities.
PJSIP message composition indication header file declares these functions.
pj_xml_node* pjsip_iscomposing_create_xml( pj_pool_t *pool,
pj_bool_t is_composing,const pj_time_val *last_active,
const pj_str_t *content_type,
int refresh);Create XML document conformant to “application/im-iscomposing+xml”
specification. The only required arguments are the pool and is_composing
status. Other arguments are optional attributes to be put in the XML
document. The last_active attribute indicates the time when the person islast typing. Put NULL to omit this attribute. The content_type argument
Page 110PJSIP Developer’s Guide
specifies the type of message being composed. Put NULL to omit this
attribute. The refresh argument indicates when the recepient can expect
the sender to refresh the status. Put -1 to omit this attribute.
pjsip_msg_body* pjsip_iscomposing_create_body( pj_pool_t *pool,
pj_bool_t is_composing,const pj_time_val *last_active,
const pj_str_t *content_type,
int refresh);Create a SIP message body containing the XML document for the message
composition indication.
pj_status_t pjsip_iscomposing_parse( pj_pool_t *pool,char *msg,
pj_size_t len,
pj_bool_t *p_is_composing,
pj_str_t **p_last_active,
pj_str_t **p_content_type,
int *p_refresh);

Parse a buffer containg XML document containing the message
composition indication. The values in the document will be returned in
p_is_composing, p_last_active, p_content_type, and p_refresh arguments,
which are all optional.

Page 111PJSIP Developer’s Guide

Chapter 17:PJSUA Abstraction
The PJSUA API is a very high layer abstraction of PJSIP, to facilitate the creationof multimedia SIP UA (more commonly refered to as “softphone”). PJSUA API
integrates all PJSIP components and PJMEDIA API in a single library, and provides
very high level “call” API to manage INVITE sessions.
PJSUA API can be used to create a pretty complex applications. Currently it has
the following features:multiple account registrations, with each account correspond to a specificrealm/registrar server and each can have different route set.



multiple concurrent calls, with hard-limit of 254 concurrent calls. The
actual limit will probably be lower than this because of the CPU limitationfor encoding/decoding the audio.

N-party conferencing, with hard limit of 254 conference ports, and flexible
port connections arrangements. The conference party does not need touse the same codec or clock rate.



call hold and unattended call transfer.

local buddy list.



SIP presence, with independent online status indication for each account.



instant messaging and message composition indication.

wideband (16KHz) and ultra-wideband (32 KHz) audio support.



audio codecs: PCMA, PCMU, GSM, and Speex (including wideband/16KHz
and ultra-wideband/32KHz). More codecs will be added.



DTMF (RFC 2833) handling.



streaming file to conference bridge.

Currently the PJSUA abstraction is used by pjsua console application.
The PJSUA abstraction API is declared in <pjsua-lib/pjsua.h>, and application
MUST linked with pjsua-lib static library.
Although it has been tested to work properly, the PJSUA abstraction library is stillin experimental stage, until enough applications are built on top of it and the API
is proven to be sufficiently strong.

Page 112