package net.i2p.router.networkdb.kademlia; import java.util.concurrent.atomic.AtomicInteger; import net.i2p.data.Hash; import net.i2p.data.router.RouterInfo; import net.i2p.data.i2np.DatabaseSearchReplyMessage; import net.i2p.data.i2np.DatabaseStoreMessage; import net.i2p.data.i2np.I2NPMessage; import net.i2p.router.MessageSelector; import net.i2p.router.RouterContext; import net.i2p.util.Log; /** * Check to see the message is a reply from the peer regarding the current * search * */ class SearchMessageSelector implements MessageSelector { private final Log _log; private final RouterContext _context; private static final AtomicInteger __searchSelectorId = new AtomicInteger(); private final Hash _peer; private volatile boolean _found; private final int _id; private final long _exp; private final SearchState _state; public SearchMessageSelector(RouterContext context, RouterInfo peer, long expiration, SearchState state) { _context = context; _log = context.logManager().getLog(SearchMessageSelector.class); _peer = peer.getIdentity().getHash(); _exp = expiration; _state = state; _id = __searchSelectorId.incrementAndGet(); if (_log.shouldLog(Log.DEBUG)) _log.debug("[" + _id + "] Created: " + toString()); } @Override public String toString() { return "Search selector [" + _id + "] looking for a reply from " + _peer + " with regards to " + _state.getTarget(); } public boolean continueMatching() { boolean expired = _context.clock().now() > _exp; if (expired) return false; // so we dont drop outstanding replies after receiving the value // > 1 to account for the 'current' match if (_state.getPending().size() > 1) return true; if (_found) { if (_log.shouldLog(Log.DEBUG)) _log.debug("[" + _id + "] Dont continue matching! looking for a reply from " + _peer + " with regards to " + _state.getTarget()); return false; } else { return true; } } public long getExpiration() { return _exp; } public boolean isMatch(I2NPMessage message) { if (_log.shouldLog(Log.DEBUG)) _log.debug("[" + _id + "] isMatch("+message.getClass().getName() + ") [want dbStore or dbSearchReply from " + _peer + " for " + _state.getTarget() + "]"); if (message instanceof DatabaseStoreMessage) { DatabaseStoreMessage msg = (DatabaseStoreMessage)message; if (msg.getKey().equals(_state.getTarget())) { if (_log.shouldLog(Log.DEBUG)) _log.debug("[" + _id + "] Was a DBStore of the key we're looking for. " + "May not have been from who we're checking against though, " + "but DBStore doesn't include that info"); _found = true; return true; } else { if (_log.shouldLog(Log.DEBUG)) _log.debug("[" + _id + "] DBStore of a key we're not looking for"); return false; } } else if (message instanceof DatabaseSearchReplyMessage) { DatabaseSearchReplyMessage msg = (DatabaseSearchReplyMessage)message; if (_peer.equals(msg.getFromHash())) { if (msg.getSearchKey().equals(_state.getTarget())) { if (_log.shouldLog(Log.DEBUG)) _log.debug("[" + _id + "] Was a DBSearchReply from who we're " + "checking with for a key we're looking for"); _found = true; return true; } else { if (_log.shouldLog(Log.DEBUG)) _log.debug("[" + _id + "] Was a DBSearchReply from who we're checking " + "with but NOT for the key we're looking for"); return false; } } else { if (_log.shouldLog(Log.DEBUG)) _log.debug("[" + _id + "] DBSearchReply from someone we are not checking with [" + msg.getFromHash() + ", not " + _state.getTarget() + "]"); return false; } } else { //_log.debug("Not a DbStore or DbSearchReply"); return false; } } }