10 Forking SIP Requests, Dialog Termination, and Session Keep Alive

This chapter describes methods for forking SIP requests, SIP dialog termination and handling session keep alive.

Forking SIP Requests

The forking of SIP requests means that multiple dialogs can be established from a single request. When ever multiple dialogs are created due to forking a derived session is created from the original session. Such derived sessions that effectively represent such sibling dialogs belong to a forking context. The ForkingContext interface helps an application to navigate to all such derived sessions. Thus a SipSession and its derived siblings belong to the same forking context.

A ForkingContext is created whenever the first session on a new dialog is created and it remains valid as long as at least one SipSession that belongs to the forking context remains valid. Applications can obtain an instance of a ForkingContext using the SipSession.getForkingContext() method.

When acting as a User Agent (UA), it is possible that an application might want to send a new request on the same forking context, but on a different dialog. In that case such a request establishes a new dialog. An example of such a request is the NOTIFY request as specified in RFC 6665, https://tools.ietf.org/html/rfc6665. SIP servlet applications can create new requests with the same forking Context using the method ForkingContext.createRequest(String method).

Note:

For details on the API described in this section, see the Java SIP Servlet API 2.0 JavaDocs.

Binding Attributes to a ForkingContext

A servlet can bind an object attribute to a ForkingContext by name. Hence ForkingContext is also an attribute store. See the discussion of Attribute Stores in Chapter 7 of JSR-359, https://jcp.org/en/jsr/detail?id=359 for more details.

Creating a Request

When ForkingContext.createRequest() is called, Converged Application Server derives a new session and creates a request using that session. Only NOTIFY requests can be created since this API is only applicable in that scenario. When an application tries to create any other requests, an IllegalArgumentException is thrown. The new derived session is created based upon the first session setup in the forking context.

Cloning Attributes

A ForkingContext supports the flag, enableDerivedSessionAttributeCloning(), for enabling or disabling the cloning of attributes when creating a derived session within the forking context scope. In legacy implementations, when creating a derived session, the attributes in the original session are retrieved and assigned to the new derived session. The new derived session refers to the same attributes object of the original session. When enableDerivedSessionAttributeCloning() is set to true, the attribute values of the original session are cloned, and the derived session refers to a new attributes object. The default value for enableDerivedSessionAttributeCloning() is false.

Terminating Dialogs

When the ForkingContext.terminateDialogs() method is called, Converged Application Server will terminate all SIP sessions of the forking context if they are not explicitly excluded. This method is available for both UA and proxy modes. When ForkingContext.terminateDialogs() is called in proxy mode, the feature proxy send bye will be added to the terminate proxy dialogs.

Max-Breadth Header Support

The Max-Breadth header limits the number of parallel forks that can be made on a Session Initiation Protocol (SIP) request by downstream proxies. Following RFC 5393, https://tools.ietf.org/html/rfc5393, each downstream proxy distributes the Max-Breadth among the active parallel branches so that the outgoing Max-Breadth is the sum of the Max-Breadth header field values in all forwarded requests in the response contexts that have not received a final response.

In Converged Application Server, the application decides the number of times the request is forked in parallel. An application may explicitly set the breadth on the forked requests by using the SipServletRequest.setMaxBreadth() method. Applications may retrieve the forked request by using the ProxyBranch.getRequest() method.

If the received request contains no Max-Breadth header, the container uses 60 as the default value.

In Converged Application Server, the SIP container is configured to automatically check the Max-Breadth header. The associated configuration parameter, Max-Breadth Check Support, is accessible in the Administration Console. The check box entry for Max-Breadth Check Support is selected, by default. You can disable the automatic checking of the Max-Breadth header. To do so, access the General configuration tab for SIP Server in the Domain Structure for the Administration Console and clear the Max-Breadth Check Support check box. See "About Accessing the Administration Console" in Converged Application Server Administrator's Guide.

If a Proxy application does not set the breadth explicitly, Converged Application Server distributes the available breadth evenly to the branches when the application invokes the Proxy.proxyTo() or Proxy.startProxy() methods.

At the time of forking, if the sum of the Max-Breadth values of active parallel branches exceeds the Max-Breadth of the original incoming request, Converged Application Server throws an InsufficientBreadthException. For a proxy, this check is done when the application invokes the Proxy.proxyTo() and Proxy.startProxy() methods. Applications may catch this exception and send an error response (440) or attempt to proxy again after adjusting the breadth.

Max-Breadth is used within Converged Application Server for loop detection.

Note:

For details on the SipServletRequest.setMaxBreadth() method, see the Java SIP Servlet API 2.0 JavaDocs.

Loop Detection

There is a possibility that loops may occur in invoked applications, such as when A proxies to B which proxies back to A. It is important that such loops be detected and handled. Converged Application Server decrements the value of the Max-Forwards header whenever a request is proxied internally, or whenever a request is forwarded by a servlet acting as a Back to Back User Agent (B2BUA).

Converged Application Server also checks the Max-Breadth header to verify whether the request can be proxied in parallel or forwarded to multiple destinations by a servlet acting as a B2BUA in parallel. Converged Application Server generates an InsufficentBreadthException when the Max-Breadth check fails.

SIP Dialog Termination

An application may terminate a Session Initiation Protocol (SIP) dialog using the SipSession.terminateDialog method at any time. If the application is acting as a SIP user agent on the SipSession, and if the SipSession corresponds to an established SIP dialog, or a dialog-establishing transaction is pending, terminateDialog method call instructs the container to send the appropriate SIP messages to terminate the dialog, otherwise the call results in a no-op.

Note:

SIP dialogs are only created by the INVITE, REFER, and SUBSCRIBE methods, and, therefore, terminateDialog only affects dialogs created by these methods. For any other session, the method call will result in an IllegalStateException.

Once the terminateDialog method is called, the application cannot send any more messages in the SipSession. Any attempt to do so will cause IllegalStateException to be thrown by the SipServletMessage.send() method. Furthermore, the container will not invoke the application's SipServlet service() or doXXX() methods from that point on. When the dialog is terminated, the app is notified by the current SipSessionListener.sessionReadyToInvalidate() method.

An application may terminate all dialogs belong to a forking context using ForkingContext.terminateDialogs() method. The container will also terminate all derived sessions that belong to the same ForkingContext, created after executing this method. For more information, see "Forking SIP Requests".

Note:

This method will not terminate dialogs that belong to a proxy application.

In certain cases, an application may wish to modify the outgoing SIP message that the container is sending in order to terminate a dialog. For example, the application may want to add a Reason header to a BYE method, or a message content to a NOTIFY method. There are also cases where the application may wish to be notified of incoming SIP messages. The application may provide a listener using the following method:

SipSession.terminateDialog(AutomaticProcessingListener listener)

The AutomaticProcessingListener should not make changes to message that subvert the RFCs and container behavior in terminating the dialog. Oracle also recommends that applications do not throw any exceptions during the execution of AutomaticProcessingListener. Any exception thrown by the application will be ignored by the SIP servlet container.

Table 10-1 describes the AutomaticProcessingListener methods.

Table 10-1 AutomaticProcessingListener Methods

Method Name Description

outgoingRequest(request)

This method is invoked before Converged Application Server sends a SIP request. The application may modify the request in-place.

outgoingResponse(response)

This method is invoked before the Converged Application Server sends a SIP response. The application may modify the response in-place.

incomingRequest(request)

This method is invoked when the Converged Application Server receives a SIP request.

incomingResponse(response)

This method is invoked when the Converged Application Server receives a SIP response.


Note:

For details on the API described in this section, see the Java SIP Servlet API 2.0 JavaDocs.

Terminating Proxy Dialogs

As defined in RFC 3261, https://www.ietf.org/rfc/rfc3261.txt, a SIP proxy must not create and send requests in an established dialog. However, some 3GPP applications need this ability (see 3GPP TS 24.229, http://www.3gpp.org/dynareport/24229.htm, section 5.2.8.1.2 Release of an existing session). To support that use case, a separate method is provided so that an application can terminate proxy dialogs.

Note:

Given the way that this method breaks RFC 3261, this method should be used with caution and any application that uses it should be carefully tested. 3GPP specifications also require a way where the termination messages are sent for either one side of the proxy or both.

If the SipSession corresponds to an established SIP dialog, or a dialog-establishing transaction is pending, the methods in Table 10-2 instruct the container to send the appropriate SIP messages to terminate the dialog.

Table 10-2 Proxy Dialog Termination Methods

Method Name Description

terminateProxiedDialog(direction)

Terminates the proxied dialog by sending appropriate messages in the direction specified. For example, if the direction is UAC, Converged Application Server will send BYE message to terminate an INVITE dialog in the direction of UAC.

terminateProxiedDialog(direction, listener)

Terminates the proxied dialog by sending appropriate messages in the direction specified. Applications may intercept messages during termination.

terminateProxiedDialog()

Terminates the proxied dialog by sending appropriate messages in both directions.

terminateProxiedDialog(listener)

Terminates the proxied dialog by sending appropriate messages in both the directions. Applications may intercept messages during termination.


Note:

An application should invoke the first two terminateProxiedDialog methods only when it find using some other means that other side of the specified direction will not respond. Any message on the other side may be ignored by Converged Application Server.

Notes on Container Behavior

Converged Application Server uses the following RFCs as guidelines for correct dialog termination behavior:

The following sections provide examples of Converged Application Server behavior in terminating SIP dialogs based on those RFCs. In the examples, the terms UA, UAC and UAS should be understood to mean the Converged Application Server acting on behalf of an UA application that has called SipSession.terminateDialog(). Similarly, when a proxy dialog is being terminated using SipSession.terminateProxiedDialog(), these terms corresponds to the direction(s) in which the messages are being sent.

INVITE Dialog

Keep in mind the following INVITE dialog points:

  • When a dialog is in its early state, a caller UA must send CANCEL to terminate the dialog. (While RFC3261 allows sending CANCEL or BYE, RFC 5407 section 2 says UAC MAY send BYE, but not recommended, so Converged Application Server sends a CANCEL request.). The callee UA can send an error as a final response.

  • The callee's UA must not send a BYE on a confirmed dialog until it has received an ACK for its 2xx response or until the server transaction times out. (See RFC3261 sec 15, and RFC6026).

  • When a UA receives a BYE, it must respond to any pending requests received for that dialog with a 487 response (RFC3261 sec 15.1.2).

  • While not specified explicitly, a UA should respond to any pending requests before sending BYE. Converged Application Server sends a 487 response code when responding to pending requests.

  • Various race conditions as described by RFC5407, for example when a requests have arrived after a UA has sent BYE, are responded to.

SUBSCRIBE Dialog

Keep in mind the following SUBSCRIBE dialog points:

  • A SUBSCRIBE dialog can be created explicitly by subscriber sending SUBSCRIBE.

  • A SUBSCRIBE dialog can also be created implicitly by REFER.

  • A subscription is destroyed when a UA acting as notifier sends a NOTIFY request with a "Subscription-State" of "terminated". If the dialog is not otherwise in use, the SIP dialog is terminated.

  • A UA acting as a subscriber cannot explicitly terminate a subscription. A UA acting as subscriber may send a SUBSCRIBE request with an "Expires" header of 0 in order to trigger the notifier to send a NOTIFY request that destroys the subscription.

Multiple Dialogs

Keep in mind the following points when using multiple dialogs:

  • It is possible for a dialog to have multiple usages (RFC 5057). For the purpose of dialog termination, in order to terminate the dialog the UA must terminate each of those usages independently in order to terminate the entire dialog.

  • The order in which messages are sent to terminate the usages is not important. For example, the UA may need to send BYE and NOTIFY to terminate the INVITE and SUBSCRIBE usages in a dialog respectively, and the UA may send these messages in either order.

Session Keep Alive

Session Initiation Protocol (SIP) user agents (UAs) and proxies depend on session terminating messages to end the session and clean up resources. When a terminating message does not arrive, Converged Application Server supports a mechanism to determine whether the session should be kept alive or not as explained in this section. For instance, when a UA fails to send a BYE message at the end of a session, or when the BYE message is lost due to network problems, a Call Stateful Proxy (CSP) needs to know when the session has ended.

RFC 4028, https://tools.ietf.org/html/rfc4028, defines an extension that defines a keep alive mechanism for SIP sessions. UAs send periodic re-INVITE or UPDATE requests to keep the session alive. The interval for the session refresh requests is determined through a negotiation mechanism defined in RFC 4028. If a session refresh request is not received before the interval passes, the session is considered terminated. Both UAs are supposed to send a BYE, and CSPs can remove any state for the call. Converged Application Server supports this keep alive mechanism as defined in this section.

Enabling Session Keep Alive

A SIP servlet can enable the session keep alive by setting appropriate keep alive preference to generate an initial session refresh request, and can retrieve a SessionKeepAlive.Preference object using the method SipServletMessage.getSessionKeepAlivePreference(). The servlet can then enable the keep alive by invoking SessionKeepAlive.Preference.setEnabled(true). Converged Application Server sets the headers (Session-Expires, Supported, Min-SE, and others) as specified in RFC 4028 by using the values specified in SessionKeepAlive.Preference if the session keep alive is enabled.

If a User Agent Client (UAC) wants the session timer to be applied to the session, the UAC is required to enable the session keep alive by invoking SessionKeepAlive.Preference.setEnabled(true)before sending the initial session refresh request. Converged Application Server sets Session-Expires to a default value of 1800 seconds once the keep alive is enabled, if it has not been set previously.

For proxies and User Agent Servers (UAS), session keep alive is enabled, if the initial session refresh request contains a Session-Expires header. If there is no Session-Expires header in the request, then the UAS or proxy may apply a session timer to the session by enabling the session keep alive.

Once session keep alive is enabled, Converged Application Server follows the procedures specified in RFC 4028 for UAC, Proxy, and UAS for activating session timer for the session.

Note:

For details on the API described in this section, see the Java SIP Servlet API 2.0 JavaDocs.

Disabling Session Keep Alive

The proxy and UAS may receive a session refresh request with a Session-Expires header. In that case, by default, session keep alive is enabled. If a proxy or UAS does not want to take part in the session keep alive activity, then it may choose to disable the session keep alive by invoking SessionKeepAlive.Preference.setEnabled(false).

Note:

Disabling session keep alive does not mean that a UAC will not send session refresh requests any more. It may continue to send session refresh requests if the session keep alive remains enabled.

Refreshing Sessions

When the UA that enabled session keep alive assumes the role of refresher, Converged Application Server schedules a keep alive timer. However Converged Application Server will not send a refresh request on its own. A SIP servlet can provide a refresh callback that will be executed by Converged Application Server at the appropriate time for sending the session refresh request. The refresh callback needs to implement the SessionKeepAlive.Callback interface.

Example 10-1 illustrates such a callback.

Example 10-1 Refreshing a Session

request.getSessionKeepAlivePreference().setEnabled(true);
SessionKeepAlive skl = request.getSession().getKeepAlive();
skl.setRefreshCallback(new SessionKeepAlive.Callback() {
  @Override
  public void handle(SipSession session) {
    try {
      session.createRequest("UPDATE").send();
    } catch (IOException e) {
    }
  }
});

Converged Application Server invokes the refresh callback once half of the session expiration interval has elapsed. If the application sends a refresh request on its own by that time, Converged Application Server will re-calculate the next session expiration time and invoke the refresh callback accordingly.

An application can remove the refresh callback by setting a null refresh task by invoking SessionKeepAlive.setRefreshCallback(null);

Expiring Sessions

When a Proxy or UA does not receive a session refresh request before the expiration interval, Converged Application Server invokes the expiry callback. The expiry callback needs to implement SessionKeepAlive.Callback interface as shown in Example 10-2.

Example 10-2 Expiring a Session

request.getSessionKeepAlivePreference().setEnabled(true);
SessionKeepAlive skl = request.getSession().getKeepAlive();
skl.setExpiryCallback(new SessionKeepAlive.Callback() {
  @Override
  public void handle(SipSession session) {
    try {
      session.createRequest("BYE").send();
    } catch (IOException e) {
    }
  }
});

Sending Provisional Responses to Non-Invite Requests

In Converged Application Server, if the application or proxy does not respond to a non-invite request before the TimerE reaches T2, the container responds with a 100 TRYING to the request. It does so, if the container has not otherwise responded after the amount of time it takes a client transaction's TimerE to be reset to T2. For more information about TimeE and SIP Non-Invite actions, please refer to RFC 4320 at

http://tools.ietf.org/html/rfc4320

The associated configuration parameter, Enable Sending 100 For Non-Invite Request Support, is accessible in the Administration Console. The check box entry for Enable Sending 100 For Non-Invite Request Support is selected, by default. You can disable the container from responding with a 100 TRYING to such non-invite requests. To do so, access the General configuration tab for SIP Server in the Domain Structure for the Administration Console and clear the Enable Sending 100 For Non-Invite Request Support check box. See "About Accessing the Administration Console" in Converged Application Server Administrator's Guide.

422 Responses

UAS and Proxy applications are expected to generate a 422 response if they find that the session expiration interval is too small. Similarly, UACs are expected to handle the 422 response and retry the request as specified in RFC 4028.