/* * PeerConnectionIn - Handles incomming messages and hands them to PeerState. * Copyright (C) 2003 Mark J. Wielaard * * This file is part of Snark. * * 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 2, 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., 59 Temple * Place - Suite 330, Boston, MA 02111-1307, USA. */ package org.klomp.snark; import java.io.DataInputStream; import java.io.IOException; import java.util.logging.Level; import java.util.logging.Logger; class PeerConnectionIn implements Runnable { private final Peer peer; private final DataInputStream din; private Thread thread; private boolean quit; public PeerConnectionIn (Peer peer, DataInputStream din) { this.peer = peer; this.din = din; quit = false; } void disconnect () { if (quit == true) { return; } quit = true; Thread t = thread; if (t != null) { t.interrupt(); } } public void run () { thread = Thread.currentThread(); try { PeerState ps = peer.state; while (!quit && ps != null) { // Common variables used for some messages. int piece; int begin; int len; // Wait till we hear something... // The length of a complete message in bytes. int i = din.readInt(); if (i < 0) { throw new IOException("Unexpected length prefix: " + i); } if (i == 0) { ps.keepAliveMessage(); continue; } byte b = din.readByte(); Message m = new Message(); m.type = b; switch (b) { case 0: ps.chokeMessage(true); break; case 1: ps.chokeMessage(false); break; case 2: ps.interestedMessage(true); break; case 3: ps.interestedMessage(false); break; case 4: piece = din.readInt(); ps.haveMessage(piece); break; case 5: byte[] bitmap = new byte[i - 1]; din.readFully(bitmap); ps.bitfieldMessage(bitmap); break; case 6: piece = din.readInt(); begin = din.readInt(); len = din.readInt(); ps.requestMessage(piece, begin, len); break; case 7: piece = din.readInt(); begin = din.readInt(); len = i - 9; Request req = ps.getOutstandingRequest(piece, begin, len); byte[] piece_bytes; if (req != null) { piece_bytes = req.bs; din.readFully(piece_bytes, begin, len); ps.pieceMessage(req); } else { // XXX - Consume but throw away afterwards. piece_bytes = new byte[len]; din.readFully(piece_bytes); } break; case 8: piece = din.readInt(); begin = din.readInt(); len = din.readInt(); ps.cancelMessage(piece, begin, len); break; default: byte[] bs = new byte[i - 1]; din.readFully(bs); ps.unknownMessage(b, bs); } } } catch (IOException ioe) { // Ignore, probably the other side closed connection. } catch (Throwable t) { log.log(Level.SEVERE, peer + " failed", t); } finally { peer.disconnect(); } } protected static final Logger log = Logger.getLogger("org.klomp.snark.peer"); }