WARNING: The online documentation has moved to https://docs.pjsip.org.

Visit the new documentation at https://docs.pjsip.org:

BLOG | DOCUMENTATION | GITHUB

Home --> Documentations --> PJSIP Reference

SIP Replaces support (RFC 3891 - "Replaces" Header)

SIP Replaces support (RFC 3891 - "Replaces" Header) More...

Data Structures

struct  pjsip_replaces_hdr
 

Functions

pj_status_t pjsip_replaces_init_module (pjsip_endpoint *endpt)
 
pjsip_replaces_hdrpjsip_replaces_hdr_create (pj_pool_t *pool)
 
pj_status_t pjsip_replaces_verify_request (pjsip_rx_data *rdata, pjsip_dialog **p_dlg, pj_bool_t lock_dlg, pjsip_tx_data **p_tdata)
 

Detailed Description

This module implements support for Replaces header in PJSIP. The Replaces specification is written in RFC 3891 - The Session Initiation Protocol (SIP) "Replaces" Header, and can be used to enable a variety of features, for example: "Attended Transfer" and "Call Pickup".

Using PJSIP Replaces Support

Initialization

Application needs to call pjsip_replaces_init_module() during application initialization stage to register "replaces" support in PJSIP.

UAC Behavior: Sending a Replaces Header

A User Agent that wishes to replace a single existing early or confirmed dialog with a new dialog of its own, MAY send the target User Agent an INVITE request containing a Replaces header field. The User Agent Client (UAC) places the Call-ID, to-tag, and from-tag information for the target dialog in a single Replaces header field and sends the new INVITE to the target.

To initiate outgoing INVITE request with Replaces header, application would create the INVITE request with pjsip_inv_invite(), then adds pjsip_replaces_hdr instance into the request, filling up the Call-ID, To-tag, and From-tag properties of the header with the identification of the dialog to be replaced. Application may also optionally set the early_only property of the header to indicate that it only wants to replace early dialog.

Note that when the outgoing INVITE request (with Replaces) is initiated from an incoming REFER request (as in Attended Call Transfer case), this process should be done rather more automatically by PJSIP. Upon receiving incoming incoming REFER request, normally these processes will be performed:

  • Application finds Refer-To header,
  • Application creates outgoing dialog/invite session, specifying the URI in the Refer-To header as the initial remote target,
  • The URI in the Refer-To header may contain header parameters such as Replaces and Require headers.
  • The dialog keeps the header fields in the header parameters of the URI, and the invite session would add these headers into the outgoing INVITE request. Because of this, the outgoing INVITE request will contain the Replaces and Require headers.

For more information, please see the implementation of pjsua_call_xfer_replaces() in PJSUA API - High Level Softphone API source code.

UAS Behavior: Receiving a Replaces Header

The Replaces header contains information used to match an existing SIP dialog (call-id, to-tag, and from-tag). Upon receiving an INVITE with a Replaces header, the User Agent (UA) attempts to match this information with a confirmed or early dialog.

In PJSIP, if application wants to process the Replaces header in the incoming INVITE request, it should call pjsip_replaces_verify_request() before creating the INVITE session. The pjsip_replaces_verify_request() function checks and verifies the request to see if Replaces request can be processed. To be more specific, it performs the following verification:

  • checks that Replaces header is present. If not, the function will return PJ_SUCCESS without doing anything.
  • checks that no duplicate Replaces headers are present, or otherwise it will return 400 "Bad Request" response.
  • checks for matching dialog and verifies that the invite session has the correct state, and may return 481 "Call/Transaction Does Not Exist", 603 "Declined", or 486 "Busy Here" according to the processing rules specified in RFC 3891.
  • if matching dialog with correct state is found, it will give PJ_SUCCESS status and return the matching dialog back to the application.

The following pseudocode illustrates how application can process the incoming INVITE if it wants to support Replaces extension:

// Incoming INVITE request handler
pj_bool_t on_rx_invite(pjsip_rx_data *rdata)
{
pjsip_dialog *dlg, *replaced_dlg;
pjsip_tx_data *response;
pj_status_t status;
// Check whether Replaces header is present in the request and process accordingly.
//
status = pjsip_replaces_verify_request(rdata, &replaced_dlg, PJ_FALSE, &response);
if (status != PJ_SUCCESS) {
// Something wrong with Replaces request.
//
pj_status_t status;
if (response) {
status = pjsip_endpt_send_response(endpt, rdata, response, NULL, NULL);
if (status != PJ_SUCCESS) pjsip_tx_data_dec_ref(tdata);
} else {
// Respond with 500 (Internal Server Error)
status = pjsip_endpt_respond_stateless(endpt, rdata, 500, NULL, NULL, NULL);
if (status != PJ_SUCCESS) pjsip_tx_data_dec_ref(tdata);
}
}
// Create UAS Invite session as usual.
//
status = pjsip_dlg_create_uas_and_inc_lock(.., rdata, .., &dlg);
..
status = pjsip_inv_create_uas(dlg, .., &inv);
// Send initial 100 "Trying" to the INVITE request
//
status = pjsip_inv_initial_answer(inv, rdata, 100, ..., &response);
if (status == PJ_SUCCESS)
pjsip_inv_send_msg(inv, response);
// This is where processing is different between normal call
// (without Replaces) and call with Replaces.
//
if (replaced_dlg) {
pjsip_inv_session *replaced_inv;
// Always answer the new INVITE with 200, regardless whether
// the replaced call is in early or confirmed state.
//
status = pjsip_inv_answer(inv, 200, NULL, NULL, &response);
if (status == PJ_SUCCESS)
pjsip_inv_send_msg(inv, response);
// Get the INVITE session associated with the replaced dialog.
//
replaced_inv = pjsip_dlg_get_inv_session(replaced_dlg);
// Disconnect the "replaced" INVITE session.
//
status = pjsip_inv_end_session(replaced_inv, PJSIP_SC_GONE, NULL, &tdata);
if (status == PJ_SUCCESS && tdata)
status = pjsip_inv_send_msg(replaced_inv, tdata);
// It's up to application to associate the new INVITE session
// with the old (now terminated) session. For example, application
// may assign the same User Interface object for the new INVITE
// session.
} else {
// Process normal INVITE without Replaces.
...
}
}
pj_status_t pjsip_dlg_create_uas_and_inc_lock(pjsip_user_agent *ua, pjsip_rx_data *rdata, const pj_str_t *contact, pjsip_dialog **p_dlg)
pj_status_t pjsip_endpt_respond_stateless(pjsip_endpoint *endpt, pjsip_rx_data *rdata, int st_code, const pj_str_t *st_text, const pjsip_hdr *hdr_list, const pjsip_msg_body *body)
pj_status_t pjsip_endpt_send_response(pjsip_endpoint *endpt, pjsip_response_addr *res_addr, pjsip_tx_data *tdata, void *token, pjsip_send_callback cb)
pj_status_t pjsip_inv_send_msg(pjsip_inv_session *inv, pjsip_tx_data *tdata)
pj_status_t pjsip_inv_end_session(pjsip_inv_session *inv, int st_code, const pj_str_t *st_text, pjsip_tx_data **p_tdata)
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 **p_inv)
pj_status_t pjsip_inv_initial_answer(pjsip_inv_session *inv, pjsip_rx_data *rdata, int st_code, const pj_str_t *st_text, const pjmedia_sdp_session *sdp, pjsip_tx_data **p_tdata)
pjsip_inv_session * pjsip_dlg_get_inv_session(pjsip_dialog *dlg)
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 **p_tdata)
pj_status_t pjsip_replaces_verify_request(pjsip_rx_data *rdata, pjsip_dialog **p_dlg, pj_bool_t lock_dlg, pjsip_tx_data **p_tdata)
pj_status_t pjsip_tx_data_dec_ref(pjsip_tx_data *tdata)
int pj_bool_t
int pj_status_t
PJ_SUCCESS
PJ_FALSE
Definition: sip_dialog.h:136
Definition: sip_inv.h:431
Definition: sip_transport.h:295
Definition: sip_transport.h:522

For a complete sample implementation, please see pjsua_call_on_incoming() function of PJSUA API - High Level Softphone API in pjsua_call.c file.

References

References:

Function Documentation

◆ pjsip_replaces_init_module()

pj_status_t pjsip_replaces_init_module ( pjsip_endpoint endpt)

Initialize Replaces support in PJSIP. This would, among other things, register the header parser for Replaces header.

Parameters
endptThe endpoint instance.
Returns
PJ_SUCCESS on success.

◆ pjsip_replaces_hdr_create()

pjsip_replaces_hdr * pjsip_replaces_hdr_create ( pj_pool_t pool)

Create Replaces header.

Parameters
poolPool to allocate the header instance from.
Returns
An empty Replaces header instance.

◆ pjsip_replaces_verify_request()

pj_status_t pjsip_replaces_verify_request ( pjsip_rx_data rdata,
pjsip_dialog **  p_dlg,
pj_bool_t  lock_dlg,
pjsip_tx_data **  p_tdata 
)

Verify that incoming request with Replaces header can be processed. This function will perform all necessary checks according to RFC 3891 Section 3 "User Agent Server Behavior: Receiving a Replaces Header".

Parameters
rdataThe incoming request to be verified.
p_dlgOn return, it will be filled with the matching dialog.
lock_dlgSpecifies whether this function should acquire lock to the matching dialog. If yes (and should be yes!), then application will need to release the dialog's lock with pjsip_dlg_dec_lock() when the function returns PJ_SUCCESS and the p_dlg parameter is filled with the dialog instance.
p_tdataUpon error, it will be filled with the final response to be sent to the request sender.
Returns
The function returns the following:
  • If the request doesn't contain Replaces header, the function returns PJ_SUCCESS and p_dlg parameter will be set to NULL.
  • If the request contains Replaces header and a valid, matching dialog is found, the function returns PJ_SUCCESS and p_dlg parameter will be set to the matching dialog instance.
  • Upon error condition (as described by RFC 3891), the function returns non-PJ_SUCCESS, and p_tdata parameter SHOULD be set with a final response message to be sent to the sender of the request.

References PJ_END_DECL.

 


PJSIP Open Source, high performance, small footprint, and very very portable SIP stack
Copyright (C) 2006-2008 Teluu Inc.