/******************************************************************************* * gMix open source project - https://svs.informatik.uni-hamburg.de/gmix/ * Copyright (C) 2014 SVS * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. *******************************************************************************/ /** * */ package userGeneratedContent.testbedPlugIns.layerPlugIns.layer5application.httpPush_v0_001.entryClient; import java.io.IOException; import java.net.InetSocketAddress; import java.net.ServerSocket; import java.nio.channels.ClosedChannelException; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; import java.security.SecureRandom; import java.util.Iterator; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.LinkedBlockingQueue; import staticContent.framework.clock.Clock; import staticContent.framework.config.Settings; import userGeneratedContent.testbedPlugIns.layerPlugIns.layer5application.httpPush_v0_001.dataObjects.Cache; import userGeneratedContent.testbedPlugIns.layerPlugIns.layer5application.httpPush_v0_001.dataObjects.Connection; import userGeneratedContent.testbedPlugIns.layerPlugIns.layer5application.httpPush_v0_001.dataObjects.HttpInfo; import userGeneratedContent.testbedPlugIns.layerPlugIns.layer5application.httpPush_v0_001.dataObjects.HttpPartType; import userGeneratedContent.testbedPlugIns.layerPlugIns.layer5application.httpPush_v0_001.mix.ConnectionPoolInterface; /** * @author bash * * This class holds all connections with the webbrowser * * The ConnectionPool holds a Socket and instantiates a new connection object if the webbrowser established a new connection- * The new connection is added to the connection hashtable to identify a connection by the id. * * If the webbrowser sends data on the stream the Pool added the receiving connection to a Queue. * From this queue EntryDataToMix class could take the connection and exercise on the data. * * */ public class ApplicationConnectionPool extends Thread implements ConnectionPoolInterface { private Cache cache; private LinkedBlockingQueue<Connection> readableConnections; private SecureRandom randomGen = new SecureRandom(); private int connectionCounter; private ConcurrentHashMap<Integer, Connection> connectionMap; private Clock clock; private Selector selector = null; private ServerSocketChannel serverChannel = null; private Settings settings; /** * Constructor */ public ApplicationConnectionPool(int port, int bufferSize, LinkedBlockingQueue<Connection> readableConnections, ConcurrentHashMap<Integer, Connection> connectionMap, Settings settings) { // this.entryClient = entryClient; // this.port = port; // this.bufferSize = bufferSize; this.readableConnections = readableConnections; this.connectionMap = connectionMap; clock = new Clock(settings); this.settings = settings; connectionCounter = 0; // Open ServerSocket NIO try { selector = Selector.open(); serverChannel = ServerSocketChannel.open(); serverChannel.configureBlocking(false); ServerSocket ss = serverChannel.socket(); InetSocketAddress address = new InetSocketAddress(port); ss.bind(address); System.err.println("listening on 127.0.0.1:" +port +" for connections"); // System.out.println("Waiting for Connection on Port " + port); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } try { serverChannel.register(selector, SelectionKey.OP_ACCEPT); } catch (ClosedChannelException e) { // TODO Auto-generated catch block e.printStackTrace(); } cache = new Cache(settings.getPropertyAsInt("HP_CACHE_SIZE"), connectionMap); } public Selector getSelector() { return selector; } /** * Thread method * * This method handles the incoming connection and instatiates a new connection. * It also adds a connection to the queue if a webbrowser sends data. */ @Override public void run() { while (true) { try { selector.select(); } catch (IOException e) { continue; } synchronized (this) { // Synchronized is necessary to prevent a race condition // with the registerConnection Method // Set<SelectionKey> selectedKeys = ; Iterator<SelectionKey> it = selector.selectedKeys().iterator(); //Wait for event on socket while (it.hasNext()) { SelectionKey key = (SelectionKey) it.next(); //True if new Connection is established if (key.isAcceptable()) { Connection newConnection = null; // Accept the new connection ServerSocketChannel ssc = (ServerSocketChannel) key.channel(); SocketChannel sc = null; try { sc = ssc.accept(); sc.configureBlocking(false); int connectionId = connectionCounter; connectionCounter += 1; // int connectionId = randomGen.nextInt(); newConnection = new Connection(sc, connectionId, clock, settings, this, cache); newConnection.setStatusHTTPFromApp(new HttpInfo(HttpPartType.SocksAuth, 0)); newConnection.setStatusHTTPFromMix(new HttpInfo(HttpPartType.Header, 0)); // registerSocket(sc, newConnection, // SelectionKey.OP_READ); sc.register(selector, SelectionKey.OP_READ, newConnection); connectionMap.put(connectionId, newConnection); // System.out.println("Got connection from " + sc); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); System.err.println("Connection could not be established"); } it.remove(); //True if connection contains data from Webbrowser } else if (key.isReadable()) { Connection connection = (Connection) key.attachment(); key.cancel(); it.remove(); this.readableConnections.add(connection); } } } } } /** * Method to register a readflag for the underlying connection * * @return SelectionKey (null if fails) * @throws IOException */ public SelectionKey registerSocket(SocketChannel serverSocket, Connection connection, int event) throws IOException { SelectionKey newKey = null; synchronized (this) { selector.wakeup(); selector.selectNow(); newKey = serverSocket.register(selector, event, connection); return newKey; } } /** * @return the connectionMap */ public ConcurrentHashMap<Integer, Connection> getConnectionMap() { return connectionMap; } /** * @param connectionMap the connectionMap to set */ public void setConnectionMap(ConcurrentHashMap<Integer, Connection> connectionMap) { this.connectionMap = connectionMap; } }