/** * Call when the ports might have changed * The transports can call this pretty quickly at startup, * which can have multiple UPnP threads running at once, but * that should be ok. */ public void update(Set<TransportManager.Port> ports) { if (_log.shouldLog(Log.DEBUG)) _log.debug("UPnP Update with " + ports.size() + " ports"); //synchronized(this) { // TODO // called too often and may block for too long // may not have started if net was disconnected previously //if (!_isRunning && !ports.isEmpty()) // start(); if (!_isRunning) return; //} Set<ForwardPort> forwards = new HashSet<ForwardPort>(ports.size()); for (TransportManager.Port entry : ports) { String style = entry.style; int port = entry.port; int protocol = -1; if ("SSU".equals(style)) protocol = ForwardPort.PROTOCOL_UDP_IPV4; else if ("NTCP".equals(style)) protocol = ForwardPort.PROTOCOL_TCP_IPV4; else continue; if (_log.shouldLog(Log.DEBUG)) _log.debug("Adding: " + style + " " + port); ForwardPort fp = new ForwardPort(style, false, protocol, port); forwards.add(fp); } // non-blocking _upnp.onChangePublicPorts(forwards, _upnpCallback); }
/** * Fetch to memory * * @param retries if < 0, set timeout to a few seconds * @param initialSize buffer size * @param maxSize fails if greater * @return null on error * @since 0.9.4 */ public byte[] get(String url, boolean rewrite, int retries, int initialSize, int maxSize) { if (_log.shouldLog(Log.DEBUG)) _log.debug("Fetching [" + url + "] to memory"); String fetchURL = url; if (rewrite) fetchURL = rewriteAnnounce(url); int timeout; if (retries < 0) { if (!connected()) return null; timeout = EEPGET_CONNECT_TIMEOUT_SHORT; retries = 0; } else { timeout = EEPGET_CONNECT_TIMEOUT; if (!connected()) { if (!connect()) return null; } } ByteArrayOutputStream out = new ByteArrayOutputStream(initialSize); EepGet get = new I2PSocketEepGet(_context, _manager, retries, -1, maxSize, null, out, fetchURL); get.addHeader("User-Agent", EEPGET_USER_AGENT); if (get.fetch(timeout)) { if (_log.shouldLog(Log.DEBUG)) _log.debug("Fetch successful [" + url + "]: size=" + out.size()); return out.toByteArray(); } else { if (_log.shouldLog(Log.WARN)) _log.warn("Fetch failed [" + url + "]"); return null; } }
/** * SOCKS5 connection initialization. This method assumes that SOCKS "VER" field has been stripped * from the input stream. */ private void init(DataInputStream in, DataOutputStream out) throws IOException, SOCKSException { int nMethods = in.readUnsignedByte(); int method = Method.NO_ACCEPTABLE_METHODS; for (int i = 0; i < nMethods; ++i) { int meth = in.readUnsignedByte(); if (((!authRequired) && meth == Method.NO_AUTH_REQUIRED) || (authRequired && meth == Method.USERNAME_PASSWORD)) { // That's fine, we do support this method method = meth; } } switch (method) { case Method.USERNAME_PASSWORD: _log.debug("username/password authentication required"); sendInitReply(Method.USERNAME_PASSWORD, out); verifyPassword(in, out); return; case Method.NO_AUTH_REQUIRED: _log.debug("no authentication required"); sendInitReply(Method.NO_AUTH_REQUIRED, out); return; default: _log.debug( "no suitable authentication methods found (" + Integer.toHexString(method) + ")"); sendInitReply(Method.NO_ACCEPTABLE_METHODS, out); throw new SOCKSException("Unsupported authentication method"); } }
public int allocPage() throws IOException { if (freeListStart != 0) { try { if (flb == null) flb = new FreeListBlock(file, freeListStart); if (!flb.isEmpty()) { if (log.shouldLog(Log.DEBUG)) log.debug("Alloc from " + flb); return flb.takePage(); } else { if (log.shouldLog(Log.DEBUG)) log.debug("Alloc returning empty " + flb); freeListStart = flb.getNextPage(); writeSuperBlock(); int rv = flb.page; flb = null; return rv; } } catch (IOException ioe) { log.error("Discarding corrupt free list block page " + freeListStart, ioe); freeListStart = 0; } } long offset = file.length(); fileLen = offset + PAGESIZE; file.setLength(fileLen); writeSuperBlock(); return (int) ((offset / PAGESIZE) + 1); }
protected boolean execStreamClose(Properties props) { if (props == null) { _log.debug("No parameters specified in STREAM CLOSE message"); return false; } int id; { String strid = props.getProperty("ID"); if (strid == null) { _log.debug("ID not specified in STREAM CLOSE message"); return false; } try { id = Integer.parseInt(strid); } catch (NumberFormatException e) { _log.debug("Invalid STREAM CLOSE ID specified: " + strid); return false; } } boolean closed = getStreamSession().closeConnection(id); if ((!closed) && (_log.shouldLog(Log.WARN))) _log.warn("Stream unable to be closed, but this is non fatal"); return true; }
/** * Called when a full chunk (i.e. a piece message) has been received by PeerConnectionIn. * * <p>This may block quite a while if it is the last chunk for a piece, as it calls the listener, * who stores the piece and then calls havePiece for every peer on the torrent (including us). */ void pieceMessage(Request req) { int size = req.len; peer.downloaded(size); listener.downloaded(peer, size); if (_log.shouldLog(Log.DEBUG)) _log.debug( "got end of Chunk(" + req.getPiece() + "," + req.off + "," + req.len + ") from " + peer); // Last chunk needed for this piece? // FIXME if priority changed to skip, we will think we're done when we aren't if (getFirstOutstandingRequest(req.getPiece()) == -1) { // warning - may block here for a while if (listener.gotPiece(peer, req.getPartialPiece())) { if (_log.shouldLog(Log.DEBUG)) _log.debug("Got " + req.getPiece() + ": " + peer); } else { if (_log.shouldLog(Log.WARN)) _log.warn("Got BAD " + req.getPiece() + " from " + peer); } } // ok done with this one synchronized (this) { pendingRequest = null; } }
/** * Sets DataIn/OutputStreams, does the handshake and returns the id reported by the other side. */ private byte[] handshake(InputStream in, OutputStream out) throws IOException { din = new DataInputStream(in); dout = new DataOutputStream(out); // Handshake write - header dout.write(19); dout.write("BitTorrent protocol".getBytes("UTF-8")); // Handshake write - options long myOptions = OPTION_EXTENSION; // FIXME get util here somehow // if (util.getDHT() != null) // myOptions |= OPTION_I2P_DHT; dout.writeLong(myOptions); // Handshake write - metainfo hash dout.write(infohash); // Handshake write - peer id dout.write(my_id); dout.flush(); if (_log.shouldLog(Log.DEBUG)) _log.debug("Wrote my shared hash and ID to " + toString()); // Handshake read - header byte b = din.readByte(); if (b != 19) throw new IOException("Handshake failure, expected 19, got " + (b & 0xff) + " on " + sock); byte[] bs = new byte[19]; din.readFully(bs); String bittorrentProtocol = new String(bs, "UTF-8"); if (!"BitTorrent protocol".equals(bittorrentProtocol)) throw new IOException( "Handshake failure, expected " + "'Bittorrent protocol', got '" + bittorrentProtocol + "'"); // Handshake read - options options = din.readLong(); // Handshake read - metainfo hash bs = new byte[20]; din.readFully(bs); if (!Arrays.equals(infohash, bs)) throw new IOException("Unexpected MetaInfo hash"); // Handshake read - peer id din.readFully(bs); if (_log.shouldLog(Log.DEBUG)) _log.debug("Read the remote side's hash and peerID fully from " + toString()); if (DataHelper.eq(my_id, bs)) throw new IOException("Connected to myself"); if (options != 0) { // send them something in runConnection() above if (_log.shouldLog(Log.DEBUG)) _log.debug("Peer supports options 0x" + Long.toString(options, 16) + ": " + toString()); } return bs; }
public void debug(String msg, Object arg0, Object arg1) { if (arg0 == null && arg1 == null) { _log.debug(msg); } else if (arg0 != null && arg1 == null && arg0 instanceof Throwable) { _log.debug(msg, (Throwable) arg0); } else if (_log.shouldLog(Log.DEBUG)) { synchronized (_buffer) { format(msg, arg0, arg1); _log.debug(_buffer.toString()); } } }
/** * Blocking, may take a while, up to 20 seconds */ public synchronized void stop() { if (_log.shouldLog(Log.DEBUG)) _log.debug("UPnP Stop"); _shouldBeRunning = false; _rescanner.cancel(); if (_isRunning) _upnp.terminate(); _isRunning = false; _detectedAddress = null; if (_log.shouldLog(Log.DEBUG)) _log.debug("UPnP Stop Done"); }
/** * @param claimedAddress an IP/port based RemoteHostId, or null if unknown * @param remoteHostId non-null, == claimedAddress if direct, or a hash-based one if indirect * @param addr non-null */ public OutboundEstablishState( RouterContext ctx, RemoteHostId claimedAddress, RemoteHostId remoteHostId, RouterIdentity remotePeer, SessionKey introKey, UDPAddress addr, DHSessionKeyBuilder.Factory dh) { _context = ctx; _log = ctx.logManager().getLog(OutboundEstablishState.class); if (claimedAddress != null) { _bobIP = claimedAddress.getIP(); _bobPort = claimedAddress.getPort(); } else { // _bobIP = null; _bobPort = -1; } _claimedAddress = claimedAddress; _remoteHostId = remoteHostId; _remotePeer = remotePeer; _introKey = introKey; _queuedMessages = new LinkedBlockingQueue<OutNetMessage>(); _establishBegin = ctx.clock().now(); _remoteAddress = addr; _introductionNonce = -1; _keyFactory = dh; if (addr.getIntroducerCount() > 0) { if (_log.shouldLog(Log.DEBUG)) _log.debug( "new outbound establish to " + remotePeer.calculateHash() + ", with address: " + addr); _currentState = OutboundState.OB_STATE_PENDING_INTRO; } else { _currentState = OutboundState.OB_STATE_UNKNOWN; } }
synchronized void setChoking(boolean choke) { if (choking != choke) { if (_log.shouldLog(Log.DEBUG)) _log.debug(peer + " setChoking(" + choke + ")"); choking = choke; out.sendChoke(choke); } }
/** * @return lowest offset of any request for the piece * @since 0.8.2 */ private synchronized Request getLowestOutstandingRequest(int piece) { Request rv = null; int lowest = Integer.MAX_VALUE; for (Request r : outstandingRequests) { if (r.getPiece() == piece && r.off < lowest) { lowest = r.off; rv = r; } } if (pendingRequest != null && pendingRequest.getPiece() == piece && pendingRequest.off < lowest) rv = pendingRequest; if (_log.shouldLog(Log.DEBUG)) _log.debug( peer + " lowest for " + piece + " is " + rv + " out of " + pendingRequest + " and " + outstandingRequests); return rv; }
private void connectWithPeers() { if (_peerDestFiles != null) { for (int i = 0; i < _peerDestFiles.length; i++) { try { FileInputStream fin = new FileInputStream(_peerDestFiles[i]); byte dest[] = new byte[1024]; int read = DataHelper.read(fin, dest); String remDest = new String(dest, 0, read); int con = 0; Flooder flooder = null; synchronized (_remotePeers) { con = _remotePeers.size() + 1; flooder = new Flooder(con, remDest); _remotePeers.put(new Integer(con), flooder); } byte msg[] = (DataHelper.getUTF8("STREAM CONNECT ID=" + con + " DESTINATION=" + remDest + "\n")); synchronized (_samOut) { _samOut.write(msg); _samOut.flush(); } I2PThread flood = new I2PThread(flooder, "Flood " + con); flood.start(); _log.debug("Starting flooder with peer from " + _peerDestFiles[i] + ": " + con); } catch (IOException ioe) { _log.error("Unable to read the peer from " + _peerDestFiles[i]); } } } }
/** * This is the callback that PeerConnectionOut calls * * @return bytes or null for errors * @since 0.8.2 */ public ByteArray loadData(int piece, int begin, int length) { ByteArray pieceBytes = listener.gotRequest(peer, piece, begin, length); if (pieceBytes == null) { // XXX - Protocol error-> diconnect? if (_log.shouldLog(Log.WARN)) _log.warn("Got request for unknown piece: " + piece); return null; } // More sanity checks if (length != pieceBytes.getData().length) { // XXX - Protocol error-> disconnect? if (_log.shouldLog(Log.WARN)) _log.warn( "Got out of range 'request: " + piece + ", " + begin + ", " + length + "' message from " + peer); return null; } if (_log.shouldLog(Log.DEBUG)) _log.debug("Sending (" + piece + ", " + begin + ", " + length + ")" + " to " + peer); return pieceBytes; }
void bitfieldMessage(byte[] bitmap) { synchronized (this) { if (_log.shouldLog(Log.DEBUG)) _log.debug(peer + " rcv bitfield"); if (bitfield != null) { // XXX - Be liberal in what you accept? if (_log.shouldLog(Log.WARN)) _log.warn("Got unexpected bitfield message from " + peer); return; } // XXX - Check for weird bitfield and disconnect? // FIXME will have to regenerate the bitfield after we know exactly // how many pieces there are, as we don't know how many spare bits there are. if (metainfo == null) bitfield = new BitField(bitmap, bitmap.length * 8); else bitfield = new BitField(bitmap, metainfo.getPieces()); } if (metainfo == null) return; boolean interest = listener.gotBitField(peer, bitfield); setInteresting(interest); if (bitfield.complete() && !interest) { // They are seeding and we are seeding, // why did they contact us? (robert) // Dump them quick before we send our whole bitmap if (_log.shouldLog(Log.WARN)) _log.warn("Disconnecting seed that connects to seeds: " + peer); peer.disconnect(true); } }
/** * Distribute the message. If the dest is local, it blocks until its passed to the target * ClientConnectionRunner (which then fires it into a MessageReceivedJob). If the dest is remote, * it blocks until it is added into the ClientMessagePool */ MessageId distributeMessage(SendMessageMessage message) { Payload payload = message.getPayload(); Destination dest = message.getDestination(); MessageId id = new MessageId(); id.setMessageId(getNextMessageId()); long expiration = 0; int flags = 0; if (message.getType() == SendMessageExpiresMessage.MESSAGE_TYPE) { SendMessageExpiresMessage msg = (SendMessageExpiresMessage) message; expiration = msg.getExpirationTime(); flags = msg.getFlags(); } if (message.getNonce() != 0 && !_dontSendMSM) _acceptedPending.add(id); if (_log.shouldLog(Log.DEBUG)) _log.debug( "** Receiving message " + id.getMessageId() + " with payload of size " + payload.getSize() + " for session " + _sessionId.getSessionId()); // long beforeDistribute = _context.clock().now(); // the following blocks as described above SessionConfig cfg = _config; if (cfg != null) _manager.distributeMessage(cfg.getDestination(), dest, payload, id, expiration, flags); // else log error? // long timeToDistribute = _context.clock().now() - beforeDistribute; // if (_log.shouldLog(Log.DEBUG)) // _log.warn("Time to distribute in the manager to " // + dest.calculateHash().toBase64() + ": " // + timeToDistribute); return id; }
/** * Can't find a published standard for this anywhere. See the libtorrent code. Here we use the * "added" key as a single string of concatenated 32-byte peer hashes. added.f and dropped * unsupported * * @since 0.8.4 */ private static void handlePEX(Peer peer, PeerListener listener, byte[] bs, Log log) { if (log.shouldLog(Log.DEBUG)) log.debug("Got PEX msg from " + peer); try { InputStream is = new ByteArrayInputStream(bs); BDecoder dec = new BDecoder(is); BEValue bev = dec.bdecodeMap(); Map<String, BEValue> map = bev.getMap(); bev = map.get("added"); if (bev == null) return; byte[] ids = bev.getBytes(); if (ids.length < HASH_LENGTH) return; int len = Math.min(ids.length, (I2PSnarkUtil.MAX_CONNECTIONS - 1) * HASH_LENGTH); List<PeerID> peers = new ArrayList<PeerID>(len / HASH_LENGTH); for (int off = 0; off < len; off += HASH_LENGTH) { byte[] hash = new byte[HASH_LENGTH]; System.arraycopy(ids, off, hash, 0, HASH_LENGTH); if (DataHelper.eq(hash, peer.getPeerID().getDestHash())) continue; PeerID pID = new PeerID(hash, listener.getUtil()); peers.add(pID); } // could include ourselves, listener must remove listener.gotPeers(peer, peers); } catch (Exception e) { if (log.shouldLog(Log.INFO)) log.info("PEX msg exception from " + peer, e); // peer.disconnect(false); } }
/** * There is no more data coming from the I2P side. Does NOT clear pending data. messageReceived() * MUST have been called previously with the messageId of the CLOSE packet. */ public void closeReceived() { synchronized (_dataLock) { if (_log.shouldLog(Log.DEBUG)) { StringBuilder buf = new StringBuilder(128); buf.append("Close received, ready bytes: "); long available = 0; for (int i = 0; i < _readyDataBlocks.size(); i++) available += _readyDataBlocks.get(i).getValid(); available -= _readyDataBlockIndex; buf.append(available); buf.append(" blocks: ").append(_readyDataBlocks.size()); buf.append(" not ready blocks: "); long notAvailable = 0; for (Long id : _notYetReadyBlocks.keySet()) { ByteArray ba = _notYetReadyBlocks.get(id); buf.append(id).append(" "); if (ba != null) notAvailable += ba.getValid(); } buf.append("not ready bytes: ").append(notAvailable); buf.append(" highest ready block: ").append(_highestReadyBlockId); _log.debug(buf.toString(), new Exception("closed")); } _closeReceived = true; _dataLock.notifyAll(); } }
public void run() { String header = null; String nick; String dest; String version; try { header = DataHelper.readLine(is).trim(); StringTokenizer tok = new StringTokenizer(header, " "); if (tok.countTokens() != 3) { // This is not a correct message, for sure _log.debug("Error in message format"); return; } version = tok.nextToken(); if (!"3.0".equals(version)) return; nick = tok.nextToken(); dest = tok.nextToken(); byte[] data = new byte[is.available()]; is.read(data); SessionRecord rec = sSessionsHash.get(nick); if (rec != null) { rec.getHandler().session.sendBytes(dest, data); } } catch (Exception e) { } }
/** * Send the specified reply during SOCKS5 authorization * * @since 0.8.2 */ private void sendAuthReply(int replyCode, DataOutputStream out) throws IOException { byte[] reply = new byte[2]; reply[0] = AUTH_VERSION; reply[1] = (byte) replyCode; if (_log.shouldLog(Log.DEBUG)) _log.debug("Sending auth reply:\n" + HexDump.dump(reply)); out.write(reply); }
/** * Constructs a new <code>TrustedUpdate</code> with the given {@link net.i2p.I2PAppContext}. * * @param context An instance of <code>I2PAppContext</code>. */ public TrustedUpdate(I2PAppContext context) { _context = context; _log = _context.logManager().getLog(TrustedUpdate.class); _trustedKeys = new HashMap(4); String propertyTrustedKeys = context.getProperty(PROP_TRUSTED_KEYS); if ((propertyTrustedKeys != null) && (propertyTrustedKeys.length() > 0)) { StringTokenizer propertyTrustedKeysTokens = new StringTokenizer(propertyTrustedKeys, " ,\r\n"); while (propertyTrustedKeysTokens.hasMoreTokens()) { // If a key from the defaults, use the same name String key = propertyTrustedKeysTokens.nextToken().trim(); String name = DEFAULT_KEYS.get(key); if (name == null) name = ""; addKey(key, name); } } else { for (Map.Entry<String, String> e : DEFAULT_KEYS.entrySet()) { addKey(e.getKey(), e.getValue()); } } if (_log.shouldLog(Log.DEBUG)) _log.debug("TrustedUpdate created, trusting " + _trustedKeys.size() + " keys."); }
public void load(Properties props) { _successfulLookups = getLong(props, "dbHistory.successfulLookups"); _failedLookups = getLong(props, "dbHistory.failedLookups"); _lookupsReceived = getLong(props, "dbHistory.lookupsReceived"); _lookupReplyDuplicate = getLong(props, "dbHistory.lookupReplyDuplicate"); _lookupReplyInvalid = getLong(props, "dbHistory.lookupReplyInvalid"); _lookupReplyNew = getLong(props, "dbHistory.lookupReplyNew"); _lookupReplyOld = getLong(props, "dbHistory.lookupReplyOld"); _unpromptedDbStoreNew = getLong(props, "dbHistory.unpromptedDbStoreNew"); _unpromptedDbStoreOld = getLong(props, "dbHistory.unpromptedDbStoreOld"); _lastLookupReceived = getLong(props, "dbHistory.lastLookupReceived"); _avgDelayBetweenLookupsReceived = getLong(props, "dbHistory.avgDelayBetweenLookupsReceived"); try { _failedLookupRate.load(props, "dbHistory.failedLookupRate", true); _log.debug("Loading dbHistory.failedLookupRate"); } catch (IllegalArgumentException iae) { _log.warn("DB History failed lookup rate is corrupt, resetting", iae); } try { _invalidReplyRate.load(props, "dbHistory.invalidReplyRate", true); } catch (IllegalArgumentException iae) { _log.warn("DB History invalid reply rate is corrupt, resetting", iae); createRates(_statGroup); } }
/** * Blocking call (run in the establisher thread) to determine if the session was created properly. * If it wasn't, all the SessionCreated remnants are dropped (perhaps they were spoofed, etc) so * that we can receive another one * * <p>Generates session key and mac key. * * @return true if valid */ public synchronized boolean validateSessionCreated() { if (_currentState == OutboundState.OB_STATE_VALIDATION_FAILED) { if (_log.shouldLog(Log.WARN)) _log.warn("Session created already failed"); return false; } if (_receivedSignature != null) { if (_log.shouldLog(Log.WARN)) _log.warn("Session created already validated"); return true; } boolean valid = true; try { generateSessionKey(); } catch (DHSessionKeyBuilder.InvalidPublicParameterException ippe) { if (_log.shouldLog(Log.WARN)) _log.warn("Peer " + getRemoteHostId() + " sent us an invalid DH parameter", ippe); valid = false; } if (valid) decryptSignature(); if (valid && verifySessionCreated()) { if (_log.shouldLog(Log.DEBUG)) _log.debug("Session created passed validation"); return true; } else { if (_log.shouldLog(Log.WARN)) _log.warn( "Session created failed validation, clearing state for " + _remoteHostId.toString()); fail(); return false; } }
/** * Returns <code>true</code> if one or more client threads are running in a given plugin. * * @param pluginName * @return true if running */ private static boolean isClientThreadRunning(String pluginName, RouterContext ctx) { ThreadGroup group = pluginThreadGroups.get(pluginName); if (group == null) return false; boolean rv = group.activeCount() > 0; // Plugins start before the eepsite, and will create the static Timer thread // in RolloverFileOutputStream, which never stops. Don't count it. if (rv) { Log log = ctx.logManager().getLog(PluginStarter.class); Thread[] activeThreads = new Thread[128]; int count = group.enumerate(activeThreads); boolean notRollover = false; for (int i = 0; i < count; i++) { if (activeThreads[i] != null) { String name = activeThreads[i].getName(); if (!"org.eclipse.jetty.util.RolloverFileOutputStream".equals(name)) notRollover = true; if (log.shouldLog(Log.DEBUG)) log.debug( "Found " + activeThreads[i].getState() + " thread for " + pluginName + ": " + name); } } rv = notRollover; } return rv; }
public long receiveEncrypted(byte encrypted[]) { TunnelDataMessage msg = new TunnelDataMessage(_context); msg.setData(encrypted); msg.setTunnelId(_config.getConfig(0).getSendTunnel()); if (_log.shouldLog(Log.DEBUG)) _log.debug("received encrypted, sending out " + _config + ": " + msg); RouterInfo ri = _nextHopCache; if (ri == null) ri = _context.netDb().lookupRouterInfoLocally(_config.getPeer(1)); if (ri != null) { _nextHopCache = ri; send(msg, ri); return msg.getUniqueId(); } else { // It should be rare to forget the router info for a peer in our own tunnel. if (_log.shouldLog(Log.WARN)) _log.warn("lookup of " + _config.getPeer(1) + " required for " + msg); _context .netDb() .lookupRouterInfo( _config.getPeer(1), new SendJob(_context, msg), new FailedJob(_context), MAX_LOOKUP_TIME); return -1; } }
/** Create a new search for the routingKey specified */ public SearchJob( RouterContext context, KademliaNetworkDatabaseFacade facade, Hash key, Job onSuccess, Job onFailure, long timeoutMs, boolean keepStats, boolean isLease) { super(context); if ((key == null) || (key.getData() == null)) throw new IllegalArgumentException("Search for null key? wtf"); _log = getContext().logManager().getLog(getClass()); _facade = facade; _state = new SearchState(getContext(), key); _onSuccess = onSuccess; _onFailure = onFailure; _timeoutMs = timeoutMs; _keepStats = keepStats; _isLease = isLease; _deferredSearches = new ArrayList(0); _peerSelector = facade.getPeerSelector(); _startedOn = -1; _expiration = getContext().clock().now() + timeoutMs; getContext().statManager().addRateData("netDb.searchCount", 1, 0); if (_log.shouldLog(Log.DEBUG)) _log.debug( "Search (" + getClass().getName() + " for " + key.toBase64(), new Exception("Search enqueued by")); }
/** Search totally failed */ protected void fail() { if (isLocal()) { if (_log.shouldLog(Log.ERROR)) _log.error( getJobId() + ": why did we fail if the target is local?: " + _state.getTarget().toBase64(), new Exception("failure cause")); succeed(); return; } if (_log.shouldLog(Log.INFO)) _log.info(getJobId() + ": Failed search for key " + _state.getTarget()); if (_log.shouldLog(Log.DEBUG)) _log.debug(getJobId() + ": State of failed search: " + _state); long time = getContext().clock().now() - _state.getWhenStarted(); int attempted = _state.getAttempted().size(); getContext().statManager().addRateData("netDb.failedAttemptedPeers", attempted, time); if (_keepStats) { getContext().statManager().addRateData("netDb.failedTime", time, 0); // _facade.fail(_state.getTarget()); } if (_onFailure != null) getContext().jobQueue().addJob(_onFailure); _facade.searchComplete(_state.getTarget()); handleDeferred(false); }
/** Search was totally successful */ private void succeed() { if (_log.shouldLog(Log.INFO)) _log.info( getJobId() + ": Succeeded search for key " + _state.getTarget() + " after querying " + _state.getAttempted().size()); if (_log.shouldLog(Log.DEBUG)) _log.debug(getJobId() + ": State of successful search: " + _state); if (_keepStats) { long time = getContext().clock().now() - _state.getWhenStarted(); getContext().statManager().addRateData("netDb.successTime", time, 0); getContext() .statManager() .addRateData("netDb.successPeers", _state.getAttempted().size(), time); } if (_onSuccess != null) getContext().jobQueue().addJob(_onSuccess); _facade.searchComplete(_state.getTarget()); handleDeferred(true); resend(); }
/** * Set of Hash structures for routers we want to check next. This is the 'interesting' part of the * algorithm. But to keep you on your toes, we've refactored it to the * PeerSelector.selectNearestExplicit * * @return ordered list of Hash objects */ private List getClosestRouters(Hash key, int numClosest, Set alreadyChecked) { Hash rkey = getContext().routingKeyGenerator().getRoutingKey(key); if (_log.shouldLog(Log.DEBUG)) _log.debug(getJobId() + ": Current routing key for " + key + ": " + rkey); return _peerSelector.selectNearestExplicit( rkey, numClosest, alreadyChecked, _facade.getKBuckets()); }
/** * Add the page to the free list. The file is never shrunk. TODO: Reclaim free pages at end of * file, or even do a full compaction. Does not throw exceptions; logs on failure. */ public void freePage(int page) { if (page <= METAINDEX_PAGE) { log.error("Bad page free attempt: " + page); return; } try { if (freeListStart == 0) { freeListStart = page; FreeListBlock.initPage(file, page); writeSuperBlock(); if (log.shouldLog(Log.DEBUG)) log.debug("Freed page " + page + " as new FLB"); return; } try { if (flb == null) flb = new FreeListBlock(file, freeListStart); if (flb.isFull()) { // Make the free page a new FLB if (log.shouldLog(Log.DEBUG)) log.debug("Full: " + flb); FreeListBlock.initPage(file, page); if (flb.getNextPage() == 0) { // Put it at the tail. // Next free will make a new FLB at the head, // so we have one more FLB than we need. flb.setNextPage(page); } else { // Put it at the head flb = new FreeListBlock(file, page); flb.setNextPage(freeListStart); freeListStart = page; writeSuperBlock(); } if (log.shouldLog(Log.DEBUG)) log.debug("Freed page " + page + " to full " + flb); return; } flb.addPage(page); if (log.shouldLog(Log.DEBUG)) log.debug("Freed page " + page + " to " + flb); } catch (IOException ioe) { log.error("Discarding corrupt free list block page " + freeListStart, ioe); freeListStart = page; FreeListBlock.initPage(file, page); writeSuperBlock(); flb = null; } } catch (IOException ioe) { log.error("Error freeing page: " + page, ioe); } }