Loading...
Searching...
No Matches
Sofia SIP User Agent Library - "nua" - High-Level User Agent Module

# Module Meta Information

The nua module contains the user-agent library taking care of basic SIP User Agent functions. Its functionality includes call management, messaging and event retrieval.

Contact:\n Pekka Pessi <Pekka.Pessi@nokia-email.address.hidden>

Status:\n Sofia SIP Core library

License:\n LGPL

Contributor(s):
  - Pekka Pessi Pekka.nosp@m..Pes.nosp@m.si@no.nosp@m.kia..nosp@m.com
  - Pasi Rinne-Rahkola Pasi..nosp@m.Rinn.nosp@m.e-Rah.nosp@m.kola.nosp@m.@noki.nosp@m.a.co.nosp@m.m
  - Kai Vehmanen Kai.V.nosp@m.ehma.nosp@m.nen@n.nosp@m.okia.nosp@m..com
  - Martti Mela Martt.nosp@m.i.Me.nosp@m.la@no.nosp@m.kia..nosp@m.com

# Overview

The NUA API gives the high-level application programmer transparent and full control to the SIP protocol engine below it. NUA provides the call semantics on top of existing transaction semantics found in nta module. With NUA it is possible to create different kind of SIP User Agents, like terminals, gateways or MCUs.

The nua engine hides many low-level signaling and media management aspects from the application programmer. It is possible to use different kind of media interfaces - even remote ones - in a fully transparent way.

The application and the protocol engine within User Agent library can be run in separate threads. The protocol engine communicates with the application using events, delivered to the application with a a callback function. The callback function is called within the thread context of the application, represented with a su_root_t object.

# Sofia Concepts for NUA User

## Introduction

The Sofia software suite is based on certain basic ideas and concepts that are used in all levels of Sofia software. Many of those are implemented in Sofia utility library (su) providing unified interface to the most important OS services and utilities .

The following sections contain descriptions of the concepts that a user of NUA library must understand to create a working application. The other utilities (in the SU library and other libraries of Sofia software suite) might also be useful for an application developer but one must be careful when using them because they might change the behavior of the Sofia software suite in a way that causes NUA library to work incorrectly. See [su] for more detailed description of the SU services.

## Event loop - root object

The NUA uses the reactor pattern (also known as dispatcher pattern and notifier pattern) for event driven systems (see [Using Design Patterns to Develop Reusable Object-oriented Communication Software, D.C. Schmidt, CACM October '95, 38(10): 65-74]). Sofia uses a task as basic execution unit for the programming model. According to the model, the program can ask that the event loop invokes a callback function when a certain event occurs. Such events include I/O activity, timers or a asynchronously delivered messages from other task.

The root object is a handle representing the task in the application. Another way of seeing the same thing is that the root object represents the main event loop of the task. Through the root object the task code can access its context information (magic) and thread-synchronization features like wait objects, timers, and messages.

An application using NUA services must create a root object and the callback routine to handle NUA events. The root object is created with su_root_create() function and the callback routine is registered with nua_create() function.

Root object has type su_root_t.

See documentation of <sofia-sip/su_wait.h> and <su_root.c> for more information of root object.

See section nua_event_e for more information of the callback function.

## Magic

The magic is a term used for the context pointer that can be bound to various objects in Sofia stack (for example root object and operation handle) by the application code. This context pointer is passed back to the application code when a registered callback function is called by the main event loop. The Sofia stack retains the context information between calls to the callback function. An application can use the context information to store any information it needs for processing the events.

## Memory Handling

The home-based memory management is useful when a lot of memory blocks are allocated for given task. The allocations are done via the memory home, which keeps a reference to each allocated memory block. When the memory home is then freed, it will free all memory blocks to which it has reference. This simplifies application logic because application code does not need to keep track of the allocated memory and free every allocated block separately.

An application using NUA services can use the memory management services provided by the SU library but it is not mandatory.

See documentation of <sofia-sip/su_alloc.h> for more information of memory management services.

## Tags

Tagging is the mechanism used in Sofia software for packing parameters to functions. It enables passing a variable number of parameters having non-fixed types. For an application programmer the tagging is visible as macros that are used to encapsulate the passed parameters. When evaluated a tagging macro creates a structure that contains a tag (telling what is the type of a parameter) and a value (pointer to opaque data). By checking the tag the layers of Sofia software check whether they can handle the parameter or should it just be passed to lower layers for processing.

There are some tags with special meaning:

- TAG_NULL() (synonymous to TAG_END()) end of tag list
- TAG_SKIP() empty tag item
- TAG_NEXT() tag item pointing to another tag list, ends the current tag list
- TAG_ANY() filter tag accepting any tag
- TAG_IF() conditional inclusion of tag item

The NUA functions can be called with a list of tagged values if they have following parameters at the end of parameter list:

tag_type_t tag,
tag_value_t value,
...);
tag_value_t
intptr_t tag_value_t
tag_type_t
struct tag_type_s const * tag_type_t

The last tagged value on the parameter list must be TAG_NULL() (or TAG_END(), synonym for TAG_NULL()).

Every tag has two versions:
NUTAG_<tagname>
which takes a value parameter and
NUTAG_<tagname>_REF
which takes a reference parameter. The latter is used with tl_gets() function to retrieve tag values from tag list.

For SIP headers there exists also additional version of tags:
SIPTAG_<tagname>_STR
This tag version takes a C-language character string as parameter. The corresponding tag without _STR suffix takes a parsed value structure as parameter.

The following is an example of call to NUA function containing tagged values:

nua_unregister(op->op_handle,
TAG_IF(use_registrar, NUTAG_REGISTRAR(registrar)),
SIPTAG_CONTACT_STR("*"),
SIPTAG_EXPIRES_STR("0"),
TAG_NULL());
SIPTAG_CONTACT_STR
#define SIPTAG_CONTACT_STR(s)
SIPTAG_EXPIRES_STR
#define SIPTAG_EXPIRES_STR(s)
nua_unregister
void nua_unregister(nua_handle_t *nh, tag_type_t, tag_value_t,...)
Unregister.
Definition nua.c:625
NUTAG_REGISTRAR
#define NUTAG_REGISTRAR(x)
Registrar URL.
Definition nua_tag.h:325
TAG_IF
#define TAG_IF(condition, item)
TAG_NULL
#define TAG_NULL()

An application using NUA services must use tagged arguments for passing the parameters to functions. See nua_invite() for discussion on how a SIP message is constructed from the tags.

See documentation of <sofia-sip/su_tag.h> for more information of tags and the module-specific documentation of each Sofia module for information of tags specific for that module.

## Debugging and Logging

The modules of Sofia stack contain configurable debugging and logging functionality based on the services defined in <sofia-sip/su_log.h>. The debugging and logging details (for example level of details on output and output file name) can be configured by environment variables, directives in configuration files and compilation directives in the source files.

Examples of useful directives/ environment variables are:

- #SOFIA_DEBUG Default debug level (0..9)
- #NUA_DEBUG NUA debug level (0..9)
- #NTA_DEBUG Transaction engine debug level (0..9)
- #TPORT_DEBUG Transport event debug level (0..9)
- #TPORT_LOG If set, print out all parsed SIP messages on transport layer
- #TPORT_DUMP Filename for dumping unparsed messages from transport

The defined debug output levels are:

- 0 fatal errors, panic
- 1 critical errors, minimal progress at subsystem level
- 2 non-critical errors
- 3 warnings, progress messages
- 5 signaling protocol actions (incoming packets, ...)
- 7 media protocol actions (incoming packets, ...)
- 9 entering/exiting functions, very verbatim progress

An application using NUA services can also use the debugging and logging services provided by the Sofia stack but it is not mandatory.

See documentation of <sofia-sip/su_log.h> for more information of debugging and logging services.

# NUA Concepts

## NUA Stack Object

Stack object represents an instance of SIP stack and media engine. It contains reference to root object of that stack, user-agent-specific settings, and reference to the SIP transaction engine, for example.

A NUA stack object is created by nua_create() function and deleted by nua_destroy() function. The nua_shutdown() function is used to gracefully release active the sessions by nua engine.

NUA stack object has type nua_t.

## NUA Operation Handle

Operation handle represents an abstract SIP call/session. It contains information of SIP dialog and media session, and state machine that takes care of the call, high-level SDP offer-answer protocol, registration, subscriptions, publications and simple SIP transactions. An operation handle may contain list of tags used when SIP messages are created by NUA (e.g. From and To headers).

An operation handle is created explicitly by the application using NUA for sending messages (function nua_handle()) and by stack for incoming calls/sessions (starting with INVITE or MESSAGE). The handle is destroyed by the application using NUA (function nua_handle_destroy()).

Indication and response events are associated with an operation handle.

NUA operation handle has type nua_handle_t.

## Stack Thread and Message Passing Concepts

The stack thread is a separate thread from application that provides the real-time protocol stack operations so that application thread can for example block or redraw UI as it likes.

The communication between stack thread and application thread is asynchronous. Most of the NUA API functions cause a send of a message to the stack thread for processing and similarly when something happens in the stack thread it sends a message to the application thread. The messages to the application thread are delivered as invokes of the application callback function when the application calls su_root_run() or su_root_step() function.

## SIP Message and Header Manipulation

SIP messages are manipulated with typesafe SIPTAG_ tags. There are three versions of each SIP tag:

- SIPTAG_<tagname>() takes a parsed value as parameter.
- SIPTAG_<tagname>STR() takes an unparsed string as parameter.
- SIPTAG<tagname>REF() takes a reference as parameter, is used with tl_gets() function to retrieve tag values from tag list.
- SIPTAG<tagname>__STR_REF() takes a reference as parameter, is used with tl_gets() function to retrieve string tag values from tag list.

For example a header named "Example" would have tags names SIPTAG_EXAMPLE(), SIPTAG_EXAMPLE_STR(), and SIPTAG_EXAMPLE_REF().

When tags are used in NUA calls the corresponding headers are added to the message. In case the header can be present only once in a message and there already exists a value for the header the value given by tag replaces the existing header value. Passing tag value NULL has no effect on headers. Passing tag value (void *)-1 removes corresponding headers from the message.

For example:

- sending a SUBSCRIBE with Event: header and two Accept: headers:

nua_subscribe(nh,
SIPTAG_EVENT_STR("presence"),
SIPTAG_ACCEPT(accept1),
SIPTAG_ACCEPT(accept2),
TAG_END());
SIPTAG_ACCEPT
#define SIPTAG_ACCEPT(x)
SIPTAG_EVENT_STR
#define SIPTAG_EVENT_STR(s)
nua_subscribe
void nua_subscribe(nua_handle_t *nh, tag_type_t, tag_value_t,...)
Subscribe a SIP event.
Definition nua.c:702
TAG_END
#define TAG_END()

- fetching tag values when processing nua_r_subscribe event:

sip_accept_t *ac = NULL;
sip_event_t *o = NULL;
tl_gets(tl,
SIPTAG_EVENT_REF(o), /* _REF takes a reference! */
SIPTAG_ACCEPT_REF(ac),
TAG_END());
SIPTAG_ACCEPT_REF
#define SIPTAG_ACCEPT_REF(x)
sip_accept_t
struct sip_accept_s sip_accept_t
sip_event_t
struct sip_event_s sip_event_t
SIPTAG_EVENT_REF
#define SIPTAG_EVENT_REF(x)
tl_gets
int tl_gets(tagi_t const lst[], tag_type_t, tag_value_t,...)

# SIP/NUA tutorial

This section describes basic usage scenarios of NUA/Sofia stack using message sequence charts.

## Outgoing Call

## Incoming Call

## Basic Outgoing Operation

## Basic Incoming Operation

## Outgoing Operation with Authentication

# Simple Application

The following sections will present code examples from a simple application that uses services of NUA. The example is not complete but should present all relevant details of the basic use of NUA.

On sourceforge.net there is available an example application sofisip_cli.c that can be studied for more complete example.

## Data Structures & Defines

An application using services of NUA normally defines data areas that are used to store context information (i.e., "magic"). The types of pointers to these context information areas are passed to NUA by defines.

/* type for application context data */
typedef struct application application;
#define NUA_MAGIC_T application
/* type for operation context data */
typedef union oper_ctx_u oper_ctx_t;
#define NUA_HMAGIC_T oper_ctx_t

The information area contents themselves can be defined as C structures or unions:

/* example of application context information structure */
typedef struct application
{
su_home_t home[1]; /* memory home */
su_root_t *root; /* root object */
nua_t *nua; /* NUA stack object */
/* other data as needed ... */
} application;
/* Example of operation handle context information structure */
typedef union operation
{
nua_handle_t *handle; /* operation handle /
struct
{
nua_handle_t *handle; /* operation handle /
... /* call-related information */
} call;
struct
{
nua_handle_t *handle; /* operation handle /
... /* subscription-related information */
} subscription;
/* other data as needed ... */
} operation;
nua_handle_t
struct nua_handle_s nua_handle_t
NUA transaction handle.
Definition nua_tag.h:66
nua_t
struct nua_s nua_t
NUA agent.
Definition nua_tag.h:63
su_home_t
SU_HOME_T su_home_t
su_root_t
struct su_root_t su_root_t

NUA stack object and handle are opaque to the application programmer. Likewise, the application context is completely opaque to the NUA stack module. NUA functions are passed a pointer, and that pointer is then given back to the application within the callback parameters. In this case the application context information structure is also used to store a root object and memory home for memory handling. The application context information also contains the NUA stack object information.

## Initialization and deinitialization

The following code is an example of application function that initializes the system, enters the main loop for processing the messages, and, after message processing is ended, deinitalizes the system.

If the application is not just responding to incoming SIP messages there must also be means to send messages to NUA. This can be handled for example by having a separate thread that calls NUA functions to send messages or by having a socket connection to the application for sending commands to the application (see documentation of su_wait_create() and su_root_register()).

/* Application context structure */
application appl[1] = {{{{(sizeof appl)}}}};
/* initialize system utilities */
su_init();
/* initialize memory handling */
su_home_init(appl->home);
/* initialize root object */
appl->root = su_root_create(appl);
if (appl->root != NULL) {
/* create NUA stack */
appl->nua = nua_create(appl->root,
app_callback,
appl,
/* tags as necessary ...*/
TAG_NULL());
if (appl->nua != NULL) {
/* set necessary parameters */
nua_set_params(appl->nua,
/* tags as necessary ... */
TAG_NULL());
/* enter main loop for processing of messages */
su_root_run(appl->root);
/* destroy NUA stack */
nua_destroy(appl->nua);
}
/* deinit root object */
su_root_destroy(appl->root);
appl->root = NULL;
}
/* deinitialize memory handling */
su_home_deinit(appl->home);
/* deinitialize system utilities */
su_deinit();
nua_create
nua_t * nua_create(su_root_t *root, nua_callback_f callback, nua_magic_t *magic, tag_type_t tag, tag_value_t value,...)
Create a NUA agent.
Definition nua.c:131
nua_set_params
void nua_set_params(nua_t *, tag_type_t, tag_value_t,...)
Set NUA parameters.
Definition nua.c:570
nua_destroy
void nua_destroy(nua_t *nua)
Destroy the NUA stack.
Definition nua.c:216
su_deinit
void su_deinit(void)
su_init
int su_init(void)
su_home_deinit
void su_home_deinit(su_home_t *h)
su_home_init
int su_home_init(su_home_t *h)
su_root_destroy
void su_root_destroy(su_root_t *)
su_root_run
void su_root_run(su_root_t *root)
su_root_create
su_root_t * su_root_create(su_root_magic_t *magic))

## Handling events

Handling of the events coming from NUA stack is done in the callback function that is registered for NUA stack with the nua_create() function when the application is initialized. The content of callback function is in its simplest form just a switch/case statement that dispatches the incoming events for processing to separate functions.

void app_callback(nua_event_t event,
int status,
char const *phrase,
nua_t *nua,
nua_magic_t *magic,
nua_handle_t *nh,
nua_hmagic_t *hmagic,
sip_t const *sip,
tagi_t tags[])
{
switch (event) {
case nua_i_invite:
app_i_invite(status, phrase, nua, magic, nh, hmagic, sip, tags);
break;
case nua_r_invite:
app_r_invite(status, phrase, nua, magic, nh, hmagic, sip, tags);
break;
/* and so on ... */
default:
/* unknown event -> print out error message */
if (status > 100) {
printf("unknown event %d: %03d %s\n",
event,
status,
phrase);
}
else {
printf("unknown event %d\n", event);
}
tl_print(stdout, "", tags);
break;
}
} /* app_callback */
tl_print
void tl_print(FILE *f, char const *title, tagi_t const lst[])
nua_hmagic_t
NUA_HMAGIC_T nua_hmagic_t
Application context for NUA handle.
Definition nua.h:66
nua_r_invite
@ nua_r_invite
Answer to outgoing INVITE.
Definition nua.h:129
nua_i_invite
@ nua_i_invite
Incoming call INVITE.
Definition nua.h:90
nua_magic_t
NUA_MAGIC_T nua_magic_t
Application context for NUA agent.
Definition nua.h:60
nua_event_t
enum nua_event_e nua_event_t
Events.
sip_t
struct sip_s sip_t
tagi_t

## Place a call

The following three functions show an example of how a basic SIP call is created.

The place_a_call() function creates an operation handle and invokes the SIP INVITE method.

operation *place_a_call(char const *name, url_t const *url)
{
operation *op;
sip_to_t *to;
/* create operation context information */
op = su_zalloc(appl->home, (sizeof *op));
if (!op)
return NULL;
/* Destination address */
to = sip_to_create(NULL, url);
if (!to)
return NULL;
to->a_display = name;
/* create operation handle */
op->handle = nua_handle(appl->nua, op, SIPTAG_TO(to), TAG_END());
if (op->handle == NULL) {
printf("cannot create operation handle\n");
return NULL;
}
nua_invite(op->handle,
/* other tags as needed ... */
TAG_END());
} /* place_a_call */
sip_to_t
struct sip_addr_s sip_to_t
SIPTAG_TO
#define SIPTAG_TO(x)
sip_to_create
sip_to_t * sip_to_create(su_home_t *, url_string_t const *url)
nua_handle
nua_handle_t * nua_handle(nua_t *nua, nua_hmagic_t *hmagic, tag_type_t, tag_value_t,...)
Create an operation handle.
Definition nua.c:305
nua_invite
void nua_invite(nua_handle_t *nh, tag_type_t, tag_value_t,...)
Place a call using SIP INVITE method.
Definition nua.c:631
sip_addr_s::a_display
char const * a_display
url_t
su_zalloc
void * su_zalloc(su_home_t *h, isize_t size))

The app_r_invite() function is called by callback function when response to INVITE message is received. Here it is assumed that automatic acknowledge is not enabled so ACK response must be sent explicitly.

void app_r_invite(int status,
char const *phrase,
nua_t *nua,
nua_magic_t *magic,
nua_handle_t *nh,
nua_hmagic_t *hmagic,
sip_t const *sip,
tagi_t tags[])
{
if (status == 200) {
nua_ack(nh, TAG_END());
}
else {
printf("response to INVITE: %03d %s\n", status, phrase);
}
} /* app_r_invite */
nua_ack
void nua_ack(nua_handle_t *nh, tag_type_t, tag_value_t,...)
Acknowledge a succesfull response to INVITE request.
Definition nua.c:637

The nua_i_state event is sent (and app_i_state() function called by callback function) when the call state changes (see client-side call model).

void app_i_state(int status,
char const *phrase,
nua_t *nua,
nua_magic_t *magic,
nua_handle_t *nh,
nua_hmagic_t *hmagic,
sip_t const *sip,
tagi_t tags[])
{
nua_callstate_t state = nua_callstate_init;
tl_gets(tags,
NUTAG_CALLSTATE_REF(state),
NUTAG__REF(state),
state = (nua_callstate_t)t->t_value;
printf("call %s\n", nua_callstate_name(state));
} /* app_i_state */
nua_callstate_name
char const * nua_callstate_name(enum nua_callstate state)
Get name for NUA callstate.
Definition nua_common.c:383
nua_callstate_init
@ nua_callstate_init
Initial state.
Definition nua_tag.h:499
NUTAG_CALLSTATE_REF
#define NUTAG_CALLSTATE_REF(x)
Reference tag for NUTAG_CALLSTATE().
Definition nua_tag.h:495

## Receive a call

The app_i_invite() function is called by callback function when incoming INVITE message is received. This example assumes that autoanswer is not enabled so the response must be sent explicitly.

void app_i_invite(int status,
char const *phrase,
nua_t *nua,
nua_magic_t *magic,
nua_handle_t *nh,
nua_hmagic_t *hmagic,
sip_t const *sip,
tagi_t tags[])
{
printf("incoming call\n");
nua_respond(nh, 200, "OK", SOA_USER_SDP(magic->sdp), TAG_END());
} /* app_i_invite */
nua_respond
void nua_respond(nua_handle_t *nh, int status, char const *phrase, tag_type_t, tag_value_t,...)
Respond to a request with given status code and phrase.
Definition nua.c:874

The app_i_state() function is called by the callback function when call has been successfully set up and the media has been activated.

void app_i_active(int status,
char const *phrase,
nua_t *nua,
nua_magic_t *magic,
nua_handle_t *nh,
nua_hmagic_t *hmagic,
sip_t const *sip,
tagi_t tags[])
{
printf("call active\n");
} /* app_i_active */

## Terminating a call

The following three functions show an example of how a basic SIP call is terminated.

The terminate_call() function sends the SIP BYE message.

void terminate_call(void)
{
nua_bye(op->handle, TAG_END());
} /* terminate call */
nua_bye
void nua_bye(nua_handle_t *, tag_type_t, tag_value_t,...)
Hangdown a call.
Definition nua.c:643

The app_r_bye() function is called by the callback function when answer to the BYE message is received. The function destroys the call handle and releases the memory allocated to operation context information.

void app_r_bye(int status,
char const *phrase,
nua_t *nua,
nua_magic_t *magic,
nua_handle_t *nh,
nua_hmagic_t *hmagic,
sip_t const *sip,
tagi_t tags[])
{
if (status < 200)
return;
printf("call released\n");
/* release operation handle */
nua_handle_destroy(hmagic->handle);
op->handle = NULL;
/* release operation context information */
su_free(appl->home, hmagic);
} /* app_r_bye */
nua_handle_destroy
void nua_handle_destroy(nua_handle_t *h)
Destroy a handle.
Definition nua.c:919
su_free
void su_free(su_home_t *h, void *)

The app_i_bye() function is called by the callback function when an incoming BYE message is received. The function destroys the call handle and releases the memory allocated to operation context information.

void app_i_bye(int status,
char const *phrase,
nua_t *nua,
nua_magic_t *magic,
nua_handle_t *nh,
nua_hmagic_t *hmagic,
sip_t const *sip,
tagi_t tags[])
{
printf("call released\n");
/* release operation handle */
nua_handle_destroy(hmagic->handle);
op->handle = NULL;
/* release operation context information */
su_free(appl->home, hmagic);
} /* app_i_bye */

## Sending a message

The following functions show an example of how a SIP MESSAGE is sent.

The send_message() function sends the SIP MESSAGE.

void send_message(void)
{
op_t *op;
/* create operation context information */
op = su_zalloc(appl->home, sizeof(op_t));
if (op = NULL) {
printf("cannot create operation context information\n");
return;
}
/* how we create destination_address? */
/* create operation handle */
op->handle = nua_handle(appl->nua,
op,
NUTAG_URL(destination_address),
TAG_END());
if (op->handle == NULL) {
printf("cannot create operation handle\n");
return;
}
/* send MESSAGE */
nua_message(op->handle,
SIPTAG_CONTENT_TYPE_STR("text/plain"),
SIPTAG_PAYLOAD_STR("Hello, world!"),
/* other tags as needed ... */
TAG_END());
} /* send_message */
SIPTAG_CONTENT_TYPE_STR
#define SIPTAG_CONTENT_TYPE_STR(s)
SIPTAG_PAYLOAD_STR
#define SIPTAG_PAYLOAD_STR(s)
nua_message
void nua_message(nua_handle_t *nh, tag_type_t, tag_value_t,...)
Send an instant message.
Definition nua.c:661
NUTAG_URL
#define NUTAG_URL(x)
URL address from application to NUA.
Definition nua_tag.h:75

The app_r_message() function is called by the callback function when answer to the MESSAGE is received.

void app_r_message(int status,
char const *phrase,
nua_t *nua,
nua_magic_t *magic,
nua_handle_t *nh,
nua_hmagic_t *hmagic,
sip_t const *sip,
tagi_t tags[])
{
printf("response to MESSAGE: %03d %s\n", status, phrase);
} /* app_r_message */

## Receiving a message

The following function shows an example of how a SIP MESSAGE is received.

The app_i_message() function is called by the callback function when a SIP MESSAGE is received.

void app_i_message(int status,
char const *phrase,
nua_t *nua,
nua_magic_t *magic,
nua_handle_t *nh,
nua_hmagic_t *hmagic,
sip_t const *sip,
tagi_t tags[])
{
printf("received MESSAGE: %03d %s\n", status, phrase);
printf("From: %s%s" URL_PRINT_FORMAT "\n",
sip->sip_from->a_display ? sip->sip_from->a_display : "",
sip->sip_from->a_display ? " " : "",
URL_PRINT_ARGS(sip->sip_from->a_url));
if (sip->sip_subject) {
printf("Subject: %s\n", sip->sip_subject->g_value);
}
if (sip->sip_payload) {
fwrite(sip->sip_payload->pl_data, sip->sip_payload->pl_len, 1, stdout);
fputs("\n", stdout);
}
} /* app_i_message */
msg_payload_s::pl_len
usize_t pl_len
msg_payload_s::pl_data
char * pl_data
sip_addr_s::a_url
url_t a_url[1]
sip_s::sip_from
sip_from_t * sip_from
sip_s::sip_payload
sip_payload_t * sip_payload
sip_s::sip_subject
sip_subject_t * sip_subject
URL_PRINT_FORMAT
#define URL_PRINT_FORMAT
URL_PRINT_ARGS
#define URL_PRINT_ARGS(u)

## Creating a Presence Server

...
application_t *app;
operation_t *oper;
...
oper->app = app;
app->nua = nua_create(ssip->s_root,
app_callback,
app,
TAG_NULL());
...
oper->handle = nua_handle(app->nua, app,
NUTAG_URL(to->a_url),
SIPTAG_TO(to),
ta_tags(ta));
...
nua_notifier(oper->handle,
SIPTAG_EXPIRES_STR("3600"),
SIPTAG_EVENT_STR("presence"),
SIPTAG_CONTENT_TYPE_STR("application/pidf-partial+xml"),
NUTAG_SUBSTATE(nua_substate_pending),
TAG_END());
nua_notifier
void nua_notifier(nua_handle_t *, tag_type_t, tag_value_t,...)
Create an event server.
Definition nua.c:745
nua_substate_pending
@ nua_substate_pending
Pending subscription.
Definition nua_tag.h:526
NUTAG_SUBSTATE
#define NUTAG_SUBSTATE(x)
Subscription state.
Definition nua_tag.h:515
ta_tags
#define ta_tags(ta)

After the nua_notifier object – the presence server – is created, an event nua_r_notifier is returned. Status and phrase values of the app_callback function indicate the success of the creation.

Authorization of an incoming subscription (to the local presence server) can be handled in the callback function.

void app_callback(nua_event_t event,
int status, char const *phrase,
nua_t *nua, application_t *app,
nua_handle_t *nh, oper_t *op,
sip_t const *sip, tagi_t tags[])
{
nea_sub_t *subscriber = NULL;
switch (event) {
case nua_i_subscription:
tl_gets(tags,
NEATAG_SUB_REF(subscriber),
TAG_END());
nua_authorize(nua_substate_active);
default:
break;
}
nea_sub_t
struct nea_sub_s nea_sub_t
nua_authorize
void nua_authorize(nua_handle_t *, tag_type_t, tag_value_t,...)
Authorize a subscriber.
Definition nua.c:861
nua_i_subscription
@ nua_i_subscription
Incoming subscription to be authorized.
Definition nua.h:110
nua_substate_active
@ nua_substate_active
Active subscription.
Definition nua_tag.h:527

## Shutdown

The following functions show an example of how application terminates the NUA stack.

The shutdown() function starts the termination.

void shutdown(void)
{
nua_shutdown(appl->nua);
} /* shutdown */
nua_shutdown
void nua_shutdown(nua_t *nua)
Shutdown NUA stack.
Definition nua.c:187

The app_r_shutdown() function is called by the callback function when NUA stack termination is either finished or failed.

void app_r_shutdown(int status,
char const *phrase,
nua_t *nua,
nua_magic_t *magic,
nua_handle_t *nh,
nua_hmagic_t *hmagic,
sip_t const *sip,
tagi_t tags[])
{
printf("shutdown: %d %s\n", status, phrase);
if (status < 200) {
/* shutdown in progress -> return */
return;
}
/* end the event loop. su_root_run() will return */
su_root_break(magic->root);
} /* app_r_shutdown */
su_root_break
void su_root_break(su_root_t *root)

Sofia-SIP 1.12.11devel - Copyright (C) 2006 Nokia Corporation. All rights reserved. Licensed under the terms of the GNU Lesser General Public License.