diff --git a/src/freenet/io/comm/MessageFilter.java b/src/freenet/io/comm/MessageFilter.java index 9c07d905606..30a2e808bbb 100644 --- a/src/freenet/io/comm/MessageFilter.java +++ b/src/freenet/io/comm/MessageFilter.java @@ -180,6 +180,10 @@ public MessageFilter or(MessageFilter or) { throw new IllegalStateException("Setting a second .or() on the same filter will replace the " + "existing one, not add another. " + _or + " would be replaced by " + or + "."); } + if(or._initialTimeout != _initialTimeout) { + Logger.error(this, "Message filters being or()ed have different timeouts! This is very dangerous! This is "+this+" or is "+or); + // FIXME throw new IllegalArgumentException() + } _or = or; return this; } diff --git a/src/freenet/node/AnnounceSender.java b/src/freenet/node/AnnounceSender.java index b96ffefa5b7..ba62ed39cf3 100644 --- a/src/freenet/node/AnnounceSender.java +++ b/src/freenet/node/AnnounceSender.java @@ -141,8 +141,7 @@ private void realRun() { if(onlyNode == null) { // Route it - next = node.peers.closerPeer(source, nodesRoutedTo, target, true, node.isAdvancedModeEnabled(), -1, - null, null, htl, 0, source == null, false, false); + next = node.peers.closerPeerAnnouncement(source, nodesRoutedTo, target, htl); } else { next = onlyNode; if(nodesRoutedTo.contains(onlyNode)) { @@ -262,7 +261,7 @@ private void realRun() { MessageFilter mfAnnounceReply = MessageFilter.create().setSource(next).setField(DMT.UID, uid).setTimeout(ANNOUNCE_TIMEOUT).setType(DMT.FNPOpennetAnnounceReply); MessageFilter mfOpennetDisabled = MessageFilter.create().setSource(next).setField(DMT.UID, uid).setTimeout(ANNOUNCE_TIMEOUT).setType(DMT.FNPOpennetDisabled); MessageFilter mfNotWanted = MessageFilter.create().setSource(next).setField(DMT.UID, uid).setTimeout(ANNOUNCE_TIMEOUT).setType(DMT.FNPOpennetAnnounceNodeNotWanted); - MessageFilter mfOpennetNoderefRejected = MessageFilter.create().setSource(next).setField(DMT.UID, uid).setTimeout(ACCEPTED_TIMEOUT).setType(DMT.FNPOpennetNoderefRejected); + MessageFilter mfOpennetNoderefRejected = MessageFilter.create().setSource(next).setField(DMT.UID, uid).setTimeout(ANNOUNCE_TIMEOUT).setType(DMT.FNPOpennetNoderefRejected); MessageFilter mf = mfAnnounceCompleted.or(mfRouteNotFound.or(mfRejectedOverload.or(mfAnnounceReply.or(mfOpennetDisabled.or(mfNotWanted.or(mfOpennetNoderefRejected)))))); try { @@ -290,6 +289,7 @@ private void realRun() { if(msg.getSpec() == DMT.FNPOpennetAnnounceCompleted) { // Send the completion on immediately. We don't want to accumulate 30 seconds per hop! complete(); + //"complete" should always be the last message, but we might grab it out-of-order from our queue. mfAnnounceReply.setTimeout(END_TIMEOUT).setTimeoutRelativeToCreation(true); mfNotWanted.setTimeout(END_TIMEOUT).setTimeoutRelativeToCreation(true); mfAnnounceReply.clearOr(); @@ -494,6 +494,7 @@ private void rnf(PeerNode next) { } private void complete() { + addRefIfWanted(); synchronized(this) { while(waitingForTransfers > 0) { try { @@ -521,12 +522,19 @@ private boolean transferNoderef() { if(noderefBuf == null) { return false; } - SimpleFieldSet fs = OpennetManager.validateNoderef(noderefBuf, 0, noderefLength, source, false); + fs = OpennetManager.validateNoderef(noderefBuf, 0, noderefLength, source, false); if(fs == null) { OpennetManager.rejectRef(uid, source, DMT.NODEREF_REJECTED_INVALID, this); return false; } + return true; + } + + private SimpleFieldSet fs; + + private void addRefIfWanted() { // If we want it, add it and send it. + if (fs==null ) return; try { // Allow reconnection - sometimes one side has the ref and the other side doesn't. if(om.addNewOpennetNode(fs, ConnectionType.ANNOUNCE, true) != null) { @@ -540,20 +548,20 @@ private boolean transferNoderef() { } catch (FSParseException e) { Logger.warning(this, "Rejecting noderef: "+e, e); OpennetManager.rejectRef(uid, source, DMT.NODEREF_REJECTED_INVALID, this); - return false; + return; } catch (PeerParseException e) { Logger.warning(this, "Rejecting noderef: "+e, e); OpennetManager.rejectRef(uid, source, DMT.NODEREF_REJECTED_INVALID, this); - return false; + return; } catch (ReferenceSignatureVerificationException e) { Logger.warning(this, "Rejecting noderef: "+e, e); OpennetManager.rejectRef(uid, source, DMT.NODEREF_REJECTED_INVALID, this); - return false; + return; } catch (NotConnectedException e) { Logger.normal(this, "Could not receive noderef, disconnected"); - return false; + return; } - return true; + return; } private void sendNotWanted() throws NotConnectedException { diff --git a/src/freenet/node/Announcer.java b/src/freenet/node/Announcer.java index b6035f9b01a..cb5fbc489de 100644 --- a/src/freenet/node/Announcer.java +++ b/src/freenet/node/Announcer.java @@ -48,6 +48,11 @@ public class Announcer { private int runningAnnouncements; /** We want to announce to 5 different seednodes. */ private static final int WANT_ANNOUNCEMENTS = 5; + /** If true, announce through opennet peers as well as seednodes. If false, only announce through + * seednodes. FIXME SECURITY Capture by a single seednode may be slightly easier if we announce + * through opennet peers as well as seednodes, but until we have proper countermeasures to seed + * capture don't worry about it. FIXME make this configurable. */ + private static final boolean ANNOUNCE_THROUGH_OPENNET_PEERS = true; private int sentAnnouncements; private long startTime; private long timeAddedSeeds; @@ -493,14 +498,16 @@ protected void maybeSendAnnouncement() { return; } // Now find a node to announce to - List seeds = node.peers.getConnectedSeedServerPeersVector(announcedToIdentities); + List seeds = + ANNOUNCE_THROUGH_OPENNET_PEERS ? node.peers.getAnnounceStartPeersVector(announcedToIdentities) : + node.peers.getConnectedSeedServerPeersVector(announcedToIdentities); while(sentAnnouncements < WANT_ANNOUNCEMENTS) { if(seeds.isEmpty()) { if(logMINOR) Logger.minor(this, "No more seednodes, announcedTo = "+announcedToIdentities.size()); break; } - final SeedServerPeerNode seed = ListUtils.removeRandomBySwapLastSimple(node.random, seeds); + final PeerNode seed = ListUtils.removeRandomBySwapLastSimple(node.random, seeds); InetAddress[] addrs = seed.getInetAddresses(); if(!newAnnouncedIPs(addrs)) { if(logMINOR) @@ -565,7 +572,7 @@ private synchronized boolean newAnnouncedIPs(InetAddress[] addrs) { return !hasNonLocalAddresses; } - protected boolean sendAnnouncement(final SeedServerPeerNode seed) { + protected boolean sendAnnouncement(final PeerNode seed) { if(!node.isOpennetEnabled()) { if(logMINOR) Logger.minor(this, "Not announcing to "+seed+" because opennet is disabled"); @@ -623,7 +630,10 @@ public void run() { // If it takes more than COOLING_OFF_PERIOD to disconnect, we might not be able to reannounce to this // node. However, we can't reannounce to it anyway until announcedTo is cleared, which probably will // be more than that period in the future. - node.peers.disconnectAndRemove(seed, true, false, false); + if(seed instanceof SeedServerPeerNode) { + node.peers.disconnectAndRemove(seed, true, false, false); + if(logMINOR) Logger.minor(this, "Disconnected from seed server "+seed); + } int shallow=node.maxHTL()-(totalAdded+totalNotWanted); if(acceptedSomewhere) System.out.println("Announcement to "+seed.userToString()+" completed ("+totalAdded+" added, "+totalNotWanted+" not wanted, "+shallow+" shallow)"); diff --git a/src/freenet/node/BaseSender.java b/src/freenet/node/BaseSender.java index 0c5036adab6..ba2bf5d8f17 100644 --- a/src/freenet/node/BaseSender.java +++ b/src/freenet/node/BaseSender.java @@ -556,7 +556,7 @@ protected void innerRouteRequestsNew(PeerNode next, UIDTag origTag) { private PeerNode closerPeer(HashSet exclude, long now, boolean newLoadManagement) { return node.peers.closerPeer(sourceForRouting(), exclude, target, true, node.isAdvancedModeEnabled(), -1, null, - 2.0, isInsert() ? null : key, htl, ignoreLowBackoff(), source == null, realTimeFlag, null, false, now, newLoadManagement); + 2.0, isInsert() ? null : key, htl, ignoreLowBackoff(), source == null, realTimeFlag, null, false, now, newLoadManagement, false); } protected PeerNode sourceForRouting() { diff --git a/src/freenet/node/DarknetPeerNode.java b/src/freenet/node/DarknetPeerNode.java index 3d643f2dbec..f971984ae80 100644 --- a/src/freenet/node/DarknetPeerNode.java +++ b/src/freenet/node/DarknetPeerNode.java @@ -1948,4 +1948,10 @@ protected void sendInitialMessages() { } } } + + @Override + public int getMaxSimultaneousAnnouncements() { + // Darknet! + return 0; + } } diff --git a/src/freenet/node/FNPPacketMangler.java b/src/freenet/node/FNPPacketMangler.java index 53c3dd1aad9..2a9f77f8461 100644 --- a/src/freenet/node/FNPPacketMangler.java +++ b/src/freenet/node/FNPPacketMangler.java @@ -1345,6 +1345,7 @@ private void processJFKMessage3(byte[] payload, int inputOffset, PeerNode pn,Pee // Promote if necessary boolean dontWant = false; if(oldOpennetPeer) { + OpennetPeerNode opn = (OpennetPeerNode)pn; OpennetManager opennet = node.getOpennet(); if(opennet == null) { Logger.normal(this, "Dumping incoming old-opennet peer as opennet just turned off: "+pn+"."); @@ -1354,10 +1355,10 @@ private void processJFKMessage3(byte[] payload, int inputOffset, PeerNode pn,Pee * immediately dropped when there is no droppable peer to drop. If it was dropped * from the bottom of the LRU list, we would not have added it to the LRU; so it was * somewhere in the middle. */ - if(!opennet.wantPeer(pn, false, false, true, ConnectionType.RECONNECT)) { + if(!opennet.wantPeer(opn, false, false, true, ConnectionType.RECONNECT)) { Logger.normal(this, "No longer want peer "+pn+" - dumping it after connecting"); dontWant = true; - opennet.purgeOldOpennetPeer(pn); + opennet.purgeOldOpennetPeer(opn); } // wantPeer will call node.peers.addPeer(), we don't have to. } @@ -1570,14 +1571,15 @@ private boolean processJFKMessage4(byte[] payload, int inputOffset, PeerNode pn, Logger.normal(this, "Dumping incoming old-opennet peer as opennet just turned off: "+pn+"."); return true; } + OpennetPeerNode opn = (OpennetPeerNode)pn; /* When an old-opennet-peer connects, add it at the top of the LRU, so that it isn't * immediately dropped when there is no droppable peer to drop. If it was dropped * from the bottom of the LRU list, we would not have added it to the LRU; so it was * somewhere in the middle. */ - if(!opennet.wantPeer(pn, false, false, true, ConnectionType.RECONNECT)) { + if(!opennet.wantPeer(opn, false, false, true, ConnectionType.RECONNECT)) { Logger.normal(this, "No longer want peer "+pn+" - dumping it after connecting"); dontWant = true; - opennet.purgeOldOpennetPeer(pn); + opennet.purgeOldOpennetPeer(opn); } // wantPeer will call node.peers.addPeer(), we don't have to. } diff --git a/src/freenet/node/NodeClientCore.java b/src/freenet/node/NodeClientCore.java index b5694b6a047..312deb28307 100644 --- a/src/freenet/node/NodeClientCore.java +++ b/src/freenet/node/NodeClientCore.java @@ -2112,7 +2112,7 @@ public long checkRecentlyFailed(Key key, boolean realTime) { // slots and CPU. FIXME SECURITY/NETWORK: Reconsider if we ever decide // not to decrement on the originator. short origHTL = node.decrementHTL(null, node.maxHTL()); - node.peers.closerPeer(null, new HashSet(), key.toNormalizedDouble(), true, false, -1, null, 2.0, key, origHTL, 0, true, realTime, r, false, System.currentTimeMillis(), node.enableNewLoadManagement(realTime)); + node.peers.closerPeer(null, new HashSet(), key.toNormalizedDouble(), true, false, -1, null, 2.0, key, origHTL, 0, true, realTime, r, false, System.currentTimeMillis(), node.enableNewLoadManagement(realTime), false); return r.recentlyFailed(); } diff --git a/src/freenet/node/NodeDispatcher.java b/src/freenet/node/NodeDispatcher.java index 4e85c16a2eb..2a04331e401 100644 --- a/src/freenet/node/NodeDispatcher.java +++ b/src/freenet/node/NodeDispatcher.java @@ -432,10 +432,10 @@ private void finishDisconnect(final Message m, final PeerNode source) { // around in secondary tables etc in order to more easily reconnect later. // (Mostly used on opennet) boolean purge = m.getBoolean(DMT.PURGE); - if(purge) { + if(purge && source instanceof OpennetPeerNode) { OpennetManager om = node.getOpennet(); if(om != null) - om.purgeOldOpennetPeer(source); + om.purgeOldOpennetPeer((OpennetPeerNode)source); } // Process parting message int type = m.getInt(DMT.NODE_TO_NODE_MESSAGE_TYPE); diff --git a/src/freenet/node/OpennetManager.java b/src/freenet/node/OpennetManager.java index 9b859777804..fc5d30bd8dd 100644 --- a/src/freenet/node/OpennetManager.java +++ b/src/freenet/node/OpennetManager.java @@ -67,12 +67,12 @@ public class OpennetManager { final Announcer announcer; final SeedAnnounceTracker seedTracker = new SeedAnnounceTracker(); - /** Our peers. PeerNode's are promoted when they successfully fetch a key. Normally we take + /** Our peers. OpennetPeerNode's are promoted when they successfully fetch a key. Normally we take * the bottom peer, but if that isn't eligible to be dropped, we iterate up the list. */ - private final LRUQueue peersLRU; + private final LRUQueue peersLRU; /** Old peers. Opennet peers which we dropped but would still like to talk to * if we have no other option. */ - private final LRUQueue oldPeers; + private final LRUQueue oldPeers; /** Maximum number of old peers */ static final int MAX_OLD_PEERS = 25; /** Time at which last dropped a peer due to an incoming connection of each type. */ @@ -205,8 +205,8 @@ public OpennetManager(Node node, NodeCryptoConfig opennetConfig, long startupTim crypto.initCrypto(); } } - peersLRU = new LRUQueue(); - oldPeers = new LRUQueue(); + peersLRU = new LRUQueue(); + oldPeers = new LRUQueue(); node.peers.tryReadPeers(node.nodeDir().file("openpeers-"+crypto.portNumber).toString(), crypto, this, true, false); OpennetPeerNode[] nodes = node.peers.getOpennetPeers(); Arrays.sort(nodes, new Comparator() { @@ -390,7 +390,7 @@ public OpennetPeerNode addNewOpennetNode(SimpleFieldSet fs, ConnectionType conne /** When did we last offer our noderef to some other node? */ private long timeLastOffered; - void forceAddPeer(PeerNode nodeToAddNow, boolean addAtLRU) { + void forceAddPeer(OpennetPeerNode nodeToAddNow, boolean addAtLRU) { synchronized(this) { if(addAtLRU) peersLRU.pushLeast(nodeToAddNow); @@ -421,7 +421,7 @@ void forceAddPeer(PeerNode nodeToAddNow, boolean addAtLRU) { * because of the first check. * @return True if the node was added / should be added. */ - public boolean wantPeer(PeerNode nodeToAddNow, boolean addAtLRU, boolean justChecking, boolean oldOpennetPeer, ConnectionType connectionType) { + public boolean wantPeer(OpennetPeerNode nodeToAddNow, boolean addAtLRU, boolean justChecking, boolean oldOpennetPeer, ConnectionType connectionType) { boolean notMany = false; boolean noDisconnect; long now = System.currentTimeMillis(); @@ -512,7 +512,7 @@ public boolean wantPeer(PeerNode nodeToAddNow, boolean addAtLRU, boolean justChe // Allow an offer to be predicated on throwing out a connected node, // provided that we meet the other criteria e.g. time since last added, // node isn't too new. - PeerNode toDrop = peerToDrop(noDisconnect, false, nodeToAddNow != null, connectionType, maxPeers); + OpennetPeerNode toDrop = peerToDrop(noDisconnect, false, nodeToAddNow != null, connectionType, maxPeers); if(toDrop == null) { if(logMINOR) Logger.minor(this, "No more peers to drop (in first bit), still "+peersLRU.size()+" peers, cannot accept peer"+(nodeToAddNow == null ? "" : nodeToAddNow.toString())); @@ -658,7 +658,7 @@ void dropExcessPeers() { while(getSize() > maxPeers) { if(logMINOR) Logger.minor(this, "Dropping opennet peers: currently "+peersLRU.size()); - PeerNode toDrop; + OpennetPeerNode toDrop; toDrop = peerToDrop(false, false, false, null, maxPeers); if(toDrop == null) toDrop = peerToDrop(false, true, false, null, maxPeers); if(toDrop == null) return; @@ -683,8 +683,8 @@ void dropExcessPeers() { */ synchronized public int getSize() { int x = 0; - for (Enumeration e = peersLRU.elements(); e.hasMoreElements();) { - PeerNode pn = e.nextElement(); + for (Enumeration e = peersLRU.elements(); e.hasMoreElements();) { + OpennetPeerNode pn = e.nextElement(); if(!pn.isUnroutableOlderVersion()) x++; } return x; @@ -807,12 +807,12 @@ public void onRemove(OpennetPeerNode pn) { } } - synchronized PeerNode[] getOldPeers() { - return oldPeers.toArrayOrdered(new PeerNode[oldPeers.size()]); + synchronized OpennetPeerNode[] getOldPeers() { + return oldPeers.toArrayOrdered(new OpennetPeerNode[oldPeers.size()]); } - synchronized PeerNode[] getUnsortedOldPeers() { - return oldPeers.toArray(new PeerNode[oldPeers.size()]); + synchronized OpennetPeerNode[] getUnsortedOldPeers() { + return oldPeers.toArray(new OpennetPeerNode[oldPeers.size()]); } /** @@ -820,7 +820,7 @@ synchronized PeerNode[] getUnsortedOldPeers() { * if we are desperate. * @param pn The node to add to the old opennet nodes LRU. */ - synchronized void addOldOpennetNode(PeerNode pn) { + synchronized void addOldOpennetNode(OpennetPeerNode pn) { oldPeers.push(pn); } @@ -832,13 +832,13 @@ synchronized int countOldOpennetPeers() { return oldPeers.size(); } - PeerNode randomOldOpennetNode() { - PeerNode[] nodes = getUnsortedOldPeers(); + OpennetPeerNode randomOldOpennetNode() { + OpennetPeerNode[] nodes = getUnsortedOldPeers(); if(nodes.length == 0) return null; return nodes[node.random.nextInt(nodes.length)]; } - public synchronized void purgeOldOpennetPeer(PeerNode source) { + public synchronized void purgeOldOpennetPeer(OpennetPeerNode source) { oldPeers.remove(source); } @@ -1200,7 +1200,7 @@ public int getAnnouncementThreshold() { /** Notification that a peer was disconnected. Query the Announcer, * it may need to rerun. */ - public void onDisconnect(PeerNode node2) { + public void onDisconnect() { if(announcer != null) announcer.maybeSendAnnouncementOffThread(); } diff --git a/src/freenet/node/OpennetPeerNode.java b/src/freenet/node/OpennetPeerNode.java index 39374165130..f98ee69dba3 100644 --- a/src/freenet/node/OpennetPeerNode.java +++ b/src/freenet/node/OpennetPeerNode.java @@ -273,4 +273,13 @@ boolean dontKeepFullFieldSet() { return true; } + /** FIXME there clearly should be some limit, but if it's too low it'll + * be a problem for seednodes and their direct peers? */ + static final int MAX_SIMULTANEOUS_ANNOUNCEMENTS_PER_PEER = 10; + + @Override + public int getMaxSimultaneousAnnouncements() { + return MAX_SIMULTANEOUS_ANNOUNCEMENTS_PER_PEER; + } + } diff --git a/src/freenet/node/PacketSender.java b/src/freenet/node/PacketSender.java index 4fafa542f7c..92b9ef9145b 100644 --- a/src/freenet/node/PacketSender.java +++ b/src/freenet/node/PacketSender.java @@ -426,9 +426,9 @@ private void realRun() { OpennetManager om = node.getOpennet(); if(om != null && node.getUptime() > 30*1000) { - PeerNode[] peers = om.getOldPeers(); + OpennetPeerNode[] peers = om.getOldPeers(); - for(PeerNode pn : peers) { + for(OpennetPeerNode pn : peers) { if(pn.timeLastConnected() <= 0) Logger.error(this, "Last connected is zero or negative for old-opennet-peer "+pn); // Will be removed by next line. diff --git a/src/freenet/node/PeerManager.java b/src/freenet/node/PeerManager.java index 7aa971258fc..5ca200400ca 100644 --- a/src/freenet/node/PeerManager.java +++ b/src/freenet/node/PeerManager.java @@ -266,7 +266,7 @@ private boolean readPeers(File peersFile, OutgoingPacketMangler mangler, NodeCry // FIXME tell the user??? } if(oldOpennetPeers) - opennet.addOldOpennetNode(pn); + opennet.addOldOpennetNode((OpennetPeerNode)pn); else addPeer(pn, true, false); gotSome = true; @@ -333,7 +333,7 @@ boolean addPeer(PeerNode pn, boolean ignoreOpennet, boolean reactivate) { if((!ignoreOpennet) && pn instanceof OpennetPeerNode) { OpennetManager opennet = node.getOpennet(); if(opennet != null) - opennet.forceAddPeer(pn, true); + opennet.forceAddPeer((OpennetPeerNode)pn, true); else { Logger.error(this, "Adding opennet peer when no opennet enabled!!!: " + pn + " - removing..."); removePeer(pn); @@ -879,7 +879,13 @@ public PeerNode getRandomPeer() { public PeerNode closerPeer(PeerNode pn, Set routedTo, double loc, boolean ignoreSelf, boolean calculateMisrouting, int minVersion, List addUnpickedLocsTo, Key key, short outgoingHTL, int ignoreBackoffUnder, boolean isLocal, boolean realTime, boolean excludeMandatoryBackoff) { - return closerPeer(pn, routedTo, loc, ignoreSelf, calculateMisrouting, minVersion, addUnpickedLocsTo, 2.0, key, outgoingHTL, ignoreBackoffUnder, isLocal, realTime, null, false, System.currentTimeMillis(), excludeMandatoryBackoff); + return closerPeer(pn, routedTo, loc, ignoreSelf, calculateMisrouting, minVersion, addUnpickedLocsTo, 2.0, key, outgoingHTL, ignoreBackoffUnder, isLocal, realTime, null, false, System.currentTimeMillis(), excludeMandatoryBackoff, false); + } + + public PeerNode closerPeerAnnouncement(PeerNode source, Set nodesRoutedTo, double target, short htl) { + return closerPeer(source, nodesRoutedTo, target, true, node.isAdvancedModeEnabled(), -1, + null, 2.0, null, htl, 0, source == null, false, + null, false, System.currentTimeMillis(), false, true); } /** @@ -903,10 +909,11 @@ public PeerNode closerPeer(PeerNode pn, Set routedTo, double loc, bool * RecentlyFailed message to be returned to the originator, allowing them to retry in a little while. Note that the * scheduler is not clever enough to retry immediately when that timeout elapses, and even if it was, it probably * wouldn't be a good idea due to introducing a round-trip-to-request-originator; FIXME consider this. + * @param opennetOnly If true, only route to opennet peers (not including seed clients etc). */ public PeerNode closerPeer(PeerNode pn, Set routedTo, double target, boolean ignoreSelf, boolean calculateMisrouting, int minVersion, List addUnpickedLocsTo, double maxDistance, Key key, short outgoingHTL, int ignoreBackoffUnder, boolean isLocal, boolean realTime, - RecentlyFailedReturn recentlyFailed, boolean ignoreTimeout, long now, boolean newLoadManagement) { + RecentlyFailedReturn recentlyFailed, boolean ignoreTimeout, long now, boolean newLoadManagement, boolean opennetOnly) { int countWaiting = 0; long soonestTimeoutWakeup = Long.MAX_VALUE; @@ -999,6 +1006,11 @@ public PeerNode closerPeer(PeerNode pn, Set routedTo, double target, b Logger.minor(this, "Skipping old version: " + p.getPeer()); continue; } + if(opennetOnly && !(p instanceof OpennetPeerNode)) { + if(logMINOR) + Logger.minor(this, "Skipping non-opennet peer: "+p.getPeer()); + continue; + } if(enableFOAFMitigationHack) { double selectionRate = selectionRates[i]; double selectionSamplesPercentage = selectionRate / totalSelectionRate; @@ -1165,7 +1177,7 @@ public PeerNode closerPeer(PeerNode pn, Set routedTo, double target, b // Recently failed is possible. // Route twice, each time ignoring timeout. // If both return a node which is in timeout, we should do RecentlyFailed. - PeerNode first = closerPeer(pn, routedTo, target, ignoreSelf, false, minVersion, null, maxDistance, key, outgoingHTL, ignoreBackoffUnder, isLocal, realTime, null, true, now, newLoadManagement); + PeerNode first = closerPeer(pn, routedTo, target, ignoreSelf, false, minVersion, null, maxDistance, key, outgoingHTL, ignoreBackoffUnder, isLocal, realTime, null, true, now, newLoadManagement, opennetOnly); if(first != null) { long firstTime; long secondTime; @@ -1173,7 +1185,7 @@ public PeerNode closerPeer(PeerNode pn, Set routedTo, double target, b if(logMINOR) Logger.minor(this, "First choice is past now"); HashSet newRoutedTo = new HashSet(routedTo); newRoutedTo.add(first); - PeerNode second = closerPeer(pn, newRoutedTo, target, ignoreSelf, false, minVersion, null, maxDistance, key, outgoingHTL, ignoreBackoffUnder, isLocal, realTime, null, true, now, newLoadManagement); + PeerNode second = closerPeer(pn, newRoutedTo, target, ignoreSelf, false, minVersion, null, maxDistance, key, outgoingHTL, ignoreBackoffUnder, isLocal, realTime, null, true, now, newLoadManagement, opennetOnly); if(second != null) { if((secondTime = entry.getTimeoutTime(first, outgoingHTL, now, false)) > now) { if(logMINOR) Logger.minor(this, "Second choice is past now"); @@ -1965,7 +1977,7 @@ public List getConnectedSeedServerPeersVector(HashSet getConnectedSeedServerPeersVector(HashSet getAnnounceStartPeersVector(HashSet exclude) { + PeerNode[] peers = myPeers(); + // FIXME optimise! Maybe maintain as a separate list? + ArrayList v = new ArrayList(peers.length); + for(PeerNode p : peers) { + if(p.isDarknet()) continue; + if(!(p instanceof SeedServerPeerNode || p instanceof OpennetPeerNode)) { + // FIXME we can't announce through darknet peers. If we can, change this. + continue; + } + if(!p.isConnected()) continue; + if(exclude != null && exclude.contains(new ByteArrayWrapper(p.getPubKeyHash()))) { + if(logMINOR) + Logger.minor(this, "Not including in getConnectedAnnounceablePeersVector() as in exclude set: " + p.userToString()); + continue; + } + v.add(p); + } + return v; + } + public List getSeedServerPeersVector() { PeerNode[] peers = myPeers(); // FIXME optimise! Maybe maintain as a separate list? diff --git a/src/freenet/node/PeerNode.java b/src/freenet/node/PeerNode.java index 1565eb2a02c..5afa045750d 100644 --- a/src/freenet/node/PeerNode.java +++ b/src/freenet/node/PeerNode.java @@ -1377,7 +1377,7 @@ public void run() { // Tell opennet manager even if this is darknet, because we may need more opennet peers now. OpennetManager om = node.getOpennet(); if(om != null) - om.onDisconnect(this); + om.onDisconnect(); outputLoadTrackerRealTime.failSlotWaiters(true); outputLoadTrackerBulk.failSlotWaiters(true); loadSenderRealTime.onDisconnect(); @@ -4036,19 +4036,24 @@ public int getSigParamsByteLength() { return byteLen; } - static final int MAX_SIMULTANEOUS_ANNOUNCEMENTS = 1; static final int MAX_ANNOUNCE_DELAY = 1000; private long timeLastAcceptedAnnouncement; private long[] runningAnnounceUIDs = new long[0]; + /** Protection against too many simultaneous announcements over a single + * connection. + * @param uid The announcement UID. + * @return True if we should accept the announcement. False to reject it. + */ public synchronized boolean shouldAcceptAnnounce(long uid) { long now = System.currentTimeMillis(); - if(runningAnnounceUIDs.length < MAX_SIMULTANEOUS_ANNOUNCEMENTS && + if(runningAnnounceUIDs.length < getMaxSimultaneousAnnouncements() && now - timeLastAcceptedAnnouncement > MAX_ANNOUNCE_DELAY) { long[] newList = new long[runningAnnounceUIDs.length + 1]; if(runningAnnounceUIDs.length > 0) System.arraycopy(runningAnnounceUIDs, 0, newList, 0, runningAnnounceUIDs.length); newList[runningAnnounceUIDs.length] = uid; + runningAnnounceUIDs = newList; timeLastAcceptedAnnouncement = now; return true; } else { @@ -4056,24 +4061,32 @@ public synchronized boolean shouldAcceptAnnounce(long uid) { } } + /** Report that an announcement finished. */ public synchronized boolean completedAnnounce(long uid) { - final int runningAnnounceUIDsLength = runningAnnounceUIDs.length; - if(runningAnnounceUIDsLength < 1) return false; - long[] newList = new long[runningAnnounceUIDsLength - 1]; + if(runningAnnounceUIDs.length < 1) return false; + long[] newList = new long[runningAnnounceUIDs.length - 1]; int x = 0; - for(int i=0;i v = new ArrayList(); + for(Peer peer: getHandshakeIPs()) { + FreenetInetAddress fa = peer.getFreenetAddress().dropHostname(); + if(fa == null) continue; + InetAddress ia = fa.getAddress(); + if(v.contains(ia)) continue; + v.add(ia); + } + if(v.isEmpty()) { + Logger.error(this, "No valid addresses for node "+this); + } + return v.toArray(new InetAddress[v.size()]); + } + } diff --git a/src/freenet/node/RequestSender.java b/src/freenet/node/RequestSender.java index 4d2d7d48aa8..6fcdb6f7e3c 100644 --- a/src/freenet/node/RequestSender.java +++ b/src/freenet/node/RequestSender.java @@ -348,7 +348,7 @@ protected void routeRequests() { // Route it next = node.peers.closerPeer(source, nodesRoutedTo, target, true, node.isAdvancedModeEnabled(), -1, null, - 2.0, key, htl, 0, source == null, realTimeFlag, r, false, now, newLoadManagement); + 2.0, key, htl, 0, source == null, realTimeFlag, r, false, now, newLoadManagement, false); long recentlyFailed = r.recentlyFailed(); if(recentlyFailed > now) { diff --git a/src/freenet/node/SeedClientPeerNode.java b/src/freenet/node/SeedClientPeerNode.java index 33625557c7d..b79ebb47f25 100644 --- a/src/freenet/node/SeedClientPeerNode.java +++ b/src/freenet/node/SeedClientPeerNode.java @@ -169,5 +169,11 @@ boolean dontKeepFullFieldSet() { return true; } + @Override + public int getMaxSimultaneousAnnouncements() { + // Seed clients should only be able to do one announcement at a time. + return 1; + } + } diff --git a/src/freenet/node/SeedServerPeerNode.java b/src/freenet/node/SeedServerPeerNode.java index 7fb96655cef..f5ec2d86af9 100644 --- a/src/freenet/node/SeedServerPeerNode.java +++ b/src/freenet/node/SeedServerPeerNode.java @@ -96,21 +96,6 @@ public void run() { } } - public InetAddress[] getInetAddresses() { - ArrayList v = new ArrayList(); - for(Peer peer: getHandshakeIPs()) { - FreenetInetAddress fa = peer.getFreenetAddress().dropHostname(); - if(fa == null) continue; - InetAddress ia = fa.getAddress(); - if(v.contains(ia)) continue; - v.add(ia); - } - if(v.isEmpty()) { - Logger.error(this, "No valid addresses for seed node "+this); - } - return v.toArray(new InetAddress[v.size()]); - } - @Override public boolean handshakeUnknownInitiator() { return true; @@ -175,4 +160,10 @@ boolean dontKeepFullFieldSet() { return false; } + @Override + public int getMaxSimultaneousAnnouncements() { + // Announcements are not sent to seed clients. + return 0; + } + }