Author: toad
Date: 2007-06-29 23:35:54 +0000 (Fri, 29 Jun 2007)
New Revision: 13837
Added:
trunk/freenet/src/freenet/node/NodeIPPortDetector.java
Modified:
trunk/freenet/src/freenet/node/FNPPacketMangler.java
trunk/freenet/src/freenet/node/IPDetectorPluginManager.java
trunk/freenet/src/freenet/node/Node.java
trunk/freenet/src/freenet/node/NodeARKInserter.java
trunk/freenet/src/freenet/node/NodeCrypto.java
trunk/freenet/src/freenet/node/NodeCryptoConfig.java
trunk/freenet/src/freenet/node/NodeIPDetector.java
trunk/freenet/src/freenet/node/OutgoingPacketMangler.java
trunk/freenet/src/freenet/node/PeerNode.java
Log:
Lots more refactoring:
- Peer detection split into global address detection and port (NodeCrypto) -
specific peer detection
- Opennet refs should now therefore include the correct port
- ARKs are inserted for both opennet and darknet
Modified: trunk/freenet/src/freenet/node/FNPPacketMangler.java
===================================================================
--- trunk/freenet/src/freenet/node/FNPPacketMangler.java 2007-06-29
23:14:12 UTC (rev 13836)
+++ trunk/freenet/src/freenet/node/FNPPacketMangler.java 2007-06-29
23:35:54 UTC (rev 13837)
@@ -1558,4 +1558,8 @@
public SocketHandler getSocketHandler() {
return sock;
}
+
+ public Peer[] getPrimaryIPAddress() {
+ return crypto.detector.getPrimaryPeers();
+ }
}
Modified: trunk/freenet/src/freenet/node/IPDetectorPluginManager.java
===================================================================
--- trunk/freenet/src/freenet/node/IPDetectorPluginManager.java 2007-06-29
23:14:12 UTC (rev 13836)
+++ trunk/freenet/src/freenet/node/IPDetectorPluginManager.java 2007-06-29
23:35:54 UTC (rev 13837)
@@ -4,6 +4,7 @@
import java.util.HashSet;
import java.util.Vector;
+import freenet.io.comm.FreenetInetAddress;
import freenet.io.comm.Peer;
import freenet.l10n.L10n;
import freenet.node.useralerts.ProxyUserAlert;
@@ -239,7 +240,7 @@
if(logMINOR) Logger.minor(this, "Maybe running IP detection
plugins", new Exception("debug"));
PeerNode[] peers = node.getPeerNodes();
PeerNode[] conns = node.getConnectedPeers();
- Peer[] nodeAddrs = detector.getPrimaryIPAddress();
+ FreenetInetAddress[] nodeAddrs = detector.getPrimaryIPAddress();
long now = System.currentTimeMillis();
synchronized(this) {
if(plugins.length == 0) {
@@ -407,7 +408,7 @@
* @param nodeAddrs Our peers' addresses.
* @return True if we should run a detection.
*/
- private boolean shouldDetectDespiteRealIP(long now, PeerNode[] peers,
Peer[] nodeAddrs) {
+ private boolean shouldDetectDespiteRealIP(long now, PeerNode[] peers,
FreenetInetAddress[] nodeAddrs) {
// We might still be firewalled?
// First, check only once per day or startup
if(now - lastDetectAttemptEndedTime < 12*60*60*1000) {
@@ -432,7 +433,7 @@
// Is it internal?
boolean internal = false;
for(int
j=0;j<nodeAddrs.length;j++) {
-
if(addr.equals(nodeAddrs[j].getAddress())) {
+
if(addr.equals(nodeAddrs[j])) {
// Internal
internal = true;
break;
Modified: trunk/freenet/src/freenet/node/Node.java
===================================================================
--- trunk/freenet/src/freenet/node/Node.java 2007-06-29 23:14:12 UTC (rev
13836)
+++ trunk/freenet/src/freenet/node/Node.java 2007-06-29 23:35:54 UTC (rev
13837)
@@ -598,6 +598,10 @@
usm = new MessageCore();
+ // FIXME maybe these configs should actually be under a node.ip
subconfig?
+ ipDetector = new NodeIPDetector(this);
+ sortOrder = ipDetector.registerConfigs(nodeConfig, sortOrder);
+
// Determine the port number
NodeCryptoConfig darknetConfig = new
NodeCryptoConfig(nodeConfig, sortOrder++);
@@ -607,9 +611,6 @@
// Must be created after darknetCrypto
dnsr = new DNSRequester(this);
ps = new PacketSender(this);
- // FIXME maybe these configs should actually be under a node.ip
subconfig?
- ipDetector = new NodeIPDetector(this, darknetCrypto);
- sortOrder = ipDetector.registerConfigs(nodeConfig, sortOrder);
Logger.normal(Node.class, "Creating node...");
@@ -2587,4 +2588,17 @@
public SimpleFieldSet exportDarknetPrivateFieldSet() {
return darknetCrypto.exportPrivateFieldSet();
}
+
+ /**
+ * Should the IP detection code only use the IP address override and
the bindTo information,
+ * rather than doing a full detection?
+ */
+ public synchronized boolean dontDetect() {
+ // Only return true if bindTo is set on all ports which are in
use
+ if(!darknetCrypto.bindto.isRealInternetAddress(false, true))
return false;
+ if(opennet != null) {
+ if(opennet.crypto.bindto.isRealInternetAddress(false,
true)) return false;
+ }
+ return true;
+ }
}
Modified: trunk/freenet/src/freenet/node/NodeARKInserter.java
===================================================================
--- trunk/freenet/src/freenet/node/NodeARKInserter.java 2007-06-29 23:14:12 UTC
(rev 13836)
+++ trunk/freenet/src/freenet/node/NodeARKInserter.java 2007-06-29 23:35:54 UTC
(rev 13837)
@@ -30,14 +30,14 @@
*/
private final Node node;
private final NodeCrypto crypto;
- private final NodeIPDetector detector;
+ private final NodeIPPortDetector detector;
private static boolean logMINOR;
/**
* @param node
* @param old If true, use the old ARK rather than the new ARK
*/
- NodeARKInserter(Node node, NodeCrypto crypto, NodeIPDetector detector) {
+ NodeARKInserter(Node node, NodeCrypto crypto, NodeIPPortDetector
detector) {
this.node = node;
this.crypto = crypto;
this.detector = detector;
@@ -82,7 +82,7 @@
}
private boolean checkIPUpdated() {
- Peer[] p = detector.getPrimaryIPAddress();
+ Peer[] p = detector.detectPrimaryPeers();
if(p == null) {
if(logMINOR) Logger.minor(this, "Not inserting because
no IP address");
return false; // no point inserting
Modified: trunk/freenet/src/freenet/node/NodeCrypto.java
===================================================================
--- trunk/freenet/src/freenet/node/NodeCrypto.java 2007-06-29 23:14:12 UTC
(rev 13836)
+++ trunk/freenet/src/freenet/node/NodeCrypto.java 2007-06-29 23:35:54 UTC
(rev 13837)
@@ -23,6 +23,7 @@
import freenet.crypt.Global;
import freenet.crypt.RandomSource;
import freenet.crypt.SHA256;
+import freenet.io.comm.FreenetInetAddress;
import freenet.io.comm.Peer;
import freenet.io.comm.UdpSocketHandler;
import freenet.keys.FreenetURI;
@@ -45,7 +46,7 @@
/** The object which handles our specific UDP port, pulls messages from
it, feeds them to the packet mangler for decryption etc */
UdpSocketHandler socket;
public FNPPacketMangler packetMangler;
- final InetAddress bindto;
+ final FreenetInetAddress bindto;
// FIXME: abstract out address stuff? Possibly to something like
NodeReference?
final int portNumber;
byte[] myIdentity; // FIXME: simple identity block; should be unique
@@ -65,6 +66,7 @@
long myARKNumber;
static boolean logMINOR;
final NodeCryptoConfig config;
+ final NodeIPPortDetector detector;
// Noderef related
/** The signature of the above fieldset */
@@ -103,7 +105,7 @@
for(int i=0;i<200000;i++) {
int portNo = 1024 + random.nextInt(65535-1024);
try {
- u = new UdpSocketHandler(portNo,
bindto, node);
+ u = new UdpSocketHandler(portNo,
bindto.getAddress(), node);
port = u.getPortNumber();
break;
} catch (Exception e) {
@@ -117,7 +119,7 @@
throw new
NodeInitException(NodeInitException.EXIT_NO_AVAILABLE_UDP_PORTS, "Could not
find an available UDP port number for FNP (none specified)");
} else {
try {
- u = new UdpSocketHandler(port, bindto, node);
+ u = new UdpSocketHandler(port,
bindto.getAddress(), node);
} catch (Exception e) {
throw new
NodeInitException(NodeInitException.EXIT_IMPOSSIBLE_USM_PORT, "Could not bind
to port: "+port+" (node already running?)");
}
@@ -132,6 +134,9 @@
((UdpSocketHandler)socket).setDropProbability(config.getDropProbability());
socket.setLowLevelFilter(packetMangler = new
FNPPacketMangler(node, this, socket));
+
+ detector = new NodeIPPortDetector(node, node.ipDetector, this);
+
} catch (NodeInitException e) {
config.stopping(this);
throw e;
@@ -255,7 +260,7 @@
SimpleFieldSet exportPublicFieldSet(boolean forSetup) {
SimpleFieldSet fs = exportPublicCryptoFieldSet(forSetup);
// IP addresses
- Peer[] ips = node.ipDetector.getPrimaryIPAddress();
+ Peer[] ips = detector.detectPrimaryPeers();
if(ips != null) {
for(int i=0;i<ips.length;i++)
fs.putAppend("physical.udp",
ips[i].toString()); // Keep; important that node know all our IPs
@@ -376,5 +381,13 @@
socket.close(true);
config.stopping(this);
}
+
+ public PeerNode[] getPeerNodes() {
+ if(node.peers == null) return null;
+ if(isOpennet)
+ return node.peers.getOpennetPeers();
+ else
+ return node.peers.getDarknetPeers();
+ }
}
Modified: trunk/freenet/src/freenet/node/NodeCryptoConfig.java
===================================================================
--- trunk/freenet/src/freenet/node/NodeCryptoConfig.java 2007-06-29
23:14:12 UTC (rev 13836)
+++ trunk/freenet/src/freenet/node/NodeCryptoConfig.java 2007-06-29
23:35:54 UTC (rev 13837)
@@ -3,7 +3,6 @@
* http://www.gnu.org/ for further details of the GPL. */
package freenet.node;
-import java.net.InetAddress;
import java.net.UnknownHostException;
import freenet.config.InvalidConfigValueException;
@@ -26,7 +25,7 @@
private int portNumber;
/** Bind address. 0.0.0.0 = all addresses. */
- private InetAddress bindTo;
+ private FreenetInetAddress bindTo;
/** If nonzero, 1/dropProbability = probability of UdpSocketHandler
dropping a packet (for debugging
* purposes; not static as we may need to simulate some nodes with more
loss than others). */
@@ -79,7 +78,8 @@
config.register("bindTo", "0.0.0.0", sortOrder++, true, true,
"Node.bindTo", "Node.bindToLong", new NodeBindtoCallback());
try {
- bindTo =
InetAddress.getByName(config.getString("bindTo"));
+ bindTo = new
FreenetInetAddress(config.getString("bindTo"), false);
+
} catch (UnknownHostException e) {
throw new
NodeInitException(NodeInitException.EXIT_COULD_NOT_BIND_USM, "Invalid bindTo:
"+config.getString("bindTo"));
}
@@ -137,7 +137,7 @@
class NodeBindtoCallback implements StringCallback {
public String get() {
- return FreenetInetAddress.getHostName(bindTo);
+ return bindTo.toString();
}
public void set(String val) throws InvalidConfigValueException {
@@ -147,7 +147,7 @@
}
}
- public InetAddress getBindTo() {
+ public FreenetInetAddress getBindTo() {
return bindTo;
}
Modified: trunk/freenet/src/freenet/node/NodeIPDetector.java
===================================================================
--- trunk/freenet/src/freenet/node/NodeIPDetector.java 2007-06-29 23:14:12 UTC
(rev 13836)
+++ trunk/freenet/src/freenet/node/NodeIPDetector.java 2007-06-29 23:35:54 UTC
(rev 13837)
@@ -11,7 +11,6 @@
import freenet.config.SubConfig;
import freenet.io.comm.FreenetInetAddress;
import freenet.io.comm.Peer;
-import freenet.io.comm.UdpSocketHandler;
import freenet.l10n.L10n;
import freenet.node.useralerts.IPUndetectedUserAlert;
import freenet.node.useralerts.SimpleUserAlert;
@@ -24,11 +23,14 @@
import freenet.support.transport.ip.IPAddressDetector;
import freenet.support.transport.ip.IPUtil;
+/**
+ * Detect the IP address of the node. Doesn't return port numbers, doesn't
have access to per-port
+ * information (NodeCrypto - UdpSocketHandler etc).
+ */
public class NodeIPDetector {
/** Parent node */
final Node node;
- final NodeCrypto crypto;
/** Ticker */
final Ticker ticker;
/** Explicit forced IP address */
@@ -38,70 +40,68 @@
/** Detected IP's and their NAT status from plugins */
DetectedIP[] pluginDetectedIPs;
/** Last detected IP address */
- Peer[] lastIPAddress;
+ FreenetInetAddress[] lastIPAddress;
/** The minimum reported MTU on all detected interfaces */
private int minimumMTU;
/** IP address detector */
private final IPAddressDetector ipDetector;
/** Plugin manager for plugin IP address detectors e.g. STUN */
- private final IPDetectorPluginManager ipDetectorManager;
+ final IPDetectorPluginManager ipDetectorManager;
/** UserAlert shown when we can't detect an IP address */
private static IPUndetectedUserAlert primaryIPUndetectedAlert;
// FIXME redundant? see lastIPAddress
- Peer[] lastIP;
+ FreenetInetAddress[] lastIP;
/** If true, include local addresses on noderefs */
public boolean includeLocalAddressesInNoderefs;
- /** ARK inserter. */
- private final NodeARKInserter arkPutter;
/** Set when we have grounds to believe that we may be behind a
symmetric NAT. */
boolean maybeSymmetric;
private boolean hasDetectedPM;
private boolean hasDetectedIAD;
+ /** Subsidiary detectors: NodeIPPortDetector's which rely on this
object */
+ private NodeIPPortDetector[] portDetectors;
SimpleUserAlert maybeSymmetricAlert;
- public NodeIPDetector(Node node, NodeCrypto crypto) {
+ public NodeIPDetector(Node node) {
this.node = node;
- this.crypto = crypto;
this.ticker = node.ps;
ipDetectorManager = new IPDetectorPluginManager(node, this);
ipDetector = new IPAddressDetector(10*1000, this);
primaryIPUndetectedAlert = new IPUndetectedUserAlert(node);
- arkPutter = new NodeARKInserter(node, crypto, this);
+ portDetectors = new NodeIPPortDetector[0];
}
+ public synchronized void addPortDetector(NodeIPPortDetector detector) {
+ NodeIPPortDetector[] newDetectors = new
NodeIPPortDetector[portDetectors.length+1];
+ System.arraycopy(portDetectors, 0, newDetectors, 0,
portDetectors.length);
+ newDetectors[portDetectors.length] = detector;
+ portDetectors = newDetectors;
+ }
+
/**
- * @return Our current main IP address.
- * FIXME - we should support more than 1, and we should do the
- * detection properly with NetworkInterface, and we should use
- * third parties if available and UP&P if available.
+ * What is my IP address? Use all globally available information
(everything which isn't
+ * specific to a given port i.e. opennet or darknet) to determine our
current IP addresses.
+ * Will include more than one IP in many cases when we are not strictly
multi-homed. For
+ * example, if we have a DNS name set, we will usually return an IP as
well; if we are
+ * behind a NAT we may return both a rewritten port number and the
original; etc.
+ *
+ * Will warn the user with a UserAlert if we don't have sufficient
information.
*/
- Peer[] detectPrimaryIPAddress() {
+ FreenetInetAddress[] detectPrimaryIPAddress() {
boolean addedValidIP = false;
- int portNumber = crypto.portNumber;
Logger.minor(this, "Redetecting IPs...");
Vector addresses = new Vector();
if(overrideIPAddress != null) {
// If the IP is overridden, the override has to be the
first element.
- Peer p = new Peer(overrideIPAddress, portNumber);
- addresses.add(p);
- if(p.getFreenetAddress().isRealInternetAddress(false,
true))
+ addresses.add(overrideIPAddress);
+ if(overrideIPAddress.isRealInternetAddress(false, true))
addedValidIP = true;
}
- boolean dontDetect = false;
- UdpSocketHandler sock = crypto.socket;
- if(sock != null) {
- InetAddress addr = sock.getBindTo();
- if(addr != null && (IPUtil.isValidAddress(addr,
false))) {
- dontDetect = true;
- Peer p = new Peer(addr, portNumber);
- if(!addresses.contains(p)) addresses.add(p);
- dontDetect = true;
- }
+
+ if(!node.dontDetect()) {
+ addedValidIP |= innerDetect(addresses);
}
- if(!dontDetect) {
- addedValidIP = innerDetect(addresses, addedValidIP,
portNumber);
- }
+
if(node.clientCore != null) {
if (addedValidIP) {
node.clientCore.alerts.unregister(primaryIPUndetectedAlert);
@@ -109,24 +109,29 @@
node.clientCore.alerts.register(primaryIPUndetectedAlert);
}
}
- lastIPAddress = (Peer[]) addresses.toArray(new
Peer[addresses.size()]);
+ lastIPAddress = (FreenetInetAddress[]) addresses.toArray(new
FreenetInetAddress[addresses.size()]);
return lastIPAddress;
}
- private boolean innerDetect(Vector addresses, boolean addedValidIP, int
portNumber) {
- boolean setMaybeSymmetric = false;
+ /**
+ * Core of the IP detection algorithm.
+ * @param addresses
+ * @param addedValidIP
+ * @return
+ */
+ private boolean innerDetect(Vector addresses) {
+ boolean addedValidIP = false;
InetAddress[] detectedAddrs = ipDetector.getAddress();
assert(detectedAddrs != null);
synchronized(this) {
hasDetectedIAD = true;
}
-
for(int i=0;i<detectedAddrs.length;i++) {
- Peer p = new Peer(detectedAddrs[i], portNumber);
- if(!addresses.contains(p)) {
- Logger.normal(this, "Detected IP address: "+p);
- addresses.add(p);
-
if(p.getFreenetAddress().isRealInternetAddress(false, false))
+ FreenetInetAddress addr = new
FreenetInetAddress(detectedAddrs[i]);
+ if(!addresses.contains(addr)) {
+ Logger.normal(this, "Detected IP address:
"+addr);
+ addresses.add(addr);
+ if(addr.isRealInternetAddress(false, false))
addedValidIP = true;
}
}
@@ -135,7 +140,7 @@
for(int i=0;i<pluginDetectedIPs.length;i++) {
InetAddress addr =
pluginDetectedIPs[i].publicAddress;
if(addr == null) continue;
- Peer a = new Peer(new FreenetInetAddress(addr),
portNumber);
+ FreenetInetAddress a = new
FreenetInetAddress(addr);
if(!addresses.contains(a)) {
Logger.normal(this, "Plugin detected IP
address: "+a);
addresses.add(a);
@@ -143,8 +148,10 @@
}
}
}
+
if(addresses.isEmpty() && (oldIPAddress != null) &&
!oldIPAddress.equals(overrideIPAddress))
- addresses.add(new Peer(oldIPAddress, portNumber));
+ addresses.add(oldIPAddress);
+
// Try to pick it up from our connections
if(node.peers != null) {
PeerNode[] peerList = node.peers.connectedPeers;
@@ -152,36 +159,38 @@
// FIXME use a standard mutable int object, we have one
somewhere
for(int i=0;i<peerList.length;i++) {
Peer p = peerList[i].getRemoteDetectedPeer();
- if((p == null) || p.isNull()) continue;
+ if(p == null || p.isNull()) continue;
+ FreenetInetAddress addr = p.getFreenetAddress();
+ if(addr == null) continue;
// DNSRequester doesn't deal with our own node
- if(!IPUtil.isValidAddress(p.getAddress(true),
false)) continue;
- Logger.normal(this, "Peer
"+peerList[i].getPeer()+" thinks we are "+p);
- if(countsByPeer.containsKey(p)) {
- Integer count = (Integer)
countsByPeer.get(p);
+
if(!IPUtil.isValidAddress(addr.getAddress(false), false)) continue;
+ Logger.normal(this, "Peer
"+peerList[i].getPeer()+" thinks we are "+addr);
+ if(countsByPeer.containsKey(addr)) {
+ Integer count = (Integer)
countsByPeer.get(addr);
Integer newCount = new
Integer(count.intValue()+1);
- countsByPeer.put(p, newCount);
+ countsByPeer.put(addr, newCount);
} else {
- countsByPeer.put(p, new Integer(1));
+ countsByPeer.put(addr, new Integer(1));
}
}
if(countsByPeer.size() == 1) {
Iterator it = countsByPeer.keySet().iterator();
- Peer p = (Peer) (it.next());
- Logger.minor(this, "Everyone agrees we are "+p);
- if(!addresses.contains(p)) {
-
if(p.getFreenetAddress().isRealInternetAddress(false, false))
+ FreenetInetAddress addr = (FreenetInetAddress)
(it.next());
+ Logger.minor(this, "Everyone agrees we are
"+addr);
+ if(!addresses.contains(addr)) {
+ if(addr.isRealInternetAddress(false,
false))
addedValidIP = true;
- addresses.add(p);
+ addresses.add(addr);
}
} else if(countsByPeer.size() > 1) {
Iterator it = countsByPeer.keySet().iterator();
// Take two most popular addresses.
- Peer best = null;
- Peer secondBest = null;
+ FreenetInetAddress best = null;
+ FreenetInetAddress secondBest = null;
int bestPopularity = 0;
int secondBestPopularity = 0;
while(it.hasNext()) {
- Peer cur = (Peer) (it.next());
+ FreenetInetAddress cur =
(FreenetInetAddress) (it.next());
int curPop = ((Integer)
(countsByPeer.get(cur))).intValue();
Logger.normal(this, "Detected peer:
"+cur+" popularity "+curPop);
if(curPop >= bestPopularity) {
@@ -196,46 +205,24 @@
if(!addresses.contains(best)) {
Logger.normal(this,
"Adding best peer "+best+" ("+bestPopularity+ ')');
addresses.add(best);
-
if(best.getFreenetAddress().isRealInternetAddress(false, false))
+
if(best.isRealInternetAddress(false, false))
addedValidIP =
true;
}
if((secondBest != null) &&
(secondBestPopularity > 1)) {
if(!addresses.contains(secondBest)) {
Logger.normal(this, "Adding second best peer "+secondBest+" ("+secondBest+ ')');
addresses.add(secondBest);
-
if(secondBest.getFreenetAddress().isRealInternetAddress(false, false))
+
if(secondBest.isRealInternetAddress(false, false))
addedValidIP = true;
}
-
if(best.getAddress().equals(secondBest.getAddress()) && bestPopularity == 1) {
-
Logger.error(this, "Hrrrm, maybe this is a symmetric NAT? Expect trouble
connecting!");
-
System.err.println("Hrrrm, maybe this is a symmetric NAT? Expect trouble
connecting!");
-
setMaybeSymmetric = true;
-
-
if(ipDetectorManager != null && ipDetectorManager.isEmpty()) {
-
if(maybeSymmetricAlert == null) {
-
maybeSymmetricAlert = new SimpleUserAlert(true, l10n("maybeSymmetricTitle"),
-
l10n("maybeSymmetric"), UserAlert.ERROR);
- }
-
if(node.clientCore != null && node.clientCore.alerts != null)
-
node.clientCore.alerts.register(maybeSymmetricAlert);
- } else {
-
if(maybeSymmetricAlert != null)
-
node.clientCore.alerts.unregister(maybeSymmetricAlert);
- }
-
- Peer p = new
Peer(best.getFreenetAddress(), portNumber);
-
if(!addresses.contains(p))
-
addresses.add(p);
- }
}
}
}
}
}
- this.maybeSymmetric = setMaybeSymmetric;
return addedValidIP;
}
-
+
private String l10n(String key) {
return L10n.getString("NodeIPDetector."+key);
}
@@ -244,7 +231,7 @@
return L10n.getString("NodeIPDetector."+key, pattern, value);
}
- Peer[] getPrimaryIPAddress() {
+ FreenetInetAddress[] getPrimaryIPAddress() {
if(lastIPAddress == null) return detectPrimaryIPAddress();
return lastIPAddress;
}
@@ -277,16 +264,18 @@
}
}
redetectAddress();
- arkPutter.update();
}
public void redetectAddress() {
- Peer[] newIP = detectPrimaryIPAddress();
+ FreenetInetAddress[] newIP = detectPrimaryIPAddress();
+ NodeIPPortDetector[] detectors;
synchronized(this) {
if(Arrays.equals(newIP, lastIP)) return;
lastIP = newIP;
+ detectors = portDetectors;
}
- arkPutter.update();
+ for(int i=0;i<detectors.length;i++)
+ detectors[i].update();
node.writeNodeFile();
}
@@ -411,7 +400,12 @@
// 60 second delay for inserting ARK to avoid reinserting more
than necessary if we don't detect IP on startup.
ticker.queueTimedJob(new FastRunnable() {
public void run() {
- arkPutter.start();
+ NodeIPPortDetector[] detectors;
+ synchronized(this) {
+ detectors = portDetectors;
+ }
+ for(int i=0;i<detectors.length;i++)
+ detectors[i].startARK();
}
}, 60*1000);
}
@@ -437,5 +431,19 @@
public int getMinimumDetectedMTU() {
return minimumMTU > 0 ? minimumMTU : 1500;
}
+
+ public void setMaybeSymmetric() {
+ if(ipDetectorManager != null && ipDetectorManager.isEmpty()) {
+ if(maybeSymmetricAlert == null) {
+ maybeSymmetricAlert = new SimpleUserAlert(true,
l10n("maybeSymmetricTitle"),
+ l10n("maybeSymmetric"),
UserAlert.ERROR);
+ }
+ if(node.clientCore != null && node.clientCore.alerts !=
null)
+
node.clientCore.alerts.register(maybeSymmetricAlert);
+ } else {
+ if(maybeSymmetricAlert != null)
+
node.clientCore.alerts.unregister(maybeSymmetricAlert);
+ }
+ }
}
Added: trunk/freenet/src/freenet/node/NodeIPPortDetector.java
===================================================================
--- trunk/freenet/src/freenet/node/NodeIPPortDetector.java
(rev 0)
+++ trunk/freenet/src/freenet/node/NodeIPPortDetector.java 2007-06-29
23:35:54 UTC (rev 13837)
@@ -0,0 +1,156 @@
+/* This code is part of Freenet. It is distributed under the GNU General
+ * Public License, version 2 (or at your option any later version). See
+ * http://www.gnu.org/ for further details of the GPL. */
+package freenet.node;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Vector;
+
+import freenet.io.comm.FreenetInetAddress;
+import freenet.io.comm.Peer;
+import freenet.support.Logger;
+import freenet.support.transport.ip.IPUtil;
+
+/**
+ * Combine the detected IP address with the NodeCrypto's port number and the
port numbers we have
+ * on connections in the given class to get a list of Peer's.
+ * @author toad
+ */
+public class NodeIPPortDetector {
+
+ /** The Node object */
+ final Node node;
+ /** The NodeIPDetector which determines the node's IP address but not
its port number */
+ final NodeIPDetector ipDetector;
+ /** The NodeCrypto with the node's port number */
+ final NodeCrypto crypto;
+ /** ARK inserter. */
+ private final NodeARKInserter arkPutter;
+ /** Last detected IP address */
+ Peer[] lastPeers;
+
+ NodeIPPortDetector(Node node, NodeIPDetector ipDetector, NodeCrypto
crypto) {
+ this.node = node;
+ this.ipDetector = ipDetector;
+ this.crypto = crypto;
+ arkPutter = new NodeARKInserter(node, crypto, this);
+ }
+
+ /**
+ * Combine the NodeIPDetector's output with any per-port information we
may have to get a definitive
+ * (for that port/NodeCrypto) list of IP addresses (still without port
numbers).
+ */
+ FreenetInetAddress[] detectPrimaryIPAddress() {
+ FreenetInetAddress[] addresses =
ipDetector.detectPrimaryIPAddress();
+ FreenetInetAddress addr = crypto.bindto;
+ if(addr.isRealInternetAddress(false, true)) {
+ for(int i=0;i<addresses.length;i++) {
+ if(addresses[i] == addr) return addresses;
+ }
+ FreenetInetAddress[] newAddresses = new
FreenetInetAddress[addresses.length+1];
+ System.arraycopy(addresses, 0, newAddresses, 0,
addresses.length);
+ return newAddresses;
+ }
+ return addresses;
+ }
+
+ Peer[] detectPrimaryPeers() {
+ Vector addresses = new Vector();
+ FreenetInetAddress[] addrs = detectPrimaryIPAddress();
+ for(int i=0;i<addrs.length;i++) {
+ addresses.add(new Peer(addrs[i], crypto.portNumber));
+ }
+ // Now try to get the rewritten port number from our peers.
+ // Only considering those within this crypto port, this time.
+
+ PeerNode[] peerList = crypto.getPeerNodes();
+
+ if(peerList != null) {
+ HashMap countsByPeer = new HashMap();
+ // FIXME use a standard mutable int object, we have one
somewhere
+ for(int i=0;i<peerList.length;i++) {
+ Peer p = peerList[i].getRemoteDetectedPeer();
+ if((p == null) || p.isNull()) continue;
+ // DNSRequester doesn't deal with our own node
+ if(!IPUtil.isValidAddress(p.getAddress(true),
false)) continue;
+ Logger.normal(this, "Peer
"+peerList[i].getPeer()+" thinks we are "+p);
+ if(countsByPeer.containsKey(p)) {
+ Integer count = (Integer)
countsByPeer.get(p);
+ Integer newCount = new
Integer(count.intValue()+1);
+ countsByPeer.put(p, newCount);
+ } else {
+ countsByPeer.put(p, new Integer(1));
+ }
+ }
+ if(countsByPeer.size() == 1) {
+ Iterator it = countsByPeer.keySet().iterator();
+ Peer p = (Peer) (it.next());
+ Logger.minor(this, "Everyone agrees we are "+p);
+ if(!addresses.contains(p)) {
+ addresses.add(p);
+ }
+ } else if(countsByPeer.size() > 1) {
+ Iterator it = countsByPeer.keySet().iterator();
+ // Take two most popular addresses.
+ Peer best = null;
+ Peer secondBest = null;
+ int bestPopularity = 0;
+ int secondBestPopularity = 0;
+ while(it.hasNext()) {
+ Peer cur = (Peer) (it.next());
+ int curPop = ((Integer)
(countsByPeer.get(cur))).intValue();
+ Logger.normal(this, "Detected peer:
"+cur+" popularity "+curPop);
+ if(curPop >= bestPopularity) {
+ secondBestPopularity =
bestPopularity;
+ bestPopularity = curPop;
+ secondBest = best;
+ best = cur;
+ }
+ }
+ if(best != null) {
+ if((bestPopularity > 1) ||
(addrs.length == 0)) {
+ if(!addresses.contains(best)) {
+ Logger.normal(this,
"Adding best peer "+best+" ("+bestPopularity+ ')');
+ addresses.add(best);
+ }
+ if((secondBest != null) &&
(secondBestPopularity > 1)) {
+
if(!addresses.contains(secondBest)) {
+
Logger.normal(this, "Adding second best peer "+secondBest+" ("+secondBest+ ')');
+
addresses.add(secondBest);
+ }
+
if(best.getAddress().equals(secondBest.getAddress()) && bestPopularity == 1) {
+
Logger.error(this, "Hrrrm, maybe this is a symmetric NAT? Expect trouble
connecting!");
+
System.err.println("Hrrrm, maybe this is a symmetric NAT? Expect trouble
connecting!");
+
+
ipDetector.setMaybeSymmetric();
+
+ Peer p = new
Peer(best.getFreenetAddress(), crypto.portNumber);
+
if(!addresses.contains(p))
+
addresses.add(p);
+
+ }
+ }
+ }
+ }
+ }
+ }
+ lastPeers = (Peer[]) addresses.toArray(new
Peer[addresses.size()]);
+ return lastPeers;
+ }
+
+ void update() {
+ arkPutter.update();
+ }
+
+ void startARK() {
+ arkPutter.start();
+ }
+
+ public Peer[] getPrimaryPeers() {
+ if(lastPeers == null)
+ return detectPrimaryPeers();
+ else
+ return lastPeers;
+ }
+}
Modified: trunk/freenet/src/freenet/node/OutgoingPacketMangler.java
===================================================================
--- trunk/freenet/src/freenet/node/OutgoingPacketMangler.java 2007-06-29
23:14:12 UTC (rev 13836)
+++ trunk/freenet/src/freenet/node/OutgoingPacketMangler.java 2007-06-29
23:35:54 UTC (rev 13837)
@@ -5,6 +5,7 @@
import freenet.io.comm.AsyncMessageCallback;
import freenet.io.comm.NotConnectedException;
+import freenet.io.comm.Peer;
import freenet.io.comm.PeerContext;
import freenet.io.comm.SocketHandler;
import freenet.support.WouldBlockException;
@@ -90,4 +91,8 @@
*/
public SocketHandler getSocketHandler();
+ /**
+ * Get our addresses, as peers.
+ */
+ public Peer[] getPrimaryIPAddress();
}
Modified: trunk/freenet/src/freenet/node/PeerNode.java
===================================================================
--- trunk/freenet/src/freenet/node/PeerNode.java 2007-06-29 23:14:12 UTC
(rev 13836)
+++ trunk/freenet/src/freenet/node/PeerNode.java 2007-06-29 23:35:54 UTC
(rev 13837)
@@ -749,8 +749,7 @@
// Hack for two nodes on the same IP that can't talk over inet for
routing reasons
FreenetInetAddress localhost = node.fLocalhostAddress;
- Peer[] nodePeers = node.ipDetector.getPrimaryIPAddress();
-// FreenetInetAddress nodeAddr = node.getPrimaryIPAddress();
+ Peer[] nodePeers = outgoingMangler.getPrimaryIPAddress();
Vector peers = null;
synchronized(this) {