2006-02-19 jrandom
* Moved the current net's reseed URL to a different location than where the old net looks (dev.i2p.net/i2pdb2/ vs .../i2pdb/) * More aggressively expire inbound messages (on receive, not just on send) * Add in a hook for breaking backwards compatibility in the SSU wire protocol directly by including a version as part of the handshake. The version is currently set to 0, however, so the wire protocol from this build is compatible with all earlier SSU implementations. * Increased the number of complete message readers, cutting down substantially on the delay processing inbound messages. * Delete the message history file on startup * Reworked the restart/shutdown display on the console (thanks bd_!)
This commit is contained in:
@ -141,7 +141,7 @@ public class ConfigNetHandler extends FormHandler {
|
||||
}
|
||||
}
|
||||
|
||||
private static final String DEFAULT_SEED_URL = "http://dev.i2p.net/i2pdb/";
|
||||
private static final String DEFAULT_SEED_URL = ReseedHandler.DEFAULT_SEED_URL;
|
||||
/**
|
||||
* Reseed has been requested, so lets go ahead and do it. Fetch all of
|
||||
* the routerInfo-*.dat files from the specified URL (or the default) and
|
||||
|
@ -0,0 +1,75 @@
|
||||
package net.i2p.router.web;
|
||||
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.router.Router;
|
||||
import net.i2p.router.RouterContext;
|
||||
import net.i2p.router.web.ConfigServiceHandler.UpdateWrapperManagerTask;
|
||||
import net.i2p.router.web.ConfigServiceHandler.UpdateWrapperManagerAndRekeyTask;
|
||||
|
||||
/**
|
||||
* simple helper to control restarts/shutdowns in the left hand nav
|
||||
*
|
||||
*/
|
||||
public class ConfigRestartBean {
|
||||
public static String getNonce() {
|
||||
RouterContext ctx = ContextHelper.getContext(null);
|
||||
String nonce = System.getProperty("console.nonce");
|
||||
if (nonce == null) {
|
||||
nonce = ""+ctx.random().nextLong();
|
||||
System.setProperty("console.nonce", nonce);
|
||||
}
|
||||
return nonce;
|
||||
}
|
||||
public static String renderStatus(String urlBase, String action, String nonce) {
|
||||
RouterContext ctx = ContextHelper.getContext(null);
|
||||
String systemNonce = getNonce();
|
||||
if ( (nonce != null) && (systemNonce.equals(nonce)) && (action != null) ) {
|
||||
if ("shutdownImmediate".equals(action)) {
|
||||
ctx.router().addShutdownTask(new ConfigServiceHandler.UpdateWrapperManagerTask(Router.EXIT_HARD));
|
||||
ctx.router().shutdown(Router.EXIT_HARD); // never returns
|
||||
} else if ("cancelShutdown".equals(action)) {
|
||||
ctx.router().cancelGracefulShutdown();
|
||||
} else if ("restartImmediate".equals(action)) {
|
||||
ctx.router().addShutdownTask(new ConfigServiceHandler.UpdateWrapperManagerTask(Router.EXIT_HARD_RESTART));
|
||||
ctx.router().shutdown(Router.EXIT_HARD_RESTART); // never returns
|
||||
} else if ("restart".equals(action)) {
|
||||
ctx.router().addShutdownTask(new ConfigServiceHandler.UpdateWrapperManagerTask(Router.EXIT_GRACEFUL_RESTART));
|
||||
ctx.router().shutdownGracefully(Router.EXIT_GRACEFUL_RESTART);
|
||||
} else if ("shutdown".equals(action)) {
|
||||
ctx.router().addShutdownTask(new ConfigServiceHandler.UpdateWrapperManagerTask(Router.EXIT_GRACEFUL));
|
||||
ctx.router().shutdownGracefully();
|
||||
}
|
||||
}
|
||||
|
||||
boolean shuttingDown = isShuttingDown(ctx);
|
||||
boolean restarting = isRestarting(ctx);
|
||||
long timeRemaining = ctx.router().getShutdownTimeRemaining();
|
||||
if (shuttingDown) {
|
||||
if (timeRemaining <= 0) {
|
||||
return "<b>Shutdown imminent</b>";
|
||||
} else {
|
||||
return "<b>Shutdown in " + DataHelper.formatDuration(timeRemaining) + "</b><br />"
|
||||
+ "<a href=\"" + urlBase + "?consoleNonce=" + systemNonce + "&action=shutdownImmediate\">Shutdown immediately</a><br />"
|
||||
+ "<a href=\"" + urlBase + "?consoleNonce=" + systemNonce + "&action=cancelShutdown\">Cancel shutdown</a> ";
|
||||
}
|
||||
} else if (restarting) {
|
||||
if (timeRemaining <= 0) {
|
||||
return "<b>Restart imminent</b>";
|
||||
} else {
|
||||
return "<b>Restart in " + DataHelper.formatDuration(timeRemaining) + "</b><br />"
|
||||
+ "<a href=\"" + urlBase + "?consoleNonce=" + systemNonce + "&action=restartImmediate\">Restart immediately</a><br />"
|
||||
+ "<a href=\"" + urlBase + "?consoleNonce=" + systemNonce + "&action=cancelShutdown\">Cancel restart</a> ";
|
||||
}
|
||||
} else {
|
||||
return "<a href=\"" + urlBase + "?consoleNonce=" + systemNonce + "&action=restart\" title=\"Graceful restart\">Restart</a> "
|
||||
+ "<a href=\"" + urlBase + "?consoleNonce=" + systemNonce + "&action=shutdown\" title=\"Graceful shutdown\">Shutdown</a>";
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isShuttingDown(RouterContext ctx) {
|
||||
return Router.EXIT_GRACEFUL == ctx.router().scheduledGracefulExitCode();
|
||||
}
|
||||
private static boolean isRestarting(RouterContext ctx) {
|
||||
return Router.EXIT_GRACEFUL_RESTART == ctx.router().scheduledGracefulExitCode();
|
||||
}
|
||||
}
|
@ -24,6 +24,7 @@ public class NoticeHelper {
|
||||
}
|
||||
|
||||
public String getSystemNotice() {
|
||||
if (true) return ""; // moved to the left hand nav
|
||||
if (_context.router().gracefulShutdownInProgress()) {
|
||||
long remaining = _context.router().getShutdownTimeRemaining();
|
||||
if (remaining > 0)
|
||||
|
@ -17,7 +17,7 @@ import net.i2p.util.I2PThread;
|
||||
|
||||
/**
|
||||
* Handler to deal with reseed requests. This reseed from the URL
|
||||
* http://dev.i2p.net/i2pdb/ unless the java env property "i2p.reseedURL" is
|
||||
* http://dev.i2p.net/i2pdb2/ unless the java env property "i2p.reseedURL" is
|
||||
* set. It always writes to ./netDb/, so don't mess with that.
|
||||
*
|
||||
*/
|
||||
@ -58,7 +58,7 @@ public class ReseedHandler {
|
||||
}
|
||||
}
|
||||
|
||||
private static final String DEFAULT_SEED_URL = "http://dev.i2p.net/i2pdb/";
|
||||
static final String DEFAULT_SEED_URL = "http://dev.i2p.net/i2pdb2/";
|
||||
/**
|
||||
* Reseed has been requested, so lets go ahead and do it. Fetch all of
|
||||
* the routerInfo-*.dat files from the specified URL (or the default) and
|
||||
|
@ -28,19 +28,6 @@
|
||||
<input type="hidden" name="nonce" value="<%=System.getProperty("net.i2p.router.web.ConfigNetHandler.nonce")%>" />
|
||||
<input type="hidden" name="action" value="blah" />
|
||||
|
||||
<b>External UDP address:</b> <i><jsp:getProperty name="nethelper" property="udpAddress" /></i><br />
|
||||
<b>Require SSU introductions? </b>
|
||||
<input type="checkbox" name="requireIntroductions" value="true" <jsp:getProperty name="nethelper" property="requireIntroductionsChecked" /> /><br />
|
||||
<p>If you can, please poke a hole in your NAT or firewall to allow unsolicited UDP packets to reach
|
||||
you on your external UDP address. If you can't, I2P now includes supports UDP hole punching
|
||||
with "SSU introductions" - peers who will relay a request from someone you don't know to your
|
||||
router for your router so that you can make an outbound connection to them. I2P will use these
|
||||
introductions automatically if it detects that the port is not forwarded (as shown by
|
||||
the <i>Status: OK (NAT)</i> line), or you can manually require them here.
|
||||
Users behind symmetric NATs, such as OpenBSD's pf, are not currently supported.</p>
|
||||
<input type="submit" name="recheckReachability" value="Check network reachability..." />
|
||||
<hr />
|
||||
|
||||
<b>Bandwidth limiter</b><br />
|
||||
Inbound rate:
|
||||
<input name="inboundrate" type="text" size="2" value="<jsp:getProperty name="nethelper" property="inboundRate" />" /> KBps
|
||||
@ -65,6 +52,18 @@
|
||||
to pick faster peers, but can cost substantial bandwidth. Relevent data from the
|
||||
load testing is fed into the profiles as well as the
|
||||
<a href="oldstats.jsp#test.rtt">test.rtt</a> and related stats.</p>
|
||||
<hr />
|
||||
<b>External UDP address:</b> <i><jsp:getProperty name="nethelper" property="udpAddress" /></i><br />
|
||||
<b>Require SSU introductions? </b>
|
||||
<input type="checkbox" name="requireIntroductions" value="true" <jsp:getProperty name="nethelper" property="requireIntroductionsChecked" /> /><br />
|
||||
<p>If you can, please poke a hole in your NAT or firewall to allow unsolicited UDP packets to reach
|
||||
you on your external UDP address. If you can't, I2P now includes supports UDP hole punching
|
||||
with "SSU introductions" - peers who will relay a request from someone you don't know to your
|
||||
router for your router so that you can make an outbound connection to them. I2P will use these
|
||||
introductions automatically if it detects that the port is not forwarded (as shown by
|
||||
the <i>Status: OK (NAT)</i> line), or you can manually require them here.
|
||||
Users behind symmetric NATs, such as OpenBSD's pf, are not currently supported.</p>
|
||||
<input type="submit" name="recheckReachability" value="Check network reachability..." />
|
||||
<hr />
|
||||
<b>Dynamic Router Keys: </b>
|
||||
<input type="checkbox" name="dynamicKeys" value="true" <jsp:getProperty name="nethelper" property="dynamicKeysChecked" /> /><br />
|
||||
|
@ -23,45 +23,6 @@ if (System.getProperty("router.consoleNonce") == null) {
|
||||
</div>
|
||||
|
||||
<div class="main" id="main">
|
||||
|
||||
<jsp:useBean class="net.i2p.router.web.ConfigServiceHandler" id="servicehandler" scope="request" />
|
||||
<jsp:setProperty name="servicehandler" property="*" />
|
||||
<jsp:setProperty name="servicehandler" property="contextId" value="<%=(String)session.getAttribute("i2p.contextId")%>" />
|
||||
<font color="red"><jsp:getProperty name="servicehandler" property="errors" /></font>
|
||||
<i><jsp:getProperty name="servicehandler" property="notices" /></i>
|
||||
|
||||
<jsp:useBean class="net.i2p.router.web.ConfigNetHandler" id="nethandler" scope="request" />
|
||||
<jsp:setProperty name="nethandler" property="*" />
|
||||
<jsp:setProperty name="nethandler" property="contextId" value="<%=(String)session.getAttribute("i2p.contextId")%>" />
|
||||
<font color="red"><jsp:getProperty name="nethandler" property="errors" /></font>
|
||||
<i><jsp:getProperty name="nethandler" property="notices" /></i>
|
||||
|
||||
<jsp:useBean class="net.i2p.router.web.ConfigNetHelper" id="nethelper" scope="request" />
|
||||
<jsp:setProperty name="nethelper" property="contextId" value="<%=(String)session.getAttribute("i2p.contextId")%>" />
|
||||
|
||||
<form action="index.jsp" method="POST">
|
||||
<input type="hidden" name="nonce" value="<%=System.getProperty("router.consoleNonce")%>" />
|
||||
<input type="hidden" name="updateratesonly" value="true" />
|
||||
<input type="hidden" name="save" value="Save changes" />
|
||||
Inbound bandwidth:
|
||||
<input name="inboundrate" type="text" size="2" value="<jsp:getProperty name="nethelper" property="inboundRate" />" /> KBps
|
||||
bursting up to
|
||||
<input name="inboundburstrate" type="text" size="2" value="<jsp:getProperty name="nethelper" property="inboundBurstRate" />" /> KBps for
|
||||
<jsp:getProperty name="nethelper" property="inboundBurstFactorBox" /><br />
|
||||
Outbound bandwidth:
|
||||
<input name="outboundrate" type="text" size="2" value="<jsp:getProperty name="nethelper" property="outboundRate" />" /> KBps
|
||||
bursting up to
|
||||
<input name="outboundburstrate" type="text" size="2" value="<jsp:getProperty name="nethelper" property="outboundBurstRate" />" /> KBps for
|
||||
<jsp:getProperty name="nethelper" property="outboundBurstFactorBox" /><br />
|
||||
<i>KBps = kilobytes per second = 1024 bytes per second.</i>
|
||||
<input type="submit" value="Save changes" name="action" />
|
||||
<hr />
|
||||
<input type="submit" name="action" value="Graceful restart" />
|
||||
<input type="submit" name="action" value="Shutdown gracefully" />
|
||||
<a href="configservice.jsp">Other shutdown/restart options</a>
|
||||
<hr />
|
||||
</form>
|
||||
|
||||
<jsp:useBean class="net.i2p.router.web.ContentHelper" id="contenthelper" scope="request" />
|
||||
<jsp:setProperty name="contenthelper" property="page" value="docs/readme.html" />
|
||||
<jsp:setProperty name="contenthelper" property="maxLines" value="300" />
|
||||
|
@ -14,10 +14,10 @@
|
||||
<b>Version:</b> <jsp:getProperty name="helper" property="version" /><br />
|
||||
<b>Uptime:</b> <jsp:getProperty name="helper" property="uptime" /><br />
|
||||
<b>Now:</b> <jsp:getProperty name="helper" property="time" /><br />
|
||||
<b>Status:</b> <a href="config.jsp"><jsp:getProperty name="helper" property="reachability" /></a><br /><%
|
||||
<b>Status:</b> <a href="config.jsp"><jsp:getProperty name="helper" property="reachability" /></a><%
|
||||
if (helper.updateAvailable()) {
|
||||
if ("true".equals(System.getProperty("net.i2p.router.web.UpdateHandler.updateInProgress", "false"))) {
|
||||
out.print(update.getStatus());
|
||||
out.print("<br />" + update.getStatus());
|
||||
} else {
|
||||
long nonce = new java.util.Random().nextLong();
|
||||
String prev = System.getProperty("net.i2p.router.web.UpdateHandler.nonce");
|
||||
@ -28,10 +28,12 @@
|
||||
uri = uri + "&updateNonce=" + nonce;
|
||||
else
|
||||
uri = uri + "?updateNonce=" + nonce;
|
||||
out.print(" <a href=\"" + uri + "\">Update available</a>");
|
||||
out.print("<br /><a href=\"" + uri + "\">Update available</a>");
|
||||
}
|
||||
}
|
||||
%><hr />
|
||||
%>
|
||||
<br /><%=net.i2p.router.web.ConfigRestartBean.renderStatus(request.getRequestURI(), request.getParameter("action"), request.getParameter("consoleNonce"))%>
|
||||
<hr />
|
||||
|
||||
<u><b><a href="peers.jsp">Peers</a></b></u><br />
|
||||
<b>Active:</b> <jsp:getProperty name="helper" property="activePeers" />/<jsp:getProperty name="helper" property="activeProfiles" /><br />
|
||||
@ -62,7 +64,7 @@
|
||||
}
|
||||
%><hr />
|
||||
|
||||
<u><b>Bandwidth in/out</b></u><br />
|
||||
<u><b><a href="config.jsp" title="Configure the bandwidth limits">Bandwidth in/out</a></b></u><br />
|
||||
<b>1s:</b> <jsp:getProperty name="helper" property="inboundMinuteKBps" />/<jsp:getProperty name="helper" property="outboundMinuteKBps" />KBps<br />
|
||||
<b>5m:</b> <jsp:getProperty name="helper" property="inboundFiveMinuteKBps" />/<jsp:getProperty name="helper" property="outboundFiveMinuteKBps" />KBps<br />
|
||||
<b>Total:</b> <jsp:getProperty name="helper" property="inboundLifetimeKBps" />/<jsp:getProperty name="helper" property="outboundLifetimeKBps" />KBps<br />
|
||||
|
15
history.txt
15
history.txt
@ -1,4 +1,17 @@
|
||||
$Id: history.txt,v 1.405 2006/02/18 01:48:48 jrandom Exp $
|
||||
$Id: history.txt,v 1.406 2006/02/18 22:22:33 jrandom Exp $
|
||||
|
||||
2006-02-19 jrandom
|
||||
* Moved the current net's reseed URL to a different location than where
|
||||
the old net looks (dev.i2p.net/i2pdb2/ vs .../i2pdb/)
|
||||
* More aggressively expire inbound messages (on receive, not just on send)
|
||||
* Add in a hook for breaking backwards compatibility in the SSU wire
|
||||
protocol directly by including a version as part of the handshake. The
|
||||
version is currently set to 0, however, so the wire protocol from this
|
||||
build is compatible with all earlier SSU implementations.
|
||||
* Increased the number of complete message readers, cutting down
|
||||
substantially on the delay processing inbound messages.
|
||||
* Delete the message history file on startup
|
||||
* Reworked the restart/shutdown display on the console (thanks bd_!)
|
||||
|
||||
2006-02-18 jrandom
|
||||
* Migrate the outbound packets from a central component to the individual
|
||||
|
@ -1,4 +1,4 @@
|
||||
<code>$Id: udp.html,v 1.18.2.1 2006/02/15 00:16:29 jrandom Exp $</code>
|
||||
<code>$Id: udp.html,v 1.19 2006/02/15 00:33:32 jrandom Exp $</code>
|
||||
|
||||
<h1>Secure Semireliable UDP (SSU)</h1>
|
||||
<b>DRAFT</b>
|
||||
@ -47,13 +47,18 @@ size payload encrypted with the appropriate key. The MAC used is
|
||||
HMAC-MD5, truncated to 16 bytes, while the key is a full AES256
|
||||
key. The specific construct of the MAC is the first 16 bytes from:</p>
|
||||
<pre>
|
||||
HMAC-MD5(payload || IV || payloadLength, macKey)
|
||||
HMAC-MD5(payload || IV || (payloadLength ^ protocolVersion), macKey)
|
||||
</pre>
|
||||
|
||||
<p>The payload itself is AES256/CBC encrypted with the IV and the
|
||||
sessionKey, with replay prevention addressed within its body,
|
||||
explained below. The payloadLength in the MAC is a 2 byte unsigned
|
||||
integer in 2s complement.</p>
|
||||
|
||||
<p>The protocolVersion is a 2 byte unsigned integer in 2s complement,
|
||||
and currently set to 0. Peers using a different protocol version will
|
||||
not be able to communicate with this peer, though earlier versions not
|
||||
using this flag are.</p>
|
||||
|
||||
<h2><a name="payload">Payload</a></h2>
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
package net.i2p.router;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.text.SimpleDateFormat;
|
||||
@ -33,6 +34,7 @@ public class MessageHistory {
|
||||
private ReinitializeJob _reinitializeJob;
|
||||
private WriteJob _writeJob;
|
||||
private SubmitMessageHistoryJob _submitMessageHistoryJob;
|
||||
private volatile boolean _firstPass;
|
||||
|
||||
private final static byte[] NL = System.getProperty("line.separator").getBytes();
|
||||
private final static int FLUSH_SIZE = 1000; // write out at least once every 1000 entries
|
||||
@ -53,6 +55,7 @@ public class MessageHistory {
|
||||
_fmt.setTimeZone(TimeZone.getTimeZone("GMT"));
|
||||
_reinitializeJob = new ReinitializeJob();
|
||||
_writeJob = new WriteJob();
|
||||
_firstPass = true;
|
||||
//_submitMessageHistoryJob = new SubmitMessageHistoryJob(_context);
|
||||
initialize(true);
|
||||
}
|
||||
@ -103,6 +106,12 @@ public class MessageHistory {
|
||||
_localIdent = getName(_context.routerHash());
|
||||
_unwrittenEntries = new ArrayList(64);
|
||||
updateSettings();
|
||||
// clear the history file on startup
|
||||
if (_firstPass) {
|
||||
File f = new File(_historyFile);
|
||||
f.delete();
|
||||
}
|
||||
_firstPass = false;
|
||||
addEntry(getPrefix() + "** Router initialized (started up or changed identities)");
|
||||
_context.jobQueue().addJob(_writeJob);
|
||||
//_submitMessageHistoryJob.getTiming().setStartAfter(_context.clock().now() + 2*60*1000);
|
||||
|
@ -15,9 +15,9 @@ import net.i2p.CoreVersion;
|
||||
*
|
||||
*/
|
||||
public class RouterVersion {
|
||||
public final static String ID = "$Revision: 1.348 $ $Date: 2006/02/18 01:38:30 $";
|
||||
public final static String ID = "$Revision: 1.349 $ $Date: 2006/02/18 22:22:32 $";
|
||||
public final static String VERSION = "0.6.1.10";
|
||||
public final static long BUILD = 4;
|
||||
public final static long BUILD = 5;
|
||||
public static void main(String args[]) {
|
||||
System.out.println("I2P Router version: " + VERSION + "-" + BUILD);
|
||||
System.out.println("Router ID: " + RouterVersion.ID);
|
||||
|
@ -20,7 +20,7 @@ import net.i2p.util.Log;
|
||||
* parse 'em into I2NPMessages, and stick them on the
|
||||
* {@link net.i2p.router.InNetMessagePool} by way of the {@link UDPTransport}.
|
||||
*/
|
||||
public class MessageReceiver implements Runnable {
|
||||
public class MessageReceiver {
|
||||
private RouterContext _context;
|
||||
private Log _log;
|
||||
private UDPTransport _transport;
|
||||
@ -28,7 +28,6 @@ public class MessageReceiver implements Runnable {
|
||||
private List _completeMessages;
|
||||
private boolean _alive;
|
||||
private ByteCache _cache;
|
||||
private I2NPMessageHandler _handler;
|
||||
|
||||
public MessageReceiver(RouterContext ctx, UDPTransport transport) {
|
||||
_context = ctx;
|
||||
@ -36,16 +35,31 @@ public class MessageReceiver implements Runnable {
|
||||
_transport = transport;
|
||||
_completeMessages = new ArrayList(16);
|
||||
_cache = ByteCache.getInstance(64, I2NPMessage.MAX_SIZE);
|
||||
_handler = new I2NPMessageHandler(ctx);
|
||||
_context.statManager().createRateStat("udp.inboundExpired", "How many messages were expired before reception?", "udp", new long[] { 60*1000l, 10*60*1000l });
|
||||
_context.statManager().createRateStat("udp.inboundRemaining", "How many messages were remaining when a message is pulled off the complete queue?", "udp", new long[] { 60*1000l, 10*60*1000l });
|
||||
_context.statManager().createRateStat("udp.inboundReady", "How many messages were ready when a message is added to the complete queue?", "udp", new long[] { 60*1000l, 10*60*1000l });
|
||||
_context.statManager().createRateStat("udp.inboundReadTime", "How long it takes to parse in the completed fragments into a message?", "udp", new long[] { 60*1000l, 10*60*1000l });
|
||||
_context.statManager().createRateStat("udp.inboundReceiveProcessTime", "How long it takes to add the message to the transport?", "udp", new long[] { 60*1000l, 10*60*1000l });
|
||||
_context.statManager().createRateStat("udp.inboundLag", "How long the olded ready message has been sitting on the queue (period is the queue size)?", "udp", new long[] { 60*1000l, 10*60*1000l });
|
||||
|
||||
_alive = true;
|
||||
}
|
||||
|
||||
|
||||
public void startup() {
|
||||
_alive = true;
|
||||
I2PThread t = new I2PThread(this, "UDP message receiver");
|
||||
t.setDaemon(true);
|
||||
t.start();
|
||||
for (int i = 0; i < 5; i++) {
|
||||
I2PThread t = new I2PThread(new Runner(), "UDP message receiver " + i);
|
||||
t.setDaemon(true);
|
||||
t.start();
|
||||
}
|
||||
}
|
||||
|
||||
private class Runner implements Runnable {
|
||||
private I2NPMessageHandler _handler;
|
||||
public Runner() { _handler = new I2NPMessageHandler(_context); }
|
||||
public void run() { loop(_handler); }
|
||||
}
|
||||
|
||||
public void shutdown() {
|
||||
_alive = false;
|
||||
synchronized (_completeMessages) {
|
||||
@ -55,34 +69,65 @@ public class MessageReceiver implements Runnable {
|
||||
}
|
||||
|
||||
public void receiveMessage(InboundMessageState state) {
|
||||
int total = 0;
|
||||
long lag = -1;
|
||||
synchronized (_completeMessages) {
|
||||
_completeMessages.add(state);
|
||||
total = _completeMessages.size();
|
||||
if (total > 1)
|
||||
lag = ((InboundMessageState)_completeMessages.get(0)).getLifetime();
|
||||
_completeMessages.notifyAll();
|
||||
}
|
||||
if (total > 1)
|
||||
_context.statManager().addRateData("udp.inboundReady", total, 0);
|
||||
if (lag > 1000)
|
||||
_context.statManager().addRateData("udp.inboundLag", lag, total);
|
||||
}
|
||||
|
||||
public void run() {
|
||||
public void loop(I2NPMessageHandler handler) {
|
||||
InboundMessageState message = null;
|
||||
ByteArray buf = _cache.acquire();
|
||||
|
||||
while (_alive) {
|
||||
int expired = 0;
|
||||
long expiredLifetime = 0;
|
||||
int remaining = 0;
|
||||
try {
|
||||
synchronized (_completeMessages) {
|
||||
if (_completeMessages.size() > 0)
|
||||
message = (InboundMessageState)_completeMessages.remove(0);
|
||||
else
|
||||
_completeMessages.wait();
|
||||
while (message == null) {
|
||||
if (_completeMessages.size() > 0) // grab the tail for lowest latency
|
||||
message = (InboundMessageState)_completeMessages.remove(_completeMessages.size()-1);
|
||||
else
|
||||
_completeMessages.wait(5000);
|
||||
if ( (message != null) && (message.isExpired()) ) {
|
||||
expiredLifetime += message.getLifetime();
|
||||
message = null;
|
||||
expired++;
|
||||
}
|
||||
remaining = _completeMessages.size();
|
||||
}
|
||||
}
|
||||
} catch (InterruptedException ie) {}
|
||||
|
||||
if (expired > 0)
|
||||
_context.statManager().addRateData("udp.inboundExpired", expired, expiredLifetime);
|
||||
|
||||
if (message != null) {
|
||||
long before = System.currentTimeMillis();
|
||||
if (remaining > 0)
|
||||
_context.statManager().addRateData("udp.inboundRemaining", remaining, 0);
|
||||
int size = message.getCompleteSize();
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Full message received (" + message.getMessageId() + ") after " + message.getLifetime());
|
||||
I2NPMessage msg = readMessage(buf, message);
|
||||
I2NPMessage msg = readMessage(buf, message, handler);
|
||||
long afterRead = System.currentTimeMillis();
|
||||
if (msg != null)
|
||||
_transport.messageReceived(msg, null, message.getFrom(), message.getLifetime(), size);
|
||||
message = null;
|
||||
long after = System.currentTimeMillis();
|
||||
if (afterRead - before > 100)
|
||||
_context.statManager().addRateData("udp.inboundReadTime", afterRead - before, remaining);
|
||||
if (after - afterRead > 100)
|
||||
_context.statManager().addRateData("udp.inboundReceiveProcessTime", after - afterRead, remaining);
|
||||
}
|
||||
}
|
||||
|
||||
@ -90,7 +135,7 @@ public class MessageReceiver implements Runnable {
|
||||
_cache.release(buf, false);
|
||||
}
|
||||
|
||||
private I2NPMessage readMessage(ByteArray buf, InboundMessageState state) {
|
||||
private I2NPMessage readMessage(ByteArray buf, InboundMessageState state, I2NPMessageHandler handler) {
|
||||
try {
|
||||
//byte buf[] = new byte[state.getCompleteSize()];
|
||||
ByteArray fragments[] = state.getFragments();
|
||||
@ -109,7 +154,7 @@ public class MessageReceiver implements Runnable {
|
||||
_log.error("Hmm, offset of the fragments = " + off + " while the state says " + state.getCompleteSize());
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Raw byte array for " + state.getMessageId() + ": " + Base64.encode(buf.getData(), 0, state.getCompleteSize()));
|
||||
I2NPMessage m = I2NPMessageImpl.fromRawByteArray(_context, buf.getData(), 0, state.getCompleteSize(), _handler);
|
||||
I2NPMessage m = I2NPMessageImpl.fromRawByteArray(_context, buf.getData(), 0, state.getCompleteSize(), handler);
|
||||
m.setUniqueId(state.getMessageId());
|
||||
return m;
|
||||
} catch (I2NPMessageException ime) {
|
||||
|
@ -88,6 +88,7 @@ public class OutboundMessageFragments {
|
||||
peer.dropOutbound();
|
||||
synchronized (_activePeers) {
|
||||
_activePeers.remove(peer);
|
||||
_activePeers.notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
@ -159,7 +160,7 @@ public class OutboundMessageFragments {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Error initializing " + msg);
|
||||
}
|
||||
finishMessages();
|
||||
//finishMessages();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -211,6 +212,7 @@ public class OutboundMessageFragments {
|
||||
i--;
|
||||
}
|
||||
}
|
||||
_activePeers.notifyAll();
|
||||
}
|
||||
for (int i = 0; i < peers.size(); i++) {
|
||||
PeerState state = (PeerState)peers.get(i);
|
||||
@ -238,7 +240,7 @@ public class OutboundMessageFragments {
|
||||
while (_alive && (state == null) ) {
|
||||
long now = _context.clock().now();
|
||||
int nextSendDelay = -1;
|
||||
//finishMessages();
|
||||
finishMessages();
|
||||
try {
|
||||
synchronized (_activePeers) {
|
||||
for (int i = 0; i < _activePeers.size(); i++) {
|
||||
|
@ -30,6 +30,9 @@ public class PacketBuilder {
|
||||
private static final ByteCache _ivCache = ByteCache.getInstance(64, UDPPacket.IV_SIZE);
|
||||
private static final ByteCache _hmacCache = ByteCache.getInstance(64, Hash.HASH_LENGTH);
|
||||
private static final ByteCache _blockCache = ByteCache.getInstance(64, 16);
|
||||
|
||||
/** we only talk to people of the right version */
|
||||
static final int PROTOCOL_VERSION = 0;
|
||||
|
||||
public PacketBuilder(I2PAppContext ctx, UDPTransport transport) {
|
||||
_context = ctx;
|
||||
@ -160,10 +163,11 @@ public class PacketBuilder {
|
||||
off += 2;
|
||||
|
||||
int sizeWritten = state.writeFragment(data, off, fragment);
|
||||
if (sizeWritten != size)
|
||||
if (sizeWritten != size) {
|
||||
_log.error("Size written: " + sizeWritten + " but size: " + size
|
||||
+ " for fragment " + fragment + " of " + state.getMessageId());
|
||||
else if (_log.shouldLog(Log.DEBUG))
|
||||
return null;
|
||||
} else if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Size written: " + sizeWritten + " for fragment " + fragment
|
||||
+ " of " + state.getMessageId());
|
||||
size = sizeWritten;
|
||||
@ -1004,7 +1008,7 @@ public class PacketBuilder {
|
||||
* Encrypt the packet with the cipher key and the given IV, generate a
|
||||
* MAC for that encrypted data and IV, and store the result in the packet.
|
||||
* The MAC used is:
|
||||
* HMAC-SHA256(payload || IV || payloadLength, macKey)[0:15]
|
||||
* HMAC-SHA256(payload || IV || (payloadLength ^ protocolVersion), macKey)[0:15]
|
||||
*
|
||||
* @param packet prepared packet with the first 32 bytes empty and a length
|
||||
* whose size is mod 16
|
||||
@ -1024,7 +1028,7 @@ public class PacketBuilder {
|
||||
off += encryptSize;
|
||||
System.arraycopy(iv.getData(), 0, data, off, UDPPacket.IV_SIZE);
|
||||
off += UDPPacket.IV_SIZE;
|
||||
DataHelper.toLong(data, off, 2, encryptSize);
|
||||
DataHelper.toLong(data, off, 2, encryptSize ^ PROTOCOL_VERSION);
|
||||
|
||||
int hmacOff = packet.getPacket().getOffset();
|
||||
int hmacLen = encryptSize + UDPPacket.IV_SIZE + 2;
|
||||
|
@ -145,7 +145,7 @@ public class UDPPacket {
|
||||
ByteArray buf = _validateCache.acquire();
|
||||
|
||||
// validate by comparing _data[0:15] and
|
||||
// HMAC(payload + IV + payloadLength, macKey)
|
||||
// HMAC(payload + IV + (payloadLength ^ protocolVersion), macKey)
|
||||
|
||||
int payloadLength = _packet.getLength() - MAC_SIZE - IV_SIZE;
|
||||
if (payloadLength > 0) {
|
||||
@ -154,7 +154,7 @@ public class UDPPacket {
|
||||
off += payloadLength;
|
||||
System.arraycopy(_data, _packet.getOffset() + MAC_SIZE, buf.getData(), off, IV_SIZE);
|
||||
off += IV_SIZE;
|
||||
DataHelper.toLong(buf.getData(), off, 2, payloadLength);
|
||||
DataHelper.toLong(buf.getData(), off, 2, payloadLength ^ PacketBuilder.PROTOCOL_VERSION);
|
||||
off += 2;
|
||||
|
||||
eq = _context.hmac().verify(macKey, buf.getData(), 0, off, _data, _packet.getOffset(), MAC_SIZE);
|
||||
|
@ -570,7 +570,10 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Received another message: " + inMsg.getClass().getName());
|
||||
}
|
||||
PeerState peer = getPeerState(remoteIdentHash);
|
||||
super.messageReceived(inMsg, remoteIdent, remoteIdentHash, msToReceive, bytesReceived);
|
||||
if (peer != null)
|
||||
peer.expireInboundMessages();
|
||||
}
|
||||
|
||||
|
||||
@ -1354,8 +1357,9 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
|
||||
"<b id=\"def.rate\">in/out</b>: the rates show a smoothed inbound and outbound transfer rate (KBytes per second)<br />\n" +
|
||||
"<b id=\"def.up\">up</b>: the uptime is how long ago this session was established<br />\n" +
|
||||
"<b id=\"def.skew\">skew</b>: the skew says how far off the other user's clock is, relative to your own<br />\n" +
|
||||
"<b id=\"def.cwnd\">cwnd</b>: the congestion window is how many bytes in 'in flight' you can send without an acknowledgement / <br />\n" +
|
||||
" the number of currently active messages being sent /<br />\n the maximum number of concurrent messages to send /<br />\n"+
|
||||
"<b id=\"def.cwnd\">cwnd</b>: the congestion window is how many bytes in 'in flight' you can send w/out an acknowledgement / <br />\n" +
|
||||
" the number of currently active messages being sent /<br />\n" +
|
||||
" the maximum number of concurrent messages to send /<br />\n"+
|
||||
" the number of consecutive sends which were blocked due to throws message window size<br />\n" +
|
||||
"<b id=\"def.ssthresh\">ssthresh</b>: the slow start threshold help make sure the cwnd doesn't grow too fast<br />\n" +
|
||||
"<b id=\"def.rtt\">rtt</b>: the round trip time is how long it takes to get an acknowledgement of a packet<br />\n" +
|
||||
|
Reference in New Issue
Block a user