Click2Dial- Code II

From Wesip

From Wesip

C2CDefaultServlet

The C2CDefaultServlet servlet is responsible for servlet initialization stuff and SIP logic common to both the source and the destination call legs. C2CSrcCallSipServlet and C2CDstCallSipServlet inherit such logic.

The initialization simply stores references to the ServletContext and the SipFactory as class fields for easier access from the servlets.

The common SIP logic manages authentication errors and BYE messages. The authentication code will retry INVITEs wich are required to authenticate adding the authentication header with the credentials properly encoded following the typical proxy authentication handshake.

//Creates a new INVITE request in the same session of the answer received.
SipServletRequest invite = errResp.getSession().createRequest("INVITE");
//Obtain credentials
String user = c2cSS.getUser();
String password = c2cSS.getPassword();
//Set the header Authorization Proxy or WWW 
MessageDigestAlgorithm.setAuthInfo(user, password, errResp, invite);
//If the first INVITE had content 
//we have to copy it new INVITE created.
if(errResp.getRequest().getContent() != null){
   invite.setContent(errResp.getRequest().getContent(), 
                     errResp.getRequest().getContentType());
}

....

// Send the new INVITE with auth header.
invite.send();

Note how the developer doesn't have to ACK the failure response. The container ACK automatically all non-2xx response for him/her.

The management of BYE requests is very simple. When a BYE arrives it is answered with a 200OK and then the peer leg is dropped with the generation of a BYE from the B2BUA. After that HttpSession clean up takes place in order to allow the end user to make new calls.

C2CSrcCallSipServlet

The C2CSrcCallSipServlet manages the source call leg. It extends from CDCDefaultServlet and overrides two methods.

The first is doProvisionalResponse(SipServletResponse provisional) where the servlet updates the status of the source connection to reflect progress of the call as reported by the different provisional responses. Note how the C2CSession bean is used to track state

c2cSS.setSrcState(DELIVERY_STATUS);

and how it is retrieved from the application session

// Get the c2cSession from the ApplicationSession.
C2CSession c2cSS = 
  (C2CSession) provisional.
                    getApplicationSession().
                    getAttribute(C2CSESSION);


The second overriden method and more interesting is doSuccessResponse(SipServletResponse response) which initiates the second call leg upon reception of a success response from the caller.

// Create a new call leg to reach the destination
SipServletRequest inviteDestination = 
     sipFactory.createRequest(response.getApplicationSession(),
                              "INVITE",
                              c2cSS.getSrcAddress(),
                              c2cSS.getDstAddress());
//The responses and subsequent requests of the destination call leg
//will be managed by the destination sip servlet
inviteDestination.getSession().setHandler(C2C_DST_SIP_SERVLET);

Again, we have UAC behaviour with the usage of SipFactory to create the initial request of the new dialog and the call to setHandler to delegate handling of the newly created call to a third servlet.

There is a very common technique used when developing B2BUA applications. B2BUA applications have in common that typically manage scenarios with two call legs, two endpoints which actually communicate, and one B2BUA entity that stays in the middle. The technique consists in that each call leg holds a reference to its counterpart as a SipSession attribute. Both references are saved with the same name (i.e. PEER_SESSION). This way it's easier to implement B2BUA behaviour when a new request arrives, because the processing call leg always has a handle on the peer. In the example this is accomplished like this

//Each call leg will hold a reference 
//to the peer call leg as a session attribute
inviteDestination.getSession().setAttribute(PEER_SESSION, srcSipSession);
srcSipSession.setAttribute(PEER_SESSION, inviteDestination.getSession());


As per the 3pcc model the SDP offer received in the 200OK of the caller must be placed in the INVITE to the callee. The SDP is the content of the response message and is copied to the initial request with the line

//Set the downstream SDP
inviteDestination.setContent(response.getContent(), 
                             response.getContentType());

C2CDstCallSipServlet

Just like C2CSrcCallSipServlet , C2CDstCallSipServlet extends C2CDefaultServlet. Again it overrides three methods. doProvisionalResponse(SipServletResponse provisional) with a behaviour identical to that of C2CSrcCallSipServlet, doErrorResponse(SipServletResponse errResp) and doSuccessResponse(SipServletResponse response).

doErrorResponse is overriden to handle the case where it is impossible to reach the callee of destination but we have already connected to the caller. In such case the caller leg must be dropped

SipSession srcSipSession = 
   (SipSession) errResp.getSession().getAttribute(PEER_SESSION);
srcSipSession.createRequest("BYE").send();

The doSuccessResponse overriden method closes the 3pcc handshake sending the callee SDP to the caller in the ACK (which was pending).

//Get the SRC SipSession
SipSession srcSipSession = 
   (SipSession) dstSipSession.getAttribute(PEER_SESSION);
//Get the Success Response of the caller leg so we can ACK
//We saved it in the source session, remember ?
SipServletResponse srcSuccessResponse = 
  (SipServletResponse) srcSipSession.getAttribute(CALLER_RESPONSE);
// ACK the caller leg using the received SDP
SipServletRequest otherAck = srcSuccessResponse.createAck();
otherAck.setContent(response.getContent(), response.getContentType());

Other files

Apart from the deployment descriptors, the jsp's, the servlet classes and the libraries the application includes other two important files to be taken into account. They are dwr.xml and server-config.wsdd and configure the Ajax-DWR and the Axis-webservice interfaces respectively.

<< Code