/* * MockBitTorrentHandler.java * * Created on Feb 3, 2010, 11:51:24 PM * * Description: A channel handler for a bit torrent bitfield message. * * Copyright (C) Feb 3, 2010 reed. * * 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, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ package org.texai.network.netty.handler; import net.jcip.annotations.NotThreadSafe; import org.apache.log4j.Logger; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ExceptionEvent; import org.jboss.netty.channel.MessageEvent; import org.texai.torrent.message.BitTorrentBitFieldMessage; import org.texai.torrent.message.BitTorrentCancelMessage; import org.texai.torrent.message.BitTorrentChokeMessage; import org.texai.torrent.message.BitTorrentHandshakeMessage; import org.texai.torrent.message.BitTorrentHaveMessage; import org.texai.torrent.message.BitTorrentInterestedMessage; import org.texai.torrent.message.BitTorrentKeepAliveMessage; import org.texai.torrent.message.BitTorrentMessage; import org.texai.torrent.message.BitTorrentNotInterestedMessage; import org.texai.torrent.message.BitTorrentPieceMessage; import org.texai.torrent.message.BitTorrentRequestMessage; import org.texai.torrent.message.BitTorrentUnchokeMessage; import org.texai.util.TexaiException; /** A channel handler for a bit torrent bitfield message. * * @author reed */ @NotThreadSafe public final class MockBitTorrentHandler extends AbstractBitTorrentHandler { /** the logger */ private static final Logger LOGGER = Logger.getLogger(MockBitTorrentHandler.class); /** the lock that allows the client to resume when the messaging is done */ final Object clientResume_lock; /** the test iteration limit */ final int iterationLimit; /** the peer identification bytes */ private static final byte[] PEER_ID_BYTES = { 0x14, 0x13, 0x12, 0x11, 0x10, 0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01 }; /** Constructs a new MockBitTorrentHandler instance. * * @param clientResume_lock the lock that allows the client to resume when the messaging is done, or * null if this is the client side handler * @param iterationLimit the test iteration limit */ public MockBitTorrentHandler( final Object clientResume_lock, final int iterationLimit) { //Preconditions assert iterationLimit >= 0 : "iterationLimit must not be negative"; this.clientResume_lock = clientResume_lock; this.iterationLimit = iterationLimit; } /** Receives a message object from a remote peer. * * @param channelHandlerContext the channel handler context * @param messageEvent the message event */ @Override public void messageReceived( final ChannelHandlerContext channelHandlerContext, final MessageEvent messageEvent) { //Preconditions assert channelHandlerContext != null : "channelHandlerContext must not be null"; assert messageEvent != null : "messageEvent must not be null"; assert messageEvent.getMessage() instanceof BitTorrentMessage; final Channel channel = channelHandlerContext.getChannel(); final BitTorrentMessage bitTorrentMessage = (BitTorrentMessage) messageEvent.getMessage(); final boolean isClient = clientResume_lock != null; if (isClient) { LOGGER.info("client received messageEvent: " + messageEvent); if (bitTorrentMessage instanceof BitTorrentHandshakeMessage) { final BitTorrentHandshakeMessage bitTorrentHandshakeMessage = (BitTorrentHandshakeMessage) bitTorrentMessage; LOGGER.info("handling server's handshake: " + bitTorrentHandshakeMessage); final byte[] bitField = {0x01, 0x02}; final BitTorrentBitFieldMessage bitTorrentBitfieldMessage = new BitTorrentBitFieldMessage(bitField, PEER_ID_BYTES); LOGGER.info("writing client's bitfield: " + bitTorrentBitfieldMessage); channel.write(bitTorrentBitfieldMessage); } else if (bitTorrentMessage instanceof BitTorrentUnchokeMessage) { LOGGER.info("handling server's unchoke: " + bitTorrentMessage); synchronized (clientResume_lock) { // notify the waiting client thread that processing is done clientResume_lock.notifyAll(); } } else { assert false; } } else { LOGGER.info("server received messageEvent: " + messageEvent); if (bitTorrentMessage instanceof BitTorrentHandshakeMessage) { final BitTorrentHandshakeMessage bitTorrentHandshakeMessage = (BitTorrentHandshakeMessage) bitTorrentMessage; LOGGER.info("handling client's handshake: " + bitTorrentHandshakeMessage); final BitTorrentHandshakeMessage replyBitTorrentHandshakeMessage = new BitTorrentHandshakeMessage( bitTorrentHandshakeMessage.getInfoHash(), PEER_ID_BYTES); LOGGER.info("writing server's handshake: " + replyBitTorrentHandshakeMessage); channel.write(replyBitTorrentHandshakeMessage); } else if (bitTorrentMessage instanceof BitTorrentBitFieldMessage) { final BitTorrentBitFieldMessage bitTorrentBitfieldMessage = (BitTorrentBitFieldMessage) bitTorrentMessage; LOGGER.info("handling bitfield: " + bitTorrentBitfieldMessage); final BitTorrentUnchokeMessage bitTorrentUnchokeMessage = new BitTorrentUnchokeMessage(PEER_ID_BYTES); LOGGER.info("writing server's unchoke: " + bitTorrentUnchokeMessage); channel.write(bitTorrentUnchokeMessage); } else if (bitTorrentMessage instanceof BitTorrentCancelMessage) { final BitTorrentCancelMessage bitTorrentCancelMessage = (BitTorrentCancelMessage) bitTorrentMessage; LOGGER.info("handling cancel: " + bitTorrentCancelMessage); } else if (bitTorrentMessage instanceof BitTorrentChokeMessage) { final BitTorrentChokeMessage bitTorrentChokeMessage = (BitTorrentChokeMessage) bitTorrentMessage; LOGGER.info("handling choke: " + bitTorrentChokeMessage); } else if (bitTorrentMessage instanceof BitTorrentHaveMessage) { final BitTorrentHaveMessage bitTorrentHaveMessage = (BitTorrentHaveMessage) bitTorrentMessage; LOGGER.info("handling have: " + bitTorrentHaveMessage); } else if (bitTorrentMessage instanceof BitTorrentInterestedMessage) { final BitTorrentInterestedMessage bitTorrentInterestedMessage = (BitTorrentInterestedMessage) bitTorrentMessage; LOGGER.info("handling interested: " + bitTorrentInterestedMessage); } else if (bitTorrentMessage instanceof BitTorrentKeepAliveMessage) { final BitTorrentKeepAliveMessage bitTorrentKeepAliveMessage = (BitTorrentKeepAliveMessage) bitTorrentMessage; LOGGER.info("handling keep-alive: " + bitTorrentKeepAliveMessage); } else if (bitTorrentMessage instanceof BitTorrentNotInterestedMessage) { final BitTorrentNotInterestedMessage bitTorrentNotInterestedMessage = (BitTorrentNotInterestedMessage) bitTorrentMessage; LOGGER.info("handling not-interested: " + bitTorrentNotInterestedMessage); } else if (bitTorrentMessage instanceof BitTorrentPieceMessage) { final BitTorrentPieceMessage bitTorrentPieceMessage = (BitTorrentPieceMessage) bitTorrentMessage; LOGGER.info("handling piece: " + bitTorrentPieceMessage); } else if (bitTorrentMessage instanceof BitTorrentRequestMessage) { final BitTorrentRequestMessage bitTorrentRequestMessage = (BitTorrentRequestMessage) bitTorrentMessage; LOGGER.info("handling request: " + bitTorrentRequestMessage); } else if (bitTorrentMessage instanceof BitTorrentUnchokeMessage) { final BitTorrentUnchokeMessage bitTorrentUnchokeMessage = (BitTorrentUnchokeMessage) bitTorrentMessage; LOGGER.info("handling unchoke: " + bitTorrentUnchokeMessage); } else { assert false; } } } /** Handles a caught exception. * * @param channelHandlerContext the channel handler event * @param exceptionEvent the exception event */ @Override public void exceptionCaught( final ChannelHandlerContext channelHandlerContext, final ExceptionEvent exceptionEvent) { //Preconditions assert channelHandlerContext != null : "channelHandlerContext must not be null"; assert exceptionEvent != null : "exceptionEvent must not be null"; LOGGER.error("exceptionEvent: " + exceptionEvent); throw new TexaiException(exceptionEvent.getCause()); } }