Package freenet.node

Source Code of freenet.node.OpennetPeerNode

package freenet.node;

import static java.util.concurrent.TimeUnit.HOURS;
import static java.util.concurrent.TimeUnit.SECONDS;

import freenet.io.comm.PeerParseException;
import freenet.io.comm.ReferenceSignatureVerificationException;
import freenet.node.OpennetManager.ConnectionType;
import freenet.node.OpennetManager.LinkLengthClass;
import freenet.node.updater.NodeUpdateManager;
import freenet.node.updater.UpdateOverMandatoryManager;
import freenet.support.Logger;
import freenet.support.SimpleFieldSet;

public class OpennetPeerNode extends PeerNode {

  final OpennetManager opennet;
  private long timeLastSuccess;
  // Not persisted across restart, since after restart grace periods don't apply anyway (except disconnection, which is really separate anyway).
  private ConnectionType opennetNodeAddedReason;
 
  public OpennetPeerNode(SimpleFieldSet fs, Node node2, NodeCrypto crypto, OpennetManager opennet, PeerManager peers, boolean fromLocal, OutgoingPacketMangler mangler) throws FSParseException, PeerParseException, ReferenceSignatureVerificationException {
    super(fs, node2, crypto, peers, fromLocal, false, mangler, true);

    if (fromLocal) {
      SimpleFieldSet metadata = fs.subset("metadata");
      timeLastSuccess = metadata.getLong("timeLastSuccess", 0);
    }
   
    this.opennet = opennet;
  }

  @Override
  public PeerNodeStatus getStatus(boolean noHeavy) {
    return new OpennetPeerNodeStatus(this, noHeavy);
  }

  @Override
  public boolean isRoutingCompatible() {
    if(!node.isOpennetEnabled()) return false;
    return super.isRoutingCompatible();
  }

  @Override
  public boolean isDarknet() {
    return false;
  }

  @Override
  public boolean isOpennet() {
    return true;
  }

  @Override
  public boolean isSeed() {
    return false;
  }

  enum NOT_DROP_REASON {
    DROPPABLE,
    TOO_NEW_PEER,
    TOO_LOW_UPTIME,
    RECONNECT_GRACE_PERIOD
  }
 
  public boolean isDroppable(boolean ignoreDisconnect) {
    return isDroppableWithReason(ignoreDisconnect) == NOT_DROP_REASON.DROPPABLE;
  }
   
  /** Is the peer droppable?
   * SIDE EFFECT: If we are now outside the grace period, we reset peerAddedTime and opennetPeerAddedReason.
   * Note that the caller must check separately whether the node is TOO OLD and connected. */
  public NOT_DROP_REASON isDroppableWithReason(boolean ignoreDisconnect) {
    long now = System.currentTimeMillis();
    int status = getPeerNodeStatus();
    long age = now - getPeerAddedTime();
    if(age < OpennetManager.DROP_MIN_AGE) {
      if(status == PeerManager.PEER_NODE_STATUS_NEVER_CONNECTED) {
        // New peer, never connected.
        // Allow it 1 minute to connect.
        if(age < OpennetManager.DROP_MIN_AGE_DISCONNECTED)
          return NOT_DROP_REASON.TOO_NEW_PEER;
      } else if(status != PeerManager.PEER_NODE_STATUS_DISCONNECTED) {
        // Based on the time added, *not* the last connected time.
        // This prevents various dubious ways of staying connected while not delivering anything useful.
        return NOT_DROP_REASON.TOO_NEW_PEER; // New node
      }
    } else {
      synchronized(this) {
        peerAddedTime = 0;
        opennetNodeAddedReason = null;
      }
    }
    if(now - node.usm.getStartedTime() < OpennetManager.DROP_STARTUP_DELAY)
      return NOT_DROP_REASON.TOO_LOW_UPTIME; // Give them time to connect after we startup
    if(!ignoreDisconnect) {
    synchronized(this) {
      // This only applies after it has connected, and only if !ignoreDisconnect.
      // Hence only DISCONNECTED and not NEVER CONNECTED.
      if((status == PeerManager.PEER_NODE_STATUS_DISCONNECTED) && (!super.neverConnected()) &&
          now - timeLastDisconnect < OpennetManager.DROP_DISCONNECT_DELAY &&
          now - timePrevDisconnect > OpennetManager.DROP_DISCONNECT_DELAY_COOLDOWN) {
        // Grace period for node restarting
        return NOT_DROP_REASON.RECONNECT_GRACE_PERIOD;
      }
    }
    }
    return NOT_DROP_REASON.DROPPABLE;
  }
 
  @Override
  public void onSuccess(boolean insert, boolean ssk) {
    if(insert || ssk) return;
    timeLastSuccess = System.currentTimeMillis();
    opennet.onSuccess(this);
  }

  @Override
  public void onRemove() {
    opennet.onRemove(this);
    super.onRemove();
  }
 
  @Override
  public synchronized SimpleFieldSet exportMetadataFieldSet(long now) {
    SimpleFieldSet fs = super.exportMetadataFieldSet(now);
    fs.put("timeLastSuccess", timeLastSuccess);
    return fs;
  }

  public final long timeLastSuccess() {
    return timeLastSuccess;
  }
 
  /**
   * Is the SimpleFieldSet a valid noderef?
   */
  public static boolean validateRef(SimpleFieldSet ref) {
    if(!ref.getBoolean("opennet", false)) return false;
    return true;
  }

  @Override
  public boolean isRealConnection() {
    return true;
  }

  @Override
  public boolean recordStatus() {
    return true;
  }

  @Override
  protected boolean generateIdentityFromPubkey() {
    return false;
  }
  @Override
  public boolean equals(Object o) {
    if(o == this) return true;
    // Only equal to seednode of its own type.
    if(o instanceof OpennetPeerNode) {
      return super.equals(o);
    } else return false;
  }
 
  @Override
  public final boolean shouldDisconnectAndRemoveNow() {
    // Allow announced peers 15 minutes to download the auto-update.
    if(isConnected() && isUnroutableOlderVersion()) {
      return shouldDisconnectTooOld();
    }
    return false;
  }

  /** If a node is TOO OLD, we should keep it connected for a brief period for it to
   * allow it to issue a UOM request, we should keep it connected while the UOM transfer
   * is in progress, but otherwise we should disconnect. */
  private boolean shouldDisconnectTooOld() {
    long uptime = System.currentTimeMillis() - timeLastConnectionCompleted();
    if(uptime < SECONDS.toMillis(30))
      // Allow 30 seconds to send the UOM request.
      return false;
    // FIXME remove, paranoia
    if(uptime < HOURS.toMillis(1))
      return false;
    NodeUpdateManager updater = node.nodeUpdater;
    if(updater == null) return true; // Not going to UOM.
    UpdateOverMandatoryManager uom = updater.uom;
    if(uom == null) return true; // Not going to UOM
    if(uptime > HOURS.toMillis(2)) {
      // UOM transfers can take ages, but there has to be some limit...
      return true;
    }
    if(timeSinceSentUOM() < SECONDS.toMillis(60)) {
      // Let it finish.
      // 60 seconds extra to ensure it has time to parse the jar and start fetching dependencies.
      return false;
    }
    return true;
  }

  @Override
  protected void onConnect() {
    super.onConnect();
    opennet.crypto.socket.getAddressTracker().setPresumedGuiltyAt(System.currentTimeMillis() + HOURS.toMillis(1));
  }
 
  private boolean wasDropped;

  synchronized void setWasDropped() {
    wasDropped = true;
  }
 
  synchronized boolean wasDropped() {
    return wasDropped;
  }
 
  synchronized boolean grabWasDropped() {
    boolean ret = wasDropped;
    wasDropped = false;
    return ret;
  }
 
  @Override
  public synchronized void setAddedReason(ConnectionType connectionType) {
    opennetNodeAddedReason = connectionType;
  }
 
  @Override
  public synchronized ConnectionType getAddedReason() {
    return opennetNodeAddedReason;
  }

  @Override
  /** Opennet nodes need to know when a peer node was added.
   * We do NOT clear it on connect, because we use it for determining whether we are in the initial grace period.
   * However we will reset it after the grace period expires, in isDroppableWithReason(). */
  protected void maybeClearPeerAddedTimeOnConnect() {
    // Guarantee that it gets cleared.
    node.getTicker().queueTimedJob(new FastRunnable() {

      @Override
      public void run() {
        isDroppableWithReason(false);
      }
     
    }, OpennetManager.DROP_MIN_AGE+1);
  }

  @Override
  /* Opennet peers do not export the peer added time. It is only relevant for the grace period anyway. */
  protected boolean shouldExportPeerAddedTime() {
    return false;
  }

  @Override
  protected void maybeClearPeerAddedTimeOnRestart(long now) {
    // Do nothing.
  }

  @Override
  public void fatalTimeout() {
    if(node.isStopping()) return;
    Logger.error(this, "Disconnecting "+this+" because of fatal timeout");
    // Disconnect.
    forceDisconnect();
  }
 
  @Override
  public boolean shallWeRouteAccordingToOurPeersLocation() {
    return node.shallWeRouteAccordingToOurPeersLocation();
  }

  @Override
  boolean dontKeepFullFieldSet() {
    return true;
  }
 
    public LinkLengthClass linkLengthClass() {
        if(!Location.isValid(getLocation())) {
            Logger.error(this, "No location on "+this, new Exception("debug"));
            return LinkLengthClass.SHORT; // FIXME add unknown to enum? Would need more complex error handling...
        }
        // FIXME OPTIMISE This should not change since we don't swap on opennet.
        if(Location.distance(this, opennet.node.getLocation()) > OpennetManager.LONG_DISTANCE)
            return LinkLengthClass.LONG;
        else
            return LinkLengthClass.SHORT;
    }

}
TOP

Related Classes of freenet.node.OpennetPeerNode

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.