Exemplo n.º 1
0
  /**
   * Send a block of encoded bytes to a peer. This is called by send, and by
   * IncomingPacketFilter.processOutgoing(..).
   *
   * @param blockToSend The data block to send.
   * @param destination The peer to send it to.
   */
  public void sendPacket(byte[] blockToSend, Peer destination, boolean allowLocalAddresses)
      throws LocalAddressException {
    assert (blockToSend != null);
    if (!_active) {
      Logger.error(this, "Trying to send packet but no longer active");
      // It is essential that for recording accurate AddressTracker data that we don't send any more
      // packets after shutdown.
      return;
    }
    // there should be no DNS needed here, but go ahead if we can, but complain doing it
    if (destination.getAddress(false, allowLocalAddresses) == null) {
      Logger.error(
          this,
          "Tried sending to destination without pre-looked up IP address(needs a real Peer.getHostname()): null:"
              + destination.getPort(),
          new Exception("error"));
      if (destination.getAddress(true, allowLocalAddresses) == null) {
        Logger.error(
            this,
            "Tried sending to bad destination address: null:" + destination.getPort(),
            new Exception("error"));
        return;
      }
    }
    if (_dropProbability > 0) {
      if (dropRandom.nextInt() % _dropProbability == 0) {
        Logger.normal(this, "DROPPED: " + _sock.getLocalPort() + " -> " + destination.getPort());
        return;
      }
    }
    InetAddress address = destination.getAddress(false, allowLocalAddresses);
    assert (address != null);
    int port = destination.getPort();
    DatagramPacket packet = new DatagramPacket(blockToSend, blockToSend.length);
    packet.setAddress(address);
    packet.setPort(port);

    try {
      _sock.send(packet);
      tracker.sentPacketTo(destination);
      collector.addInfo(address + ":" + port, 0, blockToSend.length + UDP_HEADERS_LENGTH);
      if (logMINOR)
        Logger.minor(
            this, "Sent packet length " + blockToSend.length + " to " + address + ':' + port);
    } catch (IOException e) {
      if (packet.getAddress() instanceof Inet6Address) {
        Logger.normal(
            this, "Error while sending packet to IPv6 address: " + destination + ": " + e, e);
      } else {
        Logger.error(this, "Error while sending packet to " + destination + ": " + e, e);
      }
    }
  }
  /**
   * Get our Peer's. This is a list of IP:port's at which we might be contactable. Some of them will
   * have the same port as the listenPort, but if we are behind a NAT which rewrites our port
   * number, some of them may not. (If we're behind a symmetric NAT which rewrites it differently
   * for each connection, we're stuffed, and we tell the user).
   */
  Peer[] detectPrimaryPeers() {
    final boolean logMINOR = NodeIPPortDetector.logMINOR;
    ArrayList<Peer> addresses = new ArrayList<Peer>();
    FreenetInetAddress[] addrs = detectPrimaryIPAddress();
    for (FreenetInetAddress addr : addrs) {
      addresses.add(new Peer(addr, crypto.portNumber));
      if (logMINOR) Logger.minor(this, "Adding " + addr);
    }
    // Now try to get the rewritten port number from our peers.
    // Only considering those within this crypto port, this time.

    PeerNode[] peerList = crypto.getPeerNodes();

    if (peerList != null) {
      HashMap<Peer, Integer> countsByPeer = new HashMap<Peer, Integer>();
      // FIXME use a standard mutable int object, we have one somewhere
      for (PeerNode pn : peerList) {
        Peer p = pn.getRemoteDetectedPeer();
        if ((p == null) || p.isNull()) continue;
        // DNSRequester doesn't deal with our own node
        if (!IPUtil.isValidAddress(p.getAddress(true), false)) continue;
        if (logMINOR) Logger.minor(this, "Peer " + pn.getPeer() + " thinks we are " + p);
        if (countsByPeer.containsKey(p)) {
          countsByPeer.put(p, countsByPeer.get(p) + 1);
        } else {
          countsByPeer.put(p, 1);
        }
      }
      if (countsByPeer.size() == 1) {
        Iterator<Peer> it = countsByPeer.keySet().iterator();
        Peer p = (it.next());
        Logger.minor(this, "Everyone agrees we are " + p);
        if (!addresses.contains(p)) {
          addresses.add(p);
        }
      } else if (countsByPeer.size() > 1) {
        // Take two most popular addresses.
        Peer best = null;
        Peer secondBest = null;
        int bestPopularity = 0;
        int secondBestPopularity = 0;
        for (Map.Entry<Peer, Integer> entry : countsByPeer.entrySet()) {
          Peer cur = entry.getKey();
          int curPop = entry.getValue();
          Logger.normal(this, "Detected peer: " + cur + " popularity " + curPop);
          if (curPop >= bestPopularity) {
            secondBestPopularity = bestPopularity;
            bestPopularity = curPop;
            secondBest = best;
            best = cur;
          }
        }
        if (best != null) {
          if ((bestPopularity > 1) || (addrs.length == 0)) {
            if (!addresses.contains(best)) {
              Logger.normal(this, "Adding best peer " + best + " (" + bestPopularity + ')');
              addresses.add(best);
            }
            if ((secondBest != null) && (secondBestPopularity > 1)) {
              if (!addresses.contains(secondBest)) {
                Logger.normal(
                    this, "Adding second best peer " + secondBest + " (" + secondBest + ')');
                addresses.add(secondBest);
              }
              if (best.getAddress().equals(secondBest.getAddress()) && bestPopularity == 1) {
                Logger.error(
                    this, "Hrrrm, maybe this is a symmetric NAT? Expect trouble connecting!");
                System.err.println(
                    "Hrrrm, maybe this is a symmetric NAT? Expect trouble connecting!");

                ipDetector.setMaybeSymmetric();

                Peer p = new Peer(best.getFreenetAddress(), crypto.portNumber);
                if (!addresses.contains(p)) addresses.add(p);
              }
            }
          }
        }
      }
    }
    lastPeers = addresses.toArray(new Peer[addresses.size()]);
    if (logMINOR)
      Logger.minor(
          this, "Returning for port " + crypto.portNumber + " : " + Arrays.toString(lastPeers));
    return lastPeers;
  }