package com.limegroup.gnutella.dht; import java.net.SocketAddress; import java.util.List; import org.limewire.io.IpPort; import org.limewire.mojito.EntityKey; import org.limewire.mojito.KUID; import org.limewire.mojito.MojitoDHT; import org.limewire.mojito.concurrent.DHTFuture; import org.limewire.mojito.db.DHTValue; import org.limewire.mojito.result.FindValueResult; import org.limewire.mojito.result.StoreResult; import org.limewire.mojito.routing.Vendor; import org.limewire.mojito.routing.Version; import com.limegroup.gnutella.NodeAssigner; import com.limegroup.gnutella.connection.ConnectionLifecycleListener; import com.limegroup.gnutella.messages.vendor.DHTContactsMessage; import com.limegroup.gnutella.util.EventDispatcher; /** * The DHT Manager interface defines methods to start, stop and perform * operations related to the maintenance of the DHT (bootstrapping, etc.). * It also takes care of switching between different DHT modes for a DHT node. */ public interface DHTManager extends ConnectionLifecycleListener, EventDispatcher<DHTEvent, DHTEventListener>{ /** * Defines the modes of a DHT Node (inactive, active, passive and passive leaf). */ public static enum DHTMode { /** * A DHT Node is in INACTIVE mode if it supports the DHT * but is currently not capable of joining it. * * @see NodeAssigner.java */ INACTIVE(0x00, new byte[]{ 'I', 'D', 'H', 'T' }), /** * A DHT Node is ACTIVE mode if it's a full participant * of the DHT, e.g. a non-firewalled Gnutella leave node * with a sufficiently stable connection. */ ACTIVE(0x01, new byte[]{ 'A', 'D', 'H', 'T' }), /** * A DHT Node is in PASSIVE mode if it's connected to * the DHT but is not part of the global DHT routing table. * Thus, a passive node never receives requests from the DHT * and does necessarily have an accurate knowledge of the DHT * structure. However, it can perform queries and requests stores. */ PASSIVE(0x02, new byte[]{ 'P', 'D', 'H', 'T' }), /** * The PASSIVE_LEAF mode is very similar to PASSIVE mode with * two major differences: * <pre> * 1) A passive leaf has a fixed size LRU Map as its RouteTable. * That means it has almost no knowledge of the global DHT * RouteTable and depends entirely on an another peer (Ultrapeer) * that feeds it continuously with fresh contacts. * * 2) A passive leaf node does not perform any Kademlia maintenance * operations!</pre> */ PASSIVE_LEAF(0x03, new byte[]{ 'L', 'D', 'H', 'T' }); public static final byte DHT_MODE_MASK = 0x0F; private final int mode; private final byte[] capabilityName; private DHTMode(int mode, byte[] capabilityName) { assert (capabilityName.length == 4); this.mode = mode; this.capabilityName = capabilityName; } /** * Returns the mode as byte. */ public byte byteValue() { return (byte)(mode & 0xFF); } /** * Returns the VM capability name. */ public byte[] getCapabilityName() { byte[] copy = new byte[capabilityName.length]; System.arraycopy(capabilityName, 0, copy, 0, copy.length); return copy; } private static final DHTMode[] MODES; static { DHTMode[] modes = values(); MODES = new DHTMode[modes.length]; for (DHTMode m : modes) { int index = (m.mode & 0xFF) % MODES.length; assert (MODES[index] == null); MODES[index] = m; } } /** * Returns a DHTMode enum for the given mode and null * if no such DHTMode exists. */ public static DHTMode valueOf(int mode) { int index = (mode & 0xFF) % MODES.length; DHTMode s = MODES[index]; if (s.mode == mode) { return s; } return null; } } /** * Sets whether or not the DHT is enabled. */ public void setEnabled(boolean enabled); /** * Returns whether or not the DHT is enabled. */ public boolean isEnabled(); /** * Starts the DHT Node either in active or passive mode. * <p> * Note: You can use this method to stop the DHT by passing in * DHTMode.INACTIVE. The difference between using this method * and the {@link #stop()} method is that stop() is synchronous * (i.e. blocking) and start() with DHTMode.INACTIVE isn't. */ public void start(DHTMode mode); /** * Stops the DHT Node. */ public void stop(); /** * Passes the given active DHT node to the DHT controller * in order to bootstrap or perform other maintenance operations. */ public void addActiveDHTNode(SocketAddress hostAddress); /** * Passes the given passive DHT node to the DHT controller * in order to bootstrap or perform other maintenance operations. */ public void addPassiveDHTNode(SocketAddress hostAddress); /** * Notifies the DHT controller that our external Address has changed. */ public void addressChanged(); /** * Returns maxNodes number of active Node's IP:Ports. */ public List<IpPort> getActiveDHTNodes(int maxNodes); /** * Returns the mode of the DHT. */ public DHTMode getDHTMode(); /** * Returns whether this Node is running. */ public boolean isRunning(); /** * Returns whether this Node is bootstrapped. */ public boolean isBootstrapped(); /** * Returns whether this Node is part of the DHT. */ public boolean isMemberOfDHT(); /** * Returns whether this Node is waiting for Nodes or not. */ public boolean isWaitingForNodes(); /** * Returns the MojitoDHT instance (null if Node is running in inactive mode!). */ public MojitoDHT getMojitoDHT(); /** * Returns the Vendor code of this Node. */ public Vendor getVendor(); /** * Returns the Vendor code of this Node. */ public Version getVersion(); /** * Callback to notify the manager about new DHT Contacts that * were exchanged over regular Gnutella messages. * * @see com.limegroup.gnutella.messages.vendor.DHTContactsMessage */ public void handleDHTContactsMessage(DHTContactsMessage msg); /** * Calls the {@link MojitoDHT#get(EntityKey)} if a bootstrappable DHT is available. * Also handles the locking properly to ensure thread safety. * * @param eKey the entity key used to perform lookup in the DHT. * * @return an instance of <code>DHTFuture</code> containing the result of the lookup. * <br> Returns null if DHT is unavailable or the DHT is not bootstrapped. */ public DHTFuture<FindValueResult> get(EntityKey eKey); /** * Calls the {@link MojitoDHT#put(KUID, DHTValue)} if a bootstrappable DHT is available. * Also handles the locking properly to ensure thread safety. * * @param eKey the entity key used to perform lookup in the DHT. * * @return an instance of <code>DHTFuture</code> containing the result of the lookup. * <br> Returns null if DHT is unavailable or the DHT is not bootstrapped. */ public DHTFuture<StoreResult> put(KUID key, DHTValue value); }