merge of '5cbdacfbeb8f09f9ac497016e429eaf6fe7225c6'
and 'dae5a2b76e24fc3215d46d5b96ea0f547c83f63c'
This commit is contained in:
10
INSTALL.txt
10
INSTALL.txt
@ -1,10 +1,17 @@
|
|||||||
I2P source installation instructions
|
I2P source installation instructions
|
||||||
|
|
||||||
|
Prerequisites to build from source:
|
||||||
|
Java SDK (preferably Sun) 1.5.0 or higher (1.6 recommended)
|
||||||
|
Apache Ant 1.7.0 or higher
|
||||||
|
Optional, For multilanguage support: The xgettext, msgfmt, and msgmerge tools installed
|
||||||
|
from the GNU gettext package http://www.gnu.org/software/gettext/
|
||||||
|
|
||||||
To build and install I2P from source, you must first build
|
To build and install I2P from source, you must first build
|
||||||
and package up the appropriate installer by running:
|
and package up the appropriate installer by running:
|
||||||
|
|
||||||
ant pkg
|
ant pkg
|
||||||
|
|
||||||
|
|
||||||
This will produce a few key files:
|
This will produce a few key files:
|
||||||
* install.jar: the GUI and console installer
|
* install.jar: the GUI and console installer
|
||||||
* i2pinstall.exe: the GUI and console installer wrapped for cross-platform execution
|
* i2pinstall.exe: the GUI and console installer wrapped for cross-platform execution
|
||||||
@ -18,9 +25,6 @@ Or run the GUI installer:
|
|||||||
|
|
||||||
Or move the update file into an existing installation directory and restart.
|
Or move the update file into an existing installation directory and restart.
|
||||||
|
|
||||||
You will need to have ant installed from http://ant.apache.org/
|
|
||||||
(1.7.0 or newer)
|
|
||||||
|
|
||||||
Supported JVMs:
|
Supported JVMs:
|
||||||
Windows: Latest available from http://java.sun.com/ (1.5+ supported)
|
Windows: Latest available from http://java.sun.com/ (1.5+ supported)
|
||||||
Linux: Latest available from http://java.sun.com/ (1.5+ supported)
|
Linux: Latest available from http://java.sun.com/ (1.5+ supported)
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
Prerequisites to build from source:
|
Prerequisites to build from source:
|
||||||
Java SDK (preferably Sun) 1.5.0 or higher (1.6 recommended)
|
Java SDK (preferably Sun) 1.5.0 or higher (1.6 recommended)
|
||||||
Apache Ant 1.7.0 or higher
|
Apache Ant 1.7.0 or higher
|
||||||
|
Optional, For multilanguage support: The xgettext, msgfmt, and msgmerge tools installed
|
||||||
|
from the GNU gettext package http://www.gnu.org/software/gettext/
|
||||||
|
|
||||||
To build:
|
To build:
|
||||||
ant pkg
|
ant pkg
|
||||||
Run 'ant' with no arguments to see other build options.
|
Run 'ant' with no arguments to see other build options.
|
||||||
See http://www.i2p2.de/download.html for installation instructions.
|
See INSTALL.txt or http://www.i2p2.de/download.html for installation instructions.
|
||||||
|
|
||||||
Documentation:
|
Documentation:
|
||||||
http://www.i2p2.de/
|
http://www.i2p2.de/
|
||||||
|
@ -179,7 +179,7 @@ public class NewsFetcher implements Runnable, EepGet.StatusListener {
|
|||||||
if (get.fetch()) {
|
if (get.fetch()) {
|
||||||
String lastmod = get.getLastModified();
|
String lastmod = get.getLastModified();
|
||||||
if (lastmod != null) {
|
if (lastmod != null) {
|
||||||
if (!(_context instanceof RouterContext)) return;
|
if (!(_context.isRouterContext())) return;
|
||||||
long modtime = parse822Date(lastmod);
|
long modtime = parse822Date(lastmod);
|
||||||
if (modtime <= 0) return;
|
if (modtime <= 0) return;
|
||||||
String lastUpdate = _context.getProperty(UpdateHandler.PROP_LAST_UPDATE_TIME);
|
String lastUpdate = _context.getProperty(UpdateHandler.PROP_LAST_UPDATE_TIME);
|
||||||
@ -310,7 +310,7 @@ public class NewsFetcher implements Runnable, EepGet.StatusListener {
|
|||||||
if (_log.shouldLog(Log.DEBUG))
|
if (_log.shouldLog(Log.DEBUG))
|
||||||
_log.debug("Policy requests update, so we update");
|
_log.debug("Policy requests update, so we update");
|
||||||
UpdateHandler handler = null;
|
UpdateHandler handler = null;
|
||||||
if (_context instanceof RouterContext) {
|
if (_context.isRouterContext()) {
|
||||||
handler = new UpdateHandler((RouterContext)_context);
|
handler = new UpdateHandler((RouterContext)_context);
|
||||||
} else {
|
} else {
|
||||||
List contexts = RouterContext.listContexts();
|
List contexts = RouterContext.listContexts();
|
||||||
|
@ -40,7 +40,7 @@ public class StatsGenerator {
|
|||||||
String group = (String)entry.getKey();
|
String group = (String)entry.getKey();
|
||||||
Set stats = (Set)entry.getValue();
|
Set stats = (Set)entry.getValue();
|
||||||
buf.append("<option value=\"/stats.jsp#").append(group).append("\">");
|
buf.append("<option value=\"/stats.jsp#").append(group).append("\">");
|
||||||
buf.append(group).append("</option>\n");
|
buf.append(_(group)).append("</option>\n");
|
||||||
for (Iterator statIter = stats.iterator(); statIter.hasNext(); ) {
|
for (Iterator statIter = stats.iterator(); statIter.hasNext(); ) {
|
||||||
String stat = (String)statIter.next();
|
String stat = (String)statIter.next();
|
||||||
buf.append("<option value=\"/stats.jsp#");
|
buf.append("<option value=\"/stats.jsp#");
|
||||||
@ -52,7 +52,7 @@ public class StatsGenerator {
|
|||||||
out.write(buf.toString());
|
out.write(buf.toString());
|
||||||
buf.setLength(0);
|
buf.setLength(0);
|
||||||
}
|
}
|
||||||
buf.append("</select> <input type=\"submit\" value=\"GO\" />");
|
buf.append("</select> <input type=\"submit\" value=\"").append(_("GO")).append("\" />");
|
||||||
buf.append("</form>");
|
buf.append("</form>");
|
||||||
|
|
||||||
buf.append(_("Statistics gathered during this router's uptime")).append(" (");
|
buf.append(_("Statistics gathered during this router's uptime")).append(" (");
|
||||||
@ -69,7 +69,7 @@ public class StatsGenerator {
|
|||||||
buf.append("<h3><a name=\"");
|
buf.append("<h3><a name=\"");
|
||||||
buf.append(group);
|
buf.append(group);
|
||||||
buf.append("\">");
|
buf.append("\">");
|
||||||
buf.append(group);
|
buf.append(_(group));
|
||||||
buf.append("</a></h3>");
|
buf.append("</a></h3>");
|
||||||
buf.append("<ul>");
|
buf.append("<ul>");
|
||||||
out.write(buf.toString());
|
out.write(buf.toString());
|
||||||
@ -104,7 +104,7 @@ public class StatsGenerator {
|
|||||||
for (int i = 0; i < periods.length; i++) {
|
for (int i = 0; i < periods.length; i++) {
|
||||||
if (periods[i] > uptime)
|
if (periods[i] > uptime)
|
||||||
break;
|
break;
|
||||||
renderPeriod(buf, periods[i], "frequency");
|
renderPeriod(buf, periods[i], _("frequency"));
|
||||||
Frequency curFreq = freq.getFrequency(periods[i]);
|
Frequency curFreq = freq.getFrequency(periods[i]);
|
||||||
buf.append(" <i>avg per period:</i> (");
|
buf.append(" <i>avg per period:</i> (");
|
||||||
buf.append(num(curFreq.getAverageEventsPerPeriod()));
|
buf.append(num(curFreq.getAverageEventsPerPeriod()));
|
||||||
@ -138,7 +138,7 @@ public class StatsGenerator {
|
|||||||
buf.append("</i><br>");
|
buf.append("</i><br>");
|
||||||
}
|
}
|
||||||
if (rate.getLifetimeEventCount() <= 0) {
|
if (rate.getLifetimeEventCount() <= 0) {
|
||||||
buf.append("No lifetime events<br>\n");
|
buf.append(_("No lifetime events")).append("<br>\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
long now = _context.clock().now();
|
long now = _context.clock().now();
|
||||||
@ -150,9 +150,9 @@ public class StatsGenerator {
|
|||||||
if (curRate.getLastCoalesceDate() <= curRate.getCreationDate())
|
if (curRate.getLastCoalesceDate() <= curRate.getCreationDate())
|
||||||
break;
|
break;
|
||||||
buf.append("<li>");
|
buf.append("<li>");
|
||||||
renderPeriod(buf, periods[i], "rate");
|
renderPeriod(buf, periods[i], _("rate"));
|
||||||
if (curRate.getLastEventCount() > 0) {
|
if (curRate.getLastEventCount() > 0) {
|
||||||
buf.append( "<i>avg value:</i> (");
|
buf.append( "<i>").append(_("avg value")).append(":</i> (");
|
||||||
buf.append(num(curRate.getAverageValue()));
|
buf.append(num(curRate.getAverageValue()));
|
||||||
buf.append(" peak ");
|
buf.append(" peak ");
|
||||||
buf.append(num(curRate.getExtremeAverageValue()));
|
buf.append(num(curRate.getExtremeAverageValue()));
|
||||||
@ -181,21 +181,21 @@ public class StatsGenerator {
|
|||||||
buf.append(num(curRate.getExtremeSaturationLimit()));
|
buf.append(num(curRate.getExtremeSaturationLimit()));
|
||||||
buf.append(")");
|
buf.append(")");
|
||||||
}
|
}
|
||||||
buf.append(" <i>events:</i> ");
|
buf.append(" <i>").append(_("events")).append(":</i> ");
|
||||||
buf.append(curRate.getLastEventCount());
|
buf.append(curRate.getLastEventCount());
|
||||||
buf.append(" <i>in this period which ended:</i> ");
|
buf.append(" <i>in this period which ended:</i> ");
|
||||||
buf.append(DataHelper.formatDuration(now - curRate.getLastCoalesceDate()));
|
buf.append(DataHelper.formatDuration(now - curRate.getLastCoalesceDate()));
|
||||||
buf.append(" ago ");
|
buf.append(" ago ");
|
||||||
} else {
|
} else {
|
||||||
buf.append(" <i>No events</i> ");
|
buf.append(" <i>").append(_("No events")).append("</i> ");
|
||||||
}
|
}
|
||||||
long numPeriods = curRate.getLifetimePeriods();
|
long numPeriods = curRate.getLifetimePeriods();
|
||||||
if (numPeriods > 0) {
|
if (numPeriods > 0) {
|
||||||
double avgFrequency = curRate.getLifetimeEventCount() / (double)numPeriods;
|
double avgFrequency = curRate.getLifetimeEventCount() / (double)numPeriods;
|
||||||
double peakFrequency = curRate.getExtremeEventCount();
|
double peakFrequency = curRate.getExtremeEventCount();
|
||||||
buf.append(" (lifetime average: ");
|
buf.append(" (").append(_("lifetime average")).append(": ");
|
||||||
buf.append(num(avgFrequency));
|
buf.append(num(avgFrequency));
|
||||||
buf.append(", peak average: ");
|
buf.append(", ").append(_("peak average")).append(": ");
|
||||||
buf.append(curRate.getExtremeEventCount());
|
buf.append(curRate.getExtremeEventCount());
|
||||||
buf.append(")");
|
buf.append(")");
|
||||||
}
|
}
|
||||||
@ -213,7 +213,7 @@ public class StatsGenerator {
|
|||||||
buf.append("</li>\n");
|
buf.append("</li>\n");
|
||||||
}
|
}
|
||||||
// Display the strict average
|
// Display the strict average
|
||||||
buf.append("<li><b>lifetime average value:</b> ");
|
buf.append("<li><b>").append(_("lifetime average value")).append(":</b> ");
|
||||||
buf.append(num(rate.getLifetimeAverageValue()));
|
buf.append(num(rate.getLifetimeAverageValue()));
|
||||||
buf.append(" over ");
|
buf.append(" over ");
|
||||||
buf.append(rate.getLifetimeEventCount());
|
buf.append(rate.getLifetimeEventCount());
|
||||||
@ -240,4 +240,9 @@ public class StatsGenerator {
|
|||||||
private String _(String s) {
|
private String _(String s) {
|
||||||
return Messages.getString(s, _context);
|
return Messages.getString(s, _context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** translate a string */
|
||||||
|
private String _(String s, Object o) {
|
||||||
|
return Messages.getString(s, o, _context);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -62,6 +62,9 @@ public class SummaryHelper extends HelperBase {
|
|||||||
return DataHelper.formatDuration(router.getUptime());
|
return DataHelper.formatDuration(router.getUptime());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
this displayed offset, not skew - now handled in reachability()
|
||||||
|
|
||||||
private String timeSkew() {
|
private String timeSkew() {
|
||||||
if (_context == null) return "";
|
if (_context == null) return "";
|
||||||
//if (!_context.clock().getUpdatedSuccessfully())
|
//if (!_context.clock().getUpdatedSuccessfully())
|
||||||
@ -72,6 +75,7 @@ public class SummaryHelper extends HelperBase {
|
|||||||
return "";
|
return "";
|
||||||
return " (" + DataHelper.formatDuration(diff) + " " + _("skew") + ")";
|
return " (" + DataHelper.formatDuration(diff) + " " + _("skew") + ")";
|
||||||
}
|
}
|
||||||
|
**/
|
||||||
|
|
||||||
public boolean allowReseed() {
|
public boolean allowReseed() {
|
||||||
return _context.netDb().isInitialized() &&
|
return _context.netDb().isInitialized() &&
|
||||||
@ -83,15 +87,20 @@ public class SummaryHelper extends HelperBase {
|
|||||||
public int getAllPeers() { return Math.max(_context.netDb().getKnownRouters() - 1, 0); }
|
public int getAllPeers() { return Math.max(_context.netDb().getKnownRouters() - 1, 0); }
|
||||||
|
|
||||||
public String getReachability() {
|
public String getReachability() {
|
||||||
return reachability() + timeSkew();
|
return reachability(); // + timeSkew();
|
||||||
}
|
}
|
||||||
|
|
||||||
private String reachability() {
|
private String reachability() {
|
||||||
if (_context.router().getUptime() > 60*1000 && (!_context.router().gracefulShutdownInProgress()) &&
|
if (_context.router().getUptime() > 60*1000 && (!_context.router().gracefulShutdownInProgress()) &&
|
||||||
!_context.clientManager().isAlive())
|
!_context.clientManager().isAlive())
|
||||||
return _("ERR-Client Manager I2CP Error - check logs"); // not a router problem but the user should know
|
return _("ERR-Client Manager I2CP Error - check logs"); // not a router problem but the user should know
|
||||||
if (!_context.clock().getUpdatedSuccessfully())
|
// Warn based on actual skew from peers, not update status, so if we successfully offset
|
||||||
return _("ERR-ClockSkew");
|
// the clock, we don't complain.
|
||||||
|
//if (!_context.clock().getUpdatedSuccessfully())
|
||||||
|
Long skew = _context.commSystem().getFramedAveragePeerClockSkew(33);
|
||||||
|
// Display the actual skew, not the offset
|
||||||
|
if (skew != null && Math.abs(skew.longValue()) > 45)
|
||||||
|
return _("ERR-Clock Skew of {0}", DataHelper.formatDuration(Math.abs(skew.longValue()) * 1000));
|
||||||
if (_context.router().isHidden())
|
if (_context.router().isHidden())
|
||||||
return _("Hidden");
|
return _("Hidden");
|
||||||
|
|
||||||
@ -118,7 +127,9 @@ public class SummaryHelper extends HelperBase {
|
|||||||
default:
|
default:
|
||||||
ra = _context.router().getRouterInfo().getTargetAddress("SSU");
|
ra = _context.router().getRouterInfo().getTargetAddress("SSU");
|
||||||
if (ra == null && _context.router().getUptime() > 5*60*1000) {
|
if (ra == null && _context.router().getUptime() > 5*60*1000) {
|
||||||
if (_context.getProperty(ConfigNetHelper.PROP_I2NP_NTCP_HOSTNAME) == null ||
|
if (getActivePeers() <= 0)
|
||||||
|
return _("ERR-No Active Peers, Check Network Connection and Firewall");
|
||||||
|
else if (_context.getProperty(ConfigNetHelper.PROP_I2NP_NTCP_HOSTNAME) == null ||
|
||||||
_context.getProperty(ConfigNetHelper.PROP_I2NP_NTCP_PORT) == null)
|
_context.getProperty(ConfigNetHelper.PROP_I2NP_NTCP_PORT) == null)
|
||||||
return _("ERR-UDP Disabled and Inbound TCP host/port not set");
|
return _("ERR-UDP Disabled and Inbound TCP host/port not set");
|
||||||
else
|
else
|
||||||
|
@ -233,7 +233,7 @@ public class TunnelRenderer {
|
|||||||
Collections.sort(peerList, new CountryComparator(this._context.commSystem()));
|
Collections.sort(peerList, new CountryComparator(this._context.commSystem()));
|
||||||
|
|
||||||
out.write("<h2><a name=\"peers\"></a>" + _("Tunnel Counts By Peer") + "</h2>\n");
|
out.write("<h2><a name=\"peers\"></a>" + _("Tunnel Counts By Peer") + "</h2>\n");
|
||||||
out.write("<table><tr><th>" + _("Peer") + "</th><th>" + _("Expl. + Client") + "</th><th>" + _("% of total") + "</th><th>" + _("Part. from + to") + "</th><th>" + _("% of total") + "</th></tr>\n");
|
out.write("<table><tr><th>" + _("Peer") + "</th><th>" + _("Our Tunnels") + "</th><th>" + _("% of total") + "</th><th>" + _("Participating Tunnels") + "</th><th>" + _("% of total") + "</th></tr>\n");
|
||||||
for (Hash h : peerList) {
|
for (Hash h : peerList) {
|
||||||
out.write("<tr> <td class=\"cells\" align=\"center\">");
|
out.write("<tr> <td class=\"cells\" align=\"center\">");
|
||||||
out.write(netDbLink(h));
|
out.write(netDbLink(h));
|
||||||
@ -251,7 +251,7 @@ public class TunnelRenderer {
|
|||||||
out.write('0');
|
out.write('0');
|
||||||
out.write('\n');
|
out.write('\n');
|
||||||
}
|
}
|
||||||
out.write("<tr class=\"tablefooter\"> <td align=\"center\"><b>" + _("Tunnels") + "</b> <td align=\"center\"><b>" + tunnelCount);
|
out.write("<tr class=\"tablefooter\"> <td align=\"center\"><b>" + _("Totals") + "</b> <td align=\"center\"><b>" + tunnelCount);
|
||||||
out.write("</b> <td> </td> <td align=\"center\"><b>" + partCount);
|
out.write("</b> <td> </td> <td align=\"center\"><b>" + partCount);
|
||||||
out.write("</b> <td> </td></tr></table></div>\n");
|
out.write("</b> <td> </td></tr></table></div>\n");
|
||||||
}
|
}
|
||||||
|
@ -52,5 +52,24 @@ class Dummy {
|
|||||||
_("dark");
|
_("dark");
|
||||||
_("light");
|
_("light");
|
||||||
_("midnight");
|
_("midnight");
|
||||||
|
|
||||||
|
// stat groups for stats.jsp
|
||||||
|
_("Bandwidth");
|
||||||
|
_("BandwidthLimiter");
|
||||||
|
_("ClientMessages");
|
||||||
|
_("Encryption");
|
||||||
|
_("i2cp");
|
||||||
|
_("I2PTunnel");
|
||||||
|
_("InNetPool");
|
||||||
|
_("JobQueue");
|
||||||
|
_("NetworkDatabase");
|
||||||
|
_("ntcp");
|
||||||
|
_("Peers");
|
||||||
|
_("Router");
|
||||||
|
_("Stream");
|
||||||
|
_("Throttle");
|
||||||
|
_("Transport");
|
||||||
|
_("Tunnels");
|
||||||
|
_("udp");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -722,4 +722,11 @@ public class I2PAppContext {
|
|||||||
return new HashSet(_shutdownTasks);
|
return new HashSet(_shutdownTasks);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use this instead of context instanceof RouterContext
|
||||||
|
* @since 0.7.9
|
||||||
|
*/
|
||||||
|
public boolean isRouterContext() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -170,6 +170,7 @@ public class RateStat {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*********
|
||||||
public static void main(String args[]) {
|
public static void main(String args[]) {
|
||||||
RateStat rs = new RateStat("moo", "moo moo moo", "cow trueisms", new long[] { 60 * 1000, 60 * 60 * 1000,
|
RateStat rs = new RateStat("moo", "moo moo moo", "cow trueisms", new long[] { 60 * 1000, 60 * 60 * 1000,
|
||||||
24 * 60 * 60 * 1000});
|
24 * 60 * 60 * 1000});
|
||||||
@ -206,4 +207,5 @@ public class RateStat {
|
|||||||
} catch (InterruptedException ie) { // nop
|
} catch (InterruptedException ie) { // nop
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*********/
|
||||||
}
|
}
|
||||||
|
@ -189,7 +189,10 @@ public class Timestamper implements Runnable {
|
|||||||
long expectedDelta = 0;
|
long expectedDelta = 0;
|
||||||
_wellSynced = false;
|
_wellSynced = false;
|
||||||
for (int i = 0; i < _concurringServers; i++) {
|
for (int i = 0; i < _concurringServers; i++) {
|
||||||
try { Thread.sleep(10*1000); } catch (InterruptedException ie) {}
|
if (i > 0) {
|
||||||
|
// this delays startup when net is disconnected or the timeserver list is bad, don't make it too long
|
||||||
|
try { Thread.sleep(2*1000); } catch (InterruptedException ie) {}
|
||||||
|
}
|
||||||
now = NtpClient.currentTime(serverList);
|
now = NtpClient.currentTime(serverList);
|
||||||
long delta = now - _context.clock().now();
|
long delta = now - _context.clock().now();
|
||||||
found[i] = delta;
|
found[i] = delta;
|
||||||
|
@ -41,6 +41,7 @@ import net.i2p.stat.Rate;
|
|||||||
import net.i2p.stat.RateStat;
|
import net.i2p.stat.RateStat;
|
||||||
import net.i2p.stat.StatManager;
|
import net.i2p.stat.StatManager;
|
||||||
import net.i2p.util.FileUtil;
|
import net.i2p.util.FileUtil;
|
||||||
|
import net.i2p.util.I2PAppThread;
|
||||||
import net.i2p.util.I2PThread;
|
import net.i2p.util.I2PThread;
|
||||||
import net.i2p.util.Log;
|
import net.i2p.util.Log;
|
||||||
import net.i2p.util.SimpleScheduler;
|
import net.i2p.util.SimpleScheduler;
|
||||||
@ -201,6 +202,8 @@ public class Router {
|
|||||||
installUpdates();
|
installUpdates();
|
||||||
|
|
||||||
// Apps may use this as an easy way to determine if they are in the router JVM
|
// Apps may use this as an easy way to determine if they are in the router JVM
|
||||||
|
// But context.isRouterContext() is even easier...
|
||||||
|
// Both of these as of 0.7.9
|
||||||
System.setProperty("router.version", RouterVersion.VERSION);
|
System.setProperty("router.version", RouterVersion.VERSION);
|
||||||
|
|
||||||
// NOW we start all the activity
|
// NOW we start all the activity
|
||||||
@ -228,14 +231,10 @@ public class Router {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
_shutdownHook = new ShutdownHook(_context);
|
_shutdownHook = new ShutdownHook(_context);
|
||||||
_gracefulShutdownDetector = new I2PThread(new GracefulShutdown());
|
_gracefulShutdownDetector = new I2PAppThread(new GracefulShutdown(), "Graceful shutdown hook", true);
|
||||||
_gracefulShutdownDetector.setDaemon(true);
|
|
||||||
_gracefulShutdownDetector.setName("Graceful shutdown hook");
|
|
||||||
_gracefulShutdownDetector.start();
|
_gracefulShutdownDetector.start();
|
||||||
|
|
||||||
I2PThread watchdog = new I2PThread(new RouterWatchdog(_context));
|
Thread watchdog = new I2PAppThread(new RouterWatchdog(_context), "RouterWatchdog", true);
|
||||||
watchdog.setName("RouterWatchdog");
|
|
||||||
watchdog.setDaemon(true);
|
|
||||||
watchdog.start();
|
watchdog.start();
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -339,7 +338,7 @@ public class Router {
|
|||||||
long waited = System.currentTimeMillis() - before;
|
long waited = System.currentTimeMillis() - before;
|
||||||
if (_log.shouldLog(Log.INFO))
|
if (_log.shouldLog(Log.INFO))
|
||||||
_log.info("Waited " + waited + "ms to initialize");
|
_log.info("Waited " + waited + "ms to initialize");
|
||||||
|
|
||||||
_context.jobQueue().addJob(new StartupJob(_context));
|
_context.jobQueue().addJob(new StartupJob(_context));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -379,4 +379,12 @@ public class RouterContext extends I2PAppContext {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use this instead of context instanceof RouterContext
|
||||||
|
* @return true
|
||||||
|
* @since 0.7.9
|
||||||
|
*/
|
||||||
|
public boolean isRouterContext() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@ import java.util.StringTokenizer;
|
|||||||
import net.i2p.I2PAppContext;
|
import net.i2p.I2PAppContext;
|
||||||
import net.i2p.router.RouterContext;
|
import net.i2p.router.RouterContext;
|
||||||
import net.i2p.util.EepGet;
|
import net.i2p.util.EepGet;
|
||||||
import net.i2p.util.I2PThread;
|
import net.i2p.util.I2PAppThread;
|
||||||
import net.i2p.util.Log;
|
import net.i2p.util.Log;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -52,13 +52,15 @@ public class Reseeder {
|
|||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
System.setProperty(PROP_INPROGRESS, "true");
|
System.setProperty(PROP_INPROGRESS, "true");
|
||||||
I2PThread reseed = new I2PThread(_reseedRunner, "Reseed");
|
// set to daemon so it doesn't hang a shutdown
|
||||||
|
Thread reseed = new I2PAppThread(_reseedRunner, "Reseed", true);
|
||||||
reseed.start();
|
reseed.start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Todo: translate the messages sent via PROP_STATUS */
|
||||||
public class ReseedRunner implements Runnable, EepGet.StatusListener {
|
public class ReseedRunner implements Runnable, EepGet.StatusListener {
|
||||||
private boolean _isRunning;
|
private boolean _isRunning;
|
||||||
|
|
||||||
|
@ -105,6 +105,7 @@ public class DBHistory {
|
|||||||
*/
|
*/
|
||||||
public RateStat getFailedLookupRate() { return _failedLookupRate; }
|
public RateStat getFailedLookupRate() { return _failedLookupRate; }
|
||||||
|
|
||||||
|
/** not sure how much this is used, to be investigated */
|
||||||
public RateStat getInvalidReplyRate() { return _invalidReplyRate; }
|
public RateStat getInvalidReplyRate() { return _invalidReplyRate; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -115,6 +116,7 @@ public class DBHistory {
|
|||||||
public void lookupSuccessful() {
|
public void lookupSuccessful() {
|
||||||
_successfulLookups++;
|
_successfulLookups++;
|
||||||
_failedLookupRate.addData(0, 0);
|
_failedLookupRate.addData(0, 0);
|
||||||
|
_context.statManager().addRateData("peer.failedLookupRate", 0, 0);
|
||||||
_lastLookupSuccessful = _context.clock().now();
|
_lastLookupSuccessful = _context.clock().now();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -124,6 +126,7 @@ public class DBHistory {
|
|||||||
public void lookupFailed() {
|
public void lookupFailed() {
|
||||||
_failedLookups++;
|
_failedLookups++;
|
||||||
_failedLookupRate.addData(1, 0);
|
_failedLookupRate.addData(1, 0);
|
||||||
|
_context.statManager().addRateData("peer.failedLookupRate", 1, 0);
|
||||||
_lastLookupFailed = _context.clock().now();
|
_lastLookupFailed = _context.clock().now();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -136,6 +139,7 @@ public class DBHistory {
|
|||||||
// Fixme, redefined this to include both lookup and store fails,
|
// Fixme, redefined this to include both lookup and store fails,
|
||||||
// need to fix the javadocs
|
// need to fix the javadocs
|
||||||
_failedLookupRate.addData(0, 0);
|
_failedLookupRate.addData(0, 0);
|
||||||
|
_context.statManager().addRateData("peer.failedLookupRate", 0, 0);
|
||||||
_lastStoreSuccessful = _context.clock().now();
|
_lastStoreSuccessful = _context.clock().now();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -275,9 +279,9 @@ public class DBHistory {
|
|||||||
|
|
||||||
private void createRates(String statGroup) {
|
private void createRates(String statGroup) {
|
||||||
if (_failedLookupRate == null)
|
if (_failedLookupRate == null)
|
||||||
_failedLookupRate = new RateStat("dbHistory.failedLookupRate", "How often does this peer to respond to a lookup?", statGroup, new long[] { 60*1000l, 60*60*1000l, 24*60*60*1000l });
|
_failedLookupRate = new RateStat("dbHistory.failedLookupRate", "How often does this peer to respond to a lookup?", statGroup, new long[] { 10*60*1000l, 60*60*1000l, 24*60*60*1000l });
|
||||||
if (_invalidReplyRate == null)
|
if (_invalidReplyRate == null)
|
||||||
_invalidReplyRate = new RateStat("dbHistory.invalidReplyRate", "How often does this peer give us a bad (nonexistant, forged, etc) peer?", statGroup, new long[] { 30*60*1000l, 60*60*1000l, 24*60*60*1000l });
|
_invalidReplyRate = new RateStat("dbHistory.invalidReplyRate", "How often does this peer give us a bad (nonexistant, forged, etc) peer?", statGroup, new long[] { 30*60*1000l });
|
||||||
_failedLookupRate.setStatLog(_context.statManager().getStatLog());
|
_failedLookupRate.setStatLog(_context.statManager().getStatLog());
|
||||||
_invalidReplyRate.setStatLog(_context.statManager().getStatLog());
|
_invalidReplyRate.setStatLog(_context.statManager().getStatLog());
|
||||||
}
|
}
|
||||||
|
@ -97,10 +97,10 @@ public class ProfileOrganizer {
|
|||||||
_log = context.logManager().getLog(ProfileOrganizer.class);
|
_log = context.logManager().getLog(ProfileOrganizer.class);
|
||||||
_comp = new InverseCapacityComparator();
|
_comp = new InverseCapacityComparator();
|
||||||
_fastPeers = new HashMap(16);
|
_fastPeers = new HashMap(16);
|
||||||
_highCapacityPeers = new HashMap(16);
|
_highCapacityPeers = new HashMap(32);
|
||||||
_wellIntegratedPeers = new HashMap(16);
|
_wellIntegratedPeers = new HashMap(16);
|
||||||
_notFailingPeers = new HashMap(64);
|
_notFailingPeers = new HashMap(256);
|
||||||
_notFailingPeersList = new ArrayList(64);
|
_notFailingPeersList = new ArrayList(256);
|
||||||
_failingPeers = new HashMap(16);
|
_failingPeers = new HashMap(16);
|
||||||
_strictCapacityOrder = new TreeSet(_comp);
|
_strictCapacityOrder = new TreeSet(_comp);
|
||||||
_thresholdSpeedValue = 0.0d;
|
_thresholdSpeedValue = 0.0d;
|
||||||
@ -113,6 +113,8 @@ public class ProfileOrganizer {
|
|||||||
_context.statManager().createRateStat("peer.profileThresholdTime", "How long the reorg takes determining the tier thresholds", "Peers", new long[] { 10*60*1000 });
|
_context.statManager().createRateStat("peer.profileThresholdTime", "How long the reorg takes determining the tier thresholds", "Peers", new long[] { 10*60*1000 });
|
||||||
_context.statManager().createRateStat("peer.profilePlaceTime", "How long the reorg takes placing peers in the tiers", "Peers", new long[] { 10*60*1000 });
|
_context.statManager().createRateStat("peer.profilePlaceTime", "How long the reorg takes placing peers in the tiers", "Peers", new long[] { 10*60*1000 });
|
||||||
_context.statManager().createRateStat("peer.profileReorgTime", "How long the reorg takes overall", "Peers", new long[] { 10*60*1000 });
|
_context.statManager().createRateStat("peer.profileReorgTime", "How long the reorg takes overall", "Peers", new long[] { 10*60*1000 });
|
||||||
|
// used in DBHistory
|
||||||
|
_context.statManager().createRateStat("peer.failedLookupRate", "DB Lookup fail rate", "Peers", new long[] { 10*60*1000l, 60*60*1000l, 24*60*60*1000l });
|
||||||
}
|
}
|
||||||
|
|
||||||
private void getReadLock() {
|
private void getReadLock() {
|
||||||
|
@ -77,31 +77,26 @@ public class CommSystemFacadeImpl extends CommSystemFacade {
|
|||||||
public boolean haveHighOutboundCapacity() { return (_manager == null ? false : _manager.haveHighOutboundCapacity()); }
|
public boolean haveHighOutboundCapacity() { return (_manager == null ? false : _manager.haveHighOutboundCapacity()); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Framed average clock skew of connected peers in seconds, or null if we cannot answer.
|
* Framed average clock skew of connected peers in seconds, or the clock offset if we cannot answer.
|
||||||
* Average is calculated over the middle "percentToInclude" peers.
|
* Average is calculated over the middle "percentToInclude" peers.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Long getFramedAveragePeerClockSkew(int percentToInclude) {
|
public Long getFramedAveragePeerClockSkew(int percentToInclude) {
|
||||||
if (_manager == null) {
|
if (_manager == null) {
|
||||||
if (_log.shouldLog(Log.INFO))
|
// round toward zero
|
||||||
_log.info("Returning null for framed averege peer clock skew (no transport manager)!");
|
return Long.valueOf(_context.clock().getOffset() / 1000);
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
Vector skews = _manager.getClockSkews();
|
Vector skews = _manager.getClockSkews();
|
||||||
if (skews == null) {
|
if (skews == null) {
|
||||||
if (_log.shouldLog(Log.ERROR))
|
return Long.valueOf(_context.clock().getOffset() / 1000);
|
||||||
_log.error("Returning null for framed average peer clock skew (no data)!");
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
if (skews.size() < 20) {
|
if (skews.size() < 5) {
|
||||||
if (_log.shouldLog(Log.WARN))
|
return Long.valueOf(_context.clock().getOffset() / 1000);
|
||||||
_log.warn("Returning null for framed average peer clock skew (only " + skews.size() + " peers)!");
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
// Going to calculate, sort them
|
// Going to calculate, sort them
|
||||||
Collections.sort(skews);
|
Collections.sort(skews);
|
||||||
// Calculate frame size
|
// Calculate frame size
|
||||||
int frameSize = (skews.size() * percentToInclude / 100);
|
int frameSize = Math.min((skews.size() * percentToInclude / 100), 2);
|
||||||
int first = (skews.size() / 2) - (frameSize / 2);
|
int first = (skews.size() / 2) - (frameSize / 2);
|
||||||
int last = (skews.size() / 2) + (frameSize / 2);
|
int last = (skews.size() / 2) + (frameSize / 2);
|
||||||
// Sum skew values
|
// Sum skew values
|
||||||
@ -112,11 +107,8 @@ public class CommSystemFacadeImpl extends CommSystemFacade {
|
|||||||
_log.debug("Adding clock skew " + i + " valued " + value + " s.");
|
_log.debug("Adding clock skew " + i + " valued " + value + " s.");
|
||||||
sum = sum + value;
|
sum = sum + value;
|
||||||
}
|
}
|
||||||
// Calculate average
|
// Calculate average (round toward zero)
|
||||||
Long framedAverageClockSkew = new Long(sum / frameSize);
|
return Long.valueOf(sum / frameSize);
|
||||||
if (_log.shouldLog(Log.INFO))
|
|
||||||
_log.info("Our framed average peer clock skew is " + framedAverageClockSkew + " s.");
|
|
||||||
return framedAverageClockSkew;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public List getBids(OutNetMessage msg) {
|
public List getBids(OutNetMessage msg) {
|
||||||
|
@ -2,7 +2,7 @@ package net.i2p.router.tunnel;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import net.i2p.I2PAppContext;
|
import net.i2p.router.RouterContext;
|
||||||
import net.i2p.util.Log;
|
import net.i2p.util.Log;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -45,11 +45,10 @@ import net.i2p.util.Log;
|
|||||||
* }
|
* }
|
||||||
*/
|
*/
|
||||||
public class BatchedPreprocessor extends TrivialPreprocessor {
|
public class BatchedPreprocessor extends TrivialPreprocessor {
|
||||||
private Log _log;
|
|
||||||
private long _pendingSince;
|
private long _pendingSince;
|
||||||
private String _name;
|
private String _name;
|
||||||
|
|
||||||
public BatchedPreprocessor(I2PAppContext ctx, String name) {
|
public BatchedPreprocessor(RouterContext ctx, String name) {
|
||||||
super(ctx);
|
super(ctx);
|
||||||
_log = ctx.logManager().getLog(BatchedPreprocessor.class);
|
_log = ctx.logManager().getLog(BatchedPreprocessor.class);
|
||||||
_name = name;
|
_name = name;
|
||||||
@ -98,8 +97,9 @@ public class BatchedPreprocessor extends TrivialPreprocessor {
|
|||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* See TunnelGateway.QueuePreprocessor for Javadoc */
|
||||||
@Override
|
@Override
|
||||||
public boolean preprocessQueue(List pending, TunnelGateway.Sender sender, TunnelGateway.Receiver rec) {
|
public boolean preprocessQueue(List<TunnelGateway.Pending> pending, TunnelGateway.Sender sender, TunnelGateway.Receiver rec) {
|
||||||
StringBuilder timingBuf = null;
|
StringBuilder timingBuf = null;
|
||||||
if (_log.shouldLog(Log.DEBUG)) {
|
if (_log.shouldLog(Log.DEBUG)) {
|
||||||
_log.debug("Preprocess queue with " + pending.size() + " to send");
|
_log.debug("Preprocess queue with " + pending.size() + " to send");
|
||||||
@ -116,12 +116,15 @@ public class BatchedPreprocessor extends TrivialPreprocessor {
|
|||||||
int batchCount = 0;
|
int batchCount = 0;
|
||||||
int beforeLooping = pending.size();
|
int beforeLooping = pending.size();
|
||||||
|
|
||||||
|
// loop until the queue is empty
|
||||||
while (pending.size() > 0) {
|
while (pending.size() > 0) {
|
||||||
int allocated = 0;
|
int allocated = 0;
|
||||||
long beforePendingLoop = System.currentTimeMillis();
|
long beforePendingLoop = System.currentTimeMillis();
|
||||||
|
|
||||||
|
// loop until we fill up a single message
|
||||||
for (int i = 0; i < pending.size(); i++) {
|
for (int i = 0; i < pending.size(); i++) {
|
||||||
long pendingStart = System.currentTimeMillis();
|
long pendingStart = System.currentTimeMillis();
|
||||||
TunnelGateway.Pending msg = (TunnelGateway.Pending)pending.get(i);
|
TunnelGateway.Pending msg = pending.get(i);
|
||||||
int instructionsSize = getInstructionsSize(msg);
|
int instructionsSize = getInstructionsSize(msg);
|
||||||
instructionsSize += getInstructionAugmentationSize(msg, allocated, instructionsSize);
|
instructionsSize += getInstructionAugmentationSize(msg, allocated, instructionsSize);
|
||||||
int curWanted = msg.getData().length - msg.getOffset() + instructionsSize;
|
int curWanted = msg.getData().length - msg.getOffset() + instructionsSize;
|
||||||
@ -135,7 +138,7 @@ public class BatchedPreprocessor extends TrivialPreprocessor {
|
|||||||
// the instructions alone exceed the size, so we won't get any
|
// the instructions alone exceed the size, so we won't get any
|
||||||
// of the message into it. don't include it
|
// of the message into it. don't include it
|
||||||
i--;
|
i--;
|
||||||
msg = (TunnelGateway.Pending)pending.get(i);
|
msg = pending.get(i);
|
||||||
allocated -= curWanted;
|
allocated -= curWanted;
|
||||||
if (_log.shouldLog(Log.DEBUG))
|
if (_log.shouldLog(Log.DEBUG))
|
||||||
_log.debug("Pushback of " + curWanted + " (message " + (i+1) + " in " + pending + ")");
|
_log.debug("Pushback of " + curWanted + " (message " + (i+1) + " in " + pending + ")");
|
||||||
@ -144,6 +147,8 @@ public class BatchedPreprocessor extends TrivialPreprocessor {
|
|||||||
long waited = _context.clock().now() - _pendingSince;
|
long waited = _context.clock().now() - _pendingSince;
|
||||||
_context.statManager().addRateData("tunnel.batchDelaySent", pending.size(), waited);
|
_context.statManager().addRateData("tunnel.batchDelaySent", pending.size(), waited);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Send the message
|
||||||
long beforeSend = System.currentTimeMillis();
|
long beforeSend = System.currentTimeMillis();
|
||||||
_pendingSince = 0;
|
_pendingSince = 0;
|
||||||
send(pending, 0, i, sender, rec);
|
send(pending, 0, i, sender, rec);
|
||||||
@ -154,8 +159,9 @@ public class BatchedPreprocessor extends TrivialPreprocessor {
|
|||||||
+ " (last complete? " + (msg.getOffset() >= msg.getData().length)
|
+ " (last complete? " + (msg.getOffset() >= msg.getData().length)
|
||||||
+ ", off=" + msg.getOffset() + ", count=" + pending.size() + ")");
|
+ ", off=" + msg.getOffset() + ", count=" + pending.size() + ")");
|
||||||
|
|
||||||
|
// Remove what we sent from the pending queue
|
||||||
for (int j = 0; j < i; j++) {
|
for (int j = 0; j < i; j++) {
|
||||||
TunnelGateway.Pending cur = (TunnelGateway.Pending)pending.remove(0);
|
TunnelGateway.Pending cur = pending.remove(0);
|
||||||
if (cur.getOffset() < cur.getData().length)
|
if (cur.getOffset() < cur.getData().length)
|
||||||
throw new IllegalArgumentException("i=" + i + " j=" + j + " off=" + cur.getOffset()
|
throw new IllegalArgumentException("i=" + i + " j=" + j + " off=" + cur.getOffset()
|
||||||
+ " len=" + cur.getData().length + " alloc=" + allocated);
|
+ " len=" + cur.getData().length + " alloc=" + allocated);
|
||||||
@ -167,7 +173,7 @@ public class BatchedPreprocessor extends TrivialPreprocessor {
|
|||||||
}
|
}
|
||||||
if (msg.getOffset() >= msg.getData().length) {
|
if (msg.getOffset() >= msg.getData().length) {
|
||||||
// ok, this last message fit perfectly, remove it too
|
// ok, this last message fit perfectly, remove it too
|
||||||
TunnelGateway.Pending cur = (TunnelGateway.Pending)pending.remove(0);
|
TunnelGateway.Pending cur = pending.remove(0);
|
||||||
if (timingBuf != null)
|
if (timingBuf != null)
|
||||||
timingBuf.append(" sent perfect fit " + cur).append(".");
|
timingBuf.append(" sent perfect fit " + cur).append(".");
|
||||||
notePreprocessing(cur.getMessageId(), cur.getFragmentNumber(), msg.getData().length, msg.getMessageIds(), "flushed tail, remaining: " + pending);
|
notePreprocessing(cur.getMessageId(), cur.getFragmentNumber(), msg.getData().length, msg.getMessageIds(), "flushed tail, remaining: " + pending);
|
||||||
@ -186,18 +192,18 @@ public class BatchedPreprocessor extends TrivialPreprocessor {
|
|||||||
+ "/" + (beforeSend-start)
|
+ "/" + (beforeSend-start)
|
||||||
+ " pending current " + (pendingEnd-pendingStart)).append(".");
|
+ " pending current " + (pendingEnd-pendingStart)).append(".");
|
||||||
break;
|
break;
|
||||||
}
|
} // if >= full size
|
||||||
if (timingBuf != null)
|
if (timingBuf != null)
|
||||||
timingBuf.append(" After pending loop " + (System.currentTimeMillis()-beforePendingLoop)).append(".");
|
timingBuf.append(" After pending loop " + (System.currentTimeMillis()-beforePendingLoop)).append(".");
|
||||||
}
|
} // for
|
||||||
|
|
||||||
long afterCleared = System.currentTimeMillis();
|
long afterCleared = System.currentTimeMillis();
|
||||||
if (_log.shouldLog(Log.INFO))
|
if (_log.shouldLog(Log.INFO))
|
||||||
display(allocated, pending, "after looping to clear " + (beforeLooping - pending.size()));
|
display(allocated, pending, "after looping to clear " + (beforeLooping - pending.size()));
|
||||||
long afterDisplayed = System.currentTimeMillis();
|
long afterDisplayed = System.currentTimeMillis();
|
||||||
if (allocated > 0) {
|
if (allocated > 0) {
|
||||||
// after going through the entire pending list, we still don't
|
// After going through the entire pending list, we have only a partial message.
|
||||||
// have enough data to send a full message
|
// We might flush it or might not, but we are returning either way.
|
||||||
|
|
||||||
if ( (pending.size() > FORCE_BATCH_FLUSH) || ( (_pendingSince > 0) && (getDelayAmount() <= 0) ) ) {
|
if ( (pending.size() > FORCE_BATCH_FLUSH) || ( (_pendingSince > 0) && (getDelayAmount() <= 0) ) ) {
|
||||||
// not even a full message, but we want to flush it anyway
|
// not even a full message, but we want to flush it anyway
|
||||||
@ -209,9 +215,10 @@ public class BatchedPreprocessor extends TrivialPreprocessor {
|
|||||||
send(pending, 0, pending.size()-1, sender, rec);
|
send(pending, 0, pending.size()-1, sender, rec);
|
||||||
_context.statManager().addRateData("tunnel.batchSmallFragments", FULL_SIZE - allocated, 0);
|
_context.statManager().addRateData("tunnel.batchSmallFragments", FULL_SIZE - allocated, 0);
|
||||||
|
|
||||||
|
// Remove everything in the message from the pending queue
|
||||||
int beforeSize = pending.size();
|
int beforeSize = pending.size();
|
||||||
for (int i = 0; i < pending.size(); i++) {
|
for (int i = 0; i < pending.size(); i++) {
|
||||||
TunnelGateway.Pending cur = (TunnelGateway.Pending)pending.get(i);
|
TunnelGateway.Pending cur = pending.get(i);
|
||||||
if (cur.getOffset() >= cur.getData().length) {
|
if (cur.getOffset() >= cur.getData().length) {
|
||||||
pending.remove(i);
|
pending.remove(i);
|
||||||
notePreprocessing(cur.getMessageId(), cur.getFragmentNumber(), cur.getData().length, cur.getMessageIds(), "flushed remaining");
|
notePreprocessing(cur.getMessageId(), cur.getFragmentNumber(), cur.getData().length, cur.getMessageIds(), "flushed remaining");
|
||||||
@ -246,7 +253,9 @@ public class BatchedPreprocessor extends TrivialPreprocessor {
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
// won't get here, we returned
|
||||||
} else {
|
} else {
|
||||||
|
// We didn't flush. Note that the messages remain on the pending list.
|
||||||
_context.statManager().addRateData("tunnel.batchDelay", pending.size(), 0);
|
_context.statManager().addRateData("tunnel.batchDelay", pending.size(), 0);
|
||||||
if (_pendingSince <= 0)
|
if (_pendingSince <= 0)
|
||||||
_pendingSince = _context.clock().now();
|
_pendingSince = _context.clock().now();
|
||||||
@ -262,14 +271,15 @@ public class BatchedPreprocessor extends TrivialPreprocessor {
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
// won't get here, we returned
|
||||||
} else {
|
} else {
|
||||||
// ok, we sent some, but haven't gone back for another
|
// ok, we sent some, but haven't gone back for another
|
||||||
// pass yet. keep looping
|
// pass yet. keep looping
|
||||||
|
|
||||||
if (timingBuf != null)
|
if (timingBuf != null)
|
||||||
timingBuf.append(" Keep looping");
|
timingBuf.append(" Keep looping");
|
||||||
}
|
} // if allocated
|
||||||
}
|
} // while
|
||||||
|
|
||||||
if (_log.shouldLog(Log.DEBUG))
|
if (_log.shouldLog(Log.DEBUG))
|
||||||
_log.debug("Sent everything on the list (pending=" + pending.size() + ")");
|
_log.debug("Sent everything on the list (pending=" + pending.size() + ")");
|
||||||
@ -283,7 +293,7 @@ public class BatchedPreprocessor extends TrivialPreprocessor {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void display(long allocated, List pending, String title) {
|
private void display(long allocated, List<TunnelGateway.Pending> pending, String title) {
|
||||||
if (_log.shouldLog(Log.INFO)) {
|
if (_log.shouldLog(Log.INFO)) {
|
||||||
long highestDelay = 0;
|
long highestDelay = 0;
|
||||||
StringBuilder buf = new StringBuilder();
|
StringBuilder buf = new StringBuilder();
|
||||||
@ -294,7 +304,7 @@ public class BatchedPreprocessor extends TrivialPreprocessor {
|
|||||||
if (_pendingSince > 0)
|
if (_pendingSince > 0)
|
||||||
buf.append(" delay: ").append(getDelayAmount(false));
|
buf.append(" delay: ").append(getDelayAmount(false));
|
||||||
for (int i = 0; i < pending.size(); i++) {
|
for (int i = 0; i < pending.size(); i++) {
|
||||||
TunnelGateway.Pending curPending = (TunnelGateway.Pending)pending.get(i);
|
TunnelGateway.Pending curPending = pending.get(i);
|
||||||
buf.append(" pending[").append(i).append("]: ");
|
buf.append(" pending[").append(i).append("]: ");
|
||||||
buf.append(curPending.getOffset()).append("/").append(curPending.getData().length).append('/');
|
buf.append(curPending.getOffset()).append("/").append(curPending.getData().length).append('/');
|
||||||
buf.append(curPending.getLifetime());
|
buf.append(curPending.getLifetime());
|
||||||
@ -314,7 +324,7 @@ public class BatchedPreprocessor extends TrivialPreprocessor {
|
|||||||
* @param startAt first index in pending to send (inclusive)
|
* @param startAt first index in pending to send (inclusive)
|
||||||
* @param sendThrough last index in pending to send (inclusive)
|
* @param sendThrough last index in pending to send (inclusive)
|
||||||
*/
|
*/
|
||||||
protected void send(List pending, int startAt, int sendThrough, TunnelGateway.Sender sender, TunnelGateway.Receiver rec) {
|
protected void send(List<TunnelGateway.Pending> pending, int startAt, int sendThrough, TunnelGateway.Sender sender, TunnelGateway.Receiver rec) {
|
||||||
if (_log.shouldLog(Log.DEBUG))
|
if (_log.shouldLog(Log.DEBUG))
|
||||||
_log.debug("Sending " + startAt + ":" + sendThrough + " out of " + pending);
|
_log.debug("Sending " + startAt + ":" + sendThrough + " out of " + pending);
|
||||||
byte preprocessed[] = _dataCache.acquire().getData();
|
byte preprocessed[] = _dataCache.acquire().getData();
|
||||||
@ -346,7 +356,7 @@ public class BatchedPreprocessor extends TrivialPreprocessor {
|
|||||||
|
|
||||||
long msgId = sender.sendPreprocessed(preprocessed, rec);
|
long msgId = sender.sendPreprocessed(preprocessed, rec);
|
||||||
for (int i = 0; i < pending.size(); i++) {
|
for (int i = 0; i < pending.size(); i++) {
|
||||||
TunnelGateway.Pending cur = (TunnelGateway.Pending)pending.get(i);
|
TunnelGateway.Pending cur = pending.get(i);
|
||||||
cur.addMessageId(msgId);
|
cur.addMessageId(msgId);
|
||||||
}
|
}
|
||||||
if (_log.shouldLog(Log.DEBUG))
|
if (_log.shouldLog(Log.DEBUG))
|
||||||
@ -359,9 +369,9 @@ public class BatchedPreprocessor extends TrivialPreprocessor {
|
|||||||
*
|
*
|
||||||
* @return new offset into the target for further bytes to be written
|
* @return new offset into the target for further bytes to be written
|
||||||
*/
|
*/
|
||||||
private int writeFragments(List pending, int startAt, int sendThrough, byte target[], int offset) {
|
private int writeFragments(List<TunnelGateway.Pending> pending, int startAt, int sendThrough, byte target[], int offset) {
|
||||||
for (int i = startAt; i <= sendThrough; i++) {
|
for (int i = startAt; i <= sendThrough; i++) {
|
||||||
TunnelGateway.Pending msg = (TunnelGateway.Pending)pending.get(i);
|
TunnelGateway.Pending msg = pending.get(i);
|
||||||
int prevOffset = offset;
|
int prevOffset = offset;
|
||||||
if (msg.getOffset() == 0) {
|
if (msg.getOffset() == 0) {
|
||||||
offset = writeFirstFragment(msg, target, offset);
|
offset = writeFirstFragment(msg, target, offset);
|
||||||
|
@ -11,9 +11,9 @@ import net.i2p.router.RouterContext;
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class BatchedRouterPreprocessor extends BatchedPreprocessor {
|
public class BatchedRouterPreprocessor extends BatchedPreprocessor {
|
||||||
private RouterContext _routerContext;
|
protected RouterContext _routerContext;
|
||||||
private TunnelCreatorConfig _config;
|
private TunnelCreatorConfig _config;
|
||||||
private HopConfig _hopConfig;
|
protected HopConfig _hopConfig;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* How frequently should we flush non-full messages, in milliseconds
|
* How frequently should we flush non-full messages, in milliseconds
|
||||||
@ -79,7 +79,7 @@ public class BatchedRouterPreprocessor extends BatchedPreprocessor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void notePreprocessing(long messageId, int numFragments, int totalLength, List messageIds, String msg) {
|
protected void notePreprocessing(long messageId, int numFragments, int totalLength, List<Long> messageIds, String msg) {
|
||||||
if (_config != null)
|
if (_config != null)
|
||||||
_routerContext.messageHistory().fragmentMessage(messageId, numFragments, totalLength, messageIds, _config, msg);
|
_routerContext.messageHistory().fragmentMessage(messageId, numFragments, totalLength, messageIds, _config, msg);
|
||||||
else
|
else
|
||||||
|
@ -21,6 +21,65 @@ import net.i2p.util.SimpleTimer;
|
|||||||
* Handle fragments at the endpoint of a tunnel, peeling off fully completed
|
* Handle fragments at the endpoint of a tunnel, peeling off fully completed
|
||||||
* I2NPMessages when they arrive, and dropping fragments if they take too long
|
* I2NPMessages when they arrive, and dropping fragments if they take too long
|
||||||
* to arrive.
|
* to arrive.
|
||||||
|
*
|
||||||
|
* From tunnel-alt.html:
|
||||||
|
|
||||||
|
<p>When the gateway wants to deliver data through the tunnel, it first
|
||||||
|
gathers zero or more <a href="i2np.html">I2NP</a> messages, selects how much padding will be used,
|
||||||
|
fragments it across the necessary number of 1KB tunnel messages, and decides how
|
||||||
|
each I2NP message should be handled by the tunnel endpoint, encoding that
|
||||||
|
data into the raw tunnel payload:</p>
|
||||||
|
<ul>
|
||||||
|
<li>the first 4 bytes of the SHA256 of (the remaining preprocessed data concatenated
|
||||||
|
with the IV), using the IV as will be seen on the tunnel endpoint (for
|
||||||
|
outbound tunnels), or the IV as was seen on the tunnel gateway (for inbound
|
||||||
|
tunnels) (see below for IV processing).</li>
|
||||||
|
<li>0 or more bytes containing random nonzero integers</li>
|
||||||
|
<li>1 byte containing 0x00</li>
|
||||||
|
<li>a series of zero or more { instructions, message } pairs</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p>The instructions are encoded with a single control byte, followed by any
|
||||||
|
necessary additional information. The first bit in that control byte determines
|
||||||
|
how the remainder of the header is interpreted - if it is not set, the message
|
||||||
|
is either not fragmented or this is the first fragment in the message. If it is
|
||||||
|
set, this is a follow on fragment.</p>
|
||||||
|
|
||||||
|
<p>With the first bit being 0, the instructions are:</p>
|
||||||
|
<ul>
|
||||||
|
<li>1 byte control byte:<pre>
|
||||||
|
bit 0: is follow on fragment? (1 = true, 0 = false, must be 0)
|
||||||
|
bits 1-2: delivery type
|
||||||
|
(0x0 = LOCAL, 0x01 = TUNNEL, 0x02 = ROUTER)
|
||||||
|
bit 3: delay included? (1 = true, 0 = false)
|
||||||
|
bit 4: fragmented? (1 = true, 0 = false)
|
||||||
|
bit 5: extended options? (1 = true, 0 = false)
|
||||||
|
bits 6-7: reserved</pre></li>
|
||||||
|
<li>if the delivery type was TUNNEL, a 4 byte tunnel ID</li>
|
||||||
|
<li>if the delivery type was TUNNEL or ROUTER, a 32 byte router hash</li>
|
||||||
|
<li>if the delay included flag is true, a 1 byte value:<pre>
|
||||||
|
bit 0: type (0 = strict, 1 = randomized)
|
||||||
|
bits 1-7: delay exponent (2^value minutes)</pre></li>
|
||||||
|
<li>if the fragmented flag is true, a 4 byte message ID</li>
|
||||||
|
<li>if the extended options flag is true:<pre>
|
||||||
|
= a 1 byte option size (in bytes)
|
||||||
|
= that many bytes</pre></li>
|
||||||
|
<li>2 byte size of the I2NP message or this fragment</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p>If the first bit being 1, the instructions are:</p>
|
||||||
|
<ul>
|
||||||
|
<li>1 byte control byte:<pre>
|
||||||
|
bit 0: is follow on fragment? (1 = true, 0 = false, must be 1)
|
||||||
|
bits 1-6: fragment number
|
||||||
|
bit 7: is last? (1 = true, 0 = false)</pre></li>
|
||||||
|
<li>4 byte message ID (same one defined in the first fragment)</li>
|
||||||
|
<li>2 byte size of this fragment</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p>The I2NP message is encoded in its standard form, and the
|
||||||
|
preprocessed payload must be padded to a multiple of 16 bytes.</p>
|
||||||
|
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class FragmentHandler {
|
public class FragmentHandler {
|
||||||
@ -149,7 +208,7 @@ public class FragmentHandler {
|
|||||||
if (_log.shouldLog(Log.WARN))
|
if (_log.shouldLog(Log.WARN))
|
||||||
_log.warn("cannot verify, going past the end [off="
|
_log.warn("cannot verify, going past the end [off="
|
||||||
+ offset + " len=" + length + " paddingEnd="
|
+ offset + " len=" + length + " paddingEnd="
|
||||||
+ paddingEnd + " data:\n"
|
+ paddingEnd + " data: "
|
||||||
+ Base64.encode(preprocessed, offset, length));
|
+ Base64.encode(preprocessed, offset, length));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -165,21 +224,19 @@ public class FragmentHandler {
|
|||||||
_log.debug("endpoint IV: " + Base64.encode(preV, validLength - HopProcessor.IV_LENGTH, HopProcessor.IV_LENGTH));
|
_log.debug("endpoint IV: " + Base64.encode(preV, validLength - HopProcessor.IV_LENGTH, HopProcessor.IV_LENGTH));
|
||||||
|
|
||||||
Hash v = _context.sha().calculateHash(preV, 0, validLength);
|
Hash v = _context.sha().calculateHash(preV, 0, validLength);
|
||||||
|
_validateCache.release(ba);
|
||||||
|
|
||||||
//Hash v = _context.sha().calculateHash(preV, 0, validLength);
|
|
||||||
boolean eq = DataHelper.eq(v.getData(), 0, preprocessed, offset + HopProcessor.IV_LENGTH, 4);
|
boolean eq = DataHelper.eq(v.getData(), 0, preprocessed, offset + HopProcessor.IV_LENGTH, 4);
|
||||||
if (!eq) {
|
if (!eq) {
|
||||||
if (_log.shouldLog(Log.WARN))
|
if (_log.shouldLog(Log.WARN)) {
|
||||||
_log.warn("Corrupt tunnel message - verification fails: \n" + Base64.encode(preprocessed, offset+HopProcessor.IV_LENGTH, 4)
|
_log.warn("Corrupt tunnel message - verification fails: " + Base64.encode(preprocessed, offset+HopProcessor.IV_LENGTH, 4)
|
||||||
+ "\n" + Base64.encode(v.getData(), 0, 4));
|
+ " != " + Base64.encode(v.getData(), 0, 4));
|
||||||
if (_log.shouldLog(Log.WARN))
|
_log.warn("No matching endpoint: # pad bytes: " + (paddingEnd-(HopProcessor.IV_LENGTH+4)-1)
|
||||||
_log.warn("nomatching endpoint: # pad bytes: " + (paddingEnd-(HopProcessor.IV_LENGTH+4)-1) + "\n"
|
+ " offset=" + offset + " length=" + length + " paddingEnd=" + paddingEnd + ' '
|
||||||
+ " offset=" + offset + " length=" + length + " paddingEnd=" + paddingEnd
|
|
||||||
+ Base64.encode(preprocessed, offset, length));
|
+ Base64.encode(preprocessed, offset, length));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_validateCache.release(ba);
|
|
||||||
|
|
||||||
if (eq) {
|
if (eq) {
|
||||||
int excessPadding = paddingEnd - (HopProcessor.IV_LENGTH + 4 + 1);
|
int excessPadding = paddingEnd - (HopProcessor.IV_LENGTH + 4 + 1);
|
||||||
if (excessPadding > 0) // suboptimal fragmentation
|
if (excessPadding > 0) // suboptimal fragmentation
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package net.i2p.router.tunnel;
|
package net.i2p.router.tunnel;
|
||||||
|
|
||||||
import net.i2p.I2PAppContext;
|
|
||||||
import net.i2p.data.ByteArray;
|
import net.i2p.data.ByteArray;
|
||||||
import net.i2p.data.Hash;
|
import net.i2p.data.Hash;
|
||||||
import net.i2p.router.RouterContext;
|
import net.i2p.router.RouterContext;
|
||||||
@ -16,7 +15,7 @@ import net.i2p.util.Log;
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class InboundEndpointProcessor {
|
public class InboundEndpointProcessor {
|
||||||
private I2PAppContext _context;
|
private RouterContext _context;
|
||||||
private Log _log;
|
private Log _log;
|
||||||
private TunnelCreatorConfig _config;
|
private TunnelCreatorConfig _config;
|
||||||
private IVValidator _validator;
|
private IVValidator _validator;
|
||||||
@ -24,10 +23,10 @@ public class InboundEndpointProcessor {
|
|||||||
static final boolean USE_ENCRYPTION = HopProcessor.USE_ENCRYPTION;
|
static final boolean USE_ENCRYPTION = HopProcessor.USE_ENCRYPTION;
|
||||||
private static final ByteCache _cache = ByteCache.getInstance(128, HopProcessor.IV_LENGTH);
|
private static final ByteCache _cache = ByteCache.getInstance(128, HopProcessor.IV_LENGTH);
|
||||||
|
|
||||||
public InboundEndpointProcessor(I2PAppContext ctx, TunnelCreatorConfig cfg) {
|
public InboundEndpointProcessor(RouterContext ctx, TunnelCreatorConfig cfg) {
|
||||||
this(ctx, cfg, DummyValidator.getInstance());
|
this(ctx, cfg, DummyValidator.getInstance());
|
||||||
}
|
}
|
||||||
public InboundEndpointProcessor(I2PAppContext ctx, TunnelCreatorConfig cfg, IVValidator validator) {
|
public InboundEndpointProcessor(RouterContext ctx, TunnelCreatorConfig cfg, IVValidator validator) {
|
||||||
_context = ctx;
|
_context = ctx;
|
||||||
_log = ctx.logManager().getLog(InboundEndpointProcessor.class);
|
_log = ctx.logManager().getLog(InboundEndpointProcessor.class);
|
||||||
_config = cfg;
|
_config = cfg;
|
||||||
@ -73,23 +72,19 @@ public class InboundEndpointProcessor {
|
|||||||
|
|
||||||
_cache.release(ba);
|
_cache.release(ba);
|
||||||
|
|
||||||
// now for a little bookkeeping
|
if (_config.getLength() > 0) {
|
||||||
RouterContext ctx = null;
|
|
||||||
if (_context instanceof RouterContext)
|
|
||||||
ctx = (RouterContext)_context;
|
|
||||||
if ( (ctx != null) && (_config.getLength() > 0) ) {
|
|
||||||
int rtt = 0; // dunno... may not be related to an rtt
|
int rtt = 0; // dunno... may not be related to an rtt
|
||||||
if (_log.shouldLog(Log.DEBUG))
|
if (_log.shouldLog(Log.DEBUG))
|
||||||
_log.debug("Received a " + length + "byte message through tunnel " + _config);
|
_log.debug("Received a " + length + "byte message through tunnel " + _config);
|
||||||
for (int i = 0; i < _config.getLength(); i++)
|
for (int i = 0; i < _config.getLength(); i++)
|
||||||
ctx.profileManager().tunnelDataPushed(_config.getPeer(i), rtt, length);
|
_context.profileManager().tunnelDataPushed(_config.getPeer(i), rtt, length);
|
||||||
_config.incrementVerifiedBytesTransferred(length);
|
_config.incrementVerifiedBytesTransferred(length);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void decrypt(I2PAppContext ctx, TunnelCreatorConfig cfg, byte iv[], byte orig[], int offset, int length) {
|
private void decrypt(RouterContext ctx, TunnelCreatorConfig cfg, byte iv[], byte orig[], int offset, int length) {
|
||||||
Log log = ctx.logManager().getLog(OutboundGatewayProcessor.class);
|
Log log = ctx.logManager().getLog(OutboundGatewayProcessor.class);
|
||||||
ByteArray ba = _cache.acquire();
|
ByteArray ba = _cache.acquire();
|
||||||
byte cur[] = ba.getData(); // new byte[HopProcessor.IV_LENGTH]; // so we dont malloc
|
byte cur[] = ba.getData(); // new byte[HopProcessor.IV_LENGTH]; // so we dont malloc
|
||||||
|
@ -3,11 +3,11 @@ package net.i2p.router.tunnel;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import net.i2p.I2PAppContext;
|
|
||||||
import net.i2p.data.Base64;
|
import net.i2p.data.Base64;
|
||||||
import net.i2p.data.ByteArray;
|
import net.i2p.data.ByteArray;
|
||||||
import net.i2p.data.DataHelper;
|
import net.i2p.data.DataHelper;
|
||||||
import net.i2p.data.Hash;
|
import net.i2p.data.Hash;
|
||||||
|
import net.i2p.router.RouterContext;
|
||||||
import net.i2p.util.ByteCache;
|
import net.i2p.util.ByteCache;
|
||||||
import net.i2p.util.Log;
|
import net.i2p.util.Log;
|
||||||
|
|
||||||
@ -19,8 +19,8 @@ import net.i2p.util.Log;
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class TrivialPreprocessor implements TunnelGateway.QueuePreprocessor {
|
public class TrivialPreprocessor implements TunnelGateway.QueuePreprocessor {
|
||||||
protected I2PAppContext _context;
|
protected RouterContext _context;
|
||||||
private Log _log;
|
protected Log _log;
|
||||||
|
|
||||||
public 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 int IV_SIZE = HopProcessor.IV_LENGTH;
|
||||||
@ -28,7 +28,7 @@ public class TrivialPreprocessor implements TunnelGateway.QueuePreprocessor {
|
|||||||
protected static final ByteCache _ivCache = ByteCache.getInstance(128, IV_SIZE);
|
protected static final ByteCache _ivCache = ByteCache.getInstance(128, IV_SIZE);
|
||||||
protected static final ByteCache _hashCache = ByteCache.getInstance(128, Hash.HASH_LENGTH);
|
protected static final ByteCache _hashCache = ByteCache.getInstance(128, Hash.HASH_LENGTH);
|
||||||
|
|
||||||
public TrivialPreprocessor(I2PAppContext ctx) {
|
public TrivialPreprocessor(RouterContext ctx) {
|
||||||
_context = ctx;
|
_context = ctx;
|
||||||
_log = ctx.logManager().getLog(TrivialPreprocessor.class);
|
_log = ctx.logManager().getLog(TrivialPreprocessor.class);
|
||||||
}
|
}
|
||||||
@ -41,7 +41,7 @@ public class TrivialPreprocessor implements TunnelGateway.QueuePreprocessor {
|
|||||||
* a delayed flush to clear them
|
* a delayed flush to clear them
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public boolean preprocessQueue(List pending, TunnelGateway.Sender sender, TunnelGateway.Receiver rec) {
|
public boolean preprocessQueue(List<TunnelGateway.Pending> pending, TunnelGateway.Sender sender, TunnelGateway.Receiver rec) {
|
||||||
long begin = System.currentTimeMillis();
|
long begin = System.currentTimeMillis();
|
||||||
StringBuilder buf = null;
|
StringBuilder buf = null;
|
||||||
if (_log.shouldLog(Log.DEBUG)) {
|
if (_log.shouldLog(Log.DEBUG)) {
|
||||||
@ -49,7 +49,7 @@ public class TrivialPreprocessor implements TunnelGateway.QueuePreprocessor {
|
|||||||
buf.append("Trivial preprocessing of ").append(pending.size()).append(" ");
|
buf.append("Trivial preprocessing of ").append(pending.size()).append(" ");
|
||||||
}
|
}
|
||||||
while (pending.size() > 0) {
|
while (pending.size() > 0) {
|
||||||
TunnelGateway.Pending msg = (TunnelGateway.Pending)pending.remove(0);
|
TunnelGateway.Pending msg = pending.remove(0);
|
||||||
long beforePreproc = System.currentTimeMillis();
|
long beforePreproc = System.currentTimeMillis();
|
||||||
byte preprocessed[][] = preprocess(msg);
|
byte preprocessed[][] = preprocess(msg);
|
||||||
long afterPreproc = System.currentTimeMillis();
|
long afterPreproc = System.currentTimeMillis();
|
||||||
@ -84,7 +84,7 @@ public class TrivialPreprocessor implements TunnelGateway.QueuePreprocessor {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void notePreprocessing(long messageId, int numFragments, int totalLength, List messageIds, String msg) {}
|
protected void notePreprocessing(long messageId, int numFragments, int totalLength, List<Long> messageIds, String msg) {}
|
||||||
|
|
||||||
private byte[][] preprocess(TunnelGateway.Pending msg) {
|
private byte[][] preprocess(TunnelGateway.Pending msg) {
|
||||||
List fragments = new ArrayList(1);
|
List fragments = new ArrayList(1);
|
||||||
|
@ -7,6 +7,7 @@ import net.i2p.router.RouterContext;
|
|||||||
/**
|
/**
|
||||||
* Minor extension to track fragmentation
|
* Minor extension to track fragmentation
|
||||||
*
|
*
|
||||||
|
* @deprecated unused
|
||||||
*/
|
*/
|
||||||
public class TrivialRouterPreprocessor extends TrivialPreprocessor {
|
public class TrivialRouterPreprocessor extends TrivialPreprocessor {
|
||||||
private RouterContext _routerContext;
|
private RouterContext _routerContext;
|
||||||
@ -16,7 +17,7 @@ public class TrivialRouterPreprocessor extends TrivialPreprocessor {
|
|||||||
_routerContext = ctx;
|
_routerContext = ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void notePreprocessing(long messageId, int numFragments, int totalLength, List messageIds) {
|
protected void notePreprocessing(long messageId, int numFragments, int totalLength, List<Long> messageIds) {
|
||||||
_routerContext.messageHistory().fragmentMessage(messageId, numFragments, totalLength, messageIds, null);
|
_routerContext.messageHistory().fragmentMessage(messageId, numFragments, totalLength, messageIds, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -131,17 +131,20 @@ public class TunnelDispatcher implements Service {
|
|||||||
new long[] { 60*1000l, 10*60*1000l, 60*60*1000l });
|
new long[] { 60*1000l, 10*60*1000l, 60*60*1000l });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** for IBGW */
|
||||||
private TunnelGateway.QueuePreprocessor createPreprocessor(HopConfig cfg) {
|
private TunnelGateway.QueuePreprocessor createPreprocessor(HopConfig cfg) {
|
||||||
if (true)
|
//if (true)
|
||||||
return new BatchedRouterPreprocessor(_context, cfg);
|
return new DroppingBatchedRouterPreprocessor(_context, cfg);
|
||||||
else
|
//else
|
||||||
return new TrivialRouterPreprocessor(_context);
|
// return new TrivialRouterPreprocessor(_context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** for OBGW */
|
||||||
private TunnelGateway.QueuePreprocessor createPreprocessor(TunnelCreatorConfig cfg) {
|
private TunnelGateway.QueuePreprocessor createPreprocessor(TunnelCreatorConfig cfg) {
|
||||||
if (true)
|
//if (true)
|
||||||
return new BatchedRouterPreprocessor(_context, cfg);
|
return new BatchedRouterPreprocessor(_context, cfg);
|
||||||
else
|
//else
|
||||||
return new TrivialRouterPreprocessor(_context);
|
// return new TrivialRouterPreprocessor(_context);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -605,12 +608,17 @@ public class TunnelDispatcher implements Service {
|
|||||||
if (pctDrop <= 0)
|
if (pctDrop <= 0)
|
||||||
return false;
|
return false;
|
||||||
// increase the drop probability for OBEP,
|
// increase the drop probability for OBEP,
|
||||||
|
// (except lower it for tunnel build messages (type 21)),
|
||||||
// and lower it for IBGW, for network efficiency
|
// and lower it for IBGW, for network efficiency
|
||||||
double len = length;
|
double len = length;
|
||||||
if (type.startsWith("OBEP"))
|
if (type.startsWith("OBEP")) {
|
||||||
len *= 1.5;
|
if (type.equals("OBEP 21"))
|
||||||
else if (type.startsWith("IBGW"))
|
len /= 1.5;
|
||||||
|
else
|
||||||
|
len *= 1.5;
|
||||||
|
} else if (type.startsWith("IBGW")) {
|
||||||
len /= 1.5;
|
len /= 1.5;
|
||||||
|
}
|
||||||
// drop in proportion to size w.r.t. a standard 1024-byte message
|
// drop in proportion to size w.r.t. a standard 1024-byte message
|
||||||
// this is a little expensive but we want to adjust the curve between 0 and 1
|
// this is a little expensive but we want to adjust the curve between 0 and 1
|
||||||
// Most messages are 1024, only at the OBEP do we see other sizes
|
// Most messages are 1024, only at the OBEP do we see other sizes
|
||||||
|
@ -154,12 +154,18 @@ public class TunnelGateway {
|
|||||||
|
|
||||||
public interface QueuePreprocessor {
|
public interface QueuePreprocessor {
|
||||||
/**
|
/**
|
||||||
|
* Caller must synchronize on the list!
|
||||||
|
*
|
||||||
* @param pending list of Pending objects for messages either unsent
|
* @param pending list of Pending objects for messages either unsent
|
||||||
* or partly sent. This list should be update with any
|
* or partly sent. This list should be update with any
|
||||||
* values removed (the preprocessor owns the lock)
|
* values removed (the preprocessor owns the lock)
|
||||||
|
* Messages are not removed from the list until actually sent.
|
||||||
|
* The status of unsent and partially-sent messages is stored in
|
||||||
|
* the Pending structure.
|
||||||
|
*
|
||||||
* @return true if we should delay before preprocessing again
|
* @return true if we should delay before preprocessing again
|
||||||
*/
|
*/
|
||||||
public boolean preprocessQueue(List pending, Sender sender, Receiver receiver);
|
public boolean preprocessQueue(List<Pending> pending, Sender sender, Receiver receiver);
|
||||||
|
|
||||||
/** how long do we want to wait before flushing */
|
/** how long do we want to wait before flushing */
|
||||||
public long getDelayAmount();
|
public long getDelayAmount();
|
||||||
@ -173,6 +179,9 @@ public class TunnelGateway {
|
|||||||
public long receiveEncrypted(byte encrypted[]);
|
public long receiveEncrypted(byte encrypted[]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores all the state for an unsent or partially-sent message
|
||||||
|
*/
|
||||||
public static class Pending {
|
public static class Pending {
|
||||||
protected Hash _toRouter;
|
protected Hash _toRouter;
|
||||||
protected TunnelId _toTunnel;
|
protected TunnelId _toTunnel;
|
||||||
@ -182,7 +191,7 @@ public class TunnelGateway {
|
|||||||
protected int _offset;
|
protected int _offset;
|
||||||
protected int _fragmentNumber;
|
protected int _fragmentNumber;
|
||||||
protected long _created;
|
protected long _created;
|
||||||
private List _messageIds;
|
private List<Long> _messageIds;
|
||||||
|
|
||||||
public Pending(I2NPMessage message, Hash toRouter, TunnelId toTunnel) {
|
public Pending(I2NPMessage message, Hash toRouter, TunnelId toTunnel) {
|
||||||
this(message, toRouter, toTunnel, System.currentTimeMillis());
|
this(message, toRouter, toTunnel, System.currentTimeMillis());
|
||||||
@ -222,7 +231,7 @@ public class TunnelGateway {
|
|||||||
_messageIds.add(new Long(id));
|
_messageIds.add(new Long(id));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public List getMessageIds() {
|
public List<Long> getMessageIds() {
|
||||||
synchronized (Pending.this) {
|
synchronized (Pending.this) {
|
||||||
if (_messageIds != null)
|
if (_messageIds != null)
|
||||||
return new ArrayList(_messageIds);
|
return new ArrayList(_messageIds);
|
||||||
@ -231,6 +240,8 @@ public class TunnelGateway {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Extend for debugging */
|
||||||
class PendingImpl extends Pending {
|
class PendingImpl extends Pending {
|
||||||
public PendingImpl(I2NPMessage message, Hash toRouter, TunnelId toTunnel) {
|
public PendingImpl(I2NPMessage message, Hash toRouter, TunnelId toTunnel) {
|
||||||
super(message, toRouter, toTunnel, _context.clock().now());
|
super(message, toRouter, toTunnel, _context.clock().now());
|
||||||
|
@ -101,8 +101,11 @@ public class TunnelParticipant {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/****
|
||||||
private int _periodMessagesTransferred;
|
private int _periodMessagesTransferred;
|
||||||
private long _lastCoallesced = System.currentTimeMillis();
|
private long _lastCoallesced = System.currentTimeMillis();
|
||||||
|
****/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* take note that the peers specified were able to push us data. hmm, is this safe?
|
* take note that the peers specified were able to push us data. hmm, is this safe?
|
||||||
* this could be easily gamed to get us to rank some peer of their choosing as quite
|
* this could be easily gamed to get us to rank some peer of their choosing as quite
|
||||||
|
@ -54,9 +54,7 @@ class BuildExecutor implements Runnable {
|
|||||||
|
|
||||||
// Get stat manager, get recognized bandwidth tiers
|
// Get stat manager, get recognized bandwidth tiers
|
||||||
StatManager statMgr = _context.statManager();
|
StatManager statMgr = _context.statManager();
|
||||||
@SuppressWarnings("static-access")
|
String bwTiers = RouterInfo.BW_CAPABILITY_CHARS;
|
||||||
/* FIXME Accessing static field "BW_CAPABILITY_CHARS" FIXME */
|
|
||||||
String bwTiers = _context.router().getRouterInfo().BW_CAPABILITY_CHARS;
|
|
||||||
// For each bandwidth tier, create tunnel build agree/reject/expire stats
|
// For each bandwidth tier, create tunnel build agree/reject/expire stats
|
||||||
for (int i = 0; i < bwTiers.length(); i++) {
|
for (int i = 0; i < bwTiers.length(); i++) {
|
||||||
String bwTier = String.valueOf(bwTiers.charAt(i));
|
String bwTier = String.valueOf(bwTiers.charAt(i));
|
||||||
|
@ -79,8 +79,9 @@ public class PooledTunnelCreatorConfig extends TunnelCreatorConfig {
|
|||||||
public TunnelPool getTunnelPool() { return _pool; }
|
public TunnelPool getTunnelPool() { return _pool; }
|
||||||
|
|
||||||
|
|
||||||
/* FIXME Exporting non-public type through public API FIXME */
|
/** @deprecated unused, which makes _testJob unused - why is it here */
|
||||||
public void setTestJob(TestJob job) { _testJob = job; }
|
void setTestJob(TestJob job) { _testJob = job; }
|
||||||
|
/** does nothing, to be deprecated */
|
||||||
public void setExpireJob(Job job) { /* _expireJob = job; */ }
|
public void setExpireJob(Job job) { /* _expireJob = job; */ }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -29,6 +29,8 @@ import net.i2p.stat.RateStat;
|
|||||||
import net.i2p.util.I2PThread;
|
import net.i2p.util.I2PThread;
|
||||||
import net.i2p.util.Log;
|
import net.i2p.util.Log;
|
||||||
import net.i2p.util.ObjectCounter;
|
import net.i2p.util.ObjectCounter;
|
||||||
|
import net.i2p.util.SimpleScheduler;
|
||||||
|
import net.i2p.util.SimpleTimer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@ -42,7 +44,7 @@ public class TunnelPoolManager implements TunnelManagerFacade {
|
|||||||
private final Map<Hash, TunnelPool> _clientOutboundPools;
|
private final Map<Hash, TunnelPool> _clientOutboundPools;
|
||||||
private TunnelPool _inboundExploratory;
|
private TunnelPool _inboundExploratory;
|
||||||
private TunnelPool _outboundExploratory;
|
private TunnelPool _outboundExploratory;
|
||||||
private BuildExecutor _executor;
|
private final BuildExecutor _executor;
|
||||||
private boolean _isShutdown;
|
private boolean _isShutdown;
|
||||||
|
|
||||||
public TunnelPoolManager(RouterContext ctx) {
|
public TunnelPoolManager(RouterContext ctx) {
|
||||||
@ -263,6 +265,7 @@ public class TunnelPoolManager implements TunnelManagerFacade {
|
|||||||
TunnelPool inbound = null;
|
TunnelPool inbound = null;
|
||||||
TunnelPool outbound = null;
|
TunnelPool outbound = null;
|
||||||
// should we share the clientPeerSelector across both inbound and outbound?
|
// should we share the clientPeerSelector across both inbound and outbound?
|
||||||
|
// or just one for all clients? why separate?
|
||||||
synchronized (_clientInboundPools) {
|
synchronized (_clientInboundPools) {
|
||||||
inbound = _clientInboundPools.get(dest);
|
inbound = _clientInboundPools.get(dest);
|
||||||
if (inbound == null) {
|
if (inbound == null) {
|
||||||
@ -284,11 +287,22 @@ public class TunnelPoolManager implements TunnelManagerFacade {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
inbound.startup();
|
inbound.startup();
|
||||||
try { Thread.sleep(3*1000); } catch (InterruptedException ie) {}
|
SimpleScheduler.getInstance().addEvent(new DelayedStartup(outbound), 3*1000);
|
||||||
outbound.startup();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static class DelayedStartup implements SimpleTimer.TimedEvent {
|
||||||
|
private TunnelPool pool;
|
||||||
|
|
||||||
|
public DelayedStartup(TunnelPool p) {
|
||||||
|
this.pool = p;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void timeReached() {
|
||||||
|
this.pool.startup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void removeTunnels(Hash destination) {
|
public void removeTunnels(Hash destination) {
|
||||||
if (destination == null) return;
|
if (destination == null) return;
|
||||||
if (_context.clientManager().isLocal(destination)) {
|
if (_context.clientManager().isLocal(destination)) {
|
||||||
@ -361,12 +375,11 @@ public class TunnelPoolManager implements TunnelManagerFacade {
|
|||||||
_inboundExploratory = new TunnelPool(_context, this, inboundSettings, selector);
|
_inboundExploratory = new TunnelPool(_context, this, inboundSettings, selector);
|
||||||
_inboundExploratory.startup();
|
_inboundExploratory.startup();
|
||||||
|
|
||||||
try { Thread.sleep(3*1000); } catch (InterruptedException ie) {}
|
|
||||||
TunnelPoolSettings outboundSettings = new TunnelPoolSettings();
|
TunnelPoolSettings outboundSettings = new TunnelPoolSettings();
|
||||||
outboundSettings.setIsExploratory(true);
|
outboundSettings.setIsExploratory(true);
|
||||||
outboundSettings.setIsInbound(false);
|
outboundSettings.setIsInbound(false);
|
||||||
_outboundExploratory = new TunnelPool(_context, this, outboundSettings, selector);
|
_outboundExploratory = new TunnelPool(_context, this, outboundSettings, selector);
|
||||||
_outboundExploratory.startup();
|
SimpleScheduler.getInstance().addEvent(new DelayedStartup(_outboundExploratory), 3*1000);
|
||||||
|
|
||||||
// try to build up longer tunnels
|
// try to build up longer tunnels
|
||||||
_context.jobQueue().addJob(new BootstrapPool(_context, _inboundExploratory));
|
_context.jobQueue().addJob(new BootstrapPool(_context, _inboundExploratory));
|
||||||
|
Reference in New Issue
Block a user