/*
* bitlet - Simple bittorrent library
* Copyright (C) 2008 Alessandro Bahgat Shehata, Daniele Castagna
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bitlet.wetorrent.peer.task;
import java.io.DataInputStream;
import java.io.IOException;
import java.net.ProtocolException;
import java.util.logging.Level;
import org.bitlet.wetorrent.Event;
import org.bitlet.wetorrent.Torrent;
import org.bitlet.wetorrent.peer.TorrentPeer;
import org.bitlet.wetorrent.peer.message.Message;
import org.bitlet.wetorrent.util.thread.ThreadTask;
public class MessageReceiver implements ThreadTask {
private TorrentPeer peer;
private long lastReceivedMessageMillis;
private long receivedBytes;
public MessageReceiver(TorrentPeer peer) {
this.peer = peer;
}
private synchronized void addReceivedBytes(Integer byteNumber) {
receivedBytes += byteNumber;
}
public synchronized Long getReceivedBytes() {
return receivedBytes;
}
public boolean execute() throws Exception {
try {
DataInputStream is = new DataInputStream(peer.getSocket().getInputStream());
// peer.getPeersManager().getTorrent().addEvent(new Event(this, "Waiting new message",Level.FINEST));
int prefixLength = is.readInt();
addReceivedBytes(4 + prefixLength);
if (prefixLength == 0) { // keep alive message
peer.keepAlive();
} else if (prefixLength > 0) {
byte messageId = is.readByte();
switch (messageId) {
case Message.CHOKE: // choke: <len=0001><id=0>
if (prefixLength != 1) {
throw new ProtocolException("pl " + prefixLength);
}
peer.choke();
break;
case Message.UNCHOKE: // unchoke: <len=0001><id=1>
if (prefixLength != 1) {
throw new ProtocolException();
}
peer.unchoke();
break;
case Message.INTERESTED: // interested
if (prefixLength != 1) {
throw new ProtocolException();
}
peer.interested();
break;
case Message.NOT_INTERESTED: // not interested
if (prefixLength != 1) {
throw new ProtocolException();
}
peer.notInterested();
break;
case Message.HAVE: // have: <len=0005><id=4><piece index>
if (prefixLength != 5) {
throw new ProtocolException();
}
peer.have(is.readInt());
break;
case Message.BITFIELD: // bitfield: <len=0001+X><id=5><bitfield>
if (prefixLength != 1 + peer.getBitfieldCopy().length) {
throw new ProtocolException();
}
byte[] bitField = new byte[prefixLength - 1];
is.readFully(bitField);
peer.bitfield(bitField);
break;
case Message.REQUEST: // request: <len=0013><id=6><index><begin><length>
if (prefixLength != 13) {
throw new ProtocolException();
}
peer.request(is.readInt(), is.readInt(), is.readInt());
break;
case Message.PIECE: // piece: <len=0009+X><id=7><index><begin><block>
if (prefixLength < 10) {
throw new ProtocolException();
}
int index = is.readInt();
int begin = is.readInt();
byte[] block = new byte[prefixLength - 9];
is.readFully(block);
peer.piece(index, begin, block);
break;
case Message.CANCEL: // cancel: <len=0013><id<=8><index><begin><length>
if (prefixLength != 13) {
throw new ProtocolException();
}
peer.cancel(is.readInt(), is.readInt(), is.readInt());
break;
default:
// discard it
is.skipBytes(prefixLength - 1);
if (Torrent.verbose) {
peer.getPeersManager().getTorrent().addEvent(new Event(this, "message discarded " + messageId, Level.FINE));
}
break;
}
} else {
throw new Exception("Negative prefix length");
}
setLastReceivedMessageMillis(System.currentTimeMillis());
} catch (Exception e) {
if (Torrent.verbose) {
peer.getPeersManager().getTorrent().addEvent(new Event(peer, "Problem waiting for new message", Level.WARNING));
}
e.printStackTrace(System.err);
throw e;
}
return true;
}
public void interrupt() {
try {
peer.getSocket().close();
} catch (IOException ex) {
}
}
public void exceptionCought(Exception e) {
peer.interrupt();
}
public synchronized long getLastReceivedMessageMillis() {
return lastReceivedMessageMillis;
}
public synchronized void setLastReceivedMessageMillis(long lastReceivedMessageMillis) {
this.lastReceivedMessageMillis = lastReceivedMessageMillis;
}
}