Package net.timewalker.ffmq3.listeners.tcp.io

Source Code of net.timewalker.ffmq3.listeners.tcp.io.TcpListener

/*
* This file is part of FFMQ.
*
* FFMQ is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* FFMQ 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with FFMQ; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/
package net.timewalker.ffmq3.listeners.tcp.io;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.security.KeyStore;

import javax.jms.JMSException;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLServerSocket;

import net.timewalker.ffmq3.FFMQCoreSettings;
import net.timewalker.ffmq3.FFMQException;
import net.timewalker.ffmq3.FFMQServerSettings;
import net.timewalker.ffmq3.jmx.JMXAgent;
import net.timewalker.ffmq3.listeners.ClientProcessor;
import net.timewalker.ffmq3.listeners.tcp.AbstractTcpClientListener;
import net.timewalker.ffmq3.local.FFMQEngine;
import net.timewalker.ffmq3.transport.PacketTransport;
import net.timewalker.ffmq3.transport.PacketTransportException;
import net.timewalker.ffmq3.transport.PacketTransportType;
import net.timewalker.ffmq3.transport.tcp.io.TcpPacketTransport;
import net.timewalker.ffmq3.utils.Settings;
import net.timewalker.ffmq3.utils.id.UUIDProvider;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
* TcpNetworkServer
*/
public final class TcpListener extends AbstractTcpClientListener implements Runnable, TcpListenerMBean
{   
    private static final Log log = LogFactory.getLog(TcpListener.class);

    // Runtime
    private ServerSocket serverSocket;
    private Thread listenerThread;
    private boolean stopRequired = false;
    private boolean usingSSL;
   
    /**
     * Constructor
     */
    public TcpListener( FFMQEngine engine ,
                        String listenAddr ,
                        int port ,
                        Settings settings )
    {
        this(engine,listenAddr,port,settings,null);
    }
   
    /**
     * Constructor
     */
    public TcpListener( FFMQEngine engine ,
                        String listenAddr ,
                        int port ,
                        Settings settings ,
                        JMXAgent jmxAgent )
    {
        super(engine,settings,jmxAgent,listenAddr,port);
        this.usingSSL = settings.getBooleanProperty(FFMQCoreSettings.TRANSPORT_TCP_SSL_ENABLED, false);
    }
   
    /* (non-Javadoc)
     * @see net.timewalker.ffmq3.listeners.AbstractListener#start()
     */
    public synchronized void start() throws JMSException
    {
      if (started)
        return;
     
      log.info("Starting listener ["+getName()+"]");
     
      stopRequired = false;
     
      initServerSocket();
      listenerThread = new Thread(this,"FFMQ-TCP-Server-"+serverSocket.getLocalPort());
      listenerThread.start();
     
      started = true;
    }

    /* (non-Javadoc)
     * @see net.timewalker.ffmq3.listeners.Listener#getName()
     */
    public String getName()
    {
      return (usingSSL ? PacketTransportType.TCPS : PacketTransportType.TCP)+"-"+listenAddr+"-"+listenPort;
    }
   
    private void initServerSocket() throws JMSException
  {
    try
        {
            InetAddress bindAddress = getBindAddress();           
            int tcpBackLog = settings.getIntProperty(FFMQServerSettings.LISTENER_TCP_BACK_LOG, DEFAULT_TCP_BACK_LOG);
            log.debug("TCP back log = "+tcpBackLog);
            
            serverSocket = createServerSocket(listenPort,tcpBackLog,bindAddress,usingSSL);
            serverSocket.setReuseAddress(true);
        }
        catch (JMSException e)
        {
            throw e;
        }
        catch (Exception e)
        {
          throw new FFMQException("Could not initialize server socket","NETWORK_ERROR",e);
        }
  }
 
    private void closeServerSocket()
  {
    // Close the listen socket
        try
        {
            if (serverSocket != null)
                serverSocket.close();
        }
        catch (IOException e)
        {
            log.error("Could not close server socket",e);
        }
        finally
        {
          serverSocket = null;
        }
  }
   
    /*
     * (non-Javadoc)
     * @see net.timewalker.ffmq3.utils.concurrent.SynchronizableThread#run()
     */
    public void run()
    {
        try
        {
            log.debug("Waiting for clients ["+getName()+"]");
            while (!stopRequired)
            {
                Socket clientSocket = serverSocket.accept();
               
                // Enforce listener capacity
                int activeClients = getActiveClients();
                if (activeClients >= listenerCapacity)
                {
                  log.warn("Listener is full (max="+listenerCapacity+"), dropping new connection attempt.");
                  try
                  {
                    clientSocket.close();
                  }
                  catch (Exception e)
                    {
                        log.error("Cannot close incoming connection",e);
                    }
                  continue;
                }
               
                String clientId = UUIDProvider.getInstance().getShortUUID();
                log.debug("Accepting a new client from "+clientSocket.getInetAddress().getHostAddress()+" ("+(activeClients+1)+") : "+clientId+" ["+getName()+"]");
                try
                {
                    ClientProcessor processor = createProcessor(clientId,clientSocket);
                    registerClient(processor);
                    processor.start();
                }
                catch (Exception e)
                {
                  try
                  {
                    clientSocket.close();
                  }
                  catch (Exception ex)
                  {
                    log.error("Could not close socket ["+getName()+"]",ex);
                  }
                 
                    log.error("Client failed : "+clientId+" ["+getName()+"]",e);
                }
            }
        }
        catch (Exception e)
        {
            if (!stopRequired)
                log.fatal("Server failed ["+getName()+"]",e);
        }
    }

    /**
     * Create a new processor
     */
    protected ClientProcessor createProcessor( String clientId , Socket clientSocket ) throws PacketTransportException
    {
      PacketTransport transport = new TcpPacketTransport(clientId,clientSocket,settings);
      ClientProcessor clientProcessor = new ClientProcessor(clientId,this,localEngine,transport);
      return clientProcessor;
    }
   
    /* (non-Javadoc)
     * @see net.timewalker.ffmq3.listeners.AbstractListener#stop()
     */
    public synchronized void stop()
    {
      if (!started)
        return;
     
      log.info("Stopping listener ["+getName()+"]");
     
        stopRequired = true;
       
        // Close the listen socket
        closeServerSocket();
       
        // Wait for listener thread to stop
        try
        {
          if (listenerThread != null)
            listenerThread.join();
        }
        catch (InterruptedException e)
        {
          log.error("Wait for listener thread termination was interrupted");
        }
        finally
        {
          listenerThread = null;
        }
       
        // Then stop remaining clients
        closeRemainingClients();
       
        started = false;
    }
   
    private ServerSocket createServerSocket( int port , int tcpBackLog , InetAddress localAddr , boolean useSSL ) throws JMSException
    {
        try
        {
            if (useSSL)
            {
                SSLServerSocket socket = (SSLServerSocket)createSSLContext().getServerSocketFactory().createServerSocket(port,tcpBackLog,localAddr);
                socket.setNeedClientAuth(false);
                return socket;
            }
            else
                return new ServerSocket(port,tcpBackLog,localAddr);
        }
        catch (Exception e)
        {
            throw new FFMQException("Cannot create server socket","NETWORK_ERROR",e);
        }
    }
   
    private SSLContext createSSLContext() throws JMSException
    {
        try
        {
            String sslProtocol = settings.getStringProperty(FFMQCoreSettings.TRANSPORT_TCP_SSL_PROTOCOL, "SSLv3");
            String keyManagerAlgorithm = settings.getStringProperty(FFMQCoreSettings.TRANSPORT_TCP_SSL_KEYMANAGER_ALGORITHM, "SunX509");
            String keyStoreType = settings.getStringProperty(FFMQCoreSettings.TRANSPORT_TCP_SSL_KEYSTORE_TYPE, "JKS");
            String keyStorePath = settings.getStringProperty(FFMQCoreSettings.TRANSPORT_TCP_SSL_KEYSTORE_PATH, "../conf/server-keystore.jks");
            String keyStorePass = settings.getStringProperty(FFMQCoreSettings.TRANSPORT_TCP_SSL_KEYSTORE_PASWORD, "ffmqpass");
            String keyPass = settings.getStringProperty(FFMQCoreSettings.TRANSPORT_TCP_SSL_KEYSTORE_KEY_PASSWORD, "ffmqpass");
           
            SSLContext sslContext = SSLContext.getInstance(sslProtocol);
            log.debug("Created an SSL context : protocol=["+sslContext.getProtocol()+"] provider=["+sslContext.getProvider()+"]");
           
            // Load available keys
            KeyManager[] keyManagers;
            File keyStoreFile = new File(keyStorePath);
            if (!keyStoreFile.canRead())
                throw new FFMQException("Cannot read keystore file : "+keyStoreFile.getAbsolutePath(),"FS_ERROR");
               
            KeyStore ks = KeyStore.getInstance(keyStoreType);
            log.debug("Created keystore : type=["+ks.getType()+"] provider=["+ks.getProvider()+"]");
            char ksPass[] = keyStorePass.toCharArray();
            char ctPass[] = keyPass.toCharArray();
            log.debug("Loading keystore from "+keyStoreFile.getAbsolutePath());
            InputStream kis = new FileInputStream(keyStoreFile);
            ks.load(kis, ksPass);
            kis.close();
           
            KeyManagerFactory kmf = KeyManagerFactory.getInstance(keyManagerAlgorithm);
            log.debug("Created KeyManagerFactory : algorithm=["+kmf.getAlgorithm()+"] provider=["+kmf.getProvider()+"]");
            log.debug("Initializing KeyManagerFactory with keystore ...");
            kmf.init(ks, ctPass);
           
            keyManagers = kmf.getKeyManagers();
           
            sslContext.init(keyManagers, null, null);
           
            return sslContext;
        }
        catch (JMSException e)
        {
            throw e;
        }
        catch (Exception e)
        {
            throw new FFMQException("Cannot create SSL context","NETWORK_ERROR",e);
        }
    }
}
TOP

Related Classes of net.timewalker.ffmq3.listeners.tcp.io.TcpListener

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.