---- Table of Contents: [[PageOutline(1-3,,inline)]] ---- = Message, Buffers, and Event = SIP message (request or response) is represented by [http://www.pjsip.org/pjsip/docs/html/structpjsip__msg.htm 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, [http://www.pjsip.org/pjsip/docs/html/structpjsip__rx__data.htm pjsip_rx_data] and [http://www.pjsip.org/pjsip/docs/html/structpjsip__tx__data.htm pjsip_tx_data] respectively. When passing SIP messages among modules, PJSIP also normally does not pass the buffer directly, but rather encapsulate it as [http://www.pjsip.org/pjsip/docs/html/structpjsip__event.htm pjsip_event] structure. Because of these multi-encapsulations, extracting a particular information from a particular structure can be daunting, especially if you haven't read the PJSIP Bible (the PJSIP Developer's Guide PDF, from [http://www.pjsip.org/docs.htm PJSIP Documentation] page). This article presents a short description about these structures to help you get started quickly. == SIP Message (pjsip_msg) == The [http://www.pjsip.org/pjsip/docs/html/structpjsip__msg.htm pjsip_msg] structure corresponds directly to SIP messaging elements as described by the SIP protocol specification, [http://www.ietf.org/rfc/rfc3261.txt RFC 3261]. It contains: * SIP message type (request or response), * SIP request line or status line, depending on the message type * list of SIP header fields * message body There is nothing else in [http://www.pjsip.org/pjsip/docs/html/structpjsip__msg.htm pjsip_msg]. SIP messaging elements are declared in [source:pjproject/trunk/pjsip/include/pjsip/sip_msg.h ]. == Transmit and Receive Buffers == Incoming and outgoing messages are encapsulated in a RX or TX data buffer, [http://www.pjsip.org/pjsip/docs/html/structpjsip__rx__data.htm pjsip_rx_data] and [http://www.pjsip.org/pjsip/docs/html/structpjsip__tx__data.htm pjsip_tx_data] respectively. We need these buffers since there are more information to be conveyed in incoming and outgoing message than just a plain SIP message structure (and it would not make sense to put these information in the SIP message, since they are not messaging elements). The [http://www.pjsip.org/pjsip/docs/html/structpjsip__rx__data.htm pjsip_rx_data] contains these major parts: * transport info (''tp_info'' field), describing the transport instance which own this buffer. * information about the incoming packet (''pkt_info'' field), such as source address, arrival time, and the packet buffer, * messaging info (''msg_info'' field), containing among other thing the raw message, the parsed [http://www.pjsip.org/pjsip/docs/html/structpjsip__msg.htm pjsip_msg], and shortcuts to important headers, and * modules info (''endpt_info'' field), which will be filled by PJSIP modules as the buffer are processed by them. The [http://www.pjsip.org/pjsip/docs/html/structpjsip__tx__data.htm pjsip_tx_data] contains: * memory pool to allocate memory for this buffer, * the [http://www.pjsip.org/pjsip/docs/html/structpjsip__msg.htm pjsip_msg] itself, * reference counter, * and so on Transmit and receive buffers are declared in [source:pjproject/trunk/pjsip/include/pjsip/sip_transport.h ]. === Memory Management of the RX/TX Buffer === Each RX and TX buffer has its own memory pool ({{{pj_pool_t}}}. It is important to understand how to use the memory pool in these buffers to avoid problems with memory (memory usage keeps growing, or crash because memory no longer valid). '''Memory pool in RX buffer''' The [http://www.pjsip.org/pjsip/docs/html/structpjsip__rx__data.htm pjsip_rx_data] is a temporary object, and it is only valid in the context of the callback. Once the callback returns, this structure will be reset (because of this, you '''cannot''' keep this structure, or pass this structure to another thread for asynchronous processing). The {{{pjsip_rx_data->tp_info.pool}}} points to the memory pool owned by the RX buffer. Characteristics of this pool: - it's quite large (default value is 4000 bytes/PJSIP_POOL_RDATA_LEN, and it can expand), so it can be used to allocate large objects - the pool will be recycled/reset as soon as the callback returns, so any memory allocated from this pool will automatically be released when the callback returns. Because of the characteristics above, the pool is useful to allocate temporary objects related to the incoming message, such as: - to parse the SDP content of the message body. But beware that if you need to store the parsed result for further processing (for example, the invite session needs to store the offer in the incoming INVITE request), you will need to ''clone'' the result, since the pool will be reset upon returning from the callback, thus it will render the result invalid. - to allocate other temporary objects that are only valid during the context of the callback '''Memory pool in TX buffer''' The TX buffer is reference counted. Any objects that need to keep a reference of the TX buffer need to call [http://www.pjsip.org/pjsip/docs/html/group__PJSIP__TRANSPORT.htm#gedc51486a3217528198a6d40651949d5 pjsip_tx_data_add_ref()] to increment the reference counter, and once it has finished with the TX buffer it must call [http://www.pjsip.org/pjsip/docs/html/group__PJSIP__TRANSPORT.htm#gbeec4be34c0a472782b9224c2c7d08f1 pjsip_tx_data_dec_ref()] to decrement the reference counter (for example, the transaction needs to keep the TX buffer for retransmissions). The TX buffer will be destroyed when the reference counter has reached zero. Characteristics of this pool: - it's quite large (default value is 4000 bytes/PJSIP_POOL_TDATA_LEN, and it can expand), so it can be used to allocate large objects - the pool will be destroyed when the TX buffer is destroyed, so any memory allocated from this pool will automatically be released when the TX data is destroyed. Because of the characteristics above, the pool is useful to allocate objects that are valid for the duration of the message, such as: - SIP headers to be put on the message - SIP message body == Event == The [http://www.pjsip.org/pjsip/docs/html/structpjsip__event.htm 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 The [http://www.pjsip.org/pjsip/docs/html/structpjsip__event.htm pjsip_event] usually is a temporary variable allocated from the stack, thus it's pointer MUST NOT be kept for the duration longer than the callback. PJSIP event is declared in [source:pjproject/trunk/pjsip/include/pjsip/sip_event.h ]. More will be explained in the next section. ---- = pjsip_event = pjsip_event structure mainly consists of two main member: - {{{pjsip_event.type}}} shows the [http://www.pjsip.org/pjsip/docs/html/group__PJSIP__EVENT.htm#g887dd71c4680ebf9f85ec69fd87b8399 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 [http://www.pjsip.org/pjsip/docs/html/structpjsip__rx__data.htm 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 [http://www.pjsip.org/pjsip/docs/html/structpjsip__tx__data.htm 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: [http://www.pjsip.org/pjsip/docs/html/structpjsua__callback.htm#06e6135aeaa81b32fdc66fa603a0546c on_call_state()] and [http://www.pjsip.org/pjsip/docs/html/structpjsua__callback.htm#cec485ed428d48a6ca0d28027e5cccde on_call_tsx_state()] callbacks (these callbacks are triggered by the callbacks in the invite session layer below), - In invite session layer: [http://www.pjsip.org/pjsip/docs/html/structpjsip__inv__callback.htm#abf40987d5cb9296a2eea1a10534a061 on_state_changed()], [http://www.pjsip.org/pjsip/docs/html/structpjsip__inv__callback.htm#df8e43e12064218cc3b9312a9c357cf3 on_new_session()], and [http://www.pjsip.org/pjsip/docs/html/structpjsip__inv__callback.htm#cdca7ffb5ac919b3c953c1bd49b4db6f on_tsx_state_changed()] - In SIMPLE/presence layer: [http://www.pjsip.org/pjsip/docs/html/structpjsip__evsub__user.htm#c740cc29b827714ed5bf1cf955a9cc77 on_evsub_state()] and [http://www.pjsip.org/pjsip/docs/html/structpjsip__evsub__user.htm#da78d48ce544373ee897df5da01e27f3 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: - ''type'': PJSIP_EVENT_RX_MSG - ''src'': ''src.rdata'' contains [http://www.pjsip.org/pjsip/docs/html/structpjsip__rx__data.htm pjsip_rx_data] Outgoing transmission:: If transaction changed state because of outgoing transmission: - ''type'': PJSIP_EVENT_TX_MSG - ''src'': ''src.tdata'' contains [http://www.pjsip.org/pjsip/docs/html/structpjsip__tx__data.htm pjsip_tx_data] 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 [http://www.pjsip.org/pjsip/docs/html/structpjsip__rx__data.htm pjsip_rx_data] or [http://www.pjsip.org/pjsip/docs/html/structpjsip__tx__data.htm 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 [http://www.pjsip.org/pjsip/docs/html/structpjsip__rx__data.htm 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 [http://www.pjsip.org/pjsip/docs/html/structpjsip__rx__data.htm 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 [http://www.pjsip.org/pjsip/docs/html/structpjsip__tx__data.htm 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 [http://www.pjsip.org/pjsip/docs/html/structpjsip__tx__data.htm 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 [http://www.pjsip.org/pjsip/docs/html/group__PJSIP__MSG.htm SIP Messaging Elements] in [http://www.pjsip.org/pjsip/docs/html/index.htm 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); }}}