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.
This commit is contained in:
jrandom
2005-09-13 00:11:56 +00:00
committed by zzz
parent 31bdb8909a
commit b5784d6025
12 changed files with 120 additions and 90 deletions

View File

@ -16,6 +16,7 @@ import java.util.Iterator;
import java.util.Set; import java.util.Set;
import net.i2p.time.Timestamper; 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 * 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 _saveRequested;
private boolean _recheckReachabilityRequested; private boolean _recheckReachabilityRequested;
private boolean _timeSyncEnabled; private boolean _timeSyncEnabled;
private boolean _requireIntroductions;
private String _tcpPort; private String _tcpPort;
private String _udpPort; private String _udpPort;
private String _inboundRate; private String _inboundRate;
@ -57,6 +59,7 @@ public class ConfigNetHandler extends FormHandler {
public void setSave(String moo) { _saveRequested = true; } public void setSave(String moo) { _saveRequested = true; }
public void setEnabletimesync(String moo) { _timeSyncEnabled = true; } public void setEnabletimesync(String moo) { _timeSyncEnabled = true; }
public void setRecheckReachability(String moo) { _recheckReachabilityRequested = true; } public void setRecheckReachability(String moo) { _recheckReachabilityRequested = true; }
public void setRequireIntroductions(String moo) { _requireIntroductions = true; }
public void setHostname(String hostname) { public void setHostname(String hostname) {
_hostname = (hostname != null ? hostname.trim() : null); _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 // Time sync enable, means NOT disabled
_context.router().setConfigSetting(Timestamper.PROP_DISABLED, "false"); _context.router().setConfigSetting(Timestamper.PROP_DISABLED, "false");
} else { } else {

View File

@ -2,6 +2,9 @@ package net.i2p.router.web;
import net.i2p.time.Timestamper; import net.i2p.time.Timestamper;
import net.i2p.router.RouterContext; 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 { public class ConfigNetHelper {
private RouterContext _context; private RouterContext _context;
@ -43,19 +46,12 @@ public class ConfigNetHelper {
return "" + port; return "" + port;
} }
public String getUdpPort() { public String getUdpAddress() {
int port = 8887; RouterAddress addr = _context.router().getRouterInfo().getTargetAddress("SSU");
String val = _context.getProperty(PROP_I2NP_UDP_PORT); if (addr == null)
if (val == null) return "unknown";
val = _context.getProperty(PROP_I2NP_INTERNAL_UDP_PORT); UDPAddress ua = new UDPAddress(addr);
if (val != null) { return ua.toString();
try {
port = Integer.parseInt(val);
} catch (NumberFormatException nfe) {
// ignore, use default from above
}
}
return "" + port;
} }
public String getEnableTimeSyncChecked() { public String getEnableTimeSyncChecked() {
@ -66,6 +62,21 @@ public class ConfigNetHelper {
return " checked "; 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_INBOUND_KBPS = "i2np.bandwidth.inboundKBytesPerSecond";
public static final String PROP_OUTBOUND_KBPS = "i2np.bandwidth.outboundKBytesPerSecond"; public static final String PROP_OUTBOUND_KBPS = "i2np.bandwidth.outboundKBytesPerSecond";
public static final String PROP_INBOUND_BURST = "i2np.bandwidth.inboundBurstKBytes"; public static final String PROP_INBOUND_BURST = "i2np.bandwidth.inboundBurstKBytes";

View File

@ -28,14 +28,12 @@
<input type="hidden" name="nonce" value="<%=System.getProperty("net.i2p.router.web.ConfigNetHandler.nonce")%>" /> <input type="hidden" name="nonce" value="<%=System.getProperty("net.i2p.router.web.ConfigNetHandler.nonce")%>" />
<input type="hidden" name="action" value="blah" /> <input type="hidden" name="action" value="blah" />
UDP port: <i><jsp:getProperty name="nethelper" property="udpPort" /></i><br /> <b>External UDP address:</b> <i><jsp:getProperty name="nethelper" property="udpAddress" /></i><br />
<!-- <input name="udpPort" type="text" size="5" value="<jsp:getProperty name="nethelper" property="udpPort" />" /><br /> --> <b>Require SSU introductions through NAT hole punching? </b>
<b>You must poke a hole in your firewall or NAT (if applicable) to receive new inbound UDP packets on <input type="checkbox" name="requireIntroductions" value="true" <jsp:getProperty name="nethelper" property="requireIntroductionsChecked" /> /><br />
this port from arbitrary peers (this requirement will be removed in i2p 0.6.1, but is necessary now)</b><br /> <p>If you can't poke a hole in your NAT or firewall to allow unsolicited UDP packets to reach the
TCP port: <input name="tcpPort" type="text" size="5" value="<jsp:getProperty name="nethelper" property="tcpPort" />" /> <br /> router, as detected with the <i>Status: ERR-Reject</i>, then you will need SSU introductions.
<b>You must poke a hole in your firewall or NAT (if applicable) so that you can receive inbound TCP Users behind symmetric NATs, such as OpenBSD's pf, are not currently supported.</p>
connections on it (this requirement will be removed in i2p 0.6.1, but is necessary now)</b>
<br />
<input type="submit" name="recheckReachability" value="Check network reachability..." /> <input type="submit" name="recheckReachability" value="Check network reachability..." />
<hr /> <hr />
@ -53,35 +51,8 @@ this port from arbitrary peers (this requirement will be removed in i2p 0.6.1, b
<jsp:getProperty name="nethelper" property="sharePercentageBox" /><br /> <jsp:getProperty name="nethelper" property="sharePercentageBox" /><br />
Sharing a higher percentage will improve your anonymity and help the network Sharing a higher percentage will improve your anonymity and help the network
<hr /> <hr />
Enable internal time synchronization? <input type="checkbox" <jsp:getProperty name="nethelper" property="enableTimeSyncChecked" /> name="enabletimesync" /><br />
<i>If disabled, your machine <b>must</b> 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).</i>
<hr />
<input type="submit" name="save" value="Save changes" /> <input type="reset" value="Cancel" /><br /> <input type="submit" name="save" value="Save changes" /> <input type="reset" value="Cancel" /><br />
<i>Changing the TCP or UDP port will force a 'soft restart' - dropping your connections and clients as
if the router was stopped and restarted. <b>Please be patient</b> - it may take
a few seconds to complete.</i>
</form> </form>
<hr />
<b>Advanced network config:</b>
<p>
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.</p>
<p>
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
<a href="configadvanced.jsp">advanced</a> config and restart the router.
</p>
</div> </div>
</body> </body>

View File

@ -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 2005-09-10 jrandom
* Test the router's reachability earlier and more aggressively * Test the router's reachability earlier and more aggressively

View File

@ -132,7 +132,9 @@ public class DatabaseStoreMessage extends I2NPMessageImpl {
curIndex += 4; curIndex += 4;
if (_replyToken > 0) { 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; curIndex += 4;
byte gw[] = new byte[Hash.HASH_LENGTH]; byte gw[] = new byte[Hash.HASH_LENGTH];
@ -202,7 +204,10 @@ public class DatabaseStoreMessage extends I2NPMessageImpl {
curIndex += 4; curIndex += 4;
if (_replyToken > 0) { 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); System.arraycopy(id, 0, out, curIndex, 4);
curIndex += 4; curIndex += 4;
System.arraycopy(_replyGateway.getData(), 0, out, curIndex, Hash.HASH_LENGTH); System.arraycopy(_replyGateway.getData(), 0, out, curIndex, Hash.HASH_LENGTH);

View File

@ -15,9 +15,9 @@ import net.i2p.CoreVersion;
* *
*/ */
public class RouterVersion { 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 String VERSION = "0.6.0.5";
public final static long BUILD = 5; public final static long BUILD = 6;
public static void main(String args[]) { public static void main(String args[]) {
System.out.println("I2P Router version: " + VERSION + "-" + BUILD); System.out.println("I2P Router version: " + VERSION + "-" + BUILD);
System.out.println("Router ID: " + RouterVersion.ID); System.out.println("Router ID: " + RouterVersion.ID);

View File

@ -230,47 +230,26 @@ public class StatisticsManager implements Service {
return buf.toString(); 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) { private void includeThroughput(Properties stats) {
double sendBytes5m = 0; RateStat sendRate = _context.statManager().getRate("bw.sendRate");
double sendBytes60m = 0;
double recvBytes5m = 0;
double recvBytes60m = 0;
RateStat sendRate = _context.statManager().getRate("transport.sendMessageSize");
if (sendRate != null) { if (sendRate != null) {
Rate r = sendRate.getRate(5*60*1000); Rate r = sendRate.getRate(5*60*1000);
if (r != null) 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); r = sendRate.getRate(60*60*1000);
if (r != null) 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) { if (recvRate != null) {
Rate r = recvRate.getRate(5*60*1000); Rate r = recvRate.getRate(5*60*1000);
if (r != null) 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); r = recvRate.getRate(60*60*1000);
if (r != null) 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);
} }

View File

@ -24,6 +24,16 @@ public class FloodfillNetworkDatabaseFacade extends KademliaNetworkDatabaseFacad
_context.inNetMessagePool().registerHandlerJobBuilder(DatabaseStoreMessage.MESSAGE_TYPE, new FloodfillDatabaseStoreMessageHandler(_context, this)); _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) { 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 // 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. // of the flooding - instead, send them to a random floodfill peer so *they* can flood 'em out.

View File

@ -34,6 +34,7 @@ class FloodfillPeerSelector extends PeerSelector {
peersToIgnore = new HashSet(1); peersToIgnore = new HashSet(1);
peersToIgnore.add(_context.router().getRouterInfo().getIdentity().getHash()); peersToIgnore.add(_context.router().getRouterInfo().getIdentity().getHash());
FloodfillSelectionCollector matches = new FloodfillSelectionCollector(key, peersToIgnore, maxNumRouters); FloodfillSelectionCollector matches = new FloodfillSelectionCollector(key, peersToIgnore, maxNumRouters);
if (kbuckets == null) return new ArrayList();
kbuckets.getAll(matches); kbuckets.getAll(matches);
List rv = matches.get(maxNumRouters); List rv = matches.get(maxNumRouters);
if (_log.shouldLog(Log.DEBUG)) if (_log.shouldLog(Log.DEBUG))
@ -44,6 +45,7 @@ class FloodfillPeerSelector extends PeerSelector {
} }
public List selectFloodfillParticipants(KBucketSet kbuckets) { public List selectFloodfillParticipants(KBucketSet kbuckets) {
if (kbuckets == null) return new ArrayList();
FloodfillSelectionCollector matches = new FloodfillSelectionCollector(null, null, 0); FloodfillSelectionCollector matches = new FloodfillSelectionCollector(null, null, 0);
kbuckets.getAll(matches); kbuckets.getAll(matches);
return matches.getFloodfillParticipants(); return matches.getFloodfillParticipants();

View File

@ -8,9 +8,7 @@ package net.i2p.router.networkdb.kademlia;
* *
*/ */
import java.util.Iterator; import java.util.*;
import java.util.List;
import java.util.Set;
import net.i2p.data.DataStructure; import net.i2p.data.DataStructure;
import net.i2p.data.Hash; import net.i2p.data.Hash;
@ -21,6 +19,7 @@ import net.i2p.data.i2np.DatabaseStoreMessage;
import net.i2p.data.i2np.I2NPMessage; import net.i2p.data.i2np.I2NPMessage;
import net.i2p.router.Job; import net.i2p.router.Job;
import net.i2p.router.JobImpl; import net.i2p.router.JobImpl;
import net.i2p.router.OutNetMessage;
import net.i2p.router.ReplyJob; import net.i2p.router.ReplyJob;
import net.i2p.router.RouterContext; import net.i2p.router.RouterContext;
import net.i2p.router.TunnelInfo; import net.i2p.router.TunnelInfo;
@ -198,7 +197,9 @@ class StoreJob extends JobImpl {
//if (_log.shouldLog(Log.DEBUG)) //if (_log.shouldLog(Log.DEBUG))
// _log.debug(getJobId() + ": Current routing key for " + key + ": " + rkey); // _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) { 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); getContext().statManager().addRateData("netDb.storeLeaseSetSent", 1, 0);
else sendStoreThroughGarlic(msg, peer, expiration);
} else {
getContext().statManager().addRateData("netDb.storeRouterInfoSent", 1, 0); 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) { private void sendStoreThroughGarlic(DatabaseStoreMessage msg, RouterInfo peer, long expiration) {
long token = getContext().random().nextLong(I2NPMessage.MAX_ID_VALUE); long token = getContext().random().nextLong(I2NPMessage.MAX_ID_VALUE);

View File

@ -26,6 +26,7 @@ public class IntroductionManager {
_builder = new PacketBuilder(ctx); _builder = new PacketBuilder(ctx);
_outbound = Collections.synchronizedMap(new HashMap(128)); _outbound = Collections.synchronizedMap(new HashMap(128));
_inbound = new ArrayList(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() { public void reset() {
@ -81,6 +82,7 @@ public class IntroductionManager {
} }
public void receiveRelayIntro(RemoteHostId bob, UDPPacketReader reader) { public void receiveRelayIntro(RemoteHostId bob, UDPPacketReader reader) {
_context.statManager().addRateData("udp.receiveRelayIntro", 1, 0);
_transport.send(_builder.buildHolePunch(reader)); _transport.send(_builder.buildHolePunch(reader));
} }

View File

@ -97,7 +97,10 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
public static final String PROP_FIXED_PORT = "i2np.udp.fixedPort"; public static final String PROP_FIXED_PORT = "i2np.udp.fixedPort";
private static final String DEFAULT_FIXED_PORT = "true"; 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? */ /** how many relays offered to us will we use at a time? */
public static final int PUBLIC_RELAY_COUNT = 3; public static final int PUBLIC_RELAY_COUNT = 3;
@ -808,7 +811,6 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
_context.router().rebuildRouterInfo(); _context.router().rebuildRouterInfo();
} }
public static final String PROP_FORCE_INTRODUCERS = "i2np.udp.forceIntroducers";
public boolean introducersRequired() { public boolean introducersRequired() {
String forceIntroducers = _context.getProperty(PROP_FORCE_INTRODUCERS); String forceIntroducers = _context.getProperty(PROP_FORCE_INTRODUCERS);
if ( (forceIntroducers != null) && (Boolean.valueOf(forceIntroducers).booleanValue()) ) if ( (forceIntroducers != null) && (Boolean.valueOf(forceIntroducers).booleanValue()) )