The draft RFC draft-ietf-sip-outbound-03 describes a feature that lets a SIP client initiate a persistent SIP connection to a SIP proxy server on the other side of a firewall/NAT

Using the procedures in the RFC, the connection is kept open, and the proxy is able to route incoming SIP messages over the connection created by the client. In this way, clients that are behind a firewall/NAT can receive calls, even though their IP address is not externally visible.

Maintaining persistent connections through a firewall

The SIP RA has been enhanced to support this draft RFC. This page describe the procedures that must be used on the client and server sides to setup and maintain persistent connections through a firewall.

The SIP RA implements the JAIN SIP 1.2 API. The JAIN SIP API does not have any notion of "connections", so applications cannot manipulate a connection object. The support for the draft RFC has been implemented so that applications still use the JAIN SIP API, and connections are setup and torn down using specially-formed REGISTER requests, as described below.

Procedures at the client

Below is a summary of persistent outbound connection procedures at the client.

Initiating a persistent connection

The client initiates a persistent connection to a server by registering as described in the draft RFC, passing +sip.instance and reg-id parameters in the Contact header of the REGISTER request.

The instance parameter must uniquely identify this user agent, and must be persistent across reboots. It is up to the user agent to derive this instance identifier. The draft RFC recommends using a UUID.

The reg-id parameter is an integer, and identifies the connection to a particular endpoint. If the client wishes to initiate more than one persistent connection to the same host, each REGISTER request must specify a different reg-id. An example REGISTER message is shown below:

REGISTER sip:ext-proxy.example.com:5060;transport=tcp SIP/2.0
Via: SIP/2.0/TCP 192.168.0.100:5060;branch=z9hG4bKf-EmiaQUlzbxheKMdLiiaA
From: <sip:client@example.com>
To: <sip:client@example.com>
Call-ID: oNSYps1sGnhIHM2wwt329A
CSeq: 1 REGISTER
Max-Forwards: 70
Contact: <sip:192.168.0.100:5060;transport=tcp>;+sip.instance="<urn:uuid:00000000-0000-0000-0000-000000000001>";reg-id=1;expires=3600
Content-Length: 0

When the client attempts to send a REGISTER in this way, the SIP RA detects that a new persistent connection is required, and opens a connection to the server. If a successful response is received, then the stack marks the connection as persistent, and will automatically perform the heartbeat and reconnection procedures specified by the draft RFC. If the registration response is not successful, or times out, an alarm is raised and the RA will initiate the reconnection procedures, and will try to reconnect and register again.

Sending requests on a persistent connection

To send requests on the connection, the client only has to ensure that the request is routed to the same server that handled the REGISTER. This can be achieved by inserting a Route header in any request. For example, if the client had registered as above, it would use the Route header:

Route: <sip:ext-proxy.example.com:5060;transport=tcp;lr>

If the RA sees that a request is destined for a server that it already has a persistent connection for, then it will send the request on that connection. If there are several persistent connections open to the server, then the most recently created one is used, as specified by the draft RFC.

If a persistent connection has gone down, the RA will automatically attempt to reconnect at intervals defined in the RFC (normally starting at 30 seconds). If a client tries to send a request on the connection and it is not currently available, then a SipException will be thrown.

Re-registering

The RA will automatically re-register in the case of a connection failure, but the application is still responsible for re-registering before the previous registration expires. When the initial registration response is received, the Contact header will contain an expires parameter specifying the lifetime of the registration, in seconds. The application must set the appropriate timers so that it re-registers before the registration is due to expire.

Connection events

After establishing a persistent connection as above, an SBB client may attach to a PersistentOutboundConnection activity to be notified when the underlying connection goes up and down.

Tip See the example PersistentOutboundConnectionSbb.

Heartbeats

The RA uses the STUN heartbeat mechanism to check that the server is still responding, and also to check if the NAT mapping has changed. If a persistent connection is idle for 90 seconds, a STUN bind request is sent. If no response is received, or if the response indicated that the NAT mapping has changed, then the RA will automatically close the connection and begin reconnection procedures. No application involvement is required for handling the STUN messages, this is done entirely by the RA.

Tearing down a persistent connection

Tearing down a persistent connection is done by sending an unregister request. This is a REGISTER request as above, but with an expires value of zero. When this request is sent on a persistent connection, the RA knows it can close the connection, and it does not begin reconnection procedures, and no alarm is raised.

If the unregister request is sent when the connection is already down, the RA will treat this as a signal that the connection should be closed permanently and no more reconnection attempts will be made. Any alarms associated with the connection are cleared. The RA will pass an OK response back up to the application.

Example

An example service is included which creates and tears down a persistent connection, using the REGISTER procedures above.

Tip See PersistentOutboundConnectionSbb.java in src/com/opencloud/slee/services/sip/persistent. The Ant target deploy-persist-conn will deploy and activate the service.

The service will attempt to register when it is activated. The server it tries to register with is specified in the sip.properties variable PERSISTENT_REGISTRAR_URI. By default this is localhost:5080, but should be changed to the URI of another SLEE running the example registrar service.

Alarm types

The alarm types are:

  1. sip.persistent.connectionDown

    Description

    Raised when a single connection to an endpoint fails. Cleared automatically when the connection is restored, or if the connection is closed permanently using an unregister request.

    Source

    sip.transport.persistent.outgoing.<endpoint>.<reg-id>

    Level

    MINOR

    Message

    Connection to <endpoint> down, reg-id=<reg-id>

  2. sip.persistent.allConnectionsDown

    Description

    Raised when the SIP RA has no persistent outbound connections to an endpoint. Cleared automatically when at least one connection is restored, or all connections have been unregistered.

    Source

    sip.transport.persistent.outgoing.<endpoint>

    Level

    MAJOR

    Message

    No persistent connections available to <endpoint>

Procedures at the server

Below is a summary of persistent outbound connection procedures at the server.

X-Flow-ID header

The SIP RA uses a proprietary header, X-Flow-ID, to indicate to the server the applications whose incoming "flow" (connection) a request was received on. The header contains a string token which uniquely identifies an incoming flow on this server. The header is only set on incoming requests when the request is received on an existing persistent incoming flow, or it is an initial REGISTER request which is creating a new incoming flow.

Similarly, if an application wants to send a request on a particular incoming flow, it can set the X-Flow-ID header in the request before sending it. The RA will see the header and attempt to send on the flow indicated by the Flow-ID, throwing an exception if the flow is not present.

The RA will always remove the X-Flow-ID header before the request is sent on the network.

Registrar

Registrar applications must check incoming REGISTERs to see if the X-Flow-ID header is present, and if so, save the Flow-ID along with the other registration details. This is so that a proxy application can look up the registration and route requests to the correct flow.

The example RegistrarSbb has been updated to save the flow, along with the other registration details.

Tip See RegistrarSbb.java in src/com/opencloud/slee/services/sip/registrar.

Proxy

Proxy applications must be prepared to route requests to particular flows. When a proxy looks up a user’s registration details, it can get the Flow-ID (if present), and insert an X-Flow-ID header so the RA will send the request on the correct flow.

If the proxy is a record-routing proxy, meaning that it will see all requests in a dialog, then the proxy must take care to record-route correctly so that subsequent requests in the dialog will be sent on the correct flow. The draft RFC is not specific about how this is done, but one procedure that works is the "double record-route".

When processing an initial request, the proxy must check if the request was received on an incoming flow, or is destined for an incoming flow. If either is true, the proxy inserts two Record-Route headers. Each header may contain a Flow-ID. Later, when one of the parties in the dialog sends a subsequent request, it will arrive at the proxy with two Route headers, denoting the incoming and/or outgoing flows. The proxy removes both Route headers, and sends the request out on the flow specified in the second Route header.

Tip The example ProxySbb has been updated to retrieve flow information and use the double record-routing procedure described above. See ProxyRouter.java in src/com/opencloud/slee/services/sip/proxy.

Server-initiated connection close

The server may forcibly close a persistent incoming connection at any time, by using the proprietary API call OCSleeSipProvider.closeInboundFlow(). This method takes a string parameter, which is the value of the X-Flow-ID header, received with all requests on the connection.

Abnormal or client-initiated connection close

If the connection is closed by the client or is dropped for any reason, other than a call to closeInboundFlow() as above, the server’s RA will generate an un-REGISTER request and pass this up to the SLEE, so that registrar applications can remove the registration associated with that connection. The request will contain the correct address-of-record, contact address, instance-id, and reg-id for the connection, and will have an "expires" value of zero. The response to this request is handled internally, and will not be transmitted over the network.

Note that if the client unregisters normally and closes the connection, the stack will still generate this request, but this will have no effect since the registration would have already been removed.

If the connection is closed by the server using closeInboundFlow(), the un-REGISTER request is not generated, it is assumed that the application will be responsible for cleaning up registration state for that connection.

System properties

The following JVM system properties may be set to alter the default persistent outbound connection behaviour.

Property What it specifies Values
Default

opencloud.sip.outbound.reconnect.base-time

The base wait time between client reconnection attempts, if there are other flows still active to the same server. If a reconnection attempt fails, the wait time between subsequent reconnection attempts backs off exponentially, up to a limit of max-time.

time in seconds
90

opencloud.sip.outbound.reconnect.base-time-all-failed

The base wait time between client reconnection attempts, if there are no flows active to the same server. If a reconnection attempt fails, the wait time between subsequent reconnection attempts backs off exponentially, up to a limit of max-time.

time in seconds
30

opencloud.sip.outbound.reconnect.max-time

The maximum wait time between reconnection attempts, after backing off due to earlier failed attempts.

time in seconds
1800

opencloud.sip.persistent.connectTimeout

The maximum time to wait for a connection attempt to succeed.

time in milliseconds
15000

opencloud.sip.persistent.registrationTimeout

The maximum time to wait for a registration attempt to succeed, after a new connection was established.

time in milliseconds
15000

opencloud.sip.persistent.heartbeatTimeout

The maximum time to wait for a response to a STUN heartbeat request.

time in milliseconds
15000

opencloud.sip.persistent.idleTimeout

The time between sending STUN heartbeat requests, if there has been no activity on a flow.

time in milliseconds
90000

opencloud.sip.rfc5626Variant

Switch connection behaviour between RFC 5626 and draft-ietf-sip-outbound-03.

draft03
rfc5626

Previous page Next page