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

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

/**
 * 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.SocketException;
import java.security.KeyStore;

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

import org.coos.messaging.Message;
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 {

	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 static final Log logger = LogFactory.getLog(TCPTransport.class.getName());
	private boolean running = true;

	/**
	 * 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) {
		this.socket = socket;
	}

	/**
	 * 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
	 * */
	public SSLSocket createClient(int port, String serverHost) throws Exception {

		// 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);

		}

		SSLSocketFactory factory = sslcontext.getSocketFactory();// (SSLSocketFactory)SSLSocketFactory.getDefault();
		SSLSocket client = (SSLSocket) factory.createSocket(serverHost, port);

		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("host");
		}

		if (hostPort == 0 && properties.get("port") != null) {
			hostPort = Integer.valueOf((String) properties.get("port"));
		}

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

		// Create and start the thread that executes the communication
		Thread t = new Thread(new Runnable() {

			public void run() {
				if (socket == null) {

					boolean connecting = true;
					while (connecting && running) {
						try {
							socket = createClient(hostPort, hostName);
							// socket.connect(new InetSocketAddress(hostName,
							// hostPort));

							// Connect to the server
							// ((SSLSocket)socket).startHandshake();

							// Retrieve the server's certificate chain
							// java.security.cert.Certificate[] serverCerts =
							// socket.getSession().getPeerCertificates();

							connecting = false;
						} catch (IOException e) {
							e.printStackTrace();
							String retryStr = (String) properties.get("retry");
							if (retryStr == null || retryStr.equals("true")) {
								logger.warn("Establishing transport to " + hostName + ":" + hostPort
										+ " failed. Retrying in 10 sec.");
								try {
									Thread.sleep(10000);
								} catch (InterruptedException e1) {
									e1.printStackTrace();
								}
							} else {
								connecting = false;
							}
						} catch (Exception err) {
							err.printStackTrace();
							logger.error("Transport failed to connect due to: " + err.toString());
						}
					}
					if (running) {
						logger.info("Transport from " + socket.getLocalSocketAddress() + " to "
								+ socket.getRemoteSocketAddress() + " established.");
					}
				}
				reader = new Reader();
				writer = new Writer();
			}
		});

		t.start();
	}

	/**
	 * 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;
	}

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

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

		public void stop() {
			running = false;

		}

		public void run() {
			try {
				is = socket.getInputStream();

				DataInputStream din = new DataInputStream(is);
				while (running) {
					Message msg = null;
					try {
						msg = new DefaultMessage(din);
						transportProcessor.processMessage(msg);
					} catch (SocketException e) {
						logger.info("Connection closing");
						running = false;
					} catch (EOFException e) {
						logger.info("Connection closing EOF");
						running = false;
					} catch (Exception e) {
						e.printStackTrace();
						logger.error("Error in Message deserialization. Aborting");
						running = false;
					}
				}
				is.close();
				if (channel != null) {
					channel.disconnect();
					if(retry){
						Thread.sleep(retryTime);
						channel.connect(channel.getLinkManager());
					} 
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

	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) {
							if (e.getMessage().equals("socket closed")) {
								logger.info("Connection closing");
								running = false;
							}
						} catch (Exception e) {
							e.printStackTrace();
							logger.error("Error in Message writing. Aborting");
							running = false;
						}
					}
				}
				os.close();
				mailbox.clear();
				if (channel != null) {
					channel.disconnect();
					if(retry){
						Thread.sleep(retryTime);
						channel.connect(channel.getLinkManager());
					} 
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy