RFC 4028 — Session Timers in the Session Initiation Protocol specifies how SIP applications can make use of session timers to detect failed dialogs.
The SIP RA can optionally use session timers for any dialog activity.
How session timers work
Session timers are disabled by default. An application that wants to use session timers must request them when creating dialog activities.
The session timer for a new dialog is configured using a SessionTimerOptions
value.
This value contains the mandatory session interval parameter, which is the time in
seconds after which the dialog (session) is considered to have expired, if there were
no session refresh requests sent or received in that time. RFC 4028 defines how
the two parties on a dialog can negotiate the session interval, but it must always
be at least 90 seconds.
A session refresh request is any re-INVITE or UPDATE sent on the dialog. If a session refresh request is successful, this means that both parties on the dialog are still alive, so the session timer is reset and the dialog can continue. If a session refresh request times out, or fails with 481 (dialog does not exist), then the application should terminate the dialog.
During dialog setup, one party on the dialog is selected to be the refresher, who
must send a session refresh request periodically. An application can indicate its
preferred refresher in its SessionTimerOptions
, but this may not be applied, for
example if the other party does not support session timers.
RFC 4028 is designed so that session timers can still be used even if only one party on the dialog supports them. |
If a dialog activity in the SIP RA was selected to be the refresher, then periodically
the SIP RA will fire a SessionRefreshRequiredEvent
on the dialog, which tells the
application that it should initiate a session refresh request. If this request fails
with a timeout or 481 response then the application should terminate the dialog with
a BYE.
Dialogs are deliberately not terminated automatically by the RA when a session refresh fails or a session expires. This is so the application has full control of how it cleans up its resources. |
Regardless of who is selected to be the refresher, any successful re-INVITE or UPDATE on the dialog is implicitly a session refresh request, and resets the session timer automatically so the dialog may continue.
If there were no successful session refreshes within the session interval, then the
SIP RA considers the dialog to be expired, and fires a SessionExpiredEvent
.
The application must then terminate the dialog by sending a BYE request.
Creating dialogs with session timers
To request the use of a session timer for a dialog, the application must pass in
a SessionTimerOptions
value when creating the dialog, before sending or
responding to the initial request.
The dialog must be created using a dialog builder from
OCSleeSipProvider.newDialogBuilder()
.
This lets you specify SessionTimerOptions
in addition to other dialog options.
For example:
// Create SessionTimerOptions value with 5 minute session interval.
SessionTimerOptions timerOptions = SessionTimerOptions.builder(300).build();
// Create new outgoing dialog activity using our timer options.
DialogActivity d = sleeSipProvider.newDialogBuilder()
.outgoing(from, to)
.withSessionTimer(timerOptions)
.newDialog();
The session timer is activated when a successful response to the initial INVITE is sent or received. If the initial INVITE is not successful, then the dialog is not created and no session timer is started.
UAC behaviour
When a UAC application creates an outgoing dialog with a session timer, the initial
outgoing INVITE is updated automatically by the SIP RA using the dialog’s
SessionTimerOptions
:
-
the
Supported: timer
header is added -
the
Session-Expires
header is added, using the requested session interval -
if the
SessionTimerOptions
value specifies arefresher
, this is used for the "refresher" parameter in theSession-Expires
header -
if the
SessionTimerOptions
value specifies aminimum session interval
, then aMin-SE
header with this value is added to the request.
Handling 2xx responses
When a 2xx response arrives for the initial INVITE, the session timer is started, taking into account the session timer headers from the response:
-
If no session timer headers are present in the response, this means the UAS does not support session timers. In this case the UAC will start the session timer using its original settings, and act as the refresher.
-
The UAS may lower the
Session-Expires
value in its response, but not below the value ofMin-SE
, if it was present in the request. If the UAS wants a larger session interval it must send a 422 (Session interval too small) response. -
If the UAC did not specify a refresher, then the UAS must decide who is the refresher, and add the "refresher" parameter to the
Session-Expires
header in its response. In case the UAS does not specify a refresher either, the UAC will be the refresher.
Handling 422 responses
A 422 response indicates that the UAS wants a larger session interval. The UAS specifies
this value in the Min-SE
header of the 422 response.
The UAC should retry the initial request using the larger session interval. This is not done automatically by the SIP RA, so that the application has a chance to decide whether it wants to retry or just abort the call.
The application can ask the RA to create a new
dialog with the original parameters but with an updated session interval using
OCSleeSipProvider.retryInitialSessionRefresh()
:
private void on422Response(ClientTransaction ct, Response response) {
// create new dialog with SessionTimerOptions updated from 422 response
DialogActivity newDialog = getSleeSipProvider().retryInitialSessionRefresh(ct, response);
// attach SBB to new dialog
ActivityContextInterface newACI = getSipACIFactory().getActivityContextInterface(newDialog);
newACI.attach(getSbbLocalObject());
// Send INVITE on the new dialog
Request newInvite = newDialog.createRequest(Request.INVITE);
newDialog.sendRequest(newInvite);
}
UAS behaviour
UAS behaviour includes enforcing a minimum session interval and sending the 2xx response.
Enforcing a minimum session interval
When a UAS application receives an initial INVITE, it should first check that the request’s
Session-Expires
value (if present) agrees with the UAS application’s desired minimum
session interval. The application should inspect the request and send a 422 response if
the request’s session interval was too small.
This check can be done simply by using the convenience method
rejectIfBelowMinSE()
:
public void onInitialInvite(RequestEvent event, ActivityContextInterface aci) {
ServerTransaction st = event.getServerTransaction();
boolean rejected = getSleeSipProvider().rejectIfBelowMinSE(st, 600);
if (rejected) {
return; // 422 has been sent, nothing more to do
}
// continue processing initial INVITE...
}
This method checks the Session-Expires
value in the incoming request. If it is too small,
a 422 response will be sent automatically, containing the desired session interval in the
Min-SE
header. The method returns true
so the application knows it has responded.
No more processing is required; it is up to the UAC to retry if it wants.
Otherwise the application can continue processing the request, knowing that the INVITE’s
Session-Expires
was large enough.
Sending the 2xx response
Once the minimum session interval has been checked, the UAS application can create the dialog,
passing in its desired SessionTimerOptions
.
When the UAS application sends a 2xx response, it will be updated according to the
session timer headers in the initial request, and the dialog’s SessionTimerOptions
:
-
The
Require: timer
header will be added, if the request containedSupported: timer
. -
The
Session-Expires
header from the request will be used, unless the UAS’s timer options requested a lower value (but not lower than Min-SE).The UAS cannot increase the session expiry, or lower it below Min-SE. If the UAS wanted to increase the session expiry it should have rejected the INVITE with 422 (see Enforcing a minimum session interval).
-
The "refresher" parameter in the
Session-Expires
header will be set.-
If the UAC dos not support session timers, then the UAS is always the refresher.
-
If the UAC specified a refresher, then this value will be used.
-
Otherwise, the refresher specified by the UAS’s
SessionTimerOptions
is used. -
If the UAS did not specify a refresher either, then the RA’s
SessionTimer:default-refresher
config property is used (see Configuration).
-
ForkActivity support
Dialogs created by a
ForkActivity
"big fork" operation can also make use of session timers.
The application can pass its desired SessionTimerOptions
value to the
ForkActivity.forkTo()
method.
When the INVITE is forked to its targets, each copy of the INVITE will contain the
session timer headers corresponding to the SessionTimerOptions
value that was
supplied.
If there is a winning 2xx response, this creates a dialog and activates the session timer. The negotiated session timer options are derived as described in handling 2xx responses.
Subsequent invocations of
ForkActivity.forkTo()
on the same
ForkActivity
may pass in different SessionTimerOptions
values. The winning 2xx cancels all
other branches, and the resulting dialog’s session timer options are based on those
that were passed to the
forkTo()
call that sent the winning INVITE.
Accessing session timer state
The session timer state of a dialog activity can be queried using
SessionTimerDialog.getSessionTimer()
.
SessionTimerDialog
is a subclass of Dialog
, and any dialog activity
object may be safely type cast to this type.
The SessionTimer
interface shows whether the timer is active or expired, and also
shows the dialog’s currently applied SessionTimerOptions
.
Session refreshes
Once the dialog has been setup successfully, a session expiry timer is started using the session interval negotiated by the initial INVITE transaction. Session refresh requests must now be sent periodically to reset the expiry timer and keep the session alive. The party selected to be the refresher will do this at regular intervals if there has been no other activity, but either party may send a session refresh request at any time.
Refresher (UAC) behaviour
The dialog of the refresher starts another timer that fires halfway through
the session expiry interval (as per RFC 4028). If no other session refresh requests
are seen on the dialog, this timer causes a SessionRefreshRequiredEvent
to be
fired on the dialog’s ACI. When the application receives this event, it should send a
re-INVITE or UPDATE request on the dialog to perform the session refresh.
Sending the session refresh request
The session refresh request can be created as a normal mid-dialog request, for example
using Dialog.createRequest()
.
The SessionTimer
interface also provides methods for creating the session refresh
request, which can also take a SessionTimerOptions
value, so that the session timer
can be re-negotiated if necessary.
When sending a re-INVITE, the application must set the message body to contain the currently active SDP, from the last successful offer-answer exchange. Using UPDATE is recommended by RFC 4028, if the other party allows it. |
The application sends the request by the usual means, for example
DialogActivity.sendRequest()
.
When the session refresh request is sent, the SIP RA will update the request using
the current SessionTimerOptions
, or any new options that were passed to
generateSessionRefreshRequest()
:
Receiving the session refresh response
If a 2xx response is received for the session refresh request, the session timer is reset, and any new session timer options are applied, such as changing the session interval or the refresher.
If the session refresh request fails with an error response or timeout, then the session timer is not reset. The session timer will eventually expire unless a new session refresh request is sent and succeeds.
If the request fails with a timeout, 408, or 481 response, the application should terminate the dialog with a BYE.
For all other error responses, the application should retry the session refresh as appropriate based on the type of error.
SIP ResponseEvents
or
TimeoutEvents
for a failed session
refresh request are decorated with the
SessionRefreshFailedEvent
marker interface. This can be used to check if the event should be processed
as a failed session refresh, as in the example below.
private void processResponse(ResponseEvent event, ActivityContextInterface aci) {
if (event instanceof SessionRefreshFailedEvent) {
if (((SessionRefreshFailedEvent)event).shouldTerminate()) {
// Must have been 408 or 481, I need to send BYE now
}
}
}
Refreshee (UAS) behaviour
When a session refresh request is received on a dialog activity, it will be fired as a normal mid-dialog request event.
The UAS application can just respond to the request as it would normally. The SIP RA will automatically add session timer headers to the response.
If the UAS wants to change the session timer options, it can use the method
generateSessionRefreshResponse()
,
passing in a new SessionTimerOptions
value. Note that the new session interval
must fall within the refresh request’s Session-Expires
and Min-SE
range — values outside this range will be automatically restricted to the nearest upper
or lower bound.
If the response is a 2xx (success) response, the dialog’s session expiry timer
will be reset using the currently agreed session interval. If either party
requested that the UAS becomes the refresher, then the dialog remembers that it
is now the refresher, and starts a session refresh timer that will expire halfway
through the session interval to fire a SessionRefreshRequiredEvent
on this
dialog activity.
If the response is an error response, the session expiry timer is not reset, so the session will expire eventually unless a subsequent session refresh request (from either party) is successful.
If responding to a re-INVITE, the application must set the message body to contain the currently active SDP, from the last successful offer-answer exchange. |
Session expiration
If there were no successful session refresh requests sent or received within the
session interval, the dialog’s session expiry timer will fire, causing a SessionExpiredEvent
to be fired on the dialog activity.
The application processing the SessionExpiredEvent
should terminate the dialog
by sending a BYE. Again this is not done automatically by the RA, so that the
application can control how it cleans up its resources.
If no SBB processed the SessionExpiredEvent
, the RA will automatically send a BYE.
This avoids dialogs leaking if no service was active or able to process the event.
Once a dialog’s session timer has expired, there is no going back. The application cannot reset the timer and carry on. The dialog activity is still operational, but the only sensible course of action is to terminate the dialog as soon as possible. |
Proxy mode
Applications that need to forward messages between dialogs, such as B2BUAs, might just want to pass all messages through without directly taking part in session timer negotiation and refreshing. But it would still be useful if the application could be notified when a session expired, if the endpoints were using session timers.
This is what proxy mode is used for. In proxy mode, a dialog does not need to configure any session timer options. Instead it observes the session interval negotiated by the endpoints on the dialog, and starts a session expiry timer.
The dialog does not initiate any session refresh requests on its own. It observes all session refresh requests that pass through, and resets the expiry timer when a refresh succeeds.
If neither endpoint sends a successful session refresh within the session interval,
a SessionExpiredEvent
is fired so the application can clean up the expired dialog.
Enabling proxy mode on a dialog
All that is required to enable proxy mode for a dialog is to use the special
SessionTimerOptions
constant value,
SessionTimerOptions.PROXY
,
when creating the dialog. No further configuration is needed.
Now if either endpoint uses a session timer, the dialog will observe the Session-Expires
header in the initial request and/or response, and use this value to start its own
session expiry timer.
If a successful session refresh request re-negotiates the session interval, this will be observed as well, and the session expiry timer will be reset with the new value.
Replication
When SIP dialog replication is enabled (using the ReplicatedDialogSupport=true
config property), session timers are replicated as well so they can recover from
a node failure.
In a Rhino cluster, session timer refresh and expiry events will be fired on the same node that created the dialog activity.
If a node fails, its dialogs are automatically taken over by surviving nodes in the cluster. When a dialog is recovered on a surviving node, any session timers for that dialog are recovered as well, and will now fire on the surviving node at the expected time.
Subsequent session timer refresh and expiry events for the dialog activity will now fire on the node that took over that dialog.
Configuration properties
The SIP RA’s session timer support adds one new
configuration property:
SessionTimer:default_refresher
.
This is only required when a UAS has to select the refresher for a dialog, because
the UAC did not specify one, and the UAS application did not set a refresher in its
SessionTimerOptions
for the dialog. In this case the SessionTimer:default_refresher
property is used so the UAS can decide.
All other session timer parameters are configured by the application for each dialog,
using the appropriate SessionTimerOptions
values.
Application changes to use session timers
To use session timers, an application must:
-
Create dialogs using
OCSleeSipProvider.newDialogBuilder()
and passing in aSessionTimerOptions
value. -
When using ForkActivity, pass
SessionTimerOptions
toForkActivity.forkTo()
when initiating a fork operation. -
UAS applications may use
rejectIfBelowMinSE()
to enforce a minimum session interval. -
UAC applications may use
OCSleeSipProvider.retryInitialSessionRefresh()
to retry the initial request when handling a 422 response. -
Handle SessionRefreshRequiredEvents and send re-INVITE or UPDATE requests when needed.
-
Handle failed session refreshes and terminate the dialog if necessary.
-
Handle SessionExpiredEvents and terminate the dialog.