package com.rayo.sbcrouter; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.sip.Proxy; import javax.servlet.sip.ServletParseException; import javax.servlet.sip.SipFactory; import javax.servlet.sip.SipServlet; import javax.servlet.sip.SipServletRequest; import javax.servlet.sip.SipServletResponse; import javax.servlet.sip.TooManyHopsException; import javax.servlet.sip.URI; import org.apache.log4j.Logger; import com.rayo.server.storage.DefaultGatewayStorageService; import com.rayo.server.storage.model.Application; import com.rayo.server.storage.model.RayoNode; import com.rayo.storage.cassandra.CassandraDatastore; import com.rayo.storage.lb.BlacklistingLoadBalancer; import com.rayo.storage.lb.PriorityBasedLoadBalancer; public class SBCRouterServlet extends SipServlet { private static final long serialVersionUID = -5565293666294007230L; private static Logger LOG = Logger.getLogger(SBCRouterServlet.class); private CassandraDatastore dataStore; private DefaultGatewayStorageService storageService; private BlacklistingLoadBalancer loadBalancer; private SipFactory _sipFactory; @Override public void init() throws ServletException { _sipFactory = (SipFactory) getServletContext().getAttribute(SipFactory.class.getName()); String hostName = getServletConfig().getInitParameter("CassandraHost"); String port = getServletConfig().getInitParameter("CassandraPort"); if (hostName == null || port == null) { throw new IllegalArgumentException("Please configure servlet parameter: CassandraHost and CassandraPort."); } dataStore = new CassandraDatastore(); dataStore.setHostname(hostName); dataStore.setPort(port); dataStore.setOverrideExistingSchema(false); try { dataStore.init(); } catch (Exception ex) { LOG.error("Exception when initializing Cassandra connection, the properties:" + hostName + ":" + port, ex); throw new RuntimeException(ex); } storageService = new DefaultGatewayStorageService(); storageService.setStore(dataStore); loadBalancer = new PriorityBasedLoadBalancer(); loadBalancer.setStorageService(storageService); } @Override protected void doRequest(SipServletRequest req) throws ServletException, IOException { if (req.isInitial()) { proxyTo(req); } } @Override protected void doResponse(SipServletResponse resp) throws ServletException, IOException { processReponse(resp); } @Override protected void doBranchResponse(SipServletResponse resp) throws ServletException, IOException { processReponse(resp); } private void proxyTo(SipServletRequest req) { URI uri = req.getTo().getURI(); Application application = dataStore.getApplicationForAddress(uri.toString()); if (application == null) { LOG.error("Can't find application for request:" + req); LOG.debug("Trying to fetch default application: 'voxeo'"); application = dataStore.getApplication("voxeo"); if (application != null) { LOG.debug("Found application " + application + " for request:" + req); } else { return; } } else { if (LOG.isDebugEnabled()) { LOG.debug("Found application " + application + " for request:" + req); } } RayoNode node = loadBalancer.pickRayoNode(application.getPlatform()); if (node == null) { LOG.error("Could not find available node for request " + req); return; } else { if (LOG.isDebugEnabled()) { LOG.debug("Found node " + node + " for request:" + req); } req.setAttribute("CurrentTryingRayoNode", node); } try { Proxy proxy = req.getProxy(true); proxy.setAddToPath(true); proxy.setRecordRoute(true); proxy.setRecurse(false); proxy.setParallel(false); proxy.setSupervised(true); proxy.proxyTo(_sipFactory.createURI("sip:" + node.getIpAddress())); } catch (TooManyHopsException e) { LOG.error("Can't proxy request:" + req, e); } catch (ServletParseException e) { LOG.error("Can't parse uri " + "sip:" + node.getIpAddress(), e); } } private void processReponse(SipServletResponse resp) { if (resp.getStatus() >= 200) { SipServletRequest req = resp.getProxy().getOriginalRequest(); RayoNode oldNode = (RayoNode) req.getAttribute("CurrentTryingRayoNode"); if ((resp.getStatus() >= 500 && resp.getStatus() < 600) || (resp.getStatus() == SipServletResponse.SC_REQUEST_TIMEOUT && resp.getReasonPhrase().equalsIgnoreCase( "Request Timeout:Proxy Created Internally"))) { LOG.warn("Node operation failed:" + oldNode + " for request:" + req); loadBalancer.nodeOperationFailed(oldNode); proxyTo(req); } else { loadBalancer.nodeOperationSuceeded(oldNode); } } } }