private boolean addInternal(RemoteFileDesc host) {
    // initialize the sha1 if we don't have one
    if (sha1 == null) {
      if (host.getSHA1Urn() != null) sha1 = host.getSHA1Urn();
      else //  BUGFIX:  We can't discard sources w/out a SHA1 when we dont' have
        //  a SHA1 for the download, or else it won't be possible to download a
        //  file from a query hit without a SHA1, if we can received UDP pings
        return testedLocations.add(host); // we can't do anything yet
    }

    // do not allow duplicate hosts
    if (running && knowsAboutHost(host)) return false;

    if (LOG.isDebugEnabled()) LOG.debug("adding new host " + host + " " + host.getPushAddr());

    boolean ret = false;

    // don't bother ranking multicasts
    if (host.isReplyToMulticast()) ret = verifiedHosts.add(host);
    else ret = newHosts.add(host); // rank

    // make sure that if we were stopped, we return true
    ret = ret | !running;

    // initialize the guid if we don't have one
    if (myGUID == null && meshHandler != null) {
      myGUID = new GUID(GUID.makeGuid());
      RouterService.getMessageRouter().registerMessageListener(myGUID.bytes(), this);
    }

    return ret;
  }
 /*
  * Returns true if both rfd "have the same content".  Currently
  * rfd1~=rfd2 iff either of the following conditions hold:
  *
  * <ul>
  * <li>Both files have the same hash, i.e.,
  *     rfd1.getSHA1Urn().equals(rfd2.getSHA1Urn().  Note that this (almost)
  *     always means that rfd1.getSize()==rfd2.getSize(), though rfd1 and
  *     rfd2 may have different names.
  * <li>Both files have the same name and size and don't have conflicting
  *     hashes, i.e., rfd1.getName().equals(rfd2.getName()) &&
  *     rfd1.getSize()==rfd2.getSize() && (rfd1.getSHA1Urn()==null ||
  *     rfd2.getSHA1Urn()==null ||
  *     rfd1.getSHA1Urn().equals(rfd2.getSHA1Urn())).
  * </ul>
  * Note that the second condition allows risky resumes, i.e., resumes when
  * one (or both) of the files doesn't have a hash.
  *
  * @see getFile
  */
 static boolean same(RemoteFileDesc rfd1, RemoteFileDesc rfd2) {
   return same(
       rfd1.getFileName(),
       rfd1.getSize(),
       rfd1.getSHA1Urn(),
       rfd2.getFileName(),
       rfd2.getSize(),
       rfd2.getSHA1Urn());
 }
  /** pings a bunch of hosts if necessary */
  private void pingNewHosts() {
    // if we have reached our desired # of altlocs, don't ping
    if (isCancelled()) return;

    // if we don't have anybody to ping, don't ping
    if (!hasNonBusy()) return;

    // if we haven't found a single RFD with URN, don't ping anybody
    if (sha1 == null) return;

    // if its not time to ping yet, don't ping
    // use the same interval as workers for now
    long now = System.currentTimeMillis();
    if (now - lastPingTime < DownloadSettings.WORKER_INTERVAL.getValue()) return;

    // create a ping for the non-firewalled hosts
    HeadPing ping = new HeadPing(myGUID, sha1, getPingFlags());

    // prepare a batch of hosts to ping
    int batch = DownloadSettings.PING_BATCH.getValue();
    List toSend = new ArrayList(batch);
    int sent = 0;
    for (Iterator iter = newHosts.iterator(); iter.hasNext() && sent < batch; ) {
      RemoteFileDesc rfd = (RemoteFileDesc) iter.next();
      if (rfd.isBusy(now)) continue;
      iter.remove();

      if (rfd.needsPush()) {
        if (rfd.getPushProxies().size() > 0 && rfd.getSHA1Urn() != null) pingProxies(rfd);
      } else {
        pingedHosts.put(rfd, rfd);
        toSend.add(rfd);
      }
      testedLocations.add(rfd);
      sent++;
    }

    if (LOG.isDebugEnabled()) {
      LOG.debug(
          "\nverified hosts "
              + verifiedHosts.size()
              + "\npingedHosts "
              + pingedHosts.values().size()
              + "\nnewHosts "
              + newHosts.size()
              + "\npinging hosts: "
              + sent);
    }

    pinger.rank(toSend, null, this, ping);
    lastPingTime = now;
  }
  /** schedules a push ping to each proxy of the given host */
  private void pingProxies(RemoteFileDesc rfd) {
    if (RouterService.acceptedIncomingConnection()
        || (RouterService.getUdpService().canDoFWT() && rfd.supportsFWTransfer())) {
      HeadPing pushPing =
          new HeadPing(
              myGUID,
              rfd.getSHA1Urn(),
              new GUID(rfd.getPushAddr().getClientGUID()),
              getPingFlags());

      for (Iterator iter = rfd.getPushProxies().iterator(); iter.hasNext(); )
        pingedHosts.put(iter.next(), rfd);

      if (LOG.isDebugEnabled()) LOG.debug("pinging push location " + rfd.getPushAddr());

      pinger.rank(rfd.getPushProxies(), null, this, pushPing);
    }
  }
 public URN getSHA1Urn() {
   return remoteFileDesc.getSHA1Urn();
 }
 /**
  * Same as getFile(String, urn, int), except taking the values from the RFD. getFile(rfd) ==
  * getFile(rfd.getFileName(), rfd.getSHA1Urn(), rfd.getSize());
  */
 public synchronized File getFile(RemoteFileDesc rfd) throws IOException {
   return getFile(rfd.getFileName(), rfd.getSHA1Urn(), rfd.getSize());
 }