Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/**
* 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.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
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.util.Collections;
import java.util.Hashtable;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLEngineResult;
import javax.net.ssl.SSLEngineResult.HandshakeStatus;
import javax.net.ssl.SSLEngineResult.Status;
import org.coos.messaging.Channel;
import org.coos.messaging.Message;
import org.coos.messaging.Processor;
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.impl.DefaultProcessor;
/**
* Represents one non-blocking tcp connection. Decodes messages by reading the
* length from the first 4 bytes.
*
* @author Morten Versvik, Tellu AS
*
*/
public class SecureNioTCPTransport extends DefaultProcessor implements Transport, Service {
protected List mailbox = Collections.synchronizedList(new LinkedList());
protected Processor transportProcessor;
private ByteBuffer netOutBuffer, netInBuffer, inBuffer;
SocketChannel sc;
SecureNioTCPTransportManager tm;
/**
* Initial buffer size.
*/
private final static int BUFFER_SIZE = 20 * 1024;
private byte[] buffer = new byte[BUFFER_SIZE];
private int pos = 0;
private int newmsgLength = Integer.MAX_VALUE;
protected int MAX_LENGTH = 8 * 1024; // Max length for a coos msg
/**
* 1 int is 4 bytes.
*/
private static final int SIZE_POSITION = 4 - 1;
SSLEngine sslEngine;
public SecureNioTCPTransport(SecureNioTCPTransportManager tm, Selector selector, SocketChannel sc,
Hashtable properties) throws IOException, NoSuchAlgorithmException, KeyManagementException,
KeyStoreException, CertificateException, UnrecoverableKeyException {
this.sc = sc;
netInBuffer = ByteBuffer.allocateDirect(sc.socket().getReceiveBufferSize());
inBuffer = ByteBuffer.allocateDirect(sc.socket().getReceiveBufferSize());
netOutBuffer = ByteBuffer.allocateDirect(BUFFER_SIZE);
netOutBuffer.flip(); // Start empty
this.tm = tm;
String keystore = ((String) properties.get("keystore"));
char[] keystorepass = ((String) properties.get("keystorepass")).toCharArray();
char[] keypassword = ((String) properties.get("keypassword")).toCharArray();
// Fetch the keystore
KeyStore ks = KeyStore.getInstance("JKS");
ks.load(new FileInputStream(keystore), keystorepass);
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(ks, keypassword);
// set the context to SSL 3
SSLContext sslcontext = SSLContext.getInstance("SSLv3");
sslcontext.init(kmf.getKeyManagers(), null, null);
sslEngine = sslcontext.createSSLEngine();
sslEngine.setUseClientMode(false);
sslEngine.setNeedClientAuth(false);
sslEngine.setWantClientAuth(false);
}
@Override
public void setChainedProcessor(Processor chainedProcessor) {
this.transportProcessor = chainedProcessor;
}
public void receivedMessage(Message in) {
try {
transportProcessor.processMessage(in);
} catch (ProcessorException e) {
e.printStackTrace();
}
}
public int getMailboxSize() {
return mailbox.size();
}
public Message getMessage() {
return mailbox.remove(0);
}
@Override
public void setChannel(Channel channel) {
}
@Override
public void processMessage(Message msg) throws ProcessorException {
String priStr = msg.getHeader(Message.PRIORITY);
if (priStr != null) {
int pri = Integer.valueOf(priStr);
int idx = 0;
for (Message message : mailbox) {
String pr = message.getHeader(Message.PRIORITY);
if (pr != null) {
int p = Integer.valueOf(pr);
if (pri < p) {
mailbox.add(idx, msg);
synchronized (this) {
this.notify();
}
break;
}
}
idx++;
}
} else {
mailbox.add(msg);
synchronized (this) {
this.notify();
}
}
// A new message was added, notify the writer.
if (sc != null)
tm.readyWrite(sc);
}
@Override
public void start() throws Exception {
}
@Override
public void stop() throws Exception {
}
public byte[] decode(ByteBuffer socketBuffer) throws IOException {
// Reads until the buffer is empty or until a packet
// is fully reassembled.
while (socketBuffer.hasRemaining()) {
// Copies into the temporary buffer
byte data = socketBuffer.get();
try {
buffer[pos] = data;
if (pos == SIZE_POSITION) { // Got size parameter
ByteArrayInputStream bin = new ByteArrayInputStream(buffer);
DataInputStream din = new DataInputStream(bin);
newmsgLength = din.readInt() + SIZE_POSITION + 1;
if (newmsgLength > MAX_LENGTH)
throw new IOException("Packet too big");
if (buffer.length < newmsgLength)
buffer = new byte[newmsgLength];
}
} catch (IndexOutOfBoundsException e) {
// We resize the buffer, shouldn't happen.
e.printStackTrace();
throw new IOException("Packet too big. Maximum size allowed: " + BUFFER_SIZE + " bytes.");
}
pos++;
// Check if it is the final byte of a packet.
if (pos == newmsgLength) {
newmsgLength = Integer.MAX_VALUE;
// The current packet is fully reassembled. Return it
byte[] newBuffer = new byte[pos];
System.arraycopy(buffer, 0, newBuffer, 0, pos);
pos = 0;
return newBuffer;
}
}
// No packet was reassembled. There is not enough data. Wait
// for more data to arrive.
return null;
}
public void decodeFromSocket() throws Exception {
int readBytes = sc.read(netInBuffer);
if (readBytes == -1) {
sc.close();
tm.socketDisconnected(sc);
return;
}
/*
* if (readBytes == 0 && !netInBuffer.hasRemaining()) { return; }
*/
netInBuffer.flip();
SSLEngineResult ser = sslEngine.unwrap(netInBuffer, inBuffer);
// System.out.println("read: " + ser + " in: " + inBuffer.position() +
// " - " + inBuffer.limit());
if (ser.getHandshakeStatus() == HandshakeStatus.FINISHED) {
initDone = true;
}
if (ser.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
Executor exec = Executors.newSingleThreadExecutor();
Runnable task;
while ((task = sslEngine.getDelegatedTask()) != null) {
exec.execute(task);
}
}
if (ser.getHandshakeStatus() == HandshakeStatus.NEED_WRAP) {
tm.readyWrite(sc);
netInBuffer.compact();
return;
}
inBuffer.flip();
byte[] bb = decode(inBuffer);
// System.out.println("decode: " + " in: " + inBuffer.position() + " - "
// + inBuffer.limit());
if (bb == null) {
// Partial packet received. Must wait for more data. All the
// contents
// of inBuffer were processed by the protocol decoder. We can
// delete it and prepare for more data.
inBuffer.clear();
netInBuffer.compact();
// netInBuffer.flip();
// netInBuffer.clear();
} else {
// A packet was reassembled.
Message msg;
try {
// System.out.println(bb.length);
msg = new DefaultMessage(new DataInputStream(new ByteArrayInputStream(bb)));
// System.out.println(msg);
receivedMessage(msg);
inBuffer.compact();
netInBuffer.compact();
// netInBuffer.flip();
} catch (Exception e) {
e.printStackTrace();
}
// The netInBuffer might still have some data left. Perhaps
// the beginning of another packet. So don't clear it. Next
// time reading is activated, we start by processing the netInBuffer
// again.
}
}
boolean initDone = false;
public void handleWrite() throws Exception {
netOutBuffer.flip();
if (!netOutBuffer.hasRemaining()) {
netOutBuffer.clear();
SSLEngineResult ser = null;
// netOutBuffer = ByteBuffer.allocate(50000);
if (initDone) {
if (mailbox.isEmpty()) {
tm.doneWrite(sc);
return;
} else {
Message msg = getMessage();
// netOutBuffer.flip();
ser = sslEngine.wrap(ByteBuffer.wrap(msg.serialize()), netOutBuffer);
if (ser.getStatus() == Status.BUFFER_OVERFLOW) {
mailbox.add(0, msg); // Insert first again
netOutBuffer = ByteBuffer.allocateDirect(netOutBuffer.capacity() * 2);
handleWrite(); // Retry encryption
return;
}
}
} else {
// SslEngine wants to send more headers?
ser = sslEngine.wrap(ByteBuffer.allocate(0), netOutBuffer);
}
if (ser.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
Executor exec = Executors.newSingleThreadExecutor();
Runnable task;
while ((task = sslEngine.getDelegatedTask()) != null) {
exec.execute(task);
}
}
if (ser.getHandshakeStatus() == HandshakeStatus.FINISHED) {
initDone = true;
}
if (ser.getStatus() == Status.BUFFER_OVERFLOW) {
netOutBuffer = ByteBuffer.allocateDirect(netOutBuffer.capacity() * 2);
handleWrite(); // Retry encryption
return;
}
netOutBuffer.flip();
sc.write(netOutBuffer);
netOutBuffer.compact();
netOutBuffer.flip();
if (ser.getHandshakeStatus() == HandshakeStatus.NEED_UNWRAP && !initDone) {
decodeFromSocket();
return;
}
}
sc.write(netOutBuffer);
// Check if there are more to be written.
if (!netOutBuffer.hasRemaining()) {
// netOutBuffer was completely written, deactivate write intent.
// tm.doneWrite(sc);
netOutBuffer.clear();
netOutBuffer.flip();
} else {
netOutBuffer.compact();
netOutBuffer.flip();
}
}
}