Search in sources :

Example 16 with Job

use of net.i2p.router.Job in project i2p.i2p by i2p.

the class IterativeSearchJob method sendQuery.

/**
 *  Send a DLM to the peer
 */
private void sendQuery(Hash peer) {
    TunnelManagerFacade tm = getContext().tunnelManager();
    RouterInfo ri = getContext().netDb().lookupRouterInfoLocally(peer);
    if (ri != null) {
        // Now that most of the netdb is Ed RIs and EC LSs, don't even bother
        // querying old floodfills that don't know about those sig types.
        // This is also more recent than the version that supports encrypted replies,
        // so we won't request unencrypted replies anymore either.
        String v = ri.getVersion();
        String since = MIN_QUERY_VERSION;
        if (VersionComparator.comp(v, since) < 0) {
            failed(peer, false);
            if (_log.shouldLog(Log.WARN))
                _log.warn(getJobId() + ": not sending query to old version " + v + ": " + peer);
            return;
        }
    }
    TunnelInfo outTunnel;
    TunnelInfo replyTunnel;
    boolean isClientReplyTunnel;
    boolean isDirect;
    if (_fromLocalDest != null) {
        outTunnel = tm.selectOutboundTunnel(_fromLocalDest, peer);
        if (outTunnel == null)
            outTunnel = tm.selectOutboundExploratoryTunnel(peer);
        replyTunnel = tm.selectInboundTunnel(_fromLocalDest, peer);
        isClientReplyTunnel = replyTunnel != null;
        if (!isClientReplyTunnel)
            replyTunnel = tm.selectInboundExploratoryTunnel(peer);
        isDirect = false;
    } else if ((!_isLease) && ri != null && getContext().commSystem().isEstablished(peer)) {
        // If it's a RI lookup, not from a client, and we're already connected, just ask directly
        // This also saves the ElG encryption for us and the decryption for the ff
        // There's no anonymity reason to use an expl. tunnel... the main reason
        // is to limit connections to the ffs. But if we're already connected,
        // do it the fast and easy way.
        outTunnel = null;
        replyTunnel = null;
        isClientReplyTunnel = false;
        isDirect = true;
        getContext().statManager().addRateData("netDb.RILookupDirect", 1);
    } else {
        outTunnel = tm.selectOutboundExploratoryTunnel(peer);
        replyTunnel = tm.selectInboundExploratoryTunnel(peer);
        isClientReplyTunnel = false;
        isDirect = false;
        getContext().statManager().addRateData("netDb.RILookupDirect", 0);
    }
    if ((!isDirect) && (replyTunnel == null || outTunnel == null)) {
        failed();
        return;
    }
    // not being able to send to the floodfill, if we don't have an older netdb entry.
    if (outTunnel != null && outTunnel.getLength() <= 1) {
        if (peer.equals(_key)) {
            failed(peer, false);
            if (_log.shouldLog(Log.WARN))
                _log.warn(getJobId() + ": not doing zero-hop self-lookup of " + peer);
            return;
        }
        if (_facade.lookupLocallyWithoutValidation(peer) == null) {
            failed(peer, false);
            if (_log.shouldLog(Log.WARN))
                _log.warn(getJobId() + ": not doing zero-hop lookup to unknown " + peer);
            return;
        }
    }
    DatabaseLookupMessage dlm = new DatabaseLookupMessage(getContext(), true);
    if (isDirect) {
        dlm.setFrom(getContext().routerHash());
    } else {
        dlm.setFrom(replyTunnel.getPeer(0));
        dlm.setReplyTunnel(replyTunnel.getReceiveTunnelId(0));
    }
    dlm.setMessageExpiration(getContext().clock().now() + SINGLE_SEARCH_MSG_TIME);
    dlm.setSearchKey(_key);
    dlm.setSearchType(_isLease ? DatabaseLookupMessage.Type.LS : DatabaseLookupMessage.Type.RI);
    if (_log.shouldLog(Log.INFO)) {
        int tries;
        synchronized (this) {
            tries = _unheardFrom.size() + _failedPeers.size();
        }
        _log.info(getJobId() + ": ISJ try " + tries + " for " + (_isLease ? "LS " : "RI ") + _key + " to " + peer + " direct? " + isDirect + " reply via client tunnel? " + isClientReplyTunnel);
    }
    long now = getContext().clock().now();
    _sentTime.put(peer, Long.valueOf(now));
    I2NPMessage outMsg = null;
    if (isDirect) {
    // never wrap
    } else if (_isLease || (getContext().getProperty(PROP_ENCRYPT_RI, DEFAULT_ENCRYPT_RI) && getContext().jobQueue().getMaxLag() < 300)) {
        // if we have the ff RI, garlic encrypt it
        if (ri != null) {
            // if (DatabaseLookupMessage.supportsEncryptedReplies(ri)) {
            if (true) {
                MessageWrapper.OneTimeSession sess;
                if (isClientReplyTunnel)
                    sess = MessageWrapper.generateSession(getContext(), _fromLocalDest);
                else
                    sess = MessageWrapper.generateSession(getContext());
                if (sess != null) {
                    if (_log.shouldLog(Log.INFO))
                        _log.info(getJobId() + ": Requesting encrypted reply from " + peer + ' ' + sess.key + ' ' + sess.tag);
                    dlm.setReplySession(sess.key, sess.tag);
                }
            // else client went away, but send it anyway
            }
            outMsg = MessageWrapper.wrap(getContext(), dlm, ri);
            // a response may have come in.
            if (_dead) {
                if (_log.shouldLog(Log.DEBUG))
                    _log.debug(getJobId() + ": aborting send, finished while wrapping msg to " + peer);
                return;
            }
            if (_log.shouldLog(Log.DEBUG))
                _log.debug(getJobId() + ": Encrypted DLM for " + _key + " to " + peer);
        }
    }
    if (outMsg == null)
        outMsg = dlm;
    if (isDirect) {
        OutNetMessage m = new OutNetMessage(getContext(), outMsg, outMsg.getMessageExpiration(), OutNetMessage.PRIORITY_MY_NETDB_LOOKUP, ri);
        // Should always succeed, we are connected already
        // m.setOnFailedReplyJob(onFail);
        // m.setOnFailedSendJob(onFail);
        // m.setOnReplyJob(onReply);
        // m.setReplySelector(selector);
        // getContext().messageRegistry().registerPending(m);
        getContext().commSystem().processMessage(m);
    } else {
        getContext().tunnelDispatcher().dispatchOutbound(outMsg, outTunnel.getSendTunnelId(0), peer);
    }
    // The timeout job is always run (never cancelled)
    // Note that the timeout is much shorter than the message expiration (see above)
    Job j = new IterativeTimeoutJob(getContext(), peer, this);
    long expire = Math.min(_expiration, now + _singleSearchTime);
    j.getTiming().setStartAfter(expire);
    getContext().jobQueue().addJob(j);
}
Also used : RouterInfo(net.i2p.data.router.RouterInfo) TunnelInfo(net.i2p.router.TunnelInfo) TunnelManagerFacade(net.i2p.router.TunnelManagerFacade) DatabaseLookupMessage(net.i2p.data.i2np.DatabaseLookupMessage) OutNetMessage(net.i2p.router.OutNetMessage) I2NPMessage(net.i2p.data.i2np.I2NPMessage) ReplyJob(net.i2p.router.ReplyJob) Job(net.i2p.router.Job)

Example 17 with Job

use of net.i2p.router.Job in project i2p.i2p by i2p.

the class IterativeSearchJob method runJob.

@Override
public void runJob() {
    if (_facade.isNegativeCached(_key)) {
        if (_log.shouldLog(Log.WARN))
            _log.warn("Negative cached, not searching: " + _key);
        failed();
        return;
    }
    // pick some floodfill peers and send out the searches
    List<Hash> floodfillPeers;
    KBucketSet<Hash> ks = _facade.getKBuckets();
    if (ks != null) {
        // Ideally we would add the key to an exclude list, so we don't try to query a ff peer for itself,
        // but we're passing the rkey not the key, so we do it below instead in certain cases.
        floodfillPeers = ((FloodfillPeerSelector) _facade.getPeerSelector()).selectFloodfillParticipants(_rkey, _totalSearchLimit + EXTRA_PEERS, ks);
    } else {
        floodfillPeers = new ArrayList<Hash>(_totalSearchLimit);
    }
    // For testing or local networks... we will
    // pretend that the specified router is floodfill, and always closest-to-the-key.
    // May be set after startup but can't be changed or unset later.
    // Warning - experts only!
    String alwaysQuery = getContext().getProperty("netDb.alwaysQuery");
    if (alwaysQuery != null) {
        if (_alwaysQueryHash == null) {
            byte[] b = Base64.decode(alwaysQuery);
            if (b != null && b.length == Hash.HASH_LENGTH)
                _alwaysQueryHash = Hash.create(b);
        }
    }
    if (floodfillPeers.isEmpty()) {
        // so this situation should be temporary
        if (_log.shouldLog(Log.WARN))
            _log.warn("Running netDb searches against the floodfill peers, but we don't know any");
        List<Hash> all = new ArrayList<Hash>(_facade.getAllRouters());
        if (all.isEmpty()) {
            if (_log.shouldLog(Log.ERROR))
                _log.error("We don't know any peers at all");
            failed();
            return;
        }
        Iterator<Hash> iter = new RandomIterator<Hash>(all);
        // so once we get some FFs we want to be sure to query them
        for (int i = 0; iter.hasNext() && i < MAX_NON_FF; i++) {
            floodfillPeers.add(iter.next());
        }
    }
    final boolean empty;
    // outside sync to avoid deadlock
    final Hash us = getContext().routerHash();
    synchronized (this) {
        _toTry.addAll(floodfillPeers);
        // don't ask ourselves or the target
        _toTry.remove(us);
        _toTry.remove(_key);
        empty = _toTry.isEmpty();
    }
    if (empty) {
        if (_log.shouldLog(Log.WARN))
            _log.warn(getJobId() + ": ISJ for " + _key + " had no peers to send to");
        // no floodfill peers, fail
        failed();
        return;
    }
    // This OutNetMessage is never used or sent (setMessage() is never called), it's only
    // so we can register a reply selector.
    MessageSelector replySelector = new IterativeLookupSelector(getContext(), this);
    ReplyJob onReply = new FloodOnlyLookupMatchJob(getContext(), this);
    Job onTimeout = new FloodOnlyLookupTimeoutJob(getContext(), this);
    _out = getContext().messageRegistry().registerPending(replySelector, onReply, onTimeout);
    if (_log.shouldLog(Log.INFO))
        _log.info(getJobId() + ": New ISJ for " + (_isLease ? "LS " : "RI ") + _key + " (rkey " + _rkey + ") timeout " + DataHelper.formatDuration(_timeoutMs) + " toTry: " + DataHelper.toString(_toTry));
    retry();
}
Also used : ArrayList(java.util.ArrayList) Hash(net.i2p.data.Hash) ReplyJob(net.i2p.router.ReplyJob) MessageSelector(net.i2p.router.MessageSelector) ReplyJob(net.i2p.router.ReplyJob) Job(net.i2p.router.Job) RandomIterator(net.i2p.router.util.RandomIterator)

Example 18 with Job

use of net.i2p.router.Job in project i2p.i2p by i2p.

the class KademliaNetworkDatabaseFacade method startup.

public synchronized void startup() {
    _log.info("Starting up the kademlia network database");
    RouterInfo ri = _context.router().getRouterInfo();
    String dbDir = _context.getProperty(PROP_DB_DIR, DEFAULT_DB_DIR);
    _kb = new KBucketSet<Hash>(_context, ri.getIdentity().getHash(), BUCKET_SIZE, KAD_B, new RejectTrimmer<Hash>());
    try {
        _ds = new PersistentDataStore(_context, dbDir, this);
    } catch (IOException ioe) {
        throw new RuntimeException("Unable to initialize netdb storage", ioe);
    }
    // _ds = new TransientDataStore();
    // _exploreKeys = new HashSet(64);
    _dbDir = dbDir;
    _negativeCache = new NegativeLookupCache(_context);
    createHandlers();
    _initialized = true;
    _started = System.currentTimeMillis();
    // expire old leases
    Job elj = new ExpireLeasesJob(_context, this);
    elj.getTiming().setStartAfter(_context.clock().now() + 2 * 60 * 1000);
    _context.jobQueue().addJob(elj);
    // Don't run until after RefreshRoutersJob has run, and after validate() will return invalid for old routers.
    if (!_context.commSystem().isDummy()) {
        Job erj = new ExpireRoutersJob(_context, this);
        erj.getTiming().setStartAfter(_context.clock().now() + ROUTER_INFO_EXPIRATION_FLOODFILL + 10 * 60 * 1000);
        _context.jobQueue().addJob(erj);
    }
    if (!QUIET) {
        // _context.jobQueue().addJob(new ExploreKeySelectorJob(_context, this));
        if (_exploreJob == null)
            _exploreJob = new StartExplorersJob(_context, this);
        // fire off a group of searches from the explore pool
        // Don't start it right away, so we don't send searches for random keys
        // out our 0-hop exploratory tunnels (generating direct connections to
        // one or more floodfill peers within seconds of startup).
        // We're trying to minimize the ff connections to lessen the load on the
        // floodfills, and in any case let's try to build some real expl. tunnels first.
        // No rush, it only runs every 30m.
        _exploreJob.getTiming().setStartAfter(_context.clock().now() + EXPLORE_JOB_DELAY);
        _context.jobQueue().addJob(_exploreJob);
    } else {
        _log.warn("Operating in quiet mode - not exploring or pushing data proactively, simply reactively");
        _log.warn("This should NOT be used in production");
    }
    // periodically update and resign the router's 'published date', which basically
    // serves as a version
    Job plrij = new PublishLocalRouterInfoJob(_context);
    // do not delay this, as this creates the RI too, and we need a good local routerinfo right away
    // plrij.getTiming().setStartAfter(_context.clock().now() + PUBLISH_JOB_DELAY);
    _context.jobQueue().addJob(plrij);
// plrij calls publish() for us
// try {
// publish(ri);
// } catch (IllegalArgumentException iae) {
// _context.router().rebuildRouterInfo(true);
// //_log.log(Log.CRIT, "Our local router info is b0rked, clearing from scratch", iae);
// //_context.router().rebuildNewIdentity();
// }
}
Also used : PublishLocalRouterInfoJob(net.i2p.router.networkdb.PublishLocalRouterInfoJob) RouterInfo(net.i2p.data.router.RouterInfo) IOException(java.io.IOException) Hash(net.i2p.data.Hash) PublishLocalRouterInfoJob(net.i2p.router.networkdb.PublishLocalRouterInfoJob) Job(net.i2p.router.Job) RejectTrimmer(net.i2p.kademlia.RejectTrimmer)

Example 19 with Job

use of net.i2p.router.Job in project i2p.i2p by i2p.

the class FloodOnlySearchJob method failed.

@Override
void failed() {
    synchronized (this) {
        if (_dead)
            return;
        _dead = true;
    }
    getContext().messageRegistry().unregisterPending(_out);
    long time = System.currentTimeMillis() - _created;
    if (_log.shouldLog(Log.INFO)) {
        int timeRemaining = (int) (_expiration - getContext().clock().now());
        _log.info(getJobId() + ": Floodfill search for " + _key + " failed with " + timeRemaining + " remaining after " + time);
    }
    synchronized (_unheardFrom) {
        for (Hash h : _unheardFrom) getContext().profileManager().dbLookupFailed(h);
    }
    _facade.complete(_key);
    getContext().statManager().addRateData("netDb.failedTime", time);
    for (Job j : _onFailed) {
        getContext().jobQueue().addJob(j);
    }
    _onFailed.clear();
}
Also used : Hash(net.i2p.data.Hash) ReplyJob(net.i2p.router.ReplyJob) Job(net.i2p.router.Job)

Example 20 with Job

use of net.i2p.router.Job in project i2p.i2p by i2p.

the class FloodfillDatabaseLookupMessageHandler method createJob.

public Job createJob(I2NPMessage receivedMessage, RouterIdentity from, Hash fromHash) {
    _context.statManager().addRateData("netDb.lookupsReceived", 1);
    DatabaseLookupMessage dlm = (DatabaseLookupMessage) receivedMessage;
    if (!_facade.shouldThrottleLookup(dlm.getFrom(), dlm.getReplyTunnel())) {
        Job j = new HandleFloodfillDatabaseLookupMessageJob(_context, dlm, from, fromHash);
        // } else {
        return j;
    // }
    } else {
        if (_log.shouldLog(Log.WARN))
            _log.warn("Dropping lookup request for " + dlm.getSearchKey() + " (throttled), reply was to: " + dlm.getFrom() + " tunnel: " + dlm.getReplyTunnel());
        _context.statManager().addRateData("netDb.lookupsDropped", 1, 1);
        return null;
    }
}
Also used : DatabaseLookupMessage(net.i2p.data.i2np.DatabaseLookupMessage) Job(net.i2p.router.Job)

Aggregations

Job (net.i2p.router.Job)20 Hash (net.i2p.data.Hash)9 ReplyJob (net.i2p.router.ReplyJob)7 RouterInfo (net.i2p.data.router.RouterInfo)4 TunnelInfo (net.i2p.router.TunnelInfo)3 IOException (java.io.IOException)2 ArrayList (java.util.ArrayList)2 TunnelId (net.i2p.data.TunnelId)2 DatabaseLookupMessage (net.i2p.data.i2np.DatabaseLookupMessage)2 DatabaseStoreMessage (net.i2p.data.i2np.DatabaseStoreMessage)2 I2NPMessage (net.i2p.data.i2np.I2NPMessage)2 MessageSelector (net.i2p.router.MessageSelector)2 OutNetMessage (net.i2p.router.OutNetMessage)2 SendMessageDirectJob (net.i2p.router.message.SendMessageDirectJob)2 ReadConfigJob (net.i2p.router.tasks.ReadConfigJob)2 Date (java.util.Date)1 SessionConfig (net.i2p.data.i2cp.SessionConfig)1 DeliveryStatusMessage (net.i2p.data.i2np.DeliveryStatusMessage)1 TunnelGatewayMessage (net.i2p.data.i2np.TunnelGatewayMessage)1 RouterKeyGenerator (net.i2p.data.router.RouterKeyGenerator)1