All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.coos.messaging.transport.SecureTCPTransport Maven / Gradle / Ivy

There is a newer version: 1.3.1
Show newest version
/**
 * COOS - Connected Objects Operating System (www.connectedobjects.org).
 *
 * Copyright (C) 2009 Telenor ASA and Tellu AS. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * 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 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 Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see .
 *
 * You may also contact one of the following for additional information:
 * Telenor ASA, Snaroyveien 30, N-1331 Fornebu, Norway (www.telenor.no)
 * Tellu AS, Hagalokkveien 13, N-1383 Asker, Norway (www.tellu.no)
 */
package org.coos.messaging.transport;

import java.io.DataInputStream;
import java.io.EOFException;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import java.net.InetSocketAddress;
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.SecureRandom;
import java.security.cert.CertificateException;

import javax.net.ssl.KeyManager;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;

import org.coos.messaging.Message;
import org.coos.messaging.ProcessorException;
import org.coos.messaging.Service;
import org.coos.messaging.Transport;
import org.coos.messaging.impl.DefaultMessage;
import org.coos.messaging.util.Log;
import org.coos.messaging.util.LogFactory;


/**
 * @author sverre SecureTCPTransport is a transport for COOS that implements the
 *         secure tcp.
 *
 *         This class is implemented to provide secure tcp communication in the
 *         COOS framework.
 * */
public class SecureTCPTransport extends TCPTransport implements Transport, Service {
    private static final Log logger = LogFactory.getLog(SecureTCPTransport.class.getName());

    String keyStore = "serverkeys";
    char[] keystoprepass = "hellothere".toCharArray();
    char[] keypassword = "hiagain".toCharArray();

    private String hostName;
    private int hostPort;
    // private SSLSocket socket;

    private Reader reader;
    private Writer writer;
    private boolean running = true;
    SecureTCPTransportManager tm;

    /**
     * Empty constructor to allow dynamic classloading
     * */
    public SecureTCPTransport() {
    }

    /**
     *
     * Constructor - creates a new instance of SecureTCPTransport
     *
     * @param hostIp
     *            - String indicating the ip of the host/server
     * @param hostPort
     *            - Integer indicating the host/server port
     *
     * */
    public SecureTCPTransport(String hostIP, int hostPort) {
        this.hostName = hostIP;
        this.hostPort = hostPort;
    }

    /**
     * Constructor used by the server to create a new transport on response to a
     * TCP request
     *
     * @param socket
     *            - SSLSocket to communicate with the server
     * */
    SecureTCPTransport(SSLSocket socket, SecureTCPTransportManager tm) {
        this.socket = socket;
        this.tm = tm;
    }

    /**
     * creates a SSLSocket
     *
     * @param port
     *            - Integer indicating the port of the socket
     * @param serverHost
     *            - String indicating the ip of the server/host
     *
     * @return a SSLSocket
     * @throws KeyStoreException
     * @throws CertificateException
     * @throws NoSuchAlgorithmException
     * @throws KeyManagementException
     * */
    public SSLSocket createClient(int port, String serverHost) throws IOException, KeyStoreException, NoSuchAlgorithmException, CertificateException,
        KeyManagementException {

        // set the context to SSL 3
        SSLContext sslcontext = SSLContext.getInstance("SSLv3");

        // use lines bellow to override default truststore
        if (properties.contains("truststore") && properties.contains("trustpw")) {

            KeyStore ks = KeyStore.getInstance("JKS");
            ks.load(new FileInputStream((String) properties.get("truststore")), ((String) properties.get("trustpw")).toCharArray());

            TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
            tmf.init(ks);

            sslcontext.init(null, tmf.getTrustManagers(), null);
        } else if (properties.containsKey("nosslcheck") && properties.get("nosslcheck").equals("true")) {
            TrustManager[] tm = new TrustManager[] { new NaiveTrustManager() };
            sslcontext.init(new KeyManager[0], tm, new SecureRandom());
        } else { // SSL without client certificate, with server certificate check
            sslcontext.init(null, null, null);
        }
        Socket socket = new Socket();
        socket.connect(new InetSocketAddress(hostName, hostPort), CONNECT_TIMEOUT);
        SSLSocketFactory factory = sslcontext.getSocketFactory(); // (SSLSocketFactory)SSLSocketFactory.getDefault();
        SSLSocket client = (SSLSocket) factory.createSocket(socket, hostName, hostPort, true);

        return client;

        /*
         * KeyStore ks = KeyStore.getInstance("JKS"); ks.load(new
         * FileInputStream("serverkeys"), "Wakka1337".toCharArray());
         * KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
         * kmf.init(ks, "Smorka".toCharArray());
         *
         * // set the context to SSL 3 SSLContext sslcontext =
         * SSLContext.getInstance("SSLv3");
         * sslcontext.init(kmf.getKeyManagers(), null, null);
         *
         * // create the socket SSLSocketFactory ssf =
         * sslcontext.getSocketFactory(); SSLSocket socket = (SSLSocket)
         * ssf.createSocket("127.0.0.1", port);
         *
         *
         * return socket;
         */
    }

    /**
     *
     * Starts the transport. I.E. connects the socket, and instantiate it if it
     * is null, and starts the reader and writer.
     *
     * */
    public void start() throws Exception {

        // set the flag that makes the transport run
        running = true;

        if (socket != null) {

            // Socket already exist, Start reader and writer
            reader = new Reader();
            writer = new Writer();

            return;
        }

        // socket does not exist, must be established before starting reader and
        // writer
        if (hostName == null) {
            hostName = (String) properties.get(PROPERTY_HOST);
        }

        if (properties.get(PROPERTY_PORT) != null) {
            hostPort = Integer.valueOf((String) properties.get(PROPERTY_PORT));
        }

        String retryStr = (String) properties.get(PROPERTY_RETRY);

        if ((retryStr != null) && retryStr.equals("true")) {
            retry = true;
        } else {
            retry = false;
        }

        if (properties.get(PROPERTY_RETRY_TIME) != null) {
            retryTime = Integer.valueOf((String) properties.get(PROPERTY_RETRY_TIME));
        }

        logger.info("Establishing transport to " + hostName + ":" + hostPort);

        if (retry) { // must retry in a separate thread

            Thread t = new Thread(new Runnable() {

                        public void run() {
                            boolean connecting = true;

                            try {

                                while (connecting && running) {

                                    try {
                                        socket = createClient(hostPort, hostName);
                                        connecting = false;
                                    } catch (IOException e) {
                                        logger.warn(
                                            "Establishing transport to " + hostName + ":" + hostPort + " failed. Retrying in " + retryTime +
                                            " millisec.");

                                        try {
                                            Thread.sleep(retryTime);
                                        } catch (InterruptedException e1) {
                                            logger.error("InterruptedException caught", e1);
                                        }
                                    }

                                    if (!connecting && running) {
                                        logger.info(
                                            "Transport from " + socket.getLocalSocketAddress() + " to " + socket.getRemoteSocketAddress() +
                                            " established.");
                                    }
                                }
                            } catch (Exception e) {
                                logger.error("Could not create ssl connection " + e.toString(), e);
                            }

                            if (running) {
                                reader = new Reader();
                                writer = new Writer();
                            }
                        }
                    });

            t.start();

        } else {

            try {
                socket = createClient(hostPort, hostName);
            } catch (IOException e) {
                running = false;
                logger.warn("Establishing transport to " + hostName + ":" + hostPort + " failed.");
                throw e;
            }

            if (running) {
                reader = new Reader();
                writer = new Writer();
            }
        }
    }

    /**
     * Stops the transport and takes down the connection(s)
     * */
    public void stop() throws Exception {
        logger.info("Closing transport: " + hostName + ":" + hostPort);
        running = false;

        if (reader != null) {
            reader.stop();
        }

        if (writer != null) {
            writer.stop();
        }

        if (socket != null) {
            socket.close();
        }

        socket = null;

        if (tm != null)
            tm.disconnect(this);
    }

    /**
     * class Reader consumes incomming messages
     * */
    class Reader implements Runnable {
        Thread readerThread;
        InputStream is;
        boolean running = true, failed;

        Reader() {
            readerThread = new Thread(this);
            readerThread.start();
            logger.info("Reader started on :" + socket.getLocalSocketAddress());
            failed = false;
        }

        public void stop() {
            running = false;

            if (!failed)
                retry = false;
        }

        public void run() {

            try {
                is = socket.getInputStream();

                DataInputStream din = new DataInputStream(is);

                while (running) {
                    Message msg = null;

                    try {
                        msg = new DefaultMessage(din);
                    } catch (SocketException e) {
                        logger.info("Connection closing");
                        running = false;
                        failed = true;
                    } catch (EOFException e) {
                        logger.info("Error in Message deserialization. Connection closing EOF", e); //-brudd
                        running = false;
                        failed = true;
                    } catch (Exception e) {
                        logger.error("Error in Message deserialization. Aborting", e);
                        running = false;
                        failed = true;
                    }
                    
                    try {
                        if (running) {
                            transportProcessor.processMessage(msg);
                        }
                    } catch (ProcessorException e) {
                        logger.error("ProcessorException caught when processing message " + msg.getName() + " Ignored.", e);
                    } catch (Exception e) {
                        logger.error("Unknown Exception caught when processing message " + msg.getName() + " Ignored.", e);
                    }
                }

                is.close();

                if (channel != null) {
                    channel.disconnect();

                    if (retry) {
                        Thread.sleep(retryTime);
                        channel.connect(channel.getLinkManager());
                    }
                }
            } catch (Exception e) {
                logger.error("Unknown Error in Reader", e);
            }
        }
    }

    class Writer implements Runnable {
        Thread writerThread;
        OutputStream os;
        boolean running = true;

        Writer() {
            writerThread = new Thread(this);
            writerThread.start();
            logger.info("Writer started on :" + socket.getLocalSocketAddress());
        }

        public void stop() {
            running = false;
            writerThread.interrupt();
        }

        public void run() {

            try {
                os = socket.getOutputStream();

                while (running) {

                    if (mailbox.isEmpty()) {

                        synchronized (SecureTCPTransport.this) {

                            try {
                                SecureTCPTransport.this.wait();
                            } catch (InterruptedException e) {

                                if (!running)
                                    return;
                            }
                        }
                    } else {
                        Message msg = mailbox.remove(0);

                        try {
                            os.write(msg.serialize());
                            os.flush();
                        } catch (SocketException e) {

                            running = false;
                            if (e.getMessage().equals("Socket closed")) {
                                logger.info("Connection closing");
                            } else {
                                logger.error("Error in Message writing. Aborting", e);
                            }
                        } catch (Exception e) {
                            logger.error("Error in Message writing. Aborting");
                            running = false;
                        }
                    }
                }

                os.close();

                if (!mailbox.isEmpty()) {
                    logger.warn("Discarding " + mailbox.size() + " messages");
                }

                mailbox.clear();
            } catch (Exception e) {
                logger.error("Unknown Error in Writer", e);
            }
        }
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy