URingPaxos-master/src/java/ch/usi/da/paxos/ring/SessionHandler.java
package ch.usi.da.paxos.ring;
/* 
 * Copyright (c) 2013 Università della Svizzera italiana (USI)
 * 
 * This file is part of URingPaxos.
 *
 * URingPaxos 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.
 *
 * URingPaxos 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 URingPaxos.  If not, see <http://www.gnu.org/licenses/>.
 */

import java.nio.ByteBuffer;
import java.nio.channels.CancelledKeyException;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.SelectionKey;
import java.nio.channels.SocketChannel;

import org.apache.log4j.Logger;

import ch.usi.da.paxos.message.Message;

/**
 * Name: SessionHandler<br>
 * Description: <br>
 * 
 * Creation date: Apr 02, 2013<br>
 * $Id$
 * 
 * @author Samuel Benz benz@geoid.ch
 */
public class SessionHandler {
	
	private static final Logger logger = Logger.getLogger(SessionHandler.class);
	
	private final NetworkManager manager;
	
	private final ByteBuffer readBuffer;;
	
	private final ByteBuffer writeBuffer;

	private boolean preamble = true;
	
	private int msize;

	public SessionHandler(NetworkManager manager) {
		this.manager = manager;
		readBuffer = ByteBuffer.allocate(2097152);
		writeBuffer = ByteBuffer.allocate(2097152);
	}

	protected synchronized void handleReadable(SelectionKey key) {
		try {
			SocketChannel ch = (SocketChannel) key.channel();
			if (readBuffer.hasRemaining()) {
				int count = ch.read(readBuffer);
				readBuffer.flip();
				if(count < 0) {
					// client has close inputStream
					key.interestOps(key.interestOps() & ~SelectionKey.OP_READ);
					ch.socket().shutdownInput();
				}else if (count > 0) {
					outerloop:
					while(readBuffer.hasRemaining()){
						if(preamble){
							if(readBuffer.limit()-readBuffer.position() >= 8){
								while(readBuffer.getInt() != NetworkManager.MAGIC_NUMBER){
									readBuffer.position(readBuffer.position()-3);
									if(readBuffer.limit()-readBuffer.position() < 4){
										break outerloop;
									}
								}
								msize = readBuffer.getInt();
								if(manager.crc_32) msize += 8;
								preamble = false;
							}else{
								break;
							}
						}
						if(!preamble){
							if(readBuffer.limit()-readBuffer.position() >= msize){
								try{
									Message msg = Message.fromBuffer(readBuffer);
									if(manager.crc_32 && readBuffer.getLong() == Message.getCRC32(msg)){
										manager.recv_count++;
										manager.recv_bytes = manager.recv_bytes + Message.length(msg);
										manager.receive(msg);
									}else if(!manager.crc_32){
										manager.recv_count++;
										manager.recv_bytes = manager.recv_bytes + Message.length(msg);
										manager.receive(msg);										
									}else{
										logger.error("Error in SessionHandler: Message CRC fail!");
									}
								}catch(Exception e){
									logger.error("Error in SessionHandler during de-serializing!",e);
								}
								preamble = true;
							}else{
								break;
							}
						}
					}
					readBuffer.compact();
				}
			}
		} catch (ClosedChannelException e) {
			// an other thread closed this channel
		} catch (CancelledKeyException e) {
			// an other thread closed this channel
		} catch (Exception e) {
			logger.error("Error in SessionHandler during reading!",e);
		}
	}

	protected synchronized void handleWritable(SelectionKey key) {
		try {
			SocketChannel ch = (SocketChannel) key.channel();
			if (writeBuffer.capacity() - writeBuffer.remaining() > 0) {		
				writeBuffer.flip();
				ch.write(writeBuffer);
				writeBuffer.compact();
			}
		} catch (ClosedChannelException e) {
			// an other thread closed this channel
		} catch (CancelledKeyException e) {
			// an other thread closed this channel
		} catch (Exception e) {
			logger.error("Exception in SessionHandler during writing!",e);
		}
	}

}
