/*
* Created on May 31, 2005
*
* Copyright 2005 CafeSip.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.cafesip.reference.jiplet;
import java.text.ParseException;
import java.util.ListIterator;
import javax.sip.InvalidArgumentException;
import javax.sip.ListeningPoint;
import javax.sip.RequestEvent;
import javax.sip.ResponseEvent;
import javax.sip.SipException;
import javax.sip.SipProvider;
import javax.sip.address.Address;
import javax.sip.header.ContactHeader;
import javax.sip.header.MaxForwardsHeader;
import javax.sip.header.ToHeader;
import javax.sip.header.ViaHeader;
import javax.sip.message.Request;
import javax.sip.message.Response;
import org.cafesip.jiplet.Jiplet;
import org.cafesip.jiplet.JipletException;
import org.cafesip.jiplet.JipletLogger;
import org.cafesip.jiplet.JipletRequest;
import org.cafesip.jiplet.JipletResponse;
import org.cafesip.jiplet.JipletSession;
import org.cafesip.jiplet.config.jip.JipletConfig;
import org.cafesip.jiplet.sip.ProxyUtilities;
/**
* @author Amit Chatterjee
*
*/
public class SipProxy extends Jiplet
{
private Object callIdLock = new Object();
private int callId = 0;
/**
* A constructor for this class.
*
*
*/
public SipProxy()
{
super();
}
/*
* @see org.cafesip.jiplet.Jiplet#init(org.cafesip.jiplet.config.jip.JipletConfig)
*/
public void init(JipletConfig config) throws JipletException
{
super.init(config);
ListeningPoint lp = getListeningPointDefault();
info("Started SIP stateless proxy on IP=" + lp.getIPAddress() + " port=" + lp.getPort()
+ " protocol=" + lp.getTransport());
}
/*
* @see org.cafesip.jiplet.Jiplet#processRequest(org.cafesip.jiplet.JipletRequest)
*/
public void processRequest(JipletRequest requestEvent)
{
// print the trace provided by the base-class.
super.processRequest(requestEvent);
try
{
RequestEvent req_event = requestEvent.getRequestEvent();
Request req_msg = req_event.getRequest();
SipProvider provider = (SipProvider) req_event.getSource();
JipletSession session = null;
if (req_msg.getMethod().equals(Request.INVITE) == true)
{
session = requestEvent.getSession(true);
synchronized (callIdLock)
{
callId++;
info ("SIP session " + callId + " created.");
session.setAttribute("callId", new Integer(callId));
ListeningPoint lp = provider.getListeningPoints()[0];
session.setAttribute("requestSourceIp", new String(lp.getIPAddress()));
session.setAttribute("requestSourcePort", new Integer(lp.getPort()));
}
}
else
{
session = requestEvent.getSession(false);
if (session != null)
{
Integer c = (Integer) session.getAttribute("callId");
if (c != null)
{
info("SIP request message received for session " + c);
}
}
if (req_msg.getMethod().equals(Request.BYE) == true)
{
if (session != null)
{
session.invalidate();
}
}
}
// Act as a stateless proxy. Forward the message to the phone.
ToHeader to = (ToHeader) req_msg.getHeader(ToHeader.NAME);
String addr = to.getAddress().getURI().toString();
// check if user has registered
ContactInfo contact = (ContactInfo) LocationDatabase
.getInstance().get(addr);
if (contact == null)
{
debug("Request message received for an unknown user. Tossing the request");
return;
}
// the message is for a location that has registered. Forward the message.
forwardRequestMessage(req_msg, contact.getContact(), getListeningPointDefault());
}
catch (Exception e)
{
fatal(e.getClass().getName() + ": " + e.getMessage() + "\n"
+ JipletLogger.getStackTrace(e));
}
finally
{
// forward to the SipRecorder so that it can record the request message.
forward(requestEvent, "ExampleSIPRecorderJiplet"); // this should be the last thing we do
}
}
private void forwardRequestMessage(Request request, ContactHeader contact,
ListeningPoint listeningPoint) throws ParseException,
InvalidArgumentException, SipException
{
Request req = (Request) request.clone();
// replace the URI with the contact URI
Address address = contact.getAddress();
req.setRequestURI(address.getURI());
// add the VIA header
ViaHeader via = getHeaderFactory().createViaHeader(
listeningPoint.getIPAddress(), listeningPoint.getPort(),
listeningPoint.getTransport(),
ProxyUtilities.generateBranchId());
req.addHeader(via);
// decrement the hop count
int num_forwards = 70;
MaxForwardsHeader forwards = (MaxForwardsHeader) request
.getHeader(MaxForwardsHeader.NAME);
if (forwards != null)
{
num_forwards = forwards.getMaxForwards() - 1;
if (num_forwards <= 0)
{
// oops, we are not supposed to forward further, but since we
// are not a real proxy server,
// we will do it anyways. Hopefully, the next guy will catch it.
num_forwards = 1;
}
}
forwards = getHeaderFactory().createMaxForwardsHeader(num_forwards);
req.setHeader(forwards);
debug("Forwarding the request message to " + contact.getAddress());
getSipProvider(listeningPoint).sendRequest(req);
// register for response for requests for which responses are expected.
String method = req.getMethod();
// TODO add other methods
if (method.equals(Request.ACK) == false)
{
registerForResponse(req, 30000L);
}
}
/*
* @see org.cafesip.jiplet.Jiplet#processResponse(org.cafesip.jiplet.JipletResponse)
*/
public void processResponse(JipletResponse responseEvent)
{
// print the trace provided by the base-class.
super.processResponse(responseEvent);
SipProvider provider = getSipProvider(getListeningPointDefault());
JipletSession session = responseEvent.getSession(false);
if (session != null)
{
Integer c = (Integer) session.getAttribute("callId");
if (c != null)
{
info("SIP request message received for session " + c);
}
String sourceIp = (String) session.getAttribute("requestSourceIp");
if (sourceIp != null)
{
int sourcePort = ((Integer) session.getAttribute("requestSourcePort")).intValue();
provider = getSipProvider(sourceIp, sourcePort);
}
}
try
{
ResponseEvent rsp_event = responseEvent.getResponseEvent();
Response rsp_msg = rsp_event.getResponse();
forwardResponseMessage(rsp_msg, provider);
}
catch (Exception e)
{
fatal(e.getClass().getName() + ": " + e.getMessage() + "\n"
+ JipletLogger.getStackTrace(e));
}
finally
{
// forward to the SipRecorder so that it can record the response message.
forward(responseEvent, "ExampleSIPRecorderJiplet"); // this should be the last thing we do
}
}
private void forwardResponseMessage(Response response,
SipProvider provider)
throws InvalidArgumentException, SipException
{
Response resp = (Response) response.clone();
ListIterator iter = resp.getHeaders(ViaHeader.NAME);
if (iter != null)
{
iter.next();
iter.remove();
}
if (isDebugEnabled() == true)
{
debug("Forwarding the response");
}
provider.sendResponse(resp);
}
}