package com.limegroup.gnutella.dht.db; import java.net.InetAddress; import java.net.InetSocketAddress; import java.util.Arrays; import java.util.Set; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.limewire.io.GUID; import org.limewire.io.IpPort; import org.limewire.io.IpPortImpl; import org.limewire.mojito.EntityKey; import org.limewire.mojito.KUID; import org.limewire.mojito.concurrent.DHTFuture; import org.limewire.mojito.db.DHTValue; import org.limewire.mojito.db.DHTValueEntity; import org.limewire.mojito.result.FindValueResult; import org.limewire.mojito.routing.Contact; import com.google.inject.Inject; import com.google.inject.Singleton; import com.limegroup.gnutella.PushEndpoint; import com.limegroup.gnutella.PushEndpointFactory; import com.limegroup.gnutella.dht.DHTManager; import com.limegroup.gnutella.dht.util.KUIDUtils; /** * Searches for {@link PushEndpoint push endpoints} in the DHT. */ @Singleton public class DHTPushEndpointFinder implements PushEndpointService { private static final Log LOG = LogFactory.getLog(DHTPushEndpointFinder.class); private final PushEndpointFactory pushEndpointFactory; private final DHTManager dhtManager; @Inject public DHTPushEndpointFinder(DHTManager dhtManager, PushEndpointFactory pushEndpointFactory) { this.dhtManager = dhtManager; this.pushEndpointFactory = pushEndpointFactory; } public void findPushEndpoint(GUID guid, SearchListener<PushEndpoint> listener) { listener = SearchListenerAdapter.nonNullListener(listener); if (LOG.isDebugEnabled()) { LOG.debug("starting dht lookup for guid: " + guid); } KUID key = KUIDUtils.toKUID(guid); EntityKey lookupKey = EntityKey.createEntityKey(key, AbstractPushProxiesValue.PUSH_PROXIES); DHTFuture<FindValueResult> future = dhtManager.get(lookupKey); if(future != null) { future.addFutureListener(new PushEndpointHandler(dhtManager, guid, key, listener)); } else { LOG.debug("dht manager not bootstrapped or no dht"); listener.searchFailed(); } } public PushEndpoint getPushEndpoint(GUID guid) { BlockingSearchListener<PushEndpoint> listener = new BlockingSearchListener<PushEndpoint>(); findPushEndpoint(guid, listener); return listener.getResult(); } /** * The PushAltLocsHandler listens for FindValueResults, constructs PushEndpoints * from the results and passes them to AltLocManager which in turn notifies all * Downloads about the new alternate locations. */ private class PushEndpointHandler extends AbstractResultHandler { private final GUID guid; private final SearchListener<PushEndpoint> listener; private PushEndpointHandler(DHTManager dhtManager, GUID guid, KUID key, SearchListener<PushEndpoint> listener) { super(dhtManager, key, listener, AbstractPushProxiesValue.PUSH_PROXIES); this.guid = guid; this.listener = listener; } @Override protected Result handleDHTValueEntity(DHTValueEntity entity) { DHTValue value = entity.getValue(); if (!(value instanceof PushProxiesValue)) { return Result.NOT_FOUND; } Contact creator = entity.getCreator(); InetAddress addr = ((InetSocketAddress)creator.getContactAddress()).getAddress(); PushProxiesValue pushProxies = (PushProxiesValue)value; // Compare the GUIDs from the AltLoc and PushProxy value! // They should be the same! byte[] guid = this.guid.bytes(); if (!Arrays.equals(guid, pushProxies.getGUID())) { if (LOG.isWarnEnabled()) { LOG.warn("The AltLoc and PushProxy GUIDs do not match!"); } return Result.NOT_FOUND; } Set<? extends IpPort> proxies = pushProxies.getPushProxies(); byte features = pushProxies.getFeatures(); int fwtVersion = pushProxies.getFwtVersion(); IpPort ipp = new IpPortImpl(addr, pushProxies.getPort()); PushEndpoint pe = pushEndpointFactory.createPushEndpoint(guid, proxies, features, fwtVersion, ipp); if (LOG.isDebugEnabled()) { LOG.debug("push endpoint found: " + pe); } listener.handleResult(pe); return Result.FOUND; } } }