wiki:SIP_Message_Buffer_Event

Version 2 (modified by bennylp, 11 years ago) (diff)

--

Message, Buffers, and Event

SIP message (request or response) is represented by pjsip_msg structure, but application would rarely see this structure passed directly in the API. For incoming and outgoing messages, the message would be contained in a RX or TX data buffer, pjsip_rx_data and pjsip_tx_data respectively. When passing SIP messages among modules, PJSIP also normally does not pass the buffers directly, but rather encapsulate it as pjsip_event structure.

The pjsip_event is PJSIP's way to represent any known SIP event types, such as:

  • arrival of SIP message
  • transmission of SIP message
  • transaction timeout event
  • transport error
  • and so on

For detailed information about SIP messaging and RX/TX buffer design in PJSIP, please read the PJSIP Developer's Guide PDF (also known as PJSIP Bible ;-)) in PJSIP Documentation page.


pjsip_event

pjsip_event structure mainly consists of two main member:

  • pjsip_event.type shows the event type
  • pjsip_event.body contains the data describing the event. This member is a C union, and which data to be extracted from the union depends on the event type.

pjsip_event Structure

typedef enum pjsip_event_id_e
{
    PJSIP_EVENT_UNKNOWN,         /** Unidentified event. */
    PJSIP_EVENT_TIMER,           /** Timer event, normally only used internally in transaction. */
    PJSIP_EVENT_TX_MSG,          /** Message transmission event. */
    PJSIP_EVENT_RX_MSG,          /** Message received event. */
    PJSIP_EVENT_TRANSPORT_ERROR, /** Transport error event. */
    PJSIP_EVENT_TSX_STATE,       /** Transaction state changed event. */
    PJSIP_EVENT_USER             /** Indicates that the event was triggered by user action. */
} pjsip_event_id_e;


struct pjsip_event
{
    /** This is necessary so that we can put events as a list. */
    PJ_DECL_LIST_MEMBER(struct pjsip_event);

    /** The event type */
    pjsip_event_id_e type;

    /** The event body as union, which fields depends on the event type. */
    union {
        /** Timer event. */
        struct {
            pj_timer_entry *entry;      /**< The timer entry.           */
        } timer;

        /** Transaction state has changed event. */
        struct {
            union {
                pjsip_rx_data   *rdata; /**< The incoming message.      */
                pjsip_tx_data   *tdata; /**< The outgoing message.      */
                pj_timer_entry  *timer; /**< The timer.                 */
                pj_status_t      status;/**< Transport error status.    */
                void            *data;  /**< Generic data.              */
            } src;
            pjsip_transaction   *tsx;   /**< The transaction.           */
	    int			 prev_state; /**< Previous state.	*/
            pjsip_event_id_e     type;  /**< Type of event source:      */
        } tsx_state;

        /** Message transmission event. */
        struct {
            pjsip_tx_data       *tdata; /**< The transmit data buffer.  */
        } tx_msg;

        /** Transmission error event. */
        struct {
            pjsip_tx_data       *tdata; /**< The transmit data.         */
            pjsip_transaction   *tsx;   /**< The transaction.           */
        } tx_error;

        /** Message arrival event. */
        struct {
            pjsip_rx_data       *rdata; /**< The receive data buffer.   */
        } rx_msg;

        /** User event. */
        struct {
            void                *user1; /**< User data 1.               */
            void                *user2; /**< User data 2.               */
            void                *user3; /**< User data 3.               */
            void                *user4; /**< User data 4.               */
        } user;

    } body;
};

Events

This section describes various event types and what relevant data can be extracted from the event.

Timer Event

Type: PJSIP_EVENT_TIMER
Data: event.body.timer contains the timer entry
Description: The timer event is emitted when a scheduled timer has elapsed. It is only used internally in transaction layer, and it will never reach application

RX Message Event

Type: PJSIP_EVENT_RX_MSG
Data: event.body.rx_msg contains pjsip_rx_data
Description: The RX message event is emitted by the transport layer upon arrival of a packet and after the packet is parsed successfully. The transport layer then hand over this event to pjsip_endpoint which will distribute this event to all registered modules. An application (which is a module in PJSIP) only receives this event for SIP messages that are outside any transactions. For SIP messages belonging to a transaction, the transaction layer would have filtered this event (thus it will not reach dialog or application layer), and the event will be forwarded to upper layer as Transaction State Progression event instead (see below).

TX Message Event

Type: PJSIP_EVENT_TX_MSG
Data: event.body.tx_msg contains pjsip_tx_data
Description: This event represents transmission of outgoing message.

Transmission Error Event

Type: PJSIP_EVENT_TRANSPORT_ERROR
Data: event.body.tx_error contains the pjsip_tx_data that failed to be sent and optionally the transaction that sent the message
Description: This event is only used internally in PJSIP, and it will never reach application.

Transaction State Progression Event

Type: PJSIP_EVENT_TSX_STATE
Data: event.body.tsx_state contains description about the state progression (see below)
Description: This event is emitted by SIP transaction to notify the transaction user that the transaction state has changed. If the transaction user is a dialog, the dialog will also notify the dialog usages (such as invite session or presence subscription), and the dialog usage may further notify the application about the state change.

This event is the most common event seen by application. Various callbacks in PJSIP that emit this event:

  • In PJSUA-API: on_call_state() and on_call_tsx_state() callbacks
  • In invite session layer: on_state_changed(), on_new_session(), and on_tsx_state_changed()
  • In SIMPLE/presence layer: on_evsub_state() and on_tsx_state() callbacks

The event.body.tsx_state contains these fields:

  • tsx: the transaction which state has changed
  • prev_state: the previous transaction state
  • type: the type of event that caused the transaction state to change (arrival of message, timeout event, etc.)
  • src: a union containing further data associated with the event that caused the transaction state change.

Application can inspect the original event that caused the transaction state to change by inspecting the type and src fields as described above. The relationship between type and src fields are as follows.

Incoming message::

If transaction changed state because of incoming message:

Outgoing transmission::

If transaction changed state because of outgoing transmission:

Timer event::

If transaction changed state because of (timeout) timer event:

  • type: PJSIP_EVENT_TIMER
  • src: src.timer contains the timer entry

Transport error::

If transaction changed state because of transport error:

  • type: PJSIP_EVENT_TRANSPORT_ERROR
  • src: src.status contains the transport error status

User Event

Type: PJSIP_EVENT_USER
Data: event.body.user contains user data
Description: Currently this is not used

Getting the SIP Message from pjsip_event

Before we can get the SIP message, first we need to get the pjsip_rx_data or pjsip_tx_data, depending on whether the event is related to receipt or transmission of SIP message.

Retrieving SIP Message from an Incoming Message

First we need to extract pjsip_rx_data from the event:

static pjsip_rx_data *get_rx_data(pjsip_event *e)
{
   if (e->type == PJSIP_EVENT_RX_MSG)
      return e->body.rx_msg.rdata;

   if (e->type == PJSIP_EVENT_TSX_STATE && e->body.tsx_state.type == PJSIP_EVENT_RX_MSG)
      return e->body.tsx_state.src.rdata;
   
   // There's no rdata on this eevnt
   return NULL;
}

Once we get the pjsip_rx_data, we can extract the SIP message:

   pjsip_msg *msg = rdata->msg_info.msg;

Retrieving SIP Message from an Outgoing Message

First we need to extract pjsip_tx_data from the arbitrary event:

static pjsip_rx_data *get_tx_data(pjsip_event *e)
{
   if (e->type == PJSIP_EVENT_TX_MSG)
      return e->body.tx_msg.tdata;

   if (e->type == PJSIP_EVENT_TSX_STATE && e->body.tsx_state.type == PJSIP_EVENT_TX_MSG)
      return e->body.tsx_state.src.tdata;
   
   // There's no tdata on this eevnt
   return NULL;
}

Once we get the pjsip_tx_data, we can extract the SIP message:

   pjsip_msg *msg = tdata->msg;

Manipulating the SIP Message

Below are few snippets on how to manipulate SIP messages. Please see SIP Messaging Elements in PJSIP documentation for the complete documentation.

Processing Request Line

  if (msg->type == PJSIP_REQUEST_MSG) {
     pjsip_method *m = &msg->line.req.method;
     pjsip_uri *uri = msg->line.req.uri;
  }

Processing Status Line

  if (msg->type == PJSIP_RESPONSE_MSG) {
     int code = msg->line.status.code;
     pj_str_t reason = msg->line.status.reason;
  }

Finding a Particular Header

To find header by its type:

  pjsip_contact_hdr *h = (pjsip_contact_hdr*) pjsip_msg_find_hdr(msg, PJSIP_H_CONTACT, NULL);

or to find header by its name:

  const pj_str_t hname = pj_str("Contact");
  pjsip_contact_hdr *h = (pjsip_contact_hdr*) pjsip_msg_find_hdr_by_name(msg, &hname, NULL);

Finding Multiple Headers

To find all Contact headers:

  pjsip_hdr *h;
  
  h = msg->hdr.next;
  while (h != &msg->hdr) {
     if (h->type == PJSIP_H_CONTACT) {
        // h is Contact hdr, do something with it ..
        pjsip_contact_hdr *hc = (pjsip_contact_hdr*)h;
        ...
     }
     h = h->next;
  }

or

  pjsip_hdr *h;

  h = pjsip_msg_find_hdr(msg, PJSIP_H_CONTACT, NULL);
  while (h != NULL) {
    // h is Contact hdr, do something with it ..
    pjsip_contact_hdr *hc = (pjsip_contact_hdr*)h;
    ...

    // find next Contact header after h, only if h is not the last header
    if (h->next == &msg->hdr)
       break;
    h = pjsip_msg_find_hdr(msg, PJSIP_H_CONTACT, h->next);
  }

Adding a Header

  pjsip_hdr *hdr = .. your header ..

  // To add hdr as the last header in msg:
  pjsip_msg_add_hdr(msg, hdr);
  
  // To add hdr as the first header in msg
  //   pjsip_msg_insert_first_hdr(msg, hdr)

  // To add hdr after some header (for example after Content-Type)
  //   pjsip_hdr *hctype = pjsip_msg_find_hdr(msg, PJSIP_H_CONTENT_TYPE, NULL);
  //   if (hctype)
  //        pj_list_insert_after(hctype, hdr);