/*
* TeleStax, Open Source Cloud Communications
* Copyright 2011-2013, Telestax Inc and individual contributors
* by the @authors tag.
*
* This program is free software: you can redistribute it and/or modify
* under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation; either version 3 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*/
package org.mobicents.tools.http.balancer;
import java.net.InetSocketAddress;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicLong;
import javax.servlet.ServletException;
import org.apache.log4j.Logger;
import org.jboss.netty.bootstrap.ClientBootstrap;
import org.jboss.netty.bootstrap.ServerBootstrap;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory;
import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
import org.mobicents.tools.http.urlrewriting.BalancerUrlRewriteFilter;
import org.mobicents.tools.sip.balancer.BalancerRunner;
/**
* @author Vladimir Ralev (vladimir.ralev@jboss.org)
* @author Jean Deruelle (jean.deruelle@telestax.com)
*/
public class HttpBalancerForwarder {
private static final Logger logger = Logger.getLogger(HttpBalancerForwarder.class.getCanonicalName());
ExecutorService executor;
public BalancerRunner balancerRunner;
NioServerSocketChannelFactory nioServerSocketChannelFactory = null;
NioClientSocketChannelFactory nioClientSocketChannelFactory = null;
Channel serverChannel;
Channel serverSecureChannel;
public void start() {
executor = Executors.newCachedThreadPool();
nioServerSocketChannelFactory = new NioServerSocketChannelFactory(executor, executor);
nioClientSocketChannelFactory = new NioClientSocketChannelFactory(executor, executor);
HttpChannelAssociations.serverBootstrap = new ServerBootstrap(nioServerSocketChannelFactory);
HttpChannelAssociations.serverSecureBootstrap = new ServerBootstrap(nioServerSocketChannelFactory);
HttpChannelAssociations.serverApiBootstrap = new ServerBootstrap(nioServerSocketChannelFactory);
HttpChannelAssociations.inboundBootstrap = new ClientBootstrap(nioClientSocketChannelFactory);
HttpChannelAssociations.channels = new ConcurrentHashMap<AdvancedChannel, AdvancedChannel>();
if(balancerRunner.getConfiguration().getHttpConfiguration().getUrlrewriteRule()!=null)
{
HttpChannelAssociations.urlRewriteFilter = new BalancerUrlRewriteFilter();
try {
HttpChannelAssociations.urlRewriteFilter.init(balancerRunner);
} catch (ServletException e) {
throw new IllegalStateException("Can't init url filter due to [ " + e.getMessage()+ " ] ", e);
}
}
// https://telestax.atlassian.net/browse/LB-7 making the default port the same
Integer httpPort = 2080;
if(balancerRunner.balancerContext.lbConfig != null)
httpPort = balancerRunner.balancerContext.lbConfig.getHttpConfiguration().getHttpPort();
logger.info("HTTP LB listening on port " + httpPort);
HttpChannelAssociations.serverBootstrap.setPipelineFactory(new HttpServerPipelineFactory(balancerRunner,false));
HttpChannelAssociations.serverBootstrap.setOption("child.tcpNoDelay", true);
HttpChannelAssociations.serverBootstrap.setOption("child.keepAlive", true);
serverChannel = HttpChannelAssociations.serverBootstrap.bind(new InetSocketAddress(httpPort));
Integer httpsPort = balancerRunner.balancerContext.lbConfig.getHttpConfiguration().getHttpsPort();
if(httpsPort != null)
{
logger.info("HTTPS LB listening on port " + httpsPort);
HttpChannelAssociations.serverSecureBootstrap.setPipelineFactory(new HttpServerPipelineFactory(balancerRunner, true));
serverSecureChannel = HttpChannelAssociations.serverSecureBootstrap.bind(new InetSocketAddress(httpsPort));
if(!balancerRunner.balancerContext.terminateTLSTraffic)
{
HttpChannelAssociations.inboundSecureBootstrap = new ClientBootstrap(nioClientSocketChannelFactory);
HttpChannelAssociations.inboundSecureBootstrap.setPipelineFactory(new HttpClientPipelineFactory(balancerRunner, true));
HttpChannelAssociations.inboundSecureBootstrap.setOption("child.tcpNoDelay", true);
HttpChannelAssociations.inboundSecureBootstrap.setOption("child.keepAlive", true);
}
}
Integer apiPort = balancerRunner.balancerContext.lbConfig.getCommonConfiguration().getStatisticPort();
if(apiPort != null)
{
logger.info("Load balancer API port : " + apiPort);
HttpChannelAssociations.serverApiBootstrap.setPipelineFactory(new HttpServerPipelineFactory(balancerRunner, false));
HttpChannelAssociations.serverApiChannel = HttpChannelAssociations.serverApiBootstrap.bind(new InetSocketAddress(apiPort));
}
HttpChannelAssociations.inboundBootstrap.setPipelineFactory(new HttpClientPipelineFactory(balancerRunner, false));
}
public void stop() {
if(executor == null) return; // already stopped
for (Entry<AdvancedChannel, AdvancedChannel> entry : HttpChannelAssociations.channels.entrySet()) {
entry.getKey().getChannel().unbind();
entry.getKey().getChannel().close();
entry.getKey().getChannel().getCloseFuture().awaitUninterruptibly();
entry.getValue().getChannel().unbind();
entry.getValue().getChannel().close();
entry.getValue().getChannel().getCloseFuture().awaitUninterruptibly();
}
serverChannel.unbind();
serverChannel.close();
serverChannel.getCloseFuture().awaitUninterruptibly();
if(serverSecureChannel!=null)
{
serverSecureChannel.unbind();
serverSecureChannel.close();
serverSecureChannel.getCloseFuture().awaitUninterruptibly();
}
if(HttpChannelAssociations.serverApiChannel!=null)
{
HttpChannelAssociations.serverApiChannel.unbind();
HttpChannelAssociations.serverApiChannel.close();
HttpChannelAssociations.serverApiChannel.getCloseFuture().awaitUninterruptibly();
}
executor.shutdownNow();
executor = null;
//cleaning everything
HttpChannelAssociations.serverBootstrap.shutdown();
if(HttpChannelAssociations.serverSecureBootstrap!=null)
HttpChannelAssociations.serverSecureBootstrap.shutdown();
if(HttpChannelAssociations.serverApiBootstrap!=null)
HttpChannelAssociations.serverApiBootstrap.shutdown();
HttpChannelAssociations.inboundBootstrap.shutdown();
if(HttpChannelAssociations.inboundSecureBootstrap!=null)
HttpChannelAssociations.inboundSecureBootstrap.shutdown();
nioServerSocketChannelFactory.shutdown();
nioClientSocketChannelFactory.shutdown();
// System.gc();
}
//Statistic
/**
* @return the httpRequestCount
*/
public long getNumberOfHttpRequests()
{
return balancerRunner.balancerContext.httpRequests.get();
}
/**
* @return the httpBytesToServer
*/
public long getNumberOfHttpBytesToServer()
{
return balancerRunner.balancerContext.httpBytesToServer.get();
}
/**
* @return the httpBytesToClient
*/
public long getNumberOfHttpBytesToClient()
{
return balancerRunner.balancerContext.httpBytesToClient.get();
}
/**
* @return the httpRequestsProcessedByMethod
*/
public long getHttpRequestsProcessedByMethod(String method)
{
AtomicLong httpRequestsProcessed = balancerRunner.balancerContext.httpRequestsProcessedByMethod.get(method);
if(httpRequestsProcessed != null) {
return httpRequestsProcessed.get();
}
return 0;
}
/**
* @return the httpResponseProcessedByCode
*/
public long getHttpResponseProcessedByCode(String code)
{
AtomicLong httpRequestsProcessed = balancerRunner.balancerContext.httpResponseProcessedByCode.get(code);
if(httpRequestsProcessed != null) {
return httpRequestsProcessed.get();
}
return 0;
}
/**
* @return the NumberOfActiveHttpConnections
*/
public int getNumberOfActiveHttpConnections()
{
return HttpChannelAssociations.channels.size();
}
}