forked from I2P_Developers/i2p.i2p
Compare commits
9 Commits
i2p_0_6_1_
...
i2p_0_6_1_
Author | SHA1 | Date | |
---|---|---|---|
85c2c11217 | |||
de1ca4aea4 | |||
a0f865fb99 | |||
2c3fea5605 | |||
ba1d88b5c9 | |||
2ad715c668 | |||
5f17557e54 | |||
2ad5a6f907 | |||
0920462060 |
@ -8,6 +8,8 @@ import net.i2p.router.RouterContext;
|
||||
public class PeerHelper {
|
||||
private RouterContext _context;
|
||||
private Writer _out;
|
||||
private int _sortFlags;
|
||||
private String _urlBase;
|
||||
/**
|
||||
* Configure this bean to query a particular router context
|
||||
*
|
||||
@ -25,10 +27,22 @@ public class PeerHelper {
|
||||
public PeerHelper() {}
|
||||
|
||||
public void setOut(Writer out) { _out = out; }
|
||||
public void setSort(String flags) {
|
||||
if (flags != null) {
|
||||
try {
|
||||
_sortFlags = Integer.parseInt(flags);
|
||||
} catch (NumberFormatException nfe) {
|
||||
_sortFlags = 0;
|
||||
}
|
||||
} else {
|
||||
_sortFlags = 0;
|
||||
}
|
||||
}
|
||||
public void setUrlBase(String base) { _urlBase = base; }
|
||||
|
||||
public String getPeerSummary() {
|
||||
try {
|
||||
_context.commSystem().renderStatusHTML(_out);
|
||||
_context.commSystem().renderStatusHTML(_out, _urlBase, _sortFlags);
|
||||
_context.bandwidthLimiter().renderStatusHTML(_out);
|
||||
} catch (IOException ioe) {
|
||||
ioe.printStackTrace();
|
||||
|
@ -14,6 +14,8 @@
|
||||
<jsp:useBean class="net.i2p.router.web.PeerHelper" id="peerHelper" scope="request" />
|
||||
<jsp:setProperty name="peerHelper" property="contextId" value="<%=(String)session.getAttribute("i2p.contextId")%>" />
|
||||
<jsp:setProperty name="peerHelper" property="out" value="<%=out%>" />
|
||||
<jsp:setProperty name="peerHelper" property="urlBase" value="peers.jsp" />
|
||||
<jsp:setProperty name="peerHelper" property="sort" value="<%=request.getParameter("sort") != null ? request.getParameter("sort") : ""%>" />
|
||||
<jsp:getProperty name="peerHelper" property="peerSummary" />
|
||||
</div>
|
||||
|
||||
|
@ -39,7 +39,7 @@
|
||||
<b>Active:</b> <jsp:getProperty name="helper" property="activePeers" />/<jsp:getProperty name="helper" property="activeProfiles" /><br />
|
||||
<b>Fast:</b> <jsp:getProperty name="helper" property="fastPeers" /><br />
|
||||
<b>High capacity:</b> <jsp:getProperty name="helper" property="highCapacityPeers" /><br />
|
||||
<b>Well integrated:</b> <jsp:getProperty name="helper" property="wellIntegratedPeers" /><br />
|
||||
<!-- <b>Well integrated:</b> <jsp:getProperty name="helper" property="wellIntegratedPeers" /><br /> -->
|
||||
<b>Failing:</b> <jsp:getProperty name="helper" property="failingPeers" /><br />
|
||||
<!-- <b>Shitlisted:</b> <jsp:getProperty name="helper" property="shitlistedPeers" /><br /> -->
|
||||
<b>Known:</b> <jsp:getProperty name="helper" property="allPeers" /><br /><%
|
||||
|
@ -14,8 +14,8 @@ package net.i2p;
|
||||
*
|
||||
*/
|
||||
public class CoreVersion {
|
||||
public final static String ID = "$Revision: 1.60 $ $Date: 2006/04/23 16:06:13 $";
|
||||
public final static String VERSION = "0.6.1.18";
|
||||
public final static String ID = "$Revision: 1.61 $ $Date: 2006/05/09 16:17:19 $";
|
||||
public final static String VERSION = "0.6.1.19";
|
||||
|
||||
public static void main(String args[]) {
|
||||
System.out.println("I2P Core version: " + VERSION);
|
||||
|
@ -76,15 +76,33 @@ public class FortunaRandomSource extends RandomSource implements EntropyHarveste
|
||||
if (n<=0)
|
||||
throw new IllegalArgumentException("n must be positive");
|
||||
|
||||
if ((n & -n) == n) // i.e., n is a power of 2
|
||||
return (int)((n * (long)nextBits(31)) >> 31);
|
||||
////
|
||||
// this shortcut from sun's docs neither works nor is necessary.
|
||||
//
|
||||
//if ((n & -n) == n) {
|
||||
// // i.e., n is a power of 2
|
||||
// return (int)((n * (long)nextBits(31)) >> 31);
|
||||
//}
|
||||
|
||||
int bits, val;
|
||||
do {
|
||||
bits = nextBits(31);
|
||||
val = bits % n;
|
||||
} while(bits - val + (n-1) < 0);
|
||||
return val;
|
||||
int numBits = 0;
|
||||
int remaining = n;
|
||||
int rv = 0;
|
||||
while (remaining > 0) {
|
||||
remaining >>= 1;
|
||||
rv += nextBits(8) << numBits*8;
|
||||
numBits++;
|
||||
}
|
||||
if (rv < 0)
|
||||
rv += n;
|
||||
return rv % n;
|
||||
|
||||
//int bits, val;
|
||||
//do {
|
||||
// bits = nextBits(31);
|
||||
// val = bits % n;
|
||||
//} while(bits - val + (n-1) < 0);
|
||||
//
|
||||
//return val;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -180,4 +198,19 @@ public class FortunaRandomSource extends RandomSource implements EntropyHarveste
|
||||
public synchronized void feedEntropy(String source, byte[] data, int offset, int len) {
|
||||
_fortuna.addRandomBytes(data, offset, len);
|
||||
}
|
||||
|
||||
public static void main(String args[]) {
|
||||
try {
|
||||
RandomSource rand = I2PAppContext.getGlobalContext().random();
|
||||
java.io.ByteArrayOutputStream baos = new java.io.ByteArrayOutputStream();
|
||||
java.util.zip.GZIPOutputStream gos = new java.util.zip.GZIPOutputStream(baos);
|
||||
for (int i = 0; i < 1024*1024; i++) {
|
||||
int c = rand.nextInt(256);
|
||||
gos.write((byte)c);
|
||||
}
|
||||
gos.finish();
|
||||
byte compressed[] = baos.toByteArray();
|
||||
System.out.println("Compressed size of 1MB: " + compressed.length);
|
||||
} catch (Exception e) { e.printStackTrace(); }
|
||||
}
|
||||
}
|
||||
|
43
history.txt
43
history.txt
@ -1,4 +1,45 @@
|
||||
$Id: history.txt,v 1.471 2006/05/07 22:19:46 complication Exp $
|
||||
$Id: history.txt,v 1.478 2006-05-17 22:42:57 complication Exp $
|
||||
|
||||
* 2006-05-18 0.6.1.19 released
|
||||
|
||||
2006-05-18 jrandom
|
||||
* Made the SSU ACKs less frequent when possible
|
||||
|
||||
2006-05-17 Complication
|
||||
* Fix some oversights in my previous changes:
|
||||
adjust some loglevels, make a few statements less wasteful,
|
||||
make one comparison less confusing and more likely to log unexpected values
|
||||
|
||||
2006-05-17 jrandom
|
||||
* Make the peer page sortable
|
||||
* SSU modifications to cut down on unnecessary connection failures
|
||||
|
||||
2006-05-16 jrandom
|
||||
* Further shitlist randomizations
|
||||
* Adjust the stats monitored for detecting cpu overload when dropping new
|
||||
tunnel requests
|
||||
|
||||
2006-05-15 jrandom
|
||||
* Add a load dependent throttle on the pending inbound tunnel request
|
||||
backlog
|
||||
* Increased the tunnel test failure slack before killing a tunnel
|
||||
|
||||
2006-05-13 Complication
|
||||
* Separate growth factors for tunnel count and tunnel test time
|
||||
* Reduce growth factors, so probabalistic throttle would activate
|
||||
* Square probAccept values to decelerate stronger when far from average
|
||||
* Create a bandwidth stat with approximately 15-second half life
|
||||
* Make allowTunnel() check the 1-second bandwidth for overload
|
||||
before doing allowance calculations using 15-second bandwidth
|
||||
* Tweak the overload detector in BuildExecutor to be more sensitive
|
||||
for rising edges, add ability to initiate tunnel drops
|
||||
* Add a function to seek and drop the highest-rate participating tunnel,
|
||||
keeping a fixed+random grace period between such drops.
|
||||
It doesn't seem very effective, so disabled by default
|
||||
("router.dropTunnelsOnOverload=true" to enable)
|
||||
|
||||
2006-05-11 jrandom
|
||||
* PRNG bugfix (thanks cervantes and Complication!)
|
||||
|
||||
* 2006-05-09 0.6.1.18 released
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
<i2p.news date="$Date: 2006/04/15 02:58:12 $">
|
||||
<i2p.release version="0.6.1.18" date="2006/05/09" minVersion="0.6"
|
||||
<i2p.news date="$Date: 2006/05/09 16:17:17 $">
|
||||
<i2p.release version="0.6.1.19" date="2006/05/18" minVersion="0.6"
|
||||
anonurl="http://i2p/NF2RLVUxVulR3IqK0sGJR0dHQcGXAzwa6rEO4WAWYXOHw-DoZhKnlbf1nzHXwMEJoex5nFTyiNMqxJMWlY54cvU~UenZdkyQQeUSBZXyuSweflUXFqKN-y8xIoK2w9Ylq1k8IcrAFDsITyOzjUKoOPfVq34rKNDo7fYyis4kT5bAHy~2N1EVMs34pi2RFabATIOBk38Qhab57Umpa6yEoE~rbyR~suDRvD7gjBvBiIKFqhFueXsR2uSrPB-yzwAGofTXuklofK3DdKspciclTVzqbDjsk5UXfu2nTrC1agkhLyqlOfjhyqC~t1IXm-Vs2o7911k7KKLGjB4lmH508YJ7G9fLAUyjuB-wwwhejoWqvg7oWvqo4oIok8LG6ECR71C3dzCvIjY2QcrhoaazA9G4zcGMm6NKND-H4XY6tUWhpB~5GefB3YczOqMbHq4wi0O9MzBFrOJEOs3X4hwboKWANf7DT5PZKJZ5KorQPsYRSq0E3wSOsFCSsdVCKUGsAAAA/i2p/i2pupdate.sud"
|
||||
publicurl="http://dev.i2p.net/i2p/i2pupdate.sud"
|
||||
anonannouncement="http://i2p/NF2RLVUxVulR3IqK0sGJR0dHQcGXAzwa6rEO4WAWYXOHw-DoZhKnlbf1nzHXwMEJoex5nFTyiNMqxJMWlY54cvU~UenZdkyQQeUSBZXyuSweflUXFqKN-y8xIoK2w9Ylq1k8IcrAFDsITyOzjUKoOPfVq34rKNDo7fYyis4kT5bAHy~2N1EVMs34pi2RFabATIOBk38Qhab57Umpa6yEoE~rbyR~suDRvD7gjBvBiIKFqhFueXsR2uSrPB-yzwAGofTXuklofK3DdKspciclTVzqbDjsk5UXfu2nTrC1agkhLyqlOfjhyqC~t1IXm-Vs2o7911k7KKLGjB4lmH508YJ7G9fLAUyjuB-wwwhejoWqvg7oWvqo4oIok8LG6ECR71C3dzCvIjY2QcrhoaazA9G4zcGMm6NKND-H4XY6tUWhpB~5GefB3YczOqMbHq4wi0O9MzBFrOJEOs3X4hwboKWANf7DT5PZKJZ5KorQPsYRSq0E3wSOsFCSsdVCKUGsAAAA/pipermail/i2p/2005-September/000878.html"
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
<info>
|
||||
<appname>i2p</appname>
|
||||
<appversion>0.6.1.18</appversion>
|
||||
<appversion>0.6.1.19</appversion>
|
||||
<authors>
|
||||
<author name="I2P" email="support@i2p.net"/>
|
||||
</authors>
|
||||
|
18
news.xml
18
news.xml
@ -1,5 +1,5 @@
|
||||
<i2p.news date="$Date: 2006/05/02 21:11:06 $">
|
||||
<i2p.release version="0.6.1.18" date="2006/05/09" minVersion="0.6"
|
||||
<i2p.news date="$Date: 2006/05/09 21:38:42 $">
|
||||
<i2p.release version="0.6.1.19" date="2006/05/18" minVersion="0.6"
|
||||
anonurl="http://i2p/NF2RLVUxVulR3IqK0sGJR0dHQcGXAzwa6rEO4WAWYXOHw-DoZhKnlbf1nzHXwMEJoex5nFTyiNMqxJMWlY54cvU~UenZdkyQQeUSBZXyuSweflUXFqKN-y8xIoK2w9Ylq1k8IcrAFDsITyOzjUKoOPfVq34rKNDo7fYyis4kT5bAHy~2N1EVMs34pi2RFabATIOBk38Qhab57Umpa6yEoE~rbyR~suDRvD7gjBvBiIKFqhFueXsR2uSrPB-yzwAGofTXuklofK3DdKspciclTVzqbDjsk5UXfu2nTrC1agkhLyqlOfjhyqC~t1IXm-Vs2o7911k7KKLGjB4lmH508YJ7G9fLAUyjuB-wwwhejoWqvg7oWvqo4oIok8LG6ECR71C3dzCvIjY2QcrhoaazA9G4zcGMm6NKND-H4XY6tUWhpB~5GefB3YczOqMbHq4wi0O9MzBFrOJEOs3X4hwboKWANf7DT5PZKJZ5KorQPsYRSq0E3wSOsFCSsdVCKUGsAAAA/i2p/i2pupdate.sud"
|
||||
publicurl="http://dev.i2p.net/i2p/i2pupdate.sud"
|
||||
anonannouncement="http://i2p/NF2RLVUxVulR3IqK0sGJR0dHQcGXAzwa6rEO4WAWYXOHw-DoZhKnlbf1nzHXwMEJoex5nFTyiNMqxJMWlY54cvU~UenZdkyQQeUSBZXyuSweflUXFqKN-y8xIoK2w9Ylq1k8IcrAFDsITyOzjUKoOPfVq34rKNDo7fYyis4kT5bAHy~2N1EVMs34pi2RFabATIOBk38Qhab57Umpa6yEoE~rbyR~suDRvD7gjBvBiIKFqhFueXsR2uSrPB-yzwAGofTXuklofK3DdKspciclTVzqbDjsk5UXfu2nTrC1agkhLyqlOfjhyqC~t1IXm-Vs2o7911k7KKLGjB4lmH508YJ7G9fLAUyjuB-wwwhejoWqvg7oWvqo4oIok8LG6ECR71C3dzCvIjY2QcrhoaazA9G4zcGMm6NKND-H4XY6tUWhpB~5GefB3YczOqMbHq4wi0O9MzBFrOJEOs3X4hwboKWANf7DT5PZKJZ5KorQPsYRSq0E3wSOsFCSsdVCKUGsAAAA/pipermail/i2p/2005-September/000878.html"
|
||||
@ -10,13 +10,13 @@
|
||||
anonlogs="http://i2p/Nf3ab-ZFkmI-LyMt7GjgT-jfvZ3zKDl0L96pmGQXF1B82W2Bfjf0n7~288vafocjFLnQnVcmZd~-p0-Oolfo9aW2Rm-AhyqxnxyLlPBqGxsJBXjPhm1JBT4Ia8FB-VXt0BuY0fMKdAfWwN61-tj4zIcQWRxv3DFquwEf035K~Ra4SWOqiuJgTRJu7~o~DzHVljVgWIzwf8Z84cz0X33pv-mdG~~y0Bsc2qJVnYwjjR178YMcRSmNE0FVMcs6f17c6zqhMw-11qjKpY~EJfHYCx4lBWF37CD0obbWqTNUIbL~78vxqZRT3dgAgnLixog9nqTO-0Rh~NpVUZnoUi7fNR~awW5U3Cf7rU7nNEKKobLue78hjvRcWn7upHUF45QqTDuaM3yZa7OsjbcH-I909DOub2Q0Dno6vIwuA7yrysccN1sbnkwZbKlf4T6~iDdhaSLJd97QCyPOlbyUfYy9QLNExlRqKgNVJcMJRrIual~Lb1CLbnzt0uvobM57UpqSAAAA/meeting141"
|
||||
publiclogs="http://www.i2p.net/meeting141" />
|
||||
•
|
||||
2006-04-23: 0.6.1.17 <a href="http://dev.i2p/pipermail/i2p/2006-April/001282.html">released</a>
|
||||
with multiple improvements. Upgrading should alleviate congestion and peer selection issues.
|
||||
<br>
|
||||
2006-05-09: 0.6.1.18 <a href="http://dev.i2p/pipermail/i2p/2006-May/001287.html">released</a>
|
||||
with changes to help reduce periodism, congestion and lease failure.
|
||||
<br />
|
||||
•
|
||||
2006-05-02:
|
||||
<a href="http://dev.i2p/pipermail/i2p/2006-May/001285.html">status notes</a>
|
||||
2006-05-09:
|
||||
<a href="http://dev.i2p/pipermail/i2p/2006-May/001288.html">status notes</a>
|
||||
and
|
||||
<a href="http://www.i2p/meeting178">meeting log</a>
|
||||
<br>
|
||||
<a href="http://www.i2p/meeting179">meeting log</a>
|
||||
<br />
|
||||
</i2p.news>
|
||||
|
@ -23,7 +23,8 @@ import java.util.Set;
|
||||
public abstract class CommSystemFacade implements Service {
|
||||
public abstract void processMessage(OutNetMessage msg);
|
||||
|
||||
public void renderStatusHTML(Writer out) throws IOException { }
|
||||
public void renderStatusHTML(Writer out, String urlBase, int sortFlags) throws IOException { }
|
||||
public void renderStatusHTML(Writer out) throws IOException { renderStatusHTML(out, null, 0); }
|
||||
|
||||
/** Create the set of RouterAddress structures based on the router's config */
|
||||
public Set createAddresses() { return new HashSet(); }
|
||||
|
@ -1072,6 +1072,22 @@ public class Router {
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int get15sRate() { return get15sRate(false); }
|
||||
public int get15sRate(boolean outboundOnly) {
|
||||
RouterContext ctx = _context;
|
||||
if (ctx != null) {
|
||||
FIFOBandwidthLimiter bw = ctx.bandwidthLimiter();
|
||||
if (bw != null) {
|
||||
int out = (int)bw.getSendBps15s();
|
||||
if (outboundOnly)
|
||||
return out;
|
||||
return (int)Math.max(out, bw.getReceiveBps15s());
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int get1mRate() { return get1mRate(false); }
|
||||
public int get1mRate(boolean outboundOnly) {
|
||||
int send = 0;
|
||||
|
@ -52,6 +52,7 @@ class RouterThrottleImpl implements RouterThrottle {
|
||||
_context.statManager().createRateStat("router.throttleTunnelBytesAllowed", "How many bytes are allowed to be sent when we get a tunnel request (period is how many are currently allocated)?", "Throttle", new long[] { 10*60*1000, 60*60*1000, 24*60*60*1000 });
|
||||
_context.statManager().createRateStat("router.throttleTunnelBytesUsed", "Used Bps at request (period = max KBps)?", "Throttle", new long[] { 10*60*1000, 60*60*1000, 24*60*60*1000 });
|
||||
_context.statManager().createRateStat("router.throttleTunnelFailCount1m", "How many messages failed to be sent in the last 2 minutes when we throttle based on a spike in failures (period = 10 minute average failure count)?", "Throttle", new long[] { 60*1000, 10*60*1000, 60*60*1000});
|
||||
_context.statManager().createRateStat("router.throttleTunnelQueueOverload", "How many pending tunnel request messages have we received when we reject them due to overload (period = time to process each)?", "Throttle", new long[] { 60*1000, 10*60*1000, 60*60*1000});
|
||||
}
|
||||
|
||||
public boolean acceptNetworkMessage() {
|
||||
@ -103,7 +104,7 @@ class RouterThrottleImpl implements RouterThrottle {
|
||||
int numTunnels = _context.tunnelManager().getParticipatingCount();
|
||||
|
||||
if (numTunnels > getMinThrottleTunnels()) {
|
||||
double growthFactor = getTunnelGrowthFactor();
|
||||
double tunnelGrowthFactor = getTunnelGrowthFactor();
|
||||
Rate avgTunnels = _context.statManager().getRate("tunnel.participatingTunnels").getRate(60*60*1000);
|
||||
if (avgTunnels != null) {
|
||||
double avg = 0;
|
||||
@ -114,9 +115,10 @@ class RouterThrottleImpl implements RouterThrottle {
|
||||
int min = getMinThrottleTunnels();
|
||||
if (avg < min)
|
||||
avg = min;
|
||||
if ( (avg > 0) && (avg*growthFactor < numTunnels) ) {
|
||||
if ( (avg > 0) && (avg*tunnelGrowthFactor < numTunnels) ) {
|
||||
// we're accelerating, lets try not to take on too much too fast
|
||||
double probAccept = (avg*growthFactor) / numTunnels;
|
||||
double probAccept = (avg*tunnelGrowthFactor) / numTunnels;
|
||||
probAccept = probAccept * probAccept; // square the decelerator for tunnel counts
|
||||
int v = _context.random().nextInt(100);
|
||||
if (v < probAccept*100) {
|
||||
// ok
|
||||
@ -132,40 +134,46 @@ class RouterThrottleImpl implements RouterThrottle {
|
||||
}
|
||||
} else {
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Accepting tunnel request, since the average is " + avg
|
||||
_log.info("Accepting tunnel request, since the tunnel count average is " + avg
|
||||
+ " and we only have " + numTunnels + ")");
|
||||
}
|
||||
}
|
||||
|
||||
Rate tunnelTestTime10m = _context.statManager().getRate("tunnel.testSuccessTime").getRate(10*60*1000);
|
||||
Rate tunnelTestTime60m = _context.statManager().getRate("tunnel.testSuccessTime").getRate(60*60*1000);
|
||||
if ( (tunnelTestTime10m != null) && (tunnelTestTime60m != null) && (tunnelTestTime10m.getLastEventCount() > 0) ) {
|
||||
double avg10m = tunnelTestTime10m.getAverageValue();
|
||||
double avg60m = 0;
|
||||
if (tunnelTestTime60m.getLastEventCount() > 0)
|
||||
avg60m = tunnelTestTime60m.getAverageValue();
|
||||
else
|
||||
avg60m = tunnelTestTime60m.getLifetimeAverageValue();
|
||||
|
||||
if (avg60m < 2000)
|
||||
avg60m = 2000; // minimum before complaining
|
||||
|
||||
if ( (avg60m > 0) && (avg10m > avg60m * growthFactor) ) {
|
||||
double probAccept = (avg60m*growthFactor)/avg10m;
|
||||
int v = _context.random().nextInt(100);
|
||||
if (v < probAccept*100) {
|
||||
// ok
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Probabalistically accept tunnel request (p=" + probAccept
|
||||
+ " v=" + v + " test time avg 10m=" + avg10m + " 60m=" + avg60m + ")");
|
||||
} else {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Probabalistically refusing tunnel request (test time avg 10m=" + avg10m
|
||||
+ " 60m=" + avg60m + ")");
|
||||
_context.statManager().addRateData("router.throttleTunnelProbTestSlow", (long)(avg10m-avg60m), 0);
|
||||
return TunnelHistory.TUNNEL_REJECT_PROBABALISTIC_REJECT;
|
||||
}
|
||||
}
|
||||
|
||||
double tunnelTestTimeGrowthFactor = getTunnelTestTimeGrowthFactor();
|
||||
Rate tunnelTestTime1m = _context.statManager().getRate("tunnel.testSuccessTime").getRate(1*60*1000);
|
||||
Rate tunnelTestTime60m = _context.statManager().getRate("tunnel.testSuccessTime").getRate(60*60*1000);
|
||||
if ( (tunnelTestTime1m != null) && (tunnelTestTime60m != null) && (tunnelTestTime1m.getLastEventCount() > 0) ) {
|
||||
double avg1m = tunnelTestTime1m.getAverageValue();
|
||||
double avg60m = 0;
|
||||
if (tunnelTestTime60m.getLastEventCount() > 0)
|
||||
avg60m = tunnelTestTime60m.getAverageValue();
|
||||
else
|
||||
avg60m = tunnelTestTime60m.getLifetimeAverageValue();
|
||||
|
||||
if (avg60m < 2000)
|
||||
avg60m = 2000; // minimum before complaining
|
||||
|
||||
if ( (avg60m > 0) && (avg1m > avg60m * tunnelTestTimeGrowthFactor) ) {
|
||||
double probAccept = (avg60m*tunnelTestTimeGrowthFactor)/avg1m;
|
||||
probAccept = probAccept * probAccept; // square the decelerator for test times
|
||||
int v = _context.random().nextInt(100);
|
||||
if (v < probAccept*100) {
|
||||
// ok
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Probabalistically accept tunnel request (p=" + probAccept
|
||||
+ " v=" + v + " test time avg 1m=" + avg1m + " 60m=" + avg60m + ")");
|
||||
} else {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Probabalistically refusing tunnel request (test time avg 1m=" + avg1m
|
||||
+ " 60m=" + avg60m + ")");
|
||||
_context.statManager().addRateData("router.throttleTunnelProbTestSlow", (long)(avg1m-avg60m), 0);
|
||||
return TunnelHistory.TUNNEL_REJECT_PROBABALISTIC_REJECT;
|
||||
}
|
||||
} else {
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Accepting tunnel request, since 60m test time average is " + avg60m
|
||||
+ " and past 1m only has " + avg1m + ")");
|
||||
}
|
||||
}
|
||||
|
||||
@ -201,16 +209,37 @@ class RouterThrottleImpl implements RouterThrottle {
|
||||
}
|
||||
if (messagesPerTunnel < DEFAULT_MESSAGES_PER_TUNNEL_ESTIMATE)
|
||||
messagesPerTunnel = DEFAULT_MESSAGES_PER_TUNNEL_ESTIMATE;
|
||||
int participatingTunnels = _context.tunnelManager().getParticipatingCount();
|
||||
double bytesAllocated = messagesPerTunnel * participatingTunnels * 1024;
|
||||
|
||||
double bytesAllocated = messagesPerTunnel * numTunnels * net.i2p.router.tunnel.TrivialPreprocessor.PREPROCESSED_SIZE;
|
||||
|
||||
if (!allowTunnel(bytesAllocated, numTunnels)) {
|
||||
_context.statManager().addRateData("router.throttleTunnelBandwidthExceeded", (long)bytesAllocated, 0);
|
||||
return TunnelHistory.TUNNEL_REJECT_BANDWIDTH;
|
||||
}
|
||||
|
||||
int queuedRequests = _context.tunnelManager().getInboundBuildQueueSize();
|
||||
int timePerRequest = 1000;
|
||||
rs = _context.statManager().getRate("tunnel.decryptRequestTime");
|
||||
if (rs != null) {
|
||||
r = rs.getRate(60*1000);
|
||||
if (r.getLastEventCount() > 0)
|
||||
timePerRequest = (int)r.getAverageValue();
|
||||
else
|
||||
timePerRequest = (int)rs.getLifetimeAverageValue();
|
||||
}
|
||||
float pctFull = (queuedRequests * timePerRequest) / (10*1000f);
|
||||
float pReject = 1 - ((1-pctFull) * (1-pctFull));
|
||||
if ( (pctFull >= 1) || (pReject >= _context.random().nextFloat()) ) {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Rejecting a new tunnel request because we have too many pending requests (" + queuedRequests
|
||||
+ " at " + timePerRequest + "ms each, %full = " + pctFull);
|
||||
_context.statManager().addRateData("router.throttleTunnelQueueOverload", queuedRequests, timePerRequest);
|
||||
return TunnelHistory.TUNNEL_REJECT_TRANSIENT_OVERLOAD;
|
||||
}
|
||||
|
||||
// ok, all is well, let 'er in
|
||||
_context.statManager().addRateData("tunnel.bytesAllocatedAtAccept", (long)bytesAllocated, 60*10*1000);
|
||||
|
||||
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Accepting a new tunnel request (now allocating " + bytesAllocated + " bytes across " + numTunnels
|
||||
+ " tunnels with lag of " + lag + ")");
|
||||
@ -228,16 +257,23 @@ class RouterThrottleImpl implements RouterThrottle {
|
||||
*/
|
||||
private boolean allowTunnel(double bytesAllocated, int numTunnels) {
|
||||
int maxKBps = Math.min(_context.bandwidthLimiter().getOutboundKBytesPerSecond(), _context.bandwidthLimiter().getInboundKBytesPerSecond());
|
||||
int used1s = 0; //get1sRate(_context); // dont throttle on the 1s rate, its too volatile
|
||||
int used1m = _context.router().get1mRate();
|
||||
int used5m = 0; //get5mRate(_context); // don't throttle on the 5m rate, as that'd hide available bandwidth
|
||||
int used = Math.max(Math.max(used1s, used1m), used5m);
|
||||
int used1s = _context.router().get1sRate(); // dont throttle on the 1s rate, its too volatile
|
||||
int used15s = _context.router().get15sRate();
|
||||
int used1m = _context.router().get1mRate(); // dont throttle on the 1m rate, its too slow
|
||||
int used = used15s;
|
||||
|
||||
double share = _context.router().getSharePercentage();
|
||||
int availBps = (int)(((maxKBps*1024)*share) - used); //(int)(((maxKBps*1024) - used) * getSharePercentage());
|
||||
|
||||
// Write stats before making decisions
|
||||
_context.statManager().addRateData("router.throttleTunnelBytesUsed", used, maxKBps);
|
||||
_context.statManager().addRateData("router.throttleTunnelBytesAllowed", availBps, (long)bytesAllocated);
|
||||
|
||||
if (used1s > (maxKBps*1024)) {
|
||||
if (_log.shouldLog(Log.WARN)) _log.warn("Reject tunnel, 1s rate (" + used1s + ") indicates overload.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (true) {
|
||||
// ok, ignore any predictions of 'bytesAllocated', since that makes poorly
|
||||
// grounded conclusions about future use (or even the bursty use). Instead,
|
||||
@ -247,10 +283,14 @@ class RouterThrottleImpl implements RouterThrottle {
|
||||
double probReject = Math.pow(pctFull, 16); // steep curve
|
||||
double rand = _context.random().nextFloat();
|
||||
boolean reject = (availBps < MIN_AVAILABLE_BPS) || (rand <= probReject);
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
if (reject && _log.shouldLog(Log.WARN))
|
||||
_log.warn("reject = " + reject + " avail/maxK/used " + availBps + "/" + maxKBps + "/"
|
||||
+ used + " pReject = " + probReject + " pFull = " + pctFull + " numTunnels = " + numTunnels
|
||||
+ "rand = " + rand + " est = " + bytesAllocated + " share = " + (float)share);
|
||||
else if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("reject = " + reject + " avail/maxK/used " + availBps + "/" + maxKBps + "/"
|
||||
+ used + " pReject = " + probReject + " pFull = " + pctFull + " numTunnels = " + numTunnels
|
||||
+ "rand = " + rand + " est = " + bytesAllocated + " share = " + (float)share);
|
||||
if (reject) {
|
||||
return false;
|
||||
} else {
|
||||
@ -310,9 +350,17 @@ class RouterThrottleImpl implements RouterThrottle {
|
||||
|
||||
private double getTunnelGrowthFactor() {
|
||||
try {
|
||||
return Double.parseDouble(_context.getProperty("router.tunnelGrowthFactor", "3.0"));
|
||||
return Double.parseDouble(_context.getProperty("router.tunnelGrowthFactor", "1.3"));
|
||||
} catch (NumberFormatException nfe) {
|
||||
return 3.0;
|
||||
return 1.3;
|
||||
}
|
||||
}
|
||||
|
||||
private double getTunnelTestTimeGrowthFactor() {
|
||||
try {
|
||||
return Double.parseDouble(_context.getProperty("router.tunnelTestTimeGrowthFactor", "1.3"));
|
||||
} catch (NumberFormatException nfe) {
|
||||
return 1.3;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -15,8 +15,8 @@ import net.i2p.CoreVersion;
|
||||
*
|
||||
*/
|
||||
public class RouterVersion {
|
||||
public final static String ID = "$Revision: 1.411 $ $Date: 2006/05/07 22:19:47 $";
|
||||
public final static String VERSION = "0.6.1.18";
|
||||
public final static String ID = "$Revision: 1.418 $ $Date: 2006-05-17 22:42:57 $";
|
||||
public final static String VERSION = "0.6.1.19";
|
||||
public final static long BUILD = 0;
|
||||
public static void main(String args[]) {
|
||||
System.out.println("I2P Router version: " + VERSION + "-" + BUILD);
|
||||
|
@ -65,8 +65,10 @@ public class Shitlist {
|
||||
|
||||
long period = SHITLIST_DURATION_MS + _context.random().nextLong(SHITLIST_DURATION_MS);
|
||||
PeerProfile prof = _context.profileOrganizer().getProfile(peer);
|
||||
if (prof != null)
|
||||
if (prof != null) {
|
||||
period = SHITLIST_DURATION_MS << prof.incrementShitlists();
|
||||
period += _context.random().nextLong(period);
|
||||
}
|
||||
|
||||
if (period > 60*60*1000)
|
||||
period = 60*60*1000;
|
||||
|
@ -83,8 +83,8 @@ public class CommSystemFacadeImpl extends CommSystemFacade {
|
||||
}
|
||||
public void recheckReachability() { _manager.recheckReachability(); }
|
||||
|
||||
public void renderStatusHTML(Writer out) throws IOException {
|
||||
_manager.renderStatusHTML(out);
|
||||
public void renderStatusHTML(Writer out, String urlBase, int sortFlags) throws IOException {
|
||||
_manager.renderStatusHTML(out, urlBase, sortFlags);
|
||||
}
|
||||
|
||||
public Set createAddresses() {
|
||||
|
@ -49,6 +49,8 @@ public class FIFOBandwidthLimiter {
|
||||
private long _lastStatsUpdated;
|
||||
private float _sendBps;
|
||||
private float _recvBps;
|
||||
private float _sendBps15s;
|
||||
private float _recvBps15s;
|
||||
|
||||
private static int __id = 0;
|
||||
|
||||
@ -66,6 +68,8 @@ public class FIFOBandwidthLimiter {
|
||||
_context.statManager().createRateStat("bwLimiter.inboundDelayedTime", "How long it takes to honor an inbound request (ignoring ones with that go instantly)?", "BandwidthLimiter", new long[] { 60*1000l, 5*60*1000l, 10*60*1000l, 60*60*1000l });
|
||||
_context.statManager().createRateStat("bw.sendBps1s", "How fast we are transmitting for the 1s quantization (period is the number of bytes transmitted)?", "Bandwidth", new long[] { 60*1000l, 10*60*1000l });
|
||||
_context.statManager().createRateStat("bw.recvBps1s", "How fast we are receiving for the 1s quantization (period is the number of bytes transmitted)?", "Bandwidth", new long[] { 60*1000l, 10*60*1000l });
|
||||
_context.statManager().createRateStat("bw.sendBps15s", "How fast we are transmitting for the 15s quantization (period is the number of bytes transmitted)?", "Bandwidth", new long[] { 60*1000l, 10*60*1000l });
|
||||
_context.statManager().createRateStat("bw.recvBps15s", "How fast we are receiving for the 15s quantization (period is the number of bytes transmitted)?", "Bandwidth", new long[] { 60*1000l, 10*60*1000l });
|
||||
_pendingInboundRequests = new ArrayList(16);
|
||||
_pendingOutboundRequests = new ArrayList(16);
|
||||
_lastTotalSent = _totalAllocatedOutboundBytes;
|
||||
@ -97,6 +101,8 @@ public class FIFOBandwidthLimiter {
|
||||
public void setOutboundUnlimited(boolean isUnlimited) { _outboundUnlimited = isUnlimited; }
|
||||
public float getSendBps() { return _sendBps; }
|
||||
public float getReceiveBps() { return _recvBps; }
|
||||
public float getSendBps15s() { return _sendBps15s; }
|
||||
public float getReceiveBps15s() { return _recvBps15s; }
|
||||
|
||||
public int getOutboundKBytesPerSecond() { return _refiller.getOutboundKBytesPerSecond(); }
|
||||
public int getInboundKBytesPerSecond() { return _refiller.getInboundKBytesPerSecond(); }
|
||||
@ -270,14 +276,16 @@ public class FIFOBandwidthLimiter {
|
||||
private void updateStats() {
|
||||
long now = now();
|
||||
long time = now - _lastStatsUpdated;
|
||||
// If at least one second has passed
|
||||
if (time >= 1000) {
|
||||
long totS = _totalAllocatedOutboundBytes;
|
||||
long totR = _totalAllocatedInboundBytes;
|
||||
long sent = totS - _lastTotalSent;
|
||||
long recv = totR - _lastTotalReceived;
|
||||
long sent = totS - _lastTotalSent; // How much we sent meanwhile
|
||||
long recv = totR - _lastTotalReceived; // How much we received meanwhile
|
||||
_lastTotalSent = totS;
|
||||
_lastTotalReceived = totR;
|
||||
_lastStatsUpdated = now;
|
||||
|
||||
if (_sendBps <= 0)
|
||||
_sendBps = ((float)sent*1000f)/(float)time;
|
||||
else
|
||||
@ -286,12 +294,33 @@ public class FIFOBandwidthLimiter {
|
||||
_recvBps = ((float)recv*1000f)/(float)time;
|
||||
else
|
||||
_recvBps = (0.9f)*_recvBps + (0.1f)*((float)recv*1000)/(float)time;
|
||||
|
||||
if (_log.shouldLog(Log.WARN)) {
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("BW: time = " + time + " sent: " + sent + " recv: " + recv);
|
||||
_context.statManager().getStatLog().addData("bw", "bw.sendBps1s", (long)_sendBps, sent);
|
||||
_context.statManager().getStatLog().addData("bw", "bw.recvBps1s", (long)_recvBps, recv);
|
||||
}
|
||||
|
||||
// Maintain an approximate average with a 15-second halflife
|
||||
// Weights (0.955 and 0.045) are tuned so that transition between two values (e.g. 0..10)
|
||||
// would reach their midpoint (e.g. 5) in 15s
|
||||
if (_sendBps15s <= 0)
|
||||
_sendBps15s = ((float)sent*15*1000f)/(float)time;
|
||||
else
|
||||
_sendBps15s = (0.955f)*_sendBps15s + (0.045f)*((float)sent*1000f)/(float)time;
|
||||
|
||||
if (_recvBps15s <= 0)
|
||||
_recvBps15s = ((float)recv*15*1000f)/(float)time;
|
||||
else
|
||||
_recvBps15s = (0.955f)*_recvBps15s + (0.045f)*((float)recv*1000)/(float)time;
|
||||
|
||||
if (_log.shouldLog(Log.WARN)) {
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("BW15: time = " + time + " sent: " + sent + " recv: " + recv);
|
||||
_context.statManager().getStatLog().addData("bw", "bw.sendBps15s", (long)_sendBps15s, sent);
|
||||
_context.statManager().getStatLog().addData("bw", "bw.recvBps15s", (long)_recvBps15s, recv);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -41,7 +41,7 @@ public interface Transport {
|
||||
public int countActiveSendPeers();
|
||||
public List getMostRecentErrorMessages();
|
||||
|
||||
public void renderStatusHTML(Writer out) throws IOException;
|
||||
public void renderStatusHTML(Writer out, String urlBase, int sortFlags) throws IOException;
|
||||
public short getReachabilityStatus();
|
||||
public void recheckReachability();
|
||||
}
|
||||
|
@ -363,6 +363,7 @@ public abstract class TransportImpl implements Transport {
|
||||
public void setListener(TransportEventListener listener) { _listener = listener; }
|
||||
/** Make this stuff pretty (only used in the old console) */
|
||||
public void renderStatusHTML(Writer out) throws IOException {}
|
||||
public void renderStatusHTML(Writer out, String urlBase, int sortFlags) throws IOException { renderStatusHTML(out); }
|
||||
|
||||
public RouterContext getContext() { return _context; }
|
||||
public short getReachabilityStatus() { return CommSystemFacade.STATUS_UNKNOWN; }
|
||||
|
@ -244,7 +244,7 @@ public class TransportManager implements TransportEventListener {
|
||||
return rv;
|
||||
}
|
||||
|
||||
public void renderStatusHTML(Writer out) throws IOException {
|
||||
public void renderStatusHTML(Writer out, String urlBase, int sortFlags) throws IOException {
|
||||
TreeMap transports = new TreeMap();
|
||||
for (int i = 0; i < _transports.size(); i++) {
|
||||
Transport t = (Transport)_transports.get(i);
|
||||
@ -252,7 +252,7 @@ public class TransportManager implements TransportEventListener {
|
||||
}
|
||||
for (Iterator iter = transports.values().iterator(); iter.hasNext(); ) {
|
||||
Transport t= (Transport)iter.next();
|
||||
t.renderStatusHTML(out);
|
||||
t.renderStatusHTML(out, urlBase, sortFlags);
|
||||
}
|
||||
StringBuffer buf = new StringBuffer(4*1024);
|
||||
buf.append("Listening on: <br /><pre>\n");
|
||||
|
@ -22,7 +22,7 @@ public class ACKSender implements Runnable {
|
||||
private boolean _alive;
|
||||
|
||||
/** how frequently do we want to send ACKs to a peer? */
|
||||
static final int ACK_FREQUENCY = 100;
|
||||
static final int ACK_FREQUENCY = 200;
|
||||
|
||||
public ACKSender(RouterContext ctx, UDPTransport transport) {
|
||||
_context = ctx;
|
||||
@ -60,6 +60,16 @@ public class ACKSender implements Runnable {
|
||||
}
|
||||
}
|
||||
|
||||
private long ackFrequency(long timeSinceACK, long rtt) {
|
||||
// if we are actively pumping lots of data to them, we can depend upon
|
||||
// the unsentACKThreshold to figure out when to send an ACK instead of
|
||||
// using the timer, so we can set the timeout/frequency higher
|
||||
if (timeSinceACK < 2*1000)
|
||||
return Math.max(rtt/2, 500);
|
||||
else
|
||||
return ACK_FREQUENCY;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
while (_alive) {
|
||||
PeerState peer = null;
|
||||
@ -70,7 +80,7 @@ public class ACKSender implements Runnable {
|
||||
for (int i = 0; i < _peersToACK.size(); i++) {
|
||||
PeerState cur = (PeerState)_peersToACK.get(i);
|
||||
long wanted = cur.getWantedACKSendSince();
|
||||
long delta = wanted + ACK_FREQUENCY - now;
|
||||
long delta = wanted + ackFrequency(now-cur.getLastACKSend(), cur.getRTT()) - now;
|
||||
if ( ( (wanted > 0) && (delta < 0) ) || (cur.unsentACKThresholdReached()) ) {
|
||||
_peersToACK.remove(i);
|
||||
peer = cur;
|
||||
|
@ -943,7 +943,7 @@ public class EstablishmentManager {
|
||||
|
||||
Hash peer = outboundState.getRemoteIdentity().calculateHash();
|
||||
_context.shitlist().shitlistRouter(peer, err);
|
||||
_transport.dropPeer(peer);
|
||||
_transport.dropPeer(peer, false, err);
|
||||
//_context.profileManager().commErrorOccurred(peer);
|
||||
} else {
|
||||
while (true) {
|
||||
|
@ -447,13 +447,13 @@ public class PeerState {
|
||||
if (_concurrentMessagesActive < 0)
|
||||
_concurrentMessagesActive = 0;
|
||||
|
||||
long now = _context.clock().now()/(10*1000);
|
||||
if (_lastFailedSendPeriod >= now) {
|
||||
// ignore... too fast
|
||||
} else {
|
||||
_lastFailedSendPeriod = now;
|
||||
//long now = _context.clock().now()/(10*1000);
|
||||
//if (_lastFailedSendPeriod >= now) {
|
||||
// // ignore... too fast
|
||||
//} else {
|
||||
// _lastFailedSendPeriod = now;
|
||||
_consecutiveFailedSends++;
|
||||
}
|
||||
//}
|
||||
return _consecutiveFailedSends;
|
||||
}
|
||||
public long getInactivityTime() {
|
||||
@ -1561,6 +1561,7 @@ public class PeerState {
|
||||
buf.append(" lifetime: ").append(now-_keyEstablishedTime);
|
||||
buf.append(" cwin: ").append(_sendWindowBytes);
|
||||
buf.append(" acwin: ").append(_sendWindowBytesRemaining);
|
||||
buf.append(" consecFail: ").append(_consecutiveFailedSends);
|
||||
buf.append(" recv OK/Dup: ").append(_packetsReceived).append('/').append(_packetsReceivedDuplicate);
|
||||
buf.append(" send OK/Dup: ").append(_packetsTransmitted).append('/').append(_packetsRetransmitted);
|
||||
return buf.toString();
|
||||
|
@ -153,7 +153,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
|
||||
_needsRebuild = true;
|
||||
|
||||
_context.statManager().createRateStat("udp.alreadyConnected", "What is the lifetime of a reestablished session", "udp", new long[] { 60*1000, 10*60*1000, 60*60*1000, 24*60*60*1000 });
|
||||
_context.statManager().createRateStat("udp.droppedPeer", "How long ago did we receive from a dropped peer (duration == session lifetime", "udp", new long[] { 60*60*1000, 24*60*60*1000 });
|
||||
_context.statManager().createRateStat("udp.droppedPeer", "How long ago did we receive from a dropped peer (duration == session lifetime", "udp", new long[] { 60*1000, 60*60*1000, 24*60*60*1000 });
|
||||
_context.statManager().createRateStat("udp.droppedPeerInactive", "How long ago did we receive from a dropped peer (duration == session lifetime)", "udp", new long[] { 60*1000, 60*60*1000, 24*60*60*1000 });
|
||||
_context.statManager().createRateStat("udp.statusOK", "How many times the peer test returned OK", "udp", new long[] { 5*60*1000, 20*60*1000, 60*60*1000, 24*60*60*1000 });
|
||||
_context.statManager().createRateStat("udp.statusDifferent", "How many times the peer test returned different IP/ports", "udp", new long[] { 5*60*1000, 20*60*1000, 60*60*1000, 24*60*60*1000 });
|
||||
@ -163,6 +163,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
|
||||
_context.statManager().createRateStat("udp.addressUpdated", "How many times we adjust our own reachable IP address", "udp", new long[] { 1*60*1000, 20*60*1000, 60*60*1000, 24*60*60*1000 });
|
||||
_context.statManager().createRateStat("udp.proactiveReestablish", "How long a session was idle for when we proactively reestablished it", "udp", new long[] { 1*60*1000, 20*60*1000, 60*60*1000, 24*60*60*1000 });
|
||||
_context.statManager().createRateStat("udp.dropPeerDroplist", "How many peers currently have their packets dropped outright when a new peer is added to the list?", "udp", new long[] { 1*60*1000, 20*60*1000 });
|
||||
_context.statManager().createRateStat("udp.dropPeerConsecutiveFailures", "How many consecutive failed sends to a peer did we attempt before giving up and reestablishing a new session (lifetime is inactivity perood)", "udp", new long[] { 1*60*1000, 10*60*1000 });
|
||||
__instance = this;
|
||||
}
|
||||
|
||||
@ -601,7 +602,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
|
||||
}
|
||||
}
|
||||
_context.shitlist().shitlistRouter(peerHash, "Part of the wrong network");
|
||||
dropPeer(peerHash);
|
||||
dropPeer(peerHash, false, "wrong network");
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Dropping the peer " + peerHash.toBase64() + " because they are in the wrong net");
|
||||
return;
|
||||
@ -636,22 +637,28 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
|
||||
|
||||
public boolean isInDropList(RemoteHostId peer) { synchronized (_dropList) { return _dropList.contains(peer); } }
|
||||
|
||||
void dropPeer(Hash peer) {
|
||||
void dropPeer(Hash peer, boolean shouldShitlist, String why) {
|
||||
PeerState state = getPeerState(peer);
|
||||
if (state != null)
|
||||
dropPeer(state, false);
|
||||
dropPeer(state, shouldShitlist, why);
|
||||
}
|
||||
private void dropPeer(PeerState peer, boolean shouldShitlist) {
|
||||
private void dropPeer(PeerState peer, boolean shouldShitlist, String why) {
|
||||
if (_log.shouldLog(Log.WARN)) {
|
||||
long now = _context.clock().now();
|
||||
StringBuffer buf = new StringBuffer(4096);
|
||||
long timeSinceSend = now - peer.getLastSendTime();
|
||||
long timeSinceRecv = now - peer.getLastReceiveTime();
|
||||
long timeSinceAck = now - peer.getLastACKSend();
|
||||
long timeSinceSendOK = now - peer.getLastSendFullyTime();
|
||||
int consec = peer.getConsecutiveFailedSends();
|
||||
buf.append("Dropping remote peer: ").append(peer.toString()).append(" shitlist? ").append(shouldShitlist);
|
||||
buf.append(" lifetime: ").append(now - peer.getKeyEstablishedTime());
|
||||
buf.append(" time since send/recv/ack: ").append(timeSinceSend).append(" / ");
|
||||
buf.append(" time since send/fully/recv/ack: ").append(timeSinceSend).append(" / ");
|
||||
buf.append(timeSinceSendOK).append(" / ");
|
||||
buf.append(timeSinceRecv).append(" / ").append(timeSinceAck);
|
||||
buf.append(" consec failures: ").append(consec);
|
||||
if (why != null)
|
||||
buf.append(" cause: ").append(why);
|
||||
/*
|
||||
buf.append("Existing peers: \n");
|
||||
synchronized (_peersByIdent) {
|
||||
@ -694,14 +701,10 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
|
||||
if (peer.getRemotePeer() != null) {
|
||||
dropPeerCapacities(peer);
|
||||
|
||||
if (shouldShitlist) {
|
||||
long now = _context.clock().now();
|
||||
_context.statManager().addRateData("udp.droppedPeer", now - peer.getLastReceiveTime(), now - peer.getKeyEstablishedTime());
|
||||
if (shouldShitlist)
|
||||
_context.shitlist().shitlistRouter(peer.getRemotePeer(), "dropped after too many retries");
|
||||
} else {
|
||||
long now = _context.clock().now();
|
||||
_context.statManager().addRateData("udp.droppedPeerInactive", now - peer.getLastReceiveTime(), now - peer.getKeyEstablishedTime());
|
||||
}
|
||||
long now = _context.clock().now();
|
||||
_context.statManager().addRateData("udp.droppedPeer", now - peer.getLastReceiveTime(), now - peer.getKeyEstablishedTime());
|
||||
synchronized (_peersByIdent) {
|
||||
altByIdent = (PeerState)_peersByIdent.remove(peer.getRemotePeer());
|
||||
}
|
||||
@ -725,8 +728,8 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
|
||||
rebuildExternalAddress();
|
||||
|
||||
// deal with races to make sure we drop the peers fully
|
||||
if ( (altByIdent != null) && (peer != altByIdent) ) dropPeer(altByIdent, shouldShitlist);
|
||||
if ( (altByHost != null) && (peer != altByHost) ) dropPeer(altByHost, shouldShitlist);
|
||||
if ( (altByIdent != null) && (peer != altByIdent) ) dropPeer(altByIdent, shouldShitlist, "recurse");
|
||||
if ( (altByHost != null) && (peer != altByHost) ) dropPeer(altByHost, shouldShitlist, "recurse");
|
||||
}
|
||||
|
||||
private boolean needsRebuild() {
|
||||
@ -842,7 +845,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
|
||||
return (pref != null) && "true".equals(pref);
|
||||
}
|
||||
|
||||
private static final int MAX_IDLE_TIME = 60*1000;
|
||||
private static final int MAX_IDLE_TIME = 5*60*1000;
|
||||
|
||||
public String getStyle() { return STYLE; }
|
||||
public void send(OutNetMessage msg) {
|
||||
@ -866,7 +869,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
|
||||
(peer.getConsecutiveFailedSends() > 0) &&
|
||||
(inboundActive <= 0)) {
|
||||
// peer is waaaay idle, drop the con and queue it up as a new con
|
||||
dropPeer(peer, false);
|
||||
dropPeer(peer, false, "proactive reconnection");
|
||||
msg.timestamp("peer is really idle, dropping con and reestablishing");
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Proactive reestablish to " + to.toBase64());
|
||||
@ -1085,10 +1088,16 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
|
||||
_log.warn("Consecutive failure #" + consecutive
|
||||
+ " on " + msg.toString()
|
||||
+ " to " + msg.getPeer());
|
||||
if ( (consecutive > MAX_CONSECUTIVE_FAILED) && (msg.getPeer().getInactivityTime() > DROP_INACTIVITY_TIME))
|
||||
dropPeer(msg.getPeer(), false);
|
||||
else if (consecutive > 2 * MAX_CONSECUTIVE_FAILED) // they're sending us data, but we cant reply?
|
||||
dropPeer(msg.getPeer(), false);
|
||||
if ( (_context.clock().now() - msg.getPeer().getLastSendFullyTime() <= 60*1000) || (consecutive < MAX_CONSECUTIVE_FAILED) ) {
|
||||
// ok, a few conseutive failures, but we /are/ getting through to them
|
||||
} else {
|
||||
_context.statManager().addRateData("udp.dropPeerConsecutiveFailures", consecutive, msg.getPeer().getInactivityTime());
|
||||
dropPeer(msg.getPeer(), false, "too many failures");
|
||||
}
|
||||
//if ( (consecutive > MAX_CONSECUTIVE_FAILED) && (msg.getPeer().getInactivityTime() > DROP_INACTIVITY_TIME))
|
||||
// dropPeer(msg.getPeer(), false);
|
||||
//else if (consecutive > 2 * MAX_CONSECUTIVE_FAILED) // they're sending us data, but we cant reply?
|
||||
// dropPeer(msg.getPeer(), false);
|
||||
}
|
||||
noteSend(msg, false);
|
||||
if (m != null)
|
||||
@ -1181,21 +1190,6 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
|
||||
return active;
|
||||
}
|
||||
|
||||
private static class AlphaComparator implements Comparator {
|
||||
private static final AlphaComparator _instance = new AlphaComparator();
|
||||
public static final AlphaComparator instance() { return _instance; }
|
||||
|
||||
public int compare(Object lhs, Object rhs) {
|
||||
if ( (lhs == null) || (rhs == null) || !(lhs instanceof PeerState) || !(rhs instanceof PeerState))
|
||||
throw new IllegalArgumentException("rhs = " + rhs + " lhs = " + lhs);
|
||||
PeerState l = (PeerState)lhs;
|
||||
PeerState r = (PeerState)rhs;
|
||||
// base64 retains binary ordering
|
||||
return DataHelper.compareTo(l.getRemotePeer().getData(), r.getRemotePeer().getData());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static UDPTransport __instance;
|
||||
/** **internal, do not use** */
|
||||
public static final UDPTransport _instance() { return __instance; }
|
||||
@ -1216,8 +1210,302 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
|
||||
return peers;
|
||||
}
|
||||
|
||||
public void renderStatusHTML(Writer out) throws IOException {
|
||||
TreeSet peers = new TreeSet(AlphaComparator.instance());
|
||||
private static final int FLAG_ALPHA = 0;
|
||||
private static final int FLAG_IDLE_IN = 1;
|
||||
private static final int FLAG_IDLE_OUT = 2;
|
||||
private static final int FLAG_RATE_IN = 3;
|
||||
private static final int FLAG_RATE_OUT = 4;
|
||||
private static final int FLAG_SKEW = 5;
|
||||
private static final int FLAG_CWND= 6;
|
||||
private static final int FLAG_SSTHRESH = 7;
|
||||
private static final int FLAG_RTT = 8;
|
||||
private static final int FLAG_DEV = 9;
|
||||
private static final int FLAG_RTO = 10;
|
||||
private static final int FLAG_MTU = 11;
|
||||
private static final int FLAG_SEND = 12;
|
||||
private static final int FLAG_RECV = 13;
|
||||
private static final int FLAG_RESEND = 14;
|
||||
private static final int FLAG_DUP = 15;
|
||||
private static final int FLAG_UPTIME = 16;
|
||||
|
||||
private Comparator getComparator(int sortFlags) {
|
||||
Comparator rv = null;
|
||||
switch (Math.abs(sortFlags)) {
|
||||
case FLAG_IDLE_IN:
|
||||
rv = IdleInComparator.instance();
|
||||
break;
|
||||
case FLAG_IDLE_OUT:
|
||||
rv = IdleOutComparator.instance();
|
||||
break;
|
||||
case FLAG_RATE_IN:
|
||||
rv = RateInComparator.instance();
|
||||
break;
|
||||
case FLAG_RATE_OUT:
|
||||
rv = RateOutComparator.instance();
|
||||
break;
|
||||
case FLAG_UPTIME:
|
||||
rv = UptimeComparator.instance();
|
||||
break;
|
||||
case FLAG_SKEW:
|
||||
rv = SkewComparator.instance();
|
||||
break;
|
||||
case FLAG_CWND:
|
||||
rv = CwndComparator.instance();
|
||||
break;
|
||||
case FLAG_SSTHRESH:
|
||||
rv = SsthreshComparator.instance();
|
||||
break;
|
||||
case FLAG_RTT:
|
||||
rv = RTTComparator.instance();
|
||||
break;
|
||||
case FLAG_DEV:
|
||||
rv = DevComparator.instance();
|
||||
break;
|
||||
case FLAG_RTO:
|
||||
rv = RTOComparator.instance();
|
||||
break;
|
||||
case FLAG_MTU:
|
||||
rv = MTUComparator.instance();
|
||||
break;
|
||||
case FLAG_SEND:
|
||||
rv = SendCountComparator.instance();
|
||||
break;
|
||||
case FLAG_RECV:
|
||||
rv = RecvCountComparator.instance();
|
||||
break;
|
||||
case FLAG_RESEND:
|
||||
rv = ResendComparator.instance();
|
||||
break;
|
||||
case FLAG_DUP:
|
||||
rv = DupComparator.instance();
|
||||
break;
|
||||
case FLAG_ALPHA:
|
||||
default:
|
||||
rv = AlphaComparator.instance();
|
||||
break;
|
||||
}
|
||||
if (sortFlags < 0)
|
||||
rv = new InverseComparator(rv);
|
||||
return rv;
|
||||
}
|
||||
private static class AlphaComparator extends PeerComparator {
|
||||
private static final AlphaComparator _instance = new AlphaComparator();
|
||||
public static final AlphaComparator instance() { return _instance; }
|
||||
}
|
||||
private static class IdleInComparator extends PeerComparator {
|
||||
private static final IdleInComparator _instance = new IdleInComparator();
|
||||
public static final IdleInComparator instance() { return _instance; }
|
||||
protected int compare(PeerState l, PeerState r) {
|
||||
long rv = l.getLastReceiveTime() - r.getLastReceiveTime();
|
||||
if (rv == 0) // fallback on alpha
|
||||
return super.compare(l, r);
|
||||
else
|
||||
return (int)rv;
|
||||
}
|
||||
}
|
||||
private static class IdleOutComparator extends PeerComparator {
|
||||
private static final IdleOutComparator _instance = new IdleOutComparator();
|
||||
public static final IdleOutComparator instance() { return _instance; }
|
||||
protected int compare(PeerState l, PeerState r) {
|
||||
long rv = l.getLastSendTime() - r.getLastSendTime();
|
||||
if (rv == 0) // fallback on alpha
|
||||
return super.compare(l, r);
|
||||
else
|
||||
return (int)rv;
|
||||
}
|
||||
}
|
||||
private static class RateInComparator extends PeerComparator {
|
||||
private static final RateInComparator _instance = new RateInComparator();
|
||||
public static final RateInComparator instance() { return _instance; }
|
||||
protected int compare(PeerState l, PeerState r) {
|
||||
long rv = l.getReceiveBps() - r.getReceiveBps();
|
||||
if (rv == 0) // fallback on alpha
|
||||
return super.compare(l, r);
|
||||
else
|
||||
return (int)rv;
|
||||
}
|
||||
}
|
||||
private static class RateOutComparator extends PeerComparator {
|
||||
private static final RateOutComparator _instance = new RateOutComparator();
|
||||
public static final RateOutComparator instance() { return _instance; }
|
||||
protected int compare(PeerState l, PeerState r) {
|
||||
long rv = l.getSendBps() - r.getSendBps();
|
||||
if (rv == 0) // fallback on alpha
|
||||
return super.compare(l, r);
|
||||
else
|
||||
return (int)rv;
|
||||
}
|
||||
}
|
||||
private static class UptimeComparator extends PeerComparator {
|
||||
private static final UptimeComparator _instance = new UptimeComparator();
|
||||
public static final UptimeComparator instance() { return _instance; }
|
||||
protected int compare(PeerState l, PeerState r) {
|
||||
long rv = l.getKeyEstablishedTime() - r.getKeyEstablishedTime();
|
||||
if (rv == 0) // fallback on alpha
|
||||
return super.compare(l, r);
|
||||
else
|
||||
return (int)rv;
|
||||
}
|
||||
}
|
||||
private static class SkewComparator extends PeerComparator {
|
||||
private static final SkewComparator _instance = new SkewComparator();
|
||||
public static final SkewComparator instance() { return _instance; }
|
||||
protected int compare(PeerState l, PeerState r) {
|
||||
long rv = Math.abs(l.getClockSkew()) - Math.abs(r.getClockSkew());
|
||||
if (rv == 0) // fallback on alpha
|
||||
return super.compare(l, r);
|
||||
else
|
||||
return (int)rv;
|
||||
}
|
||||
}
|
||||
private static class CwndComparator extends PeerComparator {
|
||||
private static final CwndComparator _instance = new CwndComparator();
|
||||
public static final CwndComparator instance() { return _instance; }
|
||||
protected int compare(PeerState l, PeerState r) {
|
||||
long rv = l.getSendWindowBytes() - r.getSendWindowBytes();
|
||||
if (rv == 0) // fallback on alpha
|
||||
return super.compare(l, r);
|
||||
else
|
||||
return (int)rv;
|
||||
}
|
||||
}
|
||||
private static class SsthreshComparator extends PeerComparator {
|
||||
private static final SsthreshComparator _instance = new SsthreshComparator();
|
||||
public static final SsthreshComparator instance() { return _instance; }
|
||||
protected int compare(PeerState l, PeerState r) {
|
||||
long rv = l.getSlowStartThreshold() - r.getSlowStartThreshold();
|
||||
if (rv == 0) // fallback on alpha
|
||||
return super.compare(l, r);
|
||||
else
|
||||
return (int)rv;
|
||||
}
|
||||
}
|
||||
private static class RTTComparator extends PeerComparator {
|
||||
private static final RTTComparator _instance = new RTTComparator();
|
||||
public static final RTTComparator instance() { return _instance; }
|
||||
protected int compare(PeerState l, PeerState r) {
|
||||
long rv = l.getRTT() - r.getRTT();
|
||||
if (rv == 0) // fallback on alpha
|
||||
return super.compare(l, r);
|
||||
else
|
||||
return (int)rv;
|
||||
}
|
||||
}
|
||||
private static class DevComparator extends PeerComparator {
|
||||
private static final DevComparator _instance = new DevComparator();
|
||||
public static final DevComparator instance() { return _instance; }
|
||||
protected int compare(PeerState l, PeerState r) {
|
||||
long rv = l.getRTTDeviation() - r.getRTTDeviation();
|
||||
if (rv == 0) // fallback on alpha
|
||||
return super.compare(l, r);
|
||||
else
|
||||
return (int)rv;
|
||||
}
|
||||
}
|
||||
private static class RTOComparator extends PeerComparator {
|
||||
private static final RTOComparator _instance = new RTOComparator();
|
||||
public static final RTOComparator instance() { return _instance; }
|
||||
protected int compare(PeerState l, PeerState r) {
|
||||
long rv = l.getRTO() - r.getRTO();
|
||||
if (rv == 0) // fallback on alpha
|
||||
return super.compare(l, r);
|
||||
else
|
||||
return (int)rv;
|
||||
}
|
||||
}
|
||||
private static class MTUComparator extends PeerComparator {
|
||||
private static final MTUComparator _instance = new MTUComparator();
|
||||
public static final MTUComparator instance() { return _instance; }
|
||||
protected int compare(PeerState l, PeerState r) {
|
||||
long rv = l.getMTU() - r.getMTU();
|
||||
if (rv == 0) // fallback on alpha
|
||||
return super.compare(l, r);
|
||||
else
|
||||
return (int)rv;
|
||||
}
|
||||
}
|
||||
private static class SendCountComparator extends PeerComparator {
|
||||
private static final SendCountComparator _instance = new SendCountComparator();
|
||||
public static final SendCountComparator instance() { return _instance; }
|
||||
protected int compare(PeerState l, PeerState r) {
|
||||
long rv = l.getPacketsTransmitted() - r.getPacketsTransmitted();
|
||||
if (rv == 0) // fallback on alpha
|
||||
return super.compare(l, r);
|
||||
else
|
||||
return (int)rv;
|
||||
}
|
||||
}
|
||||
private static class RecvCountComparator extends PeerComparator {
|
||||
private static final RecvCountComparator _instance = new RecvCountComparator();
|
||||
public static final RecvCountComparator instance() { return _instance; }
|
||||
protected int compare(PeerState l, PeerState r) {
|
||||
long rv = l.getPacketsReceived() - r.getPacketsReceived();
|
||||
if (rv == 0) // fallback on alpha
|
||||
return super.compare(l, r);
|
||||
else
|
||||
return (int)rv;
|
||||
}
|
||||
}
|
||||
private static class ResendComparator extends PeerComparator {
|
||||
private static final ResendComparator _instance = new ResendComparator();
|
||||
public static final ResendComparator instance() { return _instance; }
|
||||
protected int compare(PeerState l, PeerState r) {
|
||||
long rv = l.getPacketsRetransmitted() - r.getPacketsRetransmitted();
|
||||
if (rv == 0) // fallback on alpha
|
||||
return super.compare(l, r);
|
||||
else
|
||||
return (int)rv;
|
||||
}
|
||||
}
|
||||
private static class DupComparator extends PeerComparator {
|
||||
private static final DupComparator _instance = new DupComparator();
|
||||
public static final DupComparator instance() { return _instance; }
|
||||
protected int compare(PeerState l, PeerState r) {
|
||||
long rv = l.getPacketsReceivedDuplicate() - r.getPacketsReceivedDuplicate();
|
||||
if (rv == 0) // fallback on alpha
|
||||
return super.compare(l, r);
|
||||
else
|
||||
return (int)rv;
|
||||
}
|
||||
}
|
||||
|
||||
private static class PeerComparator implements Comparator {
|
||||
public int compare(Object lhs, Object rhs) {
|
||||
if ( (lhs == null) || (rhs == null) || !(lhs instanceof PeerState) || !(rhs instanceof PeerState))
|
||||
throw new IllegalArgumentException("rhs = " + rhs + " lhs = " + lhs);
|
||||
return compare((PeerState)lhs, (PeerState)rhs);
|
||||
}
|
||||
protected int compare(PeerState l, PeerState r) {
|
||||
// base64 retains binary ordering
|
||||
return DataHelper.compareTo(l.getRemotePeer().getData(), r.getRemotePeer().getData());
|
||||
}
|
||||
}
|
||||
private static class InverseComparator implements Comparator {
|
||||
private Comparator _comp;
|
||||
public InverseComparator(Comparator comp) { _comp = comp; }
|
||||
public int compare(Object lhs, Object rhs) {
|
||||
return -1 * _comp.compare(lhs, rhs);
|
||||
}
|
||||
}
|
||||
|
||||
private void appendSortLinks(StringBuffer buf, String urlBase, int sortFlags, String descr, int ascending) {
|
||||
if (sortFlags == ascending) {
|
||||
buf.append(" <a href=\"").append(urlBase).append("?sort=").append(0-ascending);
|
||||
buf.append("\" title=\"").append(descr).append("\">V</a><b>^</b> ");
|
||||
} else if (sortFlags == 0 - ascending) {
|
||||
buf.append(" <b>V</b><a href=\"").append(urlBase).append("?sort=").append(ascending);
|
||||
buf.append("\" title=\"").append(descr).append("\">^</a> ");
|
||||
} else {
|
||||
buf.append(" <a href=\"").append(urlBase).append("?sort=").append(0-ascending);
|
||||
buf.append("\" title=\"").append(descr).append("\">V</a><a href=\"").append(urlBase).append("?sort=").append(ascending);
|
||||
buf.append("\" title=\"").append(descr).append("\">^</a> ");
|
||||
}
|
||||
}
|
||||
|
||||
//public void renderStatusHTML(Writer out) throws IOException { renderStatusHTML(out, 0); }
|
||||
public void renderStatusHTML(Writer out, int sortFlags) throws IOException {}
|
||||
public void renderStatusHTML(Writer out, String urlBase, int sortFlags) throws IOException {
|
||||
TreeSet peers = new TreeSet(getComparator(sortFlags));
|
||||
synchronized (_peersByIdent) {
|
||||
peers.addAll(_peersByIdent.values());
|
||||
}
|
||||
@ -1238,13 +1526,50 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
|
||||
StringBuffer buf = new StringBuffer(512);
|
||||
buf.append("<b id=\"udpcon\">UDP connections: ").append(peers.size()).append("</b><br />\n");
|
||||
buf.append("<table border=\"1\">\n");
|
||||
buf.append(" <tr><td><b><a href=\"#def.peer\">peer</a></b></td><td><b><a href=\"#def.idle\">idle</a></b></td>");
|
||||
buf.append(" <td><b><a href=\"#def.rate\">in/out</a></b></td>\n");
|
||||
buf.append(" <td><b><a href=\"#def.up\">up</a></b></td><td><b><a href=\"#def.skew\">skew</a></b></td>\n");
|
||||
buf.append(" <td><b><a href=\"#def.cwnd\">cwnd</a></b></td><td><b><a href=\"#def.ssthresh\">ssthresh</a></b></td>\n");
|
||||
buf.append(" <td><b><a href=\"#def.rtt\">rtt</a></b></td><td><b><a href=\"#def.dev\">dev</a></b></td><td><b><a href=\"#def.rto\">rto</a></b></td>\n");
|
||||
buf.append(" <td><b><a href=\"#def.mtu\">mtu</a></b></td><td><b><a href=\"#def.send\">send</a></b></td><td><b><a href=\"#def.recv\">recv</a></b></td>\n");
|
||||
buf.append(" <td><b><a href=\"#def.resent\">resent</a></b></td><td><b><a href=\"#def.dupRecv\">dupRecv</a></b></td>\n");
|
||||
buf.append(" <tr><td><b><a href=\"#def.peer\">peer</a></b>");
|
||||
if (sortFlags == FLAG_ALPHA)
|
||||
buf.append(" V ");
|
||||
else
|
||||
buf.append(" <a href=\"").append(urlBase).append("?sort=0\">V</a> ");
|
||||
buf.append("</td><td><b><a href=\"#def.idle\">idle</a></b>");
|
||||
appendSortLinks(buf, urlBase, sortFlags, "Sort by idle inbound", FLAG_IDLE_IN);
|
||||
buf.append("/");
|
||||
appendSortLinks(buf, urlBase, sortFlags, "Sort by idle outbound", FLAG_IDLE_OUT);
|
||||
buf.append("</td>");
|
||||
buf.append(" <td><b><a href=\"#def.rate\">in/out</a></b>");
|
||||
appendSortLinks(buf, urlBase, sortFlags, "Sort by inbound rate", FLAG_RATE_IN);
|
||||
buf.append("/");
|
||||
appendSortLinks(buf, urlBase, sortFlags, "Sort by outbound rate", FLAG_RATE_OUT);
|
||||
buf.append("</td>\n");
|
||||
buf.append(" <td><b><a href=\"#def.up\">up</a></b>");
|
||||
appendSortLinks(buf, urlBase, sortFlags, "Sort by connection uptime", FLAG_UPTIME);
|
||||
buf.append("</td><td><b><a href=\"#def.skew\">skew</a></b>");
|
||||
appendSortLinks(buf, urlBase, sortFlags, "Sort by clock skew", FLAG_SKEW);
|
||||
buf.append("</td>\n");
|
||||
buf.append(" <td><b><a href=\"#def.cwnd\">cwnd</a></b>");
|
||||
appendSortLinks(buf, urlBase, sortFlags, "Sort by congestion window", FLAG_CWND);
|
||||
buf.append("</td><td><b><a href=\"#def.ssthresh\">ssthresh</a></b>");
|
||||
appendSortLinks(buf, urlBase, sortFlags, "Sort by slow start threshold", FLAG_SSTHRESH);
|
||||
buf.append("</td>\n");
|
||||
buf.append(" <td><b><a href=\"#def.rtt\">rtt</a></b>");
|
||||
appendSortLinks(buf, urlBase, sortFlags, "Sort by round trip time", FLAG_RTT);
|
||||
buf.append("</td><td><b><a href=\"#def.dev\">dev</a></b>");
|
||||
appendSortLinks(buf, urlBase, sortFlags, "Sort by round trip time deviation", FLAG_DEV);
|
||||
buf.append("</td><td><b><a href=\"#def.rto\">rto</a></b>");
|
||||
appendSortLinks(buf, urlBase, sortFlags, "Sort by retransmission timeout", FLAG_RTO);
|
||||
buf.append("</td>\n");
|
||||
buf.append(" <td><b><a href=\"#def.mtu\">mtu</a></b>");
|
||||
appendSortLinks(buf, urlBase, sortFlags, "Sort by maximum transmit unit", FLAG_MTU);
|
||||
buf.append("</td><td><b><a href=\"#def.send\">send</a></b>");
|
||||
appendSortLinks(buf, urlBase, sortFlags, "Sort by packets sent", FLAG_SEND);
|
||||
buf.append("</td><td><b><a href=\"#def.recv\">recv</a></b>");
|
||||
appendSortLinks(buf, urlBase, sortFlags, "Sort by packets received", FLAG_RECV);
|
||||
buf.append("</td>\n");
|
||||
buf.append(" <td><b><a href=\"#def.resent\">resent</a></b>");
|
||||
appendSortLinks(buf, urlBase, sortFlags, "Sort by packets retransmitted", FLAG_RESEND);
|
||||
buf.append("</td><td><b><a href=\"#def.dupRecv\">dupRecv</a></b>");
|
||||
appendSortLinks(buf, urlBase, sortFlags, "Sort by packets received more than once", FLAG_DUP);
|
||||
buf.append("</td>\n");
|
||||
buf.append(" </tr>\n");
|
||||
out.write(buf.toString());
|
||||
buf.setLength(0);
|
||||
@ -1513,7 +1838,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
|
||||
public String toString() { return "UDP bid @ " + getLatencyMs(); }
|
||||
}
|
||||
|
||||
private static final int EXPIRE_TIMEOUT = 10*60*1000;
|
||||
private static final int EXPIRE_TIMEOUT = 30*60*1000;
|
||||
|
||||
private class ExpirePeerEvent implements SimpleTimer.TimedEvent {
|
||||
private List _expirePeers;
|
||||
@ -1539,7 +1864,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < _expireBuffer.size(); i++)
|
||||
dropPeer((PeerState)_expireBuffer.get(i), false);
|
||||
dropPeer((PeerState)_expireBuffer.get(i), false, "idle too long");
|
||||
_expireBuffer.clear();
|
||||
|
||||
if (_alive)
|
||||
|
@ -23,6 +23,7 @@ public class HopConfig {
|
||||
private SessionKey _ivKey;
|
||||
private SessionKey _replyKey;
|
||||
private ByteArray _replyIV;
|
||||
private long _creation;
|
||||
private long _expiration;
|
||||
private Map _options;
|
||||
private long _messagesProcessed;
|
||||
@ -37,8 +38,10 @@ public class HopConfig {
|
||||
_sendTo = null;
|
||||
_layerKey = null;
|
||||
_ivKey = null;
|
||||
_creation = -1;
|
||||
_expiration = -1;
|
||||
_options = null;
|
||||
_messagesProcessed = 0;
|
||||
}
|
||||
|
||||
/** what tunnel ID are we receiving on? */
|
||||
@ -94,6 +97,10 @@ public class HopConfig {
|
||||
/** when does this tunnel expire (in ms since the epoch)? */
|
||||
public long getExpiration() { return _expiration; }
|
||||
public void setExpiration(long when) { _expiration = when; }
|
||||
|
||||
/** when was this tunnel created (in ms since the epoch)? */
|
||||
public long getCreation() { return _creation; }
|
||||
public void setCreation(long when) { _creation = when; }
|
||||
|
||||
/**
|
||||
* what are the configuration options for this tunnel (if any). keys to
|
||||
|
@ -22,7 +22,7 @@ public class TrivialPreprocessor implements TunnelGateway.QueuePreprocessor {
|
||||
protected I2PAppContext _context;
|
||||
private Log _log;
|
||||
|
||||
static final int PREPROCESSED_SIZE = 1024;
|
||||
public static final int PREPROCESSED_SIZE = 1024;
|
||||
protected static final int IV_SIZE = HopProcessor.IV_LENGTH;
|
||||
protected static final ByteCache _dataCache = ByteCache.getInstance(512, PREPROCESSED_SIZE);
|
||||
protected static final ByteCache _ivCache = ByteCache.getInstance(128, IV_SIZE);
|
||||
|
@ -137,7 +137,7 @@ public class TunnelCreatorConfig implements TunnelInfo {
|
||||
}
|
||||
|
||||
|
||||
private static final int MAX_CONSECUTIVE_TEST_FAILURES = 2;
|
||||
private static final int MAX_CONSECUTIVE_TEST_FAILURES = 3;
|
||||
|
||||
/**
|
||||
* The tunnel failed, so stop using it
|
||||
|
@ -38,6 +38,8 @@ public class TunnelDispatcher implements Service {
|
||||
private long _lastParticipatingExpiration;
|
||||
private BloomFilterIVValidator _validator;
|
||||
private LeaveTunnel _leaveJob;
|
||||
/** what is the date/time we last deliberately dropped a tunnel? **/
|
||||
private long _lastDropTime;
|
||||
|
||||
/** Creates a new instance of TunnelDispatcher */
|
||||
public TunnelDispatcher(RouterContext ctx) {
|
||||
@ -49,6 +51,7 @@ public class TunnelDispatcher implements Service {
|
||||
_inboundGateways = new HashMap();
|
||||
_participatingConfig = new HashMap();
|
||||
_lastParticipatingExpiration = 0;
|
||||
_lastDropTime = 0;
|
||||
_validator = null;
|
||||
_leaveJob = new LeaveTunnel(ctx);
|
||||
ctx.statManager().createRateStat("tunnel.participatingTunnels",
|
||||
@ -527,6 +530,70 @@ public class TunnelDispatcher implements Service {
|
||||
return new ArrayList(_participatingConfig.values());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static final int DROP_BASE_INTERVAL = 40 * 1000;
|
||||
private static final int DROP_RANDOM_BOOST = 10 * 1000;
|
||||
|
||||
/**
|
||||
* If a router is too overloaded to build its own tunnels,
|
||||
* the build executor may call this.
|
||||
*/
|
||||
|
||||
public void dropBiggestParticipating() {
|
||||
|
||||
List partTunnels = listParticipatingTunnels();
|
||||
if ((partTunnels == null) || (partTunnels.size() == 0)) {
|
||||
if (_log.shouldLog(Log.ERROR))
|
||||
_log.error("Not dropping tunnel, since partTunnels was null or had 0 items!");
|
||||
return;
|
||||
}
|
||||
|
||||
long periodWithoutDrop = _context.clock().now() - _lastDropTime;
|
||||
if (periodWithoutDrop < DROP_BASE_INTERVAL) {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Not dropping tunnel, since last drop was " + periodWithoutDrop + " ms ago!");
|
||||
return;
|
||||
}
|
||||
|
||||
HopConfig biggest = null;
|
||||
HopConfig current = null;
|
||||
|
||||
long biggestMessages = 0;
|
||||
long biggestAge = -1;
|
||||
double biggestRate = 0;
|
||||
|
||||
for (int i=0; i<partTunnels.size(); i++) {
|
||||
|
||||
current = (HopConfig)partTunnels.get(i);
|
||||
|
||||
long currentMessages = current.getProcessedMessagesCount();
|
||||
long currentAge = (_context.clock().now() - current.getCreation());
|
||||
double currentRate = ((double) currentMessages / (currentAge / 1000));
|
||||
|
||||
// Determine if this is the biggest, but don't include tunnels
|
||||
// with less than 20 messages (unpredictable rates)
|
||||
if ((currentMessages > 20) && ((biggest == null) || (currentRate > biggestRate))) {
|
||||
// Update our profile of the biggest
|
||||
biggest = current;
|
||||
biggestMessages = currentMessages;
|
||||
biggestAge = currentAge;
|
||||
biggestRate = currentRate;
|
||||
}
|
||||
}
|
||||
|
||||
if (biggest == null) {
|
||||
if (_log.shouldLog(Log.ERROR))
|
||||
_log.error("Not dropping tunnel, since no suitable tunnel was found.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Dropping tunnel with " + biggestRate + " messages/s and " + biggestMessages +
|
||||
" messages, last drop was " + (periodWithoutDrop / 1000) + " s ago.");
|
||||
remove(biggest);
|
||||
_lastDropTime = _context.clock().now() + _context.random().nextInt(DROP_RANDOM_BOOST);
|
||||
}
|
||||
|
||||
public void startup() {
|
||||
// NB: 256 == assume max rate (size adjusted to handle 256 messages per second)
|
||||
|
@ -46,9 +46,6 @@ class BuildExecutor implements Runnable {
|
||||
_handler = new BuildHandler(ctx, this);
|
||||
}
|
||||
|
||||
// Estimated cost of one tunnel build attempt, bytes
|
||||
private static final int BUILD_BANDWIDTH_ESTIMATE_BYTES = 5*1024;
|
||||
|
||||
private int allowed() {
|
||||
StringBuffer buf = null;
|
||||
if (_log.shouldLog(Log.DEBUG)) {
|
||||
@ -118,52 +115,75 @@ class BuildExecutor implements Runnable {
|
||||
return 0; // if we have a job heavily blocking our jobqueue, ssllloowww dddooowwwnnn
|
||||
}
|
||||
|
||||
if (isOverloaded()) {
|
||||
int used1s = _context.router().get1sRate(true);
|
||||
// If 1-second average indicates we could manage building one tunnel
|
||||
if ((maxKBps*1024) - used1s > BUILD_BANDWIDTH_ESTIMATE_BYTES) {
|
||||
// Check if we're already building some tunnels
|
||||
if (concurrent > 0) {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Mild overload and favourable 1s rate (" + used1s + ") but already building, so allowed 0.");
|
||||
return 0;
|
||||
} else {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Mild overload and favourable 1s rate(" + used1s + "), so allowed 1.");
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
// Allow none
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("We had serious overload, so allowed building 0.");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
// Trim the number of allowed tunnels for overload,
|
||||
// initiate a tunnel drop on severe overload
|
||||
allowed = trimForOverload(allowed,concurrent);
|
||||
|
||||
return allowed;
|
||||
}
|
||||
|
||||
|
||||
// Estimated cost of tunnel build attempt, bytes
|
||||
private static final int BUILD_BANDWIDTH_ESTIMATE_BYTES = 5*1024;
|
||||
|
||||
/**
|
||||
* Don't even try to build tunnels if we're saturated
|
||||
*/
|
||||
private boolean isOverloaded() {
|
||||
//if (true) return false;
|
||||
private int trimForOverload(int allowed, int concurrent) {
|
||||
|
||||
// dont include the inbound rates when throttling tunnel building, since
|
||||
// that'd expose a pretty trivial attack.
|
||||
int maxKBps = _context.bandwidthLimiter().getOutboundKBytesPerSecond();
|
||||
int used1s = 0; // dont throttle on the 1s rate, its too volatile
|
||||
int used1m = _context.router().get1mRate(true);
|
||||
int used5m = 0; //get5mRate(_context); // don't throttle on the 5m rate, as that'd hide available bandwidth
|
||||
int used = Math.max(Math.max(used1s, used1m), used5m);
|
||||
if ((maxKBps * 1024) - used <= 0) {
|
||||
int used1s = _context.router().get1sRate(true); // Avoid reliance on the 1s rate, too volatile
|
||||
int used15s = _context.router().get15sRate(true);
|
||||
int used1m = _context.router().get1mRate(true); // Avoid reliance on the 1m rate, too slow
|
||||
|
||||
int maxKBps = _context.bandwidthLimiter().getOutboundKBytesPerSecond();
|
||||
int maxBps = maxKBps * 1024;
|
||||
int overBuildLimit = maxBps - BUILD_BANDWIDTH_ESTIMATE_BYTES; // Beyond this, refrain from building
|
||||
int nearBuildLimit = maxBps - (2*BUILD_BANDWIDTH_ESTIMATE_BYTES); // Beyond this, consider it close
|
||||
|
||||
// Detect any fresh overload which could set back tunnel building
|
||||
if (Math.max(used1s,used15s) > overBuildLimit) {
|
||||
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Too overloaded to build our own tunnels (used=" + used + ", maxKBps=" + maxKBps + ", 1s=" + used1s + ", 1m=" + used1m + ")");
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
_log.warn("Overloaded, trouble building tunnels (maxKBps=" + maxKBps +
|
||||
", 1s=" + used1s + ", 15s=" + used15s + ", 1m=" + used1m + ")");
|
||||
|
||||
// Detect serious overload
|
||||
if (((used1s > maxBps) && (used1s > used15s) && (used15s > nearBuildLimit)) ||
|
||||
((used1s > maxBps) && (used15s > overBuildLimit)) ||
|
||||
((used1s > overBuildLimit) && (used15s > overBuildLimit))) {
|
||||
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Serious overload, allow building 0.");
|
||||
|
||||
// If so configured, drop biggest participating tunnel
|
||||
if (Boolean.valueOf(_context.getProperty("router.dropTunnelsOnOverload","false")).booleanValue() == true) {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Requesting drop of biggest participating tunnel.");
|
||||
_context.tunnelDispatcher().dropBiggestParticipating();
|
||||
}
|
||||
return(0);
|
||||
} else {
|
||||
// Mild overload, check if we already build tunnels
|
||||
if (concurrent == 0) {
|
||||
// We aren't building, allow 1
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Mild overload, allow building 1.");
|
||||
return(1);
|
||||
} else {
|
||||
// Already building, allow 0
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Mild overload but already building " + concurrent + ", so allow 0.");
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
// No overload, allow as requested
|
||||
return(allowed);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void run() {
|
||||
_isRunning = true;
|
||||
List wanted = new ArrayList(8);
|
||||
|
@ -438,6 +438,7 @@ class BuildHandler {
|
||||
|
||||
if (response == 0) {
|
||||
HopConfig cfg = new HopConfig();
|
||||
cfg.setCreation(_context.clock().now());
|
||||
cfg.setExpiration(_context.clock().now() + 10*60*1000);
|
||||
cfg.setIVKey(req.readIVKey());
|
||||
cfg.setLayerKey(req.readLayerKey());
|
||||
@ -641,7 +642,7 @@ class BuildHandler {
|
||||
|
||||
private int estimateQueueTime(int numPendingMessages) {
|
||||
int decryptTime = 200;
|
||||
RateStat rs = _context.statManager().getRate("crypto.elGamal.decrypt");
|
||||
RateStat rs = _context.statManager().getRate("tunnel.decryptRequestTime");
|
||||
if (rs != null) {
|
||||
Rate r = rs.getRate(60*1000);
|
||||
double avg = 0;
|
||||
|
@ -118,6 +118,7 @@ public class HandleTunnelCreateMessageJob extends JobImpl {
|
||||
|
||||
HopConfig cfg = new HopConfig();
|
||||
long expiration = _request.getDurationSeconds()*1000 + getContext().clock().now();
|
||||
cfg.setCreation(getContext().clock().now());
|
||||
cfg.setExpiration(expiration);
|
||||
cfg.setIVKey(_request.getIVKey());
|
||||
cfg.setLayerKey(_request.getLayerKey());
|
||||
|
@ -607,6 +607,7 @@ public class TunnelPool {
|
||||
int j = peers.size() - 1 - i;
|
||||
cfg.setPeer(j, (Hash)peers.get(i));
|
||||
HopConfig hop = cfg.getConfig(j);
|
||||
hop.setCreation(_context.clock().now());
|
||||
hop.setExpiration(expiration);
|
||||
hop.setIVKey(_context.keyGenerator().generateSessionKey());
|
||||
hop.setLayerKey(_context.keyGenerator().generateSessionKey());
|
||||
|
Reference in New Issue
Block a user