Author: toad
Date: 2007-12-05 20:25:30 +0000 (Wed, 05 Dec 2007)
New Revision: 16339
Modified:
trunk/freenet/src/freenet/node/AnnounceSender.java
trunk/freenet/src/freenet/node/Announcer.java
trunk/freenet/src/freenet/node/OpennetManager.java
trunk/freenet/src/freenet/node/PeerManager.java
trunk/freenet/src/freenet/node/PeerNode.java
trunk/freenet/src/freenet/node/SeedServerPeerNode.java
Log:
Announcer. Still need a useralert, and probably a lot of debugging and tweaking.
Modified: trunk/freenet/src/freenet/node/AnnounceSender.java
===================================================================
--- trunk/freenet/src/freenet/node/AnnounceSender.java 2007-12-05 17:40:04 UTC
(rev 16338)
+++ trunk/freenet/src/freenet/node/AnnounceSender.java 2007-12-05 20:25:30 UTC
(rev 16339)
@@ -34,6 +34,7 @@
private double target;
private static boolean logMINOR;
private final AnnouncementCallback cb;
+ private final PeerNode onlyNode;
public AnnounceSender(Message m, long uid, PeerNode source,
OpennetManager om, Node node) {
this.source = source;
@@ -41,13 +42,14 @@
this.msg = m;
this.om = om;
this.node = node;
+ this.onlyNode = null;
htl = m.getShort(DMT.HTL);
target = m.getDouble(DMT.TARGET_LOCATION); // FIXME validate
logMINOR = Logger.shouldLog(Logger.MINOR, this);
cb = null;
}
- public AnnounceSender(double target, OpennetManager om, Node node,
AnnouncementCallback cb) {
+ public AnnounceSender(double target, OpennetManager om, Node node,
AnnouncementCallback cb, PeerNode onlyNode) {
source = null;
this.uid = node.random.nextLong();
msg = null;
@@ -56,6 +58,7 @@
this.htl = node.maxHTL();
this.target = target;
this.cb = cb;
+ this.onlyNode = onlyNode;
noderefBuf = om.crypto.myCompressedFullRef();
logMINOR = Logger.shouldLog(Logger.MINOR, this);
}
@@ -70,6 +73,8 @@
source.completedAnnounce(uid);
}
node.completed(uid);
+ if(cb != null)
+ cb.completed();
}
}
@@ -105,9 +110,17 @@
return;
}
- // Route it
- PeerNode next;
- next = node.peers.closerPeer(source, nodesRoutedTo,
nodesNotIgnored, target, true, node.isAdvancedModeEnabled(), -1, null);
+ PeerNode next;
+ if(onlyNode == null) {
+ // Route it
+ next = node.peers.closerPeer(source, nodesRoutedTo,
nodesNotIgnored, target, true, node.isAdvancedModeEnabled(), -1, null);
+ } else {
+ next = onlyNode;
+ if(nodesRoutedTo.contains(onlyNode)) {
+ rnf(onlyNode);
+ return;
+ }
+ }
if(next == null) {
// Backtrack
Modified: trunk/freenet/src/freenet/node/Announcer.java
===================================================================
--- trunk/freenet/src/freenet/node/Announcer.java 2007-12-05 17:40:04 UTC
(rev 16338)
+++ trunk/freenet/src/freenet/node/Announcer.java 2007-12-05 20:25:30 UTC
(rev 16339)
@@ -3,6 +3,22 @@
* http://www.gnu.org/ for further details of the GPL. */
package freenet.node;
+import java.io.BufferedInputStream;
+import java.io.BufferedReader;
+import java.io.EOFException;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.HashSet;
+import java.util.Vector;
+
+import freenet.io.comm.PeerParseException;
+import freenet.io.comm.ReferenceSignatureVerificationException;
+import freenet.support.Logger;
+import freenet.support.SimpleFieldSet;
+import freenet.support.io.Closer;
+
/**
* Decide whether to announce, and announce if necessary to a node in the
* routing table, or to a seednode.
@@ -12,15 +28,249 @@
final Node node;
final OpennetManager om;
+ private int status;
+ final int STATUS_LOADING = 0;
+ final int STATUS_CONNECTING_SEEDNODES = 1;
+ final int STATUS_NO_SEEDNODES = -1;
+ private int runningAnnouncements;
+ /** We want to announce to 3 different seednodes. */
+ final int WANT_ANNOUNCEMENTS = 3;
+ private int sentAnnouncements;
+ /** The time when we last sent an announcement. */
+ private long timeSentAnnouncement;
+ private long timeCompletedAnnouncement;
+ private long startTime;
+ private long timeAddedSeeds;
+ static final long MIN_ADDED_SEEDS_INTERVAL = 60*1000;
+ /** After we have sent 3 announcements, wait for 1 minute before
sending 3 more if we still have no connections. */
+ static final int COOLING_OFF_PERIOD = 60*1000;
+ /** Identities of nodes we have announced to */
+ private final HashSet announcedToIdentities;
+ /** IPs of nodes we have announced to. Maybe this should be
first-two-bytes, but I'm not sure how to do that with IPv6. */
+ private final Vector announcedToIPs;
+ /** How many nodes to connect to at once? */
+ static final int CONNECT_AT_ONCE = 10;
+ /** Do not announce if there are more than this many opennet peers
connected */
+ private static final int MIN_OPENNET_CONNECTED_PEERS = 10;
+ /** Identities of nodes we have tried to connect to */
+ private final HashSet connectedToIdentities;
+ /** Total nodes added by announcement so far */
+ private int announcementAddedNodes;
+ /** Total nodes that didn't want us so far */
+ private int announcementNotWantedNodes;
Announcer(OpennetManager om) {
this.om = om;
this.node = om.node;
+ announcedToIdentities = new HashSet();
+ announcedToIPs = new Vector();
+ connectedToIdentities = new HashSet();
}
public void start() {
+ if(node.peers.getDarknetPeers().length +
node.peers.getOpennetPeers().length + om.countOldOpennetPeers() == 0) {
+ // We know opennet is enabled.
+ // We have no peers AT ALL.
+ // So lets connect to a few seednodes, and attempt an
announcement.
+ System.err.println("Attempting announcement to
seednodes...");
+ synchronized(this) {
+ status = STATUS_LOADING;
+ }
+ registerAlert();
+ connectSomeSeednodes();
+ } else {
+ // Wait a minute, then check whether we need to seed.
+ node.getTicker().queueTimedJob(new Runnable() {
+ public void run() {
+ try {
+ maybeSendAnnouncement();
+ } catch (Throwable t) {
+ Logger.error(this, "Caught
"+t+" trying to send announcements", t);
+ }
+ }
+ }, MIN_ADDED_SEEDS_INTERVAL);
+ }
+ }
+
+ private void registerAlert() {
// TODO Auto-generated method stub
}
+
+ private void connectSomeSeednodes() {
+ Vector/*<SimpleFieldSet>*/ seeds = readSeednodes();
+ if(seeds.size() == 0) {
+ synchronized(this) {
+ status = STATUS_NO_SEEDNODES;
+ return;
+ }
+ } else {
+ status = STATUS_CONNECTING_SEEDNODES;
+ }
+ // Try to connect to some seednodes.
+ // Once they are connected they will report back and we can
attempt an announcement.
+
+ int count = 0;
+ while(count < CONNECT_AT_ONCE) {
+ if(seeds.size() == 0) break;
+ SimpleFieldSet fs = (SimpleFieldSet)
seeds.remove(node.random.nextInt(seeds.size()));
+ try {
+ SeedServerPeerNode seed =
+ new SeedServerPeerNode(fs, node,
om.crypto, node.peers, false, om.crypto.packetMangler);
+ if(node.peers.addPeer(seed)) {
+ count++;
+
connectedToIdentities.add(seed.identity);
+ }
+ } catch (FSParseException e) {
+ Logger.error(this, "Invalid seed in file: "+e+"
for\n"+fs, e);
+ continue;
+ } catch (PeerParseException e) {
+ Logger.error(this, "Invalid seed in file: "+e+"
for\n"+fs, e);
+ continue;
+ } catch (ReferenceSignatureVerificationException e) {
+ Logger.error(this, "Invalid seed in file: "+e+"
for\n"+fs, e);
+ continue;
+ }
+
+ }
+ // If none connect in a minute, try some more.
+ node.getTicker().queueTimedJob(new Runnable() {
+ public void run() {
+ try {
+ maybeSendAnnouncement();
+ } catch (Throwable t) {
+ Logger.error(this, "Caught "+t+" trying
to send announcements", t);
+ }
+ }
+ }, MIN_ADDED_SEEDS_INTERVAL);
+ }
+
+ private Vector readSeednodes() {
+ File file = new File(node.nodeDir, "seednodes.fref");
+ Vector list = new Vector();
+ FileInputStream fis = null;
+ try {
+ fis = new FileInputStream(file);
+ BufferedInputStream bis = new BufferedInputStream(fis);
+ InputStreamReader isr = new InputStreamReader(bis,
"UTF-8");
+ BufferedReader br = new BufferedReader(isr);
+ while(true) {
+ try {
+ SimpleFieldSet fs = new
SimpleFieldSet(br, false, false);
+ list.add(fs);
+ } catch (EOFException e) {
+ return list;
+ }
+ }
+ } catch (IOException e) {
+ return list;
+ } finally {
+ Closer.close(fis);
+ }
+ }
+
+ public void stop() {
+ // Do nothing at present
+ }
+
+ public void maybeSendAnnouncement() {
+ // Do we want to send an announcement to the node?
+ int opennetCount = node.peers.countConnectedOpennetPeers();
+ // First, do we actually need to announce?
+ if(opennetCount > MIN_OPENNET_CONNECTED_PEERS) {
+ return;
+ }
+ long now = System.currentTimeMillis();
+ synchronized(this) {
+ // Second, do we have many announcements running?
+ if(runningAnnouncements > WANT_ANNOUNCEMENTS) {
+ return;
+ }
+ // In cooling-off period?
+ if(System.currentTimeMillis() < startTime) {
+ return;
+ }
+ if(sentAnnouncements >= WANT_ANNOUNCEMENTS) {
+ return;
+ }
+ // Now find a node to announce to
+ Vector seeds =
node.peers.getSeedServerPeersVector(announcedToIdentities);
+ for(int i=sentAnnouncements;i<WANT_ANNOUNCEMENTS;i++) {
+ if(seeds.isEmpty()) break;
+ final SeedServerPeerNode seed =
(SeedServerPeerNode) seeds.remove(node.random.nextInt(seeds.size()));
+ sentAnnouncements++;
+ runningAnnouncements++;
+ timeSentAnnouncement = now;
+ sendAnnouncement(seed);
+ }
+ if(runningAnnouncements >= WANT_ANNOUNCEMENTS)
+ return;
+ // Do we want to connect some more seednodes?
+ if(now - timeAddedSeeds < MIN_ADDED_SEEDS_INTERVAL) {
+ // Don't connect seednodes yet
+ node.getTicker().queueTimedJob(new Runnable() {
+ public void run() {
+ try {
+ maybeSendAnnouncement();
+ } catch (Throwable t) {
+ Logger.error(this,
"Caught "+t+" trying to send announcements", t);
+ }
+ }
+ }, (timeAddedSeeds + MIN_ADDED_SEEDS_INTERVAL)
- now);
+ return;
+ }
+ }
+ connectSomeSeednodes();
+ }
+ public void sendAnnouncement(final SeedServerPeerNode seed) {
+ AnnounceSender sender = new AnnounceSender(node.getLocation(),
om, node, new AnnouncementCallback() {
+ private int totalAdded;
+ private int totalNotWanted;
+ public void addedNode(PeerNode pn) {
+ synchronized(Announcer.this) {
+ announcementAddedNodes++;
+ totalAdded++;
+ }
+ Logger.error(this, "Announcement to "+seed+"
added node "+pn+" for a total of "+announcementAddedNodes+" ("+totalAdded+"
from this announcement)");
+ return;
+ }
+ public void bogusNoderef(String reason) {
+ Logger.error(this, "Announcement to "+seed+"
got bogus noderef: "+reason, new Exception("debug"));
+ }
+ public void completed() {
+ long now = System.currentTimeMillis();
+ synchronized(Announcer.this) {
+ runningAnnouncements--;
+ Logger.error(this, "Announcement to
"+seed+" completed, now running "+runningAnnouncements+" announcements");
+ timeCompletedAnnouncement = now;
+ if(runningAnnouncements == 0) {
+ startTime =
System.currentTimeMillis() + COOLING_OFF_PERIOD;
+ sentAnnouncements = 0;
+ // Wait for COOLING_OFF_PERIOD
before trying again
+
node.getTicker().queueTimedJob(new Runnable() {
+
+ public void run() {
+
maybeSendAnnouncement();
+ }
+
+ }, COOLING_OFF_PERIOD);
+ }
+ }
+ }
+
+ public void nodeFailed(PeerNode pn, String reason) {
+ Logger.error(this, "Announcement to node "+pn+"
failed");
+ }
+ public void nodeNotWanted() {
+ synchronized(Announcer.this) {
+ announcementNotWantedNodes++;
+ totalNotWanted++;
+ }
+ Logger.error(this, "Announcement to "+seed+"
returned node not wanted for a total of "+announcementNotWantedNodes+"
("+totalNotWanted+" from this announcement)");
+ }
+ }, seed);
+ node.executor.execute(sender, "Announcer to "+seed);
+ }
+
}
Modified: trunk/freenet/src/freenet/node/OpennetManager.java
===================================================================
--- trunk/freenet/src/freenet/node/OpennetManager.java 2007-12-05 17:40:04 UTC
(rev 16338)
+++ trunk/freenet/src/freenet/node/OpennetManager.java 2007-12-05 20:25:30 UTC
(rev 16339)
@@ -209,6 +209,7 @@
* Called when opennet is disabled
*/
public void stop(boolean purge) {
+ announcer.stop();
crypto.stop();
if(purge)
node.peers.removeOpennetPeers();
@@ -648,7 +649,7 @@
* announcement location, because it is easy for them to get the
location they want later on anyway,
* and we can do a much more effective announcement this way. */
public void announce(double target, AnnouncementCallback cb) {
- AnnounceSender sender = new AnnounceSender(target, this, node,
cb);
+ AnnounceSender sender = new AnnounceSender(target, this, node,
cb, null);
node.executor.execute(sender, "Announcement to "+target);
}
Modified: trunk/freenet/src/freenet/node/PeerManager.java
===================================================================
--- trunk/freenet/src/freenet/node/PeerManager.java 2007-12-05 17:40:04 UTC
(rev 16338)
+++ trunk/freenet/src/freenet/node/PeerManager.java 2007-12-05 20:25:30 UTC
(rev 16339)
@@ -1325,6 +1325,22 @@
return (DarknetPeerNode[])v.toArray(new
DarknetPeerNode[v.size()]);
}
+ public Vector getSeedServerPeersVector(HashSet exclude) {
+ PeerNode[] peers;
+ synchronized(this) {
+ peers = myPeers;
+ }
+ // FIXME optimise! Maybe maintain as a separate list?
+ Vector v = new Vector(myPeers.length);
+ for(int i=0;i<peers.length;i++) {
+ if(peers[i] instanceof SeedServerPeerNode) {
+ if(exclude.contains(peers[i].getIdentity()))
continue;
+ v.add(peers[i]);
+ }
+ }
+ return v;
+ }
+
/**
* Get the opennet peers list.
*/
@@ -1391,10 +1407,23 @@
PeerNode[] peers = connectedPeers;
for(int i=0;i<peers.length;i++) {
if(peers[i] == null) continue;
+ if(!(peers[i] instanceof DarknetPeerNode)) continue;
if(peers[i].isOpennet()) continue;
if(!peers[i].isRoutable()) continue;
count++;
}
return count;
}
+
+ public int countConnectedOpennetPeers() {
+ int count = 0;
+ PeerNode[] peers = connectedPeers;
+ for(int i=0;i<peers.length;i++) {
+ if(peers[i] == null) continue;
+ if(!(peers[i] instanceof OpennetPeerNode)) continue;
+ if(!peers[i].isRoutable()) continue;
+ count++;
+ }
+ return count;
+ }
}
Modified: trunk/freenet/src/freenet/node/PeerNode.java
===================================================================
--- trunk/freenet/src/freenet/node/PeerNode.java 2007-12-05 17:40:04 UTC
(rev 16338)
+++ trunk/freenet/src/freenet/node/PeerNode.java 2007-12-05 20:25:30 UTC
(rev 16339)
@@ -1681,7 +1681,7 @@
/**
* Send any high level messages that need to be sent on connect.
*/
- private void sendInitialMessages() {
+ protected void sendInitialMessages() {
Message locMsg =
DMT.createFNPLocChangeNotification(node.lm.getLocation());
Message ipMsg = DMT.createFNPDetectedIPAddress(detectedPeer);
Message timeMsg = DMT.createFNPTime(System.currentTimeMillis());
Modified: trunk/freenet/src/freenet/node/SeedServerPeerNode.java
===================================================================
--- trunk/freenet/src/freenet/node/SeedServerPeerNode.java 2007-12-05
17:40:04 UTC (rev 16338)
+++ trunk/freenet/src/freenet/node/SeedServerPeerNode.java 2007-12-05
20:25:30 UTC (rev 16339)
@@ -5,6 +5,7 @@
import freenet.io.comm.PeerParseException;
import freenet.io.comm.ReferenceSignatureVerificationException;
+import freenet.support.Logger;
import freenet.support.SimpleFieldSet;
/**
@@ -49,4 +50,15 @@
return false;
}
+ protected void sendInitialMessages() {
+ super.sendInitialMessages();
+ OpennetManager om = node.getOpennet();
+ if(om == null) {
+ Logger.normal(this, "Opennet turned off while
connecting to seednodes");
+ node.peers.disconnect(this, true, true);
+ } else {
+ om.announcer.maybeSendAnnouncement();
+ }
+ }
+
}