/* 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); } } } }