Version 6 (modified by bennylp, 16 years ago) (diff)


Processing Call Redirection (3xx) Response in PJSIP

This article describes SIP redirection support in PJSIP, that is implemented by ticket #10 in release 1.0.1 (December 2008).

The redirection in this article is about processing SIP redirect (3xx) response in outgoing calls, and not about sending redirection/3xx response. Sending 3xx response in PJSUA-LIB is easy; just use pjsua_call_hangup() and give the new targets in Contact header in msg_data parameter.


The redirected call handling is implemented by ticket #10. The objective statements of this work are:

  • must be implemented in PJSIP level rather than PJSUA-LIB level, to allow the usage on non-PJSUA-LIB based applications.
  • must allow application to accept or reject the redirection request on a per-target basis (by means of callback)
  • must allow application to defer the decision to accept or reject the redirection request (for example, to ask for user confirmation to accept or reject the target)
  • the subsequent INVITE requests sent after the 3xx response must have the same To, From, and Call-ID as used by the original INVITE. While RFC 3261 only put this at RECOMMENDED strength (see section, in practice there are many servers out there that relies on this property.

Implementation Details


A new callback was added to the invite session callback (pjsip_inv_callback) in pjsip-ua library:

    void (*on_redirected)(pjsip_inv_session *inv, const pjsip_uri *target,
			  pjsip_redirect_op *cmd, const pjsip_event *e);

Application MUST implement this callback if it wants the invite session to manage redirection. If this callback is not implemented, the invite session will be disconnected upon receipt of 3xx response.

If this callback is implemented, the default behavior (that is when the callback contains no function body) is to follow the redirection.

This callback is called when the invite session is being redirected to a new target. If there are multiple targets, then the callback will be called multiple times, once for each target. This function is called on these events:

  • a 3xx response containing usable Contact header(s) is received
  • a 4xx or 5xx response to subsequent INVITE request is received, and the invite session has at least one more valid target to try. This happens for example when multiple Contact headers (alternate targets) are received for the original INVITE, and 4xx/5xx response is received for the second INVITE (to the first alternate target). The callback then will be called before the invite session tries to send the third INVITE to the second alternate target.

The arguments for this callback are as follows:

The invite session

The current target URI to which the INVITE will be sent to.
Action to be performed. The default value is to accept the redirection. Application can change this to one of the following values:
  • PJSIP_REDIRECT_ACCEPT: immediately accept the redirection (default value upon callback entry). The session will immediately resend INVITE request to the target upon return of this callback.
  • PJSIP_REDIRECT_REJECT: immediately reject this target. The session will continue retrying with next target if present (and it will call this callback again for the next target), or immediately disconnect the call if there is no more target to try (notifying the on_state_changed() callback as usual).
  • PJSIP_REDIRECT_STOP: stop the whole redirection process and immediately disconnect the call, regardless on whether there is other target to try or not (notifying the on_state_changed() callback as usual).
  • PJSIP_REDIRECT_PENDING: set to this value if no decision can be made immediately (for example to request user approval). Application then MUST call pjsip_inv_process_redirect() (see below) to either accept or reject the redirection upon getting user decision.
The event that triggers this callback to be called. This could be of type PJSIP_EVENT_TSX_STATE containing receipt of 3xx, 4xx, or 5xx response, or any other type depending on what is passed to pjsip_inv_process_redirect() below, or of type PJSIP_EVENT_USER if this callback is called by pjsip_inv_process_redirect() below and the event argument to that function is NULL, or NULL.

A new function for the invite session (pjsip_inv_session) was also added:

PJ_DECL(pj_status_t) pjsip_inv_process_redirect(pjsip_inv_session *inv,
						pjsip_redirect_op cmd,
						pjsip_event *e);

This function allows the application to notify the invite session about the result of user confirmation.

The event (e) argument is the event that will be passed to on_redirected() callback when the user rejects the redirection and there is another target to try. When NULL is passed to this argument, then the invite session will create PJSIP_EVENT_USER event with NULL values to pass to the callback.

The redirection usage scenarios will be explained below.

Accept Redirection to This Target

Set the cmd argument of the callback to PJSIP_REDIRECT_ACCEPT to accept the redirection to this target. And INVITE session will be sent immediately to the target.

Reject Redirection to This Target

Set the cmd argument of the callback to PJSIP_REDIRECT_REJECT to reject the redirection to this target. If there is another target to try, then the callback will be called again with this next target, otherwise the invite session will be disconnected immediately.

Stop Redirection

Set the cmd argument of the callback to PJSIP_REDIRECT_STOP to stop the redirection process and disconnect the call immediately, regardless of whether there are more targets to try.

Defer the Decision

Set the cmd argument of the callback to PJSIP_REDIRECT_PENDING to tell the invite session that a decision cannot be made that this time (for example to ask for user approval), and the application will notify the invite session about the decision later.

Once the application decides what to do with the redirection, it MUST call pjsip_inv_process_redirect() function to notify the session about this. It may accept or reject the target, or stop the redirection altogether by setting the appropriate value to the cmd argument. It must not set PJSIP_REDIRECT_PENDING to this argument.

Failure to call pjsip_inv_process_redirect() will cause the invite session to be kept alive indefinitely until the library is shutdown.

When the pjsip_inv_process_redirect() function is called for the next target in the context of this function (that is when this function is called with reject command and next target is selected, hence the callback is called), the event (e) argument passed to this function will be passed down to the callback. And similarly when the disconnect callback is called. If NULL is given to the event argument of this function, this function will create a PJSIP_EVENT_USER event with NULL values, to be passed to the callbacks.

Because of this, application MUST be prepared to handle these type of events in both the on_redirected() and on_state_changed() callbacks. Traditionally only PJSIP_EVENT_TSX_STATE event is passed to on_state_changed() callback.


Similar callback and function were added to PJSUA-LIB:

void (*on_call_redirected)(pjsua_call_id call_id, const pjsip_uri *target,
			   pjsip_redirect_op *cmd, const pjsip_event *e);

PJ_DECL(pj_status_t) pjsua_call_process_redirect(pjsua_call_id call_id,
						 pjsip_redirect_op cmd);

Please see the PJSIP section above on how to use this feature.


The following additions were made to pjsua:

  • new command line argument "--accept-redirect=N", with valid values for N:
    • 0: reject/stop,
    • 1: follow automatically (default),
    • 2: ask
  • the default behavior is to follow redirection automatically
  • when --accept-redirect is set to 2 (ask), user can enter 'Ra', 'Rr', or 'Rd' to accept, reject, or stop/disconnect the redirection.

Open Issues

3xx Response after 183

When 3xx response is received after 183 with SDP response is received, the invite session will treat the SDP answer in the subsequent INVITE as an offer rather than answer. This is because the SDP has been negotiated in the previous INVITE offer/answer.

While it is uncommon to send 183 before 3xx, this is a bug.

Library shutdown with a pending redirection causes assertion failure

Assertion will be triggered in the invite session when the library is shutdown while the invite session is still waiting for pjsip_inv_process_redirect function to be called.

While this is caused by application not following the requirement to call pjsip_inv_process_redirect(), nevertheless the library should be robust enough to handle this, so this will be fixed.