/* This code is part of Freenet. It is distributed under the GNU General
* Public License, version 2 (or at your option any later version). See
* http://www.gnu.org/ for further details of the GPL. */
package freenet.io.xfer;
import static java.util.concurrent.TimeUnit.SECONDS;
import freenet.io.comm.ByteCounter;
import freenet.io.comm.DMT;
import freenet.io.comm.DisconnectedException;
import freenet.io.comm.Message;
import freenet.io.comm.MessageFilter;
import freenet.io.comm.NotConnectedException;
import freenet.io.comm.PeerContext;
import freenet.io.comm.RetrievalException;
import freenet.support.ShortBuffer;
/**
* Bulk (not block) data transfer - receiver class. Bulk transfer is designed for largish files, much
* larger than blocks, where we have the whole file at the outset.
* @author toad
*/
public class BulkReceiver {
static final long TIMEOUT = SECONDS.toMillis(60);
/** Tracks the data we have received */
final PartiallyReceivedBulk prb;
/** Peer we are receiving from */
final PeerContext peer;
/** Transfer UID for messages */
final long uid;
private boolean sentCancel;
/** Not persistent over reboots */
final long peerBootID;
private final ByteCounter ctr;
public BulkReceiver(PartiallyReceivedBulk prb, PeerContext peer, long uid, ByteCounter ctr) {
this.prb = prb;
this.peer = peer;
this.uid = uid;
this.peerBootID = peer.getBootID();
this.ctr = ctr;
prb.recv = this;
}
public void onAborted() {
synchronized(this) {
if(sentCancel) return;
sentCancel = true;
}
try {
peer.sendAsync(DMT.createFNPBulkReceiveAborted(uid), null, ctr);
} catch (NotConnectedException e) {
// Cool
}
}
/**
* Receive the file.
* @return True if the whole file was received, false otherwise.
*/
public boolean receive() {
while(true) {
MessageFilter mfSendKilled = MessageFilter.create().setSource(peer).setType(DMT.FNPBulkSendAborted) .setField(DMT.UID, uid).setTimeout(TIMEOUT);
MessageFilter mfPacket = MessageFilter.create().setSource(peer).setType(DMT.FNPBulkPacketSend) .setField(DMT.UID, uid).setTimeout(TIMEOUT);
if(prb.hasWholeFile()) {
try {
peer.sendAsync(DMT.createFNPBulkReceivedAll(uid), null, ctr);
} catch (NotConnectedException e) {
// Ignore, we have the data.
}
return true;
}
Message m;
try {
m = prb.usm.waitFor(mfSendKilled.or(mfPacket), ctr);
} catch (DisconnectedException e) {
prb.abort(RetrievalException.SENDER_DISCONNECTED, "Sender disconnected");
return false;
}
if(peer.getBootID() != peerBootID) {
prb.abort(RetrievalException.SENDER_DIED, "Sender restarted");
return false;
}
if(m == null) {
prb.abort(RetrievalException.TIMED_OUT, "Sender timeout");
return false;
}
if(m.getSpec() == DMT.FNPBulkSendAborted) {
prb.abort(RetrievalException.SENDER_DIED, "Sender cancelled send");
return false;
}
if(m.getSpec() == DMT.FNPBulkPacketSend) {
int packetNo = m.getInt(DMT.PACKET_NO);
byte[] data = ((ShortBuffer) m.getObject(DMT.DATA)).getData();
prb.received(packetNo, data, 0, data.length);
}
}
}
}