net.jradius.server.TCPListener.java Source code

Java tutorial

Introduction

Here is the source code for net.jradius.server.TCPListener.java

Source

/**
 * JRadius - A RADIUS Server Java Adapter
 * Copyright (C) 2004-2006 PicoPoint, B.V.
 * Copyright (c) 2006-2007 David Bird <david@coova.com>
 *
 * This library 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.1 of the License, or (at
 * your option) any later version.
 *
 * This library 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 this library; if not, write to the Free Software Foundation,
 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 *
 */

package net.jradius.server;

import java.io.FileInputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.BlockingQueue;

import javax.net.ServerSocketFactory;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;

import net.jradius.exception.RadiusException;
import net.jradius.log.RadiusLog;
import net.jradius.server.config.Configuration;
import net.jradius.server.config.ListenerConfigurationItem;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.pool.ObjectPool;
import org.apache.commons.pool.PoolableObjectFactory;
import org.apache.commons.pool.impl.SoftReferenceObjectPool;

/**
 * The base abstract class of all Listeners
 * 
 * @author Gert Jan Verhoog
 * @author David Bird
 */
public abstract class TCPListener extends JRadiusThread implements Listener {
    protected Log log = LogFactory.getLog(getClass());

    protected boolean active = false;
    protected ListenerConfigurationItem config;

    protected BlockingQueue<ListenerRequest> queue;

    protected int port = 1814;
    protected int backlog = 1024;
    protected boolean requiresSSL = false;
    protected boolean usingSSL = false;
    protected boolean keepAlive;

    protected ServerSocket serverSocket;

    protected final List<KeepAliveListener> keepAliveListeners = new LinkedList<KeepAliveListener>();

    protected boolean sslWantClientAuth;
    protected boolean sslNeedClientAuth;
    protected String[] sslEnabledProtocols;
    protected String[] sslEnabledCiphers;

    protected ObjectPool requestObjectPool = new SoftReferenceObjectPool(new PoolableObjectFactory() {
        public boolean validateObject(Object arg0) {
            return true;
        }

        public void passivateObject(Object arg0) throws Exception {
        }

        public Object makeObject() throws Exception {
            return new TCPListenerRequest();
        }

        public void destroyObject(Object arg0) throws Exception {
        }

        public void activateObject(Object arg0) throws Exception {
            TCPListenerRequest req = (TCPListenerRequest) arg0;
            req.clear();
        }
    });

    public void setConfiguration(ListenerConfigurationItem cfg) {
        try {
            setConfiguration(cfg, false);
        } catch (Exception e) {
            e.printStackTrace();
            RadiusLog.error("Invalid JRadius configuration.", e);
        }
    }

    public void setConfiguration(ListenerConfigurationItem cfg, boolean noKeepAlive)
            throws KeyStoreException, NoSuchAlgorithmException, CertificateException, UnrecoverableKeyException,
            KeyManagementException, IOException {
        keepAlive = !noKeepAlive;
        config = cfg;

        Map props = config.getProperties();

        String s = (String) props.get("port");
        if (s != null)
            port = new Integer(s).intValue();

        s = (String) props.get("backlog");
        if (s != null)
            backlog = new Integer(s).intValue();

        if (keepAlive) {
            s = (String) props.get("keepAlive");
            if (s != null)
                keepAlive = new Boolean(s).booleanValue();
        }

        String useSSL = (String) props.get("useSSL");
        String trustAll = (String) props.get("trustAll");

        if (requiresSSL || "true".equalsIgnoreCase(useSSL)) {
            KeyManager[] keyManagers = null;
            TrustManager[] trustManagers = null;

            String keyManager = (String) props.get("keyManager");

            if (keyManager != null && keyManager.length() > 0) {
                try {
                    KeyManager manager = (KeyManager) Configuration.getBean(keyManager);
                    keyManagers = new KeyManager[] { manager };
                } catch (Exception e) {
                    e.printStackTrace();
                }
            } else {
                String keystore = (String) props.get("keyStore");
                String keystoreType = (String) props.get("keyStoreType");
                String keystorePassword = (String) props.get("keyStorePassword");
                String keyPassword = (String) props.get("keyPassword");

                if (keystore != null) {
                    if (keystoreType == null)
                        keystoreType = "pkcs12";

                    KeyStore ks = KeyStore.getInstance(keystoreType);
                    ks.load(new FileInputStream(keystore),
                            keystorePassword == null ? null : keystorePassword.toCharArray());

                    KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
                    kmf.init(ks, keyPassword == null ? null : keyPassword.toCharArray());
                    keyManagers = kmf.getKeyManagers();
                }
            }

            String trustManager = (String) props.get("trustManager");

            if (trustManager != null && trustManager.length() > 0) {
                try {
                    TrustManager manager = (TrustManager) Configuration.getBean(trustManager);
                    trustManagers = new TrustManager[] { manager };
                } catch (Exception e) {
                    e.printStackTrace();
                }
            } else if ("true".equalsIgnoreCase(trustAll)) {
                trustManagers = new TrustManager[] { new X509TrustManager() {
                    public void checkClientTrusted(X509Certificate[] chain, String authType) {

                    }

                    public void checkServerTrusted(X509Certificate[] chain, String authType) {

                    }

                    public X509Certificate[] getAcceptedIssuers() {
                        return new X509Certificate[0];
                    }
                } };
            } else {
                String keystore = (String) props.get("caStore");
                String keystoreType = (String) props.get("caStoreType");
                String keystorePassword = (String) props.get("caStorePassword");

                if (keystore != null) {
                    if (keystoreType == null)
                        keystoreType = "pkcs12";

                    KeyStore caKeys = KeyStore.getInstance(keystoreType);
                    caKeys.load(new FileInputStream(keystore),
                            keystorePassword == null ? null : keystorePassword.toCharArray());
                    TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
                    tmf.init(caKeys);
                    trustManagers = tmf.getTrustManagers();
                }
            }

            SSLContext sslContext = SSLContext.getInstance("SSLv3");
            sslContext.init(keyManagers, trustManagers, null);

            ServerSocketFactory socketFactory = sslContext.getServerSocketFactory();
            SSLServerSocket sslServerSocket = (SSLServerSocket) socketFactory.createServerSocket(port, backlog);
            serverSocket = sslServerSocket;

            if (sslWantClientAuth)
                sslServerSocket.setWantClientAuth(true);

            if (sslNeedClientAuth)
                sslServerSocket.setNeedClientAuth(true);

            if (sslEnabledProtocols != null)
                sslServerSocket.setEnabledProtocols(sslEnabledProtocols);

            if (sslEnabledCiphers != null)
                sslServerSocket.setEnabledCipherSuites(sslEnabledCiphers);

            usingSSL = true;
        } else {
            serverSocket = new ServerSocket(port, backlog);
        }

        serverSocket.setReuseAddress(true);
        setActive(true);
    }

    /**
     * Sets the request queue for this listener
     * 
     * @param q the RequestQueue;
     */
    public void setRequestQueue(BlockingQueue<ListenerRequest> q) {
        queue = q;
    }

    /**
     * Sets the listeners ConfigurationItem
     * @param cfg a configuration item
     */
    public void setListenerConfigurationItem(ListenerConfigurationItem cfg) {
        config = cfg;
        this.setName(config.getName());
    }

    /**
     * Listen for one object and place it on the request queue
     * @throws IOException
     * @throws InterruptedException
     * @throws RadiusException
     */
    public void listen() throws Exception {
        RadiusLog.debug("Listening on socket...");
        Socket socket = serverSocket.accept();

        socket.setTcpNoDelay(false);

        if (keepAlive) {
            KeepAliveListener keepAliveListener = new KeepAliveListener(socket, this, queue);
            keepAliveListener.start();

            synchronized (keepAliveListeners) {
                keepAliveListeners.add(keepAliveListener);
            }
        } else {
            TCPListenerRequest lr = (TCPListenerRequest) requestObjectPool.borrowObject();
            lr.setBorrowedFromPool(requestObjectPool);
            lr.accept(socket, this, false, false);

            while (true) {
                try {
                    this.queue.put(lr);
                    break;
                } catch (InterruptedException e) {
                }
            }
        }
    }

    public void deadKeepAliveListener(KeepAliveListener keepAliveListener) {
    }

    public boolean getActive() {
        return active;
    }

    public void setActive(boolean active) {
        this.active = active;
        if (!active) {
            for (KeepAliveListener listener : keepAliveListeners) {
                try {
                    listener.shutdown(true);
                } catch (Throwable e) {
                }
            }

            this.keepAliveListeners.clear();

            try {
                this.serverSocket.close();
            } catch (Throwable e) {
            }

            try {
                this.interrupt();
            } catch (Exception e) {
            }
        }
    }

    /**
     * The thread's run method repeatedly calls listen()
     */
    public void run() {
        while (getActive()) {
            try {
                Thread.yield();
                listen();
            } catch (SocketException e) {
                if (getActive() == false) {
                    break;
                } else {
                    RadiusLog.error("Socket exception", e);
                }
            } catch (InterruptedException e) {
            } catch (SSLException e) {
                RadiusLog.error("Error occured in TCPListener.", e);
                active = false;
            } catch (Throwable e) {
                RadiusLog.error("Error occured in TCPListener.", e);
            }
        }

        RadiusLog.debug("Listener: " + this.getClass().getName() + " exiting (not active)");
    }

    public boolean isUsingSSL() {
        return usingSSL;
    }

    public boolean isKeepAlive() {
        return keepAlive;
    }

    public void setBacklog(int backlog) {
        this.backlog = backlog;
    }

    public void setKeepAlive(boolean keepAlive) {
        this.keepAlive = keepAlive;
    }

    public void setPort(int port) {
        this.port = port;
    }

    public void setUsingSSL(boolean usingSSL) {
        this.usingSSL = usingSSL;
    }
}