/******************************************************************************* * 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.layer1network.cascade_TCP_v0_001; import java.io.IOException; import java.net.InetAddress; import java.net.InetSocketAddress; import java.nio.BufferUnderflowException; import java.util.HashMap; import org.apache.mina.core.buffer.IoBuffer; import org.apache.mina.core.service.IoAcceptor; import org.apache.mina.filter.codec.CumulativeProtocolDecoder; import org.apache.mina.filter.codec.ProtocolCodecFilter; import org.apache.mina.filter.codec.ProtocolDecoderOutput; import org.apache.mina.filter.codec.ProtocolEncoderAdapter; import org.apache.mina.filter.codec.ProtocolEncoderOutput; import org.apache.mina.transport.socket.nio.NioSocketAcceptor; import org.apache.mina.core.service.IoHandlerAdapter; import org.apache.mina.core.session.IoSession; import staticContent.framework.controller.SubImplementation; import staticContent.framework.message.MixMessage; import staticContent.framework.message.Reply; import staticContent.framework.message.Request; import staticContent.framework.userDatabase.User; import staticContent.framework.util.Util; /** * Implements an asynchronous Client I/O Handler based on Mina 2.0.4 Extends the * abstract class SubImplementation * * @author Christopher Bartz, Jan Henrik Röwekamp, Arne Springborn * */ public class ClientHandler_TCP_FCFS_async_mina extends SubImplementation { private int port; private InetAddress bindAddress; private int maxRequestLength; //private boolean DUPLEX_ON; @Override public void constructor() { this.bindAddress = settings.getPropertyAsInetAddress("GLOBAL_MIX_BIND_ADDRESS"); this.port = settings.getPropertyAsInt("GLOBAL_MIX_BIND_PORT"); //this.backlog = settings.getPropertyAsInt("BACKLOG"); this.maxRequestLength = settings.getPropertyAsInt("MAX_REQUEST_LENGTH"); } @Override public void initialize() { //this.DUPLEX_ON = infoService.getIsDuplexModeOn(); } @Override public void begin() { IoAcceptor acceptor = new NioSocketAcceptor(); // adds one filter(the codec) to the filterchain acceptor.getFilterChain().addLast("codec", new ProtocolCodecFilter(new New_ProtocolEncoder(), new New_ProtocolDecoder())); // sets the acceptor to use the new implemented Handler acceptor.setHandler(new ClientIOHandler()); try { acceptor.bind(new InetSocketAddress(this.bindAddress, this.port)); } catch (IOException e) { e.printStackTrace(); throw new RuntimeException("Could not open ServerSocket."); } } /** * The ClientIOHandler extends the abstract class IoHandlerAdapter and * therefore has to implement the methods exceptionCaught, messageReceived * and sessionCreated * */ class ClientIOHandler extends IoHandlerAdapter { private int counter; HashMap<User, IoSession> lsession; ClientIOHandler() { super(); counter = 0; lsession = new HashMap<User, IoSession>(); new AsyncMinaReplyThread().start(); } /** * Implements the exception handling */ @Override public void exceptionCaught(IoSession session, Throwable cause) throws Exception { cause.printStackTrace(); } /** * is called when a message is received. writes the message to the upper * layer */ @Override public void messageReceived(IoSession session, Object message) throws Exception { Request request = (Request) message; anonNode.putInRequestInputQueue(request); } /** * is called when a new session is created. generates a new user and * binds the session */ @Override public void sessionCreated(IoSession session) throws Exception { if (++this.counter % 100 == 0) { System.out.println(counter + " connections"); } User user = userDatabase.generateUser(); userDatabase.addUser(user); lsession.put(user, session); session.setAttribute("user", user); } /** * Implements a basic Thread to reply requests from clients * */ class AsyncMinaReplyThread extends Thread { @Override public void run() { while (true) { Reply[] replies = anonNode.getFromReplyOutputQueue(); for (Reply reply : replies) { User user = reply.getOwner(); byte[] bytemsg = reply.getByteMessage(); byte[] length = Util.intToByteArray(bytemsg.length); byte[] msg = new byte[bytemsg.length + length.length]; for (int i = 0; i < 4; i++) { msg[i] = length[i]; } for (int i = 0; i < bytemsg.length; i++) { msg[i + length.length] = bytemsg[i]; } lsession.get(user).write(msg); } } } } } /** * Implements a Codec to prevent a negative impact of message fragmenting. * is used to convert the input bytes to high-level Mina Objects * */ class New_ProtocolDecoder extends CumulativeProtocolDecoder { /** * continuously tries to decodes a message until true is returned. */ @Override protected boolean doDecode(IoSession session, IoBuffer in, ProtocolDecoderOutput out) throws Exception { int startposition = in.position(); if (in.remaining() < 4) { return false; // not enough data to read -> doDecode is called again } byte[] msgLength = new byte[4]; in.get(msgLength); int messageLength = Util.byteArrayToInt(msgLength); byte[] msg = new byte[messageLength]; try { in.get(msg, 0, messageLength); } catch (BufferUnderflowException e) { in.position(startposition); return false; // not enough data to read -> doDecode is called again } User user = (User) session.getAttribute("user"); if (messageLength > maxRequestLength) throw new IOException("warning: user " + user + " sent a too large message"); // a too large message is not expected -> throws an exception Request request = MixMessage.getInstanceRequest(msg, user); out.write(request); return true; // reading the message was successful -> continue with the next // filter } } /** * forwards the sending data to the output. No Protocol processing is needed * */ class New_ProtocolEncoder extends ProtocolEncoderAdapter { @Override public void encode(IoSession session, Object msg, ProtocolEncoderOutput out) throws Exception { byte[] bytemsg = (byte[]) msg; IoBuffer buf = IoBuffer.wrap(bytemsg); out.write(buf); } } }