/* 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.*; import java.net.*; import java.util.*; 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) { Snark.debug(peer + ": " + t, Snark.ERROR); t.printStackTrace(); } finally { peer.disconnect(); } } }