/** Handle an incoming FNPDataRequest. */ private boolean handleDataRequest(Message m, PeerNode source, boolean isSSK) { long id = m.getLong(DMT.UID); ByteCounter ctr = isSSK ? node.nodeStats.sskRequestCtr : node.nodeStats.chkRequestCtr; if (node.recentlyCompleted(id)) { Message rejected = DMT.createFNPRejectedLoop(id); try { source.sendAsync(rejected, null, ctr); } catch (NotConnectedException e) { Logger.normal(this, "Rejecting data request (loop, finished): " + e); } return true; } short htl = m.getShort(DMT.HTL); Key key = (Key) m.getObject(DMT.FREENET_ROUTING_KEY); final RequestTag tag = new RequestTag(isSSK, RequestTag.START.REMOTE); if (!node.lockUID(id, isSSK, false, false, false, tag)) { if (logMINOR) Logger.minor(this, "Could not lock ID " + id + " -> rejecting (already running)"); Message rejected = DMT.createFNPRejectedLoop(id); try { source.sendAsync(rejected, null, ctr); } catch (NotConnectedException e) { Logger.normal(this, "Rejecting request from " + source.getPeer() + ": " + e); } node.failureTable.onFinalFailure(key, null, htl, htl, -1, source); return true; } else { if (logMINOR) Logger.minor(this, "Locked " + id); } // There are at least 2 threads that call this function. // DO NOT reuse the meta object, unless on a per-thread basis. // Object allocation is pretty cheap in modern Java anyway... // If we do reuse it, call reset(). BlockMetadata meta = new BlockMetadata(); KeyBlock block = node.fetch(key, false, false, false, false, meta); String rejectReason = nodeStats.shouldRejectRequest( !isSSK, false, isSSK, false, false, source, block != null && !meta.isOldBlock()); if (rejectReason != null) { // can accept 1 CHK request every so often, but not with SSKs because they aren't throttled so // won't sort out bwlimitDelayTime, which was the whole reason for accepting them when // overloaded... Logger.normal( this, "Rejecting " + (isSSK ? "SSK" : "CHK") + " request from " + source.getPeer() + " preemptively because " + rejectReason); Message rejected = DMT.createFNPRejectedOverload(id, true); try { source.sendAsync(rejected, null, ctr); } catch (NotConnectedException e) { Logger.normal( this, "Rejecting (overload) data request from " + source.getPeer() + ": " + e); } tag.setRejected(); node.unlockUID(id, isSSK, false, false, false, false, tag); // Do not tell failure table. // Otherwise an attacker can flood us with requests very cheaply and purge our // failure table even though we didn't accept any of them. return true; } nodeStats.reportIncomingRequestLocation(key.toNormalizedDouble()); // if(!node.lockUID(id)) return false; RequestHandler rh = new RequestHandler(m, source, id, node, htl, key, tag, block); node.executor.execute( rh, "RequestHandler for UID " + id + " on " + node.getDarknetPortNumber()); return true; }