8 Managing Client Initiated Connections

This chapter describes how to manage client-initiated connections in Oracle Communications Converged Application Server.

The Session Initiation Protocol (SIP) outbound specification, as defined in RFC-5656, https://tools.ietf.org/html/rfc5656, specifies techniques for keeping connections that a User Application (UA) establishes alive, especially in environments where the UA is behind a Network Address Translation (NAT) device or a firewall. A SIP Servlet application may take different roles with respect to those defined in RFC 5626 for keeping the connections alive. For example, a SIP Servlet application may act as an authoritative proxy, an edge proxy, a registrar, or a UA. Refer to RFC 5626 for more details about the exact procedure for managing client-initiated connections.

Converged Application SIP Servlet containers support sending keep alive messages from a user agent as well as responding to keep alive messages defined in RFC 5626. They also support a FlowBinder interface for managing the connections as described in the following sections.

In RFC 5626, a flow is a transport-layer association between two hosts that is represented by the network address and port number of both ends and by the transport protocol. For Transport Control Protocol (TCP), a flow is equivalent to a TCP connection. For User Datagram Protocol (UDP), a flow is a bidirectional stream of datagrams between a single pair of Internet Protocol (IP) addresses and ports of both peers.

From a SIP Servlet application's perspective, the flow is a transport layer association between the SIP Servlet container and another SIP endpoint on a specific transport.

Table 8-1 describes the Flow interface's methods.

Table 8-1 Flow Interface Methods

Method Description

getToken()

Retrieves the flow token representing a flow.

getLocalURI()

Retrieves the SipURI representation of the local end of transport association.

getRemoteURI()

Retrieves the SipURI representation of the remote end of transport association.

release()

Indicates to the container that the application will not use the Flow object any more.

isActive()

Indicates whether the flow is active or not. Flow becomes inactive when it is closed.


Applications may get an instance of a Flow that represents this transport layer association by using the SipSession.getFlow(), Proxy.getFlow(), or ProxyBranch.getFlow() methods.

Note:

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

Retrieving a Flow Object from the Container

A SIP Servlet application can retrieve the Flow object corresponding to a flow token from the container by using the SipServletContext.getFlow(String flowToken) method.

Maintaining Connections Initiated by SIP User Agents

By default, when a SIP user agent located behind a NAT device or firewall initiates a connection, the SIP container keeps the connections alive. SIP user agents located behind a NAT are able to communicate with SIP nodes located on the other side of NAT.

The associated configuration parameter, SIP Outbound Support, is accessible in the Administration Console. The check box entry for SIP Outbound Support is selected, by default. You can disable the default support for connections that SIP user agents located behind a NAT initiate with SIP nodes located on the other side of NAT. To do so, the General configuration tab for SIP Server in the Domain Structure for the Administration Console and clear and the SIP Outbound Support check box.

If the check box for the SIP Outbound Support entry is cleared, all communication handling between user agents located behind a NAT and SIP nodes located on the other side of NAT is disabled. See "About Accessing the Administration Console" in Converged Application Server Administrator's Guide.

UAC Sending Keep-Alive

If a SIP Servlet acting as a User Agent Client (UAC) sends a REGISTER request with the headers required for RFC 5626 support, on receiving a 200 response to such a request, if that response contains an outbound option-tag in the Require header field, Converged Application Server starts sending keep-alive messages. These keep-alive messages may be double Carriage Return Line Feeds (CRLFs) for connection-oriented transports, such as TCP and Session Traversal Utilities for NAT (STUN) binding requests as described in RFC 5626.

Example 8-1 shows an implementation of such a UAC:

Example 8-1 UAC Keep-Alive

void sendRegister(SipServletRequest register) throws Exception {
  register.setHeader("Supported", "path,outbound");
  // Add the instance ID...
  Parameterable contact = register.getParameterableHeader("Contact");
  contact.setParameter("+sip.instance", <instanceId>);
  // Add the registration ID...
  contact.setParameter("reg-id", <registrationId>);
  register.send();
}

// The container starts sending keep-alive messages...
@SuccessResponse
public void handle200ok (SipServletResponse resp) {
  Flow flow = resp.getSession().getFlow();
}

Handling Flow Failures

An instance of FlowListener may be configured as a SipListener. Whenever the flow fails, the container invokes all configured FlowListeners. Applications may retrieve the flow and complete the necessary business logic, which typically includes sending the REGISTER message again.

Example 8-2 shows the FlowListener and FlowFailedEvent definitions.

Example 8-2 Flow Failure Handling

public interface FlowListener extends EventListener {
  void flowFailed(FlowFailedEvent flowFailedEvent);
}
public class FlowFailedEvent extends EventObject {
  public FlowFailedEvent(Flow flow) {
    super(flow);
  }
  public Flow getFlow() {
    return (Flow) super.getSource();
  }
}

Reusing a Flow

A UAC or a User Agent Server (UAS) may specify the flow to send messages on by using one of the following methods.

  • SipSession.setFlow(Flow flow).

  • Proxy.setFlow(Flow flow)

  • ProxyBranch.setFlow(Flow flow)

For example, a UAC can specify that the same flow that is used for sending REGISTER messages be used for sending INVITE messages as shown in Example 8-3.

Example 8-3 Reusing a Flow

void sendInvite(SipServletRequest invite){
  Flow flow = // Retrieve the flow...
  invite.getSession().setFlow(flow);
  invite.send();
}

Implementing Edge Proxies

When an edge proxy is implemented using SIP Servlets, the application inserts the flow token into the request as explained in RFC 5626. The application can retrieve flow tokens from the Flow object for that purpose.

Example 8-4 illustrates how an application might implement this logic.

Example 8-4 Inserting a Flow Token in a Request

@Register
public void handleRegister(SipServletRequest request){
  Proxy proxy = request.getProxy();
  Flow flow = proxy.getFlow();
  proxy.setAddToPath(true);
  SipURI pathURI = proxy.getPathURI();
  pathURI.setUser("edge");
  pathURI.setParameter("flow", flow.getToken());
  pathURI.setParameter("ob", "true");
  proxy.proxyTo(request.getRequestURI());
}

Similarly, when a different request that needs to be forwarded to a UA arrives at the edge proxy, it can look up the Flow object using the flow token present in the request. After the retrieved flow object is set on the Proxy (or ProxyBranch) by using the Proxy.setFlow(Flow flow) or ProxyBranch.setFlow(Flow flow) methods, the SIP Servlet container uses the corresponding transport association to send the message.

Example 8-5 illustrates one such implementation.

Example 8-5 Looking up a Flow Object

@Invite
public void handleInvite(SipServletRequest request) {
  Address route = request.getPoppedRoute();
  String flowToken = route.getURI().getParameter("flow");
  Proxy proxy = request.getProxy();
  Flow flow = sipServletContext.getFlow(flowToken);
  proxy.setFlow(flow);
  proxy.proxyTo(request.getRequestURI());
}

Releasing a Flow

An application can signal to Converged Application Server that it is no longer interested in using Flow by invoking the Flow.release() method. Converged Application Server uses that signal while making the decision to stop the keep-alive and/or terminating the underlying transport association. Since more than one application may be using the same transport association, Flow.release() should not be considered equivalent to terminating the transport association.