/**
  * 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);
     }
   }
 }
  private static long getSecretPingResponse(Node source, PeerNode pathway, long uid)
      throws DisconnectedException {
    // wait for a reject or pong
    MessageFilter mfPong =
        MessageFilter.create()
            .setSource(pathway)
            .setField(DMT.UID, uid)
            .setTimeout(SECRETPONG_TIMEOUT)
            .setType(DMT.FNPSecretPong);
    MessageFilter mfRejectLoop =
        MessageFilter.create()
            .setSource(pathway)
            .setField(DMT.UID, uid)
            .setTimeout(SECRETPONG_TIMEOUT)
            .setType(DMT.FNPRejectedLoop);
    Message msg = source.getUSM().waitFor(mfPong.or(mfRejectLoop), null);

    if (msg == null) {
      Logger.error(
          source, "fatal timeout in waiting for secretpong from " + getPortNumber(pathway));
      return -2;
    }

    if (msg.getSpec() == DMT.FNPSecretPong) {
      int suppliedCounter = msg.getInt(DMT.COUNTER);
      long secret = msg.getLong(DMT.SECRET);
      Logger.normal(source, "got secret, counter=" + suppliedCounter);
      return secret;
    }

    if (msg.getSpec() == DMT.FNPRejectedLoop) {
      Logger.error(
          source,
          "top level secret ping should not reject!: "
              + getPortNumber(source)
              + " -> "
              + getPortNumber(pathway));
      return -1;
    }

    return -3;
  }
  private static boolean getAck(Node source, PeerNode pathway, long uid)
      throws DisconnectedException {
    // wait for an accepted
    MessageFilter mfAccepted =
        MessageFilter.create()
            .setSource(pathway)
            .setField(DMT.UID, uid)
            .setTimeout(SECRETPONG_TIMEOUT)
            .setType(DMT.FNPAccepted);
    Message msg = source.getUSM().waitFor(mfAccepted, null);

    if (msg == null) {
      return false;
    }

    if (msg.getSpec() == DMT.FNPAccepted) {
      return true;
    }

    Logger.error(source, "got " + msg);
    return false;
  }