private boolean handleGetOfferedKey(Message m, PeerNode source) { Key key = (Key) m.getObject(DMT.KEY); byte[] authenticator = ((ShortBuffer) m.getObject(DMT.OFFER_AUTHENTICATOR)).getData(); long uid = m.getLong(DMT.UID); if (!HMAC.verifyWithSHA256( node.failureTable.offerAuthenticatorKey, key.getFullKey(), authenticator)) { Logger.error( this, "Invalid offer request from " + source + " : authenticator did not verify"); try { source.sendAsync( DMT.createFNPGetOfferedKeyInvalid(uid, DMT.GET_OFFERED_KEY_REJECTED_BAD_AUTHENTICATOR), null, node.failureTable.senderCounter); } catch (NotConnectedException e) { // Too bad. } return true; } if (logMINOR) Logger.minor(this, "Valid GetOfferedKey for " + key + " from " + source); // Do we want it? We can RejectOverload if we don't have the bandwidth... boolean isSSK = key instanceof NodeSSK; OfferReplyTag tag = new OfferReplyTag(isSSK); node.lockUID(uid, isSSK, false, true, false, tag); boolean needPubKey; try { needPubKey = m.getBoolean(DMT.NEED_PUB_KEY); String reject = nodeStats.shouldRejectRequest(true, false, isSSK, false, true, source, false); if (reject != null) { Logger.normal( this, "Rejecting FNPGetOfferedKey from " + source + " for " + key + " : " + reject); Message rejected = DMT.createFNPRejectedOverload(uid, true); try { source.sendAsync(rejected, null, node.failureTable.senderCounter); } catch (NotConnectedException e) { Logger.normal( this, "Rejecting (overload) data request from " + source.getPeer() + ": " + e); } node.unlockUID(uid, isSSK, false, false, true, false, tag); return true; } } catch (Error e) { node.unlockUID(uid, isSSK, false, false, true, false, tag); throw e; } catch (RuntimeException e) { node.unlockUID(uid, isSSK, false, false, true, false, tag); throw e; } // Otherwise, sendOfferedKey is responsible for unlocking. // Accept it. try { node.failureTable.sendOfferedKey(key, isSSK, needPubKey, uid, source, tag); } catch (NotConnectedException e) { // Too bad. } return true; }
public void onReceivedRejectOverload( double nearest, double best, short counter, short uniqueCounter, short linearCounter, String reason) throws NotConnectedException { Message ro = DMT.createFNPRejectedOverload(uid, false, false, false); Message sub = DMT.createFNPRHReturnSubMessage( nearest, best, counter, uniqueCounter, linearCounter, reason); ro.addSubMessage(sub); source.sendAsync(ro, null, sender); }
public void onRNF( short htl, double nearest, double best, short counter, short uniqueCounter, short linearCounter) throws NotConnectedException { Message rnf = DMT.createFNPRouteNotFound(uid, htl); Message sub = DMT.createFNPRHReturnSubMessage( nearest, best, counter, uniqueCounter, linearCounter, "rnf"); rnf.addSubMessage(sub); source.sendAsync(rnf, null, sender); }
/** Handle an FNPRoutedRejected message. */ private boolean handleRoutedRejected(Message m) { long id = m.getLong(DMT.UID); Long lid = Long.valueOf(id); RoutedContext rc = routedContexts.get(lid); if (rc == null) { // Gah Logger.error(this, "Unrecognized FNPRoutedRejected"); return false; // locally originated?? } short htl = rc.lastHtl; if (rc.source != null) htl = rc.source.decrementHTL(htl); short ohtl = m.getShort(DMT.HTL); if (ohtl < htl) htl = ohtl; if (htl == 0) { // Equivalent to DNF. // Relay. if (rc.source != null) { try { rc.source.sendAsync( DMT.createFNPRoutedRejected(id, (short) 0), null, nodeStats.routedMessageCtr); } catch (NotConnectedException e) { // Ouch. Logger.error(this, "Unable to relay probe DNF: peer disconnected: " + rc.source); } } } else { // Try routing to the next node forward(rc.msg, id, rc.source, htl, rc.msg.getDouble(DMT.TARGET_LOCATION), rc, rc.identity); } return true; }
public void onTrace( long uid, double nearest, double best, short htl, short counter, short uniqueCounter, double location, long myUID, ShortBuffer peerLocs, ShortBuffer peerUIDs, short forkCount, short linearCounter, String reason, long prevUID) throws NotConnectedException { Message trace = DMT.createFNPRHProbeTrace( uid, nearest, best, htl, counter, uniqueCounter, location, myUID, peerLocs, peerUIDs, forkCount, linearCounter, reason, prevUID); source.sendAsync(trace, null, sender); }
/** * Handle a routed-to-a-specific-node message. * * @param m * @return False if we want the message put back on the queue. */ boolean handleRouted(Message m, PeerNode source) { if (logMINOR) Logger.minor(this, "handleRouted(" + m + ')'); long id = m.getLong(DMT.UID); Long lid = Long.valueOf(id); short htl = m.getShort(DMT.HTL); byte[] identity = ((ShortBuffer) m.getObject(DMT.NODE_IDENTITY)).getData(); if (source != null) htl = source.decrementHTL(htl); RoutedContext ctx; ctx = routedContexts.get(lid); if (ctx != null) { try { source.sendAsync(DMT.createFNPRoutedRejected(id, htl), null, nodeStats.routedMessageCtr); } catch (NotConnectedException e) { if (logMINOR) Logger.minor(this, "Lost connection rejecting " + m); } return true; } ctx = new RoutedContext(m, source, identity); synchronized (routedContexts) { routedContexts.put(lid, ctx); } // source == null => originated locally, keep full htl double target = m.getDouble(DMT.TARGET_LOCATION); if (logMINOR) Logger.minor(this, "id " + id + " from " + source + " htl " + htl + " target " + target); if (Math.abs(node.lm.getLocation() - target) <= Double.MIN_VALUE) { if (logMINOR) Logger.minor(this, "Dispatching " + m.getSpec() + " on " + node.getDarknetPortNumber()); // Handle locally // Message type specific processing dispatchRoutedMessage(m, source, id); return true; } else if (htl == 0) { Message reject = DMT.createFNPRoutedRejected(id, (short) 0); if (source != null) try { source.sendAsync(reject, null, nodeStats.routedMessageCtr); } catch (NotConnectedException e) { if (logMINOR) Logger.minor(this, "Lost connection rejecting " + m); } return true; } else { return forward(m, id, source, htl, target, ctx, identity); } }
public void onCompletion( double nearest, double best, short counter, short uniqueCounter, short linearCounter) throws NotConnectedException { source.sendAsync( DMT.createFNPRHProbeReply(uid, nearest, best, counter, uniqueCounter, linearCounter), null, sender); }
private boolean handleAnnounceRequest(Message m, PeerNode source) { long uid = m.getLong(DMT.UID); OpennetManager om = node.getOpennet(); if (om == null || !source.canAcceptAnnouncements()) { Message msg = DMT.createFNPOpennetDisabled(uid); try { source.sendAsync(msg, null, node.nodeStats.announceByteCounter); } catch (NotConnectedException e) { // Ok } return true; } if (node.recentlyCompleted(uid)) { Message msg = DMT.createFNPRejectedLoop(uid); try { source.sendAsync(msg, null, node.nodeStats.announceByteCounter); } catch (NotConnectedException e) { // Ok } return true; } boolean success = false; // No way to check whether it's actually running atm, so lets report it to the completed list // immediately. // FIXME we should probably keep a list! node.completed(uid); try { if (!source.shouldAcceptAnnounce(uid)) { Message msg = DMT.createFNPRejectedOverload(uid, true); try { source.sendAsync(msg, null, node.nodeStats.announceByteCounter); } catch (NotConnectedException e) { // Ok } return true; } AnnounceSender sender = new AnnounceSender(m, uid, source, om, node); node.executor.execute(sender, "Announcement sender for " + uid); success = true; return true; } finally { if (!success) source.completedAnnounce(uid); } }
public void onAborted() { synchronized (this) { if (sentCancel) return; sentCancel = true; } try { peer.sendAsync(DMT.createFNPBulkReceiveAborted(uid), null, ctr); } catch (NotConnectedException e) { // Cool } }
private boolean handleProbeRequest(Message m, PeerNode source) { long id = m.getLong(DMT.UID); if (node.recentlyCompleted(id)) { Message rejected = DMT.createFNPRejectedLoop(id); try { source.sendAsync(rejected, null, node.nodeStats.probeRequestCtr); } catch (NotConnectedException e) { Logger.normal(this, "Rejecting probe request from " + source.getPeer() + ": " + e); } return true; } // Lets not bother with full lockUID, just add it to the recently completed list. node.completed(id); // SSKs don't fix bwlimitDelayTime so shouldn't be accepted when overloaded. if (source.shouldRejectProbeRequest()) { Logger.normal(this, "Rejecting probe request from " + source.getPeer()); Message rejected = DMT.createFNPRejectedOverload(id, true); try { source.sendAsync(rejected, null, node.nodeStats.probeRequestCtr); } catch (NotConnectedException e) { Logger.normal( this, "Rejecting (overload) insert request from " + source.getPeer() + ": " + e); } return true; } double target = m.getDouble(DMT.TARGET_LOCATION); if (target > 1.0 || target < 0.0) { Logger.normal( this, "Rejecting invalid (target=" + target + ") probe request from " + source.getPeer()); Message rejected = DMT.createFNPRejectedOverload(id, true); try { source.sendAsync(rejected, null, node.nodeStats.probeRequestCtr); } catch (NotConnectedException e) { Logger.normal( this, "Rejecting (invalid) insert request from " + source.getPeer() + ": " + e); } return true; } ProbeRequestHandler.start(m, source, node, target); return true; }
private boolean forward( Message m, long id, PeerNode pn, short htl, double target, RoutedContext ctx, byte[] targetIdentity) { if (logMINOR) Logger.minor(this, "Should forward"); // Forward m = preForward(m, htl); while (true) { PeerNode next = node.peers.getByIdentity(targetIdentity); if (next != null && !next.isConnected()) { Logger.error(this, "Found target but disconnected!: " + next); next = null; } if (next == null) next = node.peers.closerPeer( pn, ctx.routedTo, target, true, node.isAdvancedModeEnabled(), -1, null, null, htl); if (logMINOR) Logger.minor(this, "Next: " + next + " message: " + m); if (next != null) { // next is connected, or at least has been => next.getPeer() CANNOT be null. if (logMINOR) Logger.minor(this, "Forwarding " + m.getSpec() + " to " + next.getPeer().getPort()); ctx.addSent(next); try { next.sendAsync(m, null, nodeStats.routedMessageCtr); } catch (NotConnectedException e) { continue; } } else { if (logMINOR) Logger.minor( this, "Reached dead end for " + m.getSpec() + " on " + node.getDarknetPortNumber()); // Reached a dead end... Message reject = DMT.createFNPRoutedRejected(id, htl); if (pn != null) try { pn.sendAsync(reject, null, nodeStats.routedMessageCtr); } catch (NotConnectedException e) { Logger.error(this, "Cannot send reject message back to source " + pn); return true; } } return true; } }
static void start(Message m, PeerNode source, Node n, double target) { long uid = m.getLong(DMT.UID); double nearestLoc = m.getDouble(DMT.NEAREST_LOCATION); double best = m.getDouble(DMT.BEST_LOCATION); short htl = m.getShort(DMT.HTL); ProbeRequestSender sender = new ProbeRequestSender(target, htl, uid, n, nearestLoc, source, best); ProbeRequestHandler handler = new ProbeRequestHandler(source, uid, sender); sender.addListener(handler); PeerNode[] peers = n.peers.connectedPeers; Message accepted = DMT.createFNPAccepted(uid); Message trace = DMT.createFNPRHProbeTrace( uid, sender.getNearestLoc(), sender.getBest(), htl, (short) 1, (short) 1, n.getLocation(), n.swapIdentifier, LocationManager.extractLocs(peers, true), LocationManager.extractUIDs(peers), (short) 0, (short) 1, "", source.swapIdentifier); try { source.sendAsync(accepted, null, sender); source.sendAsync(trace, null, sender); } catch (NotConnectedException e) { // We completed(id), rather than locking it, so we don't need to unlock. return; // So all we need to do is not start the sender. } sender.start(); }
/** * Receive the file. * * @return True if the whole file was received, false otherwise. */ public boolean receive() { while (true) { MessageFilter mfSendKilled = MessageFilter.create() .setSource(peer) .setType(DMT.FNPBulkSendAborted) .setField(DMT.UID, uid) .setTimeout(TIMEOUT); MessageFilter mfPacket = MessageFilter.create() .setSource(peer) .setType(DMT.FNPBulkPacketSend) .setField(DMT.UID, uid) .setTimeout(TIMEOUT); if (prb.hasWholeFile()) { try { peer.sendAsync(DMT.createFNPBulkReceivedAll(uid), null, ctr); } catch (NotConnectedException e) { // Ignore, we have the data. } return true; } Message m; try { m = prb.usm.waitFor(mfSendKilled.or(mfPacket), ctr); } catch (DisconnectedException e) { prb.abort(RetrievalException.SENDER_DISCONNECTED, "Sender disconnected"); return false; } if (peer.getBootID() != peerBootID) { prb.abort(RetrievalException.SENDER_DIED, "Sender restarted"); return false; } if (m == null) { prb.abort(RetrievalException.TIMED_OUT, "Sender timeout"); return false; } if (m.getSpec() == DMT.FNPBulkSendAborted) { prb.abort(RetrievalException.SENDER_DIED, "Sender cancelled send"); return false; } if (m.getSpec() == DMT.FNPBulkPacketSend) { int packetNo = m.getInt(DMT.PACKET_NO); byte[] data = ((ShortBuffer) m.getObject(DMT.DATA)).getData(); prb.received(packetNo, data, 0, data.length); } } }
/** * Deal with a routed-to-node message that landed on this node. This is where * message-type-specific code executes. * * @param m * @return */ private boolean dispatchRoutedMessage(Message m, PeerNode src, long id) { if (m.getSpec() == DMT.FNPRoutedPing) { if (logMINOR) Logger.minor(this, "RoutedPing reached other side! (" + id + ")"); int x = m.getInt(DMT.COUNTER); Message reply = DMT.createFNPRoutedPong(id, x); if (logMINOR) Logger.minor(this, "Replying - counter = " + x + " for " + id); try { src.sendAsync(reply, null, nodeStats.routedMessageCtr); } catch (NotConnectedException e) { if (logMINOR) Logger.minor(this, "Lost connection replying to " + m + " in dispatchRoutedMessage"); } return true; } return false; }
public static void main(String[] args) throws FSParseException, PeerParseException, InvalidThresholdException, NodeInitException, ReferenceSignatureVerificationException { // Logger.setupStdoutLogging(LogLevel.NORMAL, // "freenet.node.CPUAdjustingSwapRequestInterval:minor" // /*"freenet.node.LocationManager:debug,freenet.node.FNPPacketManager:normal,freenet.io.comm.MessageCore:debug"*/); System.out.println("SecretPing (CRAM) test using real nodes:"); System.out.println(); String wd = "realNodeSecretPingTest"; new File(wd).mkdir(); // NOTE: globalTestInit returns in ignored random source NodeStarter.globalTestInit( wd, false, LogLevel.ERROR, "freenet.node.Location:normal,freenet.node.simulator.RealNodeSecretPingTest:normal,freenet.node.NetworkIDManager:normal", true); DummyRandomSource random = new DummyRandomSource(); // DiffieHellman.init(random); Node[] nodes = new Node[NUMBER_OF_NODES]; Logger.normal(RealNodeRoutingTest.class, "Creating nodes..."); Executor executor = new PooledExecutor(); // Allow secret pings, but don't automatically send them (this is the test for them!) freenet.node.NetworkIDManager.disableSecretPings = false; freenet.node.NetworkIDManager.disableSecretPinger = true; for (int i = 0; i < NUMBER_OF_NODES; i++) { nodes[i] = NodeStarter.createTestNode( DARKNET_PORT_BASE + i, 0, wd, true, MAX_HTL, 0 /* no dropped packets */, random, executor, 500 * NUMBER_OF_NODES, storeSize, true, true, false, false, false, true, true, 0, true, false, true, false, null); Logger.normal(RealNodeRoutingTest.class, "Created node " + i); } Logger.normal(RealNodeRoutingTest.class, "Created " + NUMBER_OF_NODES + " nodes"); // Now link them up makeKleinbergNetwork(nodes); Logger.normal(RealNodeRoutingTest.class, "Added small-world links"); for (int i = 0; i < NUMBER_OF_NODES; i++) nodes[i].start(false); // Now sit back and watch the fireworks! int cycleNumber = 0; RunningAverage avg2 = new BootstrappingDecayingRunningAverage(0.0, 0.0, 1.0, 100, null); while (true) { cycleNumber++; try { Thread.sleep(2000); } catch (InterruptedException e) { // Ignore } Node source = nodes[random.nextInt(NUMBER_OF_NODES)]; PeerNode verify = source.peers.getRandomPeer(); PeerNode pathway = source.peers.getRandomPeer(verify); Logger.error( source, "verify (" + getPortNumber(verify) + ") through: " + getPortNumber(pathway) + "; so far " + avg2.currentValue()); long uid = random.nextLong(); long secret = random.nextLong(); if (verify == null) { Logger.error(source, "verify peernode is null"); continue; } if (pathway == null) { Logger.error(source, "pathway peernode is null"); continue; } try { // Send the FNPStoreSecret message to the 'verify' node verify.sendSync(DMT.createFNPStoreSecret(uid, secret), null, false); if (!getAck(source, verify, uid)) { Logger.error(source, "did not get storesecret ack for " + uid); avg2.report(0.0); continue; } // Send the request for the secret through the 'pathway' node. pathway.sendSync( DMT.createFNPSecretPing( uid, verify.getLocation(), PING_HTL, DAWN_HTL, 0, verify.getIdentity()), null, false); long result = getSecretPingResponse(source, pathway, uid); if (result != secret) { Logger.error(source, "not matched: " + secret + " != " + result); avg2.report(0.0); } else { Logger.error(source, "match: " + secret); avg2.report(1.0); } } catch (NotConnectedException e) { Logger.error(source, "what?", e); avg2.report(0.0); } catch (DisconnectedException e) { Logger.error(source, "huh?", e); avg2.report(0.0); } catch (SyncSendWaitedTooLongException e) { Logger.error(source, "eh?", e); avg2.report(0.0); } } }
public boolean handleMessage(Message m) { PeerNode source = (PeerNode) m.getSource(); if (source == null) { // Node has been disconnected and garbage collected already! Ouch. return true; } if (logMINOR) Logger.minor(this, "Dispatching " + m + " from " + source); if (callback != null) { try { callback.snoop(m, node); } catch (Throwable t) { Logger.error(this, "Callback threw " + t, t); } } MessageType spec = m.getSpec(); if (spec == DMT.FNPPing) { // Send an FNPPong Message reply = DMT.createFNPPong(m.getInt(DMT.PING_SEQNO)); try { source.sendAsync(reply, null, pingCounter); // nothing we can do if can't contact source } catch (NotConnectedException e) { if (logMINOR) Logger.minor(this, "Lost connection replying to " + m); } return true; } else if (spec == DMT.FNPStoreSecret) { return node.netid.handleStoreSecret(m); } else if (spec == DMT.FNPSecretPing) { return node.netid.handleSecretPing(m); } else if (spec == DMT.FNPDetectedIPAddress) { Peer p = (Peer) m.getObject(DMT.EXTERNAL_ADDRESS); source.setRemoteDetectedPeer(p); node.ipDetector.redetectAddress(); return true; } else if (spec == DMT.FNPTime) { return handleTime(m, source); } else if (spec == DMT.FNPUptime) { return handleUptime(m, source); } else if (spec == DMT.FNPSentPackets) { source.handleSentPackets(m); return true; } else if (spec == DMT.FNPVoid) { return true; } else if (spec == DMT.FNPDisconnect) { handleDisconnect(m, source); return true; } else if (spec == DMT.nodeToNodeMessage) { node.receivedNodeToNodeMessage(m, source); return true; } else if (spec == DMT.UOMAnnounce && source.isRealConnection()) { return node.nodeUpdater.uom.handleAnnounce(m, source); } else if (spec == DMT.UOMRequestRevocation && source.isRealConnection()) { return node.nodeUpdater.uom.handleRequestRevocation(m, source); } else if (spec == DMT.UOMSendingRevocation && source.isRealConnection()) { return node.nodeUpdater.uom.handleSendingRevocation(m, source); } else if (spec == DMT.UOMRequestMain && source.isRealConnection()) { return node.nodeUpdater.uom.handleRequestJar(m, source, false); } else if (spec == DMT.UOMRequestExtra && source.isRealConnection()) { return node.nodeUpdater.uom.handleRequestJar(m, source, true); } else if (spec == DMT.UOMSendingMain && source.isRealConnection()) { return node.nodeUpdater.uom.handleSendingMain(m, source); } else if (spec == DMT.UOMSendingExtra && source.isRealConnection()) { return node.nodeUpdater.uom.handleSendingExt(m, source); } else if (spec == DMT.FNPOpennetAnnounceRequest) { return handleAnnounceRequest(m, source); } else if (spec == DMT.FNPRoutingStatus) { if (source instanceof DarknetPeerNode) { boolean value = m.getBoolean(DMT.ROUTING_ENABLED); if (logMINOR) Logger.minor(this, "The peer (" + source + ") asked us to set routing=" + value); ((DarknetPeerNode) source).setRoutingStatus(value, false); } // We claim it in any case return true; } else if (source.isRealConnection() && spec == DMT.FNPLocChangeNotificationNew) { double newLoc = m.getDouble(DMT.LOCATION); ShortBuffer buffer = ((ShortBuffer) m.getObject(DMT.PEER_LOCATIONS)); double[] locs = Fields.bytesToDoubles(buffer.getData()); /** * Do *NOT* remove the sanity check below! * * @see http://archives.freenetproject.org/message/20080718.144240.359e16d3.en.html */ if ((OpennetManager.MAX_PEERS_FOR_SCALING < locs.length) && (source.isOpennet())) { if (locs.length > OpennetManager.PANIC_MAX_PEERS) { // This can't happen by accident Logger.error( this, "We received " + locs.length + " locations from " + source.toString() + "! That should *NOT* happen! Possible attack!"); source.forceDisconnect(true); return true; } else { // A few extra can happen by accident. Just use the first 20. Logger.normal( this, "Too many locations from " + source.toString() + " : " + locs.length + " could be an accident, using the first " + OpennetManager.MAX_PEERS_FOR_SCALING); double[] firstLocs = new double[OpennetManager.MAX_PEERS_FOR_SCALING]; System.arraycopy(locs, 0, firstLocs, 0, OpennetManager.MAX_PEERS_FOR_SCALING); locs = firstLocs; } } // We are on darknet and we trust our peers OR we are on opennet // and the amount of locations sent to us seems reasonable source.updateLocation(newLoc, locs); return true; } if (!source.isRoutable()) return false; if (logDEBUG) Logger.debug(this, "Not routable"); if (spec == DMT.FNPNetworkID) { source.handleFNPNetworkID(m); return true; } else if (spec == DMT.FNPSwapRequest) { return node.lm.handleSwapRequest(m, source); } else if (spec == DMT.FNPSwapReply) { return node.lm.handleSwapReply(m, source); } else if (spec == DMT.FNPSwapRejected) { return node.lm.handleSwapRejected(m, source); } else if (spec == DMT.FNPSwapCommit) { return node.lm.handleSwapCommit(m, source); } else if (spec == DMT.FNPSwapComplete) { return node.lm.handleSwapComplete(m, source); } else if (spec == DMT.FNPCHKDataRequest) { return handleDataRequest(m, source, false); } else if (spec == DMT.FNPSSKDataRequest) { return handleDataRequest(m, source, true); } else if (spec == DMT.FNPInsertRequest) { return handleInsertRequest(m, source, false); } else if (spec == DMT.FNPSSKInsertRequest) { return handleInsertRequest(m, source, true); } else if (spec == DMT.FNPSSKInsertRequestNew) { return handleInsertRequest(m, source, true); } else if (spec == DMT.FNPRHProbeRequest) { return handleProbeRequest(m, source); } else if (spec == DMT.FNPRoutedPing) { return handleRouted(m, source); } else if (spec == DMT.FNPRoutedPong) { return handleRoutedReply(m); } else if (spec == DMT.FNPRoutedRejected) { return handleRoutedRejected(m); // FIXME implement threaded probe requests of various kinds. // Old probe request code was a major pain, never really worked. // We should have threaded probe requests (for simple code), // and one for each routing strategy. // } else if(spec == DMT.FNPProbeRequest) { // return handleProbeRequest(m, source); // } else if(spec == DMT.FNPProbeReply) { // return handleProbeReply(m, source); // } else if(spec == DMT.FNPProbeRejected) { // return handleProbeRejected(m, source); // } else if(spec == DMT.FNPProbeTrace) { // return handleProbeTrace(m, source); } else if (spec == DMT.FNPOfferKey) { return handleOfferKey(m, source); } else if (spec == DMT.FNPGetOfferedKey) { return handleGetOfferedKey(m, source); } return false; }
/** 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; }
private boolean handleInsertRequest(Message m, PeerNode source, boolean isSSK) { ByteCounter ctr = isSSK ? node.nodeStats.sskInsertCtr : node.nodeStats.chkInsertCtr; long id = m.getLong(DMT.UID); if (node.recentlyCompleted(id)) { Message rejected = DMT.createFNPRejectedLoop(id); try { source.sendAsync(rejected, null, ctr); } catch (NotConnectedException e) { Logger.normal(this, "Rejecting insert request from " + source.getPeer() + ": " + e); } return true; } InsertTag tag = new InsertTag(isSSK, InsertTag.START.REMOTE); if (!node.lockUID(id, isSSK, true, 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 insert request from " + source.getPeer() + ": " + e); } return true; } // SSKs don't fix bwlimitDelayTime so shouldn't be accepted when overloaded. String rejectReason = nodeStats.shouldRejectRequest(!isSSK, true, isSSK, false, false, source, false); if (rejectReason != null) { Logger.normal( this, "Rejecting insert 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) insert request from " + source.getPeer() + ": " + e); } node.unlockUID(id, isSSK, true, false, false, false, tag); return true; } boolean forkOnCacheable = Node.FORK_ON_CACHEABLE_DEFAULT; Message forkControl = m.getSubMessage(DMT.FNPSubInsertForkControl); if (forkControl != null) forkOnCacheable = forkControl.getBoolean(DMT.ENABLE_INSERT_FORK_WHEN_CACHEABLE); long now = System.currentTimeMillis(); if (m.getSpec().equals(DMT.FNPSSKInsertRequest)) { NodeSSK key = (NodeSSK) m.getObject(DMT.FREENET_ROUTING_KEY); byte[] data = ((ShortBuffer) m.getObject(DMT.DATA)).getData(); byte[] headers = ((ShortBuffer) m.getObject(DMT.BLOCK_HEADERS)).getData(); short htl = m.getShort(DMT.HTL); SSKInsertHandler rh = new SSKInsertHandler( key, data, headers, htl, source, id, node, now, tag, node.canWriteDatastoreInsert(htl), forkOnCacheable); rh.receivedBytes(m.receivedByteCount()); node.executor.execute( rh, "SSKInsertHandler for " + id + " on " + node.getDarknetPortNumber()); } else if (m.getSpec().equals(DMT.FNPSSKInsertRequestNew)) { NodeSSK key = (NodeSSK) m.getObject(DMT.FREENET_ROUTING_KEY); short htl = m.getShort(DMT.HTL); SSKInsertHandler rh = new SSKInsertHandler( key, null, null, htl, source, id, node, now, tag, node.canWriteDatastoreInsert(htl), forkOnCacheable); rh.receivedBytes(m.receivedByteCount()); node.executor.execute( rh, "SSKInsertHandler for " + id + " on " + node.getDarknetPortNumber()); } else { CHKInsertHandler rh = new CHKInsertHandler(m, source, id, node, now, tag, forkOnCacheable); node.executor.execute( rh, "CHKInsertHandler for " + id + " on " + node.getDarknetPortNumber()); } if (logMINOR) Logger.minor(this, "Started InsertHandler for " + id); return true; }