diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ConfigNetHandler.java b/apps/routerconsole/java/src/net/i2p/router/web/ConfigNetHandler.java index 42290cb15..7c0518a92 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigNetHandler.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigNetHandler.java @@ -16,6 +16,7 @@ import java.util.Iterator; import java.util.Set; import net.i2p.time.Timestamper; +import net.i2p.router.transport.udp.UDPTransport; /** * Handler to deal with form submissions from the main config form and act @@ -29,6 +30,7 @@ public class ConfigNetHandler extends FormHandler { private boolean _saveRequested; private boolean _recheckReachabilityRequested; private boolean _timeSyncEnabled; + private boolean _requireIntroductions; private String _tcpPort; private String _udpPort; private String _inboundRate; @@ -57,6 +59,7 @@ public class ConfigNetHandler extends FormHandler { public void setSave(String moo) { _saveRequested = true; } public void setEnabletimesync(String moo) { _timeSyncEnabled = true; } public void setRecheckReachability(String moo) { _recheckReachabilityRequested = true; } + public void setRequireIntroductions(String moo) { _requireIntroductions = true; } public void setHostname(String hostname) { _hostname = (hostname != null ? hostname.trim() : null); @@ -253,7 +256,14 @@ public class ConfigNetHandler extends FormHandler { } } - if (_timeSyncEnabled) { + if (_requireIntroductions) { + _context.router().setConfigSetting(UDPTransport.PROP_FORCE_INTRODUCERS, "true"); + addFormNotice("Requiring SSU introduers"); + } else { + _context.router().removeConfigSetting(UDPTransport.PROP_FORCE_INTRODUCERS); + } + + if (true || _timeSyncEnabled) { // Time sync enable, means NOT disabled _context.router().setConfigSetting(Timestamper.PROP_DISABLED, "false"); } else { diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ConfigNetHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/ConfigNetHelper.java index 12e01852a..12df19d01 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigNetHelper.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigNetHelper.java @@ -2,6 +2,9 @@ package net.i2p.router.web; import net.i2p.time.Timestamper; import net.i2p.router.RouterContext; +import net.i2p.router.CommSystemFacade; +import net.i2p.data.RouterAddress; +import net.i2p.router.transport.udp.UDPAddress; public class ConfigNetHelper { private RouterContext _context; @@ -43,19 +46,12 @@ public class ConfigNetHelper { return "" + port; } - public String getUdpPort() { - int port = 8887; - String val = _context.getProperty(PROP_I2NP_UDP_PORT); - if (val == null) - val = _context.getProperty(PROP_I2NP_INTERNAL_UDP_PORT); - if (val != null) { - try { - port = Integer.parseInt(val); - } catch (NumberFormatException nfe) { - // ignore, use default from above - } - } - return "" + port; + public String getUdpAddress() { + RouterAddress addr = _context.router().getRouterInfo().getTargetAddress("SSU"); + if (addr == null) + return "unknown"; + UDPAddress ua = new UDPAddress(addr); + return ua.toString(); } public String getEnableTimeSyncChecked() { @@ -66,6 +62,21 @@ public class ConfigNetHelper { return " checked "; } + public String getRequireIntroductionsChecked() { + short status = _context.commSystem().getReachabilityStatus(); + switch (status) { + case CommSystemFacade.STATUS_OK: + return ""; + case CommSystemFacade.STATUS_DIFFERENT: + case CommSystemFacade.STATUS_REJECT_UNSOLICITED: + return "checked=\"true\""; + case CommSystemFacade.STATUS_UNKNOWN: + return ""; + default: + return "checked=\"true\""; + } + } + public static final String PROP_INBOUND_KBPS = "i2np.bandwidth.inboundKBytesPerSecond"; public static final String PROP_OUTBOUND_KBPS = "i2np.bandwidth.outboundKBytesPerSecond"; public static final String PROP_INBOUND_BURST = "i2np.bandwidth.inboundBurstKBytes"; diff --git a/apps/routerconsole/jsp/config.jsp b/apps/routerconsole/jsp/config.jsp index 5edc79c0c..11b98ca41 100644 --- a/apps/routerconsole/jsp/config.jsp +++ b/apps/routerconsole/jsp/config.jsp @@ -28,14 +28,12 @@ " /> - UDP port:
- -You must poke a hole in your firewall or NAT (if applicable) to receive new inbound UDP packets on -this port from arbitrary peers (this requirement will be removed in i2p 0.6.1, but is necessary now)
- TCP port: " />
- You must poke a hole in your firewall or NAT (if applicable) so that you can receive inbound TCP - connections on it (this requirement will be removed in i2p 0.6.1, but is necessary now) -
+ External UDP address:
+ Require SSU introductions through NAT hole punching? + />
+

If you can't poke a hole in your NAT or firewall to allow unsolicited UDP packets to reach the + router, as detected with the Status: ERR-Reject, then you will need SSU introductions. + Users behind symmetric NATs, such as OpenBSD's pf, are not currently supported.


@@ -53,35 +51,8 @@ this port from arbitrary peers (this requirement will be removed in i2p 0.6.1, b
Sharing a higher percentage will improve your anonymity and help the network
- Enable internal time synchronization? name="enabletimesync" />
- If disabled, your machine must be NTP synchronized - your clock must always - be within a few seconds of "correct". You will need to be able to send outbound UDP - packets on port 123 to one of the pool.ntp.org machines (or some other SNTP server). -

- Changing the TCP or UDP port will force a 'soft restart' - dropping your connections and clients as - if the router was stopped and restarted. Please be patient - it may take - a few seconds to complete. -
- Advanced network config: -

- One advanced network option has to do with reseeding - you should never need to - reseed your router as long as you can find at least one other peer on the network. However, - when you do need to reseed, a link will show up on the left hand side which will - fetch all of the routerInfo-* files from http://dev.i2p.net/i2pdb/. That URL is just an - apache folder pointing at the netDb/ directory of a router - anyone can run one, and you can - configure your router to seed off an alternate URL by adding the java environmental property - "i2p.reseedURL=someURL" (e.g. java -Di2p.reseedURL=http://dev.i2p.net/i2pdb/ ...). You can - also do it manually by getting routerInfo-*.dat files from someone (a friend, someone on IRC, - whatever) and saving them to your netDb/ directory.

-

- With the SSU transport, the internal UDP port may be different from the external - UDP port (in case of a firewall/NAT) - the UDP port field above specifies the - external one and assumes they are the same, but if you want to set the internal - port to something else, you can add "i2np.udp.internalPort=1234" to the - advanced config and restart the router. -

diff --git a/history.txt b/history.txt index f48bb43c0..21d53ebb9 100644 --- a/history.txt +++ b/history.txt @@ -1,4 +1,11 @@ -$Id: history.txt,v 1.243 2005/09/09 23:30:37 jrandom Exp $ +$Id: history.txt,v 1.244 2005/09/10 22:22:52 jrandom Exp $ + +2005-09-12 jrandom + * More aggressively publish updated routerInfo. + * Expose the flag to force SSU introductions on the router console + * Don't give people the option to disable SNTP time sync, at least not + through the router console, because there is no reason to disable it. + No, not even if your OS is "ntp synced", because chances are, its not. 2005-09-10 jrandom * Test the router's reachability earlier and more aggressively diff --git a/router/java/src/net/i2p/data/i2np/DatabaseStoreMessage.java b/router/java/src/net/i2p/data/i2np/DatabaseStoreMessage.java index add6c9e5c..3bb22152b 100644 --- a/router/java/src/net/i2p/data/i2np/DatabaseStoreMessage.java +++ b/router/java/src/net/i2p/data/i2np/DatabaseStoreMessage.java @@ -132,7 +132,9 @@ public class DatabaseStoreMessage extends I2NPMessageImpl { curIndex += 4; if (_replyToken > 0) { - _replyTunnel = new TunnelId(DataHelper.fromLong(data, curIndex, 4)); + long tunnel = DataHelper.fromLong(data, curIndex, 4); + if (tunnel > 0) + _replyTunnel = new TunnelId(tunnel); curIndex += 4; byte gw[] = new byte[Hash.HASH_LENGTH]; @@ -202,7 +204,10 @@ public class DatabaseStoreMessage extends I2NPMessageImpl { curIndex += 4; if (_replyToken > 0) { - byte id[] = DataHelper.toLong(4, _replyTunnel.getTunnelId()); + long replyTunnel = 0; + if (_replyTunnel != null) + replyTunnel = _replyTunnel.getTunnelId(); + byte id[] = DataHelper.toLong(4, replyTunnel); System.arraycopy(id, 0, out, curIndex, 4); curIndex += 4; System.arraycopy(_replyGateway.getData(), 0, out, curIndex, Hash.HASH_LENGTH); diff --git a/router/java/src/net/i2p/router/RouterVersion.java b/router/java/src/net/i2p/router/RouterVersion.java index 35bddc109..48cd8b190 100644 --- a/router/java/src/net/i2p/router/RouterVersion.java +++ b/router/java/src/net/i2p/router/RouterVersion.java @@ -15,9 +15,9 @@ import net.i2p.CoreVersion; * */ public class RouterVersion { - public final static String ID = "$Revision: 1.230 $ $Date: 2005/09/09 23:30:36 $"; + public final static String ID = "$Revision: 1.231 $ $Date: 2005/09/10 22:22:52 $"; public final static String VERSION = "0.6.0.5"; - public final static long BUILD = 5; + public final static long BUILD = 6; public static void main(String args[]) { System.out.println("I2P Router version: " + VERSION + "-" + BUILD); System.out.println("Router ID: " + RouterVersion.ID); diff --git a/router/java/src/net/i2p/router/StatisticsManager.java b/router/java/src/net/i2p/router/StatisticsManager.java index 7079942a2..df7fbcc2b 100644 --- a/router/java/src/net/i2p/router/StatisticsManager.java +++ b/router/java/src/net/i2p/router/StatisticsManager.java @@ -230,47 +230,26 @@ public class StatisticsManager implements Service { return buf.toString(); } - private String renderThroughput(double bytes, long ms) { - if (bytes <= 0) - return "0;0;0;0;"; - else - return num(bytes/(ms/1000)) + ";0;0;0;"; - } - private void includeThroughput(Properties stats) { - double sendBytes5m = 0; - double sendBytes60m = 0; - double recvBytes5m = 0; - double recvBytes60m = 0; - - RateStat sendRate = _context.statManager().getRate("transport.sendMessageSize"); + RateStat sendRate = _context.statManager().getRate("bw.sendRate"); if (sendRate != null) { Rate r = sendRate.getRate(5*60*1000); if (r != null) - sendBytes5m = r.getLastTotalValue(); + stats.setProperty("stat_bandwidthSendBps.5m", num(r.getAverageValue()) + ';' + num(r.getExtremeAverageValue()) + ";0;0;"); r = sendRate.getRate(60*60*1000); if (r != null) - sendBytes60m = r.getLastTotalValue(); + stats.setProperty("stat_bandwidthSendBps.60m", num(r.getAverageValue()) + ';' + num(r.getExtremeAverageValue()) + ";0;0;"); } - RateStat recvRate = _context.statManager().getRate("transport.receiveMessageSize"); + RateStat recvRate = _context.statManager().getRate("bw.recvRate"); if (recvRate != null) { Rate r = recvRate.getRate(5*60*1000); if (r != null) - recvBytes5m = r.getLastTotalValue(); + stats.setProperty("stat_bandwidthReceiveBps.5m", num(r.getAverageValue()) + ';' + num(r.getExtremeAverageValue()) + ";0;0;"); r = recvRate.getRate(60*60*1000); if (r != null) - recvBytes60m = r.getLastTotalValue(); + stats.setProperty("stat_bandwidthReceiveBps.60m", num(r.getAverageValue()) + ';' + num(r.getExtremeAverageValue()) + ";0;0;"); } - - String throughputRate = renderThroughput(sendBytes5m, 5*60*1000); - stats.setProperty("stat_bandwidthSendBps.5m", throughputRate); - //throughputRate = renderThroughput(sendBytes60m, 60*60*1000); - //stats.setProperty("stat_bandwidthSendBps.60m", throughputRate); - throughputRate = renderThroughput(recvBytes5m, 5*60*1000); - stats.setProperty("stat_bandwidthReceiveBps.5m", throughputRate); - //throughputRate = renderThroughput(recvBytes60m, 60*60*1000); - //stats.setProperty("stat_bandwidthReceiveBps.60m", throughputRate); } diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillNetworkDatabaseFacade.java b/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillNetworkDatabaseFacade.java index 553b4c799..662b511a5 100644 --- a/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillNetworkDatabaseFacade.java +++ b/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillNetworkDatabaseFacade.java @@ -24,6 +24,16 @@ public class FloodfillNetworkDatabaseFacade extends KademliaNetworkDatabaseFacad _context.inNetMessagePool().registerHandlerJobBuilder(DatabaseStoreMessage.MESSAGE_TYPE, new FloodfillDatabaseStoreMessageHandler(_context, this)); } + private static final long PUBLISH_TIMEOUT = 30*1000; + + /** + * @throws IllegalArgumentException if the local router info is invalid + */ + public void publish(RouterInfo localRouterInfo) throws IllegalArgumentException { + super.publish(localRouterInfo); + sendStore(localRouterInfo.getIdentity().calculateHash(), localRouterInfo, null, null, PUBLISH_TIMEOUT, null); + } + public void sendStore(Hash key, DataStructure ds, Job onSuccess, Job onFailure, long sendTimeout, Set toIgnore) { // if we are a part of the floodfill netDb, don't send out our own leaseSets as part // of the flooding - instead, send them to a random floodfill peer so *they* can flood 'em out. diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillPeerSelector.java b/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillPeerSelector.java index 86b2c306a..15ecfebcb 100644 --- a/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillPeerSelector.java +++ b/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillPeerSelector.java @@ -34,6 +34,7 @@ class FloodfillPeerSelector extends PeerSelector { peersToIgnore = new HashSet(1); peersToIgnore.add(_context.router().getRouterInfo().getIdentity().getHash()); FloodfillSelectionCollector matches = new FloodfillSelectionCollector(key, peersToIgnore, maxNumRouters); + if (kbuckets == null) return new ArrayList(); kbuckets.getAll(matches); List rv = matches.get(maxNumRouters); if (_log.shouldLog(Log.DEBUG)) @@ -44,6 +45,7 @@ class FloodfillPeerSelector extends PeerSelector { } public List selectFloodfillParticipants(KBucketSet kbuckets) { + if (kbuckets == null) return new ArrayList(); FloodfillSelectionCollector matches = new FloodfillSelectionCollector(null, null, 0); kbuckets.getAll(matches); return matches.getFloodfillParticipants(); diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/StoreJob.java b/router/java/src/net/i2p/router/networkdb/kademlia/StoreJob.java index 623def4b6..aaccb6139 100644 --- a/router/java/src/net/i2p/router/networkdb/kademlia/StoreJob.java +++ b/router/java/src/net/i2p/router/networkdb/kademlia/StoreJob.java @@ -8,9 +8,7 @@ package net.i2p.router.networkdb.kademlia; * */ -import java.util.Iterator; -import java.util.List; -import java.util.Set; +import java.util.*; import net.i2p.data.DataStructure; import net.i2p.data.Hash; @@ -21,6 +19,7 @@ import net.i2p.data.i2np.DatabaseStoreMessage; import net.i2p.data.i2np.I2NPMessage; import net.i2p.router.Job; import net.i2p.router.JobImpl; +import net.i2p.router.OutNetMessage; import net.i2p.router.ReplyJob; import net.i2p.router.RouterContext; import net.i2p.router.TunnelInfo; @@ -198,7 +197,9 @@ class StoreJob extends JobImpl { //if (_log.shouldLog(Log.DEBUG)) // _log.debug(getJobId() + ": Current routing key for " + key + ": " + rkey); - return _peerSelector.selectNearestExplicit(rkey, numClosest, alreadyChecked, _facade.getKBuckets()); + KBucketSet ks = _facade.getKBuckets(); + if (ks == null) return new ArrayList(); + return _peerSelector.selectNearestExplicit(rkey, numClosest, alreadyChecked, ks); } /** @@ -231,13 +232,43 @@ class StoreJob extends JobImpl { } private void sendStore(DatabaseStoreMessage msg, RouterInfo peer, long expiration) { - if (msg.getValueType() == DatabaseStoreMessage.KEY_TYPE_LEASESET) + if (msg.getValueType() == DatabaseStoreMessage.KEY_TYPE_LEASESET) { getContext().statManager().addRateData("netDb.storeLeaseSetSent", 1, 0); - else + sendStoreThroughGarlic(msg, peer, expiration); + } else { getContext().statManager().addRateData("netDb.storeRouterInfoSent", 1, 0); - sendStoreThroughGarlic(msg, peer, expiration); + sendDirect(msg, peer, expiration); + } } + private void sendDirect(DatabaseStoreMessage msg, RouterInfo peer, long expiration) { + long token = getContext().random().nextLong(I2NPMessage.MAX_ID_VALUE); + msg.setReplyToken(token); + msg.setReplyGateway(getContext().routerHash()); + + if (_log.shouldLog(Log.DEBUG)) + _log.debug(getJobId() + ": send(dbStore) w/ token expected " + token); + + _state.addPending(peer.getIdentity().getHash()); + + SendSuccessJob onReply = new SendSuccessJob(getContext(), peer); + FailedJob onFail = new FailedJob(getContext(), peer, getContext().clock().now()); + StoreMessageSelector selector = new StoreMessageSelector(getContext(), getJobId(), peer, token, expiration); + + if (_log.shouldLog(Log.DEBUG)) + _log.debug("sending store directly to " + peer.getIdentity().getHash()); + OutNetMessage m = new OutNetMessage(getContext()); + m.setExpiration(expiration); + m.setMessage(msg); + m.setOnFailedReplyJob(onFail); + m.setOnFailedSendJob(onFail); + m.setOnReplyJob(onReply); + m.setPriority(STORE_PRIORITY); + m.setReplySelector(selector); + m.setTarget(peer); + getContext().commSystem().processMessage(m); + } + private void sendStoreThroughGarlic(DatabaseStoreMessage msg, RouterInfo peer, long expiration) { long token = getContext().random().nextLong(I2NPMessage.MAX_ID_VALUE); diff --git a/router/java/src/net/i2p/router/transport/udp/IntroductionManager.java b/router/java/src/net/i2p/router/transport/udp/IntroductionManager.java index 8968ddee9..db7e36123 100644 --- a/router/java/src/net/i2p/router/transport/udp/IntroductionManager.java +++ b/router/java/src/net/i2p/router/transport/udp/IntroductionManager.java @@ -26,6 +26,7 @@ public class IntroductionManager { _builder = new PacketBuilder(ctx); _outbound = Collections.synchronizedMap(new HashMap(128)); _inbound = new ArrayList(128); + ctx.statManager().createRateStat("udp.receiveRelayIntro", "How often we get a relayed request for us to talk to someone?", "udp", new long[] { 60*1000, 5*60*1000, 10*60*1000 }); } public void reset() { @@ -81,6 +82,7 @@ public class IntroductionManager { } public void receiveRelayIntro(RemoteHostId bob, UDPPacketReader reader) { + _context.statManager().addRateData("udp.receiveRelayIntro", 1, 0); _transport.send(_builder.buildHolePunch(reader)); } diff --git a/router/java/src/net/i2p/router/transport/udp/UDPTransport.java b/router/java/src/net/i2p/router/transport/udp/UDPTransport.java index 1f0b1374d..0d6f7f592 100644 --- a/router/java/src/net/i2p/router/transport/udp/UDPTransport.java +++ b/router/java/src/net/i2p/router/transport/udp/UDPTransport.java @@ -97,7 +97,10 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority public static final String PROP_FIXED_PORT = "i2np.udp.fixedPort"; private static final String DEFAULT_FIXED_PORT = "true"; - + + /** do we require introducers, regardless of our status? */ + public static final String PROP_FORCE_INTRODUCERS = "i2np.udp.forceIntroducers"; + /** how many relays offered to us will we use at a time? */ public static final int PUBLIC_RELAY_COUNT = 3; @@ -808,7 +811,6 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority _context.router().rebuildRouterInfo(); } - public static final String PROP_FORCE_INTRODUCERS = "i2np.udp.forceIntroducers"; public boolean introducersRequired() { String forceIntroducers = _context.getProperty(PROP_FORCE_INTRODUCERS); if ( (forceIntroducers != null) && (Boolean.valueOf(forceIntroducers).booleanValue()) )