SIP Proxies

Document Sample
SIP Proxies Powered By Docstoc
					Chapter 13. SIP Proxies
Objects in this chapter

Start by defining what a SIP proxy is, and by explaining its crucial role in
the routing of SIP messages in the SIP architecture.
Classify the mode of behavior of SIP proxies into stateless and stateful.
A detailed explanation of the proxy behavior is then presented. This is
particularly useful for the last part of this chapter, in which we will show
some practical examples of how a very much simplified SIP proxy might
be implemented using JAIN SIP.

What Is a SIP Proxy?-(1)
 A SIP proxy server is an
 intermediary entity that helps route
 SIP requests to UASs, and SIP
 responses to UACs.
 SIP Routing
    SIP proxies typically make routing
    decisions by changing the Request-
    URI. In a simplified model, a proxy
    receives a request, modifies the
    Request-URI according to some
    rules, and then forwards the request
    to the new destination URI.
    SIP proxies may modify specific
    header fields in a request before
    forwarding it.

   What Is a SIP Proxy?-(2)
Proxies are not limited to outbound or inbound types.
In the path from UAC to UAS, an arbitrary number of
proxies may be traversed,
In addition to making routing decisions, proxies may
also implement a limited amount of service logic, such
as call barring, call forwarding, and so forth.
More-complex service logic requires that B2BUAs are
used. For instance, SIP applications that require SIP
dialog manipulation (e.g., terminate a confirmed
dialog, generate new dialogs, change parameters of the
session, initiate calls from the application server, and
so on) cannot be implemented using a SIP proxy; they
require B2BUA functionality.
SIP proxies can be split into transaction stateful and
transaction stateless proxies. This categorization refers,
in fact, to the roles that a proxy can perform, rather
than to proxies themselves. So the same proxy may
play a stateful role in some cases (e.g., when dealing
with some particular requests), but behave like a
stateless proxy in other situations.

  Transaction Stateful Proxies-Treatment of Transactions -
A transaction stateful proxy, also called stateful
proxy in short, has a server transaction associated
with one or more client transactions. The service
logic that maintains the association between server
transaction and client transactions is called the proxy
In a very simple scenario, a request is received
through the server transaction, processed by the
proxy core (which might change the Request-URI),
and then forwarded through a client transaction.
Likewise, responses would be received by the client
transaction, passed to the proxy core, and sent back
through the server transaction.
This state information has two components.
      The first is the information stored in the server
      and client transaction, which is needed for the
      proper behavior of SIP transactions
      The second is the state needed by the proxy
      core to perform its function. For instance, the
      proxy core needs to maintain an association
      between server and client transactions.

 Transaction Stateful Proxies-Treatment of Transactions -
Notice that the 100 (Trying) provisional response does not
follow the end-to-end approach. It represents an exception
to the rule: it is sent by the SIP proxy as soon as it receives
the INVITE request to quench requests retransmissions
rapidly in order to avoid network congestion.
This hop-by-hop reliability mechanism is quite efficient
because retransmissions are implemented just in the hop
where they are needed (in the case of UDP).

Transaction Stateful Proxies- Treatment of Transactions -
  This kind of behavior—end-to-end
  request/response and hop-by-hop
  reliability—is applied to all SIP
  transactions, with some quite important
      a SIP proxy sends back a 100 (Trying)
      provisional response as soon as it
      receives an INVITE request. This is done
      in order to quench retransmissions rapidly
      and so avoid network congestion.
      If the INVITE transaction is answered
      with a 200 OK, it is quite important that
      the reliability mechanism used to assure
      delivery of the response is end to end
      rather than hop by hop. This has to do
      with the fact that a successful INVITE
      transaction generates, in both endpoints,
      state that needs to be fully synchronized.
      Therefore, when a server transaction
      sends a 200 OK, it terminates. Likewise,
      when a client transaction receives a 200
      OK, it also immediately terminates. This
      implies that the retransmission of 200 OK
      messages is made end to end by the SIP
      core layer. Moreover, the ACK request is
      sent statelessly and treated statelessly by
      the proxy.

Transaction Stateful Proxies- Treatment of Transactions -
  This kind of behavior—end-to-end
  request/response and hop-by-hop
  reliability—is applied to all SIP
  transactions, with some quite
  important exceptions.
     If the INVITE transaction is
     answered with a non-2XX final
     response, the stateful proxy must
     generate the ACK for that response,
     being the ACK part of the original
     INVITE transaction. What this
     means is that 4XX, 5XX, or 6XX
     responses to INVITE are always
     treated hop by hop rather than end to

Transaction Stateful Proxies- Treatment of Transactions -
  This kind of behavior—end-to-end
  request/response and hop-by-hop
  reliability—is applied to all SIP
  transactions, with some quite
  important exceptions.
  The CANCEL transaction is by
  nature a hop-by-hop request. It has
  significance only between a client
  transaction and its adjacent server
  transaction. When receiving a
  CANCEL request, the stateful proxy
  will generate new CANCEL
  requests in the outgoing branches
  that it created when the INVITE
  was received.

Transaction Stateful Proxies-Call Stateful
  Call stateful proxies are transaction stateful proxies that keep track of calls
  traversing them. Such proxies record-route, so as to be in the signaling path of
  all the messages within a dialog, and also maintain information related to the
  call. These proxies may be used, for instance, to generate records that include
  both the start time and finish time of the call for charging purposes. It is
  important that record-routing is used carefully because it increases processing
  required by a proxy.

Stateful Proxy Behavior-Treatment of Requests(1)

 The first thing the proxy core does is to validate the request. It checks a number of
     The syntax is correct
     The scheme in the Request-URI is understood
     Max-Forwards header field is not zero (a zero value would indicate that this request has gone
     through too many hops)
     Loop detection
 Requests that reach the proxy may have a Route header field whose first value indicates
 this proxy. This situation may occur because a previous proxy or UAC may have put that
 value in the Route header so as to force the requests to traverse the proxy. In such a case,
 the proxy should delete that value because it has already been used and is no longer
 The next step is to determine the new target(s) of the request—that is, the new Request-
 URI. This step is the essence of the proxy role. Two situations may occur:
     If our proxy is not responsible for the domain that appears in the Request-URI, then the Request-
     URI is not modified.
     If our proxy is responsible for the domain that appears in the Request-URI, then a location
     service is accessed in order to determine the new Request-URI.
 The next step is to decrement the Max-Forwards header-field value by 1 in order to
 reflect the fact that the request has just traversed another proxy.

Stateful Proxy Behavior- Treatment of Requests-(2)

 If the received request initiates a dialog, and the proxy wishes to remain
 in the path of future requests within that dialog, the proxy then inserts a
 new Record-Route header value that indicates its address.
 If local policy in the proxy mandates that the request needs to traverse
 a specific set of other proxies, our proxy could push new Route header-
 field values into the request that point to these other proxies.
 The next step is to determine the IP address, port, and address for the
 next hop. This is done according to [RFC 3263], as was explained in
 Chapter 6.
 Then the proxy inserts a new Via header-field value, creates a new
 client transaction, and forwards the request through it.
 The last step consists of starting a timer (called Timer C) in order to
 handle the case where an INVITE request never generates a final
 response. The proxy updates the timer as soon as it receives a
 provisional response.

Stateful Proxy Behavior- Treatment of Requests-(4)

   The proxy may handle the new
   branches sequentially or in

 Transaction Stateless Proxies

Not transaction aware
The selection of the appropriate
server and client transport is
done on the information in the
message itself, not on stored

Stateless Proxy Behavior
 A stateless proxy is just a simple message forwarder.
 the main aspects in which a stateless proxy core behavior is different
 from the behavior of a stateful proxy core, described in previous
    Stateless proxies can forward requests to only one single destination. In other words,
    they cannot fork requests.
    Original requests and their retransmissions are undistinguishable by the stateless
    Received requests do not cause the proxy core to generate a server transaction.
    Stateless proxies do not perform special processing for CANCEL requests.
    Response processing, as described in Section 13.3.2, “ Treatment of Responses, ”

    does not apply to a stateless proxy   .

Practice: SIP Server- Scope
 It encompasses a very simple SIP proxy, SIP registrar, and location service.
 some considerations about the scope of our application:
    The SIP proxy is a simple routing engine. It does not implement
    forking. An incoming request maps to one (and only one) outgoing
    The SIP proxy implements routing by querying an internal location
    service that is implemented by a class variable. That is, the location
    information is not persistent.
    The SIP proxy can be configured to record-route or not.
    The SIP registrar is a quite simple one. It just receives REGISTER
    requests and updates the location service accordingly.
    The SIP registrar accepts only one contact address for each address
    of record. It does not store or check the expiration time of the
    records in the location service. It always includes in responses to
    REGISTER the same Expires header that was received in the
    original request.

 Practice: SIP Server- Architecture

Separate the user interface (SipproxyGUI.class) from the listener
The management console is also used for displaying information about the ongoing
client and server transaction handled by the proxy, as well as the content of the location
service (mapping between addresses of record and contact addresses).
Two main interfaces in this architecture:
    Interface between SipproxyListener and the SIP implementation (JAIN SIP)
    Interface between SipproxyGUI and SipproxyListener

Practice: SIP Server- Architecture
 The interface between the management console and the listener is used
 mainly for two purposes:
    Configuration of the proxy at start-up.
    Displaying proxy internal data in the management console, such as the list of
    ongoing transactions or the actual content of the location service database.
 From SipproxyGUI to SipproxyListener
 From SipproxyListener to SipproxyGUI

Management Console (GUI)
 Two purposes
    Configure the SIP server.
    Display real-time information about its internal data.

Management Console (GUI)- The Tracer Display

Management Console (GUI)- The Location Service

Management Console (GUI)- The Transaction Display

JAIN SIP Initialization
 In the case of the proxy, we will set to OFF the value of the
 AUTOMATIC_DIALOG_SUPPORT property, whose default value is
 ON. This property determines if the underlying implementation
 automatically generates and handles dialog objects. This is quite useful
 if we want to implement dialog-aware SIP applications such as User
 Agents. If, on the other hand, our application does not need to be aware
 of dialogs, there is no need to impose this additional overhead on the
 implementation. For those cases, the recommended value is OFF. That
 is the case of our SIP proxy application:
 myProperties.setProperty( "
 javax.sip.AUTOMATIC_DIALOG_SUPPORT, “, " OFF " );

Proxying Requests
    A SIP proxy must at least differentiate between:
       CANCEL requests
       ACK requests
       Non-ACK, non-CANCEL requests (including INVITE, and so on)
Request myRequest=requestReceivedEvent.getRequest();
ServerTransaction myServerTransaction =
String method=myRequest.getMethod();
myGUI.displayServer( " <<< " +myRequest.toString());
if (myServerTransaction==null) {

Proxying Requests-
Non-ACK, Non-CANCEL Requests
    The first step is request validation. Our simple proxy will
    not implement any request validation. The next step is to
    check the topmost received RouteHeader and delete it if it
    coincides with our proxy address:
RouteHeader receivedRouteHeader =
(RouteHeader) myRequest.getHeader(RouteHeader.NAME);
SipURI receivedRouteHeaderSipURI=(SipURI)
Request newRequest = (Request) myRequest.clone();
if (receivedRouteHeaderDomain.equals(myIP)) {

Proxying Requests-
Non-ACK, Non-CANCEL Requests
    Next comes the essence of the proxy role,
    which is to determine the new target for the
    request. It will check the domain in the
    Request-URI. If the domain corresponds with
    the domain this proxy is responsible for, the
    proxy will query the location service using the
    received Request-URI as the key and
    retrieving the new Request-URI:
    omain) {
URI newRequestURI= (URI)
    The location service is implemented by a
    simple HashMap object, where the key
    elements are the addresses of record and where
    the values correspond to the contact addresses.

Proxying Requests-
Non-ACK, Non-CANCEL Requests
     Next the proxy should decrement the Max-Forwards header:
MaxForwardsHeader newMaxForwardsHeader=(MaxForwardsHeader)
     The following step is to include a Record-Route header if the proxy is configured to record-route:
if (recordRoute) {
Address proxyAddress = myAddressFactory.createAddress(mySipURI);
RecordRouteHeader recordRouteHeader =
     The next step in proxy processing is Route header modification. Our proxy does not define any local
     routing policy, so it will not further modify the Route header.
     Next the proxy needs to add the Via header and send the new request statefully:
ViaHeader vH = myHeaderFactory.createViaHeader(myIP, myPort, " udp, " null);
ClientTransaction myClientTransaction=mySipProvider.getNewClientTransaction(newRequest);
String bid=myClientTransaction.getBranchId();
myGUI.displayClient( " >>> " +newRequest.toString());

 Proxying Requests-
 Non-ACK, Non-CANCEL Requests
The context information needs to
hold sufficient information in order
to implement these scenarios. At
least it must contain the mapping
between server and client
transaction. We have created an
ArrayList in SipproxyListener
called transactionContext , which
keeps all the context information.
The ArrayList is composed of
Context objects. The Context class
is a new class that we have created.
It represents the state stored by the
proxy for each non-CANCEL, non-
ACK transaction that it handles.

 Proxying Requests-
 Non-ACK, Non-CANCEL Requests
The members of the Context class are shown in Table 13.2 .

Proxying Requests-
Non-ACK, Non-CANCEL Requests
 The last proxy processing step for non-CANCEL, non-ACK requests is
 to populate the transactionContext object:
  Context ctxt=new Context();
 And to update the displayed info in the management console:
  myGUI.appendOngoingTransactionDisplay(ctxt.method+ " " +
  ctxt.clientTrans.toString().substring(25) + " " +
  ctxt.serverTrans.toString().substring(25)+ " \n " );

Proxying Requests-
ACK Requests
 Two cases can be distinguished.
    The ACK request matches an existing transaction. This occurs if the ACK
    is generated by the UAC when it receives a non-2XX fi nal response. In
    those cases, the ACK is part of the INVITE transaction, and is processed
    just by the server transaction in the proxy. The ACK is not passed to our
    proxy application.
    The ACK request does not match an existing transaction. This occurs if the
    ACK is generated by the UAC when it receives a 2XX response. In those
    cases, the ACK is NOT part of the INVITE transaction, and is passed to our
    proxy application for processing.
 Therefore, we just need to provide code to cope with case 2. The ACK requests,
 in this case, are handled in the same way as non-CANCEL, non-ACK requests,
 except for the following aspects:
    ACK requests are forwarded statelessly:
 ACK requests do not generate context information. Therefore, the
 transactionContext object must not be updated.

Proxying Requests-
CANCEL Requests
 If the request is a CANCEL request, the proxy must explore the transactionContext
 object in order to retrieve the context information associated with the server transaction
 that is to be canceled.
 In order to find this information, the branch id in the CANCEL request is compared
 against the branch id of the server transactions stored in the transactionContext ArrayList
 . Once the corresponding element in the ArrayList is found, its data is used to generate
 and send a 487 (Request Terminated) response through the original server transaction,
 and a new CANCEL request that cancels the client transaction associated with the
 original server transaction. Likewise, a 200 OK response to the CANCEL request is sent
 back to the originator:
   Iterator iter = transactionContext.iterator();
   while (iter.hasNext()) {
   Context con=(Context);
   if (con.serverTrans.getBranchId().equals(myServerTransaction.
   getBranchId())) {
   Request originalRequest = (Request) con.requestIn;
   Response originalTransactionResponse =
   myMessageFactory.createResponse(487, originalRequest);
   Response cancelResponse = myMessageFactory.createResponse(200,
   Request newCancelRequest = con.clientTrans.createCancel();
   myGUI.displayServer( " >>> " + originalTransactionResponse.
   myGUI.displayServer( " >>> " + cancelResponse.toString());
   ClientTransaction cancelClientTransaction =
   myGUI.displayClient( " >>> " + newCancelRequest.toString());
   }                                                      (32)
Proxying Responses-(1)
 The response processing is quite simple. First we receive the response:
    ClientTransaction myClientTransaction=
    myGUI.displayClient( " <<< " + myResponse.toString());
 Then we check if the response is a 100 (Trying) or 487 (Request
 Terminated). We also check if the response corresponds to a
 CANCEL transaction. In all these cases, the proxy must not relay
 the response backward:
    int statusCode=myResponse.getStatusCode();
    CSeqHeader originalCSeq=
    (CSeqHeader) myClientTransaction.getRequest().
    String method=originalCSeq.getMethod();
    if ( (statusCode == 100)||(statusCode==487) ) return;
    if ( method.equals( " CANCEL " ) ) return;
Proxying Responses-(2)
 If the response does not match any of the previous conditions, normal response treatment continues. First
 we will clone the response and strip off the topmost ViaHeader :
   Response newResponse = (Response) myResponse.clone();
 Then we search the transactionContext for a Context object whose client transaction maps the one on which
 this response was received. If a match is found, the response is sent back through the corres ponding server
 transaction. If no match is found, the response is sent back statelessly:
   Iterator iter = transactionContext.iterator();
   while (iter.hasNext()) {
   Context con=(Context);
   if (con.clientTrans.equals(myClientTransaction)) {
   myGUI.displayServer( " >>> " + newResponse.toString());
   } else {
   Response newResponse = (Response) myResponse.clone();
   myGUI.displayServer( " >>> " + newResponse.toString());

Terminated Transactions
 Whenever a transaction is terminated, the JAIN SIP implementation fires a TransactionTerminatedEvent on to the SIP listener. We can use
 such a procedure in order to update the transactionContext object so that terminated transactions are deleted.
 The following code in the processTransactionTerminated method in SipproxyListener :
    public void processTransactionTerminated(TransactionTerminatedEvent
    transactionTerminatedEvent) {
    if (transactionTerminatedEvent.isServerTransaction()) {
    ServerTransaction st = transactionTerminatedEvent.
    Iterator iter = transactionContext.iterator();
    myGUI.jTextArea3.setText( " " );
    while(iter.hasNext()) {
    Context con=(Context);
    if (con.serverTrans.equals(st)) {
    else myGUI.appendOngoingTransactionsDisplay(con.method+ " " +
    " " +con.serverTrans.toString().substring(25)+ " \n " );

Handling Registrations
 Processing of REGISTER requests is quite straightforward. First we will check if the Expires header contains a zero
 value, indicating a deregistration.
 If that is the case, the corresponding entry in the location service is deleted by using the remove() method in the
 locationService HashMap .
 Otherwise the location service is updated using the put() method:
   ToHeader registerToHeader = (ToHeader) myRequest.getHeader
   URI addressOfRecord = registerToHeader.getAddress().getURI();
   ContactHeader registerContactHeader =
   (ContactHeader) myRequest.getHeader(ContactHeader.NAME);
   URI contactAddress = registerContactHeader.getAddress().getURI();
   ExpiresHeader expH=(ExpiresHeader) myRequest.
   int exp=expH.getExpires();
   if (exp==0) locationService.remove(addressOfRecord);
   else locationService.put(addressOfRecord, contactAddress);
 Then a new 200 OK response is generated and sent back to the UAC. The received Contact header and
 Expires header are copied in the response:
   Response registerOK=myMessageFactory.createResponse(200,myRequest);
   myGUI.displayServer( " >>> " +registerOK.toString());

The Enhanced Client-(1)
     The differences are described next:
     There is a new text box that allows the
     user to configure the IP address of the
     home SIP server. This is a crucial
     configuration parameter that will be
     passed to the Softphone2Listener
     constructor method. It represents the
     address where registrations need to be
     sent, as well as the address of the
     outbound proxy to use for outgoing calls.
     The new Softphone2Listener constructor
     method has the following signature:
          public Softphone2Listener(int
             port,String name,String
             ID,Softphone2GUI GUI, String
    The sipserver argument is stored in the
      myServer class variable of
      Softphone2Listener .
 The ID box is now renamed Public ID, and it
 must now contain the full public ID of the
 user—that is, both userinfo and domain fields
 in the following
 format: userinfo@domain

The Enhanced Client-(2)
 The main difference from Softphone1Listener is the fact that the new
 softphone needs to register against a SIP server. This leads us to add a
 couple of new states to our soft-phone application. Those states are:
    UNREGISTERED: It represents the state the application enters when the
    registration process is not successful.
    REGISTERING: It represents the state the application enters when the
    REGISTER message has been sent out, but a response has not yet been
    received from the server.
 Also, the IDLE state is redefi ned to mean that the soft-phone is
 actually registered.

The Enhanced Client-(3)
 In the constructor method, Softphone2Listener we will now include the generation and sending of the REGISTER command:
    Address registrarAddress=myAddressFactory.createAddress( " sip: "+myServer);
    Address registerToAddress = fromAddress;
    Address registerFromAddress=fromAddress;
    ToHeader myToHeader = myHeaderFactory.createToHeader(registerToAddress, null);
    FromHeader myFromHeader = myHeaderFactory.createFromHeader(registerFromAddress,
    " 647554 " );
    myViaHeader = myHeaderFactory.createViaHeader(myIP,myPort, " udp, " null);
    ArrayList myViaHeaders = new ArrayList();
    MaxForwardsHeader myMaxForwardsHeader = myHeaderFactory.createMaxForwardsHeader(70);
    CSeqHeader myCSeqHeader = myHeaderFactory.createCSeqHeader(1," REGISTER " );
    ExpiresHeader myExpiresHeader=myHeaderFactory.
    CallIdHeader myCallIDHeader = mySipProvider.getNewCallId();
    SipURI myRequestURI = (SipURI) registrarAddress.getURI();
    Request myRegisterRequest = myMessageFactory.createRequest(myRequestURI, " REGISTER, "
    myCallIDHeader, myCSeqHeader, myFromHeader,
    myClientTransaction = mySipProvider.getNewClientTransaction(myRegisterRequest);
    String bid=myClientTransaction.getBranchId();

The Enhanced Client-(4)
 The other difference in Softphone2Listener as compared to
 Softphone1Listener is the fact that when sending the INVITE request
 (when the user presses the “ Yes ” button in IDLE state), now a Route
 header needs to be included, pointing to the confi gured SIP server:
  Address routeAddress = myAddressFactory.createAddress( " sip: "
   +myServer+ " ;lr " );

Putting It All Together


Shared By: