Inbound requests: ");
synchronized (_pendingInboundRequests) {
for (int i = 0; i < _pendingInboundRequests.size(); i++) {
@@ -643,7 +643,7 @@ public class FIFOBandwidthLimiter {
buf.append("ms ago
\n");
}
}
- buf.append("
\n");
+ buf.append("
\n");
out.write(buf.toString());
out.flush();
}
diff --git a/router/java/src/net/i2p/router/transport/TransportManager.java b/router/java/src/net/i2p/router/transport/TransportManager.java
index 0b7d8d5470..813f7aa26a 100644
--- a/router/java/src/net/i2p/router/transport/TransportManager.java
+++ b/router/java/src/net/i2p/router/transport/TransportManager.java
@@ -369,7 +369,7 @@ public class TransportManager implements TransportEventListener {
t.renderStatusHTML(out, urlBase, sortFlags);
}
StringBuffer buf = new StringBuffer(4*1024);
- buf.append("Listening on:
\n");
+ buf.append("
Router Transport Addresses:
\n");
for (int i = 0; i < _transports.size(); i++) {
Transport t = (Transport)_transports.get(i);
if (t.getCurrentAddress() != null)
@@ -379,6 +379,8 @@ public class TransportManager implements TransportEventListener {
}
buf.append("
\n");
out.write(buf.toString());
+ out.write(_upnpManager.renderStatusHTML());
+ buf.append("\n");
out.flush();
}
}
diff --git a/router/java/src/net/i2p/router/transport/UPnP.java b/router/java/src/net/i2p/router/transport/UPnP.java
index aef65adc57..61ce5183b3 100644
--- a/router/java/src/net/i2p/router/transport/UPnP.java
+++ b/router/java/src/net/i2p/router/transport/UPnP.java
@@ -108,11 +108,17 @@ public class UPnP extends ControlPoint implements DeviceChangeListener {
DetectedIP result = null;
final String natAddress = getNATAddress();
+ if (natAddress == null || natAddress.length() <= 0) {
+ _log.warn("No external address returned");
+ return null;
+ }
try {
InetAddress detectedIP = InetAddress.getByName(natAddress);
+
short status = DetectedIP.NOT_SUPPORTED;
thinksWeAreDoubleNatted = !TransportImpl.isPubliclyRoutable(detectedIP.getAddress());
// If we have forwarded a port AND we don't have a private address
+ _log.warn("NATAddress: \"" + natAddress + "\" detectedIP: " + detectedIP + " double? " + thinksWeAreDoubleNatted);
if((portsForwarded.size() > 1) && (!thinksWeAreDoubleNatted))
status = DetectedIP.FULL_INTERNET;
@@ -291,6 +297,7 @@ public class UPnP extends ControlPoint implements DeviceChangeListener {
return Integer.valueOf(getIP.getOutputArgumentList().getArgument("NewDownstreamMaxBitRate").getValue());
}
+/***
private void listStateTable(Service serv, StringBuilder sb) {
ServiceStateTable table = serv.getServiceStateTable();
sb.append("
");
@@ -320,6 +327,7 @@ public class UPnP extends ControlPoint implements DeviceChangeListener {
sb.append("
\n");
}
-/*****
- public String handleHTTPGet(HTTPRequest request) throws PluginHTTPException {
- if(request.isParameterSet("getDeviceCapabilities")) {
- final StringBuilder sb = new StringBuilder();
- sb.append("UPnP report");
- listSubDev("WANDevice", _router, sb);
- sb.append("");
+ public String renderStatusHTML() {
+ final StringBuilder sb = new StringBuilder();
+ sb.append("UPnP Status: ");
+
+ if(isDisabled) {
+ sb.append("The plugin has been disabled; Do you have more than one UPnP Internet Gateway Device on your LAN ?");
+ return sb.toString();
+ } else if(!isNATPresent()) {
+ sb.append("The plugin hasn't found any UPnP aware, compatible device on your LAN.");
return sb.toString();
}
- HTMLNode pageNode = pr.getPageMaker().getPageNode("UP&P plugin configuration page", false, null);
- HTMLNode contentNode = pr.getPageMaker().getContentNode(pageNode);
-
- if(isDisabled) {
- HTMLNode disabledInfobox = contentNode.addChild("div", "class", "infobox infobox-error");
- HTMLNode disabledInfoboxHeader = disabledInfobox.addChild("div", "class", "infobox-header");
- HTMLNode disabledInfoboxContent = disabledInfobox.addChild("div", "class", "infobox-content");
-
- disabledInfoboxHeader.addChild("#", "UP&P plugin report");
- disabledInfoboxContent.addChild("#", "The plugin has been disabled; Do you have more than one UP&P IGD on your LAN ?");
- return pageNode.generate();
- } else if(!isNATPresent()) {
- HTMLNode notFoundInfobox = contentNode.addChild("div", "class", "infobox infobox-warning");
- HTMLNode notFoundInfoboxHeader = notFoundInfobox.addChild("div", "class", "infobox-header");
- HTMLNode notFoundInfoboxContent = notFoundInfobox.addChild("div", "class", "infobox-content");
-
- notFoundInfoboxHeader.addChild("#", "UP&P plugin report");
- notFoundInfoboxContent.addChild("#", "The plugin hasn't found any UP&P aware, compatible device on your LAN.");
- return pageNode.generate();
- }
-
- HTMLNode foundInfobox = contentNode.addChild("div", "class", "infobox infobox-normal");
- HTMLNode foundInfoboxHeader = foundInfobox.addChild("div", "class", "infobox-header");
- HTMLNode foundInfoboxContent = foundInfobox.addChild("div", "class", "infobox-content");
-
// FIXME L10n!
- foundInfoboxHeader.addChild("#", "UP&P plugin report");
- foundInfoboxContent.addChild("p", "The following device has been found : ").addChild("a", "href", "?getDeviceCapabilities").addChild("#", _router.getFriendlyName());
- foundInfoboxContent.addChild("p", "Our current external ip address is : " + getNATAddress());
+ sb.append("
Found ");
+ listSubDev(null, _router, sb);
+ sb.append(" The current external IP address reported by UPnP is " + getNATAddress());
int downstreamMaxBitRate = getDownstreamMaxBitRate();
int upstreamMaxBitRate = getUpstramMaxBitRate();
if(downstreamMaxBitRate > 0)
- foundInfoboxContent.addChild("p", "Our reported max downstream bit rate is : " + getDownstreamMaxBitRate()+ " bits/sec");
+ sb.append(" UPnP reports the max downstream bit rate is : " + getDownstreamMaxBitRate()+ " bits/sec\n");
if(upstreamMaxBitRate > 0)
- foundInfoboxContent.addChild("p", "Our reported max upstream bit rate is : " + getUpstramMaxBitRate()+ " bits/sec");
+ sb.append(" UPnP reports the max upstream bit rate is : " + getUpstramMaxBitRate()+ " bits/sec\n");
synchronized(lock) {
if(portsToForward != null) {
for(ForwardPort port : portsToForward) {
- if(portsForwarded.contains(port)) {
- foundInfoboxContent.addChild("p", "The "+port.name+" port "+port.portNumber+" / "+port.protocol+" has been forwarded successfully.");
- } else {
- foundInfoboxContent.addChild("p", "The "+port.name+" port "+port.portNumber+" / "+port.protocol+" has not been forwarded.");
- }
+ sb.append(" " + protoToString(port.protocol) + " port " + port.portNumber + " for " + port.name);
+ if(portsForwarded.contains(port))
+ sb.append(" has been forwarded successfully by UPnP.\n");
+ else
+ sb.append(" has not been forwarded UPnP.\n");
}
}
}
- return pageNode.generate();
+ sb.append("
");
+ return sb.toString();
}
-
- public String handleHTTPPost(HTTPRequest request) throws PluginHTTPException {
- return null;
- }
-***/
private boolean addMapping(String protocol, int port, String description, ForwardPort fp) {
if(isDisabled || !isNATPresent() || _router == null) {
@@ -457,8 +446,8 @@ public class UPnP extends ControlPoint implements DeviceChangeListener {
}
// Just in case...
- // this confuses my linksys - zzz
- // removeMapping(protocol, port, fp, true);
+ // this confuses my linksys? - zzz
+ removeMapping(protocol, port, fp, true);
Action add = _service.getAction("AddPortMapping");
if(add == null) {
@@ -557,14 +546,18 @@ public class UPnP extends ControlPoint implements DeviceChangeListener {
registerPorts(portsToForwardNow);
}
+ private static String protoToString(int p) {
+ if(p == ForwardPort.PROTOCOL_UDP_IPV4)
+ return "UDP";
+ if(p == ForwardPort.PROTOCOL_TCP_IPV4)
+ return "TCP";
+ return "?";
+ }
+
private void registerPorts(Set portsToForwardNow) {
for(ForwardPort port : portsToForwardNow) {
- String proto;
- if(port.protocol == ForwardPort.PROTOCOL_UDP_IPV4)
- proto = "UDP";
- else if(port.protocol == ForwardPort.PROTOCOL_TCP_IPV4)
- proto = "TCP";
- else {
+ String proto = protoToString(port.protocol);
+ if (proto.length() <= 1) {
HashMap map = new HashMap();
map.put(port, new ForwardPortStatus(ForwardPortStatus.DEFINITE_FAILURE, "Protocol not supported", port.portNumber));
forwardCallback.portForwardStatus(map);
@@ -586,15 +579,10 @@ public class UPnP extends ControlPoint implements DeviceChangeListener {
private void unregisterPorts(Set portsToForwardNow) {
for(ForwardPort port : portsToForwardNow) {
- String proto;
- if(port.protocol == ForwardPort.PROTOCOL_UDP_IPV4)
- proto = "UDP";
- else if(port.protocol == ForwardPort.PROTOCOL_TCP_IPV4)
- proto = "TCP";
- else {
+ String proto = protoToString(port.protocol);
+ if (proto.length() <= 1)
// Ignore, we've already complained about it
continue;
- }
removeMapping(proto, port.portNumber, port, false);
}
}
diff --git a/router/java/src/net/i2p/router/transport/UPnPManager.java b/router/java/src/net/i2p/router/transport/UPnPManager.java
index 4deaebc4d9..a508cabef3 100644
--- a/router/java/src/net/i2p/router/transport/UPnPManager.java
+++ b/router/java/src/net/i2p/router/transport/UPnPManager.java
@@ -45,15 +45,18 @@ public class UPnPManager {
}
public synchronized void start() {
- _log.error("UPnP Start");
- Debug.on(); // UPnP stuff -> wrapper log
+ if (_log.shouldLog(Log.DEBUG)) {
+ _log.debug("UPnP Start");
+ Debug.on(); // UPnP stuff -> wrapper log
+ }
if (!_isRunning)
_upnp.runPlugin();
_isRunning = true;
}
public synchronized void stop() {
- _log.error("UPnP Stop");
+ if (_log.shouldLog(Log.DEBUG))
+ _log.debug("UPnP Stop");
if (_isRunning)
_upnp.terminate();
_isRunning = false;
@@ -61,7 +64,8 @@ public class UPnPManager {
/** call when the ports might have changed */
public void update(Map addresses) {
- _log.error("UPnP Update:");
+ if (_log.shouldLog(Log.DEBUG))
+ _log.debug("UPnP Update:");
if (!_isRunning)
return;
Set forwards = new HashSet(addresses.size());
@@ -86,7 +90,8 @@ public class UPnPManager {
protocol = ForwardPort.PROTOCOL_TCP_IPV4;
else
continue;
- _log.error("Adding: " + style + " " + port);
+ if (_log.shouldLog(Log.DEBUG))
+ _log.debug("Adding: " + style + " " + port);
ForwardPort fp = new ForwardPort(style, false, protocol, port);
forwards.add(fp);
}
@@ -98,18 +103,32 @@ public class UPnPManager {
/** Called to indicate status on one or more forwarded ports. */
public void portForwardStatus(Map statuses) {
- _log.error("UPnP Callback:");
+ if (_log.shouldLog(Log.DEBUG))
+ _log.debug("UPnP Callback:");
- DetectedIP[] ips = _upnp.getAddress();
- for (DetectedIP ip : ips) {
- _log.error("External address: " + ip.publicAddress + " type: " + ip.natType);
- }
+ DetectedIP[] ips = _upnp.getAddress();
+ if (ips != null) {
+ for (DetectedIP ip : ips) {
+ if (_log.shouldLog(Log.DEBUG))
+ _log.debug("External address: " + ip.publicAddress + " type: " + ip.natType);
+ }
+ } else {
+ if (_log.shouldLog(Log.DEBUG))
+ _log.debug("No external address returned");
+ }
- for (ForwardPort fp : statuses.keySet()) {
- ForwardPortStatus fps = statuses.get(fp);
- _log.error(fp.name + " " + fp.protocol + " " + fp.portNumber +
- " status: " + fps.status + " reason: " + fps.reasonString + " ext port: " + fps.externalPort);
- }
- }
+ for (ForwardPort fp : statuses.keySet()) {
+ ForwardPortStatus fps = statuses.get(fp);
+ if (_log.shouldLog(Log.DEBUG))
+ _log.debug(fp.name + " " + fp.protocol + " " + fp.portNumber +
+ " status: " + fps.status + " reason: " + fps.reasonString + " ext port: " + fps.externalPort);
+ }
+ }
+ }
+
+ public String renderStatusHTML() {
+ if (!_isRunning)
+ return "UPnP is not enabled\n";
+ return _upnp.renderStatusHTML();
}
}
From 06aeff9a3057a5642f4c06f963eac68e548071c8 Mon Sep 17 00:00:00 2001
From: zzz
Date: Fri, 20 Feb 2009 19:00:01 +0000
Subject: [PATCH 004/688] drop file accidentally checked in
---
router/java/src/org/imports | 57 -------------------------------------
1 file changed, 57 deletions(-)
delete mode 100644 router/java/src/org/imports
diff --git a/router/java/src/org/imports b/router/java/src/org/imports
deleted file mode 100644
index 6fd39288ba..0000000000
--- a/router/java/src/org/imports
+++ /dev/null
@@ -1,57 +0,0 @@
- * import java.io.IOException;
- * import java.io.StringReader;
- * import plugins.JabberLinker.org.xmlpull.v1.XmlPullParserException.html;
- * import plugins.JabberLinker.org.xmlpull.v1.XmlPullParserFactory;
- * import plugins.JabberLinker.org.xmlpull.v1.XmlPullParser;
-//import plugins.UPnP.org.cybergarage.util.*;
-import java.io.*;
-import java.io.*;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.PrintWriter;
-import java.io.Reader;
-import java.io.Writer;
-import java.net.*;
-import java.net.*;
-import java.util.*;
-import java.util.*;
-import java.util.Calendar;
-import java.util.Enumeration;
-import java.util.Hashtable;
-import java.util.TimeZone;
-import java.util.Vector;
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-import org.w3c.dom.Document;
-import org.w3c.dom.NamedNodeMap;
-import org.xml.sax.InputSource;
-import plugins.UPnP.org.cybergarage.http.*;
-import plugins.UPnP.org.cybergarage.http.*;
-import plugins.UPnP.org.cybergarage.net.*;
-import plugins.UPnP.org.cybergarage.net.*;
-import plugins.UPnP.org.cybergarage.soap.*;
-import plugins.UPnP.org.cybergarage.soap.*;
-import plugins.UPnP.org.cybergarage.upnp.*;
-import plugins.UPnP.org.cybergarage.upnp.*;
-import plugins.UPnP.org.cybergarage.upnp.Device;
-import plugins.UPnP.org.cybergarage.upnp.control.*;
-import plugins.UPnP.org.cybergarage.upnp.control.*;
-import plugins.UPnP.org.cybergarage.upnp.device.*;
-import plugins.UPnP.org.cybergarage.upnp.device.*;
-import plugins.UPnP.org.cybergarage.upnp.event.*;
-import plugins.UPnP.org.cybergarage.upnp.event.*;
-import plugins.UPnP.org.cybergarage.upnp.ssdp.*;
-import plugins.UPnP.org.cybergarage.upnp.ssdp.*;
-import plugins.UPnP.org.cybergarage.upnp.xml.*;
-import plugins.UPnP.org.cybergarage.upnp.xml.*;
-import plugins.UPnP.org.cybergarage.util.*;
-import plugins.UPnP.org.cybergarage.util.*;
-import plugins.UPnP.org.cybergarage.xml.*;
-import plugins.UPnP.org.cybergarage.xml.*;
-import plugins.UPnP.org.cybergarage.xml.Node;
-import plugins.UPnP.org.cybergarage.xml.Parser;
-import plugins.UPnP.org.cybergarage.xml.ParserException;
-import plugins.UPnP.org.cybergarage.xml.parser.*;
From f4c3607c4d7725997fc5d9627d70a305d3a2d0e4 Mon Sep 17 00:00:00 2001
From: zzz
Date: Sun, 22 Feb 2009 00:35:24 +0000
Subject: [PATCH 005/688] * I2PTunnel: - Add new IRCServer tunnel
type - Catch OOMs in HTTPServer - Name the IRCClient filter
threads
---
.../java/src/net/i2p/i2ptunnel/I2PTunnel.java | 49 +++++
.../i2p/i2ptunnel/I2PTunnelHTTPServer.java | 9 +
.../net/i2p/i2ptunnel/I2PTunnelIRCClient.java | 4 +-
.../net/i2p/i2ptunnel/I2PTunnelIRCServer.java | 193 ++++++++++++++++++
.../net/i2p/i2ptunnel/TunnelController.java | 15 +-
.../src/net/i2p/i2ptunnel/web/IndexBean.java | 1 +
apps/i2ptunnel/jsp/edit.jsp | 4 +-
apps/i2ptunnel/jsp/index.jsp | 1 +
8 files changed, 270 insertions(+), 6 deletions(-)
create mode 100644 apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelIRCServer.java
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnel.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnel.java
index b72ae18b31..18b517cd2c 100644
--- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnel.java
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnel.java
@@ -234,6 +234,8 @@ public class I2PTunnel implements Logging, EventDispatcher {
runServer(args, l);
} else if ("httpserver".equals(cmdname)) {
runHttpServer(args, l);
+ } else if ("ircserver".equals(cmdname)) {
+ runIrcServer(args, l);
} else if ("textserver".equals(cmdname)) {
runTextServer(args, l);
} else if ("client".equals(cmdname)) {
@@ -383,6 +385,53 @@ public class I2PTunnel implements Logging, EventDispatcher {
}
}
+ /**
+ * Same args as runServer
+ * (we should stop duplicating all this code...)
+ */
+ public void runIrcServer(String args[], Logging l) {
+ if (args.length == 3) {
+ InetAddress serverHost = null;
+ int portNum = -1;
+ File privKeyFile = null;
+ try {
+ serverHost = InetAddress.getByName(args[0]);
+ } catch (UnknownHostException uhe) {
+ l.log("unknown host");
+ _log.error(getPrefix() + "Error resolving " + args[0], uhe);
+ notifyEvent("serverTaskId", Integer.valueOf(-1));
+ return;
+ }
+
+ try {
+ portNum = Integer.parseInt(args[1]);
+ } catch (NumberFormatException nfe) {
+ l.log("invalid port");
+ _log.error(getPrefix() + "Port specified is not valid: " + args[1], nfe);
+ notifyEvent("serverTaskId", Integer.valueOf(-1));
+ return;
+ }
+
+ privKeyFile = new File(args[2]);
+ if (!privKeyFile.canRead()) {
+ l.log("private key file does not exist");
+ _log.error(getPrefix() + "Private key file does not exist or is not readable: " + args[2]);
+ notifyEvent("serverTaskId", Integer.valueOf(-1));
+ return;
+ }
+ I2PTunnelServer serv = new I2PTunnelIRCServer(serverHost, portNum, privKeyFile, args[2], l, (EventDispatcher) this, this);
+ serv.setReadTimeout(readTimeout);
+ serv.startRunning();
+ addtask(serv);
+ notifyEvent("serverTaskId", Integer.valueOf(serv.getId()));
+ return;
+ } else {
+ l.log("server ");
+ l.log(" creates a server that sends all incoming data\n" + " of its destination to host:port.");
+ notifyEvent("serverTaskId", Integer.valueOf(-1));
+ }
+ }
+
/**
* Run the HTTP server pointing at the host and port specified using the private i2p
* destination loaded from the specified file, replacing the HTTP headers
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPServer.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPServer.java
index 658dd5e327..536844af9c 100644
--- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPServer.java
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPServer.java
@@ -124,8 +124,17 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer {
_log.error("Error while closing the received i2p con", ex);
}
} catch (IOException ex) {
+ try {
+ socket.close();
+ } catch (IOException ioe) {}
if (_log.shouldLog(Log.WARN))
_log.warn("Error while receiving the new HTTP request", ex);
+ } catch (OutOfMemoryError oom) {
+ try {
+ socket.close();
+ } catch (IOException ioe) {}
+ if (_log.shouldLog(Log.ERROR))
+ _log.error("OOM in HTTP server", oom);
}
long afterHandle = getTunnel().getContext().clock().now();
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelIRCClient.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelIRCClient.java
index e6708aa21d..5b223b1a42 100644
--- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelIRCClient.java
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelIRCClient.java
@@ -83,9 +83,9 @@ public class I2PTunnelIRCClient extends I2PTunnelClientBase implements Runnable
i2ps = createI2PSocket(dest);
i2ps.setReadTimeout(readTimeout);
StringBuffer expectedPong = new StringBuffer();
- Thread in = new I2PThread(new IrcInboundFilter(s,i2ps, expectedPong));
+ Thread in = new I2PThread(new IrcInboundFilter(s,i2ps, expectedPong), "IRC Client " + __clientId + " in");
in.start();
- Thread out = new I2PThread(new IrcOutboundFilter(s,i2ps, expectedPong));
+ Thread out = new I2PThread(new IrcOutboundFilter(s,i2ps, expectedPong), "IRC Client " + __clientId + " out");
out.start();
} catch (Exception ex) {
if (_log.shouldLog(Log.ERROR))
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelIRCServer.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelIRCServer.java
new file mode 100644
index 0000000000..970d90ff01
--- /dev/null
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelIRCServer.java
@@ -0,0 +1,193 @@
+package net.i2p.i2ptunnel;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.InetAddress;
+import java.net.Socket;
+import java.net.SocketException;
+import java.util.Properties;
+
+import net.i2p.I2PAppContext;
+import net.i2p.client.streaming.I2PSocket;
+import net.i2p.crypto.SHA256Generator;
+import net.i2p.data.DataFormatException;
+import net.i2p.data.DataHelper;
+import net.i2p.data.Destination;
+import net.i2p.data.Hash;
+import net.i2p.util.EventDispatcher;
+import net.i2p.util.I2PThread;
+import net.i2p.util.Log;
+
+/**
+ * Simple extension to the I2PTunnelServer that filters the registration
+ * sequence to pass the destination hash of the client through as the hostname,
+ * so an IRC Server may track users across nick changes.
+ *
+ * Of course, this requires the ircd actually use the hostname sent by
+ * the client rather than the IP. It is common for ircds to ignore the
+ * hostname in the USER message (unless it's coming from another server)
+ * since it is easily spoofed. So you have to fix or, if you are lucky,
+ * configure your ircd first. At least in unrealircd and ngircd this is
+ * not configurable.
+ *
+ * There are three options for mangling the desthash. Put the option in the
+ * "custom options" section of i2ptunnel.
+ * - ircserver.cloakKey unset: Cloak with a random value that is persistent for
+ * the life of this tunnel. This is the default.
+ * - ircserver.cloakKey=none: Don't cloak. Users may be correlated with their
+ * (probably) shared clients destination.
+ * Of course if the ircd does cloaking than this is ok.
+ * - ircserver.cloakKey=somepassphrase: Cloak with the hash of the passphrase. Use this to
+ * have consistent mangling across restarts, or to
+ * have multiple IRC servers cloak consistently to
+ * be able to track users even when they switch servers.
+ * Note: don't quote or put spaces in the passphrase,
+ * the i2ptunnel gui can't handle it.
+ *
+ * There is no outbound filtering.
+ *
+ * @author zzz
+ */
+public class I2PTunnelIRCServer extends I2PTunnelServer implements Runnable {
+
+ private static final Log _log = new Log(I2PTunnelIRCServer.class);
+ private static final String PROP_CLOAK="ircserver.cloakKey";
+ private boolean _cloak;
+ private byte[] _cloakKey; // 32 bytes of stuff to scramble the dest with
+
+ /**
+ * @throws IllegalArgumentException if the I2PTunnel does not contain
+ * valid config to contact the router
+ */
+ public I2PTunnelIRCServer(InetAddress host, int port, String privData, Logging l, EventDispatcher notifyThis, I2PTunnel tunnel) {
+ super(host, port, privData, l, notifyThis, tunnel);
+ initCloak(tunnel);
+ }
+
+ public I2PTunnelIRCServer(InetAddress host, int port, File privkey, String privkeyname, Logging l, EventDispatcher notifyThis, I2PTunnel tunnel) {
+ super(host, port, privkey, privkeyname, l, notifyThis, tunnel);
+ initCloak(tunnel);
+ }
+
+ public I2PTunnelIRCServer(InetAddress host, int port, InputStream privData, String privkeyname, Logging l, EventDispatcher notifyThis, I2PTunnel tunnel) {
+ super(host, port, privData, privkeyname, l, notifyThis, tunnel);
+ initCloak(tunnel);
+ }
+
+ /** generate a random 32 bytes, or the hash of the passphrase */
+ private void initCloak(I2PTunnel tunnel) {
+ Properties opts = tunnel.getClientOptions();
+ String passphrase = opts.getProperty(PROP_CLOAK);
+ _cloak = passphrase == null || !"none".equals(passphrase);
+ if (_cloak) {
+ if (passphrase == null) {
+ _cloakKey = new byte[Hash.HASH_LENGTH];
+ tunnel.getContext().random().nextBytes(_cloakKey);
+ } else {
+ _cloakKey = SHA256Generator.getInstance().calculateHash(passphrase.trim().getBytes()).getData();
+ }
+ }
+ }
+
+ protected void blockingHandle(I2PSocket socket) {
+ try {
+ // give them 15 seconds to send in the request
+ socket.setReadTimeout(15*1000);
+ InputStream in = socket.getInputStream();
+ String modifiedRegistration = filterRegistration(in, cloakDest(socket.getPeerDestination()));
+ socket.setReadTimeout(readTimeout);
+ Socket s = new Socket(remoteHost, remotePort);
+ new I2PTunnelRunner(s, socket, slock, null, modifiedRegistration.getBytes(), null);
+ } catch (SocketException ex) {
+ try {
+ socket.close();
+ } catch (IOException ioe) {
+ if (_log.shouldLog(Log.ERROR))
+ _log.error("Error while closing the received i2p con", ex);
+ }
+ } catch (IOException ex) {
+ try {
+ socket.close();
+ } catch (IOException ioe) {}
+ if (_log.shouldLog(Log.WARN))
+ _log.warn("Error while receiving the new IRC Connection", ex);
+ } catch (OutOfMemoryError oom) {
+ try {
+ socket.close();
+ } catch (IOException ioe) {}
+ if (_log.shouldLog(Log.ERROR))
+ _log.error("OOM in IRC server", oom);
+ }
+ }
+
+ /**
+ * (Optionally) append 32 bytes of crap to the destination then return
+ * the first few characters of the hash of the whole thing, + ".i2p".
+ * Or do we want the full hash if the ircd is going to use this for
+ * nickserv auto-login? Or even Base32 if it will be used in a
+ * case-insensitive manner?
+ *
+ */
+ String cloakDest(Destination d) {
+ Hash h;
+ if (_cloak) {
+ byte[] b = new byte[d.size() + _cloakKey.length];
+ System.arraycopy(b, 0, d.toByteArray(), 0, d.size());
+ System.arraycopy(b, d.size(), _cloakKey, 0, _cloakKey.length);
+ h = SHA256Generator.getInstance().calculateHash(b);
+ } else {
+ h = d.calculateHash();
+ }
+ return h.toBase64().substring(0, 8) + ".i2p";
+ }
+
+ /** keep reading until we see USER or SERVER */
+ private String filterRegistration(InputStream in, String newHostname) throws IOException {
+ StringBuffer buf = new StringBuffer(128);
+ int lineCount = 0;
+
+ while (true) {
+ String s = DataHelper.readLine(in);
+ if (s == null)
+ throw new IOException("EOF reached before the end of the headers [" + buf.toString() + "]");
+ if (++lineCount > 10)
+ throw new IOException("Too many lines before USER or SERVER, giving up");
+ s = s.trim();
+ if (_log.shouldLog(Log.DEBUG))
+ _log.debug("Got line: " + s);
+
+ String field[]=s.split(" ",5);
+ String command;
+ int idx=0;
+
+ if(field[0].charAt(0)==':')
+ idx++;
+
+ try { command = field[idx++]; }
+ catch (IndexOutOfBoundsException ioobe) // wtf, server sent borked command?
+ {
+ throw new IOException("Dropping defective message: index out of bounds while extracting command.");
+ }
+
+ if ("USER".equalsIgnoreCase(command)) {
+ if (field.length < idx + 4)
+ throw new IOException("Too few parameters in USER message: " + s);
+ // USER zzz1 hostname localhost :zzz
+ // =>
+ // USER zzz1 abcd1234.i2p localhost :zzz
+ // this whole class is for these two lines...
+ buf.append("USER ").append(field[idx]).append(' ').append(newHostname).append(".i2p ");
+ buf.append(field[idx+2]).append(' ').append(field[idx+3]).append("\r\n");
+ break;
+ }
+ buf.append(s).append("\r\n");
+ if ("SERVER".equalsIgnoreCase(command))
+ break;
+ }
+ if (_log.shouldLog(Log.DEBUG))
+ _log.debug("All done, sending: " + buf.toString());
+ return buf.toString();
+ }
+}
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelController.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelController.java
index 3c9640ce5a..82b253985f 100644
--- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelController.java
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelController.java
@@ -58,7 +58,7 @@ public class TunnelController implements Logging {
setConfig(config, prefix);
_messages = new ArrayList(4);
_running = false;
- if (createKey && ("server".equals(getType()) || "httpserver".equals(getType())) )
+ if (createKey && getType().endsWith("server"))
createPrivateKey();
_starting = getStartOnLoad();
}
@@ -148,6 +148,8 @@ public class TunnelController implements Logging {
startServer();
} else if ("httpserver".equals(type)) {
startHttpServer();
+ } else if ("ircserver".equals(type)) {
+ startIrcServer();
} else {
if (_log.shouldLog(Log.ERROR))
_log.error("Cannot start tunnel - unknown type [" + type + "]");
@@ -274,6 +276,17 @@ public class TunnelController implements Logging {
_running = true;
}
+ private void startIrcServer() {
+ setI2CPOptions();
+ setSessionOptions();
+ String targetHost = getTargetHost();
+ String targetPort = getTargetPort();
+ String privKeyFile = getPrivKeyFile();
+ _tunnel.runIrcServer(new String[] { targetHost, targetPort, privKeyFile }, this);
+ acquire();
+ _running = true;
+ }
+
private void setListenOn() {
String listenOn = getListenOnInterface();
if ( (listenOn != null) && (listenOn.length() > 0) ) {
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/IndexBean.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/IndexBean.java
index 46b5557729..87d8e26f69 100644
--- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/IndexBean.java
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/IndexBean.java
@@ -386,6 +386,7 @@ public class IndexBean {
else if ("httpserver".equals(internalType)) return "HTTP server";
else if ("sockstunnel".equals(internalType)) return "SOCKS 5 proxy";
else if ("connectclient".equals(internalType)) return "CONNECT/SSL/HTTPS proxy";
+ else if ("ircserver".equals(internalType)) return "IRC server";
else return internalType;
}
diff --git a/apps/i2ptunnel/jsp/edit.jsp b/apps/i2ptunnel/jsp/edit.jsp
index 67fdf016c3..b58798b202 100644
--- a/apps/i2ptunnel/jsp/edit.jsp
+++ b/apps/i2ptunnel/jsp/edit.jsp
@@ -16,10 +16,8 @@ String tun = request.getParameter("tunnel");
int curTunnel = -1;
if (EditBean.isClient(type)) {
%><%
- } else if ("server".equals(type) || "httpserver".equals(type)) {
- %><%
} else {
- %>Invalid tunnel type<%
+ %><%
}
}
%>
diff --git a/apps/i2ptunnel/jsp/index.jsp b/apps/i2ptunnel/jsp/index.jsp
index b96236ae14..77303267c9 100644
--- a/apps/i2ptunnel/jsp/index.jsp
+++ b/apps/i2ptunnel/jsp/index.jsp
@@ -260,6 +260,7 @@
From 3603cc23ee0725256a0321e6fba59c190c1e37fe Mon Sep 17 00:00:00 2001
From: zzz
Date: Sun, 22 Feb 2009 02:58:00 +0000
Subject: [PATCH 006/688] add socks 4/4a support
---
.../i2p/i2ptunnel/socks/SOCKS4aServer.java | 283 ++++++++++++++++++
.../i2ptunnel/socks/SOCKSServerFactory.java | 4 +
.../src/net/i2p/i2ptunnel/web/IndexBean.java | 2 +-
apps/i2ptunnel/jsp/index.jsp | 2 +-
4 files changed, 289 insertions(+), 2 deletions(-)
create mode 100644 apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/SOCKS4aServer.java
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/SOCKS4aServer.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/SOCKS4aServer.java
new file mode 100644
index 0000000000..2745cb0fa9
--- /dev/null
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/SOCKS4aServer.java
@@ -0,0 +1,283 @@
+/* I2PSOCKSTunnel is released under the terms of the GNU GPL,
+ * with an additional exception. For further details, see the
+ * licensing terms in I2PTunnel.java.
+ *
+ * Copyright (c) 2004 by human
+ */
+package net.i2p.i2ptunnel.socks;
+
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.Socket;
+import java.net.SocketException;
+import java.util.List;
+
+import net.i2p.I2PAppContext;
+import net.i2p.I2PException;
+import net.i2p.client.streaming.I2PSocket;
+import net.i2p.data.DataFormatException;
+import net.i2p.i2ptunnel.I2PTunnel;
+import net.i2p.util.HexDump;
+import net.i2p.util.Log;
+
+/*
+ * Class that manages SOCKS 4/4a connections, and forwards them to
+ * destination hosts or (eventually) some outproxy.
+ *
+ * @author zzz modded from SOCKS5Server
+ */
+public class SOCKS4aServer extends SOCKSServer {
+ private static final Log _log = new Log(SOCKS4aServer.class);
+
+ private Socket clientSock = null;
+ private boolean setupCompleted = false;
+
+ /**
+ * Create a SOCKS4a server that communicates with the client using
+ * the specified socket. This method should not be invoked
+ * directly: new SOCKS4aServer objects should be created by using
+ * SOCKSServerFactory.createSOCSKServer(). It is assumed that the
+ * SOCKS VER field has been stripped from the input stream of the
+ * client socket.
+ *
+ * @param clientSock client socket
+ */
+ public SOCKS4aServer(Socket clientSock) {
+ this.clientSock = clientSock;
+ }
+
+ public Socket getClientSocket() throws SOCKSException {
+ setupServer();
+
+ return clientSock;
+ }
+
+ protected void setupServer() throws SOCKSException {
+ if (setupCompleted) { return; }
+
+ DataInputStream in;
+ DataOutputStream out;
+ try {
+ in = new DataInputStream(clientSock.getInputStream());
+ out = new DataOutputStream(clientSock.getOutputStream());
+
+ manageRequest(in, out);
+ } catch (IOException e) {
+ throw new SOCKSException("Connection error (" + e.getMessage() + ")");
+ }
+
+ setupCompleted = true;
+ }
+
+ /**
+ * SOCKS4a request management. This method assumes that all the
+ * stuff preceding or enveloping the actual request
+ * has been stripped out of the input/output streams.
+ */
+ private void manageRequest(DataInputStream in, DataOutputStream out) throws IOException, SOCKSException {
+
+ int command = in.readByte() & 0xff;
+ switch (command) {
+ case Command.CONNECT:
+ break;
+ case Command.BIND:
+ _log.debug("BIND command is not supported!");
+ sendRequestReply(Reply.CONNECTION_REFUSED, InetAddress.getByName("127.0.0.1"), 0, out);
+ throw new SOCKSException("BIND command not supported");
+ default:
+ _log.debug("unknown command in request (" + Integer.toHexString(command) + ")");
+ sendRequestReply(Reply.CONNECTION_REFUSED, InetAddress.getByName("127.0.0.1"), 0, out);
+ throw new SOCKSException("Invalid command in request");
+ }
+
+ connPort = in.readUnsignedShort();
+ if (connPort == 0) {
+ _log.debug("trying to connect to TCP port 0? Dropping!");
+ sendRequestReply(Reply.CONNECTION_REFUSED, InetAddress.getByName("127.0.0.1"), 0, out);
+ throw new SOCKSException("Invalid port number in request");
+ }
+
+ connHostName = new String("");
+ boolean alreadyWarned = false;
+ for (int i = 0; i < 4; ++i) {
+ int octet = in.readByte() & 0xff;
+ connHostName += Integer.toString(octet);
+ if (i != 3) {
+ connHostName += ".";
+ if (octet != 0 && !alreadyWarned) {
+ _log.warn("IPV4 address type in request: " + connHostName + ". Is your client secure?");
+ alreadyWarned = true;
+ }
+ }
+ }
+
+ // discard user name
+ readString(in);
+
+ // SOCKS 4a
+ if (connHostName.startsWith("0.0.0.") && !connHostName.equals("0.0.0.0"))
+ connHostName = readString(in);
+ }
+
+ private String readString(DataInputStream in) throws IOException {
+ StringBuffer sb = new StringBuffer(16);
+ char c;
+ while ((c = (char) (in.readByte() & 0xff)) != 0)
+ sb.append(c);
+ return sb.toString();
+ }
+
+ protected void confirmConnection() throws SOCKSException {
+ DataInputStream in;
+ DataOutputStream out;
+ try {
+ out = new DataOutputStream(clientSock.getOutputStream());
+
+ sendRequestReply(Reply.SUCCEEDED, InetAddress.getByName("127.0.0.1"), 1, out);
+ } catch (IOException e) {
+ throw new SOCKSException("Connection error (" + e.getMessage() + ")");
+ }
+ }
+
+ /**
+ * Send the specified reply to a request of the client. Either
+ * one of inetAddr or domainName can be null, depending on
+ * addressType.
+ */
+ private void sendRequestReply(int replyCode, InetAddress inetAddr,
+ int bindPort, DataOutputStream out) throws IOException {
+ ByteArrayOutputStream reps = new ByteArrayOutputStream();
+ DataOutputStream dreps = new DataOutputStream(reps);
+
+ // Reserved byte, should be 0x00
+ dreps.write(0x00);
+ dreps.write(replyCode);
+ dreps.writeShort(bindPort);
+ dreps.write(inetAddr.getAddress());
+
+ byte[] reply = reps.toByteArray();
+
+ if (_log.shouldLog(Log.DEBUG)) {
+ _log.debug("Sending request reply:\n" + HexDump.dump(reply));
+ }
+
+ out.write(reply);
+ }
+
+ /**
+ * Get an I2PSocket that can be used to send/receive 8-bit clean data
+ * to/from the destination of the SOCKS connection.
+ *
+ * @return an I2PSocket connected with the destination
+ */
+ public I2PSocket getDestinationI2PSocket(I2PSOCKSTunnel t) throws SOCKSException {
+ setupServer();
+
+ if (connHostName == null) {
+ _log.error("BUG: destination host name has not been initialized!");
+ throw new SOCKSException("BUG! See the logs!");
+ }
+ if (connPort == 0) {
+ _log.error("BUG: destination port has not been initialized!");
+ throw new SOCKSException("BUG! See the logs!");
+ }
+
+ DataOutputStream out; // for errors
+ try {
+ out = new DataOutputStream(clientSock.getOutputStream());
+ } catch (IOException e) {
+ throw new SOCKSException("Connection error (" + e.getMessage() + ")");
+ }
+
+ // FIXME: here we should read our config file, select an
+ // outproxy, and instantiate the proper socket class that
+ // handles the outproxy itself (SOCKS4a, SOCKS4a, HTTP CONNECT...).
+ I2PSocket destSock;
+
+ try {
+ if (connHostName.toLowerCase().endsWith(".i2p")) {
+ _log.debug("connecting to " + connHostName + "...");
+ // Let's not due a new Dest for every request, huh?
+ //I2PSocketManager sm = I2PSocketManagerFactory.createManager();
+ //destSock = sm.connect(I2PTunnel.destFromName(connHostName), null);
+ destSock = t.createI2PSocket(I2PTunnel.destFromName(connHostName));
+ } else if ("localhost".equals(connHostName) || "127.0.0.1".equals(connHostName)) {
+ String err = "No localhost accesses allowed through the Socks Proxy";
+ _log.error(err);
+ try {
+ sendRequestReply(Reply.CONNECTION_REFUSED, InetAddress.getByName("127.0.0.1"), 0, out);
+ } catch (IOException ioe) {}
+ throw new SOCKSException(err);
+ } else if (connPort == 80) {
+ // rewrite GET line to include hostname??? or add Host: line???
+ // or forward to local eepProxy (but that's a Socket not an I2PSocket)
+ // use eepProxy configured outproxies?
+ String err = "No handler for HTTP outproxy implemented - to: " + connHostName;
+ _log.error(err);
+ try {
+ sendRequestReply(Reply.CONNECTION_REFUSED, InetAddress.getByName("127.0.0.1"), 0, out);
+ } catch (IOException ioe) {}
+ throw new SOCKSException(err);
+ } else {
+ List proxies = t.getProxies(connPort);
+ if (proxies == null || proxies.size() <= 0) {
+ String err = "No outproxy configured for port " + connPort + " and no default configured either";
+ _log.error(err);
+ try {
+ sendRequestReply(Reply.CONNECTION_REFUSED, InetAddress.getByName("127.0.0.1"), 0, out);
+ } catch (IOException ioe) {}
+ throw new SOCKSException(err);
+ }
+ int p = I2PAppContext.getGlobalContext().random().nextInt(proxies.size());
+ String proxy = proxies.get(p);
+ _log.debug("connecting to port " + connPort + " proxy " + proxy + " for " + connHostName + "...");
+ // this isn't going to work, these need to be socks outproxies so we need
+ // to do a socks session to them?
+ destSock = t.createI2PSocket(I2PTunnel.destFromName(proxy));
+ }
+ confirmConnection();
+ _log.debug("connection confirmed - exchanging data...");
+ } catch (DataFormatException e) {
+ try {
+ sendRequestReply(Reply.CONNECTION_REFUSED, InetAddress.getByName("127.0.0.1"), 0, out);
+ } catch (IOException ioe) {}
+ throw new SOCKSException("Error in destination format");
+ } catch (SocketException e) {
+ try {
+ sendRequestReply(Reply.CONNECTION_REFUSED, InetAddress.getByName("127.0.0.1"), 0, out);
+ } catch (IOException ioe) {}
+ throw new SOCKSException("Error connecting ("
+ + e.getMessage() + ")");
+ } catch (IOException e) {
+ try {
+ sendRequestReply(Reply.CONNECTION_REFUSED, InetAddress.getByName("127.0.0.1"), 0, out);
+ } catch (IOException ioe) {}
+ throw new SOCKSException("Error connecting ("
+ + e.getMessage() + ")");
+ } catch (I2PException e) {
+ try {
+ sendRequestReply(Reply.CONNECTION_REFUSED, InetAddress.getByName("127.0.0.1"), 0, out);
+ } catch (IOException ioe) {}
+ throw new SOCKSException("Error connecting ("
+ + e.getMessage() + ")");
+ }
+
+ return destSock;
+ }
+
+ /*
+ * Some namespaces to enclose SOCKS protocol codes
+ */
+ private static class Command {
+ private static final int CONNECT = 0x01;
+ private static final int BIND = 0x02;
+ }
+
+ private static class Reply {
+ private static final int SUCCEEDED = 0x5a;
+ private static final int CONNECTION_REFUSED = 0x5b;
+ }
+}
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/SOCKSServerFactory.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/SOCKSServerFactory.java
index 67a52d6889..80dfacb6a0 100644
--- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/SOCKSServerFactory.java
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/SOCKSServerFactory.java
@@ -44,6 +44,10 @@ public class SOCKSServerFactory {
int socksVer = in.readByte();
switch (socksVer) {
+ case 0x04:
+ // SOCKS version 4/4a
+ serv = new SOCKS4aServer(s);
+ break;
case 0x05:
// SOCKS version 5
serv = new SOCKS5Server(s);
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/IndexBean.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/IndexBean.java
index 87d8e26f69..045ea5e583 100644
--- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/IndexBean.java
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/IndexBean.java
@@ -384,7 +384,7 @@ public class IndexBean {
else if ("ircclient".equals(internalType)) return "IRC client";
else if ("server".equals(internalType)) return "Standard server";
else if ("httpserver".equals(internalType)) return "HTTP server";
- else if ("sockstunnel".equals(internalType)) return "SOCKS 5 proxy";
+ else if ("sockstunnel".equals(internalType)) return "SOCKS 4/4a/5 proxy";
else if ("connectclient".equals(internalType)) return "CONNECT/SSL/HTTPS proxy";
else if ("ircserver".equals(internalType)) return "IRC server";
else return internalType;
diff --git a/apps/i2ptunnel/jsp/index.jsp b/apps/i2ptunnel/jsp/index.jsp
index 77303267c9..7787eb1f52 100644
--- a/apps/i2ptunnel/jsp/index.jsp
+++ b/apps/i2ptunnel/jsp/index.jsp
@@ -148,7 +148,7 @@
-
+
From 8bce2fd7a2cf10d25114dcfc3752a7e4b8b8b29f Mon Sep 17 00:00:00 2001
From: sponge
Date: Sun, 22 Feb 2009 07:04:31 +0000
Subject: [PATCH 007/688] Hopeful BOB fixes for orphaned tunnels. Additional
comments in TCPio addressing performance.
---
apps/BOB/src/net/i2p/BOB/I2Plistener.java | 2 +-
apps/BOB/src/net/i2p/BOB/MUXlisten.java | 37 ++++++++++++++++++-----
apps/BOB/src/net/i2p/BOB/TCPio.java | 19 ++++++++++++
apps/BOB/src/net/i2p/BOB/TCPlistener.java | 2 +-
4 files changed, 51 insertions(+), 9 deletions(-)
diff --git a/apps/BOB/src/net/i2p/BOB/I2Plistener.java b/apps/BOB/src/net/i2p/BOB/I2Plistener.java
index 1561b7a222..c59683270e 100644
--- a/apps/BOB/src/net/i2p/BOB/I2Plistener.java
+++ b/apps/BOB/src/net/i2p/BOB/I2Plistener.java
@@ -70,7 +70,7 @@ public class I2Plistener implements Runnable {
boolean g = false;
I2PSocket sessSocket = null;
- serverSocket.setSoTimeout(100);
+ serverSocket.setSoTimeout(50);
database.getReadLock();
info.getReadLock();
if(info.exists("INPORT")) {
diff --git a/apps/BOB/src/net/i2p/BOB/MUXlisten.java b/apps/BOB/src/net/i2p/BOB/MUXlisten.java
index bd52e27fd2..89ab53fe62 100644
--- a/apps/BOB/src/net/i2p/BOB/MUXlisten.java
+++ b/apps/BOB/src/net/i2p/BOB/MUXlisten.java
@@ -173,7 +173,7 @@ die: {
boolean spin = true;
while(spin) {
try {
- Thread.sleep(1000); //sleep for 1000 ms (One second)
+ Thread.sleep(200); //sleep for 200 ms (Two thenths second)
} catch(InterruptedException e) {
// nop
}
@@ -213,14 +213,21 @@ die: {
}
} // die
+ try {
+ Thread.sleep(500); //sleep for 500 ms (One half second)
+ } catch(InterruptedException ex) {
+ // nop
+ }
// wait for child threads and thread groups to die
// System.out.println("MUXlisten: waiting for children");
- while(tg.activeCount() + tg.activeGroupCount() != 0) {
+ if(tg.activeCount() + tg.activeGroupCount() != 0) {
tg.interrupt(); // unwedge any blocking threads.
- try {
- Thread.sleep(100); //sleep for 100 ms (One tenth second)
- } catch(InterruptedException ex) {
- // nop
+ while(tg.activeCount() + tg.activeGroupCount() != 0) {
+ try {
+ Thread.sleep(100); //sleep for 100 ms (One tenth second)
+ } catch(InterruptedException ex) {
+ // nop
+ }
}
}
tg.destroy();
@@ -260,17 +267,33 @@ die: {
}
// This is here to catch when something fucks up REALLY bad.
if(tg != null) {
- while(tg.activeCount() + tg.activeGroupCount() != 0) {
+ if(tg.activeCount() + tg.activeGroupCount() != 0) {
tg.interrupt(); // unwedge any blocking threads.
+ while(tg.activeCount() + tg.activeGroupCount() != 0) {
try {
Thread.sleep(100); //sleep for 100 ms (One tenth second)
} catch(InterruptedException ex) {
// nop
}
+ }
}
tg.destroy();
// Zap reference to the ThreadGroup so the JVM can GC it.
tg = null;
}
+
+ // Lastly try to close things again.
+ if(this.come_in) {
+ try {
+ listener.close();
+ } catch(IOException e) {
+ }
+ }
+ try {
+ socketManager.destroySocketManager();
+ } catch(Exception e) {
+ // nop
+ }
+
}
}
diff --git a/apps/BOB/src/net/i2p/BOB/TCPio.java b/apps/BOB/src/net/i2p/BOB/TCPio.java
index 25290bcdcf..41bb7cbe49 100644
--- a/apps/BOB/src/net/i2p/BOB/TCPio.java
+++ b/apps/BOB/src/net/i2p/BOB/TCPio.java
@@ -56,9 +56,28 @@ public class TCPio implements Runnable {
* Copy from source to destination...
* and yes, we are totally OK to block here on writes,
* The OS has buffers, and I intend to use them.
+ * We send an interrupt signal to the threadgroup to
+ * unwedge any pending writes.
*
*/
public void run() {
+ /*
+ * NOTE:
+ * The write method of OutputStream calls the write method of
+ * one argument on each of the bytes to be written out.
+ * Subclasses are encouraged to override this method and provide
+ * a more efficient implementation.
+ *
+ * So, is this really a performance problem?
+ * Should we expand to several bytes?
+ * I don't believe there would be any gain, since read method
+ * has the same reccomendations. If anyone has a better way to
+ * do this, I'm interested in performance improvements.
+ *
+ * --Sponge
+ *
+ */
+
int b;
byte a[] = new byte[1];
boolean spin = true;
diff --git a/apps/BOB/src/net/i2p/BOB/TCPlistener.java b/apps/BOB/src/net/i2p/BOB/TCPlistener.java
index 99ae047d31..30380a55dd 100644
--- a/apps/BOB/src/net/i2p/BOB/TCPlistener.java
+++ b/apps/BOB/src/net/i2p/BOB/TCPlistener.java
@@ -77,7 +77,7 @@ public class TCPlistener implements Runnable {
}
try {
Socket server = new Socket();
- listener.setSoTimeout(1000);
+ listener.setSoTimeout(50); // Half of the expected time from MUXlisten
info.releaseReadLock();
database.releaseReadLock();
while(spin) {
From 532077a4c15b6bf4b2f634a7d695de0eb96e55d1 Mon Sep 17 00:00:00 2001
From: sponge
Date: Sun, 22 Feb 2009 07:26:08 +0000
Subject: [PATCH 008/688] BOB version bump. Router Build bump.
---
apps/BOB/src/net/i2p/BOB/DoCMDS.java | 2 +-
history.txt | 4 ++++
router/java/src/net/i2p/router/RouterVersion.java | 2 +-
3 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/apps/BOB/src/net/i2p/BOB/DoCMDS.java b/apps/BOB/src/net/i2p/BOB/DoCMDS.java
index 6033e303bf..099d69feca 100644
--- a/apps/BOB/src/net/i2p/BOB/DoCMDS.java
+++ b/apps/BOB/src/net/i2p/BOB/DoCMDS.java
@@ -46,7 +46,7 @@ public class DoCMDS implements Runnable {
// FIX ME
// I need a better way to do versioning, but this will do for now.
- public static final String BMAJ = "00", BMIN = "00", BREV = "03", BEXT = "";
+ public static final String BMAJ = "00", BMIN = "00", BREV = "04", BEXT = "";
public static final String BOBversion = BMAJ + "." + BMIN + "." + BREV + BEXT;
private Socket server;
private Properties props;
diff --git a/history.txt b/history.txt
index 62c4430e91..ec81d5a43a 100644
--- a/history.txt
+++ b/history.txt
@@ -1,3 +1,7 @@
+2009-02-22 sponge
+ * BOB: Orphan tunnel issue fix, bump BOB version
+ * bump to Build 6
+
2009-02-16 zzz
* Streaming lib: Plug timer leak, don't send keepalives
after close, don't disconnect hard after close
diff --git a/router/java/src/net/i2p/router/RouterVersion.java b/router/java/src/net/i2p/router/RouterVersion.java
index 5203f2360b..c089489691 100644
--- a/router/java/src/net/i2p/router/RouterVersion.java
+++ b/router/java/src/net/i2p/router/RouterVersion.java
@@ -17,7 +17,7 @@ import net.i2p.CoreVersion;
public class RouterVersion {
public final static String ID = "$Revision: 1.548 $ $Date: 2008-06-07 23:00:00 $";
public final static String VERSION = CoreVersion.VERSION;
- public final static long BUILD = 5;
+ public final static long BUILD = 6;
public static void main(String args[]) {
System.out.println("I2P Router version: " + VERSION + "-" + BUILD);
System.out.println("Router ID: " + RouterVersion.ID);
From 720aa704c4c5b8750e123045131f5ce8a00cdb97 Mon Sep 17 00:00:00 2001
From: zzz
Date: Mon, 23 Feb 2009 05:09:44 +0000
Subject: [PATCH 009/688] port streamr to i2ptunnel
---
LICENSE.txt | 4 +
.../java/src/net/i2p/i2ptunnel/I2PTunnel.java | 82 +++++++
.../net/i2p/i2ptunnel/I2PTunnelIRCServer.java | 9 -
.../net/i2p/i2ptunnel/TunnelController.java | 59 +++--
.../i2p/i2ptunnel/streamr/MultiSource.java | 60 +++++
.../src/net/i2p/i2ptunnel/streamr/Pinger.java | 59 +++++
.../i2ptunnel/streamr/StreamrConsumer.java | 64 +++++
.../i2ptunnel/streamr/StreamrProducer.java | 70 ++++++
.../net/i2p/i2ptunnel/streamr/Subscriber.java | 75 ++++++
.../src/net/i2p/i2ptunnel/udp/I2PSink.java | 70 ++++++
.../i2p/i2ptunnel/udp/I2PSinkAnywhere.java | 67 ++++++
.../src/net/i2p/i2ptunnel/udp/I2PSource.java | 123 ++++++++++
.../java/src/net/i2p/i2ptunnel/udp/Sink.java | 17 ++
.../src/net/i2p/i2ptunnel/udp/Source.java | 15 ++
.../src/net/i2p/i2ptunnel/udp/Stream.java | 15 ++
.../src/net/i2p/i2ptunnel/udp/UDPSink.java | 74 ++++++
.../src/net/i2p/i2ptunnel/udp/UDPSource.java | 83 +++++++
.../udpTunnel/I2PTunnelUDPClientBase.java | 218 ++++++++++++++++++
.../udpTunnel/I2PTunnelUDPServerBase.java | 212 +++++++++++++++++
.../src/net/i2p/i2ptunnel/web/IndexBean.java | 8 +-
apps/i2ptunnel/jsp/editClient.jsp | 30 ++-
apps/i2ptunnel/jsp/editServer.jsp | 8 +
apps/i2ptunnel/jsp/index.jsp | 2 +
23 files changed, 1375 insertions(+), 49 deletions(-)
create mode 100644 apps/i2ptunnel/java/src/net/i2p/i2ptunnel/streamr/MultiSource.java
create mode 100644 apps/i2ptunnel/java/src/net/i2p/i2ptunnel/streamr/Pinger.java
create mode 100644 apps/i2ptunnel/java/src/net/i2p/i2ptunnel/streamr/StreamrConsumer.java
create mode 100644 apps/i2ptunnel/java/src/net/i2p/i2ptunnel/streamr/StreamrProducer.java
create mode 100644 apps/i2ptunnel/java/src/net/i2p/i2ptunnel/streamr/Subscriber.java
create mode 100644 apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udp/I2PSink.java
create mode 100644 apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udp/I2PSinkAnywhere.java
create mode 100644 apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udp/I2PSource.java
create mode 100644 apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udp/Sink.java
create mode 100644 apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udp/Source.java
create mode 100644 apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udp/Stream.java
create mode 100644 apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udp/UDPSink.java
create mode 100644 apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udp/UDPSource.java
create mode 100644 apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udpTunnel/I2PTunnelUDPClientBase.java
create mode 100644 apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udpTunnel/I2PTunnelUDPServerBase.java
diff --git a/LICENSE.txt b/LICENSE.txt
index 324f532c61..e937985488 100644
--- a/LICENSE.txt
+++ b/LICENSE.txt
@@ -113,6 +113,10 @@ Applications:
See licenses/LICENSE-I2PTunnel.txt
See licenses/LICENSE-GPLv2.txt
+ I2PTunnel UDP and Streamr:
+ By welterde.
+ See licenses/LICENSE-GPLv2.txt
+
Jetty 5.1.12:
Copyright 2000-2004 Mort Bay Consulting Pty. Ltd.
See licenses/LICENSE-Apache1.1.txt
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnel.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnel.java
index 18b517cd2c..dc9dfd2fcc 100644
--- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnel.java
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnel.java
@@ -62,6 +62,8 @@ import net.i2p.data.DataFormatException;
import net.i2p.data.DataHelper;
import net.i2p.data.Destination;
import net.i2p.i2ptunnel.socks.I2PSOCKSTunnel;
+import net.i2p.i2ptunnel.streamr.StreamrConsumer;
+import net.i2p.i2ptunnel.streamr.StreamrProducer;
import net.i2p.util.EventDispatcher;
import net.i2p.util.EventDispatcherImpl;
import net.i2p.util.Log;
@@ -248,6 +250,10 @@ public class I2PTunnel implements Logging, EventDispatcher {
runSOCKSTunnel(args, l);
} else if ("connectclient".equals(cmdname)) {
runConnectClient(args, l);
+ } else if ("streamrclient".equals(cmdname)) {
+ runStreamrClient(args, l);
+ } else if ("streamrserver".equals(cmdname)) {
+ runStreamrServer(args, l);
} else if ("config".equals(cmdname)) {
runConfig(args, l);
} else if ("listen_on".equals(cmdname)) {
@@ -800,6 +806,82 @@ public class I2PTunnel implements Logging, EventDispatcher {
}
}
+ /**
+ * Streamr client
+ *
+ * @param args {targethost, targetport, destinationString}
+ * @param l logger to receive events and output
+ */
+ public void runStreamrClient(String args[], Logging l) {
+ if (args.length == 3) {
+ InetAddress host;
+ try {
+ host = InetAddress.getByName(args[0]);
+ } catch (UnknownHostException uhe) {
+ l.log("unknown host");
+ _log.error(getPrefix() + "Error resolving " + args[0], uhe);
+ notifyEvent("streamrtunnelTaskId", Integer.valueOf(-1));
+ return;
+ }
+
+ int port = -1;
+ try {
+ port = Integer.parseInt(args[1]);
+ } catch (NumberFormatException nfe) {
+ l.log("invalid port");
+ _log.error(getPrefix() + "Port specified is not valid: " + args[0], nfe);
+ notifyEvent("streamrtunnelTaskId", Integer.valueOf(-1));
+ return;
+ }
+
+ StreamrConsumer task = new StreamrConsumer(host, port, args[2], l, (EventDispatcher) this, this);
+ task.startRunning();
+ addtask(task);
+ notifyEvent("streamrtunnelTaskId", Integer.valueOf(task.getId()));
+ } else {
+ l.log("streamrclient ");
+ l.log(" creates a tunnel that receives streaming data.");
+ notifyEvent("streamrtunnelTaskId", Integer.valueOf(-1));
+ }
+ }
+
+ /**
+ * Streamr server
+ *
+ * @param args {port, privkeyfile}
+ * @param l logger to receive events and output
+ */
+ public void runStreamrServer(String args[], Logging l) {
+ if (args.length == 2) {
+ int port = -1;
+ try {
+ port = Integer.parseInt(args[0]);
+ } catch (NumberFormatException nfe) {
+ l.log("invalid port");
+ _log.error(getPrefix() + "Port specified is not valid: " + args[0], nfe);
+ notifyEvent("streamrtunnelTaskId", Integer.valueOf(-1));
+ return;
+ }
+
+ File privKeyFile = new File(args[1]);
+ if (!privKeyFile.canRead()) {
+ l.log("private key file does not exist");
+ _log.error(getPrefix() + "Private key file does not exist or is not readable: " + args[3]);
+ notifyEvent("serverTaskId", Integer.valueOf(-1));
+ return;
+ }
+
+ StreamrProducer task = new StreamrProducer(port, privKeyFile, args[1], l, (EventDispatcher) this, this);
+ task.startRunning();
+ addtask(task);
+ notifyEvent("streamrtunnelTaskId", Integer.valueOf(task.getId()));
+ } else {
+ l.log("streamrserver ");
+ l.log(" creates a tunnel that sends streaming data.");
+ notifyEvent("streamrtunnelTaskId", Integer.valueOf(-1));
+ }
+ }
+
/**
* Specify the i2cp host and port
*
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelIRCServer.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelIRCServer.java
index 970d90ff01..aa95e526c8 100644
--- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelIRCServer.java
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelIRCServer.java
@@ -61,21 +61,12 @@ public class I2PTunnelIRCServer extends I2PTunnelServer implements Runnable {
* @throws IllegalArgumentException if the I2PTunnel does not contain
* valid config to contact the router
*/
- public I2PTunnelIRCServer(InetAddress host, int port, String privData, Logging l, EventDispatcher notifyThis, I2PTunnel tunnel) {
- super(host, port, privData, l, notifyThis, tunnel);
- initCloak(tunnel);
- }
public I2PTunnelIRCServer(InetAddress host, int port, File privkey, String privkeyname, Logging l, EventDispatcher notifyThis, I2PTunnel tunnel) {
super(host, port, privkey, privkeyname, l, notifyThis, tunnel);
initCloak(tunnel);
}
- public I2PTunnelIRCServer(InetAddress host, int port, InputStream privData, String privkeyname, Logging l, EventDispatcher notifyThis, I2PTunnel tunnel) {
- super(host, port, privData, privkeyname, l, notifyThis, tunnel);
- initCloak(tunnel);
- }
-
/** generate a random 32 bytes, or the hash of the passphrase */
private void initCloak(I2PTunnel tunnel) {
Properties opts = tunnel.getClientOptions();
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelController.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelController.java
index 82b253985f..6c5fa4eb99 100644
--- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelController.java
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelController.java
@@ -134,6 +134,8 @@ public class TunnelController implements Logging {
_log.warn("Cannot start the tunnel - no type specified");
return;
}
+ setI2CPOptions();
+ setSessionOptions();
if ("httpclient".equals(type)) {
startHttpClient();
} else if("ircclient".equals(type)) {
@@ -144,21 +146,26 @@ public class TunnelController implements Logging {
startConnectClient();
} else if ("client".equals(type)) {
startClient();
+ } else if ("streamrclient".equals(type)) {
+ startStreamrClient();
} else if ("server".equals(type)) {
startServer();
} else if ("httpserver".equals(type)) {
startHttpServer();
} else if ("ircserver".equals(type)) {
startIrcServer();
+ } else if ("streamrserver".equals(type)) {
+ startStreamrServer();
} else {
if (_log.shouldLog(Log.ERROR))
_log.error("Cannot start tunnel - unknown type [" + type + "]");
+ return;
}
+ acquire();
+ _running = true;
}
private void startHttpClient() {
- setI2CPOptions();
- setSessionOptions();
setListenOn();
String listenPort = getListenPort();
String proxyList = getProxyList();
@@ -167,13 +174,9 @@ public class TunnelController implements Logging {
_tunnel.runHttpClient(new String[] { listenPort, sharedClient }, this);
else
_tunnel.runHttpClient(new String[] { listenPort, sharedClient, proxyList }, this);
- acquire();
- _running = true;
}
private void startConnectClient() {
- setI2CPOptions();
- setSessionOptions();
setListenOn();
String listenPort = getListenPort();
String proxyList = getProxyList();
@@ -182,31 +185,39 @@ public class TunnelController implements Logging {
_tunnel.runConnectClient(new String[] { listenPort, sharedClient }, this);
else
_tunnel.runConnectClient(new String[] { listenPort, sharedClient, proxyList }, this);
- acquire();
- _running = true;
}
private void startIrcClient() {
- setI2CPOptions();
- setSessionOptions();
setListenOn();
String listenPort = getListenPort();
String dest = getTargetDestination();
String sharedClient = getSharedClient();
_tunnel.runIrcClient(new String[] { listenPort, dest, sharedClient }, this);
- acquire();
- _running = true;
}
private void startSocksClient() {
- setI2CPOptions();
- setSessionOptions();
setListenOn();
String listenPort = getListenPort();
String sharedClient = getSharedClient();
_tunnel.runSOCKSTunnel(new String[] { listenPort, sharedClient }, this);
- acquire();
- _running = true;
+ }
+
+ /*
+ * Streamr client is a UDP server, use the listenPort field for targetPort
+ * and the listenOnInterface field for the targetHost
+ */
+ private void startStreamrClient() {
+ String targetHost = getListenOnInterface();
+ String targetPort = getListenPort();
+ String dest = getTargetDestination();
+ _tunnel.runStreamrClient(new String[] { targetHost, targetPort, dest }, this);
+ }
+
+ /** Streamr server is a UDP client, use the targetPort field for listenPort */
+ private void startStreamrServer() {
+ String listenPort = getTargetPort();
+ String privKeyFile = getPrivKeyFile();
+ _tunnel.runStreamrServer(new String[] { listenPort, privKeyFile }, this);
}
/**
@@ -242,49 +253,33 @@ public class TunnelController implements Logging {
}
private void startClient() {
- setI2CPOptions();
- setSessionOptions();
setListenOn();
String listenPort = getListenPort();
String dest = getTargetDestination();
String sharedClient = getSharedClient();
_tunnel.runClient(new String[] { listenPort, dest, sharedClient }, this);
- acquire();
- _running = true;
}
private void startServer() {
- setI2CPOptions();
- setSessionOptions();
String targetHost = getTargetHost();
String targetPort = getTargetPort();
String privKeyFile = getPrivKeyFile();
_tunnel.runServer(new String[] { targetHost, targetPort, privKeyFile }, this);
- acquire();
- _running = true;
}
private void startHttpServer() {
- setI2CPOptions();
- setSessionOptions();
String targetHost = getTargetHost();
String targetPort = getTargetPort();
String spoofedHost = getSpoofedHost();
String privKeyFile = getPrivKeyFile();
_tunnel.runHttpServer(new String[] { targetHost, targetPort, spoofedHost, privKeyFile }, this);
- acquire();
- _running = true;
}
private void startIrcServer() {
- setI2CPOptions();
- setSessionOptions();
String targetHost = getTargetHost();
String targetPort = getTargetPort();
String privKeyFile = getPrivKeyFile();
_tunnel.runIrcServer(new String[] { targetHost, targetPort, privKeyFile }, this);
- acquire();
- _running = true;
}
private void setListenOn() {
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/streamr/MultiSource.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/streamr/MultiSource.java
new file mode 100644
index 0000000000..13d9b55202
--- /dev/null
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/streamr/MultiSource.java
@@ -0,0 +1,60 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package net.i2p.i2ptunnel.streamr;
+
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.List;
+
+import net.i2p.data.Destination;
+import net.i2p.i2ptunnel.udp.*;
+
+/**
+ * Sends to many Sinks
+ * @author welterde
+ * @author zzz modded for I2PTunnel
+ */
+public class MultiSource implements Source, Sink {
+ public MultiSource() {
+ this.sinks = new CopyOnWriteArrayList();
+ }
+
+ public void setSink(Sink sink) {
+ this.sink = sink;
+ }
+
+ public void start() {}
+
+ public void send(Destination ignored_from, byte[] data) {
+ for(Destination dest : this.sinks) {
+ this.sink.send(dest, data);
+ }
+ }
+
+ public void add(Destination sink) {
+ this.sinks.add(sink);
+ }
+
+ public void remove(Destination sink) {
+ this.sinks.remove(sink);
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ private Sink sink;
+ private List sinks;
+}
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/streamr/Pinger.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/streamr/Pinger.java
new file mode 100644
index 0000000000..a3a7975361
--- /dev/null
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/streamr/Pinger.java
@@ -0,0 +1,59 @@
+package net.i2p.i2ptunnel.streamr;
+
+import net.i2p.i2ptunnel.udp.*;
+
+/**
+ *
+ * @author welterde/zzz
+ */
+public class Pinger implements Source, Runnable {
+ public Pinger() {
+ this.thread = new Thread(this);
+ }
+ public void setSink(Sink sink) {
+ this.sink = sink;
+ }
+
+ public void start() {
+ this.running = true;
+ this.waitlock = new Object();
+ this.thread.start();
+ }
+
+ public void stop() {
+ this.running = false;
+ synchronized(this.waitlock) {
+ this.waitlock.notifyAll();
+ }
+ // send unsubscribe-message
+ byte[] data = new byte[1];
+ data[0] = 1;
+ this.sink.send(null, data);
+ }
+
+ public void run() {
+ // send subscribe-message
+ byte[] data = new byte[1];
+ data[0] = 0;
+ int i = 0;
+ while(this.running) {
+ //System.out.print("p");
+ this.sink.send(null, data);
+ synchronized(this.waitlock) {
+ int delay = 10000;
+ if (i < 5) {
+ i++;
+ delay = 2000;
+ }
+ try {
+ this.waitlock.wait(delay);
+ } catch(InterruptedException ie) {}
+ }
+ }
+ }
+
+ protected Sink sink;
+ protected Thread thread;
+ protected Object waitlock;
+ protected boolean running;
+}
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/streamr/StreamrConsumer.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/streamr/StreamrConsumer.java
new file mode 100644
index 0000000000..3fc1d881b9
--- /dev/null
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/streamr/StreamrConsumer.java
@@ -0,0 +1,64 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package net.i2p.i2ptunnel.streamr;
+
+import java.net.InetAddress;
+
+import net.i2p.data.Destination;
+import net.i2p.i2ptunnel.I2PTunnel;
+import net.i2p.i2ptunnel.Logging;
+import net.i2p.i2ptunnel.udp.*;
+import net.i2p.i2ptunnel.udpTunnel.I2PTunnelUDPClientBase;
+import net.i2p.util.EventDispatcher;
+
+/**
+ * Compared to a standard I2PTunnel,
+ * this acts like a client on the I2P side (no privkey file)
+ * but a server on the UDP side (sends to a configured host/port)
+ *
+ * @author welterde
+ * @author zzz modded for I2PTunnel
+ */
+public class StreamrConsumer extends I2PTunnelUDPClientBase {
+
+ public StreamrConsumer(InetAddress host, int port, String destination,
+ Logging l, EventDispatcher notifyThis,
+ I2PTunnel tunnel) {
+ super(destination, l, notifyThis, tunnel);
+
+ // create udp-destination
+ this.sink = new UDPSink(host, port);
+ setSink(this.sink);
+
+ // create pinger
+ this.pinger = new Pinger();
+ this.pinger.setSink(this);
+ }
+
+ public final void startRunning() {
+ super.startRunning();
+ // send subscribe-message
+ this.pinger.start();
+ }
+
+ public boolean close(boolean forced) {
+ // send unsubscribe-message
+ this.pinger.stop();
+ return super.close(forced);
+ }
+
+
+
+
+
+
+
+
+
+
+ private Sink sink;
+ private Pinger pinger;
+}
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/streamr/StreamrProducer.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/streamr/StreamrProducer.java
new file mode 100644
index 0000000000..d722c5f95c
--- /dev/null
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/streamr/StreamrProducer.java
@@ -0,0 +1,70 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package net.i2p.i2ptunnel.streamr;
+
+// system
+import java.io.File;
+
+// i2p
+import net.i2p.client.I2PSession;
+import net.i2p.i2ptunnel.I2PTunnel;
+import net.i2p.i2ptunnel.Logging;
+import net.i2p.i2ptunnel.udp.*;
+import net.i2p.i2ptunnel.udpTunnel.I2PTunnelUDPServerBase;
+import net.i2p.util.EventDispatcher;
+
+/**
+ * Compared to a standard I2PTunnel,
+ * this acts like a server on the I2P side (persistent privkey file)
+ * but a client on the UDP side (receives on a configured port)
+ *
+ * @author welterde
+ * @author zzz modded for I2PTunnel
+ */
+public class StreamrProducer extends I2PTunnelUDPServerBase {
+
+ public StreamrProducer(int port,
+ File privkey, String privkeyname, Logging l,
+ EventDispatcher notifyThis, I2PTunnel tunnel) {
+ // verify subscription requests
+ super(true, privkey, privkeyname, l, notifyThis, tunnel);
+
+ // The broadcaster
+ this.multi = new MultiSource();
+ this.multi.setSink(this);
+
+ // The listener
+ this.subscriber = new Subscriber(this.multi);
+ setSink(this.subscriber);
+
+ // now start udp-server
+ this.server = new UDPSource(port);
+ this.server.setSink(this.multi);
+ }
+
+ public final void startRunning() {
+ super.startRunning();
+ this.server.start();
+ }
+
+ public boolean close(boolean forced) {
+ // need some stop() methods in UDPSource and MultiSource
+ return super.close(forced);
+ }
+
+
+
+
+
+
+
+
+
+
+ private MultiSource multi;
+ private Source server;
+ private Sink subscriber;
+}
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/streamr/Subscriber.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/streamr/Subscriber.java
new file mode 100644
index 0000000000..97abdb8890
--- /dev/null
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/streamr/Subscriber.java
@@ -0,0 +1,75 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package net.i2p.i2ptunnel.streamr;
+
+// system
+import java.io.File;
+import java.util.Set;
+
+// i2p
+import net.i2p.client.I2PSession;
+import net.i2p.data.Destination;
+import net.i2p.i2ptunnel.I2PTunnel;
+import net.i2p.i2ptunnel.Logging;
+import net.i2p.i2ptunnel.udp.*;
+import net.i2p.i2ptunnel.udpTunnel.I2PTunnelUDPServerBase;
+import net.i2p.util.EventDispatcher;
+import net.i2p.util.ConcurrentHashSet;
+
+/**
+ * server-mode
+ * @author welterde
+ * @author zzz modded from Producer for I2PTunnel
+ */
+public class Subscriber implements Sink {
+
+ public Subscriber(MultiSource multi) {
+ this.multi = multi;
+ // subscriptions
+ this.subscriptions = new ConcurrentHashSet();
+ }
+
+ public void send(Destination dest, byte[] data) {
+ if(dest == null || data.length < 1) {
+ // invalid packet
+ // TODO: write to log
+ } else {
+ byte ctrl = data[0];
+ if(ctrl == 0) {
+ if (!this.subscriptions.contains(dest)) {
+ // subscribe
+ System.out.println("Add subscription: " + dest.toBase64().substring(0,4));
+ this.subscriptions.add(dest);
+ this.multi.add(dest);
+ } // else already subscribed
+ } else if(ctrl == 1) {
+ // unsubscribe
+ System.out.println("Remove subscription: " + dest.toBase64().substring(0,4));
+ boolean removed = this.subscriptions.remove(dest);
+ if(removed)
+ multi.remove(dest);
+ } else {
+ // invalid packet
+ // TODO: write to log
+ }
+ }
+ }
+
+
+
+
+
+
+
+
+
+
+ private I2PSession sess;
+ private Source listener;
+ private Set subscriptions;
+ private MultiSource multi;
+ private Source server;
+}
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udp/I2PSink.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udp/I2PSink.java
new file mode 100644
index 0000000000..3cbccf139e
--- /dev/null
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udp/I2PSink.java
@@ -0,0 +1,70 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package net.i2p.i2ptunnel.udp;
+
+// i2p
+import net.i2p.client.I2PSession;
+import net.i2p.client.I2PSessionException;
+import net.i2p.data.Destination;
+import net.i2p.client.datagram.I2PDatagramMaker;
+
+/**
+ * Producer
+ *
+ * This sends to a fixed destination specified in the constructor
+ *
+ * @author welterde
+ */
+public class I2PSink implements Sink {
+ public I2PSink(I2PSession sess, Destination dest) {
+ this(sess, dest, false);
+ }
+ public I2PSink(I2PSession sess, Destination dest, boolean raw) {
+ this.sess = sess;
+ this.dest = dest;
+ this.raw = raw;
+
+ // create maker
+ if (!raw)
+ this.maker = new I2PDatagramMaker(this.sess);
+ }
+
+ /** @param src ignored */
+ public synchronized void send(Destination src, byte[] data) {
+ //System.out.print("w");
+ // create payload
+ byte[] payload;
+ if(!this.raw)
+ payload = this.maker.makeI2PDatagram(data);
+ else
+ payload = data;
+
+ // send message
+ try {
+ this.sess.sendMessage(this.dest, payload);
+ } catch(I2PSessionException exc) {
+ // TODO: handle better
+ exc.printStackTrace();
+ }
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+ protected boolean raw;
+ protected I2PSession sess;
+ protected Destination dest;
+ protected I2PDatagramMaker maker;
+}
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udp/I2PSinkAnywhere.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udp/I2PSinkAnywhere.java
new file mode 100644
index 0000000000..09385d46fe
--- /dev/null
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udp/I2PSinkAnywhere.java
@@ -0,0 +1,67 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package net.i2p.i2ptunnel.udp;
+
+// i2p
+import net.i2p.client.I2PSession;
+import net.i2p.client.I2PSessionException;
+import net.i2p.data.Destination;
+import net.i2p.client.datagram.I2PDatagramMaker;
+
+/**
+ * Producer
+ *
+ * This sends to any destination specified in send()
+ *
+ * @author zzz modded from I2PSink by welterde
+ */
+public class I2PSinkAnywhere implements Sink {
+ public I2PSinkAnywhere(I2PSession sess) {
+ this(sess, false);
+ }
+ public I2PSinkAnywhere(I2PSession sess, boolean raw) {
+ this.sess = sess;
+ this.raw = raw;
+
+ // create maker
+ this.maker = new I2PDatagramMaker(this.sess);
+ }
+
+ /** @param to - where it's going */
+ public synchronized void send(Destination to, byte[] data) {
+ // create payload
+ byte[] payload;
+ if(!this.raw)
+ payload = this.maker.makeI2PDatagram(data);
+ else
+ payload = data;
+
+ // send message
+ try {
+ this.sess.sendMessage(to, payload);
+ } catch(I2PSessionException exc) {
+ // TODO: handle better
+ exc.printStackTrace();
+ }
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+ protected boolean raw;
+ protected I2PSession sess;
+ protected Destination dest;
+ protected I2PDatagramMaker maker;
+}
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udp/I2PSource.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udp/I2PSource.java
new file mode 100644
index 0000000000..0b54747772
--- /dev/null
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udp/I2PSource.java
@@ -0,0 +1,123 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package net.i2p.i2ptunnel.udp;
+
+// system
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.BlockingQueue;
+
+// i2p
+import net.i2p.client.I2PSession;
+import net.i2p.client.I2PSessionListener;
+import net.i2p.client.datagram.I2PDatagramDissector;
+
+/**
+ *
+ * @author welterde
+ */
+public class I2PSource implements Source, Runnable {
+ public I2PSource(I2PSession sess) {
+ this(sess, true, false);
+ }
+ public I2PSource(I2PSession sess, boolean verify) {
+ this(sess, verify, false);
+ }
+ public I2PSource(I2PSession sess, boolean verify, boolean raw) {
+ this.sess = sess;
+ this.sink = null;
+ this.verify = verify;
+ this.raw = raw;
+
+ // create queue
+ this.queue = new ArrayBlockingQueue(256);
+
+ // create listener
+ this.sess.setSessionListener(new Listener());
+
+ // create thread
+ this.thread = new Thread(this);
+ }
+
+ public void setSink(Sink sink) {
+ this.sink = sink;
+ }
+
+ public void start() {
+ this.thread.start();
+ }
+
+ public void run() {
+ // create dissector
+ I2PDatagramDissector diss = new I2PDatagramDissector();
+ while(true) {
+ try {
+ // get id
+ int id = this.queue.take();
+
+ // receive message
+ byte[] msg = this.sess.receiveMessage(id);
+
+ if(!this.raw) {
+ // load datagram into it
+ diss.loadI2PDatagram(msg);
+
+ // now call sink
+ if(this.verify)
+ this.sink.send(diss.getSender(), diss.getPayload());
+ else
+ this.sink.send(diss.extractSender(), diss.extractPayload());
+ } else {
+ // verify is ignored
+ this.sink.send(null, msg);
+ }
+ //System.out.print("r");
+ } catch(Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+
+
+
+
+
+ protected class Listener implements I2PSessionListener {
+
+ public void messageAvailable(I2PSession sess, int id, long size) {
+ try {
+ queue.put(id);
+ } catch(Exception e) {
+ // ignore
+ }
+ }
+
+ public void reportAbuse(I2PSession arg0, int arg1) {
+ // ignore
+ }
+
+ public void disconnected(I2PSession arg0) {
+ // ignore
+ }
+
+ public void errorOccurred(I2PSession arg0, String arg1, Throwable arg2) {
+ // ignore
+ }
+
+ }
+
+
+
+
+
+
+ protected I2PSession sess;
+ protected BlockingQueue queue;
+ protected Sink sink;
+ protected Thread thread;
+ protected boolean verify;
+ protected boolean raw;
+}
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udp/Sink.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udp/Sink.java
new file mode 100644
index 0000000000..49e3e47a3e
--- /dev/null
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udp/Sink.java
@@ -0,0 +1,17 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package net.i2p.i2ptunnel.udp;
+
+// i2p
+import net.i2p.data.Destination;
+
+/**
+ *
+ * @author welterde
+ */
+public interface Sink {
+ public void send(Destination src, byte[] data);
+}
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udp/Source.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udp/Source.java
new file mode 100644
index 0000000000..f65d03b196
--- /dev/null
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udp/Source.java
@@ -0,0 +1,15 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package net.i2p.i2ptunnel.udp;
+
+/**
+ *
+ * @author welterde
+ */
+public interface Source {
+ public void setSink(Sink sink);
+ public void start();
+}
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udp/Stream.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udp/Stream.java
new file mode 100644
index 0000000000..b8b57e696c
--- /dev/null
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udp/Stream.java
@@ -0,0 +1,15 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package net.i2p.i2ptunnel.udp;
+
+/**
+ *
+ * @author welterde
+ */
+public interface Stream {
+ public void start();
+ public void stop();
+}
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udp/UDPSink.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udp/UDPSink.java
new file mode 100644
index 0000000000..15feba6156
--- /dev/null
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udp/UDPSink.java
@@ -0,0 +1,74 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package net.i2p.i2ptunnel.udp;
+
+// system
+import java.net.DatagramSocket;
+import java.net.DatagramPacket;
+import java.net.InetAddress;
+
+// i2p
+import net.i2p.data.Destination;
+
+/**
+ *
+ * @author welterde
+ */
+public class UDPSink implements Sink {
+ public UDPSink(InetAddress host, int port) {
+ // create socket
+ try {
+ this.sock = new DatagramSocket();
+ } catch(Exception e) {
+ // TODO: fail better
+ throw new RuntimeException("failed to open udp-socket", e);
+ }
+
+ this.remoteHost = host;
+
+ // remote port
+ this.remotePort = port;
+ }
+
+ public void send(Destination src, byte[] data) {
+ // create packet
+ DatagramPacket packet = new DatagramPacket(data, data.length, this.remoteHost, this.remotePort);
+
+ // send packet
+ try {
+ this.sock.send(packet);
+ } catch(Exception e) {
+ // TODO: fail a bit better
+ e.printStackTrace();
+ }
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ protected DatagramSocket sock;
+ protected InetAddress remoteHost;
+ protected int remotePort;
+
+}
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udp/UDPSource.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udp/UDPSource.java
new file mode 100644
index 0000000000..c54a984b0a
--- /dev/null
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udp/UDPSource.java
@@ -0,0 +1,83 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package net.i2p.i2ptunnel.udp;
+
+// system
+import java.net.DatagramSocket;
+import java.net.DatagramPacket;
+
+/**
+ *
+ * @author welterde
+ */
+public class UDPSource implements Source, Runnable {
+ public static final int MAX_SIZE = 15360;
+ public UDPSource(int port) {
+ this.sink = null;
+
+ // create udp-socket
+ try {
+ this.sock = new DatagramSocket(port);
+ } catch(Exception e) {
+ throw new RuntimeException("failed to listen...", e);
+ }
+
+ // create thread
+ this.thread = new Thread(this);
+ }
+
+ public void setSink(Sink sink) {
+ this.sink = sink;
+ }
+
+ public void start() {
+ this.thread.start();
+ }
+
+ public void run() {
+ // create packet
+ byte[] buf = new byte[MAX_SIZE];
+ DatagramPacket pack = new DatagramPacket(buf, buf.length);
+ while(true) {
+ try {
+ // receive...
+ this.sock.receive(pack);
+
+ // create new data array
+ byte[] nbuf = new byte[pack.getLength()];
+
+ // copy over
+ System.arraycopy(pack.getData(), 0, nbuf, 0, nbuf.length);
+
+ // transfer to sink
+ this.sink.send(null, nbuf);
+ //System.out.print("i");
+ } catch(Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ protected DatagramSocket sock;
+ protected Sink sink;
+ protected Thread thread;
+}
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udpTunnel/I2PTunnelUDPClientBase.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udpTunnel/I2PTunnelUDPClientBase.java
new file mode 100644
index 0000000000..0123be6eab
--- /dev/null
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udpTunnel/I2PTunnelUDPClientBase.java
@@ -0,0 +1,218 @@
+/* I2PTunnel is GPL'ed (with the exception mentioned in I2PTunnel.java)
+ * (c) 2003 - 2004 mihi
+ */
+package net.i2p.i2ptunnel.udpTunnel;
+
+import java.io.ByteArrayOutputStream;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InterruptedIOException;
+import java.net.ConnectException;
+import java.net.InetAddress;
+import java.net.NoRouteToHostException;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Properties;
+
+import net.i2p.I2PAppContext;
+import net.i2p.I2PException;
+import net.i2p.client.I2PClient;
+import net.i2p.client.I2PClientFactory;
+import net.i2p.client.I2PSession;
+import net.i2p.client.I2PSessionException;
+import net.i2p.data.DataFormatException;
+import net.i2p.data.Destination;
+import net.i2p.i2ptunnel.I2PTunnel;
+import net.i2p.i2ptunnel.I2PTunnelTask;
+import net.i2p.i2ptunnel.Logging;
+import net.i2p.i2ptunnel.udp.*;
+import net.i2p.util.EventDispatcher;
+import net.i2p.util.I2PThread;
+import net.i2p.util.Log;
+
+public abstract class I2PTunnelUDPClientBase extends I2PTunnelTask implements Source, Sink {
+
+ private static final Log _log = new Log(I2PTunnelUDPClientBase.class);
+ protected I2PAppContext _context;
+ protected Logging l;
+
+ static final long DEFAULT_CONNECT_TIMEOUT = 60 * 1000;
+
+ private static volatile long __clientId = 0;
+ protected long _clientId;
+
+ protected Destination dest = null;
+
+ private boolean listenerReady = false;
+
+ private ServerSocket ss;
+
+ private Object startLock = new Object();
+ private boolean startRunning = false;
+
+ private byte[] pubkey;
+
+ private String handlerName;
+
+ private Object conLock = new Object();
+
+ /** How many connections will we allow to be in the process of being built at once? */
+ private int _numConnectionBuilders;
+ /** How long will we allow sockets to sit in the _waitingSockets map before killing them? */
+ private int _maxWaitTime;
+
+ private I2PSession _session;
+ private Source _i2pSource;
+ private Sink _i2pSink;
+ private Destination _otherDest;
+
+ /**
+ * Base client class that sets up an I2P Datagram client destination.
+ * The UDP side is not implemented here, as there are at least
+ * two possibilities:
+ *
+ * 1) UDP side is a "server"
+ * Example: Streamr Consumer
+ * - Configure a destination host and port
+ * - External application sends no data
+ * - Extending class must have a constructor with host and port arguments
+ *
+ * 2) UDP side is a client/server
+ * Example: SOCKS UDP (DNS requests?)
+ * - configure an inbound port and a destination host and port
+ * - External application sends and receives data
+ * - Extending class must have a constructor with host and 2 port arguments
+ *
+ * So the implementing class must create a UDPSource and/or UDPSink,
+ * and must call setSink().
+ *
+ * @throws IllegalArgumentException if the I2CP configuration is b0rked so
+ * badly that we cant create a socketManager
+ *
+ * @author zzz with portions from welterde's streamr
+ */
+ public I2PTunnelUDPClientBase(String destination, Logging l, EventDispatcher notifyThis,
+ I2PTunnel tunnel) throws IllegalArgumentException {
+ super("UDPServer", notifyThis, tunnel);
+ _clientId = ++__clientId;
+ this.l = l;
+
+ _context = tunnel.getContext();
+
+ tunnel.getClientOptions().setProperty("i2cp.dontPublishLeaseSet", "true");
+
+ // create i2pclient and destination
+ I2PClient client = I2PClientFactory.createClient();
+ Destination dest;
+ byte[] key;
+ try {
+ ByteArrayOutputStream out = new ByteArrayOutputStream(512);
+ dest = client.createDestination(out);
+ key = out.toByteArray();
+ } catch(Exception exc) {
+ throw new RuntimeException("failed to create i2p-destination", exc);
+ }
+
+ // create a session
+ try {
+ ByteArrayInputStream in = new ByteArrayInputStream(key);
+ _session = client.createSession(in, tunnel.getClientOptions());
+ } catch(Exception exc) {
+ throw new RuntimeException("failed to create session", exc);
+ }
+
+ // Setup the source. Always expect raw unverified datagrams.
+ _i2pSource = new I2PSource(_session, false, true);
+
+ // Setup the sink. Always send repliable datagrams.
+ if (destination != null && destination.length() > 0) {
+ try {
+ _otherDest = I2PTunnel.destFromName(destination);
+ } catch (DataFormatException dfe) {}
+ if (_otherDest == null) {
+ l.log("Could not resolve " + destination);
+ throw new RuntimeException("failed to create session - could not resolve " + destination);
+ }
+ _i2pSink = new I2PSink(_session, _otherDest, false);
+ } else {
+ _i2pSink = new I2PSinkAnywhere(_session, false);
+ }
+
+ //configurePool(tunnel);
+
+ }
+
+ /**
+ * Actually start working on outgoing connections.
+ * Classes should override to start UDP side as well.
+ *
+ * Not specified in I2PTunnelTask but used in both
+ * I2PTunnelClientBase and I2PTunnelServer so let's
+ * implement it here too.
+ */
+ public void startRunning() {
+ synchronized (startLock) {
+ try {
+ _session.connect();
+ } catch(I2PSessionException exc) {
+ throw new RuntimeException("failed to connect session", exc);
+ }
+ start();
+ startRunning = true;
+ startLock.notify();
+ }
+
+ if (open && listenerReady) {
+ notifyEvent("openBaseClientResult", "ok");
+ } else {
+ l.log("Error listening - please see the logs!");
+ notifyEvent("openBaseClientResult", "error");
+ }
+ }
+
+ /**
+ * I2PTunnelTask Methods
+ *
+ * Classes should override to close UDP side as well
+ */
+ public boolean close(boolean forced) {
+ if (!open) return true;
+ if (_session != null) {
+ try {
+ _session.destroySession();
+ } catch (I2PSessionException ise) {}
+ }
+ l.log("Closing client " + toString());
+ return true;
+ }
+
+ /**
+ * Source Methods
+ *
+ * Sets the receiver of the UDP datagrams from I2P
+ * Subclass must call this after constructor
+ * and before start()
+ */
+ public void setSink(Sink s) {
+ _i2pSource.setSink(s);
+ }
+
+ /** start the source */
+ public void start() {
+ _i2pSource.start();
+ }
+
+ /**
+ * Sink Methods
+ *
+ * @param to - ignored if configured for a single destination
+ * (we use the dest specified in the constructor)
+ */
+ public void send(Destination to, byte[] data) {
+ _i2pSink.send(to, data);
+ }
+}
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udpTunnel/I2PTunnelUDPServerBase.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udpTunnel/I2PTunnelUDPServerBase.java
new file mode 100644
index 0000000000..fe129fb131
--- /dev/null
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udpTunnel/I2PTunnelUDPServerBase.java
@@ -0,0 +1,212 @@
+/* I2PTunnel is GPL'ed (with the exception mentioned in I2PTunnel.java)
+ * (c) 2003 - 2004 mihi
+ */
+package net.i2p.i2ptunnel.udpTunnel;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.ConnectException;
+import java.net.InetAddress;
+import java.net.Socket;
+import java.net.SocketException;
+import java.net.SocketTimeoutException;
+import java.util.Iterator;
+import java.util.Properties;
+
+import net.i2p.I2PAppContext;
+import net.i2p.I2PException;
+import net.i2p.client.I2PClient;
+import net.i2p.client.I2PClientFactory;
+import net.i2p.client.I2PSession;
+import net.i2p.client.I2PSessionException;
+import net.i2p.data.Base64;
+import net.i2p.data.Destination;
+import net.i2p.i2ptunnel.I2PTunnel;
+import net.i2p.i2ptunnel.I2PTunnelTask;
+import net.i2p.i2ptunnel.Logging;
+import net.i2p.i2ptunnel.udp.*;
+import net.i2p.util.EventDispatcher;
+import net.i2p.util.I2PThread;
+import net.i2p.util.Log;
+
+public class I2PTunnelUDPServerBase extends I2PTunnelTask implements Source, Sink {
+
+ private final static Log _log = new Log(I2PTunnelUDPServerBase.class);
+
+ private Object lock = new Object();
+ protected Object slock = new Object();
+
+ private static volatile long __serverId = 0;
+
+ private Logging l;
+
+ private static final long DEFAULT_READ_TIMEOUT = -1; // 3*60*1000;
+ /** default timeout to 3 minutes - override if desired */
+ protected long readTimeout = DEFAULT_READ_TIMEOUT;
+
+ private I2PSession _session;
+ private Source _i2pSource;
+ private Sink _i2pSink;
+
+ /**
+ * Base client class that sets up an I2P Datagram server destination.
+ * The UDP side is not implemented here, as there are at least
+ * two possibilities:
+ *
+ * 1) UDP side is a "client"
+ * Example: Streamr Producer
+ * - configure an inbound port
+ * - External application receives no data
+ * - Extending class must have a constructor with a port argument
+ *
+ * 2) UDP side is a client/server
+ * Example: DNS
+ * - configure an inbound port and a destination host and port
+ * - External application sends and receives data
+ * - Extending class must have a constructor with host and 2 port arguments
+ *
+ * So the implementing class must create a UDPSource and/or UDPSink,
+ * and must call setSink().
+ *
+ * @throws IllegalArgumentException if the I2CP configuration is b0rked so
+ * badly that we cant create a socketManager
+ *
+ * @author zzz with portions from welterde's streamr
+ */
+
+ public I2PTunnelUDPServerBase(boolean verify, File privkey, String privkeyname, Logging l,
+ EventDispatcher notifyThis, I2PTunnel tunnel) {
+ super("UDPServer <- " + privkeyname, notifyThis, tunnel);
+ FileInputStream fis = null;
+ try {
+ fis = new FileInputStream(privkey);
+ init(verify, fis, privkeyname, l);
+ } catch (IOException ioe) {
+ _log.error("Error starting server", ioe);
+ notifyEvent("openServerResult", "error");
+ } finally {
+ if (fis != null)
+ try { fis.close(); } catch (IOException ioe) {}
+ }
+ }
+
+ private void init(boolean verify, InputStream privData, String privkeyname, Logging l) {
+ this.l = l;
+ int portNum = 7654;
+ if (getTunnel().port != null) {
+ try {
+ portNum = Integer.parseInt(getTunnel().port);
+ } catch (NumberFormatException nfe) {
+ _log.log(Log.CRIT, "Invalid port specified [" + getTunnel().port + "], reverting to " + portNum);
+ }
+ }
+
+ // create i2pclient
+ I2PClient client = I2PClientFactory.createClient();
+
+ try {
+ _session = client.createSession(privData, getTunnel().getClientOptions());
+ } catch(I2PSessionException exc) {
+ throw new RuntimeException("failed to create session", exc);
+ }
+
+ // Setup the source. Always expect repliable datagrams, optionally verify
+ _i2pSource = new I2PSource(_session, verify, false);
+
+ // Setup the sink. Always send raw datagrams.
+ _i2pSink = new I2PSinkAnywhere(_session, true);
+ }
+
+ /**
+ * Classes should override to start UDP side as well.
+ *
+ * Not specified in I2PTunnelTask but used in both
+ * I2PTunnelClientBase and I2PTunnelServer so let's
+ * implement it here too.
+ */
+ public void startRunning() {
+ //synchronized (startLock) {
+ try {
+ _session.connect();
+ } catch(I2PSessionException exc) {
+ throw new RuntimeException("failed to connect session", exc);
+ }
+ start();
+ //}
+
+ l.log("Ready!");
+ notifyEvent("openServerResult", "ok");
+ open = true;
+ }
+
+ /**
+ * Set the read idle timeout for newly-created connections (in
+ * milliseconds). After this time expires without data being reached from
+ * the I2P network, the connection itself will be closed.
+ */
+ public void setReadTimeout(long ms) {
+ readTimeout = ms;
+ }
+
+ /**
+ * Get the read idle timeout for newly-created connections (in
+ * milliseconds).
+ *
+ * @return The read timeout used for connections
+ */
+ public long getReadTimeout() {
+ return readTimeout;
+ }
+
+ /**
+ * I2PTunnelTask Methods
+ *
+ * Classes should override to close UDP side as well
+ */
+ public boolean close(boolean forced) {
+ if (!open) return true;
+ synchronized (lock) {
+ l.log("Shutting down server " + toString());
+ try {
+ if (_session != null) {
+ _session.destroySession();
+ }
+ } catch (I2PException ex) {
+ _log.error("Error destroying the session", ex);
+ }
+ l.log("Server shut down.");
+ open = false;
+ return true;
+ }
+ }
+
+ /**
+ * Source Methods
+ *
+ * Sets the receiver of the UDP datagrams from I2P
+ * Subclass must call this after constructor
+ * and before start()
+ */
+ public void setSink(Sink s) {
+ _i2pSource.setSink(s);
+ }
+
+ /** start the source */
+ public void start() {
+ _i2pSource.start();
+ }
+
+ /**
+ * Sink Methods
+ *
+ * @param to
+ *
+ */
+ public void send(Destination to, byte[] data) {
+ _i2pSink.send(to, data);
+ }
+}
+
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/IndexBean.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/IndexBean.java
index 045ea5e583..6fcd9f2fe3 100644
--- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/IndexBean.java
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/IndexBean.java
@@ -351,6 +351,7 @@ public class IndexBean {
("httpclient".equals(type)) ||
("sockstunnel".equals(type)) ||
("connectclient".equals(type)) ||
+ ("streamrclient".equals(type)) ||
("ircclient".equals(type)));
}
@@ -387,6 +388,8 @@ public class IndexBean {
else if ("sockstunnel".equals(internalType)) return "SOCKS 4/4a/5 proxy";
else if ("connectclient".equals(internalType)) return "CONNECT/SSL/HTTPS proxy";
else if ("ircserver".equals(internalType)) return "IRC server";
+ else if ("streamrclient".equals(internalType)) return "Streamr client";
+ else if ("streamrserver".equals(internalType)) return "Streamr server";
else return internalType;
}
@@ -434,7 +437,8 @@ public class IndexBean {
TunnelController tun = getController(tunnel);
if (tun == null) return "";
String rv;
- if ("client".equals(tun.getType())||"ircclient".equals(tun.getType()))
+ if ("client".equals(tun.getType()) || "ircclient".equals(tun.getType()) ||
+ "streamrclient".equals(tun.getType()))
rv = tun.getTargetDestination();
else
rv = tun.getProxyList();
@@ -798,7 +802,7 @@ public class IndexBean {
if ("httpclient".equals(_type) || "connectclient".equals(_type)) {
if (_proxyList != null)
config.setProperty("proxyList", _proxyList);
- } else if ("ircclient".equals(_type) || "client".equals(_type)) {
+ } else if ("ircclient".equals(_type) || "client".equals(_type) || "streamrclient".equals(_type)) {
if (_targetDestination != null)
config.setProperty("targetDestination", _targetDestination);
} else if ("httpserver".equals(_type)) {
diff --git a/apps/i2ptunnel/jsp/editClient.jsp b/apps/i2ptunnel/jsp/editClient.jsp
index 3e4c3ecd80..6a796eb7df 100644
--- a/apps/i2ptunnel/jsp/editClient.jsp
+++ b/apps/i2ptunnel/jsp/editClient.jsp
@@ -75,7 +75,11 @@
+ <% if (!"streamrserver".equals(tunnelType)) { %>
+ <% } // !streamrserver %>
+ <% if (!"streamrserver".equals(tunnelType)) { %>
+ <% } // !streamrserver %>
@@ -261,6 +262,7 @@
+
From 7e21afe6a6c2ce3d84a8973393d5ac60154d7f90 Mon Sep 17 00:00:00 2001
From: zzz
Date: Tue, 24 Feb 2009 22:59:59 +0000
Subject: [PATCH 010/688] sort the summary bar destinations
---
.../src/net/i2p/router/web/SummaryHelper.java | 47 ++++++++++++++-----
1 file changed, 36 insertions(+), 11 deletions(-)
diff --git a/apps/routerconsole/java/src/net/i2p/router/web/SummaryHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/SummaryHelper.java
index 2e56e858bc..47a07c3746 100644
--- a/apps/routerconsole/java/src/net/i2p/router/web/SummaryHelper.java
+++ b/apps/routerconsole/java/src/net/i2p/router/web/SummaryHelper.java
@@ -1,11 +1,15 @@
package net.i2p.router.web;
+import java.text.Collator;
import java.text.DateFormat;
import java.text.DecimalFormat;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
import java.util.Date;
import java.util.Iterator;
+import java.util.List;
import java.util.Locale;
-import java.util.Set;
import net.i2p.data.DataHelper;
import net.i2p.data.Destination;
@@ -346,20 +350,16 @@ public class SummaryHelper extends HelperBase {
* @return html section summary
*/
public String getDestinations() {
- Set clients = _context.clientManager().listClients();
+ // covert the set to a list so we can sort by name and not lose duplicates
+ List clients = new ArrayList(_context.clientManager().listClients());
+ Collections.sort(clients, new AlphaComparator());
StringBuffer buf = new StringBuffer(512);
buf.append("Local destinations ");
for (Iterator iter = clients.iterator(); iter.hasNext(); ) {
Destination client = (Destination)iter.next();
- TunnelPoolSettings in = _context.tunnelManager().getInboundSettings(client.calculateHash());
- TunnelPoolSettings out = _context.tunnelManager().getOutboundSettings(client.calculateHash());
- String name = (in != null ? in.getDestinationNickname() : null);
- if (name == null)
- name = (out != null ? out.getDestinationNickname() : null);
- if (name == null)
- name = client.calculateHash().toBase64().substring(0,6);
+ String name = getName(client);
buf.append("* ").append(name).append(" \n");
LeaseSet ls = _context.netDb().lookupLeaseSetLocally(client.calculateHash());
@@ -373,14 +373,38 @@ public class SummaryHelper extends HelperBase {
buf.append("No leases \n");
}
buf.append("Details ");
+ buf.append("\" target=\"_top\">Details ");
buf.append("Config \n");
+ buf.append("\" target=\"_top\">Config \n");
}
buf.append("\n");
return buf.toString();
}
+ private class AlphaComparator implements Comparator {
+ public int compare(Object lhs, Object rhs) {
+ String lname = getName((Destination)lhs);
+ String rname = getName((Destination)rhs);
+ if (lname.equals("shared clients"))
+ return -1;
+ if (rname.equals("shared clients"))
+ return 1;
+ return Collator.getInstance().compare(lname, rname);
+ }
+ }
+
+ private String getName(Destination d) {
+ TunnelPoolSettings in = _context.tunnelManager().getInboundSettings(d.calculateHash());
+ String name = (in != null ? in.getDestinationNickname() : null);
+ if (name == null) {
+ TunnelPoolSettings out = _context.tunnelManager().getOutboundSettings(d.calculateHash());
+ name = (out != null ? out.getDestinationNickname() : null);
+ if (name == null)
+ name = d.calculateHash().toBase64().substring(0,6);
+ }
+ return name;
+ }
+
/**
* How many free inbound tunnels we have.
*
@@ -511,4 +535,5 @@ public class SummaryHelper extends HelperBase {
public boolean updateAvailable() {
return NewsFetcher.getInstance(_context).updateAvailable();
}
+
}
From 7a684c160b50988cb9103d6a0033af64eb18bd08 Mon Sep 17 00:00:00 2001
From: zzz
Date: Tue, 24 Feb 2009 23:15:26 +0000
Subject: [PATCH 011/688] * Routerconsole: - Thread hard shutdown and
restart requests from the routerconsole, and add a delay even if no
tunnels, to allow time for a UI response
---
.../net/i2p/router/web/ConfigRestartBean.java | 19 +++++++++---
router/java/src/net/i2p/router/Router.java | 30 +++++++++++++++----
2 files changed, 39 insertions(+), 10 deletions(-)
diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ConfigRestartBean.java b/apps/routerconsole/java/src/net/i2p/router/web/ConfigRestartBean.java
index 3c9fe1bbf4..75a8108c50 100644
--- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigRestartBean.java
+++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigRestartBean.java
@@ -26,12 +26,14 @@ public class ConfigRestartBean {
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
+ //ctx.router().shutdown(Router.EXIT_HARD); // never returns
+ ctx.router().shutdownGracefully(Router.EXIT_HARD); // give the UI time to respond
} 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
+ //ctx.router().shutdown(Router.EXIT_HARD_RESTART); // never returns
+ ctx.router().shutdownGracefully(Router.EXIT_HARD_RESTART); // give the UI time to respond
} else if ("restart".equals(action)) {
ctx.router().addShutdownTask(new ConfigServiceHandler.UpdateWrapperManagerTask(Router.EXIT_GRACEFUL_RESTART));
ctx.router().shutdownGracefully(Router.EXIT_GRACEFUL_RESTART);
@@ -79,9 +81,18 @@ public class ConfigRestartBean {
}
private static boolean isShuttingDown(RouterContext ctx) {
- return Router.EXIT_GRACEFUL == ctx.router().scheduledGracefulExitCode();
+ return Router.EXIT_GRACEFUL == ctx.router().scheduledGracefulExitCode() ||
+ Router.EXIT_HARD == ctx.router().scheduledGracefulExitCode();
}
private static boolean isRestarting(RouterContext ctx) {
- return Router.EXIT_GRACEFUL_RESTART == ctx.router().scheduledGracefulExitCode();
+ return Router.EXIT_GRACEFUL_RESTART == ctx.router().scheduledGracefulExitCode() ||
+ Router.EXIT_HARD_RESTART == ctx.router().scheduledGracefulExitCode();
+ }
+ /** this is for summaryframe.jsp */
+ public static long getRestartTimeRemaining() {
+ RouterContext ctx = ContextHelper.getContext(null);
+ if (ctx.router().gracefulShutdownInProgress())
+ return ctx.router().getShutdownTimeRemaining();
+ return Long.MAX_VALUE/2; // summaryframe.jsp adds a safety factor so we don't want to overflow...
}
}
diff --git a/router/java/src/net/i2p/router/Router.java b/router/java/src/net/i2p/router/Router.java
index 033678924c..77e4b19681 100644
--- a/router/java/src/net/i2p/router/Router.java
+++ b/router/java/src/net/i2p/router/Router.java
@@ -446,13 +446,14 @@ public class Router {
*/
private static final String _rebuildFiles[] = new String[] { "router.info",
"router.keys",
- "netDb/my.info",
- "connectionTag.keys",
+ "netDb/my.info", // no longer used
+ "connectionTag.keys", // never used?
"keyBackup/privateEncryption.key",
"keyBackup/privateSigning.key",
"keyBackup/publicEncryption.key",
"keyBackup/publicSigning.key",
- "sessionKeys.dat" };
+ "sessionKeys.dat" // no longer used
+ };
static final String IDENTLOG = "identlog.txt";
public static void killKeys() {
@@ -859,6 +860,10 @@ public class Router {
public void shutdownGracefully() {
shutdownGracefully(EXIT_GRACEFUL);
}
+ /**
+ * Call this with EXIT_HARD or EXIT_HARD_RESTART for a non-blocking,
+ * hard, non-graceful shutdown with a brief delay to allow a UI response
+ */
public void shutdownGracefully(int exitCode) {
_gracefulExitCode = exitCode;
_config.setProperty(PROP_SHUTDOWN_IN_PROGRESS, "true");
@@ -887,7 +892,9 @@ public class Router {
}
/** How long until the graceful shutdown will kill us? */
public long getShutdownTimeRemaining() {
- if (_gracefulExitCode <= 0) return -1;
+ if (_gracefulExitCode <= 0) return -1; // maybe Long.MAX_VALUE would be better?
+ if (_gracefulExitCode == EXIT_HARD || _gracefulExitCode == EXIT_HARD_RESTART)
+ return 0;
long exp = _context.tunnelManager().getLastParticipatingExpiration();
if (exp < 0)
return -1;
@@ -906,9 +913,20 @@ public class Router {
while (true) {
boolean shutdown = (null != _config.getProperty(PROP_SHUTDOWN_IN_PROGRESS));
if (shutdown) {
- if (_context.tunnelManager().getParticipatingCount() <= 0) {
- if (_log.shouldLog(Log.CRIT))
+ if (_gracefulExitCode == EXIT_HARD || _gracefulExitCode == EXIT_HARD_RESTART ||
+ _context.tunnelManager().getParticipatingCount() <= 0) {
+ if (_gracefulExitCode == EXIT_HARD)
+ _log.log(Log.CRIT, "Shutting down after a brief delay");
+ else if (_gracefulExitCode == EXIT_HARD_RESTART)
+ _log.log(Log.CRIT, "Restarting after a brief delay");
+ else
_log.log(Log.CRIT, "Graceful shutdown progress - no more tunnels, safe to die");
+ // Allow time for a UI reponse
+ try {
+ synchronized (Thread.currentThread()) {
+ Thread.currentThread().wait(2*1000);
+ }
+ } catch (InterruptedException ie) {}
shutdown(_gracefulExitCode);
return;
} else {
From 559653f0ab532352503b527f38b326745f176940 Mon Sep 17 00:00:00 2001
From: zzz
Date: Tue, 24 Feb 2009 23:18:12 +0000
Subject: [PATCH 012/688] clean up OCMOSJ cache cleaner
---
.../OutboundClientMessageOneShotJob.java | 87 +++++++++++--------
1 file changed, 51 insertions(+), 36 deletions(-)
diff --git a/router/java/src/net/i2p/router/message/OutboundClientMessageOneShotJob.java b/router/java/src/net/i2p/router/message/OutboundClientMessageOneShotJob.java
index 0515d5c344..0e858ef779 100644
--- a/router/java/src/net/i2p/router/message/OutboundClientMessageOneShotJob.java
+++ b/router/java/src/net/i2p/router/message/OutboundClientMessageOneShotJob.java
@@ -34,6 +34,8 @@ import net.i2p.router.Router;
import net.i2p.router.RouterContext;
import net.i2p.router.TunnelInfo;
import net.i2p.util.Log;
+import net.i2p.util.SimpleScheduler;
+import net.i2p.util.SimpleTimer;
/**
* Send a client message out a random outbound tunnel and into a random inbound
@@ -98,6 +100,10 @@ public class OutboundClientMessageOneShotJob extends JobImpl {
*/
private static final int BUNDLE_PROBABILITY_DEFAULT = 100;
+ private static final Object _initializeLock = new Object();
+ private static boolean _initialized = false;
+ private static final int CLEAN_INTERVAL = 5*60*1000;
+
/**
* Send the sucker
*/
@@ -105,20 +111,26 @@ public class OutboundClientMessageOneShotJob extends JobImpl {
super(ctx);
_log = ctx.logManager().getLog(OutboundClientMessageOneShotJob.class);
- ctx.statManager().createFrequencyStat("client.sendMessageFailFrequency", "How often does a client fail to send a message?", "ClientMessages", new long[] { 60*1000l, 60*60*1000l, 24*60*60*1000l });
- ctx.statManager().createRateStat("client.sendMessageSize", "How large are messages sent by the client?", "ClientMessages", new long[] { 60*1000l, 60*60*1000l, 24*60*60*1000l });
- ctx.statManager().createRateStat("client.sendAckTime", "Message round trip time", "ClientMessages", new long[] { 60*1000l, 5*60*1000l, 60*60*1000l, 24*60*60*1000l });
- ctx.statManager().createRateStat("client.timeoutCongestionTunnel", "How lagged our tunnels are when a send times out?", "ClientMessages", new long[] { 60*1000l, 5*60*1000l, 60*60*1000l, 24*60*60*1000l });
- ctx.statManager().createRateStat("client.timeoutCongestionMessage", "How fast we process messages locally when a send times out?", "ClientMessages", new long[] { 5*60*1000l, 60*60*1000l, 24*60*60*1000l });
- ctx.statManager().createRateStat("client.timeoutCongestionInbound", "How much faster we are receiving data than our average bps when a send times out?", "ClientMessages", new long[] { 5*60*1000l, 60*60*1000l, 24*60*60*1000l });
- ctx.statManager().createRateStat("client.leaseSetFoundLocally", "How often we tried to look for a leaseSet and found it locally?", "ClientMessages", new long[] { 5*60*1000l, 60*60*1000l, 24*60*60*1000l });
- ctx.statManager().createRateStat("client.leaseSetFoundRemoteTime", "How long we tried to look for a remote leaseSet (when we succeeded)?", "ClientMessages", new long[] { 5*60*1000l, 60*60*1000l, 24*60*60*1000l });
- ctx.statManager().createRateStat("client.leaseSetFailedRemoteTime", "How long we tried to look for a remote leaseSet (when we failed)?", "ClientMessages", new long[] { 5*60*1000l, 60*60*1000l, 24*60*60*1000l });
- ctx.statManager().createRateStat("client.dispatchPrepareTime", "How long until we've queued up the dispatch job (since we started)?", "ClientMessages", new long[] { 5*60*1000l, 60*60*1000l, 24*60*60*1000l });
- ctx.statManager().createRateStat("client.dispatchTime", "How long until we've dispatched the message (since we started)?", "ClientMessages", new long[] { 5*60*1000l, 60*60*1000l, 24*60*60*1000l });
- ctx.statManager().createRateStat("client.dispatchSendTime", "How long the actual dispatching takes?", "ClientMessages", new long[] { 5*60*1000l, 60*60*1000l, 24*60*60*1000l });
- ctx.statManager().createRateStat("client.dispatchNoTunnels", "How long after start do we run out of tunnels to send/receive with?", "ClientMessages", new long[] { 5*60*1000l, 60*60*1000l, 24*60*60*1000l });
- ctx.statManager().createRateStat("client.dispatchNoACK", "Repeated message sends to a peer (no ack required)", "ClientMessages", new long[] { 60*1000l, 5*60*1000l, 60*60*1000l });
+ synchronized (_initializeLock) {
+ if (!_initialized) {
+ SimpleScheduler.getInstance().addPeriodicEvent(new OCMOSJCacheCleaner(ctx), CLEAN_INTERVAL, CLEAN_INTERVAL);
+ ctx.statManager().createFrequencyStat("client.sendMessageFailFrequency", "How often does a client fail to send a message?", "ClientMessages", new long[] { 60*1000l, 60*60*1000l, 24*60*60*1000l });
+ ctx.statManager().createRateStat("client.sendMessageSize", "How large are messages sent by the client?", "ClientMessages", new long[] { 60*1000l, 60*60*1000l, 24*60*60*1000l });
+ ctx.statManager().createRateStat("client.sendAckTime", "Message round trip time", "ClientMessages", new long[] { 60*1000l, 5*60*1000l, 60*60*1000l, 24*60*60*1000l });
+ ctx.statManager().createRateStat("client.timeoutCongestionTunnel", "How lagged our tunnels are when a send times out?", "ClientMessages", new long[] { 60*1000l, 5*60*1000l, 60*60*1000l, 24*60*60*1000l });
+ ctx.statManager().createRateStat("client.timeoutCongestionMessage", "How fast we process messages locally when a send times out?", "ClientMessages", new long[] { 5*60*1000l, 60*60*1000l, 24*60*60*1000l });
+ ctx.statManager().createRateStat("client.timeoutCongestionInbound", "How much faster we are receiving data than our average bps when a send times out?", "ClientMessages", new long[] { 5*60*1000l, 60*60*1000l, 24*60*60*1000l });
+ ctx.statManager().createRateStat("client.leaseSetFoundLocally", "How often we tried to look for a leaseSet and found it locally?", "ClientMessages", new long[] { 5*60*1000l, 60*60*1000l, 24*60*60*1000l });
+ ctx.statManager().createRateStat("client.leaseSetFoundRemoteTime", "How long we tried to look for a remote leaseSet (when we succeeded)?", "ClientMessages", new long[] { 5*60*1000l, 60*60*1000l, 24*60*60*1000l });
+ ctx.statManager().createRateStat("client.leaseSetFailedRemoteTime", "How long we tried to look for a remote leaseSet (when we failed)?", "ClientMessages", new long[] { 5*60*1000l, 60*60*1000l, 24*60*60*1000l });
+ ctx.statManager().createRateStat("client.dispatchPrepareTime", "How long until we've queued up the dispatch job (since we started)?", "ClientMessages", new long[] { 5*60*1000l, 60*60*1000l, 24*60*60*1000l });
+ ctx.statManager().createRateStat("client.dispatchTime", "How long until we've dispatched the message (since we started)?", "ClientMessages", new long[] { 5*60*1000l, 60*60*1000l, 24*60*60*1000l });
+ ctx.statManager().createRateStat("client.dispatchSendTime", "How long the actual dispatching takes?", "ClientMessages", new long[] { 5*60*1000l, 60*60*1000l, 24*60*60*1000l });
+ ctx.statManager().createRateStat("client.dispatchNoTunnels", "How long after start do we run out of tunnels to send/receive with?", "ClientMessages", new long[] { 5*60*1000l, 60*60*1000l, 24*60*60*1000l });
+ ctx.statManager().createRateStat("client.dispatchNoACK", "Repeated message sends to a peer (no ack required)", "ClientMessages", new long[] { 60*1000l, 5*60*1000l, 60*60*1000l });
+ _initialized = true;
+ }
+ }
long timeoutMs = OVERALL_TIMEOUT_MS_DEFAULT;
_clientMessage = msg;
_clientMessageId = msg.getMessageId();
@@ -201,7 +213,6 @@ public class OutboundClientMessageOneShotJob extends JobImpl {
* Key the cache on the source+dest pair.
*/
private static HashMap _leaseSetCache = new HashMap();
- private static long _lscleanTime = 0;
private LeaseSet getReplyLeaseSet(boolean force) {
LeaseSet newLS = getContext().netDb().lookupLeaseSetLocally(_from.calculateHash());
if (newLS == null)
@@ -235,10 +246,6 @@ public class OutboundClientMessageOneShotJob extends JobImpl {
// If the last leaseSet we sent him is still good, don't bother sending again
long now = getContext().clock().now();
synchronized (_leaseSetCache) {
- if (now - _lscleanTime > 5*60*1000) { // clean out periodically
- cleanLeaseSetCache(_leaseSetCache);
- _lscleanTime = now;
- }
if (!force) {
LeaseSet ls = (LeaseSet) _leaseSetCache.get(hashPair());
if (ls != null) {
@@ -306,7 +313,6 @@ public class OutboundClientMessageOneShotJob extends JobImpl {
*
*/
private static HashMap _leaseCache = new HashMap();
- private static long _lcleanTime = 0;
private boolean getNextLease() {
_leaseSet = getContext().netDb().lookupLeaseSetLocally(_to.calculateHash());
if (_leaseSet == null) {
@@ -319,10 +325,6 @@ public class OutboundClientMessageOneShotJob extends JobImpl {
// Use the same lease if it's still good
// Even if _leaseSet changed, _leaseSet.getEncryptionKey() didn't...
synchronized (_leaseCache) {
- if (now - _lcleanTime > 5*60*1000) { // clean out periodically
- cleanLeaseCache(_leaseCache);
- _lcleanTime = now;
- }
_lease = (Lease) _leaseCache.get(hashPair());
if (_lease != null) {
// if outbound tunnel length == 0 && lease.firsthop.isBacklogged() don't use it ??
@@ -607,7 +609,7 @@ public class OutboundClientMessageOneShotJob extends JobImpl {
* (needed for cleanTunnelCache)
* 44 = 32 * 4 / 3
*/
- private Hash sourceFromHashPair(String s) {
+ private static Hash sourceFromHashPair(String s) {
return new Hash(Base64.decode(s.substring(44, 88)));
}
@@ -648,8 +650,8 @@ public class OutboundClientMessageOneShotJob extends JobImpl {
* Clean out old leaseSets from a set.
* Caller must synchronize on tc.
*/
- private void cleanLeaseSetCache(HashMap tc) {
- long now = getContext().clock().now();
+ private static void cleanLeaseSetCache(RouterContext ctx, HashMap tc) {
+ long now = ctx.clock().now();
List deleteList = new ArrayList();
for (Iterator iter = tc.entrySet().iterator(); iter.hasNext(); ) {
Map.Entry entry = (Map.Entry)iter.next();
@@ -668,7 +670,7 @@ public class OutboundClientMessageOneShotJob extends JobImpl {
* Clean out old leases from a set.
* Caller must synchronize on tc.
*/
- private void cleanLeaseCache(HashMap tc) {
+ private static void cleanLeaseCache(HashMap tc) {
List deleteList = new ArrayList();
for (Iterator iter = tc.entrySet().iterator(); iter.hasNext(); ) {
Map.Entry entry = (Map.Entry)iter.next();
@@ -687,13 +689,13 @@ public class OutboundClientMessageOneShotJob extends JobImpl {
* Clean out old tunnels from a set.
* Caller must synchronize on tc.
*/
- private void cleanTunnelCache(HashMap tc) {
+ private static void cleanTunnelCache(RouterContext ctx, HashMap tc) {
List deleteList = new ArrayList();
for (Iterator iter = tc.entrySet().iterator(); iter.hasNext(); ) {
Map.Entry entry = (Map.Entry)iter.next();
String k = (String) entry.getKey();
TunnelInfo tunnel = (TunnelInfo) entry.getValue();
- if (!getContext().tunnelManager().isValidTunnel(sourceFromHashPair(k), tunnel))
+ if (!ctx.tunnelManager().isValidTunnel(sourceFromHashPair(k), tunnel))
deleteList.add(k);
}
for (Iterator iter = deleteList.iterator(); iter.hasNext(); ) {
@@ -702,6 +704,25 @@ public class OutboundClientMessageOneShotJob extends JobImpl {
}
}
+ private static class OCMOSJCacheCleaner implements SimpleTimer.TimedEvent {
+ private RouterContext _ctx;
+ private OCMOSJCacheCleaner(RouterContext ctx) {
+ _ctx = ctx;
+ }
+ public void timeReached() {
+ synchronized(_leaseSetCache) {
+ cleanLeaseSetCache(_ctx, _leaseSetCache);
+ }
+ synchronized(_leaseCache) {
+ cleanLeaseCache(_leaseCache);
+ }
+ synchronized(_tunnelCache) {
+ cleanTunnelCache(_ctx, _tunnelCache);
+ cleanTunnelCache(_ctx, _backloggedTunnelCache);
+ }
+ }
+ }
+
/**
* Use the same outbound tunnel as we did for the same destination previously,
* if possible, to keep the streaming lib happy
@@ -712,16 +733,10 @@ public class OutboundClientMessageOneShotJob extends JobImpl {
*/
private static HashMap _tunnelCache = new HashMap();
private static HashMap _backloggedTunnelCache = new HashMap();
- private static long _cleanTime = 0;
private TunnelInfo selectOutboundTunnel(Destination to) {
TunnelInfo tunnel;
long now = getContext().clock().now();
synchronized (_tunnelCache) {
- if (now - _cleanTime > 5*60*1000) { // clean out periodically
- cleanTunnelCache(_tunnelCache);
- cleanTunnelCache(_backloggedTunnelCache);
- _cleanTime = now;
- }
/**
* If old tunnel is valid and no longer backlogged, use it.
* This prevents an active anonymity attack, where a peer could tell
From 6484005569a98cfa2bbb5ec4d3e869b5e51f2e06 Mon Sep 17 00:00:00 2001
From: zzz
Date: Tue, 24 Feb 2009 23:28:53 +0000
Subject: [PATCH 013/688] I2PTunnel: First cut at SOCKS UDP (untested); also
some streamr and UDP tweaks
---
.../net/i2p/i2ptunnel/socks/MultiSink.java | 35 +++++++
.../net/i2p/i2ptunnel/socks/ReplyTracker.java | 36 +++++++
.../net/i2p/i2ptunnel/socks/SOCKS5Server.java | 84 +++++++++++++++--
.../net/i2p/i2ptunnel/socks/SOCKSHeader.java | 89 ++++++++++++++++++
.../net/i2p/i2ptunnel/socks/SOCKSUDPPort.java | 77 +++++++++++++++
.../i2p/i2ptunnel/socks/SOCKSUDPTunnel.java | 94 +++++++++++++++++++
.../i2ptunnel/socks/SOCKSUDPUnwrapper.java | 59 ++++++++++++
.../i2p/i2ptunnel/socks/SOCKSUDPWrapper.java | 49 ++++++++++
.../i2p/i2ptunnel/streamr/MultiSource.java | 4 +
.../i2ptunnel/streamr/StreamrConsumer.java | 3 +-
.../i2ptunnel/streamr/StreamrProducer.java | 5 +-
.../src/net/i2p/i2ptunnel/udp/UDPSink.java | 21 +++--
.../src/net/i2p/i2ptunnel/udp/UDPSource.java | 14 ++-
13 files changed, 549 insertions(+), 21 deletions(-)
create mode 100644 apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/MultiSink.java
create mode 100644 apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/ReplyTracker.java
create mode 100644 apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/SOCKSHeader.java
create mode 100644 apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/SOCKSUDPPort.java
create mode 100644 apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/SOCKSUDPTunnel.java
create mode 100644 apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/SOCKSUDPUnwrapper.java
create mode 100644 apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/SOCKSUDPWrapper.java
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/MultiSink.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/MultiSink.java
new file mode 100644
index 0000000000..3c63758c13
--- /dev/null
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/MultiSink.java
@@ -0,0 +1,35 @@
+package net.i2p.i2ptunnel.socks;
+
+import java.util.Map;
+
+import net.i2p.data.Destination;
+import net.i2p.i2ptunnel.udp.*;
+import net.i2p.util.Log;
+
+/**
+ * Sends to one of many Sinks
+ * @author zzz modded from streamr/MultiSource
+ */
+public class MultiSink implements Source, Sink {
+ private static final Log _log = new Log(MultiSink.class);
+
+ public MultiSink(Map cache) {
+ this.cache = cache;
+ }
+
+ /** Don't use this - put sinks in the cache */
+ public void setSink(Sink sink) {}
+
+ public void start() {}
+
+ public void send(Destination from, byte[] data) {
+ Sink s = this.cache.get(from);
+ if (s == null) {
+ _log.error("No where to go for " + from.calculateHash().toBase64().substring(0, 6));
+ return;
+ }
+ s.send(from, data);
+ }
+
+ private Map cache;
+}
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/ReplyTracker.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/ReplyTracker.java
new file mode 100644
index 0000000000..f6a124c951
--- /dev/null
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/ReplyTracker.java
@@ -0,0 +1,36 @@
+package net.i2p.i2ptunnel.socks;
+
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.Map;
+
+import net.i2p.data.Destination;
+import net.i2p.i2ptunnel.udp.*;
+import net.i2p.util.Log;
+
+/**
+ * Track who the reply goes to
+ * @author zzz
+ */
+public class ReplyTracker implements Source, Sink {
+ private static final Log _log = new Log(MultiSink.class);
+
+ public ReplyTracker(Sink reply, Map cache) {
+ this.reply = reply;
+ this.cache = cache;
+ }
+
+ public void setSink(Sink sink) {
+ this.sink = sink;
+ }
+
+ public void start() {}
+
+ public void send(Destination to, byte[] data) {
+ this.cache.put(to, this.reply);
+ this.sink.send(to, data);
+ }
+
+ private Sink reply;
+ private Map cache;
+ private Sink sink;
+}
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/SOCKS5Server.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/SOCKS5Server.java
index 38c50f2661..5e52926074 100644
--- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/SOCKS5Server.java
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/SOCKS5Server.java
@@ -13,12 +13,15 @@ import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import java.net.SocketException;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
import java.util.List;
import net.i2p.I2PAppContext;
import net.i2p.I2PException;
import net.i2p.client.streaming.I2PSocket;
import net.i2p.data.DataFormatException;
+import net.i2p.data.Destination;
import net.i2p.i2ptunnel.I2PTunnel;
import net.i2p.util.HexDump;
import net.i2p.util.Log;
@@ -67,7 +70,8 @@ public class SOCKS5Server extends SOCKSServer {
out = new DataOutputStream(clientSock.getOutputStream());
init(in, out);
- manageRequest(in, out);
+ if (manageRequest(in, out) == Command.UDP_ASSOCIATE)
+ handleUDP(in, out);
} catch (IOException e) {
throw new SOCKSException("Connection error (" + e.getMessage() + ")");
}
@@ -111,7 +115,7 @@ public class SOCKS5Server extends SOCKSServer {
* initialization, integrity/confidentiality encapsulations, etc)
* has been stripped out of the input/output streams.
*/
- private void manageRequest(DataInputStream in, DataOutputStream out) throws IOException, SOCKSException {
+ private int manageRequest(DataInputStream in, DataOutputStream out) throws IOException, SOCKSException {
int socksVer = in.readByte() & 0xff;
if (socksVer != SOCKS_VERSION_5) {
_log.debug("error in SOCKS5 request (protocol != 5? wtf?)");
@@ -127,9 +131,12 @@ public class SOCKS5Server extends SOCKSServer {
sendRequestReply(Reply.COMMAND_NOT_SUPPORTED, AddressType.DOMAINNAME, null, "0.0.0.0", 0, out);
throw new SOCKSException("BIND command not supported");
case Command.UDP_ASSOCIATE:
+ /*** if(!Boolean.valueOf(tunnel.getOptions().getProperty("i2ptunnel.socks.allowUDP")).booleanValue()) {
_log.debug("UDP ASSOCIATE command is not supported!");
sendRequestReply(Reply.COMMAND_NOT_SUPPORTED, AddressType.DOMAINNAME, null, "0.0.0.0", 0, out);
throw new SOCKSException("UDP ASSOCIATE command not supported");
+ ***/
+ break;
default:
_log.debug("unknown command in request (" + Integer.toHexString(command) + ")");
sendRequestReply(Reply.COMMAND_NOT_SUPPORTED, AddressType.DOMAINNAME, null, "0.0.0.0", 0, out);
@@ -152,7 +159,8 @@ public class SOCKS5Server extends SOCKSServer {
connHostName += ".";
}
}
- _log.warn("IPV4 address type in request: " + connHostName + ". Is your client secure?");
+ if (command != Command.UDP_ASSOCIATE)
+ _log.warn("IPV4 address type in request: " + connHostName + ". Is your client secure?");
break;
case AddressType.DOMAINNAME:
{
@@ -168,9 +176,12 @@ public class SOCKS5Server extends SOCKSServer {
_log.debug("DOMAINNAME address type in request: " + connHostName);
break;
case AddressType.IPV6:
- _log.warn("IP V6 address type in request! Is your client secure?" + " (IPv6 is not supported, anyway :-)");
- sendRequestReply(Reply.ADDRESS_TYPE_NOT_SUPPORTED, AddressType.DOMAINNAME, null, "0.0.0.0", 0, out);
- throw new SOCKSException("IPV6 addresses not supported");
+ if (command != Command.UDP_ASSOCIATE) {
+ _log.warn("IP V6 address type in request! Is your client secure?" + " (IPv6 is not supported, anyway :-)");
+ sendRequestReply(Reply.ADDRESS_TYPE_NOT_SUPPORTED, AddressType.DOMAINNAME, null, "0.0.0.0", 0, out);
+ throw new SOCKSException("IPV6 addresses not supported");
+ }
+ break;
default:
_log.debug("unknown address type in request (" + Integer.toHexString(command) + ")");
sendRequestReply(Reply.ADDRESS_TYPE_NOT_SUPPORTED, AddressType.DOMAINNAME, null, "0.0.0.0", 0, out);
@@ -183,6 +194,7 @@ public class SOCKS5Server extends SOCKSServer {
sendRequestReply(Reply.CONNECTION_NOT_ALLOWED_BY_RULESET, AddressType.DOMAINNAME, null, "0.0.0.0", 0, out);
throw new SOCKSException("Invalid port number in request");
}
+ return command;
}
protected void confirmConnection() throws SOCKSException {
@@ -293,6 +305,13 @@ public class SOCKS5Server extends SOCKSServer {
// Let's not due a new Dest for every request, huh?
//I2PSocketManager sm = I2PSocketManagerFactory.createManager();
//destSock = sm.connect(I2PTunnel.destFromName(connHostName), null);
+ Destination dest = I2PTunnel.destFromName(connHostName);
+ if (dest == null) {
+ try {
+ sendRequestReply(Reply.HOST_UNREACHABLE, AddressType.DOMAINNAME, null, "0.0.0.0", 0, out);
+ } catch (IOException ioe) {}
+ throw new SOCKSException("Host not found");
+ }
destSock = t.createI2PSocket(I2PTunnel.destFromName(connHostName));
} else if ("localhost".equals(connHostName) || "127.0.0.1".equals(connHostName)) {
String err = "No localhost accesses allowed through the Socks Proxy";
@@ -358,6 +377,59 @@ public class SOCKS5Server extends SOCKSServer {
return destSock;
}
+ // This isn't really the right place for this, we can't stop the tunnel once it starts.
+ static SOCKSUDPTunnel _tunnel;
+ static Object _startLock = new Object();
+ static byte[] dummyIP = new byte[4];
+ /**
+ * We got a UDP associate command.
+ * Loop here looking for more, never return normally,
+ * or else I2PSocksTunnel will create a streaming lib connection.
+ *
+ * Do UDP Socks clients actually send more than one Associate request?
+ * RFC 1928 isn't clear... maybe not.
+ */
+ private void handleUDP(DataInputStream in, DataOutputStream out) throws SOCKSException {
+ List ports = new ArrayList(1);
+ synchronized (_startLock) {
+ if (_tunnel == null) {
+ // tunnel options?
+ _tunnel = new SOCKSUDPTunnel(new I2PTunnel());
+ _tunnel.startRunning();
+ }
+ }
+ while (true) {
+ // Set it up. connHostName and connPort are the client's info.
+ InetAddress ia = null;
+ try {
+ ia = InetAddress.getByAddress(connHostName, dummyIP);
+ } catch (UnknownHostException uhe) {} // won't happen, no resolving done here
+ int myPort = _tunnel.add(ia, connPort);
+ ports.add(Integer.valueOf(myPort));
+ try {
+ sendRequestReply(Reply.SUCCEEDED, AddressType.IPV4, InetAddress.getByName("127.0.0.1"), null, myPort, out);
+ } catch (IOException ioe) { break; }
+
+ // wait for more ???
+ try {
+ int command = manageRequest(in, out);
+ // don't do this...
+ if (command != Command.UDP_ASSOCIATE)
+ break;
+ } catch (IOException ioe) { break; }
+ catch (SOCKSException ioe) { break; }
+ }
+
+ for (Integer i : ports)
+ _tunnel.remove(i);
+
+ // Prevent I2PSocksTunnel from calling getDestinationI2PSocket() above
+ // to create a streaming lib connection...
+ // This isn't very elegant...
+ //
+ throw new SOCKSException("End of UDP Processing");
+ }
+
/*
* Some namespaces to enclose SOCKS protocol codes
*/
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/SOCKSHeader.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/SOCKSHeader.java
new file mode 100644
index 0000000000..763b9aa10a
--- /dev/null
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/SOCKSHeader.java
@@ -0,0 +1,89 @@
+package net.i2p.i2ptunnel.socks;
+
+import net.i2p.data.Base32;
+import net.i2p.data.DataFormatException;
+import net.i2p.data.Destination;
+import net.i2p.i2ptunnel.I2PTunnel;
+
+/**
+ * Save the SOCKS header from a datagram
+ * Ref: RFC 1928
+ *
+ * @author zzz
+ */
+public class SOCKSHeader {
+
+ /**
+ * @param data the whole packet
+ */
+ public SOCKSHeader(byte[] data) {
+ if (data.length <= 8)
+ throw new IllegalArgumentException("Header too short: " + data.length);
+ if (data[0] != 0 || data[1] != 0)
+ throw new IllegalArgumentException("Not a SOCKS datagram?");
+ if (data[2] != 0)
+ throw new IllegalArgumentException("We can't handle fragments!");
+ int headerlen = 0;
+ int addressType = data[3];
+ if (addressType == 1) {
+ // this will fail in getDestination()
+ headerlen = 6 + 4;
+ } else if (addressType == 3) {
+ headerlen = 6 + 1 + (data[4] & 0xff);
+ } else if (addressType == 4) {
+ // this will fail in getDestination()
+ // but future garlicat partial hash lookup possible?
+ headerlen = 6 + 16;
+ } else {
+ throw new IllegalArgumentException("Unknown address type: " + addressType);
+ }
+ if (data.length < headerlen)
+ throw new IllegalArgumentException("Header too short: " + data.length);
+
+ this.header = new byte[headerlen];
+ System.arraycopy(this.header, 0, data, 0, headerlen);
+ }
+
+ private static final byte[] beg = {0,0,0,3,60};
+ private static final byte[] end = {'.','b','3','2','.','i','2','p',0,0};
+
+ /**
+ * Make a dummy header from a dest,
+ * for those cases where we want to receive unsolicited datagrams.
+ * Unused for now.
+ */
+ public SOCKSHeader(Destination dest) {
+ this.header = new byte[beg.length + 52 + end.length];
+ System.arraycopy(this.header, 0, beg, 0, beg.length);
+ String b32 = Base32.encode(dest.calculateHash().getData());
+ System.arraycopy(this.header, beg.length, b32.getBytes(), 0, 52);
+ System.arraycopy(this.header, beg.length + 52, end, 0, end.length);
+ }
+
+ public String getHost() {
+ int addressType = this.header[3];
+ if (addressType != 3)
+ return null;
+ int namelen = (this.header[4] & 0xff);
+ byte[] nameBytes = new byte[namelen];
+ System.arraycopy(nameBytes, 0, this.header, 5, namelen);
+ return new String(nameBytes);
+ }
+
+ public Destination getDestination() {
+ String name = getHost();
+ if (name == null)
+ return null;
+ try {
+ // the naming service does caching (thankfully)
+ return I2PTunnel.destFromName(name);
+ } catch (DataFormatException dfe) {}
+ return null;
+ }
+
+ public byte[] getBytes() {
+ return header;
+ }
+
+ private byte[] header;
+}
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/SOCKSUDPPort.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/SOCKSUDPPort.java
new file mode 100644
index 0000000000..b56c9082ff
--- /dev/null
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/SOCKSUDPPort.java
@@ -0,0 +1,77 @@
+package net.i2p.i2ptunnel.socks;
+
+import java.net.DatagramSocket;
+import java.net.InetAddress;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.Map;
+
+import net.i2p.data.Destination;
+import net.i2p.i2ptunnel.udp.*;
+
+/**
+ * Implements a UDP port and Socks encapsulation / decapsulation.
+ * This is for a single port. If there is demuxing for multiple
+ * ports, it happens outside of here.
+ *
+ * TX:
+ * UDPSource -> SOCKSUDPUnwrapper -> ReplyTracker ( -> I2PSink in SOCKSUDPTunnel)
+ *
+ * RX:
+ * UDPSink <- SOCKSUDPWrapper ( <- MultiSink <- I2PSource in SOCKSUDPTunnel)
+ *
+ * The Unwrapper passes headers to the Wrapper through a cache.
+ * The ReplyTracker passes sinks to MultiSink through a cache.
+ *
+ * @author zzz
+ */
+public class SOCKSUDPPort implements Source, Sink {
+
+ public SOCKSUDPPort(InetAddress host, int port, Map replyMap) {
+
+ // this passes the host and port from UDPUnwrapper to UDPWrapper
+ Map cache = new ConcurrentHashMap(4);
+
+ // rcv from I2P and send to a port
+ this.wrapper = new SOCKSUDPWrapper(cache);
+ this.udpsink = new UDPSink(host, port);
+ this.wrapper.setSink(this.udpsink);
+
+ // rcv from the same port and send to I2P
+ DatagramSocket sock = this.udpsink.getSocket();
+ this.udpsource = new UDPSource(sock);
+ this.unwrapper = new SOCKSUDPUnwrapper(cache);
+ this.udpsource.setSink(this.unwrapper);
+ this.udptracker = new ReplyTracker(this, replyMap);
+ this.unwrapper.setSink(this.udptracker);
+ }
+
+ /** Socks passes this back to the client on the TCP connection */
+ public int getPort() {
+ return this.udpsink.getPort();
+ }
+
+ public void setSink(Sink sink) {
+ this.udptracker.setSink(sink);
+ }
+
+ public void start() {
+ // the other Sources don't use start
+ this.udpsource.start();
+ }
+
+ public void stop() {
+ this.udpsink.stop();
+ this.udpsource.stop();
+ }
+
+ public void send(Destination from, byte[] data) {
+ this.wrapper.send(from, data);
+ }
+
+
+ private UDPSink udpsink;
+ private UDPSource udpsource;
+ private SOCKSUDPWrapper wrapper;
+ private SOCKSUDPUnwrapper unwrapper;
+ private ReplyTracker udptracker;
+}
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/SOCKSUDPTunnel.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/SOCKSUDPTunnel.java
new file mode 100644
index 0000000000..0adaa19506
--- /dev/null
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/SOCKSUDPTunnel.java
@@ -0,0 +1,94 @@
+package net.i2p.i2ptunnel.socks;
+
+import java.net.InetAddress;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import net.i2p.data.Destination;
+import net.i2p.i2ptunnel.I2PTunnel;
+import net.i2p.i2ptunnel.Logging;
+import net.i2p.i2ptunnel.udp.*;
+import net.i2p.i2ptunnel.udpTunnel.I2PTunnelUDPClientBase;
+import net.i2p.util.EventDispatcher;
+
+/**
+ * A Datagram Tunnel that can have multiple bidirectional ports on the UDP side.
+ *
+ * TX:
+ * (ReplyTracker in multiple SOCKSUDPPorts -> ) I2PSink
+ *
+ * RX:
+ * (SOCKSUDPWrapper in multiple SOCKSUDPPorts <- ) MultiSink <- I2PSource
+ *
+ * The reply from a dest goes to the last SOCKSUDPPort that sent to that dest.
+ * If multiple ports are talking to a dest at the same time, this isn't
+ * going to work very well.
+ *
+ * @author zzz modded from streamr/StreamrConsumer
+ */
+public class SOCKSUDPTunnel extends I2PTunnelUDPClientBase {
+
+ /**
+ * Set up a tunnel with no UDP side yet.
+ * Use add() for each port.
+ */
+ public SOCKSUDPTunnel(I2PTunnel tunnel) {
+ super(null, tunnel, tunnel, tunnel);
+
+ this.ports = new ConcurrentHashMap(1);
+ this.cache = new ConcurrentHashMap(1);
+ this.demuxer = new MultiSink(this.cache);
+ setSink(this.demuxer);
+ }
+
+
+ /** @return the UDP port number */
+ public int add(InetAddress host, int port) {
+ SOCKSUDPPort sup = new SOCKSUDPPort(host, port, this.cache);
+ this.ports.put(Integer.valueOf(sup.getPort()), sup);
+ sup.setSink(this);
+ sup.start();
+ return sup.getPort();
+ }
+
+ public void remove(Integer port) {
+ SOCKSUDPPort sup = this.ports.remove(port);
+ if (sup != null)
+ sup.stop();
+ for (Iterator iter = cache.entrySet().iterator(); iter.hasNext();) {
+ Map.Entry e = (Map.Entry) iter.next();
+ if (e.getValue() == sup)
+ iter.remove();
+ }
+ }
+
+ public final void startRunning() {
+ super.startRunning();
+ // demuxer start() doesn't do anything
+ startall();
+ }
+
+ public boolean close(boolean forced) {
+ stopall();
+ return super.close(forced);
+ }
+
+ /** you should really add() after startRunning() */
+ private void startall() {
+ }
+
+ private void stopall() {
+ for (SOCKSUDPPort sup : this.ports.values()) {
+ sup.stop();
+ }
+ this.ports.clear();
+ this.cache.clear();
+ }
+
+
+
+ private Map ports;
+ private Map cache;
+ private MultiSink demuxer;
+}
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/SOCKSUDPUnwrapper.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/SOCKSUDPUnwrapper.java
new file mode 100644
index 0000000000..2720b6fd47
--- /dev/null
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/SOCKSUDPUnwrapper.java
@@ -0,0 +1,59 @@
+package net.i2p.i2ptunnel.socks;
+
+import java.util.Map;
+
+import net.i2p.data.Destination;
+import net.i2p.i2ptunnel.udp.*;
+import net.i2p.util.Log;
+
+/**
+ * Strip a SOCKS header off a datagram, convert it to a Destination
+ * Ref: RFC 1928
+ *
+ * @author zzz
+ */
+public class SOCKSUDPUnwrapper implements Source, Sink {
+ private static final Log _log = new Log(SOCKSUDPUnwrapper.class);
+
+ /**
+ * @param cache put headers here to pass to SOCKSUDPWrapper
+ */
+ public SOCKSUDPUnwrapper(Map cache) {
+ this.cache = cache;
+ }
+
+ public void setSink(Sink sink) {
+ this.sink = sink;
+ }
+
+ public void start() {}
+
+ /**
+ *
+ */
+ public void send(Destination ignored_from, byte[] data) {
+ SOCKSHeader h;
+ try {
+ h = new SOCKSHeader(data);
+ } catch (IllegalArgumentException iae) {
+ _log.error(iae.toString());
+ return;
+ }
+ Destination dest = h.getDestination();
+ if (dest == null) {
+ // no, we aren't going to send non-i2p traffic to a UDP outproxy :)
+ _log.error("Destination not found: " + h.getHost());
+ return;
+ }
+
+ cache.put(dest, h);
+
+ int headerlen = h.getBytes().length;
+ byte unwrapped[] = new byte[data.length - headerlen];
+ System.arraycopy(unwrapped, 0, data, headerlen, unwrapped.length);
+ this.sink.send(dest, unwrapped);
+ }
+
+ private Sink sink;
+ private Map cache;
+}
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/SOCKSUDPWrapper.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/SOCKSUDPWrapper.java
new file mode 100644
index 0000000000..4ec8361576
--- /dev/null
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/SOCKSUDPWrapper.java
@@ -0,0 +1,49 @@
+package net.i2p.i2ptunnel.socks;
+
+import java.util.Map;
+
+import net.i2p.data.Destination;
+import net.i2p.i2ptunnel.udp.*;
+
+/**
+ * Put a SOCKS header on a datagram
+ * Ref: RFC 1928
+ *
+ * @author zzz
+ */
+public class SOCKSUDPWrapper implements Source, Sink {
+ public SOCKSUDPWrapper(Map cache) {
+ this.cache = cache;
+ }
+
+ public void setSink(Sink sink) {
+ this.sink = sink;
+ }
+
+ public void start() {}
+
+ /**
+ * Use the cached header, which should have the host string and port
+ *
+ */
+ public void send(Destination from, byte[] data) {
+ if (this.sink == null)
+ return;
+
+ SOCKSHeader h = cache.get(from);
+ if (h == null) {
+ // RFC 1928 says drop
+ // h = new SOCKSHeader(from);
+ return;
+ }
+
+ byte[] header = h.getBytes();
+ byte wrapped[] = new byte[header.length + data.length];
+ System.arraycopy(wrapped, 0, header, 0, header.length);
+ System.arraycopy(wrapped, header.length, data, 0, data.length);
+ this.sink.send(from, wrapped);
+ }
+
+ private Sink sink;
+ private Map cache;
+}
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/streamr/MultiSource.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/streamr/MultiSource.java
index 13d9b55202..5c5a08027e 100644
--- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/streamr/MultiSource.java
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/streamr/MultiSource.java
@@ -27,6 +27,10 @@ public class MultiSource implements Source, Sink {
public void start() {}
+ public void stop() {
+ this.sinks.clear();
+ }
+
public void send(Destination ignored_from, byte[] data) {
for(Destination dest : this.sinks) {
this.sink.send(dest, data);
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/streamr/StreamrConsumer.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/streamr/StreamrConsumer.java
index 3fc1d881b9..02b4434437 100644
--- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/streamr/StreamrConsumer.java
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/streamr/StreamrConsumer.java
@@ -47,6 +47,7 @@ public class StreamrConsumer extends I2PTunnelUDPClientBase {
public boolean close(boolean forced) {
// send unsubscribe-message
this.pinger.stop();
+ this.sink.stop();
return super.close(forced);
}
@@ -59,6 +60,6 @@ public class StreamrConsumer extends I2PTunnelUDPClientBase {
- private Sink sink;
+ private UDPSink sink;
private Pinger pinger;
}
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/streamr/StreamrProducer.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/streamr/StreamrProducer.java
index d722c5f95c..c3963b6a66 100644
--- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/streamr/StreamrProducer.java
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/streamr/StreamrProducer.java
@@ -51,7 +51,8 @@ public class StreamrProducer extends I2PTunnelUDPServerBase {
}
public boolean close(boolean forced) {
- // need some stop() methods in UDPSource and MultiSource
+ this.server.stop();
+ this.multi.stop();
return super.close(forced);
}
@@ -65,6 +66,6 @@ public class StreamrProducer extends I2PTunnelUDPServerBase {
private MultiSource multi;
- private Source server;
+ private UDPSource server;
private Sink subscriber;
}
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udp/UDPSink.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udp/UDPSink.java
index 15feba6156..d2e8e89247 100644
--- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udp/UDPSink.java
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udp/UDPSink.java
@@ -34,6 +34,8 @@ public class UDPSink implements Sink {
}
public void send(Destination src, byte[] data) {
+ // if data.length > this.sock.getSendBufferSize() ...
+
// create packet
DatagramPacket packet = new DatagramPacket(data, data.length, this.remoteHost, this.remotePort);
@@ -46,17 +48,18 @@ public class UDPSink implements Sink {
}
}
+ public int getPort() {
+ return this.sock.getLocalPort();
+ }
+ /** to pass to UDPSource constructor */
+ public DatagramSocket getSocket() {
+ return this.sock;
+ }
-
-
-
-
-
-
-
-
-
+ public void stop() {
+ this.sock.close();
+ }
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udp/UDPSource.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udp/UDPSource.java
index c54a984b0a..fc1dd5bf22 100644
--- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udp/UDPSource.java
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udp/UDPSource.java
@@ -28,6 +28,13 @@ public class UDPSource implements Source, Runnable {
// create thread
this.thread = new Thread(this);
}
+
+ /** use socket from UDPSink */
+ public UDPSource(DatagramSocket sock) {
+ this.sink = null;
+ this.sock = sock;
+ this.thread = new Thread(this);
+ }
public void setSink(Sink sink) {
this.sink = sink;
@@ -57,13 +64,14 @@ public class UDPSource implements Source, Runnable {
//System.out.print("i");
} catch(Exception e) {
e.printStackTrace();
+ break;
}
}
}
-
-
-
+ public void stop() {
+ this.sock.close();
+ }
From 0d2812db5063bc3c88044dbd480e05599e5f29b1 Mon Sep 17 00:00:00 2001
From: zzz
Date: Tue, 24 Feb 2009 23:32:38 +0000
Subject: [PATCH 014/688] add standard logging to NativeBigInteger
---
.../src/net/i2p/util/NativeBigInteger.java | 47 ++++++++++++-------
1 file changed, 29 insertions(+), 18 deletions(-)
diff --git a/core/java/src/net/i2p/util/NativeBigInteger.java b/core/java/src/net/i2p/util/NativeBigInteger.java
index 7a64e24e42..970de52c85 100644
--- a/core/java/src/net/i2p/util/NativeBigInteger.java
+++ b/core/java/src/net/i2p/util/NativeBigInteger.java
@@ -23,6 +23,9 @@ import freenet.support.CPUInformation.CPUInfo;
import freenet.support.CPUInformation.IntelCPUInfo;
import freenet.support.CPUInformation.UnknownCPUException;
+import net.i2p.I2PAppContext;
+import net.i2p.util.Log;
+
/**
*
BigInteger that takes advantage of the jbigi library for the modPow operation,
* which accounts for a massive segment of the processing cost of asymmetric
@@ -89,6 +92,9 @@ public class NativeBigInteger extends BigInteger {
* do we want to dump some basic success/failure info to stderr during
* initialization? this would otherwise use the Log component, but this makes
* it easier for other systems to reuse this class
+ *
+ * Well, we really want to use Log so if you are one of those "other systems"
+ * then comment out the I2PAppContext usage below.
*/
private static final boolean _doLog = System.getProperty("jbigi.dontLog") == null;
@@ -401,38 +407,32 @@ public class NativeBigInteger extends BigInteger {
boolean loaded = loadGeneric("jbigi");
if (loaded) {
_nativeOk = true;
- if (_doLog)
- System.err.println("INFO: Locally optimized native BigInteger loaded from the library path");
+ info("Locally optimized native BigInteger library loaded from the library path");
} else {
loaded = loadFromResource("jbigi");
if (loaded) {
_nativeOk = true;
- if (_doLog)
- System.err.println("INFO: Locally optimized native BigInteger loaded from resource");
+ info("Locally optimized native BigInteger library loaded from resource");
} else {
loaded = loadFromResource(true);
if (loaded) {
_nativeOk = true;
- if (_doLog)
- System.err.println("INFO: Optimized native BigInteger library '"+getResourceName(true)+"' loaded from resource");
+ info("Optimized native BigInteger library '"+getResourceName(true)+"' loaded from resource");
} else {
loaded = loadGeneric(true);
if (loaded) {
_nativeOk = true;
- if (_doLog)
- System.err.println("INFO: Optimized native BigInteger library '"+getMiddleName(true)+"' loaded from somewhere in the path");
+ info("Optimized native BigInteger library '"+getMiddleName(true)+"' loaded from somewhere in the path");
} else {
loaded = loadFromResource(false);
if (loaded) {
_nativeOk = true;
- if (_doLog)
- System.err.println("INFO: Non-optimized native BigInteger library '"+getResourceName(false)+"' loaded from resource");
+ info("Non-optimized native BigInteger library '"+getResourceName(false)+"' loaded from resource");
} else {
loaded = loadGeneric(false);
if (loaded) {
_nativeOk = true;
- if (_doLog)
- System.err.println("INFO: Non-optimized native BigInteger library '"+getMiddleName(false)+"' loaded from somewhere in the path");
+ info("Non-optimized native BigInteger library '"+getMiddleName(false)+"' loaded from somewhere in the path");
} else {
_nativeOk = false;
}
@@ -442,16 +442,27 @@ public class NativeBigInteger extends BigInteger {
}
}
}
- if (_doLog && !_nativeOk)
- System.err.println("INFO: Native BigInteger library jbigi not loaded - using pure java");
+ if (!_nativeOk) {
+ warn("Native BigInteger library jbigi not loaded - using pure Java - " +
+ "poor performance may result - see http://www.i2p2.i2p/jbigi.html for help");
+ }
}catch(Exception e){
- if (_doLog) {
- System.err.println("INFO: Native BigInteger library jbigi not loaded, reason: '"+e.getMessage()+"' - using pure java");
- e.printStackTrace();
- }
+ warn("Native BigInteger library jbigi not loaded, reason: '"+e.getMessage()+"' - using pure java");
}
}
+ private static void info(String s) {
+ if(_doLog)
+ System.err.println("INFO: " + s);
+ I2PAppContext.getGlobalContext().logManager().getLog(NativeBigInteger.class).info(s);
+ }
+
+ private static void warn(String s) {
+ if(_doLog)
+ System.err.println("WARNING: " + s);
+ I2PAppContext.getGlobalContext().logManager().getLog(NativeBigInteger.class).warn(s);
+ }
+
/**
*
Try loading it from an explictly build jbigi.dll / libjbigi.so first, before
* looking into a jbigi.jar for any other libraries.
From 84bd8274ad627e376c6e2320849d95b64f4d491e Mon Sep 17 00:00:00 2001
From: zzz
Date: Wed, 25 Feb 2009 00:05:30 +0000
Subject: [PATCH 015/688] * Router: Move addShutdownTask from Router to
I2PAppContext so that apps can register more easily
---
.../src/org/klomp/snark/SnarkManager.java | 5 ++--
.../net/i2p/router/web/ConfigNetHandler.java | 2 +-
.../net/i2p/router/web/ConfigRestartBean.java | 8 +++---
.../i2p/router/web/ConfigServiceHandler.java | 12 ++++-----
.../src/net/i2p/router/web/UpdateHandler.java | 2 +-
core/java/src/net/i2p/I2PAppContext.java | 12 +++++++++
router/java/src/net/i2p/router/Router.java | 26 ++++++-------------
7 files changed, 34 insertions(+), 33 deletions(-)
diff --git a/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java b/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java
index 7b62ace843..54367af1ac 100644
--- a/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java
+++ b/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java
@@ -81,8 +81,7 @@ public class SnarkManager implements Snark.CompleteListener {
I2PAppThread monitor = new I2PAppThread(new DirMonitor(), "Snark DirMonitor");
monitor.setDaemon(true);
monitor.start();
- if (_context instanceof RouterContext)
- ((RouterContext)_context).router().addShutdownTask(new SnarkManagerShutdown());
+ _context.addShutdownTask(new SnarkManagerShutdown());
}
/** hook to I2PSnarkUtil for the servlet */
@@ -539,7 +538,7 @@ public class SnarkManager implements Snark.CompleteListener {
String announce = info.getAnnounce();
// basic validation of url
if ((!announce.startsWith("http://")) ||
- (announce.indexOf(".i2p/") < 0))
+ (announce.indexOf(".i2p/") < 0)) // need to do better than this
return "Non-i2p tracker in " + info.getName() + ", deleting it";
List files = info.getFiles();
if ( (files != null) && (files.size() > MAX_FILES_PER_TORRENT) ) {
diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ConfigNetHandler.java b/apps/routerconsole/java/src/net/i2p/router/web/ConfigNetHandler.java
index 0ddcd58a9d..a4fe7483ec 100644
--- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigNetHandler.java
+++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigNetHandler.java
@@ -237,7 +237,7 @@ public class ConfigNetHandler extends FormHandler {
private void hiddenSwitch() {
// Full restart required to generate new keys
- _context.router().addShutdownTask(new UpdateWrapperManagerAndRekeyTask(Router.EXIT_GRACEFUL_RESTART));
+ _context.addShutdownTask(new UpdateWrapperManagerAndRekeyTask(Router.EXIT_GRACEFUL_RESTART));
_context.router().shutdownGracefully(Router.EXIT_GRACEFUL_RESTART);
}
diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ConfigRestartBean.java b/apps/routerconsole/java/src/net/i2p/router/web/ConfigRestartBean.java
index 75a8108c50..e8eb6b26d3 100644
--- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigRestartBean.java
+++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigRestartBean.java
@@ -25,20 +25,20 @@ public class ConfigRestartBean {
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.addShutdownTask(new ConfigServiceHandler.UpdateWrapperManagerTask(Router.EXIT_HARD));
//ctx.router().shutdown(Router.EXIT_HARD); // never returns
ctx.router().shutdownGracefully(Router.EXIT_HARD); // give the UI time to respond
} else if ("cancelShutdown".equals(action)) {
ctx.router().cancelGracefulShutdown();
} else if ("restartImmediate".equals(action)) {
- ctx.router().addShutdownTask(new ConfigServiceHandler.UpdateWrapperManagerTask(Router.EXIT_HARD_RESTART));
+ ctx.addShutdownTask(new ConfigServiceHandler.UpdateWrapperManagerTask(Router.EXIT_HARD_RESTART));
//ctx.router().shutdown(Router.EXIT_HARD_RESTART); // never returns
ctx.router().shutdownGracefully(Router.EXIT_HARD_RESTART); // give the UI time to respond
} else if ("restart".equals(action)) {
- ctx.router().addShutdownTask(new ConfigServiceHandler.UpdateWrapperManagerTask(Router.EXIT_GRACEFUL_RESTART));
+ ctx.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.addShutdownTask(new ConfigServiceHandler.UpdateWrapperManagerTask(Router.EXIT_GRACEFUL));
ctx.router().shutdownGracefully();
}
}
diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ConfigServiceHandler.java b/apps/routerconsole/java/src/net/i2p/router/web/ConfigServiceHandler.java
index bd3bf7a5ea..8d3e5725ce 100644
--- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigServiceHandler.java
+++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigServiceHandler.java
@@ -53,31 +53,31 @@ public class ConfigServiceHandler extends FormHandler {
if (_action == null) return;
if ("Shutdown gracefully".equals(_action)) {
- _context.router().addShutdownTask(new UpdateWrapperManagerTask(Router.EXIT_GRACEFUL));
+ _context.addShutdownTask(new UpdateWrapperManagerTask(Router.EXIT_GRACEFUL));
_context.router().shutdownGracefully();
addFormNotice("Graceful shutdown initiated");
} else if ("Shutdown immediately".equals(_action)) {
- _context.router().addShutdownTask(new UpdateWrapperManagerTask(Router.EXIT_HARD));
+ _context.addShutdownTask(new UpdateWrapperManagerTask(Router.EXIT_HARD));
_context.router().shutdown(Router.EXIT_HARD);
addFormNotice("Shutdown immediately! boom bye bye bad bwoy");
} else if ("Cancel graceful shutdown".equals(_action)) {
_context.router().cancelGracefulShutdown();
addFormNotice("Graceful shutdown cancelled");
} else if ("Graceful restart".equals(_action)) {
- _context.router().addShutdownTask(new UpdateWrapperManagerTask(Router.EXIT_GRACEFUL_RESTART));
+ _context.addShutdownTask(new UpdateWrapperManagerTask(Router.EXIT_GRACEFUL_RESTART));
_context.router().shutdownGracefully(Router.EXIT_GRACEFUL_RESTART);
addFormNotice("Graceful restart requested");
} else if ("Hard restart".equals(_action)) {
- _context.router().addShutdownTask(new UpdateWrapperManagerTask(Router.EXIT_HARD_RESTART));
+ _context.addShutdownTask(new UpdateWrapperManagerTask(Router.EXIT_HARD_RESTART));
_context.router().shutdown(Router.EXIT_HARD_RESTART);
addFormNotice("Hard restart requested");
} else if ("Rekey and Restart".equals(_action)) {
addFormNotice("Rekeying after graceful restart");
- _context.router().addShutdownTask(new UpdateWrapperManagerAndRekeyTask(Router.EXIT_GRACEFUL_RESTART));
+ _context.addShutdownTask(new UpdateWrapperManagerAndRekeyTask(Router.EXIT_GRACEFUL_RESTART));
_context.router().shutdownGracefully(Router.EXIT_GRACEFUL_RESTART);
} else if ("Rekey and Shutdown".equals(_action)) {
addFormNotice("Rekeying after graceful shutdown");
- _context.router().addShutdownTask(new UpdateWrapperManagerAndRekeyTask(Router.EXIT_GRACEFUL));
+ _context.addShutdownTask(new UpdateWrapperManagerAndRekeyTask(Router.EXIT_GRACEFUL));
_context.router().shutdownGracefully(Router.EXIT_GRACEFUL);
} else if ("Run I2P on startup".equals(_action)) {
installService();
diff --git a/apps/routerconsole/java/src/net/i2p/router/web/UpdateHandler.java b/apps/routerconsole/java/src/net/i2p/router/web/UpdateHandler.java
index be39da2fd6..83495f33e1 100644
--- a/apps/routerconsole/java/src/net/i2p/router/web/UpdateHandler.java
+++ b/apps/routerconsole/java/src/net/i2p/router/web/UpdateHandler.java
@@ -185,7 +185,7 @@ public class UpdateHandler {
}
private void restart() {
- _context.router().addShutdownTask(new ConfigServiceHandler.UpdateWrapperManagerTask(Router.EXIT_GRACEFUL_RESTART));
+ _context.addShutdownTask(new ConfigServiceHandler.UpdateWrapperManagerTask(Router.EXIT_GRACEFUL_RESTART));
_context.router().shutdownGracefully(Router.EXIT_GRACEFUL_RESTART);
}
diff --git a/core/java/src/net/i2p/I2PAppContext.java b/core/java/src/net/i2p/I2PAppContext.java
index 6b3b0fd5bf..f26f74ab7b 100644
--- a/core/java/src/net/i2p/I2PAppContext.java
+++ b/core/java/src/net/i2p/I2PAppContext.java
@@ -23,6 +23,7 @@ import net.i2p.crypto.SessionKeyManager;
import net.i2p.data.RoutingKeyGenerator;
import net.i2p.stat.StatManager;
import net.i2p.util.Clock;
+import net.i2p.util.ConcurrentHashSet;
import net.i2p.util.FortunaRandomSource;
import net.i2p.util.KeyRing;
import net.i2p.util.LogManager;
@@ -94,6 +95,7 @@ public class I2PAppContext {
private volatile boolean _randomInitialized;
private volatile boolean _keyGeneratorInitialized;
protected volatile boolean _keyRingInitialized; // used in RouterContext
+ private Set _shutdownTasks;
/**
@@ -152,6 +154,7 @@ public class I2PAppContext {
_elGamalAESEngineInitialized = false;
_logManagerInitialized = false;
_keyRingInitialized = false;
+ _shutdownTasks = new ConcurrentHashSet(0);
}
/**
@@ -557,4 +560,13 @@ public class I2PAppContext {
_randomInitialized = true;
}
}
+
+ public void addShutdownTask(Runnable task) {
+ _shutdownTasks.add(task);
+ }
+
+ public Set getShutdownTasks() {
+ return new HashSet(_shutdownTasks);
+ }
+
}
diff --git a/router/java/src/net/i2p/router/Router.java b/router/java/src/net/i2p/router/Router.java
index 77e4b19681..13e801458c 100644
--- a/router/java/src/net/i2p/router/Router.java
+++ b/router/java/src/net/i2p/router/Router.java
@@ -65,7 +65,6 @@ public class Router {
private I2PThread.OOMEventListener _oomListener;
private ShutdownHook _shutdownHook;
private I2PThread _gracefulShutdownDetector;
- private Set _shutdownTasks;
public final static String PROP_CONFIG_FILE = "router.configLocation";
@@ -171,7 +170,6 @@ public class Router {
watchdog.setDaemon(true);
watchdog.start();
- _shutdownTasks = new HashSet(0);
}
/**
@@ -491,13 +489,12 @@ public class Router {
*/
public void rebuildNewIdentity() {
killKeys();
- try {
- for (Iterator iter = _shutdownTasks.iterator(); iter.hasNext(); ) {
- Runnable task = (Runnable)iter.next();
+ for (Runnable task : _context.getShutdownTasks()) {
+ try {
task.run();
+ } catch (Throwable t) {
+ _log.log(Log.CRIT, "Error running shutdown task", t);
}
- } catch (Throwable t) {
- _log.log(Log.CRIT, "Error running shutdown task", t);
}
// hard and ugly
finalShutdown(EXIT_HARD_RESTART);
@@ -782,12 +779,6 @@ public class Router {
buf.setLength(0);
}
- public void addShutdownTask(Runnable task) {
- synchronized (_shutdownTasks) {
- _shutdownTasks.add(task);
- }
- }
-
public static final int EXIT_GRACEFUL = 2;
public static final int EXIT_HARD = 3;
public static final int EXIT_OOM = 10;
@@ -800,13 +791,12 @@ public class Router {
I2PThread.removeOOMEventListener(_oomListener);
// Run the shutdown hooks first in case they want to send some goodbye messages
// Maybe we need a delay after this too?
- try {
- for (Iterator iter = _shutdownTasks.iterator(); iter.hasNext(); ) {
- Runnable task = (Runnable)iter.next();
+ for (Runnable task : _context.getShutdownTasks()) {
+ try {
task.run();
+ } catch (Throwable t) {
+ _log.log(Log.CRIT, "Error running shutdown task", t);
}
- } catch (Throwable t) {
- _log.log(Log.CRIT, "Error running shutdown task", t);
}
try { _context.clientManager().shutdown(); } catch (Throwable t) { _log.log(Log.CRIT, "Error shutting down the client manager", t); }
try { _context.jobQueue().shutdown(); } catch (Throwable t) { _log.log(Log.CRIT, "Error shutting down the job queue", t); }
From d222c7a9986dc7bfdfb9dc1159ae46df9388ba01 Mon Sep 17 00:00:00 2001
From: zzz
Date: Wed, 25 Feb 2009 01:18:38 +0000
Subject: [PATCH 016/688] move dest-to-hash conversion to new helper class
---
.../i2p/router/web/ConfigKeyringHandler.java | 21 +----
core/java/src/net/i2p/util/ConvertToHash.java | 76 +++++++++++++++++++
2 files changed, 79 insertions(+), 18 deletions(-)
create mode 100644 core/java/src/net/i2p/util/ConvertToHash.java
diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ConfigKeyringHandler.java b/apps/routerconsole/java/src/net/i2p/router/web/ConfigKeyringHandler.java
index 09f0905bf3..b43bc4d1f1 100644
--- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigKeyringHandler.java
+++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigKeyringHandler.java
@@ -2,9 +2,9 @@ package net.i2p.router.web;
import net.i2p.I2PAppContext;
import net.i2p.data.DataFormatException;
-import net.i2p.data.Destination;
import net.i2p.data.Hash;
import net.i2p.data.SessionKey;
+import net.i2p.util.ConvertToHash;
/**
* Support additions via B64 Destkey, B64 Desthash, or blahblah.i2p
@@ -19,27 +19,12 @@ public class ConfigKeyringHandler extends FormHandler {
addFormError("You must enter a destination and a key");
return;
}
- Hash h = new Hash();
- try {
- h.fromBase64(_peer);
- } catch (DataFormatException dfe) {}
- if (h.getData() == null) {
- try {
- Destination d = new Destination();
- d.fromBase64(_peer);
- h = d.calculateHash();
- } catch (DataFormatException dfe) {}
- }
- if (h.getData() == null) {
- Destination d = _context.namingService().lookup(_peer);
- if (d != null)
- h = d.calculateHash();
- }
+ Hash h = ConvertToHash.getHash(_peer);
SessionKey sk = new SessionKey();
try {
sk.fromBase64(_key);
} catch (DataFormatException dfe) {}
- if (h.getData() != null && sk.getData() != null) {
+ if (h != null && h.getData() != null && sk.getData() != null) {
_context.keyRing().put(h, sk);
addFormNotice("Key for " + h.toBase64() + " added to keyring");
} else {
diff --git a/core/java/src/net/i2p/util/ConvertToHash.java b/core/java/src/net/i2p/util/ConvertToHash.java
new file mode 100644
index 0000000000..0878556400
--- /dev/null
+++ b/core/java/src/net/i2p/util/ConvertToHash.java
@@ -0,0 +1,76 @@
+package net.i2p.util;
+
+import net.i2p.I2PAppContext;
+import net.i2p.data.Base32;
+import net.i2p.data.DataFormatException;
+import net.i2p.data.Destination;
+import net.i2p.data.Hash;
+
+/**
+ * Convert any kind of destination String to a hash
+ * Supported:
+ * Base64 dest
+ * Base64 dest.i2p
+ * Base64 Hash
+ * Base32 Hash
+ * Base32 desthash.b32.i2p
+ * example.i2p
+ *
+ * @return null on failure
+ *
+ * @author zzz
+ */
+public class ConvertToHash {
+
+ public static Hash getHash(String peer) {
+ if (peer == null)
+ return null;
+ Hash h = new Hash();
+ String peerLC = peer.toLowerCase();
+ // b64 hash
+ if (peer.length() == 44 && !peerLC.endsWith(".i2p")) {
+ try {
+ h.fromBase64(peer);
+ } catch (DataFormatException dfe) {}
+ }
+ // b64 dest.i2p
+ if (h.getData() == null && peer.length() >= 520 && peerLC.endsWith(".i2p")) {
+ try {
+ Destination d = new Destination();
+ d.fromBase64(peer.substring(0, peer.length() - 4));
+ h = d.calculateHash();
+ } catch (DataFormatException dfe) {}
+ }
+ // b64 dest
+ if (h.getData() == null && peer.length() >= 516 && !peerLC.endsWith(".i2p")) {
+ try {
+ Destination d = new Destination();
+ d.fromBase64(peer);
+ h = d.calculateHash();
+ } catch (DataFormatException dfe) {}
+ }
+ // b32 hash.b32.i2p
+ // do this here rather than in naming service so it will work
+ // even if the leaseset is not found
+ if (h.getData() == null && peer.length() == 60 && peerLC.endsWith(".b32.i2p")) {
+ byte[] b = Base32.decode(peer.substring(0, 52));
+ if (b != null && b.length == Hash.HASH_LENGTH)
+ h.setData(b);
+ }
+ // b32 hash
+ if (h.getData() == null && peer.length() == 52 && !peerLC.endsWith(".i2p")) {
+ byte[] b = Base32.decode(peer);
+ if (b != null && b.length == Hash.HASH_LENGTH)
+ h.setData(b);
+ }
+ // example.i2p
+ if (h.getData() == null) {
+ Destination d = I2PAppContext.getGlobalContext().namingService().lookup(peer);
+ if (d != null)
+ h = d.calculateHash();
+ }
+ if (h.getData() == null)
+ return null;
+ return h;
+ }
+}
From 56473c6b65bccf9b8d410141861ab20a1011c299 Mon Sep 17 00:00:00 2001
From: zzz
Date: Wed, 25 Feb 2009 02:00:13 +0000
Subject: [PATCH 017/688] add reverse lookup by hash
---
.../client/naming/HostsTxtNamingService.java | 32 +++++++++++++++++++
.../net/i2p/client/naming/NamingService.java | 2 ++
2 files changed, 34 insertions(+)
diff --git a/core/java/src/net/i2p/client/naming/HostsTxtNamingService.java b/core/java/src/net/i2p/client/naming/HostsTxtNamingService.java
index 9fa227f817..054bd9d8f1 100644
--- a/core/java/src/net/i2p/client/naming/HostsTxtNamingService.java
+++ b/core/java/src/net/i2p/client/naming/HostsTxtNamingService.java
@@ -16,8 +16,10 @@ import java.util.Set;
import java.util.StringTokenizer;
import net.i2p.I2PAppContext;
+import net.i2p.data.DataFormatException;
import net.i2p.data.DataHelper;
import net.i2p.data.Destination;
+import net.i2p.data.Hash;
import net.i2p.util.Log;
/**
@@ -135,4 +137,34 @@ public class HostsTxtNamingService extends NamingService {
}
return null;
}
+
+ @Override
+ public String reverseLookup(Hash h) {
+ List filenames = getFilenames();
+ for (int i = 0; i < filenames.size(); i++) {
+ String hostsfile = (String)filenames.get(i);
+ Properties hosts = new Properties();
+ try {
+ File f = new File(hostsfile);
+ if ( (f.exists()) && (f.canRead()) ) {
+ DataHelper.loadProps(hosts, f, true);
+ Set keyset = hosts.keySet();
+ Iterator iter = keyset.iterator();
+ while (iter.hasNext()) {
+ String host = (String)iter.next();
+ String key = hosts.getProperty(host);
+ try {
+ Destination destkey = new Destination();
+ destkey.fromBase64(key);
+ if (h.equals(destkey.calculateHash()))
+ return host;
+ } catch (DataFormatException dfe) {}
+ }
+ }
+ } catch (Exception ioe) {
+ _log.error("Error loading hosts file " + hostsfile, ioe);
+ }
+ }
+ return null;
+ }
}
diff --git a/core/java/src/net/i2p/client/naming/NamingService.java b/core/java/src/net/i2p/client/naming/NamingService.java
index 5b61b1bcf8..ee02ec9111 100644
--- a/core/java/src/net/i2p/client/naming/NamingService.java
+++ b/core/java/src/net/i2p/client/naming/NamingService.java
@@ -16,6 +16,7 @@ import java.util.Map;
import net.i2p.I2PAppContext;
import net.i2p.data.DataFormatException;
import net.i2p.data.Destination;
+import net.i2p.data.Hash;
import net.i2p.util.Log;
/**
@@ -61,6 +62,7 @@ public abstract class NamingService {
* null if no reverse lookup is possible.
*/
public abstract String reverseLookup(Destination dest);
+ public String reverseLookup(Hash h) { return null; };
/**
* Check if host name is valid Base64 encoded dest and return this
From 6648e182aef3909b8927e968640c4a43a663e915 Mon Sep 17 00:00:00 2001
From: zzz
Date: Thu, 26 Feb 2009 14:45:45 +0000
Subject: [PATCH 018/688] * I2CP Client: Add support for muxing
---
.../net/i2p/client/streaming/PacketQueue.java | 12 +-
.../src/net/i2p/client/I2PClientImpl.java | 2 +-
core/java/src/net/i2p/client/I2PSession.java | 22 ++
.../i2p/client/I2PSessionDemultiplexer.java | 135 ++++++++
.../src/net/i2p/client/I2PSessionImpl.java | 8 +-
.../src/net/i2p/client/I2PSessionImpl2.java | 29 +-
.../net/i2p/client/I2PSessionListener.java | 4 +-
.../net/i2p/client/I2PSessionMuxedImpl.java | 319 ++++++++++++++++++
.../i2p/client/I2PSessionMuxedListener.java | 62 ++++
9 files changed, 581 insertions(+), 12 deletions(-)
create mode 100644 core/java/src/net/i2p/client/I2PSessionDemultiplexer.java
create mode 100644 core/java/src/net/i2p/client/I2PSessionMuxedImpl.java
create mode 100644 core/java/src/net/i2p/client/I2PSessionMuxedListener.java
diff --git a/apps/streaming/java/src/net/i2p/client/streaming/PacketQueue.java b/apps/streaming/java/src/net/i2p/client/streaming/PacketQueue.java
index a56e7753dd..e91cbdb7d4 100644
--- a/apps/streaming/java/src/net/i2p/client/streaming/PacketQueue.java
+++ b/apps/streaming/java/src/net/i2p/client/streaming/PacketQueue.java
@@ -89,9 +89,17 @@ class PacketQueue {
// so if we retransmit it will use a new tunnel/lease combo
expires = rpe.getNextSendTime() - 500;
if (expires > 0)
- sent = _session.sendMessage(packet.getTo(), buf, 0, size, keyUsed, tagsSent, expires);
+ // I2PSessionImpl2
+ //sent = _session.sendMessage(packet.getTo(), buf, 0, size, keyUsed, tagsSent, expires);
+ // I2PSessionMuxedImpl
+ sent = _session.sendMessage(packet.getTo(), buf, 0, size, keyUsed, tagsSent, expires,
+ I2PSession.PROTO_STREAMING, I2PSession.PORT_UNSPECIFIED, I2PSession.PORT_UNSPECIFIED);
else
- sent = _session.sendMessage(packet.getTo(), buf, 0, size, keyUsed, tagsSent);
+ // I2PSessionImpl2
+ //sent = _session.sendMessage(packet.getTo(), buf, 0, size, keyUsed, tagsSent, 0);
+ // I2PSessionMuxedImpl
+ sent = _session.sendMessage(packet.getTo(), buf, 0, size, keyUsed, tagsSent,
+ I2PSession.PROTO_STREAMING, I2PSession.PORT_UNSPECIFIED, I2PSession.PORT_UNSPECIFIED);
end = _context.clock().now();
if ( (end-begin > 1000) && (_log.shouldLog(Log.WARN)) )
diff --git a/core/java/src/net/i2p/client/I2PClientImpl.java b/core/java/src/net/i2p/client/I2PClientImpl.java
index 4783458a3a..5b1b44867d 100644
--- a/core/java/src/net/i2p/client/I2PClientImpl.java
+++ b/core/java/src/net/i2p/client/I2PClientImpl.java
@@ -77,6 +77,6 @@ class I2PClientImpl implements I2PClient {
*
*/
public I2PSession createSession(I2PAppContext context, InputStream destKeyStream, Properties options) throws I2PSessionException {
- return new I2PSessionImpl2(context, destKeyStream, options); // thread safe
+ return new I2PSessionMuxedImpl(context, destKeyStream, options); // thread safe and muxed
}
}
diff --git a/core/java/src/net/i2p/client/I2PSession.java b/core/java/src/net/i2p/client/I2PSession.java
index d8c64f2222..1776af5c0f 100644
--- a/core/java/src/net/i2p/client/I2PSession.java
+++ b/core/java/src/net/i2p/client/I2PSession.java
@@ -40,6 +40,8 @@ public interface I2PSession {
*/
public boolean sendMessage(Destination dest, byte[] payload) throws I2PSessionException;
public boolean sendMessage(Destination dest, byte[] payload, int offset, int size) throws I2PSessionException;
+ /** See I2PSessionMuxedImpl for details */
+ public boolean sendMessage(Destination dest, byte[] payload, int proto, int fromport, int toport) throws I2PSessionException;
/**
* Like sendMessage above, except the key used and the tags sent are exposed to the
@@ -71,6 +73,12 @@ public interface I2PSession {
public boolean sendMessage(Destination dest, byte[] payload, SessionKey keyUsed, Set tagsSent) throws I2PSessionException;
public boolean sendMessage(Destination dest, byte[] payload, int offset, int size, SessionKey keyUsed, Set tagsSent) throws I2PSessionException;
public boolean sendMessage(Destination dest, byte[] payload, int offset, int size, SessionKey keyUsed, Set tagsSent, long expire) throws I2PSessionException;
+ /** See I2PSessionMuxedImpl for details */
+ public boolean sendMessage(Destination dest, byte[] payload, int offset, int size, SessionKey keyUsed, Set tagsSent,
+ int proto, int fromport, int toport) throws I2PSessionException;
+ /** See I2PSessionMuxedImpl for details */
+ public boolean sendMessage(Destination dest, byte[] payload, int offset, int size, SessionKey keyUsed, Set tagsSent, long expire,
+ int proto, int fromport, int toport) throws I2PSessionException;
/** Receive a message that the router has notified the client about, returning
* the payload.
@@ -134,4 +142,18 @@ public interface I2PSession {
*
*/
public Destination lookupDest(Hash h) throws I2PSessionException;
+
+ /** See I2PSessionMuxedImpl for details */
+ public void addSessionListener(I2PSessionListener lsnr, int proto, int port);
+ /** See I2PSessionMuxedImpl for details */
+ public void addMuxedSessionListener(I2PSessionMuxedListener l, int proto, int port);
+ /** See I2PSessionMuxedImpl for details */
+ public void removeListener(int proto, int port);
+
+ public static final int PORT_ANY = 0;
+ public static final int PORT_UNSPECIFIED = 0;
+ public static final int PROTO_ANY = 0;
+ public static final int PROTO_UNSPECIFIED = 0;
+ public static final int PROTO_STREAMING = 6;
+ public static final int PROTO_DATAGRAM = 17;
}
diff --git a/core/java/src/net/i2p/client/I2PSessionDemultiplexer.java b/core/java/src/net/i2p/client/I2PSessionDemultiplexer.java
new file mode 100644
index 0000000000..9a1ff42e31
--- /dev/null
+++ b/core/java/src/net/i2p/client/I2PSessionDemultiplexer.java
@@ -0,0 +1,135 @@
+package net.i2p.client;
+
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.Map;
+
+import net.i2p.I2PAppContext;
+import net.i2p.util.Log;
+
+/*
+ * public domain
+ */
+
+/**
+ * Implement multiplexing with a 1-byte 'protocol' and a two-byte 'port'.
+ * Listeners register with either addListener() or addMuxedListener(),
+ * depending on whether they want to hear about the
+ * protocol, from port, and to port for every received message.
+ *
+ * This only calls one listener, not all that apply.
+ *
+ * @author zzz
+ */
+public class I2PSessionDemultiplexer implements I2PSessionMuxedListener {
+ private Log _log;
+ private Map _listeners;
+
+ public I2PSessionDemultiplexer(I2PAppContext ctx) {
+ _log = ctx.logManager().getLog(I2PSessionDemultiplexer.class);
+ _listeners = new ConcurrentHashMap();
+ }
+
+ /** unused */
+ public void messageAvailable(I2PSession session, int msgId, long size) {}
+
+ public void messageAvailable(I2PSession session, int msgId, long size, int proto, int fromport, int toport ) {
+ I2PSessionMuxedListener l = findListener(proto, toport);
+ if (l != null)
+ l.messageAvailable(session, msgId, size, proto, fromport, toport);
+ else {
+ // no listener, throw it out
+ _log.error("No listener found for proto: " + proto + " port: " + toport + "msg id: " + msgId +
+ " from pool of " + _listeners.size() + " listeners");
+ try {
+ session.receiveMessage(msgId);
+ } catch (I2PSessionException ise) {}
+ }
+ }
+
+ public void reportAbuse(I2PSession session, int severity) {
+ for (I2PSessionMuxedListener l : _listeners.values())
+ l.reportAbuse(session, severity);
+ }
+
+ public void disconnected(I2PSession session) {
+ for (I2PSessionMuxedListener l : _listeners.values())
+ l.disconnected(session);
+ }
+
+ public void errorOccurred(I2PSession session, String message, Throwable error) {
+ for (I2PSessionMuxedListener l : _listeners.values())
+ l.errorOccurred(session, message, error);
+ }
+
+ /**
+ * For those that don't need to hear about the protocol and ports
+ * in messageAvailable()
+ * (Streaming lib)
+ */
+ public void addListener(I2PSessionListener l, int proto, int port) {
+ _listeners.put(key(proto, port), new NoPortsListener(l));
+ }
+
+ /**
+ * For those that do care
+ * UDP perhaps
+ */
+ public void addMuxedListener(I2PSessionMuxedListener l, int proto, int port) {
+ _listeners.put(key(proto, port), l);
+ }
+
+ public void removeListener(int proto, int port) {
+ _listeners.remove(key(proto, port));
+ }
+
+ /** find the one listener that most specifically matches the request */
+ private I2PSessionMuxedListener findListener(int proto, int port) {
+ I2PSessionMuxedListener rv = getListener(proto, port);
+ if (rv != null) return rv;
+ if (port != I2PSession.PORT_ANY) { // try any port
+ rv = getListener(proto, I2PSession.PORT_ANY);
+ if (rv != null) return rv;
+ }
+ if (proto != I2PSession.PROTO_ANY) { // try any protocol
+ rv = getListener(I2PSession.PROTO_ANY, port);
+ if (rv != null) return rv;
+ }
+ if (proto != I2PSession.PROTO_ANY && port != I2PSession.PORT_ANY) { // try default
+ rv = getListener(I2PSession.PROTO_ANY, I2PSession.PORT_ANY);
+ }
+ return rv;
+ }
+
+ private I2PSessionMuxedListener getListener(int proto, int port) {
+ return _listeners.get(key(proto, port));
+ }
+
+ private Integer key(int proto, int port) {
+ return Integer.valueOf(((port << 8) & 0xffff00) | proto);
+ }
+
+ /** for those that don't care about proto and ports */
+ private static class NoPortsListener implements I2PSessionMuxedListener {
+ private I2PSessionListener _l;
+
+ public NoPortsListener(I2PSessionListener l) {
+ _l = l;
+ }
+
+ public void messageAvailable(I2PSession session, int msgId, long size) {
+ throw new IllegalArgumentException("no");
+ }
+ public void messageAvailable(I2PSession session, int msgId, long size, int proto, int fromport, int toport) {
+ _l.messageAvailable(session, msgId, size);
+ }
+ public void reportAbuse(I2PSession session, int severity) {
+ _l.reportAbuse(session, severity);
+ }
+ public void disconnected(I2PSession session) {
+ _l.disconnected(session);
+ }
+ public void errorOccurred(I2PSession session, String message, Throwable error) {
+ _l.errorOccurred(session, message, error);
+ }
+ }
+}
diff --git a/core/java/src/net/i2p/client/I2PSessionImpl.java b/core/java/src/net/i2p/client/I2PSessionImpl.java
index 00da88aa22..0e13f2c563 100644
--- a/core/java/src/net/i2p/client/I2PSessionImpl.java
+++ b/core/java/src/net/i2p/client/I2PSessionImpl.java
@@ -77,12 +77,12 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
protected OutputStream _out;
/** who we send events to */
- private I2PSessionListener _sessionListener;
+ protected I2PSessionListener _sessionListener;
/** class that generates new messages */
protected I2CPMessageProducer _producer;
/** map of Long --> MessagePayloadMessage */
- private Map _availableMessages;
+ protected Map _availableMessages;
protected I2PClientMessageHandlerMap _handlerMap;
@@ -366,14 +366,14 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
}
SimpleScheduler.getInstance().addEvent(new VerifyUsage(mid), 30*1000);
}
- private class VerifyUsage implements SimpleTimer.TimedEvent {
+ protected class VerifyUsage implements SimpleTimer.TimedEvent {
private Long _msgId;
public VerifyUsage(Long id) { _msgId = id; }
public void timeReached() {
MessagePayloadMessage removed = _availableMessages.remove(_msgId);
if (removed != null && !isClosed())
- _log.log(Log.CRIT, "Message NOT removed! id=" + _msgId + ": " + removed);
+ _log.error("Message NOT removed! id=" + _msgId + ": " + removed);
}
}
diff --git a/core/java/src/net/i2p/client/I2PSessionImpl2.java b/core/java/src/net/i2p/client/I2PSessionImpl2.java
index 56ef88974b..9abce4b72b 100644
--- a/core/java/src/net/i2p/client/I2PSessionImpl2.java
+++ b/core/java/src/net/i2p/client/I2PSessionImpl2.java
@@ -93,7 +93,7 @@ class I2PSessionImpl2 extends I2PSessionImpl {
* set to false.
*/
private static final int DONT_COMPRESS_SIZE = 66;
- private boolean shouldCompress(int size) {
+ protected boolean shouldCompress(int size) {
if (size <= DONT_COMPRESS_SIZE)
return false;
String p = getOptions().getProperty("i2cp.gzip");
@@ -102,12 +102,35 @@ class I2PSessionImpl2 extends I2PSessionImpl {
return SHOULD_COMPRESS;
}
+ public void addSessionListener(I2PSessionListener lsnr, int proto, int port) {
+ throw new IllegalArgumentException("Use MuxedImpl");
+ }
+ public void addMuxedSessionListener(I2PSessionMuxedListener l, int proto, int port) {
+ throw new IllegalArgumentException("Use MuxedImpl");
+ }
+ public void removeListener(int proto, int port) {
+ throw new IllegalArgumentException("Use MuxedImpl");
+ }
+ public boolean sendMessage(Destination dest, byte[] payload, int proto, int fromport, int toport) throws I2PSessionException {
+ throw new IllegalArgumentException("Use MuxedImpl");
+ }
+ public boolean sendMessage(Destination dest, byte[] payload, int offset, int size, SessionKey keyUsed, Set tagsSent,
+ int proto, int fromport, int toport) throws I2PSessionException {
+ throw new IllegalArgumentException("Use MuxedImpl");
+ }
+ public boolean sendMessage(Destination dest, byte[] payload, int offset, int size, SessionKey keyUsed, Set tagsSent, long expire,
+ int proto, int fromport, int toport) throws I2PSessionException {
+ throw new IllegalArgumentException("Use MuxedImpl");
+ }
+
@Override
public boolean sendMessage(Destination dest, byte[] payload) throws I2PSessionException {
return sendMessage(dest, payload, 0, payload.length);
}
public boolean sendMessage(Destination dest, byte[] payload, int offset, int size) throws I2PSessionException {
- return sendMessage(dest, payload, offset, size, new SessionKey(), new HashSet(64), 0);
+ // we don't do end-to-end crypto any more
+ //return sendMessage(dest, payload, offset, size, new SessionKey(), new HashSet(64), 0);
+ return sendMessage(dest, payload, offset, size, null, null, 0);
}
@Override
@@ -173,7 +196,7 @@ class I2PSessionImpl2 extends I2PSessionImpl {
private static final int NUM_TAGS = 50;
- private boolean sendBestEffort(Destination dest, byte payload[], SessionKey keyUsed, Set tagsSent, long expires)
+ protected boolean sendBestEffort(Destination dest, byte payload[], SessionKey keyUsed, Set tagsSent, long expires)
throws I2PSessionException {
SessionKey key = null;
SessionKey newKey = null;
diff --git a/core/java/src/net/i2p/client/I2PSessionListener.java b/core/java/src/net/i2p/client/I2PSessionListener.java
index 4c78c65272..740ebeeab3 100644
--- a/core/java/src/net/i2p/client/I2PSessionListener.java
+++ b/core/java/src/net/i2p/client/I2PSessionListener.java
@@ -20,7 +20,7 @@ public interface I2PSessionListener {
* size # of bytes.
* @param session session to notify
* @param msgId message number available
- * @param size size of the message
+ * @param size size of the message - why it's a long and not an int is a mystery
*/
void messageAvailable(I2PSession session, int msgId, long size);
@@ -42,4 +42,4 @@ public interface I2PSessionListener {
*
*/
void errorOccurred(I2PSession session, String message, Throwable error);
-}
\ No newline at end of file
+}
diff --git a/core/java/src/net/i2p/client/I2PSessionMuxedImpl.java b/core/java/src/net/i2p/client/I2PSessionMuxedImpl.java
new file mode 100644
index 0000000000..1cd7b072a0
--- /dev/null
+++ b/core/java/src/net/i2p/client/I2PSessionMuxedImpl.java
@@ -0,0 +1,319 @@
+package net.i2p.client;
+
+/*
+ * public domain
+ */
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.HashSet;
+import java.util.Properties;
+import java.util.Set;
+
+import net.i2p.I2PAppContext;
+import net.i2p.data.DataHelper;
+import net.i2p.data.Destination;
+import net.i2p.data.SessionKey;
+import net.i2p.data.SessionTag;
+import net.i2p.data.i2cp.MessagePayloadMessage;
+import net.i2p.util.Log;
+import net.i2p.util.SimpleScheduler;
+
+/**
+ * I2PSession with protocol and ports
+ *
+ * Streaming lib has been modified to send I2PSession.PROTO_STREAMING but
+ * still receives all. It sends with fromPort and toPort = 0, and receives on all ports.
+ *
+ * No datagram apps have been modified yet.
+
+ * Therefore the compatibility situation is as follows:
+ *
+ * Compatibility:
+ * old streaming -> new streaming: sends proto anything, rcvs proto anything
+ * new streaming -> old streaming: sends PROTO_STREAMING, ignores rcvd proto
+ * old datagram -> new datagram: sends proto anything, rcvs proto anything
+ * new datagram -> old datagram: sends PROTO_DATAGRAM, ignores rcvd proto
+ * In all the above cases, streaming and datagram receive traffic for the other
+ * protocol, same as before.
+ *
+ * old datagram -> new muxed: doesn't work because the old sends proto 0 but the udp side
+ * of the mux registers with PROTO_DATAGRAM, so the datagrams
+ * go to the streaming side, same as before.
+ * old streaming -> new muxed: works
+ *
+ * Typical Usage:
+ * Streaming + datagrams:
+ * I2PSocketManager sockMgr = getSocketManager();
+ * I2PSession session = sockMgr.getSession();
+ * session.addMuxedSessionListener(myI2PSessionMuxedListener, I2PSession.PROTO_DATAGRAM, I2PSession.PORT_ANY);
+ * * or *
+ * session.addSessionListener(myI2PSessionListener, I2PSession.PROTO_DATAGRAM, I2PSession.PORT_ANY);
+ * session.sendMessage(dest, payload, I2PSession.PROTO_DATAGRAM, fromPort, toPort);
+ *
+ * Datagrams only, with multiple ports:
+ * I2PClient client = I2PClientFactory.createClient();
+ * ...
+ * I2PSession session = client.createSession(...);
+ * session.addMuxedSessionListener(myI2PSessionMuxedListener, I2PSession.PROTO_DATAGRAM, I2PSession.PORT_ANY);
+ * * or *
+ * session.addSessionListener(myI2PSessionListener, I2PSession.PROTO_DATAGRAM, I2PSession.PORT_ANY);
+ * session.sendMessage(dest, payload, I2PSession.PROTO_DATAGRAM, fromPort, toPort);
+ *
+ * Multiple streaming ports:
+ * Needs some streaming lib hacking
+ *
+ * @author zzz
+ */
+class I2PSessionMuxedImpl extends I2PSessionImpl2 implements I2PSession {
+ private I2PSessionDemultiplexer _demultiplexer;
+
+ public I2PSessionMuxedImpl(I2PAppContext ctx, InputStream destKeyStream, Properties options) throws I2PSessionException {
+ super(ctx, destKeyStream, options);
+ // also stored in _sessionListener but we keep it in _demultipexer
+ // as well so we don't have to keep casting
+ _demultiplexer = new I2PSessionDemultiplexer(ctx);
+ super.setSessionListener(_demultiplexer);
+ // discards the one in super(), sorry about that... (no it wasn't started yet)
+ _availabilityNotifier = new MuxedAvailabilityNotifier();
+ }
+
+ /** listen on all protocols and ports */
+ @Override
+ public void setSessionListener(I2PSessionListener lsnr) {
+ _demultiplexer.addListener(lsnr, PROTO_ANY, PORT_ANY);
+ }
+
+ /**
+ * Listen on specified protocol and port.
+ *
+ * An existing listener with the same proto and port is replaced.
+ * Only the listener with the best match is called back for each message.
+ *
+ * @param proto 1-254 or PROTO_ANY for all; recommended:
+ * I2PSession.PROTO_STREAMING
+ * I2PSession.PROTO_DATAGRAM
+ * 255 disallowed
+ * @param port 1-65535 or PORT_ANY for all
+ */
+ public void addSessionListener(I2PSessionListener lsnr, int proto, int port) {
+ _demultiplexer.addListener(lsnr, proto, port);
+ }
+
+ /**
+ * Listen on specified protocol and port, and receive notification
+ * of proto, fromPort, and toPort for every message.
+ * @param proto 1-254 or 0 for all; 255 disallowed
+ * @param port 1-65535 or 0 for all
+ */
+ public void addMuxedSessionListener(I2PSessionMuxedListener l, int proto, int port) {
+ _demultiplexer.addMuxedListener(l, proto, port);
+ }
+
+ /** removes the specified listener (only) */
+ public void removeListener(int proto, int port) {
+ _demultiplexer.removeListener(proto, port);
+ }
+
+ @Override
+ public boolean sendMessage(Destination dest, byte[] payload) throws I2PSessionException {
+ return sendMessage(dest, payload, 0, 0, null, null, 0, PROTO_UNSPECIFIED, PORT_UNSPECIFIED, PORT_UNSPECIFIED);
+ }
+
+ @Override
+ public boolean sendMessage(Destination dest, byte[] payload, int proto, int fromport, int toport) throws I2PSessionException {
+ return sendMessage(dest, payload, 0, 0, null, null, 0, proto, fromport, toport);
+ }
+
+ @Override
+ public boolean sendMessage(Destination dest, byte[] payload, int offset, int size,
+ SessionKey keyUsed, Set tagsSent, long expires)
+ throws I2PSessionException {
+ return sendMessage(dest, payload, offset, size, keyUsed, tagsSent, 0, PROTO_UNSPECIFIED, PORT_UNSPECIFIED, PORT_UNSPECIFIED);
+ }
+
+ @Override
+ public boolean sendMessage(Destination dest, byte[] payload, int offset, int size, SessionKey keyUsed, Set tagsSent,
+ int proto, int fromport, int toport) throws I2PSessionException {
+ return sendMessage(dest, payload, offset, size, keyUsed, tagsSent, 0, proto, fromport, toport);
+ }
+
+ /**
+ * @param proto 1-254 or 0 for unset; recommended:
+ * I2PSession.PROTO_UNSPECIFIED
+ * I2PSession.PROTO_STREAMING
+ * I2PSession.PROTO_DATAGRAM
+ * 255 disallowed
+ * @param fromport 1-65535 or 0 for unset
+ * @param toport 1-65535 or 0 for unset
+ */
+ public boolean sendMessage(Destination dest, byte[] payload, int offset, int size,
+ SessionKey keyUsed, Set tagsSent, long expires,
+ int proto, int fromPort, int toPort)
+ throws I2PSessionException {
+ if (isClosed()) throw new I2PSessionException("Already closed");
+ updateActivity();
+
+ boolean sc = shouldCompress(size);
+ if (sc)
+ payload = DataHelper.compress(payload, offset, size);
+ else
+ payload = DataHelper.compress(payload, offset, size, DataHelper.NO_COMPRESSION);
+
+ setProto(payload, proto);
+ setFromPort(payload, fromPort);
+ setToPort(payload, toPort);
+
+ _context.statManager().addRateData("i2cp.tx.msgCompressed", payload.length, 0);
+ _context.statManager().addRateData("i2cp.tx.msgExpanded", size, 0);
+ return sendBestEffort(dest, payload, keyUsed, tagsSent, expires);
+ }
+
+ /**
+ * Receive a payload message and let the app know its available
+ */
+ @Override
+ public void addNewMessage(MessagePayloadMessage msg) {
+ Long mid = new Long(msg.getMessageId());
+ _availableMessages.put(mid, msg);
+ long id = msg.getMessageId();
+ byte data[] = msg.getPayload().getUnencryptedData();
+ if ((data == null) || (data.length <= 0)) {
+ if (_log.shouldLog(Log.CRIT))
+ _log.log(Log.CRIT, getPrefix() + "addNewMessage of a message with no unencrypted data",
+ new Exception("Empty message"));
+ return;
+ }
+ int size = data.length;
+ if (size < 10) {
+ _log.error(getPrefix() + "length too short for gzip header: " + size);
+ return;
+ }
+ ((MuxedAvailabilityNotifier)_availabilityNotifier).available(id, size, getProto(msg),
+ getFromPort(msg), getToPort(msg));
+ SimpleScheduler.getInstance().addEvent(new VerifyUsage(mid), 30*1000);
+ }
+
+ protected class MuxedAvailabilityNotifier extends AvailabilityNotifier {
+ private LinkedBlockingQueue _msgs;
+ private boolean _alive;
+ private static final int POISON_SIZE = -99999;
+
+ public MuxedAvailabilityNotifier() {
+ _msgs = new LinkedBlockingQueue();
+ }
+
+ public void stopNotifying() {
+ _msgs.clear();
+ if (_alive) {
+ _alive = false;
+ try {
+ _msgs.put(new MsgData(0, POISON_SIZE, 0, 0, 0));
+ } catch (InterruptedException ie) {}
+ }
+ }
+
+ /** unused */
+ public void available(long msgId, int size) { throw new IllegalArgumentException("no"); }
+
+ public void available(long msgId, int size, int proto, int fromPort, int toPort) {
+ try {
+ _msgs.put(new MsgData((int)(msgId & 0xffffffff), size, proto, fromPort, toPort));
+ } catch (InterruptedException ie) {}
+ }
+
+ public void run() {
+ _alive = true;
+ while (true) {
+ MsgData msg;
+ try {
+ msg = _msgs.take();
+ } catch (InterruptedException ie) {
+ continue;
+ }
+ if (msg.size == POISON_SIZE)
+ break;
+ try {
+ _demultiplexer.messageAvailable(I2PSessionMuxedImpl.this, msg.id,
+ msg.size, msg.proto, msg.fromPort, msg.toPort);
+ } catch (Exception e) {
+ _log.error("Error notifying app of message availability");
+ }
+ }
+ }
+ }
+
+ /** let's keep this simple */
+ private static class MsgData {
+ public int id, size, proto, fromPort, toPort;
+ public MsgData(int i, int s, int p, int f, int t) {
+ id = i;
+ size = s;
+ proto = p;
+ fromPort = f;
+ toPort = t;
+ }
+ }
+
+ /**
+ * No, we couldn't put any protocol byte in front of everything and
+ * keep backward compatibility. But there are several bytes that
+ * are unused AND unchecked in the gzip header in releases <= 0.7.
+ * So let's use 5 of them for a protocol and two 2-byte ports.
+ *
+ * Following are all the methods to hide the
+ * protocol, fromPort, and toPort in the gzip header
+ *
+ * The fields used are all ignored on receive in ResettableGzipInputStream
+ *
+ * See also ResettableGzipOutputStream.
+ * Ref: RFC 1952
+ *
+ */
+
+ /** OS byte in gzip header */
+ private static final int PROTO_BYTE = 9;
+
+ /** Upper two bytes of MTIME in gzip header */
+ private static final int FROMPORT_BYTES = 4;
+
+ /** Lower two bytes of MTIME in gzip header */
+ private static final int TOPORT_BYTES = 6;
+
+ /** Non-muxed sets the OS byte to 0xff */
+ private static int getProto(MessagePayloadMessage msg) {
+ int rv = getByte(msg, PROTO_BYTE) & 0xff;
+ return rv == 0xff ? PROTO_UNSPECIFIED : rv;
+ }
+
+ /** Non-muxed sets the MTIME bytes to 0 */
+ private static int getFromPort(MessagePayloadMessage msg) {
+ return (((getByte(msg, FROMPORT_BYTES) & 0xff) << 8) |
+ (getByte(msg, FROMPORT_BYTES + 1) & 0xff));
+ }
+
+ /** Non-muxed sets the MTIME bytes to 0 */
+ private static int getToPort(MessagePayloadMessage msg) {
+ return (((getByte(msg, TOPORT_BYTES) & 0xff) << 8) |
+ (getByte(msg, TOPORT_BYTES + 1) & 0xff));
+ }
+
+ private static int getByte(MessagePayloadMessage msg, int i) {
+ return msg.getPayload().getUnencryptedData()[i] & 0xff;
+ }
+
+ private static void setProto(byte[] payload, int p) {
+ payload[PROTO_BYTE] = (byte) (p & 0xff);
+ }
+
+ private static void setFromPort(byte[] payload, int p) {
+ payload[FROMPORT_BYTES] = (byte) ((p >> 8) & 0xff);
+ payload[FROMPORT_BYTES + 1] = (byte) (p & 0xff);
+ }
+
+ private static void setToPort(byte[] payload, int p) {
+ payload[TOPORT_BYTES] = (byte) ((p >> 8) & 0xff);
+ payload[TOPORT_BYTES + 1] = (byte) (p & 0xff);
+ }
+}
diff --git a/core/java/src/net/i2p/client/I2PSessionMuxedListener.java b/core/java/src/net/i2p/client/I2PSessionMuxedListener.java
new file mode 100644
index 0000000000..118dc75cae
--- /dev/null
+++ b/core/java/src/net/i2p/client/I2PSessionMuxedListener.java
@@ -0,0 +1,62 @@
+package net.i2p.client;
+
+/*
+ * public domain
+ */
+
+/**
+ * Define a means for the router to asynchronously notify the client that a
+ * new message is available or the router is under attack.
+ *
+ * @author zzz extends I2PSessionListener
+ */
+public interface I2PSessionMuxedListener extends I2PSessionListener {
+
+ /**
+ * Will be called only if you register via
+ * setSessionListener() or addSessionListener().
+ * And if you are doing that, just use I2PSessionListener.
+ *
+ * If you register via addSessionListener(),
+ * this will be called only for the proto(s) and toport(s) you register for.
+ *
+ * @param session session to notify
+ * @param msgId message number available
+ * @param size size of the message - why it's a long and not an int is a mystery
+ */
+ void messageAvailable(I2PSession session, int msgId, long size);
+
+ /**
+ * Instruct the client that the given session has received a message
+ *
+ * Will be called only if you register via addMuxedSessionListener().
+ * Will be called only for the proto(s) and toport(s) you register for.
+ *
+ * @param session session to notify
+ * @param msgId message number available
+ * @param size size of the message - why it's a long and not an int is a mystery
+ * @param proto 1-254 or 0 for unspecified
+ * @param fromport 1-65535 or 0 for unspecified
+ * @param toport 1-65535 or 0 for unspecified
+ */
+ void messageAvailable(I2PSession session, int msgId, long size, int proto, int fromport, int toport);
+
+ /** Instruct the client that the session specified seems to be under attack
+ * and that the client may wish to move its destination to another router.
+ * @param session session to report abuse to
+ * @param severity how bad the abuse is
+ */
+ void reportAbuse(I2PSession session, int severity);
+
+ /**
+ * Notify the client that the session has been terminated
+ *
+ */
+ void disconnected(I2PSession session);
+
+ /**
+ * Notify the client that some error occurred
+ *
+ */
+ void errorOccurred(I2PSession session, String message, Throwable error);
+}
From 3733b78ccf727b7dd4090b5b884d37c68285bfc2 Mon Sep 17 00:00:00 2001
From: zzz
Date: Fri, 27 Feb 2009 21:24:40 +0000
Subject: [PATCH 019/688] * I2PTunnelUDPClientBase: Fix client close,
client target host * I2CP Mux: Fix UDP sends
---
.../java/src/net/i2p/i2ptunnel/TunnelController.java | 9 ++++++++-
.../net/i2p/i2ptunnel/streamr/StreamrConsumer.java | 1 +
.../net/i2p/i2ptunnel/streamr/StreamrProducer.java | 1 +
.../src/net/i2p/i2ptunnel/udp/I2PSinkAnywhere.java | 3 ++-
.../i2ptunnel/udpTunnel/I2PTunnelUDPClientBase.java | 12 ++----------
.../i2ptunnel/udpTunnel/I2PTunnelUDPServerBase.java | 3 +--
apps/i2ptunnel/jsp/editServer.jsp | 6 ++++--
.../java/src/net/i2p/client/I2PSessionMuxedImpl.java | 5 +++--
8 files changed, 22 insertions(+), 18 deletions(-)
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelController.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelController.java
index 6c5fa4eb99..9cb3762ac9 100644
--- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelController.java
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelController.java
@@ -213,8 +213,15 @@ public class TunnelController implements Logging {
_tunnel.runStreamrClient(new String[] { targetHost, targetPort, dest }, this);
}
- /** Streamr server is a UDP client, use the targetPort field for listenPort */
+ /**
+ * Streamr server is a UDP client, use the targetPort field for listenPort
+ * and the targetHost field for the listenOnInterface
+ */
private void startStreamrServer() {
+ String listenOn = getTargetHost();
+ if ( (listenOn != null) && (listenOn.length() > 0) ) {
+ _tunnel.runListenOn(new String[] { listenOn }, this);
+ }
String listenPort = getTargetPort();
String privKeyFile = getPrivKeyFile();
_tunnel.runStreamrServer(new String[] { listenPort, privKeyFile }, this);
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/streamr/StreamrConsumer.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/streamr/StreamrConsumer.java
index 02b4434437..87ea0eefe6 100644
--- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/streamr/StreamrConsumer.java
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/streamr/StreamrConsumer.java
@@ -42,6 +42,7 @@ public class StreamrConsumer extends I2PTunnelUDPClientBase {
super.startRunning();
// send subscribe-message
this.pinger.start();
+ l.log("Streamr client ready");
}
public boolean close(boolean forced) {
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/streamr/StreamrProducer.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/streamr/StreamrProducer.java
index c3963b6a66..b801cb94f4 100644
--- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/streamr/StreamrProducer.java
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/streamr/StreamrProducer.java
@@ -48,6 +48,7 @@ public class StreamrProducer extends I2PTunnelUDPServerBase {
public final void startRunning() {
super.startRunning();
this.server.start();
+ l.log("Streamr server ready");
}
public boolean close(boolean forced) {
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udp/I2PSinkAnywhere.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udp/I2PSinkAnywhere.java
index 09385d46fe..58c5bfda49 100644
--- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udp/I2PSinkAnywhere.java
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udp/I2PSinkAnywhere.java
@@ -27,7 +27,8 @@ public class I2PSinkAnywhere implements Sink {
this.raw = raw;
// create maker
- this.maker = new I2PDatagramMaker(this.sess);
+ if (!raw)
+ this.maker = new I2PDatagramMaker(this.sess);
}
/** @param to - where it's going */
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udpTunnel/I2PTunnelUDPClientBase.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udpTunnel/I2PTunnelUDPClientBase.java
index 0123be6eab..c92da6ae8a 100644
--- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udpTunnel/I2PTunnelUDPClientBase.java
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udpTunnel/I2PTunnelUDPClientBase.java
@@ -141,9 +141,6 @@ public abstract class I2PTunnelUDPClientBase extends I2PTunnelTask implements So
} else {
_i2pSink = new I2PSinkAnywhere(_session, false);
}
-
- //configurePool(tunnel);
-
}
/**
@@ -165,13 +162,7 @@ public abstract class I2PTunnelUDPClientBase extends I2PTunnelTask implements So
startRunning = true;
startLock.notify();
}
-
- if (open && listenerReady) {
- notifyEvent("openBaseClientResult", "ok");
- } else {
- l.log("Error listening - please see the logs!");
- notifyEvent("openBaseClientResult", "error");
- }
+ open = true;
}
/**
@@ -187,6 +178,7 @@ public abstract class I2PTunnelUDPClientBase extends I2PTunnelTask implements So
} catch (I2PSessionException ise) {}
}
l.log("Closing client " + toString());
+ open = false;
return true;
}
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udpTunnel/I2PTunnelUDPServerBase.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udpTunnel/I2PTunnelUDPServerBase.java
index fe129fb131..8dcd66a365 100644
--- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udpTunnel/I2PTunnelUDPServerBase.java
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udpTunnel/I2PTunnelUDPServerBase.java
@@ -41,7 +41,7 @@ public class I2PTunnelUDPServerBase extends I2PTunnelTask implements Source, Sin
private static volatile long __serverId = 0;
- private Logging l;
+ protected Logging l;
private static final long DEFAULT_READ_TIMEOUT = -1; // 3*60*1000;
/** default timeout to 3 minutes - override if desired */
@@ -137,7 +137,6 @@ public class I2PTunnelUDPServerBase extends I2PTunnelTask implements Source, Sin
start();
//}
- l.log("Ready!");
notifyEvent("openServerResult", "ok");
open = true;
}
diff --git a/apps/i2ptunnel/jsp/editServer.jsp b/apps/i2ptunnel/jsp/editServer.jsp
index 0e9f9c0caa..70a9df9f72 100644
--- a/apps/i2ptunnel/jsp/editServer.jsp
+++ b/apps/i2ptunnel/jsp/editServer.jsp
@@ -88,14 +88,16 @@
<% } %>
- <% if (!"streamrserver".equals(tunnelType)) { %>
- <% } // !streamrserver %>
-
-
-
-
-
- class="tickbox" />
-
-
-
- class="tickbox" />
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+ class="tickbox" />
+
+
+
+
+
class="tickbox" />
+
Enable
+
class="tickbox" />
+
Disable
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ class="tickbox" />
+
+
+
+
+
+
+
+
+
+
-
+
(Tunnel must be stopped first)
From 59b624a4a4fb9fd5857b424c46faeab6bf6b16fe Mon Sep 17 00:00:00 2001
From: zzz
Date: Sun, 1 Mar 2009 20:44:01 +0000
Subject: [PATCH 024/688] add reasonable privkey file name default
---
apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/EditBean.java | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/EditBean.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/EditBean.java
index e68d140c5c..941edd0bda 100644
--- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/EditBean.java
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/EditBean.java
@@ -60,8 +60,9 @@ public class EditBean extends IndexBean {
TunnelController tun = getController(tunnel);
if (tun != null && tun.getPrivKeyFile() != null)
return tun.getPrivKeyFile();
- else
- return "";
+ if (tunnel < 0)
+ tunnel = _group.getControllers().size();
+ return "i2ptunnel" + tunnel + "-privKeys.dat";
}
public boolean startAutomatically(int tunnel) {
From c455fa6309fb7c66e9159d99d9f0e162010cddfa Mon Sep 17 00:00:00 2001
From: zzz
Date: Sun, 1 Mar 2009 20:45:16 +0000
Subject: [PATCH 025/688] * OCMOSJ: - Change from 5% reply requests
to at least once per minute, in hopes of reducing IRC drops -
More clean up of the cache cleaning
---
.../OutboundClientMessageOneShotJob.java | 95 +++++++++++--------
1 file changed, 58 insertions(+), 37 deletions(-)
diff --git a/router/java/src/net/i2p/router/message/OutboundClientMessageOneShotJob.java b/router/java/src/net/i2p/router/message/OutboundClientMessageOneShotJob.java
index 0e858ef779..20d69ea733 100644
--- a/router/java/src/net/i2p/router/message/OutboundClientMessageOneShotJob.java
+++ b/router/java/src/net/i2p/router/message/OutboundClientMessageOneShotJob.java
@@ -103,6 +103,7 @@ public class OutboundClientMessageOneShotJob extends JobImpl {
private static final Object _initializeLock = new Object();
private static boolean _initialized = false;
private static final int CLEAN_INTERVAL = 5*60*1000;
+ private static final int REPLY_REQUEST_INTERVAL = 60*1000;
/**
* Send the sucker
@@ -212,7 +213,7 @@ public class OutboundClientMessageOneShotJob extends JobImpl {
*
* Key the cache on the source+dest pair.
*/
- private static HashMap _leaseSetCache = new HashMap();
+ private static HashMap _leaseSetCache = new HashMap();
private LeaseSet getReplyLeaseSet(boolean force) {
LeaseSet newLS = getContext().netDb().lookupLeaseSetLocally(_from.calculateHash());
if (newLS == null)
@@ -247,7 +248,7 @@ public class OutboundClientMessageOneShotJob extends JobImpl {
long now = getContext().clock().now();
synchronized (_leaseSetCache) {
if (!force) {
- LeaseSet ls = (LeaseSet) _leaseSetCache.get(hashPair());
+ LeaseSet ls = _leaseSetCache.get(hashPair());
if (ls != null) {
if (ls.equals(newLS)) {
// still good, send it 10% of the time
@@ -312,7 +313,7 @@ public class OutboundClientMessageOneShotJob extends JobImpl {
* lease).
*
*/
- private static HashMap _leaseCache = new HashMap();
+ private static HashMap _leaseCache = new HashMap();
private boolean getNextLease() {
_leaseSet = getContext().netDb().lookupLeaseSetLocally(_to.calculateHash());
if (_leaseSet == null) {
@@ -325,7 +326,7 @@ public class OutboundClientMessageOneShotJob extends JobImpl {
// Use the same lease if it's still good
// Even if _leaseSet changed, _leaseSet.getEncryptionKey() didn't...
synchronized (_leaseCache) {
- _lease = (Lease) _leaseCache.get(hashPair());
+ _lease = _leaseCache.get(hashPair());
if (_lease != null) {
// if outbound tunnel length == 0 && lease.firsthop.isBacklogged() don't use it ??
if (!_lease.isExpired(Router.CLOCK_FUDGE_FACTOR)) {
@@ -446,6 +447,14 @@ public class OutboundClientMessageOneShotJob extends JobImpl {
}
}
+ /**
+ * This cache is used to ensure that we request a reply every so often.
+ * Hopefully this allows the router to recognize a failed tunnel and switch,
+ * before upper layers like streaming lib fail, even for low-bandwidth
+ * connections like IRC.
+ */
+ private static HashMap _lastReplyRequestCache = new HashMap();
+
/**
* Send the message to the specified tunnel by creating a new garlic message containing
* the (already created) payload clove as well as a new delivery status message. This garlic
@@ -456,18 +465,27 @@ public class OutboundClientMessageOneShotJob extends JobImpl {
*/
private void send() {
if (_finished) return;
- if (getContext().clock().now() >= _overallExpiration) {
+ long now = getContext().clock().now();
+ if (now >= _overallExpiration) {
dieFatal();
return;
}
int existingTags = GarlicMessageBuilder.estimateAvailableTags(getContext(), _leaseSet.getEncryptionKey());
_outTunnel = selectOutboundTunnel(_to);
+ // boolean wantACK = _wantACK || existingTags <= 30 || getContext().random().nextInt(100) < 5;
// what's the point of 5% random? possible improvements or replacements:
- // - wantACK if we changed their inbound lease (getNextLease() sets _wantACK)
- // - wantACK if we changed our outbound tunnel (selectOutboundTunnel() sets _wantACK)
- // - wantACK if we haven't in last 1m (requires a new static cache probably)
- boolean wantACK = _wantACK || existingTags <= 30 || getContext().random().nextInt(100) < 5;
+ // DONE (getNextLease() is called before this): wantACK if we changed their inbound lease (getNextLease() sets _wantACK)
+ // DONE (selectOutboundTunnel() moved above here): wantACK if we changed our outbound tunnel (selectOutboundTunnel() sets _wantACK)
+ // DONE (added new cache): wantACK if we haven't in last 1m (requires a new static cache probably)
+ boolean wantACK;
+ synchronized (_lastReplyRequestCache) {
+ Long lastSent = _lastReplyRequestCache.get(hashPair());
+ wantACK = _wantACK || existingTags <= 30 ||
+ lastSent == null || lastSent.longValue() < now - REPLY_REQUEST_INTERVAL;
+ if (wantACK)
+ _lastReplyRequestCache.put(hashPair(), Long.valueOf(now));
+ }
PublicKey key = _leaseSet.getEncryptionKey();
SessionKey sessKey = new SessionKey();
@@ -501,7 +519,7 @@ public class OutboundClientMessageOneShotJob extends JobImpl {
// we dont receive the reply? hmm...)
if (_log.shouldLog(Log.WARN))
_log.warn(getJobId() + ": Unable to create the garlic message (no tunnels left or too lagged) to " + _toString);
- getContext().statManager().addRateData("client.dispatchNoTunnels", getContext().clock().now() - _start, 0);
+ getContext().statManager().addRateData("client.dispatchNoTunnels", now - _start, 0);
dieFatal();
return;
}
@@ -539,12 +557,12 @@ public class OutboundClientMessageOneShotJob extends JobImpl {
} else {
if (_log.shouldLog(Log.WARN))
_log.warn(getJobId() + ": Could not find any outbound tunnels to send the payload through... this might take a while");
- getContext().statManager().addRateData("client.dispatchNoTunnels", getContext().clock().now() - _start, 0);
+ getContext().statManager().addRateData("client.dispatchNoTunnels", now - _start, 0);
dieFatal();
}
_clientMessage = null;
_clove = null;
- getContext().statManager().addRateData("client.dispatchPrepareTime", getContext().clock().now() - _start, 0);
+ getContext().statManager().addRateData("client.dispatchPrepareTime", now - _start, 0);
if (!wantACK)
getContext().statManager().addRateData("client.dispatchNoACK", 1, 0);
}
@@ -582,7 +600,7 @@ public class OutboundClientMessageOneShotJob extends JobImpl {
/**
* This is the place where we make I2P go fast.
*
- * We have four static caches.
+ * We have five static caches.
* - The LeaseSet cache is used to decide whether to bundle our own leaseset,
* which minimizes overhead.
* - The Lease cache is used to persistently send to the same lease for the destination,
@@ -590,6 +608,8 @@ public class OutboundClientMessageOneShotJob extends JobImpl {
* - The Tunnel and BackloggedTunnel caches are used to persistently use the same outbound tunnel
* for the same destination,
* which keeps the streaming lib happy by minimizing out-of-order delivery.
+ * - The last reply requested cache ensures that a reply is requested every so often,
+ * so that failed tunnels are recognized.
*
*/
@@ -629,17 +649,17 @@ public class OutboundClientMessageOneShotJob extends JobImpl {
}
if (_lease != null) {
synchronized(_leaseCache) {
- Lease l = (Lease) _leaseCache.get(key);
+ Lease l = _leaseCache.get(key);
if (l != null && l.equals(_lease))
_leaseCache.remove(key);
}
}
if (_outTunnel != null) {
synchronized(_tunnelCache) {
- TunnelInfo t =(TunnelInfo) _backloggedTunnelCache.get(key);
+ TunnelInfo t = _backloggedTunnelCache.get(key);
if (t != null && t.equals(_outTunnel))
_backloggedTunnelCache.remove(key);
- t = (TunnelInfo) _tunnelCache.get(key);
+ t = _tunnelCache.get(key);
if (t != null && t.equals(_outTunnel))
_tunnelCache.remove(key);
}
@@ -652,17 +672,12 @@ public class OutboundClientMessageOneShotJob extends JobImpl {
*/
private static void cleanLeaseSetCache(RouterContext ctx, HashMap tc) {
long now = ctx.clock().now();
- List deleteList = new ArrayList();
for (Iterator iter = tc.entrySet().iterator(); iter.hasNext(); ) {
Map.Entry entry = (Map.Entry)iter.next();
String k = (String) entry.getKey();
LeaseSet l = (LeaseSet) entry.getValue();
if (l.getEarliestLeaseDate() < now)
- deleteList.add(k);
- }
- for (Iterator iter = deleteList.iterator(); iter.hasNext(); ) {
- String k = (String) iter.next();
- tc.remove(k);
+ iter.remove();
}
}
@@ -671,17 +686,12 @@ public class OutboundClientMessageOneShotJob extends JobImpl {
* Caller must synchronize on tc.
*/
private static void cleanLeaseCache(HashMap tc) {
- List deleteList = new ArrayList();
for (Iterator iter = tc.entrySet().iterator(); iter.hasNext(); ) {
Map.Entry entry = (Map.Entry)iter.next();
String k = (String) entry.getKey();
Lease l = (Lease) entry.getValue();
if (l.isExpired(Router.CLOCK_FUDGE_FACTOR))
- deleteList.add(k);
- }
- for (Iterator iter = deleteList.iterator(); iter.hasNext(); ) {
- String k = (String) iter.next();
- tc.remove(k);
+ iter.remove();
}
}
@@ -690,17 +700,25 @@ public class OutboundClientMessageOneShotJob extends JobImpl {
* Caller must synchronize on tc.
*/
private static void cleanTunnelCache(RouterContext ctx, HashMap tc) {
- List deleteList = new ArrayList();
for (Iterator iter = tc.entrySet().iterator(); iter.hasNext(); ) {
Map.Entry entry = (Map.Entry)iter.next();
String k = (String) entry.getKey();
TunnelInfo tunnel = (TunnelInfo) entry.getValue();
if (!ctx.tunnelManager().isValidTunnel(sourceFromHashPair(k), tunnel))
- deleteList.add(k);
+ iter.remove();
}
- for (Iterator iter = deleteList.iterator(); iter.hasNext(); ) {
- String k = (String) iter.next();
- tc.remove(k);
+ }
+
+ /**
+ * Clean out old reply times
+ * Caller must synchronize on tc.
+ */
+ private static void cleanReplyCache(RouterContext ctx, HashMap tc) {
+ long now = ctx.clock().now();
+ for (Iterator iter = tc.values().iterator(); iter.hasNext(); ) {
+ Long l = (Long) iter.next();
+ if (l.longValue() < now - CLEAN_INTERVAL)
+ iter.remove();
}
}
@@ -720,6 +738,9 @@ public class OutboundClientMessageOneShotJob extends JobImpl {
cleanTunnelCache(_ctx, _tunnelCache);
cleanTunnelCache(_ctx, _backloggedTunnelCache);
}
+ synchronized(_lastReplyRequestCache) {
+ cleanReplyCache(_ctx, _lastReplyRequestCache);
+ }
}
}
@@ -731,8 +752,8 @@ public class OutboundClientMessageOneShotJob extends JobImpl {
* Key the caches on the source+dest pair.
*
*/
- private static HashMap _tunnelCache = new HashMap();
- private static HashMap _backloggedTunnelCache = new HashMap();
+ private static HashMap _tunnelCache = new HashMap();
+ private static HashMap _backloggedTunnelCache = new HashMap();
private TunnelInfo selectOutboundTunnel(Destination to) {
TunnelInfo tunnel;
long now = getContext().clock().now();
@@ -743,7 +764,7 @@ public class OutboundClientMessageOneShotJob extends JobImpl {
* if you were the originator by backlogging the tunnel, then removing the
* backlog and seeing if traffic came back or not.
*/
- tunnel = (TunnelInfo) _backloggedTunnelCache.get(hashPair());
+ tunnel = _backloggedTunnelCache.get(hashPair());
if (tunnel != null) {
if (getContext().tunnelManager().isValidTunnel(_from.calculateHash(), tunnel)) {
if (!getContext().commSystem().isBacklogged(tunnel.getPeer(1))) {
@@ -758,7 +779,7 @@ public class OutboundClientMessageOneShotJob extends JobImpl {
_backloggedTunnelCache.remove(hashPair());
}
// Use the same tunnel unless backlogged
- tunnel = (TunnelInfo) _tunnelCache.get(hashPair());
+ tunnel = _tunnelCache.get(hashPair());
if (tunnel != null) {
if (getContext().tunnelManager().isValidTunnel(_from.calculateHash(), tunnel)) {
if (tunnel.getLength() <= 1 || !getContext().commSystem().isBacklogged(tunnel.getPeer(1)))
From 8f5257d5dc818dde614a9a414b1835a579bcf6bb Mon Sep 17 00:00:00 2001
From: zzz
Date: Sun, 1 Mar 2009 23:14:38 +0000
Subject: [PATCH 026/688] make persistent client dests work
---
.../java/src/net/i2p/i2ptunnel/I2PTunnel.java | 24 ++++++----
.../net/i2p/i2ptunnel/I2PTunnelClient.java | 4 +-
.../i2p/i2ptunnel/I2PTunnelClientBase.java | 48 +++++++++++++++----
.../net/i2p/i2ptunnel/I2PTunnelIRCClient.java | 4 +-
.../net/i2p/i2ptunnel/TunnelController.java | 16 +++++--
apps/i2ptunnel/jsp/editClient.jsp | 9 ++++
6 files changed, 80 insertions(+), 25 deletions(-)
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnel.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnel.java
index dc9dfd2fcc..b11f954e7e 100644
--- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnel.java
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnel.java
@@ -552,14 +552,14 @@ public class I2PTunnel implements Logging, EventDispatcher {
* Integer port number if the client is listening
* sharedClient parameter is a String "true" or "false"
*
- * @param args {portNumber, destinationBase64 or "file:filename"[, sharedClient]}
+ * @param args {portNumber, destinationBase64 or "file:filename"[, sharedClient [, privKeyFile]]}
* @param l logger to receive events and output
*/
public void runClient(String args[], Logging l) {
boolean isShared = true;
- if (args.length == 3)
+ if (args.length >= 3)
isShared = Boolean.valueOf(args[2].trim()).booleanValue();
- if ( (args.length == 2) || (args.length == 3) ) {
+ if (args.length >= 2) {
int portNum = -1;
try {
portNum = Integer.parseInt(args[0]);
@@ -572,7 +572,10 @@ public class I2PTunnel implements Logging, EventDispatcher {
I2PTunnelTask task;
ownDest = !isShared;
try {
- task = new I2PTunnelClient(portNum, args[1], l, ownDest, (EventDispatcher) this, this);
+ String privateKeyFile = null;
+ if (args.length >= 4)
+ privateKeyFile = args[3];
+ task = new I2PTunnelClient(portNum, args[1], l, ownDest, (EventDispatcher) this, this, privateKeyFile);
addtask(task);
notifyEvent("clientTaskId", Integer.valueOf(task.getId()));
} catch (IllegalArgumentException iae) {
@@ -581,7 +584,7 @@ public class I2PTunnel implements Logging, EventDispatcher {
notifyEvent("clientTaskId", Integer.valueOf(-1));
}
} else {
- l.log("client [,]|file:[ ]");
+ l.log("client [,]|file:[ ] []");
l.log(" creates a client that forwards port to the pubkey.\n"
+ " use 0 as port to get a free port assigned. If you specify\n"
+ " a comma delimited list of pubkeys, it will rotate among them\n"
@@ -720,11 +723,11 @@ public class I2PTunnel implements Logging, EventDispatcher {
* Also sets "ircclientStatus" = "ok" or "error" after the client tunnel has started.
* parameter sharedClient is a String, either "true" or "false"
*
- * @param args {portNumber,destinationBase64 or "file:filename" [, sharedClient]}
+ * @param args {portNumber,destinationBase64 or "file:filename" [, sharedClient [, privKeyFile]]}
* @param l logger to receive events and output
*/
public void runIrcClient(String args[], Logging l) {
- if (args.length >= 2 && args.length <= 3) {
+ if (args.length >= 2) {
int port = -1;
try {
port = Integer.parseInt(args[0]);
@@ -751,7 +754,10 @@ public class I2PTunnel implements Logging, EventDispatcher {
I2PTunnelTask task;
ownDest = !isShared;
try {
- task = new I2PTunnelIRCClient(port, args[1],l, ownDest, (EventDispatcher) this, this);
+ String privateKeyFile = null;
+ if (args.length >= 4)
+ privateKeyFile = args[3];
+ task = new I2PTunnelIRCClient(port, args[1], l, ownDest, (EventDispatcher) this, this, privateKeyFile);
addtask(task);
notifyEvent("ircclientTaskId", Integer.valueOf(task.getId()));
} catch (IllegalArgumentException iae) {
@@ -760,7 +766,7 @@ public class I2PTunnel implements Logging, EventDispatcher {
notifyEvent("ircclientTaskId", Integer.valueOf(-1));
}
} else {
- l.log("ircclient []");
+ l.log("ircclient [ []]");
l.log(" creates a client that filter IRC protocol.");
l.log(" (optional) indicates if this client shares tunnels with other clients (true of false)");
notifyEvent("ircclientTaskId", Integer.valueOf(-1));
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClient.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClient.java
index 4739a07f47..502bb28d5c 100644
--- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClient.java
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClient.java
@@ -31,8 +31,8 @@ public class I2PTunnelClient extends I2PTunnelClientBase {
*/
public I2PTunnelClient(int localPort, String destinations, Logging l,
boolean ownDest, EventDispatcher notifyThis,
- I2PTunnel tunnel) throws IllegalArgumentException {
- super(localPort, ownDest, l, notifyThis, "SynSender", tunnel);
+ I2PTunnel tunnel, String pkf) throws IllegalArgumentException {
+ super(localPort, ownDest, l, notifyThis, "SynSender", tunnel, pkf);
if (waitEventValue("openBaseClientResult").equals("error")) {
notifyEvent("openClientResult", "error");
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClientBase.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClientBase.java
index c926156f42..fadbf9fa1c 100644
--- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClientBase.java
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClientBase.java
@@ -3,6 +3,7 @@
*/
package net.i2p.i2ptunnel;
+import java.io.FileInputStream;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.net.ConnectException;
@@ -59,6 +60,7 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
private byte[] pubkey;
private String handlerName;
+ private String privKeyFile;
private Object conLock = new Object();
@@ -91,18 +93,28 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
// I2PTunnelClientBase(localPort, ownDest, l, (EventDispatcher)null);
//}
+ public I2PTunnelClientBase(int localPort, boolean ownDest, Logging l,
+ EventDispatcher notifyThis, String handlerName,
+ I2PTunnel tunnel) throws IllegalArgumentException {
+ this(localPort, ownDest, l, notifyThis, handlerName, tunnel, null);
+ }
+
/**
+ * @param privKeyFile null to generate a transient key
+ *
* @throws IllegalArgumentException if the I2CP configuration is b0rked so
* badly that we cant create a socketManager
*/
public I2PTunnelClientBase(int localPort, boolean ownDest, Logging l,
EventDispatcher notifyThis, String handlerName,
- I2PTunnel tunnel) throws IllegalArgumentException{
+ I2PTunnel tunnel, String pkf) throws IllegalArgumentException{
super(localPort + " (uninitialized)", notifyThis, tunnel);
_clientId = ++__clientId;
this.localPort = localPort;
this.l = l;
this.handlerName = handlerName + _clientId;
+ this.privKeyFile = pkf;
+
_context = tunnel.getContext();
_context.statManager().createRateStat("i2ptunnel.client.closeBacklog", "How many pending sockets remain when we close one due to backlog?", "I2PTunnel", new long[] { 60*1000, 10*60*1000, 60*60*1000 });
@@ -195,28 +207,34 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
private static I2PSocketManager socketManager;
protected synchronized I2PSocketManager getSocketManager() {
- return getSocketManager(getTunnel());
+ return getSocketManager(getTunnel(), this.privKeyFile);
}
protected static synchronized I2PSocketManager getSocketManager(I2PTunnel tunnel) {
+ return getSocketManager(tunnel, null);
+ }
+ protected static synchronized I2PSocketManager getSocketManager(I2PTunnel tunnel, String pkf) {
if (socketManager != null) {
I2PSession s = socketManager.getSession();
if ( (s == null) || (s.isClosed()) ) {
_log.info("Building a new socket manager since the old one closed [s=" + s + "]");
- socketManager = buildSocketManager(tunnel);
+ socketManager = buildSocketManager(tunnel, pkf);
} else {
_log.info("Not building a new socket manager since the old one is open [s=" + s + "]");
}
} else {
_log.info("Building a new socket manager since there is no other one");
- socketManager = buildSocketManager(tunnel);
+ socketManager = buildSocketManager(tunnel, pkf);
}
return socketManager;
}
protected I2PSocketManager buildSocketManager() {
- return buildSocketManager(getTunnel());
+ return buildSocketManager(getTunnel(), this.privKeyFile);
}
protected static I2PSocketManager buildSocketManager(I2PTunnel tunnel) {
+ return buildSocketManager(tunnel, null);
+ }
+ protected static I2PSocketManager buildSocketManager(I2PTunnel tunnel, String pkf) {
Properties props = new Properties();
props.putAll(tunnel.getClientOptions());
int portNum = 7654;
@@ -230,10 +248,22 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
I2PSocketManager sockManager = null;
while (sockManager == null) {
- // if persistent dest
- // sockManager = I2PSocketManagerFactory.createManager(privData, tunnel.host, portNum, props);
- // else
- sockManager = I2PSocketManagerFactory.createManager(tunnel.host, portNum, props);
+ if (pkf != null) {
+ // Persistent client dest
+ FileInputStream fis = null;
+ try {
+ fis = new FileInputStream(pkf);
+ sockManager = I2PSocketManagerFactory.createManager(fis, tunnel.host, portNum, props);
+ } catch (IOException ioe) {
+ _log.error("Error opening key file", ioe);
+ // this is going to loop but if we break we'll get a NPE
+ } finally {
+ if (fis != null)
+ try { fis.close(); } catch (IOException ioe) {}
+ }
+ } else {
+ sockManager = I2PSocketManagerFactory.createManager(tunnel.host, portNum, props);
+ }
if (sockManager == null) {
_log.log(Log.CRIT, "Unable to create socket manager");
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelIRCClient.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelIRCClient.java
index 5b223b1a42..732c222a71 100644
--- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelIRCClient.java
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelIRCClient.java
@@ -39,12 +39,12 @@ public class I2PTunnelIRCClient extends I2PTunnelClientBase implements Runnable
Logging l,
boolean ownDest,
EventDispatcher notifyThis,
- I2PTunnel tunnel) throws IllegalArgumentException {
+ I2PTunnel tunnel, String pkf) throws IllegalArgumentException {
super(localPort,
ownDest,
l,
notifyThis,
- "IRCHandler " + (++__clientId), tunnel);
+ "IRCHandler " + (++__clientId), tunnel, pkf);
StringTokenizer tok = new StringTokenizer(destinations, ",");
dests = new ArrayList(1);
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelController.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelController.java
index 727b181581..419e5a899d 100644
--- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelController.java
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelController.java
@@ -192,7 +192,12 @@ public class TunnelController implements Logging {
String listenPort = getListenPort();
String dest = getTargetDestination();
String sharedClient = getSharedClient();
- _tunnel.runIrcClient(new String[] { listenPort, dest, sharedClient }, this);
+ if (getPersistentClientKey()) {
+ String privKeyFile = getPrivKeyFile();
+ _tunnel.runIrcClient(new String[] { listenPort, dest, sharedClient, privKeyFile }, this);
+ } else {
+ _tunnel.runIrcClient(new String[] { listenPort, dest, sharedClient }, this);
+ }
}
private void startSocksClient() {
@@ -264,7 +269,12 @@ public class TunnelController implements Logging {
String listenPort = getListenPort();
String dest = getTargetDestination();
String sharedClient = getSharedClient();
- _tunnel.runClient(new String[] { listenPort, dest, sharedClient }, this);
+ if (getPersistentClientKey()) {
+ String privKeyFile = getPrivKeyFile();
+ _tunnel.runClient(new String[] { listenPort, dest, sharedClient, privKeyFile }, this);
+ } else {
+ _tunnel.runClient(new String[] { listenPort, dest, sharedClient }, this);
+ }
}
private void startServer() {
@@ -395,7 +405,7 @@ public class TunnelController implements Logging {
public String getProxyList() { return _config.getProperty("proxyList"); }
public String getSharedClient() { return _config.getProperty("sharedClient", "true"); }
public boolean getStartOnLoad() { return "true".equalsIgnoreCase(_config.getProperty("startOnLoad", "true")); }
- public boolean getPersistentClientKey() { return Boolean.valueOf(_config.getProperty("persistentClientKey")).booleanValue(); }
+ public boolean getPersistentClientKey() { return Boolean.valueOf(_config.getProperty("option.persistentClientKey")).booleanValue(); }
public String getMyDestination() {
if (_tunnel != null) {
List sessions = _tunnel.getSessions();
diff --git a/apps/i2ptunnel/jsp/editClient.jsp b/apps/i2ptunnel/jsp/editClient.jsp
index 3c046baddc..178f564ef9 100644
--- a/apps/i2ptunnel/jsp/editClient.jsp
+++ b/apps/i2ptunnel/jsp/editClient.jsp
@@ -351,6 +351,7 @@
+ <% if ("client".equals(tunnelType) || "ircclient".equals(tunnelType)) { %>
+
+
+ Local destination:
+
+
+ (if known)
+
+ <% } %>
From 5785f500ef05da32aa93c36035051bbc154c91a1 Mon Sep 17 00:00:00 2001
From: zzz
Date: Mon, 2 Mar 2009 01:38:44 +0000
Subject: [PATCH 027/688] complete regenerate-dest-on-reconnect
---
.../src/net/i2p/i2ptunnel/I2PTunnelClientBase.java | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClientBase.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClientBase.java
index fadbf9fa1c..1b308eb371 100644
--- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClientBase.java
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClientBase.java
@@ -355,6 +355,16 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
public I2PSocket createI2PSocket(Destination dest, I2PSocketOptions opt) throws I2PException, ConnectException, NoRouteToHostException, InterruptedIOException {
I2PSocket i2ps;
+ if (Boolean.valueOf(getTunnel().getClientOptions().getProperty("i2cp.newDestOnResume")).booleanValue()) {
+ synchronized(sockMgr) {
+ I2PSocketManager oldSockMgr = sockMgr;
+ // This will build a new socket manager and a new dest if the session is closed.
+ sockMgr = getSocketManager();
+ if (oldSockMgr != sockMgr) {
+ _log.error("Built a new destination on resume");
+ }
+ }
+ } // else the old socket manager will reconnect the old session if necessary
i2ps = sockMgr.connect(dest, opt);
synchronized (sockLock) {
mySockets.add(i2ps);
From 03f16565fe53ba71c33f7035deadc63ee4027ee1 Mon Sep 17 00:00:00 2001
From: zzz
Date: Mon, 2 Mar 2009 16:01:15 +0000
Subject: [PATCH 028/688] tweak
---
README.txt | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/README.txt b/README.txt
index 49a62ee5ba..3aa2141bb4 100644
--- a/README.txt
+++ b/README.txt
@@ -25,7 +25,5 @@ Need help?
http://forum.i2p2.de/
Licenses:
- http://www.i2p2.de/licenses.html
- Also http://localhost:7657/help.jsp
- Also see licenses for the individual bundled apps in apps/*
+ See LICENSE.txt
From c4fa0d894fdb4bd00f13680473a7df5842fb377f Mon Sep 17 00:00:00 2001
From: zzz
Date: Mon, 2 Mar 2009 16:07:48 +0000
Subject: [PATCH 029/688] * Client: - Clean up retry code -
Bring I2CP listen error to the summary bar
http://forum.i2p/viewtopic.php?t=3133
---
.../src/net/i2p/router/web/SummaryHelper.java | 3 +++
apps/routerconsole/jsp/config.jsp | 4 ++++
.../net/i2p/router/ClientManagerFacade.java | 1 +
.../router/client/ClientListenerRunner.java | 23 ++++++++++++-------
.../net/i2p/router/client/ClientManager.java | 2 ++
.../client/ClientManagerFacadeImpl.java | 2 ++
6 files changed, 27 insertions(+), 8 deletions(-)
diff --git a/apps/routerconsole/java/src/net/i2p/router/web/SummaryHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/SummaryHelper.java
index 47a07c3746..1b302ff0b9 100644
--- a/apps/routerconsole/java/src/net/i2p/router/web/SummaryHelper.java
+++ b/apps/routerconsole/java/src/net/i2p/router/web/SummaryHelper.java
@@ -106,6 +106,9 @@ public class SummaryHelper extends HelperBase {
public int getAllPeers() { return _context.netDb().getKnownRouters(); }
public String getReachability() {
+ if (_context.router().getUptime() > 60*1000 && (!_context.router().gracefulShutdownInProgress()) &&
+ !_context.clientManager().isAlive())
+ return "ERR-Client Manager I2CP Error - check logs"; // not a router problem but the user should know
if (!_context.clock().getUpdatedSuccessfully())
return "ERR-ClockSkew";
if (_context.router().isHidden())
diff --git a/apps/routerconsole/jsp/config.jsp b/apps/routerconsole/jsp/config.jsp
index 132bd5315c..ae357d69f1 100644
--- a/apps/routerconsole/jsp/config.jsp
+++ b/apps/routerconsole/jsp/config.jsp
@@ -112,6 +112,7 @@
if you open up your port (generally 8887) to both UDP and TCP, and enable inbound TCP above.
If you think you have opened up your firewall and I2P still thinks you are firewalled, remember
that you may have multiple firewalls, for example both software packages and external hardware routers.
+ If there is an error, the logs may also help diagnose the problem.
OK - Your UDP port does not appear to be firewalled.
Firewalled - Your UDP port appears to be firewalled.
@@ -151,6 +152,9 @@
You have not configured inbound TCP with a hostname and port above, however
you have disabled UDP. Therefore your router cannot accept inbound connections.
Please configure a TCP host and port above or enable UDP.
+
ERR - Client Manager I2CP Error - check logs -
+ This is usually due to a port 7654 conflict. Check the logs to verify. Do you have another I2P instance running?
+ Stop the conflicting program and restart I2P.
diff --git a/router/java/src/net/i2p/router/ClientManagerFacade.java b/router/java/src/net/i2p/router/ClientManagerFacade.java
index 07f6e561fc..2e441fefe2 100644
--- a/router/java/src/net/i2p/router/ClientManagerFacade.java
+++ b/router/java/src/net/i2p/router/ClientManagerFacade.java
@@ -72,6 +72,7 @@ public abstract class ClientManagerFacade implements Service {
public abstract void messageReceived(ClientMessage msg);
public boolean verifyClientLiveliness() { return true; }
+ public boolean isAlive() { return true; }
/**
* Does the client specified want their leaseSet published?
*/
diff --git a/router/java/src/net/i2p/router/client/ClientListenerRunner.java b/router/java/src/net/i2p/router/client/ClientListenerRunner.java
index 074b161dfd..38105e9c96 100644
--- a/router/java/src/net/i2p/router/client/ClientListenerRunner.java
+++ b/router/java/src/net/i2p/router/client/ClientListenerRunner.java
@@ -31,7 +31,7 @@ public class ClientListenerRunner implements Runnable {
private int _port;
private boolean _bindAllInterfaces;
private boolean _running;
- private long _nextFailDelay = 1000;
+ private boolean _listening;
public static final String BIND_ALL_INTERFACES = "i2cp.tcp.bindAllInterfaces";
@@ -41,6 +41,7 @@ public class ClientListenerRunner implements Runnable {
_manager = manager;
_port = port;
_running = false;
+ _listening = false;
String val = context.getProperty(BIND_ALL_INTERFACES, "False");
_bindAllInterfaces = Boolean.valueOf(val).booleanValue();
@@ -48,6 +49,7 @@ public class ClientListenerRunner implements Runnable {
public void setPort(int port) { _port = port; }
public int getPort() { return _port; }
+ public boolean isListening() { return _running && _listening; }
/**
* Start up the socket listener, listens for connections, and
@@ -58,7 +60,7 @@ public class ClientListenerRunner implements Runnable {
*/
public void runServer() {
_running = true;
- int curDelay = 0;
+ int curDelay = 1000;
while (_running) {
try {
if (_bindAllInterfaces) {
@@ -77,7 +79,8 @@ public class ClientListenerRunner implements Runnable {
if (_log.shouldLog(Log.DEBUG))
_log.debug("ServerSocket created, before accept: " + _socket);
- curDelay = 0;
+ curDelay = 1000;
+ _listening = true;
while (_running) {
try {
Socket socket = _socket.accept();
@@ -96,6 +99,7 @@ public class ClientListenerRunner implements Runnable {
} catch (Throwable t) {
if (_context.router().isAlive())
_log.error("Fatal error running client listener - killing the thread!", t);
+ _listening = false;
return;
}
}
@@ -104,6 +108,7 @@ public class ClientListenerRunner implements Runnable {
_log.error("Error listening on port " + _port, ioe);
}
+ _listening = false;
if (_socket != null) {
try { _socket.close(); } catch (IOException ioe) {}
_socket = null;
@@ -111,14 +116,16 @@ public class ClientListenerRunner implements Runnable {
if (!_context.router().isAlive()) break;
- _log.error("Error listening, waiting " + _nextFailDelay + "ms before we try again");
- try { Thread.sleep(_nextFailDelay); } catch (InterruptedException ie) {}
- curDelay += _nextFailDelay;
- _nextFailDelay *= 5;
+ if (curDelay < 60*1000)
+ _log.error("Error listening, waiting " + (curDelay/1000) + "s before we try again");
+ else
+ _log.log(Log.CRIT, "I2CP error listening to port " + _port + " - is another I2P instance running? Resolve conflicts and restart");
+ try { Thread.sleep(curDelay); } catch (InterruptedException ie) {}
+ curDelay = Math.min(curDelay*3, 60*1000);
}
if (_context.router().isAlive())
- _log.error("CANCELING I2CP LISTEN. delay = " + curDelay, new Exception("I2CP Listen cancelled!!!"));
+ _log.error("CANCELING I2CP LISTEN", new Exception("I2CP Listen cancelled!!!"));
_running = false;
}
diff --git a/router/java/src/net/i2p/router/client/ClientManager.java b/router/java/src/net/i2p/router/client/ClientManager.java
index 18c9c77423..9b5eb7c4cc 100644
--- a/router/java/src/net/i2p/router/client/ClientManager.java
+++ b/router/java/src/net/i2p/router/client/ClientManager.java
@@ -108,6 +108,8 @@ public class ClientManager {
}
}
+ public boolean isAlive() { return _listener.isListening(); }
+
public void registerConnection(ClientConnectionRunner runner) {
synchronized (_pendingRunners) {
_pendingRunners.add(runner);
diff --git a/router/java/src/net/i2p/router/client/ClientManagerFacadeImpl.java b/router/java/src/net/i2p/router/client/ClientManagerFacadeImpl.java
index 796a098a98..51b8b4cb25 100644
--- a/router/java/src/net/i2p/router/client/ClientManagerFacadeImpl.java
+++ b/router/java/src/net/i2p/router/client/ClientManagerFacadeImpl.java
@@ -74,6 +74,8 @@ public class ClientManagerFacadeImpl extends ClientManagerFacade {
startup();
}
+ public boolean isAlive() { return _manager != null && _manager.isAlive(); }
+
private static final long MAX_TIME_TO_REBUILD = 10*60*1000;
public boolean verifyClientLiveliness() {
if (_manager == null) return true;
From ca783caff160012ea1dcff63cc0c722a2900dc56 Mon Sep 17 00:00:00 2001
From: zzz
Date: Mon, 2 Mar 2009 18:58:37 +0000
Subject: [PATCH 030/688] prevent configpeer.jsp oom
---
router/java/src/net/i2p/router/Blocklist.java | 27 +++++++++----------
1 file changed, 13 insertions(+), 14 deletions(-)
diff --git a/router/java/src/net/i2p/router/Blocklist.java b/router/java/src/net/i2p/router/Blocklist.java
index 1c50eaa65f..4e94d77095 100644
--- a/router/java/src/net/i2p/router/Blocklist.java
+++ b/router/java/src/net/i2p/router/Blocklist.java
@@ -754,37 +754,36 @@ public class Blocklist {
// We already shitlisted in shitlist(peer), that's good enough
}
+ /** write directly to the stream so we don't OOM on a huge list */
public void renderStatusHTML(Writer out) throws IOException {
- StringBuffer buf = new StringBuffer(1024);
- buf.append("
IP Blocklist
");
+ out.write("
IP Blocklist
");
Set singles = new TreeSet();
synchronized(_singleIPBlocklist) {
singles.addAll(_singleIPBlocklist);
}
if (singles.size() > 0) {
- buf.append("
Transient IPs
");
+ out.write("
Transient IPs
");
for (Iterator iter = singles.iterator(); iter.hasNext(); ) {
int ip = ((Integer) iter.next()).intValue();
- buf.append("
").append(toStr(ip)).append("
\n");
+ out.write("
"); out.write(toStr(ip)); out.write("
\n");
}
- buf.append("
");
+ out.write("
");
}
if (_blocklistSize > 0) {
- buf.append("
IPs from Blocklist File
From
To
");
+ out.write("
IPs from Blocklist File
From
To
");
for (int i = 0; i < _blocklistSize; i++) {
int from = getFrom(_blocklist[i]);
- buf.append("
").append(toStr(from)).append("
");
+ out.write("
"); out.write(toStr(from)); out.write("
");
int to = getTo(_blocklist[i]);
- if (to != from)
- buf.append(toStr(to)).append("
From ca3b6eb00daf0ec644f8f4dba09b53d7f3a7a28e Mon Sep 17 00:00:00 2001
From: zzz
Date: Fri, 13 Mar 2009 16:57:51 +0000
Subject: [PATCH 042/688] catch a reported NPE ?
---
.../i2p/i2ptunnel/I2PTunnelHTTPServer.java | 19 ++++++++++++++++++-
1 file changed, 18 insertions(+), 1 deletion(-)
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPServer.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPServer.java
index 536844af9c..d6cb40a259 100644
--- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPServer.java
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPServer.java
@@ -171,7 +171,24 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer {
sender.start();
browserout = _browser.getOutputStream();
- serverin = _webserver.getInputStream();
+ // NPE seen here in 0.7-7, caused by addition of socket.close() in the
+ // catch (IOException ioe) block above in blockingHandle() ???
+ // CRIT [ad-130280.hc] net.i2p.util.I2PThread : Killing thread Thread-130280.hc
+ // java.lang.NullPointerException
+ // at java.io.FileInputStream.(FileInputStream.java:131)
+ // at java.net.SocketInputStream.(SocketInputStream.java:44)
+ // at java.net.PlainSocketImpl.getInputStream(PlainSocketImpl.java:401)
+ // at java.net.Socket$2.run(Socket.java:779)
+ // at java.security.AccessController.doPrivileged(Native Method)
+ // at java.net.Socket.getInputStream(Socket.java:776)
+ // at net.i2p.i2ptunnel.I2PTunnelHTTPServer$CompressedRequestor.run(I2PTunnelHTTPServer.java:174)
+ // at java.lang.Thread.run(Thread.java:619)
+ // at net.i2p.util.I2PThread.run(I2PThread.java:71)
+ try {
+ serverin = _webserver.getInputStream();
+ } catch (NullPointerException npe) {
+ throw new IOException("getInputStream NPE");
+ }
CompressedResponseOutputStream compressedOut = new CompressedResponseOutputStream(browserout);
Sender s = new Sender(compressedOut, serverin, "server: server to browser");
if (_log.shouldLog(Log.INFO))
From cf02abd19cf15c00f725866846e486ae5f6afcd3 Mon Sep 17 00:00:00 2001
From: zzz
Date: Fri, 13 Mar 2009 16:58:23 +0000
Subject: [PATCH 043/688] allow .onion addresses for testing
---
.../java/src/net/i2p/i2ptunnel/socks/SOCKS4aServer.java | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/SOCKS4aServer.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/SOCKS4aServer.java
index 2745cb0fa9..23ec70c3fd 100644
--- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/SOCKS4aServer.java
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/SOCKS4aServer.java
@@ -198,7 +198,8 @@ public class SOCKS4aServer extends SOCKSServer {
I2PSocket destSock;
try {
- if (connHostName.toLowerCase().endsWith(".i2p")) {
+ if (connHostName.toLowerCase().endsWith(".i2p") ||
+ connHostName.toLowerCase().endsWith(".onion")) {
_log.debug("connecting to " + connHostName + "...");
// Let's not due a new Dest for every request, huh?
//I2PSocketManager sm = I2PSocketManagerFactory.createManager();
@@ -224,7 +225,7 @@ public class SOCKS4aServer extends SOCKSServer {
} else {
List proxies = t.getProxies(connPort);
if (proxies == null || proxies.size() <= 0) {
- String err = "No outproxy configured for port " + connPort + " and no default configured either";
+ String err = "No outproxy configured for port " + connPort + " and no default configured either - host: " + connHostName;
_log.error(err);
try {
sendRequestReply(Reply.CONNECTION_REFUSED, InetAddress.getByName("127.0.0.1"), 0, out);
From 5a8b3eb8f34d048df9559deb8581e09c99e34267 Mon Sep 17 00:00:00 2001
From: zzz
Date: Fri, 13 Mar 2009 18:27:29 +0000
Subject: [PATCH 044/688] Move HMac to I2PHMac, as jrandom implemented changes
that make it incompatible with the HMac in the android libraries.
---
.../src/net/i2p/crypto/HMAC256Generator.java | 9 +++++----
core/java/src/net/i2p/crypto/HMACGenerator.java | 17 +++++++++--------
.../crypto/macs/{HMac.java => I2PHMac.java} | 10 +++++++---
3 files changed, 21 insertions(+), 15 deletions(-)
rename core/java/src/org/bouncycastle/crypto/macs/{HMac.java => I2PHMac.java} (95%)
diff --git a/core/java/src/net/i2p/crypto/HMAC256Generator.java b/core/java/src/net/i2p/crypto/HMAC256Generator.java
index 2fcaa7b5ed..7d6f67a76e 100644
--- a/core/java/src/net/i2p/crypto/HMAC256Generator.java
+++ b/core/java/src/net/i2p/crypto/HMAC256Generator.java
@@ -7,7 +7,8 @@ import net.i2p.data.Hash;
import net.i2p.data.SessionKey;
import org.bouncycastle.crypto.Digest;
-import org.bouncycastle.crypto.macs.HMac;
+import org.bouncycastle.crypto.Mac;
+import org.bouncycastle.crypto.macs.I2PHMac;
/**
* Calculate the HMAC-SHA256 of a key+message. All the good stuff occurs
@@ -19,15 +20,15 @@ public class HMAC256Generator extends HMACGenerator {
public HMAC256Generator(I2PAppContext context) { super(context); }
@Override
- protected HMac acquire() {
+ protected Mac acquire() {
synchronized (_available) {
if (_available.size() > 0)
- return (HMac)_available.remove(0);
+ return (Mac)_available.remove(0);
}
// the HMAC is hardcoded to use SHA256 digest size
// for backwards compatability. next time we have a backwards
// incompatible change, we should update this by removing ", 32"
- return new HMac(new Sha256ForMAC());
+ return new I2PHMac(new Sha256ForMAC());
}
private class Sha256ForMAC extends Sha256Standalone implements Digest {
diff --git a/core/java/src/net/i2p/crypto/HMACGenerator.java b/core/java/src/net/i2p/crypto/HMACGenerator.java
index 8388590a29..52b29e19ba 100644
--- a/core/java/src/net/i2p/crypto/HMACGenerator.java
+++ b/core/java/src/net/i2p/crypto/HMACGenerator.java
@@ -10,7 +10,8 @@ import net.i2p.data.Hash;
import net.i2p.data.SessionKey;
import org.bouncycastle.crypto.digests.MD5Digest;
-import org.bouncycastle.crypto.macs.HMac;
+import org.bouncycastle.crypto.Mac;
+import org.bouncycastle.crypto.macs.I2PHMac;
/**
* Calculate the HMAC-MD5 of a key+message. All the good stuff occurs
@@ -49,7 +50,7 @@ public class HMACGenerator {
if ((key == null) || (key.getData() == null) || (data == null))
throw new NullPointerException("Null arguments for HMAC");
- HMac mac = acquire();
+ Mac mac = acquire();
mac.init(key.getData());
mac.update(data, offset, length);
//byte rv[] = new byte[Hash.HASH_LENGTH];
@@ -73,7 +74,7 @@ public class HMACGenerator {
if ((key == null) || (key.getData() == null) || (curData == null))
throw new NullPointerException("Null arguments for HMAC");
- HMac mac = acquire();
+ Mac mac = acquire();
mac.init(key.getData());
mac.update(curData, curOffset, curLength);
byte rv[] = acquireTmp();
@@ -86,17 +87,17 @@ public class HMACGenerator {
return eq;
}
- protected HMac acquire() {
+ protected Mac acquire() {
synchronized (_available) {
if (_available.size() > 0)
- return (HMac)_available.remove(0);
+ return (Mac)_available.remove(0);
}
// the HMAC is hardcoded to use SHA256 digest size
// for backwards compatability. next time we have a backwards
// incompatible change, we should update this by removing ", 32"
- return new HMac(new MD5Digest(), 32);
+ return new I2PHMac(new MD5Digest(), 32);
}
- private void release(HMac mac) {
+ private void release(Mac mac) {
synchronized (_available) {
if (_available.size() < 64)
_available.add(mac);
@@ -122,4 +123,4 @@ public class HMACGenerator {
_availableTmp.add((Object)tmp);
}
}
-}
\ No newline at end of file
+}
diff --git a/core/java/src/org/bouncycastle/crypto/macs/HMac.java b/core/java/src/org/bouncycastle/crypto/macs/I2PHMac.java
similarity index 95%
rename from core/java/src/org/bouncycastle/crypto/macs/HMac.java
rename to core/java/src/org/bouncycastle/crypto/macs/I2PHMac.java
index 7176c8acaf..a566e8a799 100644
--- a/core/java/src/org/bouncycastle/crypto/macs/HMac.java
+++ b/core/java/src/org/bouncycastle/crypto/macs/I2PHMac.java
@@ -42,8 +42,12 @@ import org.bouncycastle.crypto.Mac;
* a frequently used buffer (called on doFinal). changes released into the public
* domain in 2005.
*
+ * This is renamed from HMac because the constructor HMac(digest, sz) does not exist
+ * in the standard bouncycastle library, thus it conflicts in JVMs that contain the
+ * standard library (Android).
+ *
*/
-public class HMac
+public class I2PHMac
implements Mac
{
private final static int BLOCK_LENGTH = 64;
@@ -56,12 +60,12 @@ implements Mac
private byte[] inputPad = new byte[BLOCK_LENGTH];
private byte[] outputPad = new byte[BLOCK_LENGTH];
- public HMac(
+ public I2PHMac(
Digest digest)
{
this(digest, digest.getDigestSize());
}
- public HMac(
+ public I2PHMac(
Digest digest, int sz)
{
this.digest = digest;
From b8f22bf3bf682291c6530cfeba92ce748586a8be Mon Sep 17 00:00:00 2001
From: zzz
Date: Fri, 13 Mar 2009 18:56:16 +0000
Subject: [PATCH 045/688] - Add FileStreamFactory and I2PFile to deal with the
problems from the code CWD is / but the only writable directory is
/data/data/net.i2p.router/files/ - still a ton of places to be fixed, will
be fixed up as things get working - Load some config files from resources at
startup - Fix up logging - Add reseed capability, by copying some code over
from routerconsole - Deal with conflicting bouncycastle libs
---
android/AndroidManifest.xml | 4 +-
android/build.xml | 61 ++++++++++-
android/res/layout/main.xml | 5 +
android/res/raw/logger_config | 3 +
android/res/raw/router_config | 7 ++
android/src/net/i2p/router/I2PAndroid.java | 100 ++++++++++++++++++
.../src/net/i2p/router/web/ReseedChecker.java | 37 +++++++
.../src/net/i2p/util/FileStreamFactory.java | 64 +++++++++++
android/src/net/i2p/util/I2PFile.java | 29 +++++
android/src/net/i2p/util/LogWriter.java | 40 ++++---
.../src/net/i2p/router/web/ReseedHandler.java | 6 +-
core/java/src/net/i2p/data/DataHelper.java | 3 +-
.../src/net/i2p/util/FileStreamFactory.java | 36 +++++++
core/java/src/net/i2p/util/I2PFile.java | 24 +++++
core/java/src/net/i2p/util/LogManager.java | 8 +-
.../java/src/net/i2p/router/KeyManager.java | 5 +-
router/java/src/net/i2p/router/Router.java | 10 +-
.../kademlia/PersistentDataStore.java | 12 ++-
.../peermanager/ProfilePersistenceHelper.java | 12 ++-
.../router/startup/CreateRouterInfoJob.java | 5 +-
.../i2p/router/startup/LoadRouterInfoJob.java | 10 +-
.../router/startup/RebuildRouterInfoJob.java | 8 +-
.../router/transport/ntcp/EventPumper.java | 2 +-
23 files changed, 437 insertions(+), 54 deletions(-)
create mode 100644 android/res/raw/logger_config
create mode 100644 android/res/raw/router_config
create mode 100644 android/src/net/i2p/router/web/ReseedChecker.java
create mode 100644 android/src/net/i2p/util/FileStreamFactory.java
create mode 100644 android/src/net/i2p/util/I2PFile.java
create mode 100644 core/java/src/net/i2p/util/FileStreamFactory.java
create mode 100644 core/java/src/net/i2p/util/I2PFile.java
diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml
index b45a406134..cb63a80c13 100644
--- a/android/AndroidManifest.xml
+++ b/android/AndroidManifest.xml
@@ -3,9 +3,11 @@
package="net.i2p.router"
android:versionCode="1"
android:versionName="1.0.0">
+
+ android:label="@string/app_name"
+ android:launchMode="singleTask" >
diff --git a/android/build.xml b/android/build.xml
index a7b4119968..5875c5fed8 100644
--- a/android/build.xml
+++ b/android/build.xml
@@ -101,12 +101,15 @@
Creating output directories if needed...
+
+
+
@@ -140,7 +143,7 @@
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+ Converting compiled files and external libraries into ${outdir}/${dex-file}...
diff --git a/android/res/layout/main.xml b/android/res/layout/main.xml
index 3bfc31cff9..d764115276 100644
--- a/android/res/layout/main.xml
+++ b/android/res/layout/main.xml
@@ -9,5 +9,10 @@
android:layout_height="wrap_content"
android:text="Hello World, I2PAndroid"
/>
+
diff --git a/android/res/raw/logger_config b/android/res/raw/logger_config
new file mode 100644
index 0000000000..2aeabb9f64
--- /dev/null
+++ b/android/res/raw/logger_config
@@ -0,0 +1,3 @@
+logger.defaultLevel=INFO
+logger.record.net.i2p.router.transport.FIFOBandwidthRefiller=ERROR
+logger.record.net.i2p.stat.Rate=ERROR
diff --git a/android/res/raw/router_config b/android/res/raw/router_config
new file mode 100644
index 0000000000..19c6095429
--- /dev/null
+++ b/android/res/raw/router_config
@@ -0,0 +1,7 @@
+# initial router.config
+# save memory
+router.prng.buffers=2
+router.decayingBloomFilterM=20
+stat.full=false
+# no I2CP
+i2p.dummyClientFacade=true
diff --git a/android/src/net/i2p/router/I2PAndroid.java b/android/src/net/i2p/router/I2PAndroid.java
index 6b65bac52b..c08670e36c 100644
--- a/android/src/net/i2p/router/I2PAndroid.java
+++ b/android/src/net/i2p/router/I2PAndroid.java
@@ -1,18 +1,118 @@
package net.i2p.router;
import android.app.Activity;
+import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.Resources.NotFoundException;
import android.os.Bundle;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.io.IOException;
+
import net.i2p.router.Router;
+import net.i2p.router.web.ReseedChecker;
+import net.i2p.util.I2PFile;
public class I2PAndroid extends Activity
{
+ static Context _context;
+
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
+
+ _context = this; // Activity extends Context
+ debugStuff();
+ initialize();
+
Router.main(null);
+ System.err.println("Router.main finished");
+
+ ReseedChecker.checkReseed();
}
+
+ public void onRestart()
+ {
+ System.err.println("onRestart called");
+ super.onRestart();
+ }
+
+ public void onResume()
+ {
+ System.err.println("onResume called");
+ super.onResume();
+ }
+
+ public void onPause()
+ {
+ System.err.println("onPause called");
+ super.onPause();
+ }
+
+ public void onStop()
+ {
+ System.err.println("onStop called");
+ super.onStop();
+ }
+
+ public void onDestroy()
+ {
+ System.err.println("onDestroy called");
+ super.onDestroy();
+ }
+
+ public static Context getContext() {
+ return _context;
+ }
+
+ private void debugStuff() {
+ System.err.println("java.vendor" + ": " + System.getProperty("java.vendor"));
+ System.err.println("java.version" + ": " + System.getProperty("java.version"));
+ System.err.println("os.arch" + ": " + System.getProperty("os.arch"));
+ System.err.println("os.name" + ": " + System.getProperty("os.name"));
+ System.err.println("os.version" + ": " + System.getProperty("os.version"));
+ System.err.println("user.dir" + ": " + System.getProperty("user.dir"));
+ System.err.println("user.home" + ": " + System.getProperty("user.home"));
+ System.err.println("user.name" + ": " + System.getProperty("user.name"));
+ }
+
+ private void initialize() {
+ // Until we can edit the router.config on the device,
+ // copy it from the resource every time.
+ // File f = new I2PFile("router.config");
+ // if (!f.exists()) {
+ copyResourceToFile(R.raw.router_config, "router.config");
+ copyResourceToFile(R.raw.logger_config, "logger.config");
+ copyResourceToFile(R.raw.blocklist_txt, "blocklist.txt");
+ // }
+ }
+
+ private void copyResourceToFile(int resID, String f) {
+ InputStream in = null;
+ FileOutputStream out = null;
+
+ System.err.println("Creating file " + f + " from resource");
+ byte buf[] = new byte[4096];
+ try {
+ // Context methods
+ in = getResources().openRawResource(resID);
+ out = openFileOutput(f, 0);
+
+ int read = 0;
+ while ( (read = in.read(buf)) != -1)
+ out.write(buf, 0, read);
+
+ } catch (IOException ioe) {
+ } catch (Resources.NotFoundException nfe) {
+ } finally {
+ if (in != null) try { in.close(); } catch (IOException ioe) {}
+ if (out != null) try { out.close(); } catch (IOException ioe) {}
+ }
+ }
+
}
diff --git a/android/src/net/i2p/router/web/ReseedChecker.java b/android/src/net/i2p/router/web/ReseedChecker.java
new file mode 100644
index 0000000000..96eccce51d
--- /dev/null
+++ b/android/src/net/i2p/router/web/ReseedChecker.java
@@ -0,0 +1,37 @@
+package net.i2p.router.web;
+
+import java.io.File;
+
+import net.i2p.router.web.ReseedHandler;
+import net.i2p.util.I2PFile;
+
+/**
+ * Copied from RouterConsoleRunner.java
+ */
+public class ReseedChecker {
+
+ public static void checkReseed() {
+
+ System.err.println("Checking to see if we should reseed");
+ // we check the i2p installation directory (.) for a flag telling us not to reseed,
+ // but also check the home directory for that flag too, since new users installing i2p
+ // don't have an installation directory that they can put the flag in yet.
+ File noReseedFile = new I2PFile(new I2PFile(System.getProperty("user.home")), ".i2pnoreseed");
+ File noReseedFileAlt1 = new I2PFile(new I2PFile(System.getProperty("user.home")), "noreseed.i2p");
+ File noReseedFileAlt2 = new I2PFile(".i2pnoreseed");
+ File noReseedFileAlt3 = new I2PFile("noreseed.i2p");
+ if (!noReseedFile.exists() && !noReseedFileAlt1.exists() && !noReseedFileAlt2.exists() && !noReseedFileAlt3.exists()) {
+ File netDb = new I2PFile("netDb");
+ // sure, some of them could be "my.info" or various leaseSet- files, but chances are,
+ // if someone has those files, they've already been seeded (at least enough to let them
+ // get i2p started - they can reseed later in the web console)
+ String names[] = (netDb.exists() ? netDb.list() : null);
+ if ( (names == null) || (names.length < 15) ) {
+ System.err.println("Yes, reseeding now");
+ ReseedHandler reseedHandler = new ReseedHandler();
+ reseedHandler.requestReseed();
+ }
+ }
+ }
+
+}
diff --git a/android/src/net/i2p/util/FileStreamFactory.java b/android/src/net/i2p/util/FileStreamFactory.java
new file mode 100644
index 0000000000..b7a65e4f21
--- /dev/null
+++ b/android/src/net/i2p/util/FileStreamFactory.java
@@ -0,0 +1,64 @@
+/*
+ * This is free software, do as you please.
+ */
+
+package net.i2p.util;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+
+import net.i2p.router.I2PAndroid;
+
+/**
+ * Use android static file stream methods
+ * gaaah:
+ * 1) the CWD is /
+ * 2) we can only access /data/data/net.i2p.router/files/
+ * 3) you can't change your CWD in Java
+ * so we have this lovely and the one in I2PFile.
+ *
+ * @author zzz
+ */
+public class FileStreamFactory {
+ private static final String DIR = "/data/data/net.i2p.router/files/";
+
+ /** hopefully no path separators in string */
+ public static FileInputStream getFileInputStream(String f) throws FileNotFoundException {
+ System.err.println("Input file-s: " + I2PAndroid.getContext().getFileStreamPath(f).getAbsolutePath());
+ return I2PAndroid.getContext().openFileInput(f);
+ }
+
+ public static FileInputStream getFileInputStream(File f) throws FileNotFoundException {
+ System.err.println("Input file-f: " + getPath(f) +
+ ' ' + f.getAbsolutePath());
+ //return I2PAndroid.getContext().openFileInput(f.getName());
+ return new FileInputStream(getPath(f));
+ }
+
+ /** hopefully no path separators in string */
+ public static FileOutputStream getFileOutputStream(String f) throws FileNotFoundException {
+ System.err.println("Output file-s: " + I2PAndroid.getContext().getFileStreamPath(f).getAbsolutePath());
+ return I2PAndroid.getContext().openFileOutput(f, 0);
+ }
+
+ public static FileOutputStream getFileOutputStream(File f) throws FileNotFoundException {
+ System.err.println("Output file-f: " + getPath(f) +
+ ' ' + f.getAbsolutePath());
+ //return I2PAndroid.getContext().openFileOutput(f.getName(), 0);
+ return new FileOutputStream(getPath(f));
+ }
+
+ /**
+ * preserve path but convert /foo/blah to /data/data/net.i2p.router/files/foo/blah
+ * Although if the File arg was created with new I2PFile() then this isn't required
+ *
+ */
+ private static String getPath(File f) {
+ String abs = f.getAbsolutePath();
+ if (abs.startsWith(DIR))
+ return abs;
+ return DIR + abs.substring(1); // strip extra '/'
+ }
+}
diff --git a/android/src/net/i2p/util/I2PFile.java b/android/src/net/i2p/util/I2PFile.java
new file mode 100644
index 0000000000..94bda029b7
--- /dev/null
+++ b/android/src/net/i2p/util/I2PFile.java
@@ -0,0 +1,29 @@
+/*
+ * This is free software, do as you please.
+ */
+
+package net.i2p.util;
+
+import java.io.File;
+
+/**
+ * gaaah:
+ * 1) the CWD is /
+ * 2) we can only access /data/data/net.i2p.router/files/
+ * 3) you can't change your CWD in Java
+ * so we have this lovely and the one in FileStreamFactory.
+ *
+ * @author zzz
+ */
+public class I2PFile extends File {
+
+ public I2PFile (String f) {
+ super("/data/data/net.i2p.router/files/" + f);
+ }
+
+ /** one level deep only */
+ public I2PFile (File p, String f) {
+ super("/data/data/net.i2p.router/files/" + p.getName(), f);
+ }
+
+}
diff --git a/android/src/net/i2p/util/LogWriter.java b/android/src/net/i2p/util/LogWriter.java
index 847730d4f0..03f5577ae7 100644
--- a/android/src/net/i2p/util/LogWriter.java
+++ b/android/src/net/i2p/util/LogWriter.java
@@ -87,36 +87,44 @@ class LogWriter implements Runnable {
private void writeRecord(LogRecord rec) {
if (rec.getThrowable() == null)
- log(rec.getPriority(), rec.getSourceName(), null, rec.getThreadName(), rec.getMessage());
+ log(rec.getPriority(), rec.getSource(), rec.getSourceName(), rec.getThreadName(), rec.getMessage());
else
- log(rec.getPriority(), rec.getSourceName(), null, rec.getThreadName(), rec.getMessage(), rec.getThrowable());
+ log(rec.getPriority(), rec.getSource(), rec.getSourceName(), rec.getThreadName(), rec.getMessage(), rec.getThrowable());
}
- public void log(int priority, String className, String name, String threadName, String msg) {
- if (className != null)
+ public void log(int priority, Class src, String name, String threadName, String msg) {
+ if (src != null) {
+ String tag = src.getName();
+ int dot = tag.lastIndexOf(".");
+ if (dot >= 0)
+ tag = tag.substring(dot + 1);
android.util.Log.println(toAndroidLevel(priority),
- className,
- threadName + ' ' + msg);
- else if (name != null)
+ tag,
+ '[' + threadName + "] " + msg);
+ } else if (name != null)
android.util.Log.println(toAndroidLevel(priority),
name,
- threadName + ' ' + msg);
+ '[' + threadName + "] " + msg);
else
android.util.Log.println(toAndroidLevel(priority),
threadName, msg);
}
- public void log(int priority, String className, String name, String threadName, String msg, Throwable t) {
- if (className != null)
+ public void log(int priority, Class src, String name, String threadName, String msg, Throwable t) {
+ if (src != null) {
+ String tag = src.getName();
+ int dot = tag.lastIndexOf(".");
+ if (dot >= 0)
+ tag = tag.substring(dot + 1);
android.util.Log.println(toAndroidLevel(priority),
- className,
- threadName + ' ' + msg +
- msg + ' ' + t.toString() + ' ' + android.util.Log.getStackTraceString(t));
- else if (name != null)
+ tag,
+ '[' + threadName + "] " + msg +
+ ' ' + t.toString() + ' ' + android.util.Log.getStackTraceString(t));
+ } else if (name != null)
android.util.Log.println(toAndroidLevel(priority),
name,
- threadName + ' ' + msg +
- msg + ' ' + t.toString() + ' ' + android.util.Log.getStackTraceString(t));
+ '[' + threadName + "] " + msg +
+ ' ' + t.toString() + ' ' + android.util.Log.getStackTraceString(t));
else
android.util.Log.println(toAndroidLevel(priority),
threadName,
diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ReseedHandler.java b/apps/routerconsole/java/src/net/i2p/router/web/ReseedHandler.java
index 066cb11443..3d3d603fa4 100644
--- a/apps/routerconsole/java/src/net/i2p/router/web/ReseedHandler.java
+++ b/apps/routerconsole/java/src/net/i2p/router/web/ReseedHandler.java
@@ -15,6 +15,8 @@ import java.util.StringTokenizer;
import net.i2p.I2PAppContext;
import net.i2p.router.RouterContext;
import net.i2p.util.EepGet;
+import net.i2p.util.FileStreamFactory;
+import net.i2p.util.I2PFile;
import net.i2p.util.I2PThread;
import net.i2p.util.Log;
@@ -250,11 +252,11 @@ public class ReseedHandler {
private void writeSeed(String name, byte data[]) throws Exception {
String dirName = "netDb"; // _context.getProperty("router.networkDatabase.dbDir", "netDb");
- File netDbDir = new File(dirName);
+ File netDbDir = new I2PFile(dirName);
if (!netDbDir.exists()) {
boolean ok = netDbDir.mkdirs();
}
- FileOutputStream fos = new FileOutputStream(new File(netDbDir, "routerInfo-" + name + ".dat"));
+ FileOutputStream fos = FileStreamFactory.getFileOutputStream(new I2PFile(netDbDir, "routerInfo-" + name + ".dat"));
fos.write(data);
fos.close();
}
diff --git a/core/java/src/net/i2p/data/DataHelper.java b/core/java/src/net/i2p/data/DataHelper.java
index 53e32a347e..55b4245625 100644
--- a/core/java/src/net/i2p/data/DataHelper.java
+++ b/core/java/src/net/i2p/data/DataHelper.java
@@ -37,6 +37,7 @@ import java.util.TreeMap;
import java.util.zip.Deflater;
import net.i2p.util.ByteCache;
+import net.i2p.util.FileStreamFactory;
import net.i2p.util.OrderedProperties;
import net.i2p.util.ReusableGZIPInputStream;
import net.i2p.util.ReusableGZIPOutputStream;
@@ -217,7 +218,7 @@ public class DataHelper {
loadProps(props, file, false);
}
public static void loadProps(Properties props, File file, boolean forceLowerCase) throws IOException {
- loadProps(props, new FileInputStream(file), forceLowerCase);
+ loadProps(props, FileStreamFactory.getFileInputStream(file), forceLowerCase);
}
public static void loadProps(Properties props, InputStream inStr) throws IOException {
loadProps(props, inStr, false);
diff --git a/core/java/src/net/i2p/util/FileStreamFactory.java b/core/java/src/net/i2p/util/FileStreamFactory.java
new file mode 100644
index 0000000000..01d5056658
--- /dev/null
+++ b/core/java/src/net/i2p/util/FileStreamFactory.java
@@ -0,0 +1,36 @@
+/*
+ * public domain
+ */
+
+package net.i2p.util;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+
+
+/**
+ * This is pulled out and replaced in the android build.
+ *
+ * @author zzz
+ */
+public class FileStreamFactory {
+
+ public static FileInputStream getFileInputStream(String f) throws FileNotFoundException {
+ return new FileInputStream(f);
+ }
+
+ public static FileInputStream getFileInputStream(File f) throws FileNotFoundException {
+ return new FileInputStream(f);
+ }
+
+ public static FileOutputStream getFileOutputStream(String f) throws FileNotFoundException {
+ return new FileOutputStream(f);
+ }
+
+ public static FileOutputStream getFileOutputStream(File f) throws FileNotFoundException {
+ return new FileOutputStream(f);
+ }
+
+}
diff --git a/core/java/src/net/i2p/util/I2PFile.java b/core/java/src/net/i2p/util/I2PFile.java
new file mode 100644
index 0000000000..107286edf1
--- /dev/null
+++ b/core/java/src/net/i2p/util/I2PFile.java
@@ -0,0 +1,24 @@
+/*
+ * public domain
+ */
+
+package net.i2p.util;
+
+import java.io.File;
+
+/**
+ * This is pulled out and replaced in the android build.
+ *
+ * @author zzz
+ */
+public class I2PFile extends File {
+
+ public I2PFile (String f) {
+ super(f);
+ }
+
+ public I2PFile (File p, String f) {
+ super(p, f);
+ }
+
+}
diff --git a/core/java/src/net/i2p/util/LogManager.java b/core/java/src/net/i2p/util/LogManager.java
index 1f957515ca..52b828af91 100644
--- a/core/java/src/net/i2p/util/LogManager.java
+++ b/core/java/src/net/i2p/util/LogManager.java
@@ -240,7 +240,7 @@ public class LogManager {
//
private void loadConfig() {
- File cfgFile = new File(_location);
+ File cfgFile = new I2PFile(_location);
if (!cfgFile.exists()) {
if (!_alreadyNoticedMissingConfig) {
if (_log.shouldLog(Log.WARN))
@@ -268,11 +268,11 @@ public class LogManager {
Properties p = new Properties();
FileInputStream fis = null;
try {
- fis = new FileInputStream(cfgFile);
+ fis = FileStreamFactory.getFileInputStream(cfgFile);
p.load(fis);
_configLastRead = _context.clock().now();
} catch (IOException ioe) {
- System.err.println("Error loading logger config from " + new File(_location).getAbsolutePath());
+ System.err.println("Error loading logger config from " + new I2PFile(_location).getAbsolutePath());
} finally {
if (fis != null) try {
fis.close();
@@ -540,7 +540,7 @@ public class LogManager {
String config = createConfig();
FileOutputStream fos = null;
try {
- fos = new FileOutputStream(_location);
+ fos = FileStreamFactory.getFileOutputStream(_location);
fos.write(config.getBytes());
return true;
} catch (IOException ioe) {
diff --git a/router/java/src/net/i2p/router/KeyManager.java b/router/java/src/net/i2p/router/KeyManager.java
index 4e2ed2c518..f2150b9238 100644
--- a/router/java/src/net/i2p/router/KeyManager.java
+++ b/router/java/src/net/i2p/router/KeyManager.java
@@ -26,6 +26,7 @@ import net.i2p.data.PublicKey;
import net.i2p.data.SigningPrivateKey;
import net.i2p.data.SigningPublicKey;
import net.i2p.util.Clock;
+import net.i2p.util.FileStreamFactory;
import net.i2p.util.Log;
/**
@@ -205,12 +206,12 @@ public class KeyManager {
FileInputStream in = null;
try {
if (exists) {
- out = new FileOutputStream(keyFile);
+ out = FileStreamFactory.getFileOutputStream(keyFile);
structure.writeBytes(out);
return structure;
} else {
if (keyFile.exists()) {
- in = new FileInputStream(keyFile);
+ in = FileStreamFactory.getFileInputStream(keyFile);
structure.readBytes(in);
return structure;
} else {
diff --git a/router/java/src/net/i2p/router/Router.java b/router/java/src/net/i2p/router/Router.java
index 13e801458c..c33dc3e634 100644
--- a/router/java/src/net/i2p/router/Router.java
+++ b/router/java/src/net/i2p/router/Router.java
@@ -40,7 +40,9 @@ import net.i2p.router.transport.FIFOBandwidthLimiter;
import net.i2p.stat.Rate;
import net.i2p.stat.RateStat;
import net.i2p.stat.StatManager;
+import net.i2p.util.FileStreamFactory;
import net.i2p.util.FileUtil;
+import net.i2p.util.I2PFile;
import net.i2p.util.I2PThread;
import net.i2p.util.Log;
import net.i2p.util.SimpleScheduler;
@@ -292,7 +294,7 @@ public class Router {
}
Properties props = new Properties();
try {
- File f = new File(filename);
+ File f = new I2PFile(filename);
if (f.canRead()) {
DataHelper.loadProps(props, f);
// dont be a wanker
@@ -945,7 +947,7 @@ public class Router {
public boolean saveConfig() {
FileOutputStream fos = null;
try {
- fos = new FileOutputStream(_configFilename);
+ fos = FileStreamFactory.getFileOutputStream(_configFilename);
StringBuffer buf = new StringBuffer(8*1024);
synchronized (_config) {
TreeSet ordered = new TreeSet(_config.keySet());
@@ -1331,7 +1333,7 @@ class MarkLiveliness implements Runnable {
private void ping() {
FileOutputStream fos = null;
try {
- fos = new FileOutputStream(_pingFile);
+ fos = FileStreamFactory.getFileOutputStream(_pingFile);
fos.write(("" + System.currentTimeMillis()).getBytes());
} catch (IOException ioe) {
System.err.println("Error writing to ping file");
@@ -1378,7 +1380,7 @@ class PersistRouterInfoJob extends JobImpl {
FileOutputStream fos = null;
try {
- fos = new FileOutputStream(infoFilename);
+ fos = FileStreamFactory.getFileOutputStream(infoFilename);
info.writeBytes(fos);
} catch (DataFormatException dfe) {
_log.error("Error rebuilding the router information", dfe);
diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/PersistentDataStore.java b/router/java/src/net/i2p/router/networkdb/kademlia/PersistentDataStore.java
index 5d0d219dbe..1d9490a332 100644
--- a/router/java/src/net/i2p/router/networkdb/kademlia/PersistentDataStore.java
+++ b/router/java/src/net/i2p/router/networkdb/kademlia/PersistentDataStore.java
@@ -26,6 +26,8 @@ import net.i2p.data.RouterInfo;
import net.i2p.router.JobImpl;
import net.i2p.router.Router;
import net.i2p.router.RouterContext;
+import net.i2p.util.FileStreamFactory;
+import net.i2p.util.I2PFile;
import net.i2p.util.I2PThread;
import net.i2p.util.Log;
@@ -171,11 +173,11 @@ class PersistentDataStore extends TransientDataStore {
else
throw new IOException("We don't know how to write objects of type " + data.getClass().getName());
- dbFile = new File(dbDir, filename);
+ dbFile = new I2PFile(dbDir, filename);
long dataPublishDate = getPublishDate(data);
if (dbFile.lastModified() < dataPublishDate) {
// our filesystem is out of date, lets replace it
- fos = new FileOutputStream(dbFile);
+ fos = FileStreamFactory.getFileOutputStream(dbFile);
try {
data.writeBytes(fos);
fos.close();
@@ -278,7 +280,7 @@ class PersistentDataStore extends TransientDataStore {
FileInputStream fis = null;
boolean corrupt = false;
try {
- fis = new FileInputStream(_routerFile);
+ fis = FileStreamFactory.getFileInputStream(_routerFile);
RouterInfo ri = new RouterInfo();
ri.readBytes(fis);
if (ri.getNetworkId() != Router.NETWORK_ID) {
@@ -312,7 +314,7 @@ class PersistentDataStore extends TransientDataStore {
private File getDbDir() throws IOException {
- File f = new File(_dbDir);
+ File f = new I2PFile(_dbDir);
if (!f.exists()) {
boolean created = f.mkdirs();
if (!created)
@@ -362,7 +364,7 @@ class PersistentDataStore extends TransientDataStore {
private void removeFile(Hash key, File dir) throws IOException {
String riName = getRouterInfoName(key);
- File f = new File(dir, riName);
+ File f = new I2PFile(dir, riName);
if (f.exists()) {
boolean removed = f.delete();
if (!removed)
diff --git a/router/java/src/net/i2p/router/peermanager/ProfilePersistenceHelper.java b/router/java/src/net/i2p/router/peermanager/ProfilePersistenceHelper.java
index fd88c406bb..6b8e3105e4 100644
--- a/router/java/src/net/i2p/router/peermanager/ProfilePersistenceHelper.java
+++ b/router/java/src/net/i2p/router/peermanager/ProfilePersistenceHelper.java
@@ -18,6 +18,8 @@ import net.i2p.data.DataFormatException;
import net.i2p.data.DataHelper;
import net.i2p.data.Hash;
import net.i2p.router.RouterContext;
+import net.i2p.util.FileStreamFactory;
+import net.i2p.util.I2PFile;
import net.i2p.util.Log;
class ProfilePersistenceHelper {
@@ -61,7 +63,7 @@ class ProfilePersistenceHelper {
long before = _context.clock().now();
OutputStream fos = null;
try {
- fos = new BufferedOutputStream(new GZIPOutputStream(new FileOutputStream(f)));
+ fos = new BufferedOutputStream(new GZIPOutputStream(FileStreamFactory.getFileOutputStream(f)));
writeProfile(profile, fos);
} catch (IOException ioe) {
_log.error("Error writing profile to " + f);
@@ -264,10 +266,10 @@ class ProfilePersistenceHelper {
private void loadProps(Properties props, File file) {
try {
- FileInputStream fin = new FileInputStream(file);
+ FileInputStream fin = FileStreamFactory.getFileInputStream(file);
int c = fin.read();
fin.close();
- fin = new FileInputStream(file); // ghetto mark+reset
+ fin = FileStreamFactory.getFileInputStream(file); // ghetto mark+reset
if (c == '#') {
// uncompressed
if (_log.shouldLog(Log.INFO))
@@ -299,7 +301,7 @@ class ProfilePersistenceHelper {
}
private File pickFile(PeerProfile profile) {
- return new File(getProfileDir(), "profile-" + profile.getPeer().toBase64() + ".dat");
+ return new I2PFile(getProfileDir(), "profile-" + profile.getPeer().toBase64() + ".dat");
}
private File getProfileDir() {
@@ -315,7 +317,7 @@ class ProfilePersistenceHelper {
dir = DEFAULT_PEER_PROFILE_DIR;
}
}
- _profileDir = new File(dir);
+ _profileDir = new I2PFile(dir);
}
return _profileDir;
}
diff --git a/router/java/src/net/i2p/router/startup/CreateRouterInfoJob.java b/router/java/src/net/i2p/router/startup/CreateRouterInfoJob.java
index 92b176c30f..12c6cee6a2 100644
--- a/router/java/src/net/i2p/router/startup/CreateRouterInfoJob.java
+++ b/router/java/src/net/i2p/router/startup/CreateRouterInfoJob.java
@@ -25,6 +25,7 @@ import net.i2p.router.Job;
import net.i2p.router.JobImpl;
import net.i2p.router.Router;
import net.i2p.router.RouterContext;
+import net.i2p.util.FileStreamFactory;
import net.i2p.util.Log;
public class CreateRouterInfoJob extends JobImpl {
@@ -79,13 +80,13 @@ public class CreateRouterInfoJob extends JobImpl {
String infoFilename = getContext().router().getConfigSetting(Router.PROP_INFO_FILENAME);
if (infoFilename == null)
infoFilename = Router.PROP_INFO_FILENAME_DEFAULT;
- fos1 = new FileOutputStream(infoFilename);
+ fos1 = FileStreamFactory.getFileOutputStream(infoFilename);
info.writeBytes(fos1);
String keyFilename = getContext().router().getConfigSetting(Router.PROP_KEYS_FILENAME);
if (keyFilename == null)
keyFilename = Router.PROP_KEYS_FILENAME_DEFAULT;
- fos2 = new FileOutputStream(keyFilename);
+ fos2 = FileStreamFactory.getFileOutputStream(keyFilename);
privkey.writeBytes(fos2);
signingPrivKey.writeBytes(fos2);
pubkey.writeBytes(fos2);
diff --git a/router/java/src/net/i2p/router/startup/LoadRouterInfoJob.java b/router/java/src/net/i2p/router/startup/LoadRouterInfoJob.java
index 0374922afd..bdd3b9867c 100644
--- a/router/java/src/net/i2p/router/startup/LoadRouterInfoJob.java
+++ b/router/java/src/net/i2p/router/startup/LoadRouterInfoJob.java
@@ -21,6 +21,8 @@ import net.i2p.data.SigningPublicKey;
import net.i2p.router.JobImpl;
import net.i2p.router.Router;
import net.i2p.router.RouterContext;
+import net.i2p.util.FileStreamFactory;
+import net.i2p.util.I2PFile;
import net.i2p.util.Log;
public class LoadRouterInfoJob extends JobImpl {
@@ -62,10 +64,10 @@ public class LoadRouterInfoJob extends JobImpl {
if (keyFilename == null)
keyFilename = Router.PROP_KEYS_FILENAME_DEFAULT;
- File rif = new File(routerInfoFile);
+ File rif = new I2PFile(routerInfoFile);
if (rif.exists())
_infoExists = true;
- File rkf = new File(keyFilename);
+ File rkf = new I2PFile(keyFilename);
if (rkf.exists())
_keysExist = true;
@@ -73,14 +75,14 @@ public class LoadRouterInfoJob extends JobImpl {
FileInputStream fis2 = null;
try {
if (_infoExists) {
- fis1 = new FileInputStream(rif);
+ fis1 = FileStreamFactory.getFileInputStream(rif);
info = new RouterInfo();
info.readBytes(fis1);
_log.debug("Reading in routerInfo from " + rif.getAbsolutePath() + " and it has " + info.getAddresses().size() + " addresses");
}
if (_keysExist) {
- fis2 = new FileInputStream(rkf);
+ fis2 = FileStreamFactory.getFileInputStream(rkf);
PrivateKey privkey = new PrivateKey();
privkey.readBytes(fis2);
SigningPrivateKey signingPrivKey = new SigningPrivateKey();
diff --git a/router/java/src/net/i2p/router/startup/RebuildRouterInfoJob.java b/router/java/src/net/i2p/router/startup/RebuildRouterInfoJob.java
index 967bc7a797..f3905f89ff 100644
--- a/router/java/src/net/i2p/router/startup/RebuildRouterInfoJob.java
+++ b/router/java/src/net/i2p/router/startup/RebuildRouterInfoJob.java
@@ -25,6 +25,8 @@ import net.i2p.data.SigningPublicKey;
import net.i2p.router.JobImpl;
import net.i2p.router.Router;
import net.i2p.router.RouterContext;
+import net.i2p.util.FileStreamFactory;
+import net.i2p.util.I2PFile;
import net.i2p.util.Log;
/**
@@ -93,7 +95,7 @@ public class RebuildRouterInfoJob extends JobImpl {
String keyFilename = getContext().router().getConfigSetting(Router.PROP_KEYS_FILENAME);
if (keyFilename == null)
keyFilename = Router.PROP_KEYS_FILENAME_DEFAULT;
- File keyFile = new File(keyFilename);
+ File keyFile = new I2PFile(keyFilename);
if (keyFile.exists()) {
// ok, no need to rebuild a brand new identity, just update what we can
@@ -102,7 +104,7 @@ public class RebuildRouterInfoJob extends JobImpl {
info = new RouterInfo();
FileInputStream fis = null;
try {
- fis = new FileInputStream(keyFile);
+ fis = FileStreamFactory.getFileInputStream(keyFile);
PrivateKey privkey = new PrivateKey();
privkey.readBytes(fis);
SigningPrivateKey signingPrivKey = new SigningPrivateKey();
@@ -146,7 +148,7 @@ public class RebuildRouterInfoJob extends JobImpl {
FileOutputStream fos = null;
try {
- fos = new FileOutputStream(infoFilename);
+ fos = FileStreamFactory.getFileOutputStream(infoFilename);
info.writeBytes(fos);
} catch (DataFormatException dfe) {
_log.error("Error rebuilding the router information", dfe);
diff --git a/router/java/src/net/i2p/router/transport/ntcp/EventPumper.java b/router/java/src/net/i2p/router/transport/ntcp/EventPumper.java
index 9c75f53283..b3901f07e4 100644
--- a/router/java/src/net/i2p/router/transport/ntcp/EventPumper.java
+++ b/router/java/src/net/i2p/router/transport/ntcp/EventPumper.java
@@ -81,7 +81,7 @@ public class EventPumper implements Runnable {
public void stopPumping() {
_alive = false;
- if (_selector.isOpen())
+ if (_selector != null &&_selector.isOpen())
_selector.wakeup();
}
From 502257542928a7a3548a7b201928ca76781fbf99 Mon Sep 17 00:00:00 2001
From: zzz
Date: Fri, 13 Mar 2009 21:49:27 +0000
Subject: [PATCH 046/688] - Deal with conflicting bouncycastle libs take #2 -
Disable NTCP - Shuffle the startup/shutdown tasks some
---
android/res/raw/router_config | 2 ++
android/src/net/i2p/router/I2PAndroid.java | 19 ++++++++++++++-----
.../src/net/i2p/router/web/ReseedChecker.java | 2 ++
.../src/net/i2p/router/web/ContextHelper.java | 2 +-
.../src/net/i2p/crypto/HMAC256Generator.java | 4 ++--
.../src/net/i2p/crypto/HMACGenerator.java | 6 +++---
6 files changed, 24 insertions(+), 11 deletions(-)
diff --git a/android/res/raw/router_config b/android/res/raw/router_config
index 19c6095429..0e7cd2cedb 100644
--- a/android/res/raw/router_config
+++ b/android/res/raw/router_config
@@ -5,3 +5,5 @@ router.decayingBloomFilterM=20
stat.full=false
# no I2CP
i2p.dummyClientFacade=true
+# for now
+i2np.ntcp.enable=false
diff --git a/android/src/net/i2p/router/I2PAndroid.java b/android/src/net/i2p/router/I2PAndroid.java
index c08670e36c..bb77d290b5 100644
--- a/android/src/net/i2p/router/I2PAndroid.java
+++ b/android/src/net/i2p/router/I2PAndroid.java
@@ -12,6 +12,7 @@ import java.io.InputStream;
import java.io.IOException;
import net.i2p.router.Router;
+import net.i2p.router.web.ContextHelper;
import net.i2p.router.web.ReseedChecker;
import net.i2p.util.I2PFile;
@@ -29,11 +30,6 @@ public class I2PAndroid extends Activity
_context = this; // Activity extends Context
debugStuff();
initialize();
-
- Router.main(null);
- System.err.println("Router.main finished");
-
- ReseedChecker.checkReseed();
}
public void onRestart()
@@ -42,6 +38,16 @@ public class I2PAndroid extends Activity
super.onRestart();
}
+ public void onStart()
+ {
+ System.err.println("onStart called");
+ super.onStart();
+ Router.main(null);
+ System.err.println("Router.main finished");
+
+ ReseedChecker.checkReseed();
+ }
+
public void onResume()
{
System.err.println("onResume called");
@@ -58,6 +64,9 @@ public class I2PAndroid extends Activity
{
System.err.println("onStop called");
super.onStop();
+ // shutdown() doesn't return so use shutdownGracefully()
+ ContextHelper.getContext(null).router().shutdownGracefully(Router.EXIT_HARD);
+ System.err.println("shutdown complete");
}
public void onDestroy()
diff --git a/android/src/net/i2p/router/web/ReseedChecker.java b/android/src/net/i2p/router/web/ReseedChecker.java
index 96eccce51d..8c8ff7bf9b 100644
--- a/android/src/net/i2p/router/web/ReseedChecker.java
+++ b/android/src/net/i2p/router/web/ReseedChecker.java
@@ -30,6 +30,8 @@ public class ReseedChecker {
System.err.println("Yes, reseeding now");
ReseedHandler reseedHandler = new ReseedHandler();
reseedHandler.requestReseed();
+ } else {
+ System.err.println("No, we have " + names.length + " routers in the netDb");
}
}
}
diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ContextHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/ContextHelper.java
index 0aa2506548..7d9b28e898 100644
--- a/apps/routerconsole/java/src/net/i2p/router/web/ContextHelper.java
+++ b/apps/routerconsole/java/src/net/i2p/router/web/ContextHelper.java
@@ -5,7 +5,7 @@ import java.util.List;
import net.i2p.data.Hash;
import net.i2p.router.RouterContext;
-class ContextHelper {
+public class ContextHelper {
public static RouterContext getContext(String contextId) {
List contexts = RouterContext.listContexts();
if ( (contexts == null) || (contexts.size() <= 0) )
diff --git a/core/java/src/net/i2p/crypto/HMAC256Generator.java b/core/java/src/net/i2p/crypto/HMAC256Generator.java
index 7d6f67a76e..0335d1e7eb 100644
--- a/core/java/src/net/i2p/crypto/HMAC256Generator.java
+++ b/core/java/src/net/i2p/crypto/HMAC256Generator.java
@@ -20,10 +20,10 @@ public class HMAC256Generator extends HMACGenerator {
public HMAC256Generator(I2PAppContext context) { super(context); }
@Override
- protected Mac acquire() {
+ protected I2PHMac acquire() {
synchronized (_available) {
if (_available.size() > 0)
- return (Mac)_available.remove(0);
+ return (I2PHMac)_available.remove(0);
}
// the HMAC is hardcoded to use SHA256 digest size
// for backwards compatability. next time we have a backwards
diff --git a/core/java/src/net/i2p/crypto/HMACGenerator.java b/core/java/src/net/i2p/crypto/HMACGenerator.java
index 52b29e19ba..29d76cbd2a 100644
--- a/core/java/src/net/i2p/crypto/HMACGenerator.java
+++ b/core/java/src/net/i2p/crypto/HMACGenerator.java
@@ -50,7 +50,7 @@ public class HMACGenerator {
if ((key == null) || (key.getData() == null) || (data == null))
throw new NullPointerException("Null arguments for HMAC");
- Mac mac = acquire();
+ I2PHMac mac = acquire();
mac.init(key.getData());
mac.update(data, offset, length);
//byte rv[] = new byte[Hash.HASH_LENGTH];
@@ -87,10 +87,10 @@ public class HMACGenerator {
return eq;
}
- protected Mac acquire() {
+ protected I2PHMac acquire() {
synchronized (_available) {
if (_available.size() > 0)
- return (Mac)_available.remove(0);
+ return (I2PHMac)_available.remove(0);
}
// the HMAC is hardcoded to use SHA256 digest size
// for backwards compatability. next time we have a backwards
From 66eae60c48b1ad1958b68657f560dd1221521f60 Mon Sep 17 00:00:00 2001
From: dev
Date: Sat, 14 Mar 2009 16:24:17 +0000
Subject: [PATCH 047/688] removed some hosts
---
hosts.txt | 21 ---------------------
1 file changed, 21 deletions(-)
diff --git a/hosts.txt b/hosts.txt
index 95ca28af62..b30da63639 100644
--- a/hosts.txt
+++ b/hosts.txt
@@ -1,27 +1,6 @@
-tc.i2p=3RPLOkQGlq8anNyNWhjbMyHxpAvUyUJKbiUejI80DnPR59T3blc7-XrBhQ2iPbf-BRAR~v1j34Kpba1eDyhPk2gevsE6ULO1irarJ3~C9WcQH2wAbNiVwfWqbh6onQ~YmkSpGNwGHD6ytwbvTyXeBJcS8e6gmfNN-sYLn1aQu8UqWB3D6BmTfLtyS3eqWVk66Nrzmwy8E1Hvq5z~1lukYb~cyiDO1oZHAOLyUQtd9eN16yJY~2SRG8LiscpPMl9nSJUr6fmXMUubW-M7QGFH82Om-735PJUk6WMy1Hi9Vgh4Pxhdl7gfqGRWioFABdhcypb7p1Ca77p73uabLDFK-SjIYmdj7TwSdbNa6PCmzEvCEW~IZeZmnZC5B6pK30AdmD9vc641wUGce9xTJVfNRupf5L7pSsVIISix6FkKQk-FTW2RsZKLbuMCYMaPzLEx5gzODEqtI6Jf2teMd5xCz51RPayDJl~lJ-W0IWYfosnjM~KxYaqc4agviBuF5ZWeAAAA
-dyad.i2p=W~JFpqSH8uopylox2V5hMbpcHSsb-dJkSKvdJ1vj~KQcUFJWXFyfbetBAukcGH5S559aK9oslU0qbVoMDlJITVC4OXfXSnVbJBP1IhsK8SvjSYicjmIi2fA~k4HvSh9Wxu~bg8yo~jgfHA8tjYppK9QKc56BpkJb~hx0nNGy4Ny9eW~6A5AwAmHvwdt5NqcREYRMjRd63dMGm8BcEe-6FbOyMo3dnIFcETWAe8TCeoMxm~S1n~6Jlinw3ETxv-L6lQkhFFWnC5zyzQ~4JhVxxT3taTMYXg8td4CBGmrS078jcjW63rlSiQgZBlYfN3iEYmurhuIEV9NXRcmnMrBOQUAoXPpVuRIxJbaQNDL71FO2iv424n4YjKs84suAho34GGQKq7WoL5V5KQgihfcl0f~xne-qP3FtpoPFeyA9x-sA2JWDAsxoZlfvgkiP5eyOn23prT9TJK47HCVilHSV11uTVaC4Jc5YsjoBCZadWbgQnMCKlZ4jk-bLE1PSWLg7AAAA
-nightblade.i2p=nyErwSseXbsojcWtNkDyUul0YULtqr6qyWSzIp639Ygpe8juCdgPMLURVXcmlCvo~QPoHg6zt53KpgpGvB1-Wv2SGvc2Mvs~o8USw3ius8fP1URphqcBbulK8Ci0bgknt0kD0AfxqfMz-p~xk1QEMxq2kZEoB3oyIIFnQlpb2ByS74Lx8iKzXTrwWk19I3Dvu4nIq8CBDDwu3lYoCD2kC-jT5pjgglverGPEGN4o55LYVTtfSg4gAJFZeaE4KjBR5P1z7cca6UDjGMWfR0iCa8P3qpkY2ODYpk~8w2xgBbgDq-8Hzik~uraHc598ccS8QpwB0f0Jw~2PZcTjOPdZ-239U6p3tESXa7FXzRBCujv4Bx6CVFRhCmBHpyFnCD-MugZ~vR6XFSS2XBsCT~duXKq94HH2n1iAWslG4Vu44ut1JVhDPFzp~Dk7wujB0tCo2HXH2icRQxOWe37foU4LZSJ4oMpFDACBzwSfcZdIPsVRxGttKQx4yzgffR1Q~Jl7AAAA
-bozo.i2p=ubMPUwY0op6B7Jr8SAjY2bQXze8m1sT6xF2N0cv43dIHwLTO0gUqn7FCP9jXZDodE9DR3fu8fG8x1Yz1SpXFk4WtFmuDuhdN7uaHuLIQ71PATC2GRhDS7NXqn7GsVZgQxhHKenaE5BKjIKt2amZ2~8CM0qBKTqwievUO-Y6zG~-8l~RpnAxDZUMOjKKy5R3~jEN9DFZCaKvXSNcOVFjZRGaD6d8NvkAJjndHdE3bFSJUDNv0qhhp09-mm~Se9C~FzjrAbhgappdNRiwQepXTWqRbjjt6lUPT2eJISPDxYxoeZkBGZa9XmfO9QH3hoMo0g~RbwLeBqtgeRGhVgFiC4pN8lFt3z7j8L-12575SUeOnJPIm3hQWXdTjKX1hqf4LopYBG84N95IeydPJegsmkIkAMzEb0d~-UZfVSP9yFgs37j~Fds5yxBsu-NFc6qmZihpXEd7jrfX1-HuJVmXFmwaZgyumRSRDbj714wxr7RP4Hb-liA3JrU-FbqNQFoTMAAAA
duck.i2p=eFJdRYFmtjcpx9-Mw3JBdF6fwtb9cHRBR103Q8IGc91Jdfn0iYzK6Xx0oIzPvpbD4yOlPQm-C-7eTahrAkHa2FMCRTiiVq2a0nBp37W1uTvAToV-MKYPKTdFMxrXxvjS7qaSUXdJRcPaPexolfx-Gcjh~rN2tKCh0mz9beueiQ18~8qWGh6hUMb0yyA09ipL9vIkmHmooLwT9AZyzHXEzdLXZe1P~CG3L46QaXp9aTD7EkAwG6VBMjQrGiSJ-9FFhx4QcYAZWM-dfrtzbbVYfHxqQRBwzB27zLlaKVaqu4enC0N1cW1yy-cjnv0Wxokqe62B2uPzFYtloxQpBPfTLQZUfUzjskY-3Yg2AdSbEu37jYsnAJA95AlLz4t1W1vPTNiXzCaRqkkMX342SUkJK-HZE3wTjAgGPqJ9vMaC2YexPFViTxEO2Q0jDSjdPHG0D769qehkN5Bfb8MEI-yr3g9zLaY~w4r6T38ap33qfyISWlIJ5qCPcRVkeK8OqZ4vAAAA
irc.duck.i2p=Bxqr5E7-56oJeya1lsDLBN6L1gKme-FUS6Bh~TQS3HswomK9rpjrYNeqBTBoE8TCFl161~FI3soWqbnmFhIdhskausZsO0ez5-4IXMJW8NTilWqXQ3OJxA20M9grohx3RjkZgXU1ooTx7wviSHtXQYiiqnzGnIzmmEZo5-Xx6VjXakctebWwbi2PrsE6XLxrxXBzB34l4KlVsyX504BJiOT6KXNaVZxvG61GfGVfNHdeXljMDE5d25UdFC6RJdDnJ3Z7Yb7EjAww78aowbR0VCfJDH~cB868-VOKIxmor3Rs7giaLXmUyW~GRtFX10COJj5V6BrhKs61XOXxfbyQKGVXZ0mM2A8cdZE1ftr96SZgGy~V8uUHKvoa1HpjMNrPL5Tr6EGfJxOxAy6PHwotn6a8UMnCZgEdTbQ6U3BTywU~x3SCAQvfOT~dl3sZ-5ujYWNFRp7RhdY-WHn1Kj59MfU-VpczGYdV3bRkwT5lpIjST~vopLfkYUeB6gcVSr49AAAA
-jabber.duck.i2p=AzR8Zrms1sLXflvaZZ5CI2TS1cRvlO99D5Jh641-KS0lMSQPUnSApTfy9R4aPxZ3SWwpZPfSSGN-e7~kw8ucGQVB9EOHnht7WCz5UKC423vX4fFZqpTyqemDBx0CYXfhqRf-~7mjslXigR2nbQwh8NMl2bgLPknGe55wMlZPfsacS2WKNQYbdOvrgG6Zb6DK8RzTDrsum5h2jtIorv3CuMrNKLdfziXBDICep2Zp9jKDPBHgSsRgl6dW8A-5~WbkIPLpQwqeTzw90r8uJ9EIln~GlFulblJprCfLzxJ2LAFpxNcTkqzOJPElFfhjVrJOYbm6IfllBlHMVNbJjYTOsiJLqODxMiVt3pQx~AGFrx5mVtMUcz9cu9hVPnz2ZVmIDB~a4UGkexf~FCHhaQ6Emnr4nnZBiFSP3f4nASOMHLOs4SE3UKiYUB3ntmJssVdD1w-ZGrovHynkvXMjrJ9GhIeldFm0M5cOAhra0OtJagZ-bgphR0v99ADGPl7X5DoGAAAA
-home.duck.i2p=dQmTRCAgcKlbt3VKdW-iFI4zd3WnDaM8ULsfIZb8oEdDuTq5Sl~1JguWH2Wl8PMRuxkhHpfOZ6IUJZtxo-rr3tfaDsYPl8SZSIbvGBs5QooLl2NNTPA~gQMJOHZkuM4KWMWYnFRWoaqAUt9KAmdyl5vgF20xv0rmSgRmm8t6c3QSTfNWSeSDYkRgEumaUKP-kRJnSKNeIOez1N2HQSlaDu~cH27E-VqEuAu8HppI87dV~v6nVKXR9-KgHzCdfHXxy2pxV9trJ8vmTEZO53ab11-BdDMoZjOv5sjMUADNDnhIW1RJ3c-ZcF9OotYsUrf7E1fRo3BwGg27LKhFnyBDmzI0a5uQJ9HCDlzSQ7yfHNMqNCtMfHgZE6Bw6F3tJfr5ISP1j5ibfj4k9tODyfWVqTionQfgrP5szHdyGu14Y4AtDW01-d9BNmBTHA53jCl~Jq6Qm5~CKcGZGS-05iyhmg9x1FtR-rW5Vf6o8uitSjtE5uPt~UHXacaGxQMJSy9vAAAA
-nntp.duck.i2p=5SIb-1I6SVwFlW~XlYTNJU1NCpbyHJ3co8KdrpDxBosnHtdsZzq2qzYzGDfvkKK3WRoKmRGYCE77uXAvOQjEyWoTkkGeY2xl3B1t4t8K4j8dFvYtDJkRGePxGaY3MW-9ANGUQsGOhh6qq4lcQ7rv-AWyDftfZ3pGaHc79VukSo7-6OSh4WDw~0l~DjdFjQsZOVNTbKIfDxzSjKnkTpNc73nrLhRE5nmnMj7bljTzNtAHiVf~hFMndPxF80JZt6erLqy62-~XbevTWpn2KCTjYzhYUkwYW95-SW27ph5rIVZneizLEanSPtdUkDGhMEjjmy39Qr5rD5i9H-ioIP3NppRkjPwrtI9VJpsJtzv75uANIXy48RCBVXXA18ng8o7FVevdyjVb~C90IXpJF~mT7DI94rTT5QnzlpJVCid65kOoNzXFC80lP-iiwXMMBEcys8RGA9hdOvagkFDJ64l0GwrVpFGO2AVMsMenR0WHEvJOjNv62sT6rlntO3ZywhNXAAAA
-pgp.duck.i2p=kRm2KRa2EiWO~XQFYxSg6UM9lXYHZ93IB80j3ShFhJOOZ4AN05BrTGjMeT9nhn5n1LMEUhy9HJuN-Lhkd89Mbhufk7di6M40wqySns2g0T7XUCFUgQ8kl4~BoY8M9U0pHpM3RJcCw8WJEFGEk~fX8tgC4XQB43UIXfrdKTlNfKhxZODE4UdvlFfFdOYMgH53x8UgMZUprn~URTRNg1uwcaXr2luMwts6HnDt1bDd8elitsWViOJiw42yAFMqBnf-7mhiTCsoYg-nsOiq0Jirt58cBjAGUL5ujZo~vfXkLslDKjHOP32Y7HIi5ANEsbbRr~8QrVUojnVoJwFXs8BQBTevRpGLkCSLnKa31jNSt3msOnEP-n729Jabwj8o3pdRk9e-3~~y9gfj4bcmpSH9sOJoqmipXDiqOvv0tL9twERqse3tAwjE1NgXTvl5e2Zc~F0xJ-L2aG~6BX175ihjjEiYGWRYaoEisHMZdMtivsAK92dKl1JVEkuDF3W8KjL8AAAA
-scp.duck.i2p=AE2Ff7x-tJMI901UKEEXkcwb9~5KZKs--VBXEoZnnpC~mlgnqGsZr8MBvRvs6xAzP7xXLeL~cHQ~gvPFT60obEBitwH~JcKMahhJDGb0p23Z8B81QajXijypDpVfMDfFbMiqQGctXhnBidNKWe7HQEcJGZer-SCu3m8CiftcZ0t0g5Y67B2AtqLhza5xfepq6FQ-Tl6fpgS-UDcGUAqMpLUYfrBFB11oM09TRVsfNp~NIAvMdrvXiX8dTDUHJM4FRdpV2OsJiyDdgf5-W6s6ssxohviT5MdijUSYQw5sWj8~9Xkv~~aa11Dvty0E7K9IhXAeJlwBe3VuDizsAJGnFIU7PwZXV7-9-28Zgldarg1P-rh2QDvCqF1vjdyZe99BBcTiCqvE3zx2N-9eT~FeOURrgE~2rFBKVBZfuAASSORqiXIeAANKklCW2pGQrM3DkX8ybi93Weg~eBjwGQugO1FRZ-ISq7npRWruMiC7f~fWLqkmRUy9HahPNp8E41s9AAAA
squid.i2p=8fiWZbRjOEzrj5n4jSqjN9UN54wTrsgEjqn7GRUQpLx1svf8lwckXPV5buP2VEYGo~83ftkIcDKyMLXkxSr8jqbb4yAEgPe2~w7OT~8LNvmVPz0xZhIO6fiw0WU4xD9x5PG1spYjWPnLFv7pynEvBpWFXaUlCacjWL2KkfViiGPXvveQqQIZs7VkxVD2HK-oT4yIjdqHpc7Y8nEV9xwds3-LX6to5p70jFe~kZJA2fjWHsSCm92TtPvoR3aTlL1VS3JUKpcH6BL5irsh-SKODEtDRCErPQI~j2SHzhcD6dMUsI7bm3AxivjFpSQHqyXLmLVdxECYsMET~nIHmuv8NYTHQQ0jM0XTQzwnQwEHjHRBd1~spR9uS2~LSnX4Pw~X1WTknJpPK1f4Cu1O44X4RYcLRCsxpEzytUBXA4BQizrbYgOJVGQa9-PNGxJeZsnNUZ3PxUi23Oh-c4jUaB0ZjyKTWJSpzj1GI6vc-gW-0ixGJ358TCSbKgqdBv~g~f7yAAAA
-fillament.i2p=Pa50z7pU~ni5nWwUdaDZ5CJxG0fYjoarm9wlxnkgX~wHMX9RPgQAXz~r0Rr1Nadt2OA~dr9RMHswrMok0hutK3JZuFD707D7FjmWW2w979Ee9I3zxKyx9W5A2eE49PPT131NLa3uINXLXOYVA5frfDOmM75Dmvm533r8e2kloemJyj22HpvRiSXiQYgqYJGDMH3Hlnwk884eRkQu7P8DJL~hcuKpyY0FzLZtfxTNsdSavGjl7rKPMzJeP02-9TS5TkdHokZrstVM5Cn9ay1c8DQrMds7SPXJy13Ut34QRjb65JxRV0mrnY3teXewW6QFvFMXJCsf5C3i46t-9Fufy5D1H8cSd2Tx~Xl71MC5-1AJCcIS01Od23E9tFY3dU7IOSRhKC~FiAslyk3x-BnBSpKxbgl1w~LArBm5plNiCiUemJU88xYdn1UyukLer~yNrEHAWspckCRkXFwmUtPkaGNTvfwBSYns-skNHSd7MAUUoS-ewStBdmtnDgRkwSG9AAAA
-eco.i2p=KhRG6BGxVPh-BUDDfIgy0570cppTdighytcaGVR0HzQo46tgRMBp9Shlpax5FQX4nLHn6qHQbdFFpFbAwe7CiDhURCVF9-CxYmPurGadxlMPHMjz9O3jHX0CQiv2iULsk4XPrYXF3PqBc4t1J6vVyBVO7uTUhDi0gF6sN1Ro-1GLcWcsoR8Kx-hb~Z4WqGD0QAROOBPHnSRSb236qVBkhFvSkfigfBq3jFgEsttadYJA9ZLSUj1XrFFRBjz~xkRra8kJQSZl5dbfg-eZMlL49h61U6Uta5n1~tL6sarmnl9CaTl2Qo27SKB1OmMLeZEteA5G0-~LiOjN0nxaKpwrCjKIOyvwbQy2QqE-GEb9m8SN8nC2bwYK9fH15pTMHY8GvPYGcUukbF6RhefwzkEJLZ~PaAECrZYuLsn9KE5C35uRnlWJiuJlJ25hG7da5tFMyDB95efzq5IMxPeI0pMigRfuVfRSaGDpNos6JxjfEIX8umk3jIJUPhz1d8gP4QgrAAAA
-aum.i2p=09hSo56PTtkFLUEt1iUTO7zYTnO-B~ogsIsyyPWif6q1Iz4wz4JoBflAWZtedPmwGmH0nly4HYUS0gAADoUmBUnXwemmO6dxT-hPQkfEW-A7b3uEvYQWIN~kyFyg0Pa~FN6TaD9kGFttBN-GE4wxiHhXmWdzWNDVb0q5PVGnxMm6Jleik8xkd2Lgeexze8rIv8LCocAWx074USVkbCVQwoFi2P7EnjLq8odSz1cJAntbuCFeUZcjbslE3qmlcTFMCNCZXWKVzn7d5m4oszCQ83NidgekwxJ-S~iS6mBwIS0XKI--4iXiKXzzCFf0KtYfEWpvKCuqNJOcU8vQWAA2-i7~K28aLPzccDQn7acXWLKRTXF3tf0i6e-lSx-X6WTSWK-fuNitjAtKu~jqO10d~bCk7y~UPL-XwdH1XSTbk-Phhk7UoBTDiHY6zQHdD~iAzXER~9JXsJ4UoIrGFVabg7frzSt82CN7Ek5Li4AMz5gg3wq9H9HUa7xM5QfGIJpXAAAA
-mp3.aum.i2p=vBOu1caCAajaL5WRMuwk4LwfXrlcn0WzA6iHUKV5ULhaBpJb9pR3SZpnQms2Ot2c5Fvu5I6Rp7WF6QRcyasAhUmC915ap~2~VG8KCDP0z3Quh1-eqGcmzErsIfXdh09j3CWuxN~fH84hd~KswqGudFkWtFTM9RcuQUGSC1efG7uF03uaDI-DKu7eb4VUV-hmpXb3Lqntgo5qSMBMmjyUND-f6RBoXnqM005mUZJpMoYfsBhnUEq37GG8u6P9T94nlMmtz9R3gNURpBJJKPlnEqCBN4mlE5rwspQ0ovxAlogVMhSCpQ4jr6cyWIbNx-nMzKGDj~hMQ0ndbVnWw3EDC3KsPnRnDv0yVz8Fc1YpoPwerHej7VnTupDKxc4T-j8XNA1dN8SfPmaKYEPfavlmy7HFAGcsbmeRZOq-PVvlDdrKNflug8Ysodd5XkDbh7y2k1pRDjwNBQ1EgDVAtL05-i9jerqekHkbFKJ6DlT76f06vj1R2v9qlQzAYjpcKbI3AAAA
-ogg.aum.i2p=wR2ETKWn-mxsTurWwmSujvjpOiIjLg5TsldFUa4YFTgiRZdFIB-bXuK59shfnchlEgAZR0IR3~hH-O8bZ~j6wVBdZWq7bGTmyTxQ3MeYPdqK7wH7Jp147YUabFlqJkyI~DluwBDylJrIUyc2qw~ogJ67x-KyzIF7JLnoCC4E-T8Z0vmTAFWSa3XC-ncghrdZQCqEXaCMlG9PN~a7dcDq~qdWoNoyFcgLd0IQfE8JuJ1wSvmWUNEd9vkB2Zuu3EoSoDv4C53Fc0YhVACNug~VEEL-ZBGcCBcpVNud8dOMq-CbavkD5yKqHlvq~uzRi6BY5ajHI77uepJygkHcsm-8T0PXWXdc5ib4TtUI03tPkTar4Y2iVocY~oLk2jh7pQKZNioHJT4StWv9Pj8EWaVX4-emQB5kZOBwZItjo~EAGEoBT14NSM7CmKClgc6sg7fpvWF~-cNHkZsurBndni~~FKmUeWoO0FRQRF9Ao~C1DOt2V9oBbEW1~n6anjL5V~IyAAAA
-fcp.entropy.i2p=jy0D13oJVmxSa1MltstV3FOfA5e2WAEEZJiYOJIZSUOcNnAkaR3ghE-AX4vuqyQPyOEUydpauD6cS8vfx4iZkb2U3ddlLcOU3YrFKdLrySpGtD~V126VO-9nOJFwDQOOaKAsiVGRKtMPLC64GkpU6TWSIhiVYWb7WmeAHXLLlR71DtgamAxEIlP3VhytxlS3vuvAoEH9ItsBwkv4N~7jec60WMQINl~c7uDDsuzKFY8wQlkHnLFQJCQ0VExfNYqK9nZ3x8TXNPmNKTMMQ1CUCowgwR783U7UAYqsxNrpkuWvTleadn7QcR9i2v4~L9zOeHd4nHBy8PAjO29g6nf6DIsYhg4c2HYnPYzktQ1NIElytmW83BhbXJXLgNBs1eI9gDaQmOiXi74FMgfg63IcXCYWeqCdwEzSouSphaXEHDcZZVTx7DE9R-1Bi4Dt~KvPOFsAoOqsjHCpHq1gS0u5HiL0hkSm1I1EMk4JBY0j4rM1nAt7e0ix~WiOz5jXlTVSAAAA
-http.entropy.i2p=ON2Ud-B0-pJKbTR0Obpjp9wEG8grUpu55gEn5Mz3-dkVkPhHvHK6iLasr~P~Rf4kPPZvn-eK7z6rAVfsAytAJ9pcTH3lXERTjkd9FzVJJ0twbZSQ~XzX5d-24IPIMf00KegjnDkRJ82cRMKa-u4H-ayei~Y7xsSx64zC1eHv6qFxavtql3zRrS~du41~EHtpjqOtOo9Ea3lfFjhm2jUIJpYyVHqve3WbTfMBlguVALwGZIfenph7oQ1Hx~OnEtaviWuOEpupjm11LS9xqCNsccaEpJGvGt6ijxd9hrEuQZ5Ja~C0fNxf3xNtgRaUhakA8Xoo~jz8rCkV2vYQo58kj0E5xYrUQczomj8y-eDBZyq29BP8pfe2G1u3hpHA1z470LUeMPk8qVx8Cx8ZKmSK9XCvOl7WCnFS2~UUfzxbxSxPn9LfzxDZp05AVi9t~hJg-zkrL2n1wfEnScuUFapxarwK90rlAxNSnau-K61WfcXqyVMwDxl3leJOeVdHqhpbAAAA
-www.mail.i2p=Y~V8YK2M-my6-Gw0lkrkJouxeqPuB03idp-4uT9pkIXCA5nki9m4YFfPObSPv0E7c2shBxwlUo-6beaRQ-7tCawJssDRc0C0PhRj12QUYYdtZP7JS8SQXy68gZIylY-wfyEXleIC4mYY5mSthhdUUfyo1lqzrdHc1NpjPBxRJcyMBFBGUeM7Of9E9M518jXpVl0bAmxSnr5dy7sgKAVNufzfqIBfEHnmL2ZYH78FoGnPybsV0F9~154emkmt89ZUbx0BuYvH3kT1zin8pSxKw1NqxvqYt7p8CElq1--U38rO9U5Y~kLB9f6F3RYJdkl28ANkvdgJUgqiHLVI5oPWATrJLAOokyGKhK4Xl4Bjp4SCuemxHwTOGyd-4Kl8cO41u3w1LksndX9stkV6U1X0gL9BeSIoa1997IgMLVbUiDMyCz7-cA0y2tc0EdQdlpc2y77nTdo7z23dMSJzWDXsrfmLhX7M24D70htLLc1dpwZ1BUEvM1uPqGfsBSrHdl-sAAAA
-smtp.mail.i2p=gfSAYcvEsuU3oNGqeMpq1wZqH-whE1i~YCXEDwYzp8LrmukWsndvPER1~gF5QFrIp2RMXiietF3zEPtAJgevSG4ULxRU0s9MSAMXXlCACVhlf0m493J6kIYnkypOPC-Z8sulyF2kXM8BURLfSH57SS2uxLbx0hkc8j0kR9iys3ksxm5dgW-Rs7clAvLmmfASJkXZiU6DRhWbW84GbpAi9McE3ORhNLrWV5t1W4DXqzT0tzF2W0i8BEGns8XdOBQei9RAewzo5NRGPBmUl6ZKjEJ-2UtX189HPs7FcLknfsRxXhRcPQ1RombPezYCgcNhOgWY9owHq64mwGaDCnnpDSM01sdAuMlFfs1JJMoYNrILckjiHUNzV2XS8A0PIWdO4W0cT1EUs-V2a7Ocvg397HpR6Z4k-7fOrjs9yvpFsCPIEKYUD0mjr44N5pJIc61GGuNE~2ihQZGA3ju0OnUKTRZel3nK0rxl-qfFXsBsEB5vt-MTvKS73ZJdxUKWWzbWAAAA
-pop.mail.i2p=aG6owmzirq7QZKYovpSVa4-WBLfI1uJ38cNmb6kkSkcS8A~JdoLWPj6eXieN8r3m7YJLxxyZhf3urmK9qJbiIPBp53M8bOSSkldpFz0NkQPWUWmYXiOrEsOBlugbJ8nNelDcOebqoieKBOTaF-WPJQil5C6RYdUy~PL50O6Qp-Hog1868zP26leYBBFiyzzWI3bOpOsgV~4bNXnqKQZeHXz1Ua2DkV-vDBpeamPzvNWQI6cNodf04PBKXK~TlduLZDK7v1yTt2LhPSBM5nE7ZRtS8KQIdh4o-nyYRmHjA~OQ70gowGpmsRqXHQxOpPro~C7w3gSe2N0zhqSHKstwoFJD-NmsBQ5opyOiKccATpWEQdAwmoICD6rw7TGG4XYXCtyTD2xxLffER0SEsJ-BJesKKhdm-qyEMAOQq00jatoEs9jBYoujFLFQMUgaDejRJdEHWkiGT~x4auosHGYavmrcm-0mdX0CWYgfjwVb~PORhBqHJ1G5IgRPjoZLuxiJAAAA
-nm.i2p=UhUVbM972VwQgqS28SkGPtghCb~IpdpeMW7O9E7I3HtlB2I3XGbMeUAoya5RHsoG3TYxf~P6lA5IM5Z~mDZlcbZ~AG7255FE6Z3Jl9kfMArneou6AYaCfNBqNTRS-P7yX9s0Kss-vM63yBulxhS7CqmBKTZsXR27PNjJS0PMYsWBzciuy8UqUkE0YEhSLWSUYAXLP9FKs065CNjxsLumkkoF~MNUaBNEmbCrjpv5Ih9vrwz4XAJSE~S61qSMj6O-nvEPDVhTJJ5ymeoZnYMpIRt4r7FkCTH8vYSkXZkhqXUkLC11WPC33lw2wzh-irmIb5GQeab9o0-DuNQcvUnbK13Jxkq5XiilfK6kgKiPcEniqxMb-4paZAl8dj9Zp01LvhfjlS0c459Jv-gr7ZkjkX7hhTaEVvqwPyFgoVKnxQCitoZrK98WRKJwu7EQb-Kin2vzUsYfpGGI0aT68~gdr23oom2FsoZ~owVuur1h0bJr9mnCaMf6jaioQE7wezxgAAAA
-mp3.tc.i2p=LRCWTiJouI6ohqtaVBNHWZe2ymjhtyj3z9KdeI2G2D9l0cYFsG0CRUVT5VPYOg~WykALRVBiL-2U24fbiQ28hhPdQgBMBDl9aQiZJM2hv~di0uVOdARhRSgCDgRQAWioAfpXeg6pyklzXU3TNLY4c2CRLe~9Y7wuLbK3lONsAApcxxKeHLrfGNkZZwJTKd7PcG78KAHU07E-TVNf4tQrOh8tSrHaMB1r7cQQv1Jl8mNUZWz4fGeNYEZ1wr04w74Em2~Z5K0VZ4mH5DhFGXc9ALYzZf6uOVzZKiUC0eOcdfGNdVUbIog2CYJGH69TgAX69d5vF~kEzvHSzX7RxUTt0y25Rlbi6rHSDF36xOfBrOUVnSPn5X~TdKLygz~zusYpRdGZwlsyOTKVTzJHKlU6Vp5Dofijj1bUwXDQ59XCpFUqEDA17nETiOO0H5jfieYBPS6Ke2cFTAhutSvaw~albCd1eV7RPqeGdw-vFfKoucDIEVUT40B5qalyFRKIxx3lAAAA
mesh.firerabbit.i2p=BLt3pciNQcVIU-IGnTfSsrputh~b6drZpc1vH8qeA745XoE~nMCGtw8S7HGYX4uEbwk876nQRPV4qRwGtWWkWBs8BX9qX8NABoXFk4G-6NifB4TxEizC~ZAnXZ2uFs~nrqodhyCR8bBHJL0tzBYK3E36zc~SA-DKqQ9XSHWp7ScW7Z3cdQnYKma~x4u5eZmcS23uie3OIfOCk6pJOabtaE-YWRa1eUizhucI-ysm789GumjTo858vHR1mTQfrsPTqNri3yz0aIe~w06ifciq~UlNjVfx89lLEso1vmg8rfTQ-hwxS-qz-u3K5x5vtqdGp673vCvmEnQpU6GEycmkqoLCho9pNQzGbka-OVHg8fZqlFMeBfj2iLz~zlv170jvX6HTlMCNfBYnFqavs2RQJj7--dJ0g7JHReGMKL~TciQjxljrV5AoN-0afRzTZqtDg13PL4tltJm5U1~f-GcxlsjKLZAlv26LlZXsvTDU5plldsernv3fDcBev9UaKYCwAAAA
chess.fillament.i2p=8xvXLwcBYu2MxqMAoG6DIahvkNAwBQs43kdZTg9SlouzC3JSQ25RHvspbrxWoGIVAlB~XCxVmBB6EolYEHoSZv2YCziOj4UVxEbVP7nHkh32-7Uc5T7xlcjk8-rsmZzdgz9NhxKVn2Uhp3xtcdVAiyG4mpXisvK-7NgHY-mXPNvj6goaH58roeDUZ5otJN7nCFmcRAUpaUk-nlQs8YfgSCCEsWKOWhsVnAaHwtqtDlpdTo1YKooACMRSa-DcV5W75Il80JEWBD79qpSAeONGAOMMPT~VEMwNNg001VG-UZbvyspZdxHaETw2yd7N9l3-mwI-sYcveTTnNXLWO8IjdgDLdUIP5qrIW6WS9XZIHRKqT2kpwEw7xsEgCA~qSNiZWeai8n6Zs0rLmdyeZeafVEEW9vr6CKcLZ5W7i1SMDqCKnzSbZdd2Hvpb9aWFf5foEjLt33n8w2KSaCUe4zmN~xuQMq2yiB-vQ9~5fgPmphlMxo3ca5MTCfbhshw5137YAAAA
kaji.i2p=i-nivH~36AgabgzvS06oKHR~MLoy6NA0oSv8JuNJDLZB8FXEDzIiyzWISmw9XJm8I7QqZ1yFH8~xe84STCHHvMMIQQrfBmOUODLWbKZor~~KhiHdNLtfVZC5BpnXkBCJkklj~fMYSpWa0C~pVRrZl75RoGtBjDVP9P8hioTv5B6RC86g2ypBH5r093rY0wnzxSL8-ZuV3F~H48VYbqro8cRlbMmjx2oEsSHkDpQyjCMVkIYKaCijkSArqZTG~zX6op6Ng9CJwdrkjKSsbzjV6MLnE4aNv-jm2WaGGD5pR24h7e3ImDOGAr17tXRtmNX5ZEQ1udQp8qIhd8UMUumrnm962r8KJWK~9WNzcVeqDrIxaaxC7vcQmXxoPeEW2efbH0yKhVZ7OFu~I9cAapSe~aNWp9UK4URSpuJvOedt0axp3ORaaM-a5U7noW3Ao-HB83qfFEPU-6uUu16HNiPqCFMJiA0qODTOwHiyyx4HKQvbhjujh4mmknSbsuapdgR1AAAA
From f70adf8da63afef2727a71026dedb30e0968454e Mon Sep 17 00:00:00 2001
From: dev
Date: Sat, 14 Mar 2009 20:25:50 +0000
Subject: [PATCH 048/688] disapproval of revision
'3ae245c48c0f90b0e70cf800de354e012801f6cd'
---
hosts.txt | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)
diff --git a/hosts.txt b/hosts.txt
index b30da63639..95ca28af62 100644
--- a/hosts.txt
+++ b/hosts.txt
@@ -1,6 +1,27 @@
+tc.i2p=3RPLOkQGlq8anNyNWhjbMyHxpAvUyUJKbiUejI80DnPR59T3blc7-XrBhQ2iPbf-BRAR~v1j34Kpba1eDyhPk2gevsE6ULO1irarJ3~C9WcQH2wAbNiVwfWqbh6onQ~YmkSpGNwGHD6ytwbvTyXeBJcS8e6gmfNN-sYLn1aQu8UqWB3D6BmTfLtyS3eqWVk66Nrzmwy8E1Hvq5z~1lukYb~cyiDO1oZHAOLyUQtd9eN16yJY~2SRG8LiscpPMl9nSJUr6fmXMUubW-M7QGFH82Om-735PJUk6WMy1Hi9Vgh4Pxhdl7gfqGRWioFABdhcypb7p1Ca77p73uabLDFK-SjIYmdj7TwSdbNa6PCmzEvCEW~IZeZmnZC5B6pK30AdmD9vc641wUGce9xTJVfNRupf5L7pSsVIISix6FkKQk-FTW2RsZKLbuMCYMaPzLEx5gzODEqtI6Jf2teMd5xCz51RPayDJl~lJ-W0IWYfosnjM~KxYaqc4agviBuF5ZWeAAAA
+dyad.i2p=W~JFpqSH8uopylox2V5hMbpcHSsb-dJkSKvdJ1vj~KQcUFJWXFyfbetBAukcGH5S559aK9oslU0qbVoMDlJITVC4OXfXSnVbJBP1IhsK8SvjSYicjmIi2fA~k4HvSh9Wxu~bg8yo~jgfHA8tjYppK9QKc56BpkJb~hx0nNGy4Ny9eW~6A5AwAmHvwdt5NqcREYRMjRd63dMGm8BcEe-6FbOyMo3dnIFcETWAe8TCeoMxm~S1n~6Jlinw3ETxv-L6lQkhFFWnC5zyzQ~4JhVxxT3taTMYXg8td4CBGmrS078jcjW63rlSiQgZBlYfN3iEYmurhuIEV9NXRcmnMrBOQUAoXPpVuRIxJbaQNDL71FO2iv424n4YjKs84suAho34GGQKq7WoL5V5KQgihfcl0f~xne-qP3FtpoPFeyA9x-sA2JWDAsxoZlfvgkiP5eyOn23prT9TJK47HCVilHSV11uTVaC4Jc5YsjoBCZadWbgQnMCKlZ4jk-bLE1PSWLg7AAAA
+nightblade.i2p=nyErwSseXbsojcWtNkDyUul0YULtqr6qyWSzIp639Ygpe8juCdgPMLURVXcmlCvo~QPoHg6zt53KpgpGvB1-Wv2SGvc2Mvs~o8USw3ius8fP1URphqcBbulK8Ci0bgknt0kD0AfxqfMz-p~xk1QEMxq2kZEoB3oyIIFnQlpb2ByS74Lx8iKzXTrwWk19I3Dvu4nIq8CBDDwu3lYoCD2kC-jT5pjgglverGPEGN4o55LYVTtfSg4gAJFZeaE4KjBR5P1z7cca6UDjGMWfR0iCa8P3qpkY2ODYpk~8w2xgBbgDq-8Hzik~uraHc598ccS8QpwB0f0Jw~2PZcTjOPdZ-239U6p3tESXa7FXzRBCujv4Bx6CVFRhCmBHpyFnCD-MugZ~vR6XFSS2XBsCT~duXKq94HH2n1iAWslG4Vu44ut1JVhDPFzp~Dk7wujB0tCo2HXH2icRQxOWe37foU4LZSJ4oMpFDACBzwSfcZdIPsVRxGttKQx4yzgffR1Q~Jl7AAAA
+bozo.i2p=ubMPUwY0op6B7Jr8SAjY2bQXze8m1sT6xF2N0cv43dIHwLTO0gUqn7FCP9jXZDodE9DR3fu8fG8x1Yz1SpXFk4WtFmuDuhdN7uaHuLIQ71PATC2GRhDS7NXqn7GsVZgQxhHKenaE5BKjIKt2amZ2~8CM0qBKTqwievUO-Y6zG~-8l~RpnAxDZUMOjKKy5R3~jEN9DFZCaKvXSNcOVFjZRGaD6d8NvkAJjndHdE3bFSJUDNv0qhhp09-mm~Se9C~FzjrAbhgappdNRiwQepXTWqRbjjt6lUPT2eJISPDxYxoeZkBGZa9XmfO9QH3hoMo0g~RbwLeBqtgeRGhVgFiC4pN8lFt3z7j8L-12575SUeOnJPIm3hQWXdTjKX1hqf4LopYBG84N95IeydPJegsmkIkAMzEb0d~-UZfVSP9yFgs37j~Fds5yxBsu-NFc6qmZihpXEd7jrfX1-HuJVmXFmwaZgyumRSRDbj714wxr7RP4Hb-liA3JrU-FbqNQFoTMAAAA
duck.i2p=eFJdRYFmtjcpx9-Mw3JBdF6fwtb9cHRBR103Q8IGc91Jdfn0iYzK6Xx0oIzPvpbD4yOlPQm-C-7eTahrAkHa2FMCRTiiVq2a0nBp37W1uTvAToV-MKYPKTdFMxrXxvjS7qaSUXdJRcPaPexolfx-Gcjh~rN2tKCh0mz9beueiQ18~8qWGh6hUMb0yyA09ipL9vIkmHmooLwT9AZyzHXEzdLXZe1P~CG3L46QaXp9aTD7EkAwG6VBMjQrGiSJ-9FFhx4QcYAZWM-dfrtzbbVYfHxqQRBwzB27zLlaKVaqu4enC0N1cW1yy-cjnv0Wxokqe62B2uPzFYtloxQpBPfTLQZUfUzjskY-3Yg2AdSbEu37jYsnAJA95AlLz4t1W1vPTNiXzCaRqkkMX342SUkJK-HZE3wTjAgGPqJ9vMaC2YexPFViTxEO2Q0jDSjdPHG0D769qehkN5Bfb8MEI-yr3g9zLaY~w4r6T38ap33qfyISWlIJ5qCPcRVkeK8OqZ4vAAAA
irc.duck.i2p=Bxqr5E7-56oJeya1lsDLBN6L1gKme-FUS6Bh~TQS3HswomK9rpjrYNeqBTBoE8TCFl161~FI3soWqbnmFhIdhskausZsO0ez5-4IXMJW8NTilWqXQ3OJxA20M9grohx3RjkZgXU1ooTx7wviSHtXQYiiqnzGnIzmmEZo5-Xx6VjXakctebWwbi2PrsE6XLxrxXBzB34l4KlVsyX504BJiOT6KXNaVZxvG61GfGVfNHdeXljMDE5d25UdFC6RJdDnJ3Z7Yb7EjAww78aowbR0VCfJDH~cB868-VOKIxmor3Rs7giaLXmUyW~GRtFX10COJj5V6BrhKs61XOXxfbyQKGVXZ0mM2A8cdZE1ftr96SZgGy~V8uUHKvoa1HpjMNrPL5Tr6EGfJxOxAy6PHwotn6a8UMnCZgEdTbQ6U3BTywU~x3SCAQvfOT~dl3sZ-5ujYWNFRp7RhdY-WHn1Kj59MfU-VpczGYdV3bRkwT5lpIjST~vopLfkYUeB6gcVSr49AAAA
+jabber.duck.i2p=AzR8Zrms1sLXflvaZZ5CI2TS1cRvlO99D5Jh641-KS0lMSQPUnSApTfy9R4aPxZ3SWwpZPfSSGN-e7~kw8ucGQVB9EOHnht7WCz5UKC423vX4fFZqpTyqemDBx0CYXfhqRf-~7mjslXigR2nbQwh8NMl2bgLPknGe55wMlZPfsacS2WKNQYbdOvrgG6Zb6DK8RzTDrsum5h2jtIorv3CuMrNKLdfziXBDICep2Zp9jKDPBHgSsRgl6dW8A-5~WbkIPLpQwqeTzw90r8uJ9EIln~GlFulblJprCfLzxJ2LAFpxNcTkqzOJPElFfhjVrJOYbm6IfllBlHMVNbJjYTOsiJLqODxMiVt3pQx~AGFrx5mVtMUcz9cu9hVPnz2ZVmIDB~a4UGkexf~FCHhaQ6Emnr4nnZBiFSP3f4nASOMHLOs4SE3UKiYUB3ntmJssVdD1w-ZGrovHynkvXMjrJ9GhIeldFm0M5cOAhra0OtJagZ-bgphR0v99ADGPl7X5DoGAAAA
+home.duck.i2p=dQmTRCAgcKlbt3VKdW-iFI4zd3WnDaM8ULsfIZb8oEdDuTq5Sl~1JguWH2Wl8PMRuxkhHpfOZ6IUJZtxo-rr3tfaDsYPl8SZSIbvGBs5QooLl2NNTPA~gQMJOHZkuM4KWMWYnFRWoaqAUt9KAmdyl5vgF20xv0rmSgRmm8t6c3QSTfNWSeSDYkRgEumaUKP-kRJnSKNeIOez1N2HQSlaDu~cH27E-VqEuAu8HppI87dV~v6nVKXR9-KgHzCdfHXxy2pxV9trJ8vmTEZO53ab11-BdDMoZjOv5sjMUADNDnhIW1RJ3c-ZcF9OotYsUrf7E1fRo3BwGg27LKhFnyBDmzI0a5uQJ9HCDlzSQ7yfHNMqNCtMfHgZE6Bw6F3tJfr5ISP1j5ibfj4k9tODyfWVqTionQfgrP5szHdyGu14Y4AtDW01-d9BNmBTHA53jCl~Jq6Qm5~CKcGZGS-05iyhmg9x1FtR-rW5Vf6o8uitSjtE5uPt~UHXacaGxQMJSy9vAAAA
+nntp.duck.i2p=5SIb-1I6SVwFlW~XlYTNJU1NCpbyHJ3co8KdrpDxBosnHtdsZzq2qzYzGDfvkKK3WRoKmRGYCE77uXAvOQjEyWoTkkGeY2xl3B1t4t8K4j8dFvYtDJkRGePxGaY3MW-9ANGUQsGOhh6qq4lcQ7rv-AWyDftfZ3pGaHc79VukSo7-6OSh4WDw~0l~DjdFjQsZOVNTbKIfDxzSjKnkTpNc73nrLhRE5nmnMj7bljTzNtAHiVf~hFMndPxF80JZt6erLqy62-~XbevTWpn2KCTjYzhYUkwYW95-SW27ph5rIVZneizLEanSPtdUkDGhMEjjmy39Qr5rD5i9H-ioIP3NppRkjPwrtI9VJpsJtzv75uANIXy48RCBVXXA18ng8o7FVevdyjVb~C90IXpJF~mT7DI94rTT5QnzlpJVCid65kOoNzXFC80lP-iiwXMMBEcys8RGA9hdOvagkFDJ64l0GwrVpFGO2AVMsMenR0WHEvJOjNv62sT6rlntO3ZywhNXAAAA
+pgp.duck.i2p=kRm2KRa2EiWO~XQFYxSg6UM9lXYHZ93IB80j3ShFhJOOZ4AN05BrTGjMeT9nhn5n1LMEUhy9HJuN-Lhkd89Mbhufk7di6M40wqySns2g0T7XUCFUgQ8kl4~BoY8M9U0pHpM3RJcCw8WJEFGEk~fX8tgC4XQB43UIXfrdKTlNfKhxZODE4UdvlFfFdOYMgH53x8UgMZUprn~URTRNg1uwcaXr2luMwts6HnDt1bDd8elitsWViOJiw42yAFMqBnf-7mhiTCsoYg-nsOiq0Jirt58cBjAGUL5ujZo~vfXkLslDKjHOP32Y7HIi5ANEsbbRr~8QrVUojnVoJwFXs8BQBTevRpGLkCSLnKa31jNSt3msOnEP-n729Jabwj8o3pdRk9e-3~~y9gfj4bcmpSH9sOJoqmipXDiqOvv0tL9twERqse3tAwjE1NgXTvl5e2Zc~F0xJ-L2aG~6BX175ihjjEiYGWRYaoEisHMZdMtivsAK92dKl1JVEkuDF3W8KjL8AAAA
+scp.duck.i2p=AE2Ff7x-tJMI901UKEEXkcwb9~5KZKs--VBXEoZnnpC~mlgnqGsZr8MBvRvs6xAzP7xXLeL~cHQ~gvPFT60obEBitwH~JcKMahhJDGb0p23Z8B81QajXijypDpVfMDfFbMiqQGctXhnBidNKWe7HQEcJGZer-SCu3m8CiftcZ0t0g5Y67B2AtqLhza5xfepq6FQ-Tl6fpgS-UDcGUAqMpLUYfrBFB11oM09TRVsfNp~NIAvMdrvXiX8dTDUHJM4FRdpV2OsJiyDdgf5-W6s6ssxohviT5MdijUSYQw5sWj8~9Xkv~~aa11Dvty0E7K9IhXAeJlwBe3VuDizsAJGnFIU7PwZXV7-9-28Zgldarg1P-rh2QDvCqF1vjdyZe99BBcTiCqvE3zx2N-9eT~FeOURrgE~2rFBKVBZfuAASSORqiXIeAANKklCW2pGQrM3DkX8ybi93Weg~eBjwGQugO1FRZ-ISq7npRWruMiC7f~fWLqkmRUy9HahPNp8E41s9AAAA
squid.i2p=8fiWZbRjOEzrj5n4jSqjN9UN54wTrsgEjqn7GRUQpLx1svf8lwckXPV5buP2VEYGo~83ftkIcDKyMLXkxSr8jqbb4yAEgPe2~w7OT~8LNvmVPz0xZhIO6fiw0WU4xD9x5PG1spYjWPnLFv7pynEvBpWFXaUlCacjWL2KkfViiGPXvveQqQIZs7VkxVD2HK-oT4yIjdqHpc7Y8nEV9xwds3-LX6to5p70jFe~kZJA2fjWHsSCm92TtPvoR3aTlL1VS3JUKpcH6BL5irsh-SKODEtDRCErPQI~j2SHzhcD6dMUsI7bm3AxivjFpSQHqyXLmLVdxECYsMET~nIHmuv8NYTHQQ0jM0XTQzwnQwEHjHRBd1~spR9uS2~LSnX4Pw~X1WTknJpPK1f4Cu1O44X4RYcLRCsxpEzytUBXA4BQizrbYgOJVGQa9-PNGxJeZsnNUZ3PxUi23Oh-c4jUaB0ZjyKTWJSpzj1GI6vc-gW-0ixGJ358TCSbKgqdBv~g~f7yAAAA
+fillament.i2p=Pa50z7pU~ni5nWwUdaDZ5CJxG0fYjoarm9wlxnkgX~wHMX9RPgQAXz~r0Rr1Nadt2OA~dr9RMHswrMok0hutK3JZuFD707D7FjmWW2w979Ee9I3zxKyx9W5A2eE49PPT131NLa3uINXLXOYVA5frfDOmM75Dmvm533r8e2kloemJyj22HpvRiSXiQYgqYJGDMH3Hlnwk884eRkQu7P8DJL~hcuKpyY0FzLZtfxTNsdSavGjl7rKPMzJeP02-9TS5TkdHokZrstVM5Cn9ay1c8DQrMds7SPXJy13Ut34QRjb65JxRV0mrnY3teXewW6QFvFMXJCsf5C3i46t-9Fufy5D1H8cSd2Tx~Xl71MC5-1AJCcIS01Od23E9tFY3dU7IOSRhKC~FiAslyk3x-BnBSpKxbgl1w~LArBm5plNiCiUemJU88xYdn1UyukLer~yNrEHAWspckCRkXFwmUtPkaGNTvfwBSYns-skNHSd7MAUUoS-ewStBdmtnDgRkwSG9AAAA
+eco.i2p=KhRG6BGxVPh-BUDDfIgy0570cppTdighytcaGVR0HzQo46tgRMBp9Shlpax5FQX4nLHn6qHQbdFFpFbAwe7CiDhURCVF9-CxYmPurGadxlMPHMjz9O3jHX0CQiv2iULsk4XPrYXF3PqBc4t1J6vVyBVO7uTUhDi0gF6sN1Ro-1GLcWcsoR8Kx-hb~Z4WqGD0QAROOBPHnSRSb236qVBkhFvSkfigfBq3jFgEsttadYJA9ZLSUj1XrFFRBjz~xkRra8kJQSZl5dbfg-eZMlL49h61U6Uta5n1~tL6sarmnl9CaTl2Qo27SKB1OmMLeZEteA5G0-~LiOjN0nxaKpwrCjKIOyvwbQy2QqE-GEb9m8SN8nC2bwYK9fH15pTMHY8GvPYGcUukbF6RhefwzkEJLZ~PaAECrZYuLsn9KE5C35uRnlWJiuJlJ25hG7da5tFMyDB95efzq5IMxPeI0pMigRfuVfRSaGDpNos6JxjfEIX8umk3jIJUPhz1d8gP4QgrAAAA
+aum.i2p=09hSo56PTtkFLUEt1iUTO7zYTnO-B~ogsIsyyPWif6q1Iz4wz4JoBflAWZtedPmwGmH0nly4HYUS0gAADoUmBUnXwemmO6dxT-hPQkfEW-A7b3uEvYQWIN~kyFyg0Pa~FN6TaD9kGFttBN-GE4wxiHhXmWdzWNDVb0q5PVGnxMm6Jleik8xkd2Lgeexze8rIv8LCocAWx074USVkbCVQwoFi2P7EnjLq8odSz1cJAntbuCFeUZcjbslE3qmlcTFMCNCZXWKVzn7d5m4oszCQ83NidgekwxJ-S~iS6mBwIS0XKI--4iXiKXzzCFf0KtYfEWpvKCuqNJOcU8vQWAA2-i7~K28aLPzccDQn7acXWLKRTXF3tf0i6e-lSx-X6WTSWK-fuNitjAtKu~jqO10d~bCk7y~UPL-XwdH1XSTbk-Phhk7UoBTDiHY6zQHdD~iAzXER~9JXsJ4UoIrGFVabg7frzSt82CN7Ek5Li4AMz5gg3wq9H9HUa7xM5QfGIJpXAAAA
+mp3.aum.i2p=vBOu1caCAajaL5WRMuwk4LwfXrlcn0WzA6iHUKV5ULhaBpJb9pR3SZpnQms2Ot2c5Fvu5I6Rp7WF6QRcyasAhUmC915ap~2~VG8KCDP0z3Quh1-eqGcmzErsIfXdh09j3CWuxN~fH84hd~KswqGudFkWtFTM9RcuQUGSC1efG7uF03uaDI-DKu7eb4VUV-hmpXb3Lqntgo5qSMBMmjyUND-f6RBoXnqM005mUZJpMoYfsBhnUEq37GG8u6P9T94nlMmtz9R3gNURpBJJKPlnEqCBN4mlE5rwspQ0ovxAlogVMhSCpQ4jr6cyWIbNx-nMzKGDj~hMQ0ndbVnWw3EDC3KsPnRnDv0yVz8Fc1YpoPwerHej7VnTupDKxc4T-j8XNA1dN8SfPmaKYEPfavlmy7HFAGcsbmeRZOq-PVvlDdrKNflug8Ysodd5XkDbh7y2k1pRDjwNBQ1EgDVAtL05-i9jerqekHkbFKJ6DlT76f06vj1R2v9qlQzAYjpcKbI3AAAA
+ogg.aum.i2p=wR2ETKWn-mxsTurWwmSujvjpOiIjLg5TsldFUa4YFTgiRZdFIB-bXuK59shfnchlEgAZR0IR3~hH-O8bZ~j6wVBdZWq7bGTmyTxQ3MeYPdqK7wH7Jp147YUabFlqJkyI~DluwBDylJrIUyc2qw~ogJ67x-KyzIF7JLnoCC4E-T8Z0vmTAFWSa3XC-ncghrdZQCqEXaCMlG9PN~a7dcDq~qdWoNoyFcgLd0IQfE8JuJ1wSvmWUNEd9vkB2Zuu3EoSoDv4C53Fc0YhVACNug~VEEL-ZBGcCBcpVNud8dOMq-CbavkD5yKqHlvq~uzRi6BY5ajHI77uepJygkHcsm-8T0PXWXdc5ib4TtUI03tPkTar4Y2iVocY~oLk2jh7pQKZNioHJT4StWv9Pj8EWaVX4-emQB5kZOBwZItjo~EAGEoBT14NSM7CmKClgc6sg7fpvWF~-cNHkZsurBndni~~FKmUeWoO0FRQRF9Ao~C1DOt2V9oBbEW1~n6anjL5V~IyAAAA
+fcp.entropy.i2p=jy0D13oJVmxSa1MltstV3FOfA5e2WAEEZJiYOJIZSUOcNnAkaR3ghE-AX4vuqyQPyOEUydpauD6cS8vfx4iZkb2U3ddlLcOU3YrFKdLrySpGtD~V126VO-9nOJFwDQOOaKAsiVGRKtMPLC64GkpU6TWSIhiVYWb7WmeAHXLLlR71DtgamAxEIlP3VhytxlS3vuvAoEH9ItsBwkv4N~7jec60WMQINl~c7uDDsuzKFY8wQlkHnLFQJCQ0VExfNYqK9nZ3x8TXNPmNKTMMQ1CUCowgwR783U7UAYqsxNrpkuWvTleadn7QcR9i2v4~L9zOeHd4nHBy8PAjO29g6nf6DIsYhg4c2HYnPYzktQ1NIElytmW83BhbXJXLgNBs1eI9gDaQmOiXi74FMgfg63IcXCYWeqCdwEzSouSphaXEHDcZZVTx7DE9R-1Bi4Dt~KvPOFsAoOqsjHCpHq1gS0u5HiL0hkSm1I1EMk4JBY0j4rM1nAt7e0ix~WiOz5jXlTVSAAAA
+http.entropy.i2p=ON2Ud-B0-pJKbTR0Obpjp9wEG8grUpu55gEn5Mz3-dkVkPhHvHK6iLasr~P~Rf4kPPZvn-eK7z6rAVfsAytAJ9pcTH3lXERTjkd9FzVJJ0twbZSQ~XzX5d-24IPIMf00KegjnDkRJ82cRMKa-u4H-ayei~Y7xsSx64zC1eHv6qFxavtql3zRrS~du41~EHtpjqOtOo9Ea3lfFjhm2jUIJpYyVHqve3WbTfMBlguVALwGZIfenph7oQ1Hx~OnEtaviWuOEpupjm11LS9xqCNsccaEpJGvGt6ijxd9hrEuQZ5Ja~C0fNxf3xNtgRaUhakA8Xoo~jz8rCkV2vYQo58kj0E5xYrUQczomj8y-eDBZyq29BP8pfe2G1u3hpHA1z470LUeMPk8qVx8Cx8ZKmSK9XCvOl7WCnFS2~UUfzxbxSxPn9LfzxDZp05AVi9t~hJg-zkrL2n1wfEnScuUFapxarwK90rlAxNSnau-K61WfcXqyVMwDxl3leJOeVdHqhpbAAAA
+www.mail.i2p=Y~V8YK2M-my6-Gw0lkrkJouxeqPuB03idp-4uT9pkIXCA5nki9m4YFfPObSPv0E7c2shBxwlUo-6beaRQ-7tCawJssDRc0C0PhRj12QUYYdtZP7JS8SQXy68gZIylY-wfyEXleIC4mYY5mSthhdUUfyo1lqzrdHc1NpjPBxRJcyMBFBGUeM7Of9E9M518jXpVl0bAmxSnr5dy7sgKAVNufzfqIBfEHnmL2ZYH78FoGnPybsV0F9~154emkmt89ZUbx0BuYvH3kT1zin8pSxKw1NqxvqYt7p8CElq1--U38rO9U5Y~kLB9f6F3RYJdkl28ANkvdgJUgqiHLVI5oPWATrJLAOokyGKhK4Xl4Bjp4SCuemxHwTOGyd-4Kl8cO41u3w1LksndX9stkV6U1X0gL9BeSIoa1997IgMLVbUiDMyCz7-cA0y2tc0EdQdlpc2y77nTdo7z23dMSJzWDXsrfmLhX7M24D70htLLc1dpwZ1BUEvM1uPqGfsBSrHdl-sAAAA
+smtp.mail.i2p=gfSAYcvEsuU3oNGqeMpq1wZqH-whE1i~YCXEDwYzp8LrmukWsndvPER1~gF5QFrIp2RMXiietF3zEPtAJgevSG4ULxRU0s9MSAMXXlCACVhlf0m493J6kIYnkypOPC-Z8sulyF2kXM8BURLfSH57SS2uxLbx0hkc8j0kR9iys3ksxm5dgW-Rs7clAvLmmfASJkXZiU6DRhWbW84GbpAi9McE3ORhNLrWV5t1W4DXqzT0tzF2W0i8BEGns8XdOBQei9RAewzo5NRGPBmUl6ZKjEJ-2UtX189HPs7FcLknfsRxXhRcPQ1RombPezYCgcNhOgWY9owHq64mwGaDCnnpDSM01sdAuMlFfs1JJMoYNrILckjiHUNzV2XS8A0PIWdO4W0cT1EUs-V2a7Ocvg397HpR6Z4k-7fOrjs9yvpFsCPIEKYUD0mjr44N5pJIc61GGuNE~2ihQZGA3ju0OnUKTRZel3nK0rxl-qfFXsBsEB5vt-MTvKS73ZJdxUKWWzbWAAAA
+pop.mail.i2p=aG6owmzirq7QZKYovpSVa4-WBLfI1uJ38cNmb6kkSkcS8A~JdoLWPj6eXieN8r3m7YJLxxyZhf3urmK9qJbiIPBp53M8bOSSkldpFz0NkQPWUWmYXiOrEsOBlugbJ8nNelDcOebqoieKBOTaF-WPJQil5C6RYdUy~PL50O6Qp-Hog1868zP26leYBBFiyzzWI3bOpOsgV~4bNXnqKQZeHXz1Ua2DkV-vDBpeamPzvNWQI6cNodf04PBKXK~TlduLZDK7v1yTt2LhPSBM5nE7ZRtS8KQIdh4o-nyYRmHjA~OQ70gowGpmsRqXHQxOpPro~C7w3gSe2N0zhqSHKstwoFJD-NmsBQ5opyOiKccATpWEQdAwmoICD6rw7TGG4XYXCtyTD2xxLffER0SEsJ-BJesKKhdm-qyEMAOQq00jatoEs9jBYoujFLFQMUgaDejRJdEHWkiGT~x4auosHGYavmrcm-0mdX0CWYgfjwVb~PORhBqHJ1G5IgRPjoZLuxiJAAAA
+nm.i2p=UhUVbM972VwQgqS28SkGPtghCb~IpdpeMW7O9E7I3HtlB2I3XGbMeUAoya5RHsoG3TYxf~P6lA5IM5Z~mDZlcbZ~AG7255FE6Z3Jl9kfMArneou6AYaCfNBqNTRS-P7yX9s0Kss-vM63yBulxhS7CqmBKTZsXR27PNjJS0PMYsWBzciuy8UqUkE0YEhSLWSUYAXLP9FKs065CNjxsLumkkoF~MNUaBNEmbCrjpv5Ih9vrwz4XAJSE~S61qSMj6O-nvEPDVhTJJ5ymeoZnYMpIRt4r7FkCTH8vYSkXZkhqXUkLC11WPC33lw2wzh-irmIb5GQeab9o0-DuNQcvUnbK13Jxkq5XiilfK6kgKiPcEniqxMb-4paZAl8dj9Zp01LvhfjlS0c459Jv-gr7ZkjkX7hhTaEVvqwPyFgoVKnxQCitoZrK98WRKJwu7EQb-Kin2vzUsYfpGGI0aT68~gdr23oom2FsoZ~owVuur1h0bJr9mnCaMf6jaioQE7wezxgAAAA
+mp3.tc.i2p=LRCWTiJouI6ohqtaVBNHWZe2ymjhtyj3z9KdeI2G2D9l0cYFsG0CRUVT5VPYOg~WykALRVBiL-2U24fbiQ28hhPdQgBMBDl9aQiZJM2hv~di0uVOdARhRSgCDgRQAWioAfpXeg6pyklzXU3TNLY4c2CRLe~9Y7wuLbK3lONsAApcxxKeHLrfGNkZZwJTKd7PcG78KAHU07E-TVNf4tQrOh8tSrHaMB1r7cQQv1Jl8mNUZWz4fGeNYEZ1wr04w74Em2~Z5K0VZ4mH5DhFGXc9ALYzZf6uOVzZKiUC0eOcdfGNdVUbIog2CYJGH69TgAX69d5vF~kEzvHSzX7RxUTt0y25Rlbi6rHSDF36xOfBrOUVnSPn5X~TdKLygz~zusYpRdGZwlsyOTKVTzJHKlU6Vp5Dofijj1bUwXDQ59XCpFUqEDA17nETiOO0H5jfieYBPS6Ke2cFTAhutSvaw~albCd1eV7RPqeGdw-vFfKoucDIEVUT40B5qalyFRKIxx3lAAAA
mesh.firerabbit.i2p=BLt3pciNQcVIU-IGnTfSsrputh~b6drZpc1vH8qeA745XoE~nMCGtw8S7HGYX4uEbwk876nQRPV4qRwGtWWkWBs8BX9qX8NABoXFk4G-6NifB4TxEizC~ZAnXZ2uFs~nrqodhyCR8bBHJL0tzBYK3E36zc~SA-DKqQ9XSHWp7ScW7Z3cdQnYKma~x4u5eZmcS23uie3OIfOCk6pJOabtaE-YWRa1eUizhucI-ysm789GumjTo858vHR1mTQfrsPTqNri3yz0aIe~w06ifciq~UlNjVfx89lLEso1vmg8rfTQ-hwxS-qz-u3K5x5vtqdGp673vCvmEnQpU6GEycmkqoLCho9pNQzGbka-OVHg8fZqlFMeBfj2iLz~zlv170jvX6HTlMCNfBYnFqavs2RQJj7--dJ0g7JHReGMKL~TciQjxljrV5AoN-0afRzTZqtDg13PL4tltJm5U1~f-GcxlsjKLZAlv26LlZXsvTDU5plldsernv3fDcBev9UaKYCwAAAA
chess.fillament.i2p=8xvXLwcBYu2MxqMAoG6DIahvkNAwBQs43kdZTg9SlouzC3JSQ25RHvspbrxWoGIVAlB~XCxVmBB6EolYEHoSZv2YCziOj4UVxEbVP7nHkh32-7Uc5T7xlcjk8-rsmZzdgz9NhxKVn2Uhp3xtcdVAiyG4mpXisvK-7NgHY-mXPNvj6goaH58roeDUZ5otJN7nCFmcRAUpaUk-nlQs8YfgSCCEsWKOWhsVnAaHwtqtDlpdTo1YKooACMRSa-DcV5W75Il80JEWBD79qpSAeONGAOMMPT~VEMwNNg001VG-UZbvyspZdxHaETw2yd7N9l3-mwI-sYcveTTnNXLWO8IjdgDLdUIP5qrIW6WS9XZIHRKqT2kpwEw7xsEgCA~qSNiZWeai8n6Zs0rLmdyeZeafVEEW9vr6CKcLZ5W7i1SMDqCKnzSbZdd2Hvpb9aWFf5foEjLt33n8w2KSaCUe4zmN~xuQMq2yiB-vQ9~5fgPmphlMxo3ca5MTCfbhshw5137YAAAA
kaji.i2p=i-nivH~36AgabgzvS06oKHR~MLoy6NA0oSv8JuNJDLZB8FXEDzIiyzWISmw9XJm8I7QqZ1yFH8~xe84STCHHvMMIQQrfBmOUODLWbKZor~~KhiHdNLtfVZC5BpnXkBCJkklj~fMYSpWa0C~pVRrZl75RoGtBjDVP9P8hioTv5B6RC86g2ypBH5r093rY0wnzxSL8-ZuV3F~H48VYbqro8cRlbMmjx2oEsSHkDpQyjCMVkIYKaCijkSArqZTG~zX6op6Ng9CJwdrkjKSsbzjV6MLnE4aNv-jm2WaGGD5pR24h7e3ImDOGAr17tXRtmNX5ZEQ1udQp8qIhd8UMUumrnm962r8KJWK~9WNzcVeqDrIxaaxC7vcQmXxoPeEW2efbH0yKhVZ7OFu~I9cAapSe~aNWp9UK4URSpuJvOedt0axp3ORaaM-a5U7noW3Ao-HB83qfFEPU-6uUu16HNiPqCFMJiA0qODTOwHiyyx4HKQvbhjujh4mmknSbsuapdgR1AAAA
From 33f4fac48f0d4afc53307c3c3926c2177810f735 Mon Sep 17 00:00:00 2001
From: zzz
Date: Sat, 14 Mar 2009 21:42:50 +0000
Subject: [PATCH 049/688] summary bar help
---
apps/routerconsole/jsp/help.jsp | 116 +++++++++++++++++++++++++++++++-
1 file changed, 115 insertions(+), 1 deletion(-)
diff --git a/apps/routerconsole/jsp/help.jsp b/apps/routerconsole/jsp/help.jsp
index d53f93a885..279df95ddf 100644
--- a/apps/routerconsole/jsp/help.jsp
+++ b/apps/routerconsole/jsp/help.jsp
@@ -12,12 +12,126 @@
Help
-Sorry, there's no help text here yet, so check out the
+Sorry, there's not much help text here yet, so also check out the
FAQ on www.i2p2.i2p
or the
Deutsch FAQ.
+You may also try the
+forum
+or IRC.
+
Summary Bar Information
+
General
+
+
Ident:
+The first four characters (24 bits) of your 44-character (256-bit) Base64 router hash.
+The full hash is shown on your router info page.
+Never reveal this to anyone, as your router info contains your IP.
+
Version:
+The version of the I2P software you are running.
+
Now:
+The current time (UTC) and the skew, if any. I2P requires your computer's time be accurate.
+If the skew is more than a few seconds, please correct the problem by adjusting
+your computer's time.
+
Reachability:
+The router's view of whether it can be contacted by other routers.
+Further information is on the configuration page.
+
+
+
Peers
+
+
Active:
+The first number is the number of peers you've sent or received a message from in the last few minutes.
+This may range from 8-10 to several hundred, depending on your total bandwidth,
+shared bandwidth, and locally-generated traffic.
+The second number is the number of peers seen in the last hour or so.
+Do not be concerned if these numbers vary widely.
+
Fast:
+This is the number of peers you use for building client tunnels. It is generally in the
+range 8-15. Your fast peers are shown on the profiles page.
+
High Capacity:
+This is the number of peers you use for building some of your exploratory tunnels. It is generally in the
+range 8-25. The fast peers are included in the high capacity tier.
+Your high capacity peers are shown on the profiles page.
+
Well Integrated:
+This is the number of peers you use for network database inquiries.
+These are usually the "floodfill" peers.
+Your well integrated peers are shown on the bottom of the profiles page.
+
Known:
+This is the total number of routers you know about.
+They are listed on the network database page.
+This may range from under 100 to 1000 or more.
+This number is not the total size of the network;
+it may vary widely depending on your total bandwidth,
+shared bandwidth, and locally-generated traffic.
+I2P does not require a router to know every other router.
+
+
+
Bandwidth in/out
+Should be self-explanatory. All values are in bytes per second, not bits per second.
+Change your bandwidth limits on the configuration page.
+
+
Local destinations
+The local applications connecting through your router.
+These may be clients started through I2PTunnel
+or external programs connecting through SAM, BOB, or directly to I2CP.
+
+
Exploratory:
+Tunnels built by your router and used for communication with the floodfill peers,
+building new tunnels, and testing existing tunnels.
+
Client:
+Tunnels built by your router for each client's use.
+
Participating:
+Tunnels built by other routers through your router.
+This may vary widely depending on network demand, your
+shared bandwidth, and amount of locally-generated traffic.
+The recommended method for limiting participating tunnels is
+to change your share percentage on the configuration page.
+You may also limit the total number by setting router.maxParticipatingTunnels=nnn on
+the advanced configuration page.
+
+
+
Congestion
+Some basic indications of router overload.
+
Job lag:
+How long jobs are waiting before execution. The job queue is listed on the jobs page.
+Unfortunately, there are several other job queues in the router that may be congested,
+and their status is not available in the router console.
+The job lag should generally be zero.
+If it is consistently higher than 500ms, your computer is very slow, or the
+router has serious problems.
+
Message delay:
+How long an outbound message waits in the queue.
+This should generally be a few hundred milliseconds or less.
+If it is consistently higher than 1000ms, your computer is very slow,
+or you should adjust your bandwidth limits, or your (bittorrent?) clients
+may be sending too much data and should have their transmit bandwidth limit reduced.
+
Tunnel lag:
+This is the round trip time for a tunnel test, which sends a single message
+out a client tunnel and in an exploratory tunnel, or vice versa.
+It should usually be less than 5 seconds.
+If it is consistently higher than that, your computer is very slow,
+or you should adjust your bandwidth limits, or there are network problems.
+
Handle backlog:
+This is the number of pending requests from other routers to build a
+participating tunnel through your router.
+It should usually be close to zero.
+If it is consistently high, your computer is too slow,
+and you should reduce your share bandwidth limits.
+
Accepting/Rejecting:
+Your routers' status on accepting or rejecting
+requests from other routers to build a
+participating tunnel through your router.
+Your router may accept all requests, accept or reject a percentage of requests,
+or reject all requests for a number of reasons, to control
+the bandwidth and CPU demands and maintain capacity for
+local clients.
+
+
Legal stuff
The I2P router (router.jar) and SDK (i2p.jar) are almost entirely public domain, with
a few notable exceptions:
From 91b3889cbcba549891faeba9cad4bc90250175fe Mon Sep 17 00:00:00 2001
From: zzz
Date: Sun, 15 Mar 2009 00:16:38 +0000
Subject: [PATCH 050/688] catch a rare AIOOB
---
router/java/src/net/i2p/router/tunnel/FragmentHandler.java | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/router/java/src/net/i2p/router/tunnel/FragmentHandler.java b/router/java/src/net/i2p/router/tunnel/FragmentHandler.java
index 5a97956b9a..dbe256ebd5 100644
--- a/router/java/src/net/i2p/router/tunnel/FragmentHandler.java
+++ b/router/java/src/net/i2p/router/tunnel/FragmentHandler.java
@@ -74,6 +74,12 @@ public class FragmentHandler {
int padding = 0;
while (preprocessed[offset] != (byte)0x00) {
offset++; // skip the padding
+ // AIOOBE http://forum.i2p/viewtopic.php?t=3187
+ if (offset >= TrivialPreprocessor.PREPROCESSED_SIZE) {
+ _cache.release(new ByteArray(preprocessed));
+ _context.statManager().addRateData("tunnel.corruptMessage", 1, 1);
+ return;
+ }
padding++;
}
offset++; // skip the final 0x00, terminating the padding
From d0a969ca33d78c1eb2e0794ab5c7e4351c7bb10b Mon Sep 17 00:00:00 2001
From: zzz
Date: Mon, 16 Mar 2009 19:31:29 +0000
Subject: [PATCH 051/688] fix NPE on delayed open
http://forum.i2p/viewtopic.php?t=3189
---
.../java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java
index b42376dbf7..8e5ef9f4dc 100644
--- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java
@@ -185,7 +185,7 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable
/**
* create the default options (using the default timeout, etc)
- *
+ * unused?
*/
protected I2PSocketOptions getDefaultOptions() {
Properties defaultOpts = getTunnel().getClientOptions();
@@ -210,6 +210,9 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable
defaultOpts.setProperty(I2PSocketOptions.PROP_READ_TIMEOUT, ""+DEFAULT_READ_TIMEOUT);
if (!defaultOpts.contains("i2p.streaming.inactivityTimeout"))
defaultOpts.setProperty("i2p.streaming.inactivityTimeout", ""+DEFAULT_READ_TIMEOUT);
+ // delayed start
+ if (sockMgr == null)
+ sockMgr = getSocketManager();
I2PSocketOptions opts = sockMgr.buildOptions(defaultOpts);
if (!defaultOpts.containsKey(I2PSocketOptions.PROP_CONNECT_TIMEOUT))
opts.setConnectTimeout(DEFAULT_CONNECT_TIMEOUT);
From 0da964e47f620311b0721e7976ac69a971100370 Mon Sep 17 00:00:00 2001
From: zzz
Date: Mon, 16 Mar 2009 19:34:59 +0000
Subject: [PATCH 052/688] -9
---
history.txt | 8 ++++++++
router/java/src/net/i2p/router/RouterVersion.java | 2 +-
2 files changed, 9 insertions(+), 1 deletion(-)
diff --git a/history.txt b/history.txt
index 1388353e41..e5bfe64788 100644
--- a/history.txt
+++ b/history.txt
@@ -1,3 +1,11 @@
+2009-03-16 zzz
+ * help.jsp: Add some
+ * I2PTunnel: Cleanup
+ * I2PTunnelHTTPClient: Fix NPE on delayed open
+ * I2PTunnelHTTPServer: Maybe catch an NPE
+ * SOCKS: Allow .onion addresses for onioncat testing
+ * Tunnel: Catch a rare AIOOB
+
2009-03-09 zzz
* Client:
- Clean up retry code
diff --git a/router/java/src/net/i2p/router/RouterVersion.java b/router/java/src/net/i2p/router/RouterVersion.java
index eeea3faa97..6ade2ee810 100644
--- a/router/java/src/net/i2p/router/RouterVersion.java
+++ b/router/java/src/net/i2p/router/RouterVersion.java
@@ -17,7 +17,7 @@ import net.i2p.CoreVersion;
public class RouterVersion {
public final static String ID = "$Revision: 1.548 $ $Date: 2008-06-07 23:00:00 $";
public final static String VERSION = CoreVersion.VERSION;
- public final static long BUILD = 8;
+ public final static long BUILD = 9;
public static void main(String args[]) {
System.out.println("I2P Router version: " + VERSION + "-" + BUILD);
System.out.println("Router ID: " + RouterVersion.ID);
From e5f19c98a8bde3ee448d46f369a35b8bd787f28d Mon Sep 17 00:00:00 2001
From: zzz
Date: Tue, 24 Mar 2009 15:21:34 +0000
Subject: [PATCH 053/688] change common corrupt errors to warns
---
.../net/i2p/router/tunnel/FragmentHandler.java | 4 ++--
.../net/i2p/router/tunnel/FragmentedMessage.java | 16 ++++++++--------
2 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/router/java/src/net/i2p/router/tunnel/FragmentHandler.java b/router/java/src/net/i2p/router/tunnel/FragmentHandler.java
index dbe256ebd5..99b66c0c8b 100644
--- a/router/java/src/net/i2p/router/tunnel/FragmentHandler.java
+++ b/router/java/src/net/i2p/router/tunnel/FragmentHandler.java
@@ -393,8 +393,8 @@ public class FragmentHandler {
_log.error("Error receiving fragmented message (corrupt?): " + stringified, ioe);
} catch (I2NPMessageException ime) {
if (stringified == null) stringified = msg.toString();
- if (_log.shouldLog(Log.ERROR))
- _log.error("Error receiving fragmented message (corrupt?): " + stringified, ime);
+ if (_log.shouldLog(Log.WARN))
+ _log.warn("Error receiving fragmented message (corrupt?): " + stringified, ime);
}
}
diff --git a/router/java/src/net/i2p/router/tunnel/FragmentedMessage.java b/router/java/src/net/i2p/router/tunnel/FragmentedMessage.java
index d26c691b79..b0203f540d 100644
--- a/router/java/src/net/i2p/router/tunnel/FragmentedMessage.java
+++ b/router/java/src/net/i2p/router/tunnel/FragmentedMessage.java
@@ -78,13 +78,13 @@ public class FragmentedMessage {
return false;
}
if (length <= 0) {
- if (_log.shouldLog(Log.ERROR))
- _log.error("Length is impossible (" + length + ") for messageId " + messageId);
+ if (_log.shouldLog(Log.WARN))
+ _log.warn("Length is impossible (" + length + ") for messageId " + messageId);
return false;
}
if (offset + length > payload.length) {
- if (_log.shouldLog(Log.ERROR))
- _log.error("Length is impossible (" + length + "/" + offset + " out of " + payload.length + ") for messageId " + messageId);
+ if (_log.shouldLog(Log.WARN))
+ _log.warn("Length is impossible (" + length + "/" + offset + " out of " + payload.length + ") for messageId " + messageId);
return false;
}
if (_log.shouldLog(Log.DEBUG))
@@ -131,13 +131,13 @@ public class FragmentedMessage {
return false;
}
if (length <= 0) {
- if (_log.shouldLog(Log.ERROR))
- _log.error("Length is impossible (" + length + ") for messageId " + messageId);
+ if (_log.shouldLog(Log.WARN))
+ _log.warn("Length is impossible (" + length + ") for messageId " + messageId);
return false;
}
if (offset + length > payload.length) {
- if (_log.shouldLog(Log.ERROR))
- _log.error("Length is impossible (" + length + "/" + offset + " out of " + payload.length + ") for messageId " + messageId);
+ if (_log.shouldLog(Log.WARN))
+ _log.warn("Length is impossible (" + length + "/" + offset + " out of " + payload.length + ") for messageId " + messageId);
return false;
}
if (_log.shouldLog(Log.DEBUG))
From 09d700e1d6b6777d5fc2509dcc2b521855cdbe9d Mon Sep 17 00:00:00 2001
From: zzz
Date: Tue, 24 Mar 2009 18:19:47 +0000
Subject: [PATCH 054/688] fix encrypted leasesets
---
core/java/src/net/i2p/client/RequestLeaseSetMessageHandler.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/core/java/src/net/i2p/client/RequestLeaseSetMessageHandler.java b/core/java/src/net/i2p/client/RequestLeaseSetMessageHandler.java
index 7a8bd200e1..e662f65727 100644
--- a/core/java/src/net/i2p/client/RequestLeaseSetMessageHandler.java
+++ b/core/java/src/net/i2p/client/RequestLeaseSetMessageHandler.java
@@ -79,7 +79,7 @@ class RequestLeaseSetMessageHandler extends HandlerImpl {
leaseSet.setEncryptionKey(li.getPublicKey());
leaseSet.setSigningKey(li.getSigningPublicKey());
- boolean encrypt = Boolean.valueOf(session.getOptions().getProperty("i2cp.encryptLeaseset")).booleanValue();
+ boolean encrypt = Boolean.valueOf(session.getOptions().getProperty("i2cp.encryptLeaseSet")).booleanValue();
String sk = session.getOptions().getProperty("i2cp.leaseSetKey");
if (encrypt && sk != null) {
SessionKey key = new SessionKey();
From 47edc3c8537f079ed49c97051f8f539fd3b31168 Mon Sep 17 00:00:00 2001
From: zzz
Date: Tue, 24 Mar 2009 18:21:28 +0000
Subject: [PATCH 055/688] add warnings for some new features
---
apps/i2ptunnel/jsp/editClient.jsp | 4 ++--
apps/i2ptunnel/jsp/editServer.jsp | 2 +-
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/apps/i2ptunnel/jsp/editClient.jsp b/apps/i2ptunnel/jsp/editClient.jsp
index 6dd839d979..915da5db96 100644
--- a/apps/i2ptunnel/jsp/editClient.jsp
+++ b/apps/i2ptunnel/jsp/editClient.jsp
@@ -318,7 +318,7 @@
- Close tunnels when idle:
+ Close tunnels when idle: Experimental
@@ -353,7 +353,7 @@
- Delay tunnel open until required:
+ Delay tunnel open until required: Experimental
+Many of the stats on the summary bar may be
+configured to be
+graphed for further analysis.
+
General
Ident:
@@ -47,13 +51,16 @@ This may range from 8-10 to several hundred, depending on your total bandwidth,
shared bandwidth, and locally-generated traffic.
The second number is the number of peers seen in the last hour or so.
Do not be concerned if these numbers vary widely.
+Enable graphing
Fast:
This is the number of peers you use for building client tunnels. It is generally in the
range 8-15. Your fast peers are shown on the profiles page.
+Enable graphing
High Capacity:
This is the number of peers you use for building some of your exploratory tunnels. It is generally in the
range 8-25. The fast peers are included in the high capacity tier.
Your high capacity peers are shown on the profiles page.
+Enable graphing
Well Integrated:
This is the number of peers you use for network database inquiries.
These are usually the "floodfill" peers.
@@ -71,6 +78,7 @@ I2P does not require a router to know every other router.
Bandwidth in/out
Should be self-explanatory. All values are in bytes per second, not bits per second.
Change your bandwidth limits on the configuration page.
+Bandwidth is graphed by default.
Local destinations
The local applications connecting through your router.
@@ -93,10 +101,12 @@ The recommended method for limiting participating tunnels is
to change your share percentage on the configuration page.
You may also limit the total number by setting router.maxParticipatingTunnels=nnn on
the advanced configuration page.
+Enable graphing
Congestion
Some basic indications of router overload.
+
Job lag:
How long jobs are waiting before execution. The job queue is listed on the jobs page.
Unfortunately, there are several other job queues in the router that may be congested,
@@ -104,18 +114,21 @@ and their status is not available in the router console.
The job lag should generally be zero.
If it is consistently higher than 500ms, your computer is very slow, or the
router has serious problems.
+Enable graphing
Message delay:
How long an outbound message waits in the queue.
This should generally be a few hundred milliseconds or less.
If it is consistently higher than 1000ms, your computer is very slow,
or you should adjust your bandwidth limits, or your (bittorrent?) clients
may be sending too much data and should have their transmit bandwidth limit reduced.
+Enable graphing (transport.sendProcessingTime)
Tunnel lag:
This is the round trip time for a tunnel test, which sends a single message
out a client tunnel and in an exploratory tunnel, or vice versa.
It should usually be less than 5 seconds.
If it is consistently higher than that, your computer is very slow,
or you should adjust your bandwidth limits, or there are network problems.
+Enable graphing (tunnel.testSuccessTime)
Handle backlog:
This is the number of pending requests from other routers to build a
participating tunnel through your router.
From bb51bf49b03d35836630923ddee0c1e69c1059d4 Mon Sep 17 00:00:00 2001
From: zzz
Date: Tue, 24 Mar 2009 20:24:20 +0000
Subject: [PATCH 058/688] - Suppress log error on manual stop - Prevent NPE
when closing a delayed-open tunnel
---
.../i2p/i2ptunnel/I2PTunnelClientBase.java | 34 +++++++++++--------
1 file changed, 19 insertions(+), 15 deletions(-)
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClientBase.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClientBase.java
index 94bc959c02..b6eb392243 100644
--- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClientBase.java
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClientBase.java
@@ -375,7 +375,7 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
// This will build a new socket manager and a new dest if the session is closed.
sockMgr = getSocketManager();
if (oldSockMgr != sockMgr) {
- _log.error("Built a new destination on resume");
+ _log.warn("Built a new destination on resume");
}
}
} // else the old socket manager will reconnect the old session if necessary
@@ -431,8 +431,10 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
_context.statManager().addRateData("i2ptunnel.client.manageTime", total, total);
}
} catch (IOException ex) {
- _log.error("Error listening for connections on " + localPort, ex);
- notifyEvent("openBaseClientResult", "error");
+ if (open) {
+ _log.error("Error listening for connections on " + localPort, ex);
+ notifyEvent("openBaseClientResult", "error");
+ }
synchronized (sockLock) {
mySockets.clear();
}
@@ -513,20 +515,23 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
// might risk to create an orphan socket. Would be better
// to return with an error in that situation quickly.
synchronized (sockLock) {
- mySockets.retainAll(sockMgr.listSockets());
- if (!forced && mySockets.size() != 0) {
- l.log("There are still active connections!");
- _log.debug("can't close: there are still active connections!");
- for (Iterator it = mySockets.iterator(); it.hasNext();) {
- l.log("->" + it.next());
+ if (sockMgr != null) {
+ mySockets.retainAll(sockMgr.listSockets());
+ if (!forced && mySockets.size() != 0) {
+ l.log("There are still active connections!");
+ _log.debug("can't close: there are still active connections!");
+ for (Iterator it = mySockets.iterator(); it.hasNext();) {
+ l.log("->" + it.next());
+ }
+ return false;
+ }
+ I2PSession session = sockMgr.getSession();
+ if (session != null) {
+ getTunnel().removeSession(session);
}
- return false;
- }
- I2PSession session = sockMgr.getSession();
- if (session != null) {
- getTunnel().removeSession(session);
}
l.log("Closing client " + toString());
+ open = false;
try {
if (ss != null) ss.close();
} catch (IOException ex) {
@@ -534,7 +539,6 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
return false;
}
l.log("Client closed.");
- open = false;
}
synchronized (_waitingSockets) { _waitingSockets.notifyAll(); }
From 41718b47c16c0d51769a49645e850c75aa252b50 Mon Sep 17 00:00:00 2001
From: zzz
Date: Tue, 24 Mar 2009 21:29:15 +0000
Subject: [PATCH 059/688] increase default bw to 64/32
---
.../i2p/router/transport/FIFOBandwidthRefiller.java | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/router/java/src/net/i2p/router/transport/FIFOBandwidthRefiller.java b/router/java/src/net/i2p/router/transport/FIFOBandwidthRefiller.java
index d4bdfea85f..693df45b18 100644
--- a/router/java/src/net/i2p/router/transport/FIFOBandwidthRefiller.java
+++ b/router/java/src/net/i2p/router/transport/FIFOBandwidthRefiller.java
@@ -33,11 +33,11 @@ public class FIFOBandwidthRefiller implements Runnable {
public static final String PROP_OUTBOUND_BANDWIDTH_PEAK = "i2np.bandwidth.outboundBurstKBytes";
//public static final String PROP_REPLENISH_FREQUENCY = "i2np.bandwidth.replenishFrequencyMs";
- // no longer allow unlimited bandwidth - the user must specify a value, and if they do not, it is 32/16KBps
- public static final int DEFAULT_INBOUND_BANDWIDTH = 48;
- public static final int DEFAULT_OUTBOUND_BANDWIDTH = 24;
- public static final int DEFAULT_INBOUND_BURST_BANDWIDTH = 64;
- public static final int DEFAULT_OUTBOUND_BURST_BANDWIDTH = 32;
+ // no longer allow unlimited bandwidth - the user must specify a value, else use defaults below (KBps)
+ public static final int DEFAULT_INBOUND_BANDWIDTH = 64;
+ public static final int DEFAULT_OUTBOUND_BANDWIDTH = 32;
+ public static final int DEFAULT_INBOUND_BURST_BANDWIDTH = 80;
+ public static final int DEFAULT_OUTBOUND_BURST_BANDWIDTH = 40;
public static final int DEFAULT_BURST_SECONDS = 60;
From 2695461bd48a0da1ca056e9eda4dc803201cb0b1 Mon Sep 17 00:00:00 2001
From: zzz
Date: Tue, 24 Mar 2009 21:31:55 +0000
Subject: [PATCH 060/688] -10
---
history.txt | 10 ++++++++++
router/java/src/net/i2p/router/RouterVersion.java | 2 +-
2 files changed, 11 insertions(+), 1 deletion(-)
diff --git a/history.txt b/history.txt
index e5bfe64788..d3fcf2f4ca 100644
--- a/history.txt
+++ b/history.txt
@@ -1,3 +1,13 @@
+2009-03-24 zzz
+ * I2PTunnel:
+ - Add some warnings about new features
+ - Fix encrypted leasesets broken in about -4
+ - Suppress log error on manual stop
+ - Fix NPE on close of a tunnel not open yet
+ * Transport:
+ - Increase default bw to 64/32, burst 80/40
+ * Tunnels: Change some fragmentation errors to warns
+
2009-03-16 zzz
* help.jsp: Add some
* I2PTunnel: Cleanup
diff --git a/router/java/src/net/i2p/router/RouterVersion.java b/router/java/src/net/i2p/router/RouterVersion.java
index 6ade2ee810..c1d6bdf7c6 100644
--- a/router/java/src/net/i2p/router/RouterVersion.java
+++ b/router/java/src/net/i2p/router/RouterVersion.java
@@ -17,7 +17,7 @@ import net.i2p.CoreVersion;
public class RouterVersion {
public final static String ID = "$Revision: 1.548 $ $Date: 2008-06-07 23:00:00 $";
public final static String VERSION = CoreVersion.VERSION;
- public final static long BUILD = 9;
+ public final static long BUILD = 10;
public static void main(String args[]) {
System.out.println("I2P Router version: " + VERSION + "-" + BUILD);
System.out.println("Router ID: " + RouterVersion.ID);
From 5414d41de4d199e44da68a3b5b4376d792fc47ff Mon Sep 17 00:00:00 2001
From: zzz
Date: Wed, 25 Mar 2009 23:19:37 +0000
Subject: [PATCH 061/688] I2PSnark: Use new BW Limits message, remove
router.jar dependencies
---
apps/i2psnark/java/build.xml | 3 +-
.../java/src/org/klomp/snark/BWLimits.java | 44 +++++++++++++++++++
.../java/src/org/klomp/snark/Snark.java | 5 +--
.../src/org/klomp/snark/SnarkManager.java | 23 +++++-----
core/java/src/net/i2p/client/I2PSession.java | 5 +++
.../src/net/i2p/client/I2PSessionImpl.java | 4 ++
.../src/net/i2p/client/I2PSimpleSession.java | 2 +-
.../client/ClientMessageEventListener.java | 6 +--
8 files changed, 72 insertions(+), 20 deletions(-)
create mode 100644 apps/i2psnark/java/src/org/klomp/snark/BWLimits.java
diff --git a/apps/i2psnark/java/build.xml b/apps/i2psnark/java/build.xml
index 02eee0aabc..9689fda068 100644
--- a/apps/i2psnark/java/build.xml
+++ b/apps/i2psnark/java/build.xml
@@ -18,7 +18,6 @@
-
@@ -32,7 +31,7 @@
srcdir="./src"
debug="true" deprecation="on" source="1.5" target="1.5"
destdir="./build/obj"
- classpath="../../../core/java/build/i2p.jar:../../../router/java/build/router.jar:../../jetty/jettylib/org.mortbay.jetty.jar:../../jetty/jettylib/javax.servlet.jar:../../ministreaming/java/build/mstreaming.jar" />
+ classpath="../../../core/java/build/i2p.jar:../../jetty/jettylib/org.mortbay.jetty.jar:../../jetty/jettylib/javax.servlet.jar:../../ministreaming/java/build/mstreaming.jar" />
diff --git a/apps/i2psnark/java/src/org/klomp/snark/BWLimits.java b/apps/i2psnark/java/src/org/klomp/snark/BWLimits.java
new file mode 100644
index 0000000000..eb157cb5e4
--- /dev/null
+++ b/apps/i2psnark/java/src/org/klomp/snark/BWLimits.java
@@ -0,0 +1,44 @@
+/*
+ * Released into the public domain
+ * with no warranty of any kind, either expressed or implied.
+ */
+package org.klomp.snark;
+
+import java.util.Arrays;
+import java.util.Properties;
+
+import net.i2p.I2PAppContext;
+import net.i2p.client.I2PSessionException;
+import net.i2p.client.I2PClient;
+import net.i2p.client.I2PSession;
+import net.i2p.client.I2PSimpleClient;
+
+/**
+ * Connect via I2CP and ask the router the bandwidth limits.
+ *
+ * The call is blocking and returns null on failure.
+ * Timeout is set to 5 seconds in I2PSimpleSession but it should be much faster.
+ *
+ * @author zzz
+ */
+class BWLimits {
+
+ public static int[] getBWLimits(String host, int port) {
+ int[] rv = null;
+ try {
+ I2PClient client = new I2PSimpleClient();
+ Properties opts = new Properties();
+ opts.put(I2PClient.PROP_TCP_HOST, host);
+ opts.put(I2PClient.PROP_TCP_PORT, "" + port);
+ I2PSession session = client.createSession(null, opts);
+ session.connect();
+ rv = session.bandwidthLimits();
+ session.destroySession();
+ } catch (I2PSessionException ise) {}
+ return rv;
+ }
+
+ public static void main(String args[]) {
+ System.out.println(Arrays.toString(getBWLimits("127.0.0.1", 7654)));
+ }
+}
diff --git a/apps/i2psnark/java/src/org/klomp/snark/Snark.java b/apps/i2psnark/java/src/org/klomp/snark/Snark.java
index e124955cfc..53c42dfadf 100644
--- a/apps/i2psnark/java/src/org/klomp/snark/Snark.java
+++ b/apps/i2psnark/java/src/org/klomp/snark/Snark.java
@@ -36,7 +36,6 @@ import java.util.Timer;
import java.util.TimerTask;
import net.i2p.I2PAppContext;
-import net.i2p.router.client.ClientManagerFacadeImpl;
import net.i2p.client.streaming.I2PServerSocket;
import net.i2p.data.Destination;
import net.i2p.util.I2PThread;
@@ -261,9 +260,9 @@ public class Snark
public Snark(I2PAppContext ctx, Properties opts, String torrent,
StorageListener slistener, boolean start, String rootDir) {
this(new I2PSnarkUtil(ctx), torrent, null, -1, slistener, null, null, null, null, false, rootDir);
- String host = opts.getProperty(ClientManagerFacadeImpl.PROP_CLIENT_HOST);
+ String host = opts.getProperty("i2cp.hostname");
int port = 0;
- String s = opts.getProperty(ClientManagerFacadeImpl.PROP_CLIENT_PORT);
+ String s = opts.getProperty("i2cp.port");
if (s != null) {
try {
port = Integer.parseInt(s);
diff --git a/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java b/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java
index 54367af1ac..01a93a58c1 100644
--- a/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java
+++ b/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java
@@ -18,7 +18,6 @@ import java.util.TreeMap;
import net.i2p.I2PAppContext;
import net.i2p.data.Base64;
import net.i2p.data.DataHelper;
-import net.i2p.router.RouterContext;
import net.i2p.util.I2PAppThread;
import net.i2p.util.Log;
@@ -147,22 +146,21 @@ public class SnarkManager implements Snark.CompleteListener {
_config.setProperty(PROP_EEP_PORT, "4444");
if (!_config.containsKey(PROP_UPLOADERS_TOTAL))
_config.setProperty(PROP_UPLOADERS_TOTAL, "" + Snark.MAX_TOTAL_UPLOADERS);
- if (!_config.containsKey(PROP_UPBW_MAX)) {
- try {
- if (_context instanceof RouterContext)
- _config.setProperty(PROP_UPBW_MAX, "" + (((RouterContext)_context).bandwidthLimiter().getOutboundKBytesPerSecond() / 2));
- else
- _config.setProperty(PROP_UPBW_MAX, "" + DEFAULT_MAX_UP_BW);
- } catch (NoClassDefFoundError ncdfe) {
- _config.setProperty(PROP_UPBW_MAX, "" + DEFAULT_MAX_UP_BW);
- }
- }
if (!_config.containsKey(PROP_DIR))
_config.setProperty(PROP_DIR, "i2psnark");
if (!_config.containsKey(PROP_AUTO_START))
_config.setProperty(PROP_AUTO_START, DEFAULT_AUTO_START);
updateConfig();
}
+
+ /** call from DirMonitor since loadConfig() is called before router I2CP is up */
+ private void getBWLimit() {
+ if (!_config.containsKey(PROP_UPBW_MAX)) {
+ int[] limits = BWLimits.getBWLimits(_util.getI2CPHost(), _util.getI2CPPort());
+ if (limits != null && limits[1] > 0)
+ _util.setMaxUpBW(limits[1]);
+ }
+ }
private void updateConfig() {
String i2cpHost = _config.getProperty(PROP_I2CP_HOST);
@@ -619,6 +617,9 @@ public class SnarkManager implements Snark.CompleteListener {
_messages.remove(0);
}
+ // here because we need to delay until I2CP is up
+ // although the user will see the default until then
+ getBWLimit();
while (true) {
File dir = getDataDir();
_log.debug("Directory Monitor loop over " + dir.getAbsolutePath());
diff --git a/core/java/src/net/i2p/client/I2PSession.java b/core/java/src/net/i2p/client/I2PSession.java
index 1776af5c0f..1998dad55a 100644
--- a/core/java/src/net/i2p/client/I2PSession.java
+++ b/core/java/src/net/i2p/client/I2PSession.java
@@ -143,6 +143,11 @@ public interface I2PSession {
*/
public Destination lookupDest(Hash h) throws I2PSessionException;
+ /**
+ * Get the current bandwidth limits
+ */
+ public int[] bandwidthLimits() throws I2PSessionException;
+
/** See I2PSessionMuxedImpl for details */
public void addSessionListener(I2PSessionListener lsnr, int proto, int port);
/** See I2PSessionMuxedImpl for details */
diff --git a/core/java/src/net/i2p/client/I2PSessionImpl.java b/core/java/src/net/i2p/client/I2PSessionImpl.java
index 0e13f2c563..5b7603fdd6 100644
--- a/core/java/src/net/i2p/client/I2PSessionImpl.java
+++ b/core/java/src/net/i2p/client/I2PSessionImpl.java
@@ -656,6 +656,10 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
return null;
}
+ public int[] bandwidthLimits() throws I2PSessionException {
+ return null;
+ }
+
protected void updateActivity() {
_lastActivity = _context.clock().now();
if (_isReduced) {
diff --git a/core/java/src/net/i2p/client/I2PSimpleSession.java b/core/java/src/net/i2p/client/I2PSimpleSession.java
index ae588e05f1..b417bd7f7a 100644
--- a/core/java/src/net/i2p/client/I2PSimpleSession.java
+++ b/core/java/src/net/i2p/client/I2PSimpleSession.java
@@ -130,7 +130,7 @@ class I2PSimpleSession extends I2PSessionImpl2 {
return null;
_bwReceivedLock = new Object();
sendMessage(new GetBandwidthLimitsMessage());
- for (int i = 0; i < 5 && !_destReceived; i++) {
+ for (int i = 0; i < 5 && !_bwReceived; i++) {
try {
synchronized (_bwReceivedLock) {
_bwReceivedLock.wait(1000);
diff --git a/router/java/src/net/i2p/router/client/ClientMessageEventListener.java b/router/java/src/net/i2p/router/client/ClientMessageEventListener.java
index cf49ebcd48..3b4b1a6bed 100644
--- a/router/java/src/net/i2p/router/client/ClientMessageEventListener.java
+++ b/router/java/src/net/i2p/router/client/ClientMessageEventListener.java
@@ -280,15 +280,15 @@ class ClientMessageEventListener implements I2CPMessageReader.I2CPMessageEventLi
}
/**
- * Divide router limit by 2 for overhead.
+ * Divide router limit by 1.75 for overhead.
* This could someday give a different answer to each client.
* But it's not enforced anywhere.
*/
private void handleGetBWLimits(I2CPMessageReader reader, GetBandwidthLimitsMessage message) {
if (_log.shouldLog(Log.INFO))
_log.info("Got BW Limits request");
- int in = _context.bandwidthLimiter().getInboundKBytesPerSecond() / 2;
- int out = _context.bandwidthLimiter().getOutboundKBytesPerSecond() / 2;
+ int in = _context.bandwidthLimiter().getInboundKBytesPerSecond() * 4 / 7;
+ int out = _context.bandwidthLimiter().getOutboundKBytesPerSecond() * 4 / 7;
BandwidthLimitsMessage msg = new BandwidthLimitsMessage(in, out);
try {
_runner.doSend(msg);
From 29df534161b1f914e9abcf7f6012232282314835 Mon Sep 17 00:00:00 2001
From: zzz
Date: Thu, 26 Mar 2009 00:02:29 +0000
Subject: [PATCH 062/688] update license splash text
---
installer/resources/readme.license.txt | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/installer/resources/readme.license.txt b/installer/resources/readme.license.txt
index d707e557c2..9e40f595cf 100644
--- a/installer/resources/readme.license.txt
+++ b/installer/resources/readme.license.txt
@@ -16,12 +16,13 @@ following non-public domain code:
* Bouncycastle's hash routines (MIT license)
* Cryptix's AES routines (Cryptix license)
* Adam Buckley's SNTP routines (BSD)
+* FSF's PRNG and GMP (LGPL)
Also included in this distribution are a bunch
of third party client applications, all with
their own dependencies. Please see our license
policy page for details:
- http://www.i2p.net/licenses
+ http://www.i2p2.de/licenses
One of the bundled client apps (routerconsole)
requires us to say:
@@ -29,8 +30,11 @@ requires us to say:
the Apache Software Foundation
(http://www.apache.org/)
-Another (I2PTunnel) is GPL licensed.
+I2PTunnel, I2PSnark, SusiDNS, and SusiMail
+are GPL licensed.
+
+For more information see LICENSE.txt
+in the install directory.
For source, please see:
- http://www.i2p.net/download
-or http://www.i2p.net/cvs
\ No newline at end of file
+ http://www.i2p2.de/monotone
From 6a6cd14398d790d32ad8b56c53f2495c38b298f1 Mon Sep 17 00:00:00 2001
From: zzz
Date: Thu, 26 Mar 2009 18:28:27 +0000
Subject: [PATCH 063/688] checklist update
---
checklist.txt | 28 ++++++++++++++--------------
1 file changed, 14 insertions(+), 14 deletions(-)
diff --git a/checklist.txt b/checklist.txt
index b649bef590..fcbe650284 100644
--- a/checklist.txt
+++ b/checklist.txt
@@ -15,45 +15,45 @@ Change revision in:
core/java/src/net/i2p/CoreVersion.java
Review the complete diff from the last release:
- mtn diff -r t:i2p-0.6.(xx-1) > out.diff
+ mtn diff -r t:i2p-0.7.(xx-1) > out.diff
vi out.diff
Build and tag:
ant pkg
mtn ci
- mtn tag h: i2p-0.6.xx
+ mtn tag h: i2p-0.7.xx
Sync with mtn.i2p2.i2p
Create a signed update file with:
export I2P=~/i2p
- java -cp $I2P/lib/i2p.jar net.i2p.crypto.TrustedUpdate sign i2pupdate.zip i2pupdate.sud /path/to/private.key 0.6.xx
+ java -cp $I2P/lib/i2p.jar net.i2p.crypto.TrustedUpdate sign i2pupdate.zip i2pupdate.sud /path/to/private.key 0.7.xx
Verify signed update file with:
java -cp $I2P/lib/i2p.jar net.i2p.crypto.TrustedUpdate showversion i2pupdate.sud
java -cp $I2P/lib/i2p.jar net.i2p.crypto.TrustedUpdate verifysig i2pupdate.sud
Make the source tarball:
- Start with a clean checkout mtn -d i2p.mtn co --branch=i2p.i2p i2p-0.6.xx
+ Start with a clean checkout mtn -d i2p.mtn co --branch=i2p.i2p i2p-0.7.xx
Double-check trust list
- tar cjf i2psource-0.6.xx.tar.bz2 --exclude i2p-0.6.xx/_MTN i2p-0.6.xx
- mv i2p-0.6.xx.tar.bz2 i2p.i2p
+ tar cjf i2psource-0.7.xx.tar.bz2 --exclude i2p-0.7.xx/_MTN i2p-0.7.xx
+ mv i2p-0.7.xx.tar.bz2 i2p.i2p
Until the build script gets this ability, you need to rename some files:
- mv i2pinstall.exe i2pinstall-0.6.xx.exe
- mv i2p.tar.bz2 i2pheadless-0.6.xx.tar.bz2
- mv i2pupdate.zip i2pupdate-0.6.xx.zip
+ mv i2pinstall.exe i2pinstall-0.7.xx.exe
+ mv i2p.tar.bz2 i2pheadless-0.7.xx.tar.bz2
+ mv i2pupdate.zip i2pupdate-0.7.xx.zip
you probably don't need to rename i2pupdate.sud
Generate hashes:
- sha1sum i2p*0.6.xx.*
+ sha1sum i2p*0.7.xx.*
sha1sum i2pupdate.sud
now GPG-sign an announcement with the hashes
Generate PGP signatures:
- gpg -b i2pinstall-0.6.xx.exe
- gpg -b i2pheadless-0.6.xx.tar.bz2
- gpg -b i2psource-0.6.xx.tar.bz2
- gpg -b i2pupdate-0.6.xx.zip
+ gpg -b i2pinstall-0.7.xx.exe
+ gpg -b i2pheadless-0.7.xx.tar.bz2
+ gpg -b i2psource-0.7.xx.tar.bz2
+ gpg -b i2pupdate-0.7.xx.zip
gpg -b i2pupdate.sud
Distribute files to download locations and to www.i2p2.i2p
From 0343e8ffcd7ba0465aabdd3e1ca20472ac3d7676 Mon Sep 17 00:00:00 2001
From: zzz
Date: Thu, 26 Mar 2009 18:51:43 +0000
Subject: [PATCH 064/688] readme_fr - thanks Narya and Mathiasdm
---
build.xml | 3 ++-
readme.html | 2 +-
readme_de.html | 2 +-
readme_fr.html | 37 +++++++++++++++++++++++++++++++++++++
readme_nl.html | 2 +-
readme_sv.html | 4 ++--
6 files changed, 44 insertions(+), 6 deletions(-)
create mode 100644 readme_fr.html
diff --git a/build.xml b/build.xml
index a9f58ef202..ef84b2aab3 100644
--- a/build.xml
+++ b/build.xml
@@ -276,6 +276,7 @@
+
-
+
diff --git a/readme.html b/readme.html
index 9ba805a721..0e4891b5d8 100644
--- a/readme.html
+++ b/readme.html
@@ -1,4 +1,4 @@
-
If you've just started I2P, the Active: numbers on the left should start to
grow over the next few minutes and you'll see a "shared clients" local destination listed
on the left (if not, see below). Once those show up,
diff --git a/readme_de.html b/readme_de.html
index a6d233d6a1..1534585dab 100644
--- a/readme_de.html
+++ b/readme_de.html
@@ -1,4 +1,4 @@
-
Wenn Du gerade I2P gestartet hast, sollten die "Active:" Zahlen links in den nächsten paar Minuten anwachsen und Du siehst dann dort ein "shared clients" lokales Ziel gelistet (falls nicht, siehe Unten). Sobald das erscheint, kannst Du:
"Eepsites" besuchen - In I2P sind anonym gehostete Websites -
diff --git a/readme_fr.html b/readme_fr.html
new file mode 100644
index 0000000000..5e619cff2b
--- /dev/null
+++ b/readme_fr.html
@@ -0,0 +1,37 @@
+
Si vous venez juste de lancer I2P, les chiffres sur la gauche à coté de Active devraient commencer à augmenter dans les prochaines minutes et vous verrez un "Shared client" en destination locale listés sur la gauche (si non, voir plus bas). Une fois qu'ils apparaissent, vous pouvez:
+
+
parcourir les "eepsites" - sur I2P il y a des sites web anonymes hébergés - dites à votre navigateur d'utiliser le HTTP proxy a l'adresse localhost port 4444, ensuite vous pouvez naviguer sur les eepsites.
+
+ Il y a bien plus d'eepsites - suivez juste les liens au départ de ceux sur lesquels vous êtes, mettez-les dans vos favoris et visitez-les souvent!
+
Parcourez le web - Il y a pour l'instant un outproxy HTTP sur I2P attaché à votre propre proxy HTTP sur le port 4444 - vous devez simplement configurer le proxy de votre navigateur pour l'utiliser (comme expliqué ci-dessus) et aller sur n'importe quel URL normale - vos requêtes seront relayées par le réseau i2p.
+
Transfer de fichiers - Il y a un port intégré de Snark le client BitTorrent.
+
Utiliser le service de mail anonyme - Postman a créé un sytème de mails compatible avec un client de messagerie normal (POP3 / SMTP) qui permet d'envoyer des emails autant au sein d'i2p que vers et à partir de l'internet normal! Créez-vous un compte à hq.postman.i2p.
+ Nous fournissons dans la version de base de i2p susimail,
+ un client web pop3/smtp orienté sur l'anonymat qui est configuré pour accéder aux services email de postman.
+
Chatter de manière anonyme - Activez votre client IRC et connectez-le sur le serveur localhost port 6668. Ceci pointe vers l'un des deux serveur IRC anonyme, mais ni vous ni eux ne savent qui est l'autre
+
Créez-vous un blog anonyme - Renseignez-vous chez Syndie
+
Et bien d'autres
+
+
+
Vous voulez votre propre eepsite?
+
+
Nous fournissons de base quelques logiciels pour vous permettre de créer votre propre eepsite - une instance
+Jetty, qui écoute sur
+http://localhost:7658/. Placer simplement vos fichiers dans le répertoire eepsite/docroot/ (ou placez n'importe quel fichier JSP/Servlet standard .war) dans eepsite/webapps, ou script CGI standard dans eepsite/cgi-bin) et ils apparaitront. Après avoir démarré un tunnel pour votre eepsite (le tunnel doit pointer sur l'adresse locale du eepsite), votre eepsite sera visible pour les autes. Des instructions plus détaillées pour créer un eepsite se trouvent sur Votre eepsite temporaire.
+
Soyez patient - i2p peut s'avérer lent à démarrer la première fois car il recherche des pairs. Si, après 30 minutes, votre Actives: connecté/récent compte moins de 10 pairs connectés, vous devez ouvrir le port 8887 sur votre pare-feu pour avoir une meilleure connection. Si vous ne pouvez accéder à aucun eepsite (même www.i2p2.i2p), soyez sûr que votre navigateur utilise bien le proxy localhost sur le port 4444. Vous pouvez aussi faire part de votre démarche sur le site web I2P, poster des message sur le forum de discussion, ou passer par #i2p ou #i2p-chat sur IRC sur le serveur irc.freenode.net, irc.postman.i2p ou irc.freshcoffee.i2p (ils sont liés).
+
+
Comme vous pouvez le remarquer, il suffit d'éditer la page "docs/readme.html" pour changer la page d'acceuil
Als je net I2P opgestart hebt, zullen de 'Active:' (Actieve) getallen aan de linkerkant in de komende minuten stijgen, en je zal een "Shared clients" (Gedeelde clients) lokale bestemming zien staan aan de linkerkant (indien niet, zie hieronder). Eenmaal je deze bestemming ziet, kan je:
surfen naar "eepsites" - op I2P zijn er anonieme websites - stel je browser in om de HTTP proxy op localhost, poort 4444 te gebruiken, en surf vervolgens naar een eepsite -
diff --git a/readme_sv.html b/readme_sv.html
index e368fbc532..b1f59fa04d 100644
--- a/readme_sv.html
+++ b/readme_sv.html
@@ -1,5 +1,5 @@
Om du just har startat I2P kommer de "Aktiva: #/#" börja öka inom
några få minuter och du kommer se en destination kallad "delade
@@ -98,4 +98,4 @@ href="irc://irc.freenode.net/#i2p">irc.freenode.net, irc.postman.i2p
eller irc.freshcoffee.i2p (de är alla sammankopplade).
Du kan förändra denhär sidan genom att ändra i filen
-"docs/readme_sv.html"
\ No newline at end of file
+"docs/readme_sv.html"
From fe0d0d6737a8a5f3ae8342a1cac73ec9122b34cf Mon Sep 17 00:00:00 2001
From: zzz
Date: Fri, 27 Mar 2009 18:09:46 +0000
Subject: [PATCH 065/688] -11, catch rare AIOOB
---
history.txt | 5 +++++
router/java/src/net/i2p/data/i2np/TunnelGatewayMessage.java | 5 +++++
router/java/src/net/i2p/router/RouterVersion.java | 2 +-
3 files changed, 11 insertions(+), 1 deletion(-)
diff --git a/history.txt b/history.txt
index d3fcf2f4ca..1495d99de2 100644
--- a/history.txt
+++ b/history.txt
@@ -1,3 +1,8 @@
+2009-03-27 zzz
+ * Add readme_fr.html
+ * License splash update
+ * Catch rare TunnelGatewayMessage AIOOB, root cause unknown
+
2009-03-24 zzz
* I2PTunnel:
- Add some warnings about new features
diff --git a/router/java/src/net/i2p/data/i2np/TunnelGatewayMessage.java b/router/java/src/net/i2p/data/i2np/TunnelGatewayMessage.java
index f611c32138..8fc7c9fd9e 100644
--- a/router/java/src/net/i2p/data/i2np/TunnelGatewayMessage.java
+++ b/router/java/src/net/i2p/data/i2np/TunnelGatewayMessage.java
@@ -75,6 +75,11 @@ public class TunnelGatewayMessage extends I2NPMessageImpl {
}
DataHelper.toLong(out, curIndex, 2, _msgData.length);
curIndex += 2;
+ // where is this coming from?
+ if (curIndex + _msgData.length > out.length) {
+ _log.log(Log.ERROR, "output buffer too small idx: " + curIndex + " len: " + _msgData.length + " outlen: " + out.length);
+ throw new I2NPMessageException("Too much data to write out (id=" + _tunnelId + " data=" + _msg + ")");
+ }
System.arraycopy(_msgData, 0, out, curIndex, _msgData.length);
curIndex += _msgData.length;
return curIndex;
diff --git a/router/java/src/net/i2p/router/RouterVersion.java b/router/java/src/net/i2p/router/RouterVersion.java
index c1d6bdf7c6..510adb6dea 100644
--- a/router/java/src/net/i2p/router/RouterVersion.java
+++ b/router/java/src/net/i2p/router/RouterVersion.java
@@ -17,7 +17,7 @@ import net.i2p.CoreVersion;
public class RouterVersion {
public final static String ID = "$Revision: 1.548 $ $Date: 2008-06-07 23:00:00 $";
public final static String VERSION = CoreVersion.VERSION;
- public final static long BUILD = 10;
+ public final static long BUILD = 11;
public static void main(String args[]) {
System.out.println("I2P Router version: " + VERSION + "-" + BUILD);
System.out.println("Router ID: " + RouterVersion.ID);
From 4a9543be78e3ada39c9572680068133096b9f4e5 Mon Sep 17 00:00:00 2001
From: complication
Date: Sun, 29 Mar 2009 19:47:46 +0000
Subject: [PATCH 066/688] * Update versions, package release
---
core/java/src/net/i2p/CoreVersion.java | 2 +-
history.txt | 5 +++
initialNews.xml | 4 +-
installer/install.xml | 2 +-
news.xml | 42 +++++++++----------
.../src/net/i2p/router/RouterVersion.java | 2 +-
6 files changed, 29 insertions(+), 28 deletions(-)
diff --git a/core/java/src/net/i2p/CoreVersion.java b/core/java/src/net/i2p/CoreVersion.java
index c24542b009..6c924fe109 100644
--- a/core/java/src/net/i2p/CoreVersion.java
+++ b/core/java/src/net/i2p/CoreVersion.java
@@ -15,7 +15,7 @@ package net.i2p;
*/
public class CoreVersion {
public final static String ID = "$Revision: 1.72 $ $Date: 2008-08-24 12:00:00 $";
- public final static String VERSION = "0.7";
+ public final static String VERSION = "0.7.1";
public static void main(String args[]) {
System.out.println("I2P Core version: " + VERSION);
diff --git a/history.txt b/history.txt
index 1495d99de2..e76d410559 100644
--- a/history.txt
+++ b/history.txt
@@ -1,3 +1,8 @@
+* 2009-03-29 0.7.1 released
+
+2009-03-29 Complication
+ * Update versions, package release
+
2009-03-27 zzz
* Add readme_fr.html
* License splash update
diff --git a/initialNews.xml b/initialNews.xml
index 6a9c4b4ca2..0306dcd7b2 100644
--- a/initialNews.xml
+++ b/initialNews.xml
@@ -1,5 +1,5 @@
-
-
+
-The 0.7 release adds stability and flexibility to I2PSnark,
-which can hopefully be used to distribute I2P updates in future.
+The 0.7.1 release optimizes I2P towards better performance
+and introduces new features.
-The I2P router gets fixes and optimizations to various
-transport-level and streaming issues, network exploration,
-NetDB performance and the UDP introducer system.
-Among other features, the new release offers
-better connection limiting, higher tolerance to "out of memory" exceptions
-in helper applications, and an experimental new address system
-using Base32 hashes of destination keys (".b32.i2p" URLs).
+Multiple bugs are fixed, replacements to the SimpleTimer class
+should waste less time on object locking. Some old components
+are dropped and several classes refactored to avoid repeating code.
-Both the BOB and SAM protocols are improved upon,
-more old components dropped, Router Console features added
-and a possible latency measurement attack mitigated.
-From this release onwards, block lists for misbehaving peers
-are activated by default.
+Support for encrypted LeaseSets (for creation of links over I2P
+which an adversary cannot obstruct by attacking its gateways)
+becomes more complete. New tunnel types like IRC server tunnels
+and new options like delayed start and idling of tunnels
+also gain support, along with improved usability of the I2P
+Socks proxy mechanism.
-It seems worthwhile to remind that already since
-the last release, I2P requires Java 1.5 or higher.
-If you are uncertain about your Java version, you can verify
-by opening a terminal window or command prompt,
-and entering the command "java -version".
-If you have an older Java installed, please update it first!
+Work continues on streamlining and expanding the Router Console,
+on the BOB protocol, on I2P ports for Debian and Slackware Linux,
+on the I2PSnark client, on TCP connection properties
+and multiple other fronts. Updating is highly recommended.
+
diff --git a/router/java/src/net/i2p/router/RouterVersion.java b/router/java/src/net/i2p/router/RouterVersion.java
index 510adb6dea..450adcf289 100644
--- a/router/java/src/net/i2p/router/RouterVersion.java
+++ b/router/java/src/net/i2p/router/RouterVersion.java
@@ -17,7 +17,7 @@ import net.i2p.CoreVersion;
public class RouterVersion {
public final static String ID = "$Revision: 1.548 $ $Date: 2008-06-07 23:00:00 $";
public final static String VERSION = CoreVersion.VERSION;
- public final static long BUILD = 11;
+ public final static long BUILD = 0;
public static void main(String args[]) {
System.out.println("I2P Router version: " + VERSION + "-" + BUILD);
System.out.println("Router ID: " + RouterVersion.ID);
From 0c98d1843acf6d458bd69adfd59f34652dba39f7 Mon Sep 17 00:00:00 2001
From: sponge
Date: Mon, 30 Mar 2009 05:31:40 +0000
Subject: [PATCH 067/688] Sponge fixes and additions patch: * 3 New jbigi
build scripts and old ones fixed to work properly. * Some trivial BOB
work.
---
apps/BOB/bob.config | 2 +-
apps/BOB/nbproject/build-impl.xml | 2 +-
apps/BOB/nbproject/genfiles.properties | 4 +-
apps/BOB/nbproject/project.properties | 33 +++---
apps/BOB/src/net/i2p/BOB/TCPio.java | 3 +
core/c/jbigi/build-all.sh | 5 +-
core/c/jbigi/build.sh | 2 +-
core/c/jbigi/build_jbigi.sh | 6 +-
core/c/jbigi/mbuild-all.sh | 140 +++++++++++++++++++++++++
core/c/jbigi/mbuild_jbigi.sh | 47 +++++++++
core/c/mbuild.sh | 28 +++++
11 files changed, 245 insertions(+), 27 deletions(-)
create mode 100755 core/c/jbigi/mbuild-all.sh
create mode 100755 core/c/jbigi/mbuild_jbigi.sh
create mode 100755 core/c/mbuild.sh
diff --git a/apps/BOB/bob.config b/apps/BOB/bob.config
index f9c28d3821..810d65b295 100644
--- a/apps/BOB/bob.config
+++ b/apps/BOB/bob.config
@@ -7,7 +7,7 @@ i2cp.tcp.port=7654
BOB.host=localhost
inbound.lengthVariance=0
i2cp.messageReliability=BestEffort
-BOB.port=45067
+BOB.port=45678
outbound.length=1
inbound.length=1
outbound.lengthVariance=0
diff --git a/apps/BOB/nbproject/build-impl.xml b/apps/BOB/nbproject/build-impl.xml
index 9feea8e039..d8ed4de114 100644
--- a/apps/BOB/nbproject/build-impl.xml
+++ b/apps/BOB/nbproject/build-impl.xml
@@ -152,7 +152,7 @@ is divided into following sections:
-
+
diff --git a/apps/BOB/nbproject/genfiles.properties b/apps/BOB/nbproject/genfiles.properties
index dfc3734b8a..ca344b0d35 100644
--- a/apps/BOB/nbproject/genfiles.properties
+++ b/apps/BOB/nbproject/genfiles.properties
@@ -4,5 +4,5 @@ build.xml.stylesheet.CRC32=958a1d3e
# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml.
# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you.
nbproject/build-impl.xml.data.CRC32=209349b6
-nbproject/build-impl.xml.script.CRC32=75fac64c
-nbproject/build-impl.xml.stylesheet.CRC32=e55b27f5
+nbproject/build-impl.xml.script.CRC32=c51e188e
+nbproject/build-impl.xml.stylesheet.CRC32=65b8de21
diff --git a/apps/BOB/nbproject/project.properties b/apps/BOB/nbproject/project.properties
index 76e318ff0a..7a94ff6ddd 100644
--- a/apps/BOB/nbproject/project.properties
+++ b/apps/BOB/nbproject/project.properties
@@ -24,18 +24,22 @@ dist.dir=dist
dist.jar=${dist.dir}/BOB.jar
dist.javadoc.dir=${dist.dir}/javadoc
excludes=
+file.reference.build-javadoc=../../../i2p.i2p/build/javadoc
file.reference.core.jar=../i2p.i2p/core/dist/core.jar
file.reference.i2p.jar=../../bob/i2p/i2p.i2p/build/i2p.jar
-file.reference.i2p.jar-1=../../core/java/build/i2p.jar
+file.reference.i2p.jar-1=../../build/i2p.jar
file.reference.i2p.jar-2=../i2p.i2p/core/java/build/i2p.jar
-file.reference.i2ptunnel.jar=../i2ptunnel/java/build/i2ptunnel.jar
+file.reference.i2p.jar-3=../../../i2p.i2p/build/i2p.jar
+file.reference.i2ptunnel.jar=../../../i2p.i2p/build/i2ptunnel.jar
file.reference.java-src=../i2p.i2p/core/java/src/
file.reference.jbigi.jar=../../bob/i2p/i2p.i2p/build/jbigi.jar
file.reference.mstreaming.jar=../../bob/i2p/i2p.i2p/build/mstreaming.jar
-file.reference.mstreaming.jar-1=../ministreaming/java/build/mstreaming.jar
+file.reference.mstreaming.jar-1=../../build/mstreaming.jar
+file.reference.mstreaming.jar-2=../../../i2p.i2p/build/mstreaming.jar
file.reference.NetBeansProjects-i2p.i2p=../i2p.i2p/
+file.reference.router.jar=../../build/router.jar
file.reference.streaming.jar=../../bob/i2p/i2p.i2p/build/streaming.jar
-file.reference.streaming.jar-1=../streaming/java/build/streaming.jar
+file.reference.streaming.jar-1=../../../i2p.i2p/build/streaming.jar
file.reference.wrapper-freebsd=../../installer/lib/wrapper/freebsd/
file.reference.wrapper-linux=../../installer/lib/wrapper/linux/
file.reference.wrapper-linux64=../../installer/lib/wrapper/linux64/
@@ -43,24 +47,17 @@ file.reference.wrapper-macosx=../../installer/lib/wrapper/macosx/
file.reference.wrapper-solaris=../../installer/lib/wrapper/solaris/
file.reference.wrapper-win32=../../installer/lib/wrapper/win32/
file.reference.wrapper.jar=../../installer/lib/wrapper/linux/wrapper.jar
-file.reference.wrapper.jar-1=../../installer/lib/wrapper/freebsd/wrapper.jar
-file.reference.wrapper.jar-2=../../installer/lib/wrapper/linux64/wrapper.jar
-file.reference.wrapper.jar-3=../../installer/lib/wrapper/macosx/wrapper.jar
-file.reference.wrapper.jar-4=../../installer/lib/wrapper/solaris/wrapper.jar
-file.reference.wrapper.jar-5=../../installer/lib/wrapper/win32/wrapper.jar
includes=**
jar.compress=false
javac.classpath=\
- ${file.reference.i2p.jar-1}:\
- ${file.reference.i2ptunnel.jar}:\
- ${file.reference.mstreaming.jar-1}:\
- ${file.reference.streaming.jar-1}:\
- ${file.reference.wrapper.jar-1}:\
${file.reference.wrapper.jar}:\
- ${file.reference.wrapper.jar-2}:\
- ${file.reference.wrapper.jar-3}:\
- ${file.reference.wrapper.jar-4}:\
- ${file.reference.wrapper.jar-5}
+ ${file.reference.streaming.jar-1}:\
+ ${file.reference.i2ptunnel.jar}:\
+ ${file.reference.i2p.jar-1}:\
+ ${file.reference.router.jar}:\
+ ${file.reference.mstreaming.jar-1}:\
+ ${file.reference.mstreaming.jar-2}:\
+ ${file.reference.i2p.jar-3}
# Space-separated list of extra javac options
javac.compilerargs=
javac.deprecation=false
diff --git a/apps/BOB/src/net/i2p/BOB/TCPio.java b/apps/BOB/src/net/i2p/BOB/TCPio.java
index 41bb7cbe49..c9f4ab64cd 100644
--- a/apps/BOB/src/net/i2p/BOB/TCPio.java
+++ b/apps/BOB/src/net/i2p/BOB/TCPio.java
@@ -76,6 +76,9 @@ public class TCPio implements Runnable {
*
* --Sponge
*
+ * Tested with 128 bytes, and there was no performance gain.
+ *
+ * --Sponge
*/
int b;
diff --git a/core/c/jbigi/build-all.sh b/core/c/jbigi/build-all.sh
index 65456ee50b..861a1e0a4e 100755
--- a/core/c/jbigi/build-all.sh
+++ b/core/c/jbigi/build-all.sh
@@ -12,7 +12,7 @@ FreeBSD*)
exit;;
esac
-VER=4.2.2
+VER=4.2.4
echo "Extracting GMP Version $VER ..."
tar -xjf gmp-$VER.tar.bz2
echo "Building..."
@@ -21,7 +21,8 @@ mkdir lib
mkdir lib/net
mkdir lib/net/i2p
mkdir lib/net/i2p/util
-for x in none pentium pentiummmx pentium2 pentium3 pentium4 k6 k62 k63 athlon
+
+for x in none pentium pentiummmx pentium2 pentium3 pentium4 k6 k62 k63 athlon geode pentiumm core2
do
mkdir bin/$x
cd bin/$x
diff --git a/core/c/jbigi/build.sh b/core/c/jbigi/build.sh
index 39969b13c9..7ef9000704 100755
--- a/core/c/jbigi/build.sh
+++ b/core/c/jbigi/build.sh
@@ -15,7 +15,7 @@
mkdir -p lib/
mkdir -p bin/local
-VER=4.2.2
+VER=4.2.4
if [ "$1" != "dynamic" -a ! -d gmp-$VER ]
then
diff --git a/core/c/jbigi/build_jbigi.sh b/core/c/jbigi/build_jbigi.sh
index 859eda329a..8ff3219b8a 100755
--- a/core/c/jbigi/build_jbigi.sh
+++ b/core/c/jbigi/build_jbigi.sh
@@ -1,6 +1,7 @@
#!/bin/sh
# When executed in Mingw: Produces an jbigi.dll
-# When executed in Linux: Produces an libjbigi.so
+# When executed in Linux/FreeBSD: Produces an libjbigi.so
+# Darwin produces libjbigi.jnilib, right?
CC="gcc"
@@ -32,7 +33,8 @@ esac
#To link dynamically to GMP (use libgmp.so or gmp.lib), uncomment the first line below
#To link statically to GMP, uncomment the second line below
-if test $1 = "dynamic"
+# Bug!!! Quote *BOTH* or neither! --Sponge
+if test "$1" = "dynamic"
then
echo "Building jbigi lib that is dynamically linked to GMP"
LIBPATH="-L.libs"
diff --git a/core/c/jbigi/mbuild-all.sh b/core/c/jbigi/mbuild-all.sh
new file mode 100755
index 0000000000..a97139dfca
--- /dev/null
+++ b/core/c/jbigi/mbuild-all.sh
@@ -0,0 +1,140 @@
+#/bin/bash
+
+# TO-DO: Darwin.
+
+# Note: You will have to add the CPU ID for the platform in the CPU ID code
+# for a new CPU. Just adding them here won't let I2P use the code!
+
+#
+# If you know of other platforms i2p on linux works on,
+# please add them here.
+# Do NOT add any X86 platforms, do that below in the x86 platform list.
+#
+MISC_LINUX_PLATFORMS="hppa2.0 alphaev56 armv5tel mips64el itanium itanium2 ultrasparc2 ultrasparc2i alphaev6 powerpc970 powerpc7455 powerpc7447 atom"
+
+#
+# If you know of other platforms i2p on FREEBSD works on,
+# please add them here.
+# Do NOT add any X86 platforms, do that below in the x86 platform list.
+#
+MISC_FREEBSD_PLATFORMS="atom alphaev56 ultrasparc2i"
+
+#
+# MINGW/Windows??
+#
+MISC_MINGW_PLATFORMS=""
+
+#
+# Are there any other X86 platforms that work on i2p? Add them here.
+#
+# Oddly athlon64 builds.... I wonder what others can :-)
+#
+X86_PLATFORMS="pentium pentiummmx pentium2 pentium3 pentium4 k6 k62 k63 athlon pentiumm core2 athlon64 geode"
+
+
+#
+# You should not need to edit anything below this comment.
+#
+
+MINGW_PLATFORMS="${X86_PLATFORMS} ${MISC_MINGW_PLATFORMS}"
+LINUX_PLATFORMS="${X86_PLATFORMS} ${MISC_LINUX_PLATFORMS}"
+FREEBSD_PLATFORMS="${X86_PLATFORMS} ${MISC_FREEBSD_PLATFORMS}"
+
+VER=$(echo gmp-*.tar.bz2 | sed -re "s/(.*-)(.*)(.*.tar.bz2)$/\2/" | tail --lines=1)
+if [ "$VER" == "" ] ; then
+ echo "ERROR! Can't find gmp source tarball."
+ exit 1
+fi
+
+
+case `uname -sr` in
+MINGW*)
+ PLATFORM_LIST="${MINGW_PLATFORMS}"
+ NAME="jbigi"
+ TYPE="dll"
+ TARGET="-windows-"
+ echo "Building windows .dlls for all architectures";;
+Linux*)
+ PLATFORM_LIST="${LINUX_PLATFORMS}"
+ NAME="libjbigi"
+ TYPE="so"
+ TARGET="-linux-"
+ echo "Building linux .sos for all architectures";;
+FreeBSD*)
+ PLATFORM_LIST="${FREEBSD_PLATFORMS}"
+ NAME="libjbigi"
+ TYPE="so"
+ TARGET="-freebsd-"
+ echo "Building freebsd .sos for all architectures";;
+*)
+ echo "Unsupported build environment"
+ exit;;
+esac
+
+function make_static {
+ echo "Attempting .${4} creation for ${3}${5}${2}"
+ ../../mbuild_jbigi.sh static || return 1
+ cp ${3}.${4} ../../lib/net/i2p/util/${3}${5}${2}.${4}
+ return 0
+}
+
+function make_file {
+ # Nonfatal bail out on Failed build.
+ echo "Attempting build for ${3}${5}${2}"
+ make && return 0
+ cd ..
+ rm -R "$2"
+ echo -e "\n\nFAILED! ${3}${5}${2} not made.\a"
+ sleep 10
+ return 1
+}
+
+function configure_file {
+ echo -e "\n\n\nAttempting configure for ${3}${5}${2}\n\n\n"
+ sleep 10
+ # Nonfatal bail out on unsupported platform.
+ ../../gmp-${1}/configure --build=${2} && return 0
+ cd ..
+ rm -R "$2"
+ echo -e "\n\nSorry, ${3}${5}${2} is not supported on your build environment.\a"
+ sleep 10
+ return 1
+}
+
+function build_file {
+ configure_file "$1" "$2" "$3" "$4" "$5" && make_file "$1" "$2" "$3" "$4" "$5" && make_static "$1" "$2" "$3" "$4" "$5" && return 0
+ echo -e "\n\n\nError building static!\n\n\a"
+ sleep 10
+ return 1
+}
+
+echo "Extracting GMP Version $VER ..."
+tar -xf gmp-$VER.tar.bz2 || ( echo "Error in tarball file!" ; exit 1 )
+
+if [ ! -d bin ]; then
+ mkdir bin
+fi
+if [ ! -d lib/net/i2p/util ]; then
+ mkdir -p lib/net/i2p/util
+fi
+
+# Don't touch this one.
+NO_PLATFORM=none
+
+for x in $NO_PLATFORM $PLATFORM_LIST
+do
+ (
+ if [ ! -d bin/$x ]; then
+ mkdir bin/$x
+ cd bin/$x
+ else
+ cd bin/$x
+ rm -Rf *
+ fi
+
+ build_file "$VER" "$x" "$NAME" "$TYPE" "$TARGET"
+ )
+done
+
+echo "Success!"
+exit 0
diff --git a/core/c/jbigi/mbuild_jbigi.sh b/core/c/jbigi/mbuild_jbigi.sh
new file mode 100755
index 0000000000..1e262a6031
--- /dev/null
+++ b/core/c/jbigi/mbuild_jbigi.sh
@@ -0,0 +1,47 @@
+#!/bin/bash
+# When executed in Mingw: Produces an jbigi.dll
+# When executed in Linux/FreeBSD: Produces an libjbigi.so
+# What does Darwin produce? libjbigi.jnilib?
+CC="gcc"
+
+case `uname -sr` in
+MINGW*)
+ JAVA_HOME="c:/software/j2sdk1.4.2_05"
+ COMPILEFLAGS="-Wall"
+ INCLUDES="-I. -I../../jbigi/include -I$JAVA_HOME/include/win32/ -I$JAVA_HOME/include/"
+ LINKFLAGS="-shared -Wl,--kill-at"
+ LIBFILE="jbigi.dll";;
+CYGWIN*)
+ JAVA_HOME="c:/software/j2sdk1.4.2_05"
+ COMPILEFLAGS="-Wall -mno-cygwin"
+ INCLUDES="-I. -I../../jbigi/include -I$JAVA_HOME/include/win32/ -I$JAVA_HOME/include/"
+ LINKFLAGS="-shared -Wl,--kill-at"
+ LIBFILE="jbigi.dll";;
+Darwin*)
+ JAVA_HOME="/Library/Java/Home"
+ COMPILEFLAGS="-Wall"
+ INCLUDES="-I. -I../../jbigi/include -I$JAVA_HOME/include"
+ LINKFLAGS="-dynamiclib -framework JavaVM"
+ LIBFILE="libjbigi.jnilib";;
+*)
+ COMPILEFLAGS="-fPIC -Wall"
+ INCLUDES="-I. -I../../jbigi/include -I$JAVA_HOME/include -I$JAVA_HOME/include/linux"
+ LINKFLAGS="-shared -Wl,-soname,libjbigi.so"
+ LIBFILE="libjbigi.so";;
+esac
+
+if [ "$1" = "dynamic" ] ; then
+ echo "Building a jbigi lib that is dynamically linked to GMP"
+ LIBPATH="-L.libs"
+ INCLUDELIBS="-lgmp"
+else
+ echo "Building a jbigi lib that is statically linked to GMP"
+ STATICLIBS=".libs/libgmp.a"
+fi
+
+echo "Compiling C code..."
+rm -f jbigi.o $LIBFILE
+$CC -c $COMPILEFLAGS $INCLUDES ../../jbigi/src/jbigi.c || exit 1
+$CC $LINKFLAGS $INCLUDES $INCLUDELIBS -o $LIBFILE jbigi.o $STATICLIBS || exit 1
+
+exit 0
diff --git a/core/c/mbuild.sh b/core/c/mbuild.sh
new file mode 100755
index 0000000000..4591d5b7c8
--- /dev/null
+++ b/core/c/mbuild.sh
@@ -0,0 +1,28 @@
+#/bin/bash
+
+JBIGI=../../../installer/lib/jbigi/jbigi.jar
+
+if [ -f jbigi.jarx ] ; then
+JBIGI=../jbigi.jar
+fi
+
+(cd jcpuid ; sh build.sh ; cd ..)
+(cd jbigi ; sh mbuild-all.sh ; cd ..)
+
+mkdir t
+
+(
+ cd t
+ jar xf ../../../installer/lib/jbigi/jbigi.jar
+)
+
+cp jbigi/lib/net/i2p/util/* t/
+cp jcpuid/lib/freenet/support/CPUInformation/* t/
+
+(
+ cd t
+ jar cf ../jbigi.jar .
+)
+
+rm -R t
+echo "jbigi.jar Refreshed."
From e692e18d44339b111014493b496dc092550c2550 Mon Sep 17 00:00:00 2001
From: zzz
Date: Mon, 30 Mar 2009 16:05:48 +0000
Subject: [PATCH 068/688] Peer Selection: - Limit peers to a max % of all
tunnels with router.maxTunnelPercentage=nn, default 33 - Add
chart to tunnels.jsp to see results
---
.../i2p/router/DummyTunnelManagerFacade.java | 2 +
.../net/i2p/router/TunnelManagerFacade.java | 4 +
.../tunnel/pool/TunnelPeerSelector.java | 1 +
.../i2p/router/tunnel/pool/TunnelPool.java | 4 +-
.../router/tunnel/pool/TunnelPoolManager.java | 133 ++++++++++++++++++
5 files changed, 142 insertions(+), 2 deletions(-)
diff --git a/router/java/src/net/i2p/router/DummyTunnelManagerFacade.java b/router/java/src/net/i2p/router/DummyTunnelManagerFacade.java
index f7f204857a..aec0390fd3 100644
--- a/router/java/src/net/i2p/router/DummyTunnelManagerFacade.java
+++ b/router/java/src/net/i2p/router/DummyTunnelManagerFacade.java
@@ -10,6 +10,7 @@ package net.i2p.router;
import java.io.IOException;
import java.io.Writer;
+import java.util.Set;
import net.i2p.data.Destination;
import net.i2p.data.Hash;
@@ -44,6 +45,7 @@ class DummyTunnelManagerFacade implements TunnelManagerFacade {
public void setInboundSettings(Hash client, TunnelPoolSettings settings) {}
public void setOutboundSettings(Hash client, TunnelPoolSettings settings) {}
public int getInboundBuildQueueSize() { return 0; }
+ public Set selectPeersInTooManyTunnels() { return null; }
public void renderStatusHTML(Writer out) throws IOException {}
public void restart() {}
diff --git a/router/java/src/net/i2p/router/TunnelManagerFacade.java b/router/java/src/net/i2p/router/TunnelManagerFacade.java
index a6c1c96146..da0482e6ff 100644
--- a/router/java/src/net/i2p/router/TunnelManagerFacade.java
+++ b/router/java/src/net/i2p/router/TunnelManagerFacade.java
@@ -10,6 +10,7 @@ package net.i2p.router;
import java.io.IOException;
import java.io.Writer;
+import java.util.Set;
import net.i2p.data.Destination;
import net.i2p.data.Hash;
@@ -62,6 +63,9 @@ public interface TunnelManagerFacade extends Service {
/** count how many inbound tunnel requests we have received but not yet processed */
public int getInboundBuildQueueSize();
+ /** @return Set of peers that should not be allowed to be in another tunnel */
+ public Set selectPeersInTooManyTunnels();
+
/**
* the client connected (or updated their settings), so make sure we have
* the tunnels for them, and whenever necessary, ask them to authorize
diff --git a/router/java/src/net/i2p/router/tunnel/pool/TunnelPeerSelector.java b/router/java/src/net/i2p/router/tunnel/pool/TunnelPeerSelector.java
index 1e0247c022..92e4545171 100644
--- a/router/java/src/net/i2p/router/tunnel/pool/TunnelPeerSelector.java
+++ b/router/java/src/net/i2p/router/tunnel/pool/TunnelPeerSelector.java
@@ -176,6 +176,7 @@ public abstract class TunnelPeerSelector {
Set peers = new HashSet(1);
peers.addAll(ctx.profileOrganizer().selectPeersRecentlyRejecting());
+ peers.addAll(ctx.tunnelManager().selectPeersInTooManyTunnels());
// if (false && filterUnreachable(ctx, isInbound, isExploratory)) {
if (filterUnreachable(ctx, isInbound, isExploratory)) {
List caps = ctx.peerManager().getPeersByCapability(Router.CAPABILITY_UNREACHABLE);
diff --git a/router/java/src/net/i2p/router/tunnel/pool/TunnelPool.java b/router/java/src/net/i2p/router/tunnel/pool/TunnelPool.java
index 06a9b49991..699a8be9f1 100644
--- a/router/java/src/net/i2p/router/tunnel/pool/TunnelPool.java
+++ b/router/java/src/net/i2p/router/tunnel/pool/TunnelPool.java
@@ -28,7 +28,7 @@ public class TunnelPool {
private RouterContext _context;
private Log _log;
private TunnelPoolSettings _settings;
- private ArrayList _tunnels;
+ private ArrayList _tunnels;
private TunnelPeerSelector _peerSelector;
private TunnelPoolManager _manager;
private boolean _alive;
@@ -227,7 +227,7 @@ public class TunnelPool {
*
* @return list of TunnelInfo objects
*/
- public List listTunnels() {
+ public List listTunnels() {
synchronized (_tunnels) {
return new ArrayList(_tunnels);
}
diff --git a/router/java/src/net/i2p/router/tunnel/pool/TunnelPoolManager.java b/router/java/src/net/i2p/router/tunnel/pool/TunnelPoolManager.java
index 58637ce63a..acbb9345db 100644
--- a/router/java/src/net/i2p/router/tunnel/pool/TunnelPoolManager.java
+++ b/router/java/src/net/i2p/router/tunnel/pool/TunnelPoolManager.java
@@ -6,9 +6,12 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
import net.i2p.data.DataHelper;
import net.i2p.data.Destination;
@@ -506,6 +509,7 @@ public class TunnelPoolManager implements TunnelManagerFacade {
out.write("
\n");
out.write("Inactive participating tunnels: " + inactive + " \n");
out.write("Lifetime bandwidth usage: " + DataHelper.formatSize(processed*1024) + "B \n");
+ renderPeers(out);
}
class TunnelComparator implements Comparator {
@@ -579,6 +583,135 @@ public class TunnelPoolManager implements TunnelManagerFacade {
DataHelper.formatSize(processedOut*1024) + "B out ");
}
+ private void renderPeers(Writer out) throws IOException {
+ // count up the peers in the local pools
+ HashCounter lc = new HashCounter();
+ int tunnelCount = countTunnelsPerPeer(lc);
+
+ // count up the peers in the participating tunnels
+ HashCounter pc = new HashCounter();
+ int partCount = countParticipatingPerPeer(pc);
+
+ Set peers = new HashSet(lc.hashes());
+ peers.addAll(pc.hashes());
+ List peerList = new ArrayList(peers);
+ Collections.sort(peerList, new HashComparator());
+
+ out.write("
*
* name=val options are passed to the I2CP code to build a session,
* allowing the bridge to specify an alternate I2CP host and port, tunnel
* depth, etc.
- * @param args [[listenHost ]listenPort[ name=val]*]
+ * @param args [ keyfile [ listenHost ] listenPort [ name=val ]* ]
*/
public static void main(String args[]) {
String keyfile = DEFAULT_SAM_KEYFILE;
@@ -266,11 +274,11 @@ public class SAMBridge implements Runnable {
if (serverSocket == null) return;
try {
while (acceptConnections) {
- Socket s = serverSocket.accept();
+ SocketChannel s = serverSocket.accept();
if (_log.shouldLog(Log.DEBUG))
_log.debug("New connection from "
- + s.getInetAddress().toString() + ":"
- + s.getPort());
+ + s.socket().getInetAddress().toString() + ":"
+ + s.socket().getPort());
try {
SAMHandler handler = SAMHandlerFactory.createSAMHandler(s, i2cpProps);
@@ -289,7 +297,7 @@ public class SAMBridge implements Runnable {
_log.error("SAM error: " + e.getMessage(), e);
try {
String reply = "HELLO REPLY RESULT=I2P_ERROR MESSAGE=\"" + e.getMessage() + "\"\n";
- s.getOutputStream().write(reply.getBytes("ISO-8859-1"));
+ s.write(ByteBuffer.wrap(reply.getBytes("ISO-8859-1")));
} catch (IOException ioe) {
if (_log.shouldLog(Log.ERROR))
_log.error("SAM Error sending error reply", ioe);
diff --git a/apps/sam/java/src/net/i2p/sam/SAMDatagramSession.java b/apps/sam/java/src/net/i2p/sam/SAMDatagramSession.java
index a3e20f7df8..c8d31b489d 100644
--- a/apps/sam/java/src/net/i2p/sam/SAMDatagramSession.java
+++ b/apps/sam/java/src/net/i2p/sam/SAMDatagramSession.java
@@ -30,7 +30,7 @@ public class SAMDatagramSession extends SAMMessageSession {
private final static Log _log = new Log(SAMDatagramSession.class);
public static int DGRAM_SIZE_MAX = 31*1024;
- private SAMDatagramReceiver recv = null;
+ protected SAMDatagramReceiver recv = null;
private I2PDatagramMaker dgramMaker;
private I2PDatagramDissector dgramDissector = new I2PDatagramDissector();
@@ -84,9 +84,10 @@ public class SAMDatagramSession extends SAMMessageSession {
public boolean sendBytes(String dest, byte[] data) throws DataFormatException {
if (data.length > DGRAM_SIZE_MAX)
throw new DataFormatException("Datagram size exceeded (" + data.length + ")");
-
- byte[] dgram = dgramMaker.makeI2PDatagram(data);
-
+ byte[] dgram ;
+ synchronized (dgramMaker) {
+ dgram = dgramMaker.makeI2PDatagram(data);
+ }
return sendBytesThroughMessageSession(dest, dgram);
}
diff --git a/apps/sam/java/src/net/i2p/sam/SAMException.java b/apps/sam/java/src/net/i2p/sam/SAMException.java
index e51e35ea4f..ae965a4c8c 100644
--- a/apps/sam/java/src/net/i2p/sam/SAMException.java
+++ b/apps/sam/java/src/net/i2p/sam/SAMException.java
@@ -15,11 +15,13 @@ package net.i2p.sam;
*/
public class SAMException extends Exception {
+ static final long serialVersionUID = 1 ;
+
public SAMException() {
- super();
+ super();
}
public SAMException(String s) {
- super(s);
+ super(s);
}
}
diff --git a/apps/sam/java/src/net/i2p/sam/SAMHandler.java b/apps/sam/java/src/net/i2p/sam/SAMHandler.java
index 64d824a578..d53a5a6621 100644
--- a/apps/sam/java/src/net/i2p/sam/SAMHandler.java
+++ b/apps/sam/java/src/net/i2p/sam/SAMHandler.java
@@ -9,9 +9,8 @@ package net.i2p.sam;
*/
import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.net.Socket;
+import java.nio.channels.SocketChannel;
+import java.nio.ByteBuffer;
import java.util.Properties;
import net.i2p.util.I2PAppThread;
@@ -32,8 +31,7 @@ public abstract class SAMHandler implements Runnable {
protected SAMBridge bridge = null;
private Object socketWLock = new Object(); // Guards writings on socket
- private Socket socket = null;
- private OutputStream socketOS = null; // Stream associated to socket
+ protected SocketChannel socket = null;
protected int verMajor = 0;
protected int verMinor = 0;
@@ -53,10 +51,9 @@ public abstract class SAMHandler implements Runnable {
* @param i2cpProps properties to configure the I2CP connection (host, port, etc)
* @throws IOException
*/
- protected SAMHandler(Socket s,
+ protected SAMHandler(SocketChannel s,
int verMajor, int verMinor, Properties i2cpProps) throws IOException {
socket = s;
- socketOS = socket.getOutputStream();
this.verMajor = verMajor;
this.verMinor = verMinor;
@@ -86,8 +83,8 @@ public abstract class SAMHandler implements Runnable {
* @return input stream
* @throws IOException
*/
- protected final InputStream getClientSocketInputStream() throws IOException {
- return socket.getInputStream();
+ protected final SocketChannel getClientSocket() {
+ return socket ;
}
/**
@@ -98,13 +95,17 @@ public abstract class SAMHandler implements Runnable {
* @param data A byte array to be written
* @throws IOException
*/
- protected final void writeBytes(byte[] data) throws IOException {
+ protected final void writeBytes(ByteBuffer data) throws IOException {
synchronized (socketWLock) {
- socketOS.write(data);
- socketOS.flush();
+ writeBytes(data, socket);
}
}
+ static public void writeBytes(ByteBuffer data, SocketChannel out) throws IOException {
+ while (data.hasRemaining()) out.write(data);
+ out.socket().getOutputStream().flush();
+ }
+
/**
* If you're crazy enough to write to the raw socket, grab the write lock
* with getWriteLock(), synchronize against it, and write to the getOut()
@@ -112,7 +113,6 @@ public abstract class SAMHandler implements Runnable {
* @return socket Write lock object
*/
protected Object getWriteLock() { return socketWLock; }
- protected OutputStream getOut() { return socketOS; }
/**
* Write a string to the handler's socket. This method must
@@ -121,21 +121,25 @@ public abstract class SAMHandler implements Runnable {
*
* @param str A byte array to be written
*
- * @return True is the string was successfully written, false otherwise
+ * @return True if the string was successfully written, false otherwise
*/
protected final boolean writeString(String str) {
if (_log.shouldLog(Log.DEBUG))
_log.debug("Sending the client: [" + str + "]");
- try {
- writeBytes(str.getBytes("ISO-8859-1"));
+ return writeString(str, socket);
+ }
+
+ public static boolean writeString(String str, SocketChannel out)
+ {
+ try {
+ writeBytes(ByteBuffer.wrap(str.getBytes("ISO-8859-1")), out);
} catch (IOException e) {
_log.debug("Caught IOException", e);
return false;
}
-
- return true;
+ return true ;
}
-
+
/**
* Close the socket connected to the SAM client.
*
@@ -178,8 +182,8 @@ public abstract class SAMHandler implements Runnable {
return ("SAM handler (class: " + this.getClass().getName()
+ "; SAM version: " + verMajor + "." + verMinor
+ "; client: "
- + this.socket.getInetAddress().toString() + ":"
- + this.socket.getPort() + ")");
+ + this.socket.socket().getInetAddress().toString() + ":"
+ + this.socket.socket().getPort() + ")");
}
public final void run() {
diff --git a/apps/sam/java/src/net/i2p/sam/SAMHandlerFactory.java b/apps/sam/java/src/net/i2p/sam/SAMHandlerFactory.java
index 21a0e97d27..b5c3d198c3 100644
--- a/apps/sam/java/src/net/i2p/sam/SAMHandlerFactory.java
+++ b/apps/sam/java/src/net/i2p/sam/SAMHandlerFactory.java
@@ -9,9 +9,9 @@ package net.i2p.sam;
*/
import java.io.IOException;
-import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
-import java.net.Socket;
+import java.nio.channels.SocketChannel;
+import java.nio.ByteBuffer;
import java.util.Properties;
import java.util.StringTokenizer;
@@ -34,17 +34,17 @@ public class SAMHandlerFactory {
* @throws SAMException if the connection handshake (HELLO message) was malformed
* @return A SAM protocol handler, or null if the client closed before the handshake
*/
- public static SAMHandler createSAMHandler(Socket s, Properties i2cpProps) throws SAMException {
+ public static SAMHandler createSAMHandler(SocketChannel s, Properties i2cpProps) throws SAMException {
String line;
StringTokenizer tok;
try {
- line = DataHelper.readLine(s.getInputStream());
+ line = DataHelper.readLine(s.socket().getInputStream());
if (line == null) {
_log.debug("Connection closed by client");
return null;
}
- tok = new StringTokenizer(line, " ");
+ tok = new StringTokenizer(line.trim(), " ");
} catch (IOException e) {
throw new SAMException("Error reading from socket: "
+ e.getMessage());
@@ -89,9 +89,8 @@ public class SAMHandlerFactory {
// Let's answer positively
try {
- OutputStream out = s.getOutputStream();
- out.write(("HELLO REPLY RESULT=OK VERSION="
- + ver + "\n").getBytes("ISO-8859-1"));
+ s.write(ByteBuffer.wrap(("HELLO REPLY RESULT=OK VERSION="
+ + ver + "\n").getBytes("ISO-8859-1")));
} catch (UnsupportedEncodingException e) {
_log.error("Caught UnsupportedEncodingException ("
+ e.getMessage() + ")");
@@ -115,6 +114,9 @@ public class SAMHandlerFactory {
case 2:
handler = new SAMv2Handler(s, verMajor, verMinor, i2cpProps);
break;
+ case 3:
+ handler = new SAMv3Handler(s, verMajor, verMinor, i2cpProps);
+ break;
default:
_log.error("BUG! Trying to initialize the wrong SAM version!");
throw new SAMException("BUG! (in handler instantiation)");
@@ -128,6 +130,7 @@ public class SAMHandlerFactory {
/* Return the best version we can use, or null on failure */
private static String chooseBestVersion(String minVer, String maxVer) {
+
int minMajor = getMajor(minVer), minMinor = getMinor(minVer);
int maxMajor = getMajor(maxVer), maxMinor = getMinor(maxVer);
@@ -143,6 +146,8 @@ public class SAMHandlerFactory {
float fmaxVer = (float) maxMajor + (float) maxMinor / 10 ;
+ if ( ( fminVer <= 3.0 ) && ( fmaxVer >= 3.0 ) ) return "3.0" ;
+
if ( ( fminVer <= 2.0 ) && ( fmaxVer >= 2.0 ) ) return "2.0" ;
if ( ( fminVer <= 1.0 ) && ( fmaxVer >= 1.0 ) ) return "1.0" ;
diff --git a/apps/sam/java/src/net/i2p/sam/SAMInvalidDirectionException.java b/apps/sam/java/src/net/i2p/sam/SAMInvalidDirectionException.java
index b52ecda65d..cd1c6b1a57 100644
--- a/apps/sam/java/src/net/i2p/sam/SAMInvalidDirectionException.java
+++ b/apps/sam/java/src/net/i2p/sam/SAMInvalidDirectionException.java
@@ -15,7 +15,8 @@ package net.i2p.sam;
* @author human
*/
public class SAMInvalidDirectionException extends Exception {
-
+ static final long serialVersionUID = 1 ;
+
public SAMInvalidDirectionException() {
super();
}
diff --git a/apps/sam/java/src/net/i2p/sam/SAMMessageSession.java b/apps/sam/java/src/net/i2p/sam/SAMMessageSession.java
index b29b2f84c5..2c8ed2756b 100644
--- a/apps/sam/java/src/net/i2p/sam/SAMMessageSession.java
+++ b/apps/sam/java/src/net/i2p/sam/SAMMessageSession.java
@@ -109,8 +109,7 @@ public abstract class SAMMessageSession {
* @throws DataFormatException
*/
protected boolean sendBytesThroughMessageSession(String dest, byte[] data) throws DataFormatException {
- Destination d = new Destination();
- d.fromBase64(dest);
+ Destination d = SAMUtils.getDest(dest);
if (_log.shouldLog(Log.DEBUG)) {
_log.debug("Sending " + data.length + " bytes to " + dest);
diff --git a/apps/sam/java/src/net/i2p/sam/SAMRawSession.java b/apps/sam/java/src/net/i2p/sam/SAMRawSession.java
index 7f56066b1b..92bf4960dd 100644
--- a/apps/sam/java/src/net/i2p/sam/SAMRawSession.java
+++ b/apps/sam/java/src/net/i2p/sam/SAMRawSession.java
@@ -26,7 +26,7 @@ public class SAMRawSession extends SAMMessageSession {
private final static Log _log = new Log(SAMRawSession.class);
public static final int RAW_SIZE_MAX = 32*1024;
- private SAMRawReceiver recv = null;
+ protected SAMRawReceiver recv = null;
/**
* Create a new SAM RAW session.
*
diff --git a/apps/sam/java/src/net/i2p/sam/SAMStreamReceiver.java b/apps/sam/java/src/net/i2p/sam/SAMStreamReceiver.java
index 6d6d824b5f..326c81020e 100644
--- a/apps/sam/java/src/net/i2p/sam/SAMStreamReceiver.java
+++ b/apps/sam/java/src/net/i2p/sam/SAMStreamReceiver.java
@@ -9,6 +9,7 @@ package net.i2p.sam;
*/
import java.io.IOException;
+import java.nio.ByteBuffer;
import net.i2p.data.Destination;
@@ -60,7 +61,7 @@ public interface SAMStreamReceiver {
* @param len Number of bytes in data
* @throws IOException
*/
- public void receiveStreamBytes(int id, byte data[], int len) throws IOException;
+ public void receiveStreamBytes(int id, ByteBuffer data) throws IOException;
/**
* Notify that a connection has been closed
diff --git a/apps/sam/java/src/net/i2p/sam/SAMStreamSession.java b/apps/sam/java/src/net/i2p/sam/SAMStreamSession.java
index 280562e48e..aef2802bd8 100644
--- a/apps/sam/java/src/net/i2p/sam/SAMStreamSession.java
+++ b/apps/sam/java/src/net/i2p/sam/SAMStreamSession.java
@@ -13,6 +13,8 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.InterruptedIOException;
import java.io.OutputStream;
+import java.nio.ByteBuffer;
+import java.nio.channels.Channels;
import java.net.ConnectException;
import java.net.NoRouteToHostException;
import java.util.ArrayList;
@@ -51,15 +53,15 @@ public class SAMStreamSession {
protected SAMStreamReceiver recv = null;
- private SAMStreamSessionServer server = null;
+ protected SAMStreamSessionServer server = null;
protected I2PSocketManager socketMgr = null;
private Object handlersMapLock = new Object();
/** stream id (Long) to SAMStreamSessionSocketReader */
- private HashMap handlersMap = new HashMap();
+ private HashMap handlersMap = new HashMap();
/** stream id (Long) to StreamSender */
- private HashMap sendersMap = new HashMap();
+ private HashMap sendersMap = new HashMap();
private Object idLock = new Object();
private int lastNegativeId = 0;
@@ -76,6 +78,10 @@ public class SAMStreamSession {
public static String PROP_FORCE_FLUSH = "sam.forceFlush";
public static String DEFAULT_FORCE_FLUSH = "false";
+ public SAMStreamSession() {
+
+ }
+
/**
* Create a new SAM STREAM session.
*
@@ -166,7 +172,7 @@ public class SAMStreamSession {
}
}
- private class DisconnectListener implements I2PSocketManager.DisconnectListener {
+ protected class DisconnectListener implements I2PSocketManager.DisconnectListener {
public void sessionDisconnected() {
close();
}
@@ -572,19 +578,20 @@ public class SAMStreamSession {
_log.debug("run() called for socket reader " + id);
int read = -1;
- byte[] data = new byte[SOCKET_HANDLER_BUF_SIZE];
+ ByteBuffer data = ByteBuffer.allocateDirect(SOCKET_HANDLER_BUF_SIZE);
try {
InputStream in = i2pSocket.getInputStream();
while (stillRunning) {
- read = in.read(data);
+ data.clear();
+ read = Channels.newChannel(in).read(data);
if (read == -1) {
_log.debug("Handler " + id + ": connection closed");
break;
}
-
- recv.receiveStreamBytes(id, data, read);
+ data.flip();
+ recv.receiveStreamBytes(id, data);
}
} catch (IOException e) {
_log.debug("Caught IOException", e);
@@ -650,7 +657,7 @@ public class SAMStreamSession {
protected class v1StreamSender extends StreamSender
{
- private List _data;
+ private List _data;
private int _id;
private ByteCache _cache;
private OutputStream _out = null;
@@ -660,7 +667,7 @@ public class SAMStreamSession {
public v1StreamSender ( I2PSocket s, int id ) throws IOException {
super ( s, id );
- _data = new ArrayList(1);
+ _data = new ArrayList(1);
_id = id;
_cache = ByteCache.getInstance(4, 32*1024);
_out = s.getOutputStream();
diff --git a/apps/sam/java/src/net/i2p/sam/SAMUtils.java b/apps/sam/java/src/net/i2p/sam/SAMUtils.java
index 8bb3fac300..6a6d81f880 100644
--- a/apps/sam/java/src/net/i2p/sam/SAMUtils.java
+++ b/apps/sam/java/src/net/i2p/sam/SAMUtils.java
@@ -101,6 +101,24 @@ public class SAMUtils {
return dest;
}
+ /**
+ * Resolve the destination from a key or a hostname
+ *
+ * @param s Hostname or key to be resolved
+ *
+ * @return the Destination for the specified hostname, or null if not found
+ */
+ public static Destination getDest(String s)
+ {
+ Destination d = new Destination() ;
+ try {
+ d.fromBase64(s);
+ return d ;
+ } catch (DataFormatException e) {
+ return lookupHost(s, null);
+ }
+ }
+
/**
* Parse SAM parameters, and put them into a Propetries object
*
diff --git a/apps/sam/java/src/net/i2p/sam/SAMv1Handler.java b/apps/sam/java/src/net/i2p/sam/SAMv1Handler.java
index 93a9a8d669..ac86d69346 100644
--- a/apps/sam/java/src/net/i2p/sam/SAMv1Handler.java
+++ b/apps/sam/java/src/net/i2p/sam/SAMv1Handler.java
@@ -12,12 +12,11 @@ import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.EOFException;
import java.io.IOException;
-import java.io.InputStream;
import java.io.InterruptedIOException;
-import java.io.OutputStream;
import java.net.ConnectException;
import java.net.NoRouteToHostException;
-import java.net.Socket;
+import java.nio.channels.SocketChannel;
+import java.nio.ByteBuffer;
import java.util.Properties;
import java.util.StringTokenizer;
@@ -40,14 +39,14 @@ public class SAMv1Handler extends SAMHandler implements SAMRawReceiver, SAMDatag
private final static Log _log = new Log(SAMv1Handler.class);
- private final static int IN_BUFSIZE = 2048;
+ protected SAMRawSession rawSession = null;
+ protected SAMDatagramSession datagramSession = null;
+ protected SAMStreamSession streamSession = null;
+ protected SAMDatagramSession getDatagramSession() {return datagramSession ;}
+ protected SAMRawSession getRawSession() {return rawSession ;}
- private SAMRawSession rawSession = null;
- private SAMDatagramSession datagramSession = null;
- protected SAMStreamSession streamSession = null;
-
- private long _id;
- private static volatile long __id = 0;
+ protected long _id;
+ protected static volatile long __id = 0;
/**
* Create a new SAM version 1 handler. This constructor expects
@@ -60,7 +59,7 @@ public class SAMv1Handler extends SAMHandler implements SAMRawReceiver, SAMDatag
* @throws SAMException
* @throws IOException
*/
- public SAMv1Handler(Socket s, int verMajor, int verMinor) throws SAMException, IOException {
+ public SAMv1Handler(SocketChannel s, int verMajor, int verMinor) throws SAMException, IOException {
this(s, verMajor, verMinor, new Properties());
}
/**
@@ -75,7 +74,7 @@ public class SAMv1Handler extends SAMHandler implements SAMRawReceiver, SAMDatag
* @throws SAMException
* @throws IOException
*/
- public SAMv1Handler(Socket s, int verMajor, int verMinor, Properties i2cpProps) throws SAMException, IOException {
+ public SAMv1Handler(SocketChannel s, int verMajor, int verMinor, Properties i2cpProps) throws SAMException, IOException {
super(s, verMajor, verMinor, i2cpProps);
_id = ++__id;
_log.debug("SAM version 1 handler instantiated");
@@ -101,16 +100,13 @@ public class SAMv1Handler extends SAMHandler implements SAMRawReceiver, SAMDatag
_log.debug("SAM handling started");
try {
- InputStream in = getClientSocketInputStream();
- int b = -1;
-
while (true) {
if (shouldStop()) {
_log.debug("Stop request found");
break;
}
- msg = DataHelper.readLine(in);
+ msg = DataHelper.readLine(getClientSocket().socket().getInputStream()).trim();
if (msg == null) {
_log.debug("Connection closed by client");
break;
@@ -175,11 +171,11 @@ public class SAMv1Handler extends SAMHandler implements SAMRawReceiver, SAMDatag
} catch (IOException e) {
_log.error("Error closing socket: " + e.getMessage());
}
- if (rawSession != null) {
- rawSession.close();
+ if (getRawSession() != null) {
+ getRawSession().close();
}
- if (datagramSession != null) {
- datagramSession.close();
+ if (getDatagramSession() != null) {
+ getDatagramSession().close();
}
if (streamSession != null) {
streamSession.close();
@@ -188,13 +184,13 @@ public class SAMv1Handler extends SAMHandler implements SAMRawReceiver, SAMDatag
}
/* Parse and execute a SESSION message */
- private boolean execSessionMessage(String opcode, Properties props) {
+ protected boolean execSessionMessage(String opcode, Properties props) {
String dest = "BUG!";
try{
if (opcode.equals("CREATE")) {
- if ((rawSession != null) || (datagramSession != null)
+ if ((getRawSession() != null) || (getDatagramSession() != null)
|| (streamSession != null)) {
_log.debug("Trying to create a session, but one still exists");
return writeString("SESSION STATUS RESULT=I2P_ERROR MESSAGE=\"Session already exists\"\n");
@@ -293,7 +289,7 @@ public class SAMv1Handler extends SAMHandler implements SAMRawReceiver, SAMDatag
}
/* Parse and execute a DEST message*/
- private boolean execDestMessage(String opcode, Properties props) {
+ protected boolean execDestMessage(String opcode, Properties props) {
if (opcode.equals("GENERATE")) {
if (props.size() > 0) {
@@ -318,7 +314,7 @@ public class SAMv1Handler extends SAMHandler implements SAMRawReceiver, SAMDatag
}
/* Parse and execute a NAMING message */
- private boolean execNamingMessage(String opcode, Properties props) {
+ protected boolean execNamingMessage(String opcode, Properties props) {
if (opcode.equals("LOOKUP")) {
if (props == null) {
_log.debug("No parameters specified in NAMING LOOKUP message");
@@ -333,18 +329,18 @@ public class SAMv1Handler extends SAMHandler implements SAMRawReceiver, SAMDatag
Destination dest;
if (name.equals("ME")) {
- if (rawSession != null) {
- dest = rawSession.getDestination();
+ if (getRawSession() != null) {
+ dest = getRawSession().getDestination();
} else if (streamSession != null) {
dest = streamSession.getDestination();
- } else if (datagramSession != null) {
- dest = datagramSession.getDestination();
+ } else if (getDatagramSession() != null) {
+ dest = getDatagramSession().getDestination();
} else {
_log.debug("Lookup for SESSION destination, but session is null");
return false;
}
} else {
- dest = SAMUtils.lookupHost(name, null);
+ dest = SAMUtils.getDest(name);
}
if (dest == null) {
@@ -364,8 +360,8 @@ public class SAMv1Handler extends SAMHandler implements SAMRawReceiver, SAMDatag
/* Parse and execute a DATAGRAM message */
- private boolean execDatagramMessage(String opcode, Properties props) {
- if (datagramSession == null) {
+ protected boolean execDatagramMessage(String opcode, Properties props) {
+ if (getDatagramSession() == null) {
_log.error("DATAGRAM message received, but no DATAGRAM session exists");
return false;
}
@@ -403,7 +399,7 @@ public class SAMv1Handler extends SAMHandler implements SAMRawReceiver, SAMDatag
}
try {
- DataInputStream in = new DataInputStream(getClientSocketInputStream());
+ DataInputStream in = new DataInputStream(getClientSocket().socket().getInputStream());
byte[] data = new byte[size];
in.readFully(data);
@@ -435,8 +431,8 @@ public class SAMv1Handler extends SAMHandler implements SAMRawReceiver, SAMDatag
}
/* Parse and execute a RAW message */
- private boolean execRawMessage(String opcode, Properties props) {
- if (rawSession == null) {
+ protected boolean execRawMessage(String opcode, Properties props) {
+ if (getRawSession() == null) {
_log.error("RAW message received, but no RAW session exists");
return false;
}
@@ -474,12 +470,12 @@ public class SAMv1Handler extends SAMHandler implements SAMRawReceiver, SAMDatag
}
try {
- DataInputStream in = new DataInputStream(getClientSocketInputStream());
+ DataInputStream in = new DataInputStream(getClientSocket().socket().getInputStream());
byte[] data = new byte[size];
in.readFully(data);
- if (!rawSession.sendBytes(dest, data)) {
+ if (!getRawSession().sendBytes(dest, data)) {
_log.error("RAW SEND failed");
return true;
}
@@ -567,7 +563,7 @@ public class SAMv1Handler extends SAMHandler implements SAMRawReceiver, SAMDatag
}
try {
- if (!streamSession.sendBytes(id, getClientSocketInputStream(), size)) { // data)) {
+ if (!streamSession.sendBytes(id, getClientSocket().socket().getInputStream(), size)) { // data)) {
if (_log.shouldLog(Log.WARN))
_log.warn("STREAM SEND [" + size + "] failed");
boolean rv = writeString("STREAM CLOSED RESULT=CANT_REACH_PEER ID=" + id + " MESSAGE=\"Send of " + size + " bytes failed\"\n");
@@ -691,7 +687,7 @@ public class SAMv1Handler extends SAMHandler implements SAMRawReceiver, SAMDatag
// SAMRawReceiver implementation
public void receiveRawBytes(byte data[]) throws IOException {
- if (rawSession == null) {
+ if (getRawSession() == null) {
_log.error("BUG! Received raw bytes, but session is null!");
throw new NullPointerException("BUG! RAW session is null!");
}
@@ -701,17 +697,18 @@ public class SAMv1Handler extends SAMHandler implements SAMRawReceiver, SAMDatag
String msgText = "RAW RECEIVED SIZE=" + data.length + "\n";
msg.write(msgText.getBytes("ISO-8859-1"));
msg.write(data);
+ msg.flush();
if (_log.shouldLog(Log.DEBUG))
_log.debug("sending to client: " + msgText);
- writeBytes(msg.toByteArray());
+ writeBytes(ByteBuffer.wrap(msg.toByteArray()));
}
public void stopRawReceiving() {
_log.debug("stopRawReceiving() invoked");
- if (rawSession == null) {
+ if (getRawSession() == null) {
_log.error("BUG! Got raw receiving stop, but session is null!");
throw new NullPointerException("BUG! RAW session is null!");
}
@@ -726,7 +723,7 @@ public class SAMv1Handler extends SAMHandler implements SAMRawReceiver, SAMDatag
// SAMDatagramReceiver implementation
public void receiveDatagramBytes(Destination sender, byte data[]) throws IOException {
- if (datagramSession == null) {
+ if (getDatagramSession() == null) {
_log.error("BUG! Received datagram bytes, but session is null!");
throw new NullPointerException("BUG! DATAGRAM session is null!");
}
@@ -740,14 +737,14 @@ public class SAMv1Handler extends SAMHandler implements SAMRawReceiver, SAMDatag
if (_log.shouldLog(Log.DEBUG))
_log.debug("sending to client: " + msgText);
msg.write(data);
-
- writeBytes(msg.toByteArray());
+ msg.flush();
+ writeBytes(ByteBuffer.wrap(msg.toByteArray()));
}
public void stopDatagramReceiving() {
_log.debug("stopDatagramReceiving() invoked");
- if (datagramSession == null) {
+ if (getDatagramSession() == null) {
_log.error("BUG! Got datagram receiving stop, but session is null!");
throw new NullPointerException("BUG! DATAGRAM session is null!");
}
@@ -830,29 +827,23 @@ public class SAMv1Handler extends SAMHandler implements SAMRawReceiver, SAMDatag
}
}
- public void receiveStreamBytes(int id, byte data[], int len) throws IOException {
+ public void receiveStreamBytes(int id, ByteBuffer data) throws IOException {
if (streamSession == null) {
_log.error("Received stream bytes, but session is null!");
throw new NullPointerException("BUG! STREAM session is null!");
}
- String msgText = "STREAM RECEIVED ID=" + id +" SIZE=" + len + "\n";
+ String msgText = "STREAM RECEIVED ID=" + id +" SIZE=" + data.remaining() + "\n";
if (_log.shouldLog(Log.DEBUG))
_log.debug("sending to client: " + msgText);
- byte prefix[] = msgText.getBytes("ISO-8859-1");
+ ByteBuffer prefix = ByteBuffer.wrap(msgText.getBytes("ISO-8859-1"));
- // dont waste so much memory
- //ByteArrayOutputStream msg = new ByteArrayOutputStream();
- //msg.write(msgText.getBytes("ISO-8859-1"));
- //msg.write(data, 0, len);
- // writeBytes(msg.toByteArray());
Object writeLock = getWriteLock();
- OutputStream out = getOut();
synchronized (writeLock) {
- out.write(prefix);
- out.write(data, 0, len);
- out.flush();
+ while (prefix.hasRemaining()) socket.write(prefix);
+ while (data.hasRemaining()) socket.write(data);
+ socket.socket().getOutputStream().flush();
}
}
diff --git a/apps/sam/java/src/net/i2p/sam/SAMv2Handler.java b/apps/sam/java/src/net/i2p/sam/SAMv2Handler.java
index 75f1bd4b47..0800e17e90 100644
--- a/apps/sam/java/src/net/i2p/sam/SAMv2Handler.java
+++ b/apps/sam/java/src/net/i2p/sam/SAMv2Handler.java
@@ -9,7 +9,7 @@ package net.i2p.sam;
*/
import java.io.IOException;
-import java.net.Socket;
+import java.nio.channels.SocketChannel;
import java.util.Properties;
import net.i2p.data.DataFormatException;
@@ -36,7 +36,7 @@ public class SAMv2Handler extends SAMv1Handler implements SAMRawReceiver, SAMDat
* @param verMajor SAM major version to manage (should be 2)
* @param verMinor SAM minor version to manage
*/
- public SAMv2Handler ( Socket s, int verMajor, int verMinor ) throws SAMException, IOException
+ public SAMv2Handler ( SocketChannel s, int verMajor, int verMinor ) throws SAMException, IOException
{
this ( s, verMajor, verMinor, new Properties() );
}
@@ -52,7 +52,7 @@ public class SAMv2Handler extends SAMv1Handler implements SAMRawReceiver, SAMDat
* @param i2cpProps properties to configure the I2CP connection (host, port, etc)
*/
- public SAMv2Handler ( Socket s, int verMajor, int verMinor, Properties i2cpProps ) throws SAMException, IOException
+ public SAMv2Handler ( SocketChannel s, int verMajor, int verMinor, Properties i2cpProps ) throws SAMException, IOException
{
super ( s, verMajor, verMinor, i2cpProps );
}
diff --git a/apps/sam/java/src/net/i2p/sam/SAMv2StreamSession.java b/apps/sam/java/src/net/i2p/sam/SAMv2StreamSession.java
index de5b7851bc..4197597eb0 100644
--- a/apps/sam/java/src/net/i2p/sam/SAMv2StreamSession.java
+++ b/apps/sam/java/src/net/i2p/sam/SAMv2StreamSession.java
@@ -12,6 +12,8 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.InterruptedIOException;
import java.io.OutputStream;
+import java.nio.channels.Channels;
+import java.nio.ByteBuffer;
import java.net.ConnectException;
import java.net.NoRouteToHostException;
import java.util.ArrayList;
@@ -140,9 +142,6 @@ public class SAMv2StreamSession extends SAMStreamSession
public class StreamConnector implements Runnable
{
- private Object runningLock = new Object();
- private boolean stillRunning = true;
-
private int id;
private Destination dest ;
private I2PSocketOptions opts ;
@@ -245,7 +244,7 @@ public class SAMv2StreamSession extends SAMStreamSession
protected class v2StreamSender extends StreamSender
{
- private List _data;
+ private List _data;
private int _dataSize;
private int _id;
private ByteCache _cache;
@@ -257,7 +256,7 @@ public class SAMv2StreamSession extends SAMStreamSession
public v2StreamSender ( I2PSocket s, int id ) throws IOException
{
super ( s, id );
- _data = new ArrayList ( 1 );
+ _data = new ArrayList ( 1 );
_dataSize = 0;
_id = id;
_cache = ByteCache.getInstance ( 10, 32 * 1024 );
@@ -511,7 +510,7 @@ public class SAMv2StreamSession extends SAMStreamSession
_log.debug ( "run() called for socket reader " + id );
int read = -1;
- byte[] data = new byte[SOCKET_HANDLER_BUF_SIZE];
+ ByteBuffer data = ByteBuffer.allocateDirect(SOCKET_HANDLER_BUF_SIZE);
try
{
@@ -533,7 +532,8 @@ public class SAMv2StreamSession extends SAMStreamSession
break ;
}
- read = in.read ( data );
+ data.clear();
+ read = Channels.newChannel(in).read ( data );
if ( read == -1 )
{
@@ -542,8 +542,8 @@ public class SAMv2StreamSession extends SAMStreamSession
}
totalReceived += read ;
-
- recv.receiveStreamBytes ( id, data, read );
+ data.flip();
+ recv.receiveStreamBytes ( id, data );
}
}
catch ( IOException e )
diff --git a/apps/sam/java/src/net/i2p/sam/SAMv3DatagramSession.java b/apps/sam/java/src/net/i2p/sam/SAMv3DatagramSession.java
new file mode 100644
index 0000000000..dcca03c141
--- /dev/null
+++ b/apps/sam/java/src/net/i2p/sam/SAMv3DatagramSession.java
@@ -0,0 +1,90 @@
+/**
+ * @author MKVore
+ *
+ */
+
+package net.i2p.sam;
+
+import java.io.IOException;
+import java.io.InterruptedIOException;
+import java.util.Properties;
+
+import net.i2p.client.I2PSessionException;
+import net.i2p.data.DataFormatException;
+import net.i2p.data.Destination;
+import net.i2p.util.Log;
+
+import java.net.InetSocketAddress;
+import java.net.SocketAddress ;
+import java.nio.ByteBuffer;
+
+public class SAMv3DatagramSession extends SAMDatagramSession implements SAMv3Handler.Session, SAMDatagramReceiver {
+
+ private final static Log _log = new Log ( SAMv3DatagramSession.class );
+
+ SAMv3Handler handler = null ;
+ SAMv3Handler.DatagramServer server = null ;
+ String nick = null ;
+ SocketAddress clientAddress = null ;
+
+ public String getNick() { return nick; }
+
+ /**
+ * @param nick nickname of the session
+ * @param server DatagramServer used for communication with the client
+ * @throws IOException
+ * @throws DataFormatException
+ * @throws I2PSessionException
+ */
+ public SAMv3DatagramSession(String nick)
+ throws IOException, DataFormatException, I2PSessionException {
+
+ super(SAMv3Handler.sSessionsHash.get(nick).getDest(),
+ SAMv3Handler.sSessionsHash.get(nick).getProps(),
+ null
+ );
+ this.nick = nick ;
+ this.recv = this ;
+ this.server = SAMv3Handler.DatagramServer.getInstance() ;
+
+ SAMv3Handler.SessionRecord rec = SAMv3Handler.sSessionsHash.get(nick);
+ if ( rec==null ) throw new InterruptedIOException() ;
+
+ this.handler = rec.getHandler();
+
+ Properties props = rec.getProps();
+ String portStr = props.getProperty("PORT") ;
+ if ( portStr==null ) {
+ _log.debug("receiver port not specified. Current socket will be used.");
+ }
+ else {
+ int port = Integer.parseInt(portStr);
+
+ String host = props.getProperty("HOST");
+ if ( host==null ) {
+ _log.debug("no host specified. Take from the client socket");
+
+ host = rec.getHandler().getClientIP();
+ }
+
+
+ this.clientAddress = new InetSocketAddress(host,port);
+ }
+ }
+
+ public void receiveDatagramBytes(Destination sender, byte[] data) throws IOException {
+ if (this.clientAddress==null) {
+ this.handler.receiveDatagramBytes(sender, data);
+ } else {
+ String msg = sender.toBase64()+"\n";
+ ByteBuffer msgBuf = ByteBuffer.allocate(msg.length()+data.length);
+ msgBuf.put(msg.getBytes("ISO-8859-1"));
+ msgBuf.put(data);
+ msgBuf.flip();
+ this.server.send(this.clientAddress, msgBuf);
+ }
+ }
+
+ public void stopDatagramReceiving() {
+ }
+}
diff --git a/apps/sam/java/src/net/i2p/sam/SAMv3Handler.java b/apps/sam/java/src/net/i2p/sam/SAMv3Handler.java
new file mode 100644
index 0000000000..21ff0df680
--- /dev/null
+++ b/apps/sam/java/src/net/i2p/sam/SAMv3Handler.java
@@ -0,0 +1,748 @@
+package net.i2p.sam;
+/*
+ * free (adj.): unencumbered; not under the control of others
+ * Written by human in 2004 and released into the public domain
+ * with no warranty of any kind, either expressed or implied.
+ * It probably won't make your computer catch on fire, or eat
+ * your children, but it might. Use at your own risk.
+ *
+ */
+
+
+import java.io.ByteArrayOutputStream;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InterruptedIOException;
+import java.net.ConnectException;
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
+import java.net.NoRouteToHostException;
+import java.nio.channels.DatagramChannel;
+import java.nio.channels.SocketChannel;
+import java.nio.ByteBuffer;
+import java.util.Properties;
+import java.util.HashMap;
+import java.util.StringTokenizer;
+
+import net.i2p.I2PException;
+import net.i2p.client.I2PSessionException;
+import net.i2p.data.Base64;
+import net.i2p.data.DataFormatException;
+import net.i2p.data.DataHelper;
+import net.i2p.data.Destination;
+import net.i2p.util.Log;
+import net.i2p.data.VerifiedDestination;
+import net.i2p.util.I2PAppThread;
+
+/**
+ * Class able to handle a SAM version 3 client connection.
+ *
+ * @author mkvore
+ */
+
+public class SAMv3Handler extends SAMv1Handler
+{
+ private final static Log _log = new Log ( SAMv3Handler.class );
+
+ protected SAMv3StreamSession streamSession = null ;
+ protected SAMv3RawSession rawSession = null ;
+ protected SAMv3DatagramSession datagramSession = null ;
+
+ protected SAMDatagramSession getDatagramSession() {
+ return datagramSession ;
+ }
+
+ protected SAMRawSession getRawSession() {
+ return rawSession ;
+ }
+
+ protected Session session = null ;
+
+ interface Session {
+ String getNick();
+ void close();
+ boolean sendBytes(String dest, byte[] data) throws DataFormatException;
+ }
+
+ /**
+ * Create a new SAM version 3 handler. This constructor expects
+ * that the SAM HELLO message has been still answered (and
+ * stripped) from the socket input stream.
+ *
+ * @param s Socket attached to a SAM client
+ * @param verMajor SAM major version to manage (should be 3)
+ * @param verMinor SAM minor version to manage
+ */
+ public SAMv3Handler ( SocketChannel s, int verMajor, int verMinor ) throws SAMException, IOException
+ {
+ this ( s, verMajor, verMinor, new Properties() );
+ }
+
+ /**
+ * Create a new SAM version 3 handler. This constructor expects
+ * that the SAM HELLO message has been still answered (and
+ * stripped) from the socket input stream.
+ *
+ * @param s Socket attached to a SAM client
+ * @param verMajor SAM major version to manage (should be 3)
+ * @param verMinor SAM minor version to manage
+ * @param i2cpProps properties to configure the I2CP connection (host, port, etc)
+ */
+
+ public SAMv3Handler ( SocketChannel s, int verMajor, int verMinor, Properties i2cpProps ) throws SAMException, IOException
+ {
+ super ( s, verMajor, verMinor, i2cpProps );
+ _log.debug("SAM version 3 handler instantiated");
+ }
+
+ public boolean verifVersion()
+ {
+ return (verMajor == 3 && verMinor == 0) ;
+ }
+
+ static public class DatagramServer {
+
+ private static DatagramServer _instance = null ;
+ private static DatagramChannel server = null ;
+
+ public static DatagramServer getInstance() throws IOException {
+ return getInstance(new Properties());
+ }
+
+ public static DatagramServer getInstance(Properties props) throws IOException {
+ if (_instance==null) {
+ _instance = new DatagramServer(props);
+ }
+ return _instance ;
+ }
+
+ public DatagramServer(Properties props) throws IOException {
+ if (server==null) {
+ server = DatagramChannel.open();
+ }
+
+ String host = props.getProperty(SAMBridge.PROP_DATAGRAM_HOST, SAMBridge.DEFAULT_DATAGRAM_HOST);
+ String portStr = props.getProperty(SAMBridge.PROP_DATAGRAM_PORT, SAMBridge.DEFAULT_DATAGRAM_PORT);
+ int port ;
+ try {
+ port = Integer.parseInt(portStr);
+ } catch (NumberFormatException e) {
+ port = Integer.parseInt(SAMBridge.DEFAULT_DATAGRAM_PORT);
+ }
+
+ server.socket().bind(new InetSocketAddress(host, port));
+ new I2PAppThread(new Listener(server), "DatagramListener").start();
+ }
+
+ public void send(SocketAddress addr, ByteBuffer msg) throws IOException {
+ server.send(msg, addr);
+ }
+
+ class Listener implements Runnable {
+
+ DatagramChannel server = null;
+
+ public Listener(DatagramChannel server)
+ {
+ this.server = server ;
+ }
+ public void run()
+ {
+ ByteBuffer inBuf = ByteBuffer.allocateDirect(SAMRawSession.RAW_SIZE_MAX+1024);
+
+ while (!Thread.interrupted())
+ {
+ inBuf.clear();
+ try {
+ server.receive(inBuf);
+ } catch (IOException e) {
+ break ;
+ }
+ inBuf.flip();
+ ByteBuffer outBuf = ByteBuffer.wrap(new byte[inBuf.remaining()]);
+ outBuf.put(inBuf);
+ outBuf.flip();
+ new I2PAppThread(new MessageDispatcher(outBuf.array()), "MessageDispatcher").start();
+ }
+ }
+ }
+ }
+
+ public static class MessageDispatcher implements Runnable
+ {
+ ByteArrayInputStream is = null ;
+
+ public MessageDispatcher(byte[] buf)
+ {
+ this.is = new java.io.ByteArrayInputStream(buf) ;
+ }
+
+ public void run() {
+ String header = null ;
+ String nick ;
+ String dest ;
+
+ try {
+ header = DataHelper.readLine(is).trim();
+ StringTokenizer tok = new StringTokenizer(header, " ");
+ if (tok.countTokens() != 2) {
+ // This is not a correct message, for sure
+ _log.debug("Error in message format");
+ return;
+ }
+ nick = tok.nextToken();
+ dest = tok.nextToken();
+
+ byte[] data = new byte[is.available()];
+ is.read(data);
+ SessionRecord rec = sSessionsHash.get(nick);
+ if (rec!=null) {
+ rec.getHandler().session.sendBytes(dest,data);
+ }
+ } catch (Exception e) {}
+ }
+ }
+
+ public class SessionRecord
+ {
+ protected String m_dest ;
+ protected Properties m_props ;
+ protected ThreadGroup m_threadgroup ;
+ protected SAMv3Handler m_handler ;
+
+ public SessionRecord( String dest, Properties props, SAMv3Handler handler )
+ {
+ m_dest = new String(dest) ;
+ m_props = new Properties() ;
+ m_props.putAll(props);
+ m_threadgroup = null ;
+ m_handler = handler ;
+ }
+
+ public SessionRecord( SessionRecord in )
+ {
+ m_dest = in.getDest();
+ m_props = in.getProps();
+ m_threadgroup = in.getThreadGroup();
+ m_handler = in.getHandler();
+ }
+
+ synchronized public String getDest()
+ {
+ return new String(m_dest) ;
+ }
+ synchronized public Properties getProps()
+ {
+ Properties p = new Properties();
+ p.putAll(m_props);
+ return m_props;
+ }
+ synchronized public SAMv3Handler getHandler()
+ {
+ return m_handler ;
+ }
+ synchronized public ThreadGroup getThreadGroup()
+ {
+ return m_threadgroup ;
+ }
+ synchronized public void createThreadGroup(String name)
+ {
+ if (m_threadgroup == null)
+ m_threadgroup = new ThreadGroup(name);
+ }
+ }
+
+ public static class SessionsDB
+ {
+ static final long serialVersionUID = 0x1 ;
+
+ HashMap map ;
+
+ public SessionsDB() {
+ map = new HashMap() ;
+ }
+
+ synchronized public boolean put( String nick, SessionRecord session )
+ {
+ if ( !map.containsKey(nick) ) {
+ session.createThreadGroup("SAM session "+nick);
+ map.put(nick, session) ;
+ return true ;
+ }
+ else
+ return false ;
+ }
+ synchronized public boolean del( String nick )
+ {
+ SessionRecord rec = map.get(nick);
+
+ if ( rec!=null ) {
+ map.remove(nick);
+ return true ;
+ }
+ else
+ return false ;
+ }
+ synchronized public SessionRecord get(String nick)
+ {
+ return map.get(nick);
+ }
+ synchronized public boolean containsKey( String nick )
+ {
+ return map.containsKey(nick);
+ }
+ }
+
+ public static SessionsDB sSessionsHash = new SessionsDB() ;
+
+ public String getClientIP()
+ {
+ return this.socket.socket().getInetAddress().getHostAddress();
+ }
+
+ boolean stolenSocket = false ;
+
+ public void stealSocket()
+ {
+ stolenSocket = true ;
+ this.stopHandling();
+ }
+
+ public void handle() {
+ String msg = null;
+ String domain = null;
+ String opcode = null;
+ boolean canContinue = false;
+ StringTokenizer tok;
+ Properties props;
+
+ this.thread.setName("SAMv3Handler " + _id);
+ _log.debug("SAM handling started");
+
+ try {
+ InputStream in = getClientSocket().socket().getInputStream();
+
+ while (true) {
+ if (shouldStop()) {
+ _log.debug("Stop request found");
+ break;
+ }
+
+ msg = DataHelper.readLine(in).trim();
+ if (msg == null) {
+ _log.debug("Connection closed by client");
+ break;
+ }
+
+ if (_log.shouldLog(Log.DEBUG)) {
+ _log.debug("New message received: [" + msg + "]");
+ }
+
+ if(msg.equals("")) {
+ _log.debug("Ignoring newline");
+ continue;
+ }
+
+ tok = new StringTokenizer(msg, " ");
+ if (tok.countTokens() < 2) {
+ // This is not a correct message, for sure
+ _log.debug("Error in message format");
+ break;
+ }
+ domain = tok.nextToken();
+ opcode = tok.nextToken();
+ if (_log.shouldLog(Log.DEBUG)) {
+ _log.debug("Parsing (domain: \"" + domain
+ + "\"; opcode: \"" + opcode + "\")");
+ }
+ props = SAMUtils.parseParams(tok);
+
+ if (domain.equals("STREAM")) {
+ canContinue = execStreamMessage(opcode, props);
+ } else if (domain.equals("SESSION")) {
+ if (i2cpProps != null)
+ props.putAll(i2cpProps); // make sure we've got the i2cp settings
+ canContinue = execSessionMessage(opcode, props);
+ } else if (domain.equals("DEST")) {
+ canContinue = execDestMessage(opcode, props);
+ } else if (domain.equals("NAMING")) {
+ canContinue = execNamingMessage(opcode, props);
+ } else {
+ _log.debug("Unrecognized message domain: \""
+ + domain + "\"");
+ break;
+ }
+
+ if (!canContinue) {
+ break;
+ }
+ }
+ } catch (IOException e) {
+ _log.debug("Caught IOException ("
+ + e.getMessage() + ") for message [" + msg + "]", e);
+ } catch (Exception e) {
+ _log.error("Unexpected exception for message [" + msg + "]", e);
+ } finally {
+ _log.debug("Stopping handler");
+
+ if (!this.stolenSocket)
+ {
+ try {
+ closeClientSocket();
+ } catch (IOException e) {
+ _log.error("Error closing socket: " + e.getMessage());
+ }
+ }
+
+ die();
+ }
+ }
+
+ protected void die() {
+ SessionRecord rec = null ;
+
+ if (session!=null) {
+ session.close();
+ rec = sSessionsHash.get(session.getNick());
+ }
+ if (rec!=null) {
+ rec.getThreadGroup().interrupt() ;
+ while (rec.getThreadGroup().activeCount()>0)
+ try {
+ Thread.sleep(1000);
+ } catch ( InterruptedException e) {}
+ rec.getThreadGroup().destroy();
+ sSessionsHash.del(session.getNick());
+ }
+ }
+
+ /* Parse and execute a SESSION message */
+ @Override
+ protected boolean execSessionMessage(String opcode, Properties props) {
+
+ String dest = "BUG!";
+ String nick = null ;
+ boolean ok = false ;
+
+ try{
+ if (opcode.equals("CREATE")) {
+ if ((this.getRawSession()!= null) || (this.getDatagramSession() != null)
+ || (streamSession != null)) {
+ _log.debug("Trying to create a session, but one still exists");
+ return writeString("SESSION STATUS RESULT=I2P_ERROR MESSAGE=\"Session already exists\"\n");
+ }
+ if (props == null) {
+ _log.debug("No parameters specified in SESSION CREATE message");
+ return writeString("SESSION STATUS RESULT=I2P_ERROR MESSAGE=\"No parameters for SESSION CREATE\"\n");
+ }
+
+ dest = props.getProperty("DESTINATION");
+ if (dest == null) {
+ _log.debug("SESSION DESTINATION parameter not specified");
+ return writeString("SESSION STATUS RESULT=I2P_ERROR MESSAGE=\"DESTINATION not specified\"\n");
+ }
+ props.remove("DESTINATION");
+
+
+ if (dest.equals("TRANSIENT")) {
+ _log.debug("TRANSIENT destination requested");
+ ByteArrayOutputStream priv = new ByteArrayOutputStream(640);
+ SAMUtils.genRandomKey(priv, null);
+
+ dest = Base64.encode(priv.toByteArray());
+ } else {
+ _log.debug("Custom destination specified [" + dest + "]");
+ }
+
+ boolean good_key = false ;
+ try {
+ good_key = (new VerifiedDestination(dest)).verifyCert(true);
+ } catch (DataFormatException e) {
+ good_key = false ;
+ }
+ if (!good_key)
+ {
+ _log.debug("Bad destination key");
+ return writeString("SESSION STATUS RESULT=I2P_ERROR MESSAGE=\"bad destination key\"\n");
+ }
+
+ nick = props.getProperty("ID");
+ if (nick == null) {
+ _log.debug("SESSION ID parameter not specified");
+ return writeString("SESSION STATUS RESULT=I2P_ERROR MESSAGE=\"ID not specified\"\n");
+ }
+ props.remove("ID");
+
+
+ String style = props.getProperty("STYLE");
+ if (style == null) {
+ _log.debug("SESSION STYLE parameter not specified");
+ return writeString("SESSION STATUS RESULT=I2P_ERROR MESSAGE=\"No SESSION STYLE specified\"\n");
+ }
+ props.remove("STYLE");
+
+
+
+ // Record the session in the database sSessionsHash
+ Properties allProps = new Properties();
+ allProps.putAll(i2cpProps);
+ allProps.putAll(props);
+
+ if (! sSessionsHash.put( nick, new SessionRecord(dest, allProps, this) ) ) {
+ _log.debug("SESSION ID parameter already in use");
+ String n = nick ;
+ return writeString("SESSION STATUS RESULT=I2P_ERROR MESSAGE=\"ID "+n+" already in use\"\n");
+ }
+
+ // Create the session
+
+ if (style.equals("RAW")) {
+ DatagramServer.getInstance(i2cpProps);
+ rawSession = newSAMRawSession(nick);
+ this.session = rawSession ;
+ } else if (style.equals("DATAGRAM")) {
+ DatagramServer.getInstance(i2cpProps);
+ datagramSession = newSAMDatagramSession(nick);
+ this.session = datagramSession ;
+ } else if (style.equals("STREAM")) {
+ streamSession = newSAMStreamSession(nick);
+ this.session = streamSession ;
+ } else {
+ _log.debug("Unrecognized SESSION STYLE: \"" + style +"\"");
+ return writeString("SESSION STATUS RESULT=I2P_ERROR MESSAGE=\"Unrecognized SESSION STYLE\"\n");
+ }
+ ok = true ;
+ return writeString("SESSION STATUS RESULT=OK DESTINATION="
+ + dest + "\n");
+ } else {
+ _log.debug("Unrecognized SESSION message opcode: \""
+ + opcode + "\"");
+ return writeString("SESSION STATUS RESULT=I2P_ERROR MESSAGE=\"Unrecognized opcode\"\n");
+ }
+ } catch (DataFormatException e) {
+ _log.debug("Invalid destination specified");
+ return writeString("SESSION STATUS RESULT=INVALID_KEY DESTINATION=" + dest + " MESSAGE=\"" + e.getMessage() + "\"\n");
+ } catch (I2PSessionException e) {
+ _log.debug("I2P error when instantiating session", e);
+ return writeString("SESSION STATUS RESULT=I2P_ERROR DESTINATION=" + dest + " MESSAGE=\"" + e.getMessage() + "\"\n");
+ } catch (SAMException e) {
+ _log.error("Unexpected SAM error", e);
+ return writeString("SESSION STATUS RESULT=I2P_ERROR DESTINATION=" + dest + " MESSAGE=\"" + e.getMessage() + "\"\n");
+ } catch (IOException e) {
+ _log.error("Unexpected IOException", e);
+ return writeString("SESSION STATUS RESULT=I2P_ERROR DESTINATION=" + dest + " MESSAGE=\"" + e.getMessage() + "\"\n");
+ } finally {
+ // unregister the session if it has not been created
+ if ( !ok && nick!=null ) {
+ sSessionsHash.del(nick) ;
+ session = null ;
+ }
+ }
+ }
+
+ SAMv3StreamSession newSAMStreamSession(String login )
+ throws IOException, DataFormatException, SAMException
+ {
+ return new SAMv3StreamSession( login ) ;
+ }
+
+ SAMv3RawSession newSAMRawSession(String login )
+ throws IOException, DataFormatException, SAMException, I2PSessionException
+ {
+ return new SAMv3RawSession( login ) ;
+ }
+
+ SAMv3DatagramSession newSAMDatagramSession(String login )
+ throws IOException, DataFormatException, SAMException, I2PSessionException
+ {
+ return new SAMv3DatagramSession( login ) ;
+ }
+
+ /* Parse and execute a STREAM message */
+ protected boolean execStreamMessage ( String opcode, Properties props )
+ {
+ String nick = null ;
+ SessionRecord rec = null ;
+
+ if ( session != null )
+ {
+ _log.error ( "STREAM message received, but this session is a master session" );
+ writeString("STREAM STATUS RESULT=I2P_ERROR MESSAGE=\"master session cannot be used for streams");
+ return false;
+ }
+
+ nick = props.getProperty("ID");
+ if (nick == null) {
+ _log.debug("SESSION ID parameter not specified");
+ writeString("STREAM STATUS RESULT=I2P_ERROR MESSAGE=\"ID not specified\"\n");
+ return false ;
+ }
+ props.remove("ID");
+
+ rec = sSessionsHash.get(nick);
+
+ if ( rec==null ) {
+ _log.debug("STREAM SESSION ID does not exist");
+ writeString("STREAM STATUS RESULT=I2P_ERROR MESSAGE=\"STREAM SESSION ID does not exist\"\n");
+ return false ;
+ }
+
+ streamSession = rec.getHandler().streamSession ;
+
+ if (streamSession==null) {
+ _log.debug("specified ID is not a stream session");
+ writeString("STREAM STATUS RESULT=I2P_ERROR MESSAGE=\"specified ID is not a STREAM session\"\n");
+ return false ;
+ }
+
+ if ( opcode.equals ( "CONNECT" ) )
+ {
+ return execStreamConnect ( props );
+ }
+ else if ( opcode.equals ( "ACCEPT" ) )
+ {
+ return execStreamAccept ( props );
+ }
+ else if ( opcode.equals ( "FORWARD") )
+ {
+ return execStreamForwardIncoming( props );
+ }
+ else
+ {
+ _log.debug ( "Unrecognized RAW message opcode: \""
+ + opcode + "\"" );
+ writeString("STREAM STATUS RESULT=I2P_ERROR MESSAGE=\"Unrecognized RAW message opcode: \""
+ + opcode + "\"" );
+ return false;
+ }
+ }
+
+ protected boolean execStreamConnect( Properties props) {
+ if (props == null) {
+ _log.debug("No parameters specified in STREAM CONNECT message");
+ return false;
+ }
+ boolean verbose = props.getProperty("SILENT","false").equals("false");
+
+ String dest = props.getProperty("DESTINATION");
+ if (dest == null) {
+ _log.debug("Destination not specified in RAW SEND message");
+ return false;
+ }
+ props.remove("DESTINATION");
+
+ try {
+ try {
+ streamSession.connect( this, dest, props );
+ return true ;
+ } catch (DataFormatException e) {
+ _log.debug("Invalid destination in STREAM CONNECT message");
+ if (verbose) notifyStreamAccept ( "INVALID_KEY" );
+ } catch (ConnectException e) {
+ _log.debug("STREAM CONNECT failed: " + e.getMessage());
+ if (verbose) notifyStreamAccept ( "CONNECTION_REFUSED" );
+ } catch (NoRouteToHostException e) {
+ _log.debug("STREAM CONNECT failed: " + e.getMessage());
+ if (verbose) notifyStreamAccept ( "CANT_REACH_PEER" );
+ } catch (InterruptedIOException e) {
+ _log.debug("STREAM CONNECT failed: " + e.getMessage());
+ if (verbose) notifyStreamAccept ( "TIMEOUT" );
+ } catch (I2PException e) {
+ _log.debug("STREAM CONNECT failed: " + e.getMessage());
+ if (verbose) notifyStreamAccept ( "I2P_ERROR" );
+ }
+ } catch (IOException e) {
+ }
+ return false ;
+ }
+
+ protected boolean execStreamForwardIncoming( Properties props ) {
+ try {
+ try {
+ streamSession.startForwardingIncoming(props);
+ notifyStreamAccept("OK");
+ return true ;
+ } catch (SAMException e) {
+ _log.debug("Forwarding STREAM connections failed: " + e.getMessage());
+ notifyStreamAccept ( "FORWARDER_FAILED" );
+ }
+ } catch (IOException e) {
+ }
+ return false ;
+ }
+
+ protected boolean execStreamAccept( Properties props )
+ {
+ boolean verbose = props.getProperty( "SILENT", "false").equals("false");
+ try {
+ try {
+ streamSession.accept(this, verbose);
+ return true ;
+ } catch (InterruptedIOException e) {
+ _log.debug("STREAM ACCEPT failed: " + e.getMessage());
+ if (verbose) notifyStreamAccept( "TIMEOUT" );
+ } catch (I2PException e) {
+ _log.debug("STREAM ACCEPT failed: " + e.getMessage());
+ if (verbose) notifyStreamAccept ( "I2P_ERROR" );
+ } catch (SAMException e) {
+ _log.debug("STREAM ACCEPT failed: " + e.getMessage());
+ if (verbose) notifyStreamAccept ( "ALREADY_ACCEPTING" );
+ }
+ } catch (IOException e) {
+ }
+ return false ;
+ }
+
+
+ public void notifyStreamAccept(String status) throws IOException
+ {
+ if ( streamSession == null )
+ {
+ _log.error ( "BUG! Received stream connection, but session is null!" );
+ throw new NullPointerException ( "BUG! STREAM session is null!" );
+ }
+
+ if ( !writeString ( "STREAM STATUS RESULT="
+ + status
+ + "\n" ) )
+ {
+ throw new IOException ( "Error notifying connection to SAM client" );
+ }
+ }
+
+ public void notifyStreamOutgoingConnection(String result) throws IOException
+ {
+ if ( streamSession == null )
+ {
+ _log.error ( "BUG! Received stream connection, but session is null!" );
+ throw new NullPointerException ( "BUG! STREAM session is null!" );
+ }
+
+ if ( !writeString ( "STREAM STATUS RESULT="
+ + result
+ + "\n" ) )
+ {
+ throw new IOException ( "Error notifying connection to SAM client" );
+ }
+ }
+
+ public void notifyStreamIncomingConnection(Destination d) throws IOException {
+ if (streamSession == null) {
+ _log.error("BUG! Received stream connection, but session is null!");
+ throw new NullPointerException("BUG! STREAM session is null!");
+ }
+
+ if (!writeString(d.toBase64() + "\n")) {
+ throw new IOException("Error notifying connection to SAM client");
+ }
+ }
+
+ public static void notifyStreamIncomingConnection(SocketChannel client, Destination d) throws IOException {
+ if (!writeString(d.toBase64() + "\n", client)) {
+ throw new IOException("Error notifying connection to SAM client");
+ }
+ }
+
+}
+
diff --git a/apps/sam/java/src/net/i2p/sam/SAMv3RawSession.java b/apps/sam/java/src/net/i2p/sam/SAMv3RawSession.java
new file mode 100644
index 0000000000..1bf7d18a0b
--- /dev/null
+++ b/apps/sam/java/src/net/i2p/sam/SAMv3RawSession.java
@@ -0,0 +1,88 @@
+/**
+ *
+ */
+package net.i2p.sam;
+
+import java.io.IOException;
+import java.io.InterruptedIOException;
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
+import java.nio.ByteBuffer;
+import java.util.Properties;
+
+import net.i2p.client.I2PSessionException;
+import net.i2p.data.DataFormatException;
+import net.i2p.util.Log;
+
+/**
+ * @author MKVore
+ *
+ */
+public class SAMv3RawSession extends SAMRawSession implements SAMv3Handler.Session, SAMRawReceiver {
+
+ String nick = null ;
+ SAMv3Handler handler = null ;
+ SAMv3Handler.DatagramServer server ;
+ private final static Log _log = new Log ( SAMv3DatagramSession.class );
+ SocketAddress clientAddress = null ;
+
+ public String getNick() { return nick; }
+
+ /**
+ * @param nick nickname of the session
+ * @param server DatagramServer used for communication with the client
+ * @throws IOException
+ * @throws DataFormatException
+ * @throws I2PSessionException
+ */
+ public SAMv3RawSession(String nick)
+ throws IOException, DataFormatException, I2PSessionException {
+
+ super(SAMv3Handler.sSessionsHash.get(nick).getDest(),
+ SAMv3Handler.sSessionsHash.get(nick).getProps(),
+ SAMv3Handler.sSessionsHash.get(nick).getHandler()
+ );
+ this.nick = nick ;
+ this.recv = this ;
+ this.server = SAMv3Handler.DatagramServer.getInstance() ;
+
+ SAMv3Handler.SessionRecord rec = SAMv3Handler.sSessionsHash.get(nick);
+ if ( rec==null ) throw new InterruptedIOException() ;
+
+ this.handler = rec.getHandler();
+
+ Properties props = rec.getProps();
+
+
+ String portStr = props.getProperty("PORT") ;
+ if ( portStr==null ) {
+ _log.debug("receiver port not specified. Current socket will be used.");
+ }
+ else {
+ int port = Integer.parseInt(portStr);
+
+ String host = props.getProperty("HOST");
+ if ( host==null ) {
+ _log.debug("no host specified. Take from the client socket");
+
+ host = rec.getHandler().getClientIP();
+ }
+
+
+ this.clientAddress = new InetSocketAddress(host,port);
+ }
+ }
+
+ public void receiveRawBytes(byte[] data) throws IOException {
+ if (this.clientAddress==null) {
+ this.handler.receiveRawBytes(data);
+ } else {
+ ByteBuffer msgBuf = ByteBuffer.allocate(data.length);
+ msgBuf.put(data);
+ msgBuf.flip();
+ this.server.send(this.clientAddress, msgBuf);
+ }
+ }
+
+ public void stopRawReceiving() {}
+}
diff --git a/apps/sam/java/src/net/i2p/sam/SAMv3StreamSession.java b/apps/sam/java/src/net/i2p/sam/SAMv3StreamSession.java
new file mode 100644
index 0000000000..b9ea710c65
--- /dev/null
+++ b/apps/sam/java/src/net/i2p/sam/SAMv3StreamSession.java
@@ -0,0 +1,389 @@
+package net.i2p.sam;
+/*
+ * free (adj.): unencumbered; not under the control of others
+ * Written by human in 2004 and released into the public domain
+ * with no warranty of any kind, either expressed or implied.
+ * It probably won't make your computer catch on fire, or eat
+ * your children, but it might. Use at your own risk.
+ *
+ */
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InterruptedIOException;
+import java.net.ConnectException;
+import java.net.NoRouteToHostException;
+import java.util.Properties;
+
+import net.i2p.I2PException;
+import net.i2p.client.I2PClient;
+import net.i2p.client.streaming.I2PServerSocket;
+import net.i2p.client.streaming.I2PSocket;
+import net.i2p.client.streaming.I2PSocketManagerFactory;
+import net.i2p.client.streaming.I2PSocketOptions;
+import net.i2p.data.Base64;
+import net.i2p.data.DataFormatException;
+import net.i2p.data.Destination;
+import net.i2p.util.I2PAppThread;
+import net.i2p.util.Log;
+import java.nio.channels.Channels;
+import java.nio.channels.ReadableByteChannel;
+import java.nio.channels.WritableByteChannel;
+import java.nio.ByteBuffer ;
+import java.nio.channels.SocketChannel;
+
+/**
+ * SAMv3 STREAM session class.
+ *
+ * @author mkvore
+ */
+
+public class SAMv3StreamSession extends SAMStreamSession implements SAMv3Handler.Session
+{
+
+ private final static Log _log = new Log ( SAMv3StreamSession.class );
+
+ protected final int BUFFER_SIZE = 1024 ;
+
+ protected Object socketServerLock = new Object();
+ protected I2PServerSocket socketServer = null;
+
+ protected String nick ;
+
+ public String getNick() {
+ return nick ;
+ }
+
+ /**
+ * Create a new SAM STREAM session.
+ *
+ * @param dest Base64-encoded destination (private key)
+ * @param dir Session direction ("RECEIVE", "CREATE" or "BOTH")
+ * @param props Properties to setup the I2P session
+ * @param recv Object that will receive incoming data
+ * @throws IOException
+ * @throws DataFormatException
+ * @throws SAMException
+ */
+ public SAMv3StreamSession(String login)
+ throws IOException, DataFormatException, SAMException
+ {
+ initSAMStreamSession(login);
+ }
+
+ public static SAMv3Handler.SessionsDB getDB()
+ {
+ return SAMv3Handler.sSessionsHash ;
+ }
+
+ private void initSAMStreamSession(String login)
+ throws IOException, DataFormatException, SAMException{
+
+ SAMv3Handler.SessionRecord rec = getDB().get(login);
+ String dest = rec.getDest() ;
+ ByteArrayInputStream ba_dest = new ByteArrayInputStream(Base64.decode(dest));
+
+ this.recv = rec.getHandler();
+
+ _log.debug("SAM STREAM session instantiated");
+
+ Properties allprops = new Properties();
+ allprops.putAll(System.getProperties());
+ allprops.putAll(rec.getProps());
+
+ String i2cpHost = allprops.getProperty(I2PClient.PROP_TCP_HOST, "127.0.0.1");
+ int i2cpPort ;
+ String port = allprops.getProperty(I2PClient.PROP_TCP_PORT, "7654");
+ try {
+ i2cpPort = Integer.parseInt(port);
+ } catch (NumberFormatException nfe) {
+ throw new SAMException("Invalid I2CP port specified [" + port + "]");
+ }
+
+ _log.debug("Creating I2PSocketManager...");
+ socketMgr = I2PSocketManagerFactory.createManager(ba_dest,
+ i2cpHost,
+ i2cpPort,
+ allprops);
+ if (socketMgr == null) {
+ throw new SAMException("Error creating I2PSocketManager towards "+i2cpHost+":"+i2cpPort);
+ }
+
+ socketMgr.addDisconnectListener(new DisconnectListener());
+ this.nick = login ;
+ }
+
+ /**
+ * Connect the SAM STREAM session to the specified Destination
+ *
+ * @param id Unique id for the connection
+ * @param dest Base64-encoded Destination to connect to
+ * @param props Options to be used for connection
+ *
+ * @return true if successful
+ * @throws DataFormatException if the destination is not valid
+ * @throws ConnectException if the destination refuses connections
+ * @throws NoRouteToHostException if the destination can't be reached
+ * @throws InterruptedIOException if the connection timeouts
+ * @throws I2PException if there's another I2P-related error
+ * @throws IOException
+ */
+ public void connect ( SAMv3Handler handler, String dest, Properties props ) throws I2PException, ConnectException, NoRouteToHostException, DataFormatException, InterruptedIOException, IOException {
+
+ boolean verbose = (props.getProperty("SILENT", "false").equals("false"));
+ Destination d = new Destination();
+ d = SAMUtils.getDest(dest);
+
+ I2PSocketOptions opts = socketMgr.buildOptions(props);
+ if (props.getProperty(I2PSocketOptions.PROP_CONNECT_TIMEOUT) == null)
+ opts.setConnectTimeout(60 * 1000);
+
+ _log.debug("Connecting new I2PSocket...");
+
+ // blocking connection (SAMv3)
+
+ I2PSocket i2ps = socketMgr.connect(d, opts);
+
+ SAMv3Handler.SessionRecord rec = SAMv3Handler.sSessionsHash.get(nick);
+
+ if ( rec==null ) throw new InterruptedIOException() ;
+
+ if (verbose) handler.notifyStreamOutgoingConnection("OK") ;
+
+ handler.stealSocket() ;
+
+ ReadableByteChannel fromClient = handler.getClientSocket();
+ ReadableByteChannel fromI2P = Channels.newChannel(i2ps.getInputStream());
+ WritableByteChannel toClient = handler.getClientSocket();
+ WritableByteChannel toI2P = Channels.newChannel(i2ps.getOutputStream());
+
+ (new Thread(rec.getThreadGroup(), new I2PAppThread(new Pipe(fromClient,toI2P), "SAMPipeClientToI2P"))).start();
+ (new Thread(rec.getThreadGroup(), new I2PAppThread(new Pipe(fromI2P,toClient), "SAMPipeClientToI2P"))).start();
+
+ }
+
+ /**
+ * Accept an incoming STREAM
+ *
+ * @param id Unique id for the connection
+ * @param dest Base64-encoded Destination to connect to
+ * @param props Options to be used for connection
+ *
+ * @return true if successful
+ * @throws DataFormatException if the destination is not valid
+ * @throws ConnectException if the destination refuses connections
+ * @throws NoRouteToHostException if the destination can't be reached
+ * @throws InterruptedIOException if the connection timeouts
+ * @throws I2PException if there's another I2P-related error
+ * @throws IOException
+ */
+ public void accept(SAMv3Handler handler, boolean verbose)
+ throws I2PException, InterruptedIOException, IOException, SAMException {
+
+ synchronized( this.socketServerLock )
+ {
+ if (this.socketServer!=null) {
+ _log.debug("a socket server is already defined for this destination");
+ throw new SAMException("a socket server is already defined for this destination");
+ }
+ this.socketServer = this.socketMgr.getServerSocket();
+ }
+
+ I2PSocket i2ps;
+ i2ps = this.socketServer.accept();
+
+ synchronized( this.socketServerLock )
+ {
+ this.socketServer = null ;
+ }
+
+ SAMv3Handler.SessionRecord rec = SAMv3Handler.sSessionsHash.get(nick);
+
+ if ( rec==null ) throw new InterruptedIOException() ;
+
+ if (verbose)
+ handler.notifyStreamIncomingConnection(i2ps.getPeerDestination()) ;
+
+ handler.stealSocket() ;
+ ReadableByteChannel fromClient = handler.getClientSocket();
+ ReadableByteChannel fromI2P = Channels.newChannel(i2ps.getInputStream());
+ WritableByteChannel toClient = handler.getClientSocket();
+ WritableByteChannel toI2P = Channels.newChannel(i2ps.getOutputStream());
+
+ (new Thread(rec.getThreadGroup(), new I2PAppThread(new Pipe(fromClient,toI2P), "SAMPipeClientToI2P"))).start();
+ (new Thread(rec.getThreadGroup(), new I2PAppThread(new Pipe(fromI2P,toClient), "SAMPipeClientToI2P"))).start();
+ }
+
+
+ public void startForwardingIncoming( Properties props ) throws SAMException, InterruptedIOException
+ {
+ SAMv3Handler.SessionRecord rec = SAMv3Handler.sSessionsHash.get(nick);
+ boolean verbose = props.getProperty("SILENT", "false").equals("false");
+
+ if ( rec==null ) throw new InterruptedIOException() ;
+
+ String portStr = props.getProperty("PORT") ;
+ if ( portStr==null ) {
+ _log.debug("receiver port not specified");
+ throw new SAMException("receiver port not specified");
+ }
+ int port = Integer.parseInt(portStr);
+
+ String host = props.getProperty("HOST");
+ if ( host==null ) {
+ _log.debug("no host specified. Take from the client socket");
+
+ host = rec.getHandler().getClientIP();
+ }
+
+
+ synchronized( this.socketServerLock )
+ {
+ if (this.socketServer!=null) {
+ _log.debug("a socket server is already defined for this destination");
+ throw new SAMException("a socket server is already defined for this destination");
+ }
+ this.socketServer = this.socketMgr.getServerSocket();
+ }
+
+ SocketForwarder forwarder = new SocketForwarder(host, port, this, verbose);
+ (new Thread(rec.getThreadGroup(), new I2PAppThread(forwarder, "SAMStreamForwarder"))).start();
+
+ }
+
+ public class SocketForwarder extends Thread
+ {
+ String host = null ;
+ int port = 0 ;
+ SAMv3StreamSession session;
+ boolean verbose;
+
+ SocketForwarder(String host, int port, SAMv3StreamSession session, boolean verbose) {
+ this.host = host ;
+ this.port = port ;
+ this.session = session ;
+ this.verbose = verbose ;
+ }
+
+ public void run()
+ {
+ while (session.socketServer!=null) {
+
+ boolean available = false ;
+ I2PSocket i2ps = null ;
+ try {
+ available = session.socketServer.waitIncoming(-1);
+ } catch (ConnectException e) {
+ _log.debug("ConnectException");
+ break ;
+ } catch (I2PException e) {
+ _log.debug("I2PServerSocket has been closed");
+ break ;
+ } catch (InterruptedException e) {
+ _log.debug("InterruptedException");
+ break ;
+ }
+ if ( !available ) continue ;
+
+ java.net.InetSocketAddress addr = new java.net.InetSocketAddress(host,port);
+
+ SocketChannel clientServerSock = null ;
+ try {
+ clientServerSock = SocketChannel.open(addr) ;
+ }
+ catch ( IOException e ) {
+ continue ;
+ }
+
+ try {
+ i2ps = session.socketServer.accept(false);
+ } catch (Exception e) {}
+
+ if (i2ps==null) {
+ try {
+ clientServerSock.close();
+ } catch (IOException ee) {}
+ continue ;
+ }
+ try {
+ if (this.verbose)
+ SAMv3Handler.notifyStreamIncomingConnection(
+ clientServerSock, i2ps.getPeerDestination());
+ ReadableByteChannel fromClient = clientServerSock ;
+ ReadableByteChannel fromI2P = Channels.newChannel(i2ps.getInputStream());
+ WritableByteChannel toClient = clientServerSock ;
+ WritableByteChannel toI2P = Channels.newChannel(i2ps.getOutputStream());
+ new I2PAppThread(new Pipe(fromClient,toI2P), "SAMPipeClientToI2P").start();
+ new I2PAppThread(new Pipe(fromI2P,toClient), "SAMPipeClientToI2P").start();
+
+ } catch (IOException e) {
+ try {
+ clientServerSock.close();
+ } catch (IOException ee) {}
+ try {
+ i2ps.close();
+ } catch (IOException ee) {}
+ continue ;
+ }
+ }
+ }
+ }
+ public class Pipe extends Thread
+ {
+ ReadableByteChannel in ;
+ WritableByteChannel out ;
+ ByteBuffer buf ;
+
+ public Pipe(ReadableByteChannel in, WritableByteChannel out)
+ {
+ this.in = in ;
+ this.out = out ;
+ this.buf = ByteBuffer.allocate(BUFFER_SIZE) ;
+ }
+
+ public void run()
+ {
+ try {
+ while (!Thread.interrupted() && (in.read(buf)>=0 || buf.position() != 0)) {
+ buf.flip();
+ out.write(buf);
+ buf.compact();
+ }
+ }
+ catch (IOException e)
+ {
+ this.interrupt();
+ }
+ try {
+ in.close();
+ }
+ catch (IOException e) {}
+ try {
+ buf.flip();
+ while (buf.hasRemaining())
+ out.write(buf);
+ }
+ catch (IOException e) {}
+ try {
+ out.close();
+ }
+ catch (IOException e) {}
+ }
+ }
+
+
+
+ /**
+ * Close the stream session
+ */
+ @Override
+ public void close() {
+ socketMgr.destroySocketManager();
+ }
+
+ public boolean sendBytes(String s, byte[] b) throws DataFormatException
+ {
+ throw new DataFormatException(null);
+ }
+
+}
diff --git a/apps/sam/java/src/net/i2p/sam/client/SAMEventHandler.java b/apps/sam/java/src/net/i2p/sam/client/SAMEventHandler.java
index 7df1a23242..9df867aa55 100644
--- a/apps/sam/java/src/net/i2p/sam/client/SAMEventHandler.java
+++ b/apps/sam/java/src/net/i2p/sam/client/SAMEventHandler.java
@@ -12,17 +12,17 @@ import net.i2p.util.Log;
*
*/
public class SAMEventHandler extends SAMClientEventListenerImpl {
- private I2PAppContext _context;
+ //private I2PAppContext _context;
private Log _log;
private Boolean _helloOk;
private Object _helloLock = new Object();
private Boolean _sessionCreateOk;
private Object _sessionCreateLock = new Object();
private Object _namingReplyLock = new Object();
- private Map _namingReplies = new HashMap();
+ private Map _namingReplies = new HashMap();
public SAMEventHandler(I2PAppContext ctx) {
- _context = ctx;
+ //_context = ctx;
_log = ctx.logManager().getLog(getClass());
}
diff --git a/apps/sam/java/src/net/i2p/sam/client/SAMStreamSend.java b/apps/sam/java/src/net/i2p/sam/client/SAMStreamSend.java
index 4e9d1133b0..80db744a31 100644
--- a/apps/sam/java/src/net/i2p/sam/client/SAMStreamSend.java
+++ b/apps/sam/java/src/net/i2p/sam/client/SAMStreamSend.java
@@ -31,10 +31,10 @@ public class SAMStreamSend {
private OutputStream _samOut;
private InputStream _samIn;
private SAMReader _reader;
- private boolean _dead;
+ //private boolean _dead;
private SAMEventHandler _eventHandler;
/** Connection id (Integer) to peer (Flooder) */
- private Map _remotePeers;
+ private Map _remotePeers;
public static void main(String args[]) {
if (args.length < 4) {
@@ -42,7 +42,7 @@ public class SAMStreamSend {
return;
}
I2PAppContext ctx = new I2PAppContext();
- String files[] = new String[args.length - 3];
+ //String files[] = new String[args.length - 3];
SAMStreamSend sender = new SAMStreamSend(ctx, args[0], args[1], args[2], args[3]);
sender.startup();
}
@@ -50,14 +50,14 @@ public class SAMStreamSend {
public SAMStreamSend(I2PAppContext ctx, String samHost, String samPort, String destFile, String dataFile) {
_context = ctx;
_log = ctx.logManager().getLog(SAMStreamSend.class);
- _dead = false;
+ //_dead = false;
_samHost = samHost;
_samPort = samPort;
_destFile = destFile;
_dataFile = dataFile;
_conOptions = "";
_eventHandler = new SendEventHandler(_context);
- _remotePeers = new HashMap();
+ _remotePeers = new HashMap();
}
public void startup() {
@@ -207,7 +207,6 @@ public class SAMStreamSend {
_started = _context.clock().now();
_context.statManager().addRateData("send." + _connectionId + ".started", 1, 0);
byte data[] = new byte[1024];
- long value = 0;
long lastSend = _context.clock().now();
while (!_closed) {
try {
diff --git a/apps/sam/java/src/net/i2p/sam/client/SAMStreamSink.java b/apps/sam/java/src/net/i2p/sam/client/SAMStreamSink.java
index 8d29e37994..406150b367 100644
--- a/apps/sam/java/src/net/i2p/sam/client/SAMStreamSink.java
+++ b/apps/sam/java/src/net/i2p/sam/client/SAMStreamSink.java
@@ -31,10 +31,10 @@ public class SAMStreamSink {
private OutputStream _samOut;
private InputStream _samIn;
private SAMReader _reader;
- private boolean _dead;
+ //private boolean _dead;
private SAMEventHandler _eventHandler;
/** Connection id (Integer) to peer (Flooder) */
- private Map _remotePeers;
+ private Map _remotePeers;
public static void main(String args[]) {
if (args.length < 4) {
@@ -49,14 +49,14 @@ public class SAMStreamSink {
public SAMStreamSink(I2PAppContext ctx, String samHost, String samPort, String destFile, String sinkDir) {
_context = ctx;
_log = ctx.logManager().getLog(SAMStreamSink.class);
- _dead = false;
+ //_dead = false;
_samHost = samHost;
_samPort = samPort;
_destFile = destFile;
_sinkDir = sinkDir;
_conOptions = "";
_eventHandler = new SinkEventHandler(_context);
- _remotePeers = new HashMap();
+ _remotePeers = new HashMap();
}
public void startup() {
@@ -70,7 +70,8 @@ public class SAMStreamSink {
String ourDest = handshake();
_log.debug("Handshake complete. we are " + ourDest);
if (ourDest != null) {
- boolean written = writeDest(ourDest);
+ //boolean written =
+ writeDest(ourDest);
_log.debug("Dest written");
}
}
diff --git a/apps/streaming/java/src/net/i2p/client/streaming/ConnectionHandler.java b/apps/streaming/java/src/net/i2p/client/streaming/ConnectionHandler.java
index 7d1d4827f8..35eca57e5f 100644
--- a/apps/streaming/java/src/net/i2p/client/streaming/ConnectionHandler.java
+++ b/apps/streaming/java/src/net/i2p/client/streaming/ConnectionHandler.java
@@ -1,9 +1,11 @@
package net.i2p.client.streaming;
+import java.net.ConnectException;
import java.util.ArrayList;
import java.util.List;
import net.i2p.I2PAppContext;
+import net.i2p.util.Clock;
import net.i2p.util.Log;
import net.i2p.util.SimpleTimer;
@@ -14,7 +16,7 @@ class ConnectionHandler {
private I2PAppContext _context;
private Log _log;
private ConnectionManager _manager;
- private List _synQueue;
+ private List _synQueue;
private boolean _active;
private int _acceptTimeout;
@@ -61,13 +63,45 @@ class ConnectionHandler {
}
}
+ public boolean waitSyn( long ms ) throws InterruptedException {
+ boolean incoming = false ;
+ boolean isTimed = (ms>=0);
+
+ Clock clock = I2PAppContext.getGlobalContext().clock();
+ long now = clock.now();
+ long end = now + ms;
+ while (!incoming && (!isTimed || now<=end) ) {
+ synchronized (_synQueue) {
+
+ for (Packet p : _synQueue)
+ {
+ if (p.isFlagSet(Packet.FLAG_SYNCHRONIZE)) {
+ incoming = true ;
+ break;
+ }
+ }
+ if (!incoming) {
+ if (!isTimed) {
+ _synQueue.wait();
+ } else {
+ now = clock.now();
+ if (now < end) {
+ _synQueue.wait(end-now);
+ }
+ }
+ }
+ }
+ }
+ return incoming ;
+ }
+
/**
* Receive an incoming connection (built from a received SYN)
* Non-SYN packets with a zero SendStreamID may also be queued here so
* that they don't get thrown away while the SYN packet before it is queued.
*
- * @param timeoutMs max amount of time to wait for a connection (if less
- * than 1ms, wait indefinitely)
+ * @param timeoutMs max amount of time to wait for a connection (if negative,
+ * wait indefinitely)
* @return connection received, or null if there was a timeout or the
* handler was shut down
*/
@@ -77,8 +111,6 @@ class ConnectionHandler {
long expiration = timeoutMs + _context.clock().now();
while (true) {
- if ( (timeoutMs > 0) && (expiration < _context.clock().now()) )
- return null;
if (!_active) {
// fail all the ones we had queued up
synchronized (_synQueue) {
@@ -97,7 +129,7 @@ class ConnectionHandler {
if (_log.shouldLog(Log.DEBUG))
_log.debug("Accept("+ timeoutMs+"): active=" + _active + " queue: "
+ _synQueue.size());
- if (timeoutMs <= 0) {
+ if (timeoutMs < 0) {
try { _synQueue.wait(); } catch (InterruptedException ie) {}
} else {
long remaining = expiration - _context.clock().now();
@@ -129,6 +161,8 @@ class ConnectionHandler {
}
}
// keep looping...
+ if ( (timeoutMs >= 0) && (expiration < _context.clock().now()) )
+ return null;
}
}
diff --git a/apps/streaming/java/src/net/i2p/client/streaming/I2PServerSocketFull.java b/apps/streaming/java/src/net/i2p/client/streaming/I2PServerSocketFull.java
index 83f7c8376a..ab9cb1c9d4 100644
--- a/apps/streaming/java/src/net/i2p/client/streaming/I2PServerSocketFull.java
+++ b/apps/streaming/java/src/net/i2p/client/streaming/I2PServerSocketFull.java
@@ -1,7 +1,12 @@
package net.i2p.client.streaming;
+import java.net.ConnectException;
import java.net.SocketTimeoutException;
+
+import net.i2p.I2PAppContext;
import net.i2p.I2PException;
+import net.i2p.util.Clock;
+import net.i2p.util.Log;
/**
* Bridge to allow accepting new connections
@@ -45,4 +50,43 @@ public class I2PServerSocketFull implements I2PServerSocket {
public I2PSocketManager getManager() {
return _socketManager;
}
+
+ /**
+ * accept(true) has the same behaviour as accept().
+ * accept(false) does not wait for a socket connecting. If a socket is
+ * available in the queue, it is accepted. Else, null is returned.
+ *
+ * @param true if the call should block until a socket is available
+ *
+ * @return a connected I2PSocket, or null
+ *
+ * @throws I2PException if there is a problem with reading a new socket
+ * from the data available (aka the I2PSession closed, etc)
+ * @throws SocketTimeoutException if the timeout has been reached
+ */
+
+ public I2PSocket accept(boolean blocking) throws I2PException, SocketTimeoutException {
+ long timeout = this.getSoTimeout();
+
+ try {
+ if (blocking)
+ {
+ this.setSoTimeout(-1);
+ } else {
+ this.setSoTimeout(0);
+ }
+ try {
+ return this.accept();
+ } catch (SocketTimeoutException e) {
+ if (blocking) throw e;
+ else return null ;
+ }
+ } finally {
+ this.setSoTimeout(timeout);
+ }
+ }
+
+ public boolean waitIncoming(long timeoutMs) throws InterruptedException {
+ return this._socketManager.getConnectionManager().getConnectionHandler().waitSyn(timeoutMs);
+ }
}
From e0dccb59705afa45cff809c791f5b4a013a109f4 Mon Sep 17 00:00:00 2001
From: mkvore-commit
Date: Thu, 2 Apr 2009 08:54:28 +0000
Subject: [PATCH 073/688]
---
.../client/streaming/ConnectionHandler.java | 30 +------------------
1 file changed, 1 insertion(+), 29 deletions(-)
diff --git a/apps/streaming/java/src/net/i2p/client/streaming/ConnectionHandler.java b/apps/streaming/java/src/net/i2p/client/streaming/ConnectionHandler.java
index 35eca57e5f..a189d9a308 100644
--- a/apps/streaming/java/src/net/i2p/client/streaming/ConnectionHandler.java
+++ b/apps/streaming/java/src/net/i2p/client/streaming/ConnectionHandler.java
@@ -64,35 +64,7 @@ class ConnectionHandler {
}
public boolean waitSyn( long ms ) throws InterruptedException {
- boolean incoming = false ;
- boolean isTimed = (ms>=0);
-
- Clock clock = I2PAppContext.getGlobalContext().clock();
- long now = clock.now();
- long end = now + ms;
- while (!incoming && (!isTimed || now<=end) ) {
- synchronized (_synQueue) {
-
- for (Packet p : _synQueue)
- {
- if (p.isFlagSet(Packet.FLAG_SYNCHRONIZE)) {
- incoming = true ;
- break;
- }
- }
- if (!incoming) {
- if (!isTimed) {
- _synQueue.wait();
- } else {
- now = clock.now();
- if (now < end) {
- _synQueue.wait(end-now);
- }
- }
- }
- }
- }
- return incoming ;
+ throw new InterruptedException();
}
/**
From 53cb80636a957db640c3c4444e2e8f08e060b5c1 Mon Sep 17 00:00:00 2001
From: zzz
Date: Thu, 2 Apr 2009 18:12:38 +0000
Subject: [PATCH 074/688] remove dup comment in persisted profiles
---
core/java/src/net/i2p/stat/RateStat.java | 1 -
1 file changed, 1 deletion(-)
diff --git a/core/java/src/net/i2p/stat/RateStat.java b/core/java/src/net/i2p/stat/RateStat.java
index 329706040c..dd1fe63e3f 100644
--- a/core/java/src/net/i2p/stat/RateStat.java
+++ b/core/java/src/net/i2p/stat/RateStat.java
@@ -134,7 +134,6 @@ public class RateStat {
buf.append("# Period : ").append(DataHelper.formatDuration(_rates[i].getPeriod())).append(" for rate ")
.append(_groupName).append(" - ").append(_statName).append(NL);
buf.append(NL);
- out.write(buf.toString().getBytes());
String curPrefix = prefix + "." + DataHelper.formatDuration(_rates[i].getPeriod());
_rates[i].store(curPrefix, buf);
out.write(buf.toString().getBytes());
From f6bc9e87072a26ced4e22311751ae028d4b14efe Mon Sep 17 00:00:00 2001
From: zzz
Date: Thu, 2 Apr 2009 18:55:40 +0000
Subject: [PATCH 075/688] Profiles: - Remove unused calculators and
RateStats: CapacityCalculator, StrictSpeedCalculator,
IsFailingCalculator; sendFailureSize, processSuccessRate,
processfailureRate, commErrorRate, tunnelTestResponseTimeSlow - Reduced
number of Rates in these RateStats: sendSuccessSize, receiveSize,
rejectRate, failRate - ~5KB/profile savings total - Deflate speed
calculation once an hour instead of once a day, to improve fast tier
selection
---
.../src/net/i2p/router/RouterContext.java | 10 --
.../peermanager/IsFailingCalculator.java | 82 --------------
.../i2p/router/peermanager/PeerProfile.java | 103 +++---------------
.../peermanager/ProfileManagerImpl.java | 6 -
.../router/peermanager/ProfileOrganizer.java | 4 +-
.../peermanager/ProfilePersistenceHelper.java | 7 --
.../peermanager/ReliabilityCalculator.java | 91 ----------------
.../peermanager/StrictSpeedCalculator.java | 90 ---------------
.../i2p/router/peermanager/TunnelHistory.java | 27 +----
9 files changed, 21 insertions(+), 399 deletions(-)
delete mode 100644 router/java/src/net/i2p/router/peermanager/IsFailingCalculator.java
delete mode 100644 router/java/src/net/i2p/router/peermanager/ReliabilityCalculator.java
delete mode 100644 router/java/src/net/i2p/router/peermanager/StrictSpeedCalculator.java
diff --git a/router/java/src/net/i2p/router/RouterContext.java b/router/java/src/net/i2p/router/RouterContext.java
index 517a5ba358..e3b5e38466 100644
--- a/router/java/src/net/i2p/router/RouterContext.java
+++ b/router/java/src/net/i2p/router/RouterContext.java
@@ -16,9 +16,7 @@ import net.i2p.router.peermanager.IsFailingCalculator;
import net.i2p.router.peermanager.PeerManagerFacadeImpl;
import net.i2p.router.peermanager.ProfileManagerImpl;
import net.i2p.router.peermanager.ProfileOrganizer;
-import net.i2p.router.peermanager.ReliabilityCalculator;
import net.i2p.router.peermanager.SpeedCalculator;
-import net.i2p.router.peermanager.StrictSpeedCalculator;
import net.i2p.router.transport.CommSystemFacadeImpl;
import net.i2p.router.transport.FIFOBandwidthLimiter;
import net.i2p.router.transport.OutboundMessageRegistry;
@@ -65,9 +63,7 @@ public class RouterContext extends I2PAppContext {
private Calculator _isFailingCalc;
private Calculator _integrationCalc;
private Calculator _speedCalc;
- private Calculator _reliabilityCalc;
private Calculator _capacityCalc;
- private Calculator _oldSpeedCalc;
private static List _contexts = new ArrayList(1);
@@ -135,8 +131,6 @@ public class RouterContext extends I2PAppContext {
_isFailingCalc = new IsFailingCalculator(this);
_integrationCalc = new IntegrationCalculator(this);
_speedCalc = new SpeedCalculator(this);
- _oldSpeedCalc = new StrictSpeedCalculator(this);
- _reliabilityCalc = new ReliabilityCalculator(this);
_capacityCalc = new CapacityCalculator(this);
}
@@ -270,9 +264,6 @@ public class RouterContext extends I2PAppContext {
public Calculator integrationCalculator() { return _integrationCalc; }
/** how do we rank the speed of profiles? */
public Calculator speedCalculator() { return _speedCalc; }
- public Calculator oldSpeedCalculator() { return _oldSpeedCalc; }
- /** how do we rank the reliability of profiles? */
- public Calculator reliabilityCalculator() { return _reliabilityCalc; }
/** how do we rank the capacity of profiles? */
public Calculator capacityCalculator() { return _capacityCalc; }
@@ -301,7 +292,6 @@ public class RouterContext extends I2PAppContext {
buf.append(_isFailingCalc).append('\n');
buf.append(_integrationCalc).append('\n');
buf.append(_speedCalc).append('\n');
- buf.append(_reliabilityCalc).append('\n');
return buf.toString();
}
diff --git a/router/java/src/net/i2p/router/peermanager/IsFailingCalculator.java b/router/java/src/net/i2p/router/peermanager/IsFailingCalculator.java
deleted file mode 100644
index 1391bd8a1e..0000000000
--- a/router/java/src/net/i2p/router/peermanager/IsFailingCalculator.java
+++ /dev/null
@@ -1,82 +0,0 @@
-package net.i2p.router.peermanager;
-
-import net.i2p.router.RouterContext;
-import net.i2p.util.Log;
-
-/**
- * Simple boolean calculation to determine whether the given profile is "failing" -
- * meaning we shouldn't bother trying to get them to do something. However, if we
- * have a specific need to contact them in particular - e.g. instructions in a garlic
- * or leaseSet - we will try. The currently implemented algorithm determines that
- * a profile is failing if withing the last few minutes, they've done something bad:
- *
It has a comm error (TCP disconnect, etc) in the last minute or two
- *
They've failed to respond to a db message in the last minute or two
- *
They've rejected a tunnel in the last 5 minutes
- *
They've been unreachable any time in the last 5 minutes
- *
- *
- */
-public class IsFailingCalculator extends Calculator {
- private Log _log;
- private RouterContext _context;
-
- /** if they haven't b0rked in the last 2 minutes, they're ok */
- private final static long GRACE_PERIOD = 2*60*1000;
-
- public IsFailingCalculator(RouterContext context) {
- _context = context;
- _log = context.logManager().getLog(IsFailingCalculator.class);
- }
-
- public boolean calcBoolean(PeerProfile profile) {
- // have we failed in the last 119 seconds?
- /*
- if ( (profile.getCommError().getRate(60*1000).getCurrentEventCount() > 0) ||
- (profile.getCommError().getRate(60*1000).getLastEventCount() > 0) ||
- (profile.getCommError().getRate(10*60*1000).getCurrentEventCount() > 0) ) {
- if (_log.shouldLog(Log.DEBUG))
- _log.debug("Peer " + profile.getPeer().toBase64()
- + " is failing because it had a comm error recently ");
- return true;
- } else {
- */
- //if ( (profile.getDBHistory().getFailedLookupRate().getRate(60*1000).getCurrentEventCount() > 0) ||
- // (profile.getDBHistory().getFailedLookupRate().getRate(60*1000).getLastEventCount() > 0) ) {
- // // are they overloaded (or disconnected)?
- // return true;
- //}
-
- // this doesn't make sense with probabalistic rejections - we should be
- // adequately dampening the capacity so these peers aren't queried
-
- //Rate rejectRate = profile.getTunnelHistory().getRejectionRate().getRate(10*60*1000);
- //if (rejectRate.getCurrentEventCount() >= 2) {
- // if (_log.shouldLog(Log.DEBUG))
- // _log.debug("Peer " + profile.getPeer().toBase64()
- // + " is failing because they rejected some tunnels recently");
- // return true;
- //}
-
- ////
- // the right way to behave would be to use some statistical
- // analysis on the failure rate, and only mark the peer as failing
- // if their rate exceeded the expected rate (mean, median, stddev, etc)
- ////
-
- //Rate failedRate = profile.getTunnelHistory().getFailedRate().getRate(60*1000);
- //if (failedRate.getCurrentEventCount() >= 2) {
- // if (_log.shouldLog(Log.DEBUG))
- // _log.debug("Peer " + profile.getPeer().toBase64()
- // + " is failing because too many of their tunnels failed recently");
- // return true;
- //}
-
- // if they have rejected us saying they're totally broken anytime in the last
- // 10 minutes, dont bother 'em
- if (profile.getTunnelHistory().getLastRejectedCritical() > _context.clock().now() - 10*60*1000)
- return true;
-
- return false;
- //}
- }
-}
diff --git a/router/java/src/net/i2p/router/peermanager/PeerProfile.java b/router/java/src/net/i2p/router/peermanager/PeerProfile.java
index 4a94100bda..5c058b4938 100644
--- a/router/java/src/net/i2p/router/peermanager/PeerProfile.java
+++ b/router/java/src/net/i2p/router/peermanager/PeerProfile.java
@@ -37,25 +37,19 @@ public class PeerProfile {
private double _tunnelTestResponseTimeAvg;
// periodic rates
private RateStat _sendSuccessSize = null;
- private RateStat _sendFailureSize = null;
private RateStat _receiveSize = null;
private RateStat _dbResponseTime = null;
private RateStat _tunnelCreateResponseTime = null;
private RateStat _tunnelTestResponseTime = null;
- private RateStat _tunnelTestResponseTimeSlow = null;
- private RateStat _commError = null;
private RateStat _dbIntroduction = null;
// calculation bonuses
private long _speedBonus;
- private long _reliabilityBonus;
private long _capacityBonus;
private long _integrationBonus;
// calculation values
private double _speedValue;
- private double _reliabilityValue;
private double _capacityValue;
private double _integrationValue;
- private double _oldSpeedValue;
private boolean _isFailing;
// good vs bad behavior
private TunnelHistory _tunnelHistory;
@@ -72,7 +66,6 @@ public class PeerProfile {
_log = context.logManager().getLog(PeerProfile.class);
_expanded = false;
_speedValue = 0;
- _reliabilityValue = 0;
_capacityValue = 0;
_integrationValue = 0;
_isFailing = false;
@@ -111,6 +104,11 @@ public class PeerProfile {
* given period?)
* Also mark active if it is connected, as this will tend to encourage use
* of already-connected peers.
+ *
+ * Note: this appears to be the only use for these two RateStats.
+ *
+ * @param period must be one of the periods in the RateStat constructors below
+ * (5*60*1000 or 60*60*1000)
*/
public boolean getIsActive(long period) {
if ( (getSendSuccessSize().getRate(period).getCurrentEventCount() > 0) ||
@@ -154,8 +152,6 @@ public class PeerProfile {
/** how large successfully sent messages are, calculated over a 1 minute, 1 hour, and 1 day period */
public RateStat getSendSuccessSize() { return _sendSuccessSize; }
- /** how large messages that could not be sent were, calculated over a 1 minute, 1 hour, and 1 day period */
- public RateStat getSendFailureSize() { return _sendFailureSize; }
/** how large received messages are, calculated over a 1 minute, 1 hour, and 1 day period */
public RateStat getReceiveSize() { return _receiveSize; }
/** how long it takes to get a db response from the peer (in milliseconds), calculated over a 1 minute, 1 hour, and 1 day period */
@@ -164,10 +160,6 @@ public class PeerProfile {
public RateStat getTunnelCreateResponseTime() { return _tunnelCreateResponseTime; }
/** how long it takes to successfully test a tunnel this peer participates in (in milliseconds), calculated over a 10 minute, 1 hour, and 1 day period */
public RateStat getTunnelTestResponseTime() { return _tunnelTestResponseTime; }
- /** how long it takes to successfully test the peer (in milliseconds) when the time exceeds 5s */
- public RateStat getTunnelTestResponseTimeSlow() { return _tunnelTestResponseTimeSlow; }
- /** how long between communication errors with the peer (disconnection, etc), calculated over a 1 minute, 1 hour, and 1 day period */
- public RateStat getCommError() { return _commError; }
/** how many new peers we get from dbSearchReplyMessages or dbStore messages, calculated over a 1 hour, 1 day, and 1 week period */
public RateStat getDbIntroduction() { return _dbIntroduction; }
@@ -179,14 +171,6 @@ public class PeerProfile {
public long getSpeedBonus() { return _speedBonus; }
public void setSpeedBonus(long bonus) { _speedBonus = bonus; }
- /**
- * extra factor added to the reliability ranking - this can be updated in the profile
- * written to disk to affect how the algorithm ranks reliability. Negative values are
- * penalties
- */
- public long getReliabilityBonus() { return _reliabilityBonus; }
- public void setReliabilityBonus(long bonus) { _reliabilityBonus = bonus; }
-
/**
* extra factor added to the capacity ranking - this can be updated in the profile
* written to disk to affect how the algorithm ranks capacity. Negative values are
@@ -210,14 +194,6 @@ public class PeerProfile {
*
*/
public double getSpeedValue() { return _speedValue; }
- public double getOldSpeedValue() { return _oldSpeedValue; }
- /**
- * How likely are they to stay up and pass on messages over the next few minutes.
- * Positive numbers means more likely, negative numbers means its probably not
- * even worth trying.
- *
- */
- public double getReliabilityValue() { return _reliabilityValue; }
/**
* How many tunnels do we think this peer can handle over the next hour?
*
@@ -354,13 +330,10 @@ public class PeerProfile {
*/
public void shrinkProfile() {
_sendSuccessSize = null;
- _sendFailureSize = null;
_receiveSize = null;
_dbResponseTime = null;
_tunnelCreateResponseTime = null;
_tunnelTestResponseTime = null;
- _tunnelTestResponseTimeSlow = null;
- _commError = null;
_dbIntroduction = null;
_tunnelHistory = null;
_dbHistory = null;
@@ -378,21 +351,15 @@ public class PeerProfile {
public void expandProfile() {
String group = (null == _peer ? "profileUnknown" : _peer.toBase64().substring(0,6));
if (_sendSuccessSize == null)
- _sendSuccessSize = new RateStat("sendSuccessSize", "How large successfully sent messages are", group, new long[] { 60*1000l, 5*60*1000l, 60*60*1000l, 24*60*60*1000l });
- if (_sendFailureSize == null)
- _sendFailureSize = new RateStat("sendFailureSize", "How large messages that could not be sent were", group, new long[] { 60*1000l, 60*60*1000l, 24*60*60*1000 } );
+ _sendSuccessSize = new RateStat("sendSuccessSize", "How large successfully sent messages are", group, new long[] { 5*60*1000l, 60*60*1000l });
if (_receiveSize == null)
- _receiveSize = new RateStat("receiveSize", "How large received messages are", group, new long[] { 60*1000l, 5*60*1000l, 60*60*1000l, 24*60*60*1000 } );
+ _receiveSize = new RateStat("receiveSize", "How large received messages are", group, new long[] { 5*60*1000l, 60*60*1000l } );
if (_dbResponseTime == null)
_dbResponseTime = new RateStat("dbResponseTime", "how long it takes to get a db response from the peer (in milliseconds)", group, new long[] { 10*60*1000l, 60*60*1000l, 24*60*60*1000 } );
if (_tunnelCreateResponseTime == null)
_tunnelCreateResponseTime = new RateStat("tunnelCreateResponseTime", "how long it takes to get a tunnel create response from the peer (in milliseconds)", group, new long[] { 10*60*1000l, 30*60*1000l, 60*60*1000l, 24*60*60*1000 } );
if (_tunnelTestResponseTime == null)
_tunnelTestResponseTime = new RateStat("tunnelTestResponseTime", "how long it takes to successfully test a tunnel this peer participates in (in milliseconds)", group, new long[] { 10*60*1000l, 30*60*1000l, 60*60*1000l, 3*60*60*1000l, 24*60*60*1000 } );
- if (_tunnelTestResponseTimeSlow == null)
- _tunnelTestResponseTimeSlow = new RateStat("tunnelTestResponseTimeSlow", "how long it takes to successfully test a peer when the time exceeds 5s", group, new long[] { 10*60*1000l, 30*60*1000l, 60*60*1000l, 3*60*60*1000l, 24*60*60*1000l, });
- if (_commError == null)
- _commError = new RateStat("commErrorRate", "how long between communication errors with the peer (e.g. disconnection)", group, new long[] { 60*1000l, 10*60*1000l, 60*60*1000l, 24*60*60*1000 } );
if (_dbIntroduction == null)
_dbIntroduction = new RateStat("dbIntroduction", "how many new peers we get from dbSearchReplyMessages or dbStore messages", group, new long[] { 60*60*1000l, 6*60*60*1000l, 24*60*60*1000l });
@@ -402,18 +369,17 @@ public class PeerProfile {
_dbHistory = new DBHistory(_context, group);
_sendSuccessSize.setStatLog(_context.statManager().getStatLog());
- _sendFailureSize.setStatLog(_context.statManager().getStatLog());
_receiveSize.setStatLog(_context.statManager().getStatLog());
_dbResponseTime.setStatLog(_context.statManager().getStatLog());
_tunnelCreateResponseTime.setStatLog(_context.statManager().getStatLog());
_tunnelTestResponseTime.setStatLog(_context.statManager().getStatLog());
- _tunnelTestResponseTimeSlow.setStatLog(_context.statManager().getStatLog());
- _commError.setStatLog(_context.statManager().getStatLog());
_dbIntroduction.setStatLog(_context.statManager().getStatLog());
_expanded = true;
}
/** once a day, on average, cut the measured throughtput values in half */
- private static final long DROP_PERIOD_MINUTES = 24*60;
+ /** let's try once an hour times 3/4 */
+ private static final int DROP_PERIOD_MINUTES = 60;
+ private static final double DEGRADE_FACTOR = 0.75;
private long _lastCoalesceDate = System.currentTimeMillis();
private void coalesceThroughput() {
long now = System.currentTimeMillis();
@@ -430,46 +396,19 @@ public class PeerProfile {
break;
}
}
-
- if (false && _log.shouldLog(Log.WARN) ) {
- StringBuffer buf = new StringBuffer(128);
- buf.append("Updating throughput after ").append(tot).append(" to ");
- for (int i = 0; i < THROUGHPUT_COUNT; i++)
- buf.append(_peakThroughput[i]).append(',');
- buf.append(" for ").append(_peer.toBase64());
- _log.warn(buf.toString());
- }
} else {
- if (_context.random().nextLong(DROP_PERIOD_MINUTES*2) <= 0) {
- for (int i = 0; i < THROUGHPUT_COUNT; i++)
- _peakThroughput[i] /= 2;
-
- if (false && _log.shouldLog(Log.WARN) ) {
- StringBuffer buf = new StringBuffer(128);
- buf.append("Degrading the throughput measurements to ");
- for (int i = 0; i < THROUGHPUT_COUNT; i++)
- buf.append(_peakThroughput[i]).append(',');
- buf.append(" for ").append(_peer.toBase64());
- _log.warn(buf.toString());
- }
+ if (_context.random().nextInt(DROP_PERIOD_MINUTES*2) <= 0) {
+ for (int i = 0; i < THROUGHPUT_COUNT; i++)
+ _peakThroughput[i] *= DEGRADE_FACTOR;
}
}
// we degrade the tunnel throughput here too, regardless of the current
// activity
- if (_context.random().nextLong(DROP_PERIOD_MINUTES*2) <= 0) {
+ if (_context.random().nextInt(DROP_PERIOD_MINUTES*2) <= 0) {
for (int i = 0; i < THROUGHPUT_COUNT; i++) {
- _peakTunnelThroughput[i] /= 2;
- _peakTunnel1mThroughput[i] /= 2;
- }
-
- if (_log.shouldLog(Log.WARN) ) {
- StringBuffer buf = new StringBuffer(128);
- buf.append("Degrading the tunnel throughput measurements to ");
- for (int i = 0; i < THROUGHPUT_COUNT; i++)
- buf.append(_peakTunnel1mThroughput[i]).append(',');
- buf.append(" for ").append(_peer.toBase64());
- _log.warn(buf.toString());
+ _peakTunnelThroughput[i] *= DEGRADE_FACTOR;
+ _peakTunnel1mThroughput[i] *= DEGRADE_FACTOR;
}
}
_peakThroughputCurrentTotal = 0;
@@ -480,34 +419,27 @@ public class PeerProfile {
/** update the stats and rates (this should be called once a minute) */
public void coalesceStats() {
if (!_expanded) return;
- _commError.coalesceStats();
_dbIntroduction.coalesceStats();
_dbResponseTime.coalesceStats();
_receiveSize.coalesceStats();
- _sendFailureSize.coalesceStats();
_sendSuccessSize.coalesceStats();
_tunnelCreateResponseTime.coalesceStats();
_tunnelTestResponseTime.coalesceStats();
- _tunnelTestResponseTimeSlow.coalesceStats();
_dbHistory.coalesceStats();
_tunnelHistory.coalesceStats();
coalesceThroughput();
_speedValue = calculateSpeed();
- _oldSpeedValue = calculateOldSpeed();
- _reliabilityValue = calculateReliability();
_capacityValue = calculateCapacity();
_integrationValue = calculateIntegration();
_isFailing = calculateIsFailing();
if (_log.shouldLog(Log.DEBUG))
- _log.debug("Coalesced: speed [" + _speedValue + "] reliability [" + _reliabilityValue + "] capacity [" + _capacityValue + "] integration [" + _integrationValue + "] failing? [" + _isFailing + "]");
+ _log.debug("Coalesced: speed [" + _speedValue + "] capacity [" + _capacityValue + "] integration [" + _integrationValue + "] failing? [" + _isFailing + "]");
}
private double calculateSpeed() { return _context.speedCalculator().calc(this); }
- private double calculateOldSpeed() { return _context.oldSpeedCalculator().calc(this); }
- private double calculateReliability() { return _context.reliabilityCalculator().calc(this); }
private double calculateCapacity() { return _context.capacityCalculator().calc(this); }
private double calculateIntegration() { return _context.integrationCalculator().calc(this); }
private boolean calculateIsFailing() { return _context.isFailingCalculator().calcBoolean(this); }
@@ -584,7 +516,6 @@ public class PeerProfile {
//profile.coalesceStats();
buf.append("Peer " + profile.getPeer().toBase64()
+ ":\t Speed:\t" + fmt.format(profile.calculateSpeed())
- + " Reliability:\t" + fmt.format(profile.calculateReliability())
+ " Capacity:\t" + fmt.format(profile.calculateCapacity())
+ " Integration:\t" + fmt.format(profile.calculateIntegration())
+ " Active?\t" + profile.getIsActive()
diff --git a/router/java/src/net/i2p/router/peermanager/ProfileManagerImpl.java b/router/java/src/net/i2p/router/peermanager/ProfileManagerImpl.java
index 9e789f9c6e..df7691bd16 100644
--- a/router/java/src/net/i2p/router/peermanager/ProfileManagerImpl.java
+++ b/router/java/src/net/i2p/router/peermanager/ProfileManagerImpl.java
@@ -50,7 +50,6 @@ public class ProfileManagerImpl implements ProfileManager {
PeerProfile data = getProfile(peer);
if (data == null) return;
data.setLastSendFailed(_context.clock().now());
- data.getSendFailureSize().addData(0, 0); // yeah, should be a frequency...
}
/**
@@ -61,7 +60,6 @@ public class ProfileManagerImpl implements ProfileManager {
PeerProfile data = getProfile(peer);
if (data == null) return;
data.setLastSendFailed(_context.clock().now());
- data.getSendFailureSize().addData(0, 0); // yeah, should be a frequency...
}
/**
@@ -74,8 +72,6 @@ public class ProfileManagerImpl implements ProfileManager {
PeerProfile data = getProfile(peer);
if (data == null) return;
data.setLastSendFailed(_context.clock().now());
- data.getSendFailureSize().addData(1, 0); // yeah, should be a frequency...
- data.getCommError().addData(1, 0); // see above
}
/**
@@ -125,8 +121,6 @@ public class ProfileManagerImpl implements ProfileManager {
if (data == null) return;
data.updateTunnelTestTimeAverage(responseTimeMs);
data.getTunnelTestResponseTime().addData(responseTimeMs, responseTimeMs);
- if (responseTimeMs > getSlowThreshold())
- data.getTunnelTestResponseTimeSlow().addData(responseTimeMs, responseTimeMs);
}
public void tunnelDataPushed(Hash peer, long rtt, int size) {
diff --git a/router/java/src/net/i2p/router/peermanager/ProfileOrganizer.java b/router/java/src/net/i2p/router/peermanager/ProfileOrganizer.java
index b090d6cc78..1a42a244c6 100644
--- a/router/java/src/net/i2p/router/peermanager/ProfileOrganizer.java
+++ b/router/java/src/net/i2p/router/peermanager/ProfileOrganizer.java
@@ -1028,7 +1028,7 @@ public class ProfileOrganizer {
/**
* called after locking the reorganizeLock, place the profile in the appropriate tier.
- * This is where we implement the (betterThanAverage ? goToPierX : goToPierY) algorithms
+ * This is where we implement the (betterThanAverage ? goToTierX : goToTierY) algorithms
*
*/
private void locked_placeProfile(PeerProfile profile) {
@@ -1153,7 +1153,6 @@ public class ProfileOrganizer {
organizer.isHighCapacity(peer) ? "IR " :
organizer.isFailing(peer) ? "IX " : "I ") + "]: "
+ "\t Speed:\t" + fmt.format(profile.getSpeedValue())
- + " Reliability:\t" + fmt.format(profile.getReliabilityValue())
+ " Capacity:\t" + fmt.format(profile.getCapacityValue())
+ " Integration:\t" + fmt.format(profile.getIntegrationValue())
+ " Active?\t" + profile.getIsActive()
@@ -1164,7 +1163,6 @@ public class ProfileOrganizer {
organizer.isHighCapacity(peer) ? "R " :
organizer.isFailing(peer) ? "X " : " ") + "]: "
+ "\t Speed:\t" + fmt.format(profile.getSpeedValue())
- + " Reliability:\t" + fmt.format(profile.getReliabilityValue())
+ " Capacity:\t" + fmt.format(profile.getCapacityValue())
+ " Integration:\t" + fmt.format(profile.getIntegrationValue())
+ " Active?\t" + profile.getIsActive()
diff --git a/router/java/src/net/i2p/router/peermanager/ProfilePersistenceHelper.java b/router/java/src/net/i2p/router/peermanager/ProfilePersistenceHelper.java
index fd88c406bb..4f5d236116 100644
--- a/router/java/src/net/i2p/router/peermanager/ProfilePersistenceHelper.java
+++ b/router/java/src/net/i2p/router/peermanager/ProfilePersistenceHelper.java
@@ -95,7 +95,6 @@ class ProfilePersistenceHelper {
if (_us != null)
buf.append("# as calculated by ").append(_us.toBase64()).append(NL);
buf.append("#").append(NL);
- buf.append("# reliability: ").append(profile.getReliabilityValue()).append(NL);
buf.append("# capacity: ").append(profile.getCapacityValue()).append(NL);
buf.append("# integration: ").append(profile.getIntegrationValue()).append(NL);
buf.append("# speedValue: ").append(profile.getSpeedValue()).append(NL);
@@ -134,15 +133,12 @@ class ProfilePersistenceHelper {
if (profile.getIsExpanded()) {
// only write out expanded data if, uh, we've got it
- profile.getCommError().store(out, "commError");
profile.getDbIntroduction().store(out, "dbIntroduction");
profile.getDbResponseTime().store(out, "dbResponseTime");
profile.getReceiveSize().store(out, "receiveSize");
- profile.getSendFailureSize().store(out, "sendFailureSize");
profile.getSendSuccessSize().store(out, "sendSuccessSize");
profile.getTunnelCreateResponseTime().store(out, "tunnelCreateResponseTime");
profile.getTunnelTestResponseTime().store(out, "tunnelTestResponseTime");
- profile.getTunnelTestResponseTimeSlow().store(out, "tunnelTestResponseTimeSlow");
}
}
@@ -217,15 +213,12 @@ class ProfilePersistenceHelper {
profile.getTunnelHistory().load(props);
profile.getDBHistory().load(props);
- profile.getCommError().load(props, "commError", true);
profile.getDbIntroduction().load(props, "dbIntroduction", true);
profile.getDbResponseTime().load(props, "dbResponseTime", true);
profile.getReceiveSize().load(props, "receiveSize", true);
- profile.getSendFailureSize().load(props, "sendFailureSize", true);
profile.getSendSuccessSize().load(props, "sendSuccessSize", true);
profile.getTunnelCreateResponseTime().load(props, "tunnelCreateResponseTime", true);
profile.getTunnelTestResponseTime().load(props, "tunnelTestResponseTime", true);
- profile.getTunnelTestResponseTimeSlow().load(props, "tunnelTestResponseTimeSlow", true);
if (_log.shouldLog(Log.DEBUG))
_log.debug("Loaded the profile for " + peer.toBase64() + " from " + file.getName());
diff --git a/router/java/src/net/i2p/router/peermanager/ReliabilityCalculator.java b/router/java/src/net/i2p/router/peermanager/ReliabilityCalculator.java
deleted file mode 100644
index 674b2fd915..0000000000
--- a/router/java/src/net/i2p/router/peermanager/ReliabilityCalculator.java
+++ /dev/null
@@ -1,91 +0,0 @@
-package net.i2p.router.peermanager;
-
-import net.i2p.router.RouterContext;
-import net.i2p.stat.RateStat;
-import net.i2p.util.Log;
-
-/**
- * Determine how reliable the peer is - how likely they'll be able to respond or
- * otherwise carry out whatever we ask them to (or even merely be reachable)
- *
- */
-public class ReliabilityCalculator extends Calculator {
- private Log _log;
- private RouterContext _context;
-
- public ReliabilityCalculator(RouterContext context) {
- _context = context;
- _log = context.logManager().getLog(ReliabilityCalculator.class);
- }
-
- public double calc(PeerProfile profile) {
- // if we've never succeeded (even if we've never tried), the reliability is zip
- if (profile.getSendSuccessSize().getRate(60*60*1000).getLifetimeEventCount() < 0)
- return profile.getReliabilityBonus();
-
- long val = 0;
- val += profile.getSendSuccessSize().getRate(60*1000).getCurrentEventCount() * 20;
- val += profile.getSendSuccessSize().getRate(60*1000).getLastEventCount() * 10;
- val += profile.getSendSuccessSize().getRate(60*60*1000).getLastEventCount() * 1;
- val += profile.getSendSuccessSize().getRate(60*60*1000).getCurrentEventCount() * 5;
-
- val += profile.getTunnelCreateResponseTime().getRate(10*60*1000).getLastEventCount() * 5;
- val += profile.getTunnelCreateResponseTime().getRate(60*60*1000).getCurrentEventCount();
- val += profile.getTunnelCreateResponseTime().getRate(60*60*1000).getLastEventCount();
-
- //val -= profile.getSendFailureSize().getRate(60*1000).getLastEventCount() * 5;
- //val -= profile.getSendFailureSize().getRate(60*60*1000).getCurrentEventCount()*2;
- //val -= profile.getSendFailureSize().getRate(60*60*1000).getLastEventCount()*2;
-
- RateStat rejRate = profile.getTunnelHistory().getRejectionRate();
- if (rejRate.getRate(60*1000).getCurrentEventCount() > 0)
- val -= 200;
- if (rejRate.getRate(60*1000).getLastEventCount() > 0)
- val -= 100;
- if (rejRate.getRate(10*60*1000).getCurrentEventCount() > 0)
- val -= 10;
- if (rejRate.getRate(10*60*1000).getCurrentEventCount() > 0)
- val -= 5;
-
- // penalize them heavily for dropping netDb requests (though these could have
- // failed due to tunnel timeouts, so don't be too mean)
- if (profile.getDBHistory().getFailedLookupRate().getRate(60*1000).getCurrentEventCount() > 0)
- val -= 10;
- if (profile.getDBHistory().getFailedLookupRate().getRate(60*1000).getLastEventCount() > 0)
- val -= 5;
-
- // scream and shout on network errors
- if (profile.getCommError().getRate(60*1000).getCurrentEventCount() > 0)
- val -= 200;
- if (profile.getCommError().getRate(60*1000).getLastEventCount() > 0)
- val -= 200;
-
- if (profile.getCommError().getRate(60*60*1000).getCurrentEventCount() > 0)
- val -= 10;
- if (profile.getCommError().getRate(60*60*1000).getLastEventCount() > 0)
- val -= 10;
-
- val -= profile.getCommError().getRate(24*60*60*1000).getCurrentEventCount() * 1;
-
- //long now = _context.clock().now();
-
- long timeSinceRejection = 61*60*1000; // now - profile.getTunnelHistory().getLastRejected();
- if (timeSinceRejection > 60*60*1000) {
- // noop. rejection was over 60 minutes ago
- } else if (timeSinceRejection > 10*60*1000) {
- val -= 10; // 10-60 minutes ago we got a rejection
- } else if (timeSinceRejection > 60*1000) {
- val -= 50; // 1-10 minutes ago we got a rejection
- } else {
- val -= 100; // we got a rejection within the last minute
- }
-
- //if ( (profile.getLastSendSuccessful() > 0) && (now - 24*60*60*1000 > profile.getLastSendSuccessful()) ) {
- // // we know they're real, but we havent sent them a message successfully in over a day.
- // val -= 1000;
- //}
-
- val += profile.getReliabilityBonus();
- return val;
- }
-}
diff --git a/router/java/src/net/i2p/router/peermanager/StrictSpeedCalculator.java b/router/java/src/net/i2p/router/peermanager/StrictSpeedCalculator.java
deleted file mode 100644
index 99453b0abf..0000000000
--- a/router/java/src/net/i2p/router/peermanager/StrictSpeedCalculator.java
+++ /dev/null
@@ -1,90 +0,0 @@
-package net.i2p.router.peermanager;
-
-import net.i2p.router.RouterContext;
-import net.i2p.stat.Rate;
-import net.i2p.stat.RateStat;
-import net.i2p.util.Log;
-
-/**
- * Simple speed calculator that just counts how many messages go through the
- * tunnel.
- *
- */
-public class StrictSpeedCalculator extends Calculator {
- private Log _log;
- private RouterContext _context;
-
- public StrictSpeedCalculator(RouterContext context) {
- _context = context;
- _log = context.logManager().getLog(StrictSpeedCalculator.class);
- }
-
- public double calc(PeerProfile profile) {
- return countSuccesses(profile);
- }
- private double countSuccesses(PeerProfile profile) {
- RateStat success = profile.getTunnelHistory().getProcessSuccessRate();
- RateStat failure = profile.getTunnelHistory().getProcessFailureRate();
- return messagesPerMinute(success, failure);
- }
- private double messagesPerMinute(RateStat success, RateStat failure) {
- double rv = 0.0d;
- if (success != null) {
- Rate rate = null;
- long periods[] = success.getPeriods();
- for (int i = 0; i < periods.length; i++) {
- rate = success.getRate(periods[i]);
- if ( (rate != null) && (rate.getCurrentTotalValue() > 0) )
- break;
- }
-
- double value = rate.getCurrentTotalValue();
- value += rate.getLastTotalValue();
- rv = value * 10.0d * 60.0d * 1000.0d / (double)rate.getPeriod();
-
- // if any of the messages are getting fragmented and cannot be
- // handled, penalize like crazy
- Rate fail = failure.getRate(rate.getPeriod());
- if (fail.getCurrentTotalValue() > 0)
- rv /= fail.getCurrentTotalValue();
- }
- return rv;
- }
-
- /*
- public double calc(PeerProfile profile) {
- double successCount = countSuccesses(profile);
- double failureCount = countFailures(profile);
-
- double rv = successCount - 5*failureCount;
- if (rv < 0)
- rv = 0;
- return rv;
- }
- private double countSuccesses(PeerProfile profile) {
- RateStat success = profile.getTunnelHistory().getProcessSuccessRate();
- return messagesPerMinute(success);
- }
- private double countFailures(PeerProfile profile) {
- RateStat failure = profile.getTunnelHistory().getProcessFailureRate();
- return messagesPerMinute(failure);
- }
- private double messagesPerMinute(RateStat stat) {
- double rv = 0.0d;
- if (stat != null) {
- Rate rate = null;
- long periods[] = stat.getPeriods();
- for (int i = 0; i < periods.length; i++) {
- rate = stat.getRate(periods[i]);
- if ( (rate != null) && (rate.getCurrentTotalValue() > 0) )
- break;
- }
-
- double value = rate.getCurrentTotalValue();
- value += rate.getLastTotalValue();
- rv = value * 60.0d * 1000.0d / (double)rate.getPeriod();
- }
- return rv;
- }
- */
-}
diff --git a/router/java/src/net/i2p/router/peermanager/TunnelHistory.java b/router/java/src/net/i2p/router/peermanager/TunnelHistory.java
index 2ea23099dd..d43aff6cd4 100644
--- a/router/java/src/net/i2p/router/peermanager/TunnelHistory.java
+++ b/router/java/src/net/i2p/router/peermanager/TunnelHistory.java
@@ -26,8 +26,6 @@ public class TunnelHistory {
private volatile long _lastFailed;
private RateStat _rejectRate;
private RateStat _failRate;
- private RateStat _processSuccessRate;
- private RateStat _processFailureRate;
private String _statGroup;
/** probabalistic tunnel rejection due to a flood of requests */
@@ -47,14 +45,10 @@ public class TunnelHistory {
}
private void createRates(String statGroup) {
- _rejectRate = new RateStat("tunnelHistory.rejectRate", "How often does this peer reject a tunnel request?", statGroup, new long[] { 60*1000l, 10*60*1000l, 30*60*1000l, 60*60*1000l, 24*60*60*1000l });
- _failRate = new RateStat("tunnelHistory.failRate", "How often do tunnels this peer accepts fail?", statGroup, new long[] { 60*1000l, 10*60*1000l, 30*60*1000l, 60*60*1000l, 24*60*60*1000l });
- _processSuccessRate = new RateStat("tunnelHistory.processSuccessRate", "How many messages does a tunnel process?", statGroup, new long[] { 5*60*1000l, 10*60*1000l, 30*60*1000l, 60*60*1000l, 24*60*60*1000l });
- _processFailureRate = new RateStat("tunnelHistory.processfailureRate", "How many messages does a tunnel fail?", statGroup, new long[] { 5*60*1000l, 10*60*1000l, 30*60*1000l, 60*60*1000l, 24*60*60*1000l });
+ _rejectRate = new RateStat("tunnelHistory.rejectRate", "How often does this peer reject a tunnel request?", statGroup, new long[] { 10*60*1000l, 30*60*1000l, 60*60*1000l, 24*60*60*1000l });
+ _failRate = new RateStat("tunnelHistory.failRate", "How often do tunnels this peer accepts fail?", statGroup, new long[] { 10*60*1000l, 30*60*1000l, 60*60*1000l, 24*60*60*1000l });
_rejectRate.setStatLog(_context.statManager().getStatLog());
_failRate.setStatLog(_context.statManager().getStatLog());
- _processSuccessRate.setStatLog(_context.statManager().getStatLog());
- _processFailureRate.setStatLog(_context.statManager().getStatLog());
}
/** total tunnels the peer has agreed to participate in */
@@ -77,10 +71,7 @@ public class TunnelHistory {
public long getLastFailed() { return _lastFailed; }
public void incrementProcessed(int processedSuccessfully, int failedProcessing) {
- if (processedSuccessfully > 0)
- _processSuccessRate.addData(processedSuccessfully, 0);
- if (failedProcessing > 0)
- _processFailureRate.addData(failedProcessing, 0);
+ // old strict speed calculator
}
public void incrementAgreedTo() {
@@ -129,16 +120,12 @@ public class TunnelHistory {
public RateStat getRejectionRate() { return _rejectRate; }
public RateStat getFailedRate() { return _failRate; }
- public RateStat getProcessSuccessRate() { return _processSuccessRate; }
- public RateStat getProcessFailureRate() { return _processFailureRate; }
public void coalesceStats() {
if (_log.shouldLog(Log.DEBUG))
_log.debug("Coallescing stats");
_rejectRate.coalesceStats();
_failRate.coalesceStats();
- _processFailureRate.coalesceStats();
- _processSuccessRate.coalesceStats();
}
private final static String NL = System.getProperty("line.separator");
@@ -161,8 +148,6 @@ public class TunnelHistory {
out.write(buf.toString().getBytes());
_rejectRate.store(out, "tunnelHistory.rejectRate");
_failRate.store(out, "tunnelHistory.failRate");
- _processSuccessRate.store(out, "tunnelHistory.processSuccessRate");
- _processFailureRate.store(out, "tunnelHistory.processFailureRate");
}
private void add(StringBuffer buf, String name, long val, String description) {
@@ -187,12 +172,6 @@ public class TunnelHistory {
_failRate.load(props, "tunnelHistory.failRate", true);
if (_log.shouldLog(Log.DEBUG))
_log.debug("Loading tunnelHistory.failRate");
- _processFailureRate.load(props, "tunnelHistory.processFailureRate", true);
- if (_log.shouldLog(Log.DEBUG))
- _log.debug("Loading tunnelHistory.processFailureRate");
- _processSuccessRate.load(props, "tunnelHistory.processSuccessRate", true);
- if (_log.shouldLog(Log.DEBUG))
- _log.debug("Loading tunnelHistory.processSuccessRate");
} catch (IllegalArgumentException iae) {
_log.warn("TunnelHistory rates are corrupt, resetting", iae);
createRates(_statGroup);
From 49c7fc30c09ab42ce4741d2177d65e54bc461e99 Mon Sep 17 00:00:00 2001
From: zzz
Date: Thu, 2 Apr 2009 19:01:26 +0000
Subject: [PATCH 076/688] cleanup
---
apps/i2ptunnel/jsp/editServer.jsp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/apps/i2ptunnel/jsp/editServer.jsp b/apps/i2ptunnel/jsp/editServer.jsp
index 59a7b9cf7e..3a958fd42e 100644
--- a/apps/i2ptunnel/jsp/editServer.jsp
+++ b/apps/i2ptunnel/jsp/editServer.jsp
@@ -268,7 +268,7 @@
- Leaseset Encryption Key:
+ Encryption Key:
From 3a1218283846c44fbc06591aba97dc9089110178 Mon Sep 17 00:00:00 2001
From: zzz
Date: Thu, 2 Apr 2009 20:33:54 +0000
Subject: [PATCH 077/688] Transport: - Maintain a router hash -> IP map in
transport, to support additional IP checks (unused for now) - Catch
error on pre-2.6 kernels - Some concurrent conversion - Fix an HTML error
on peers.jsp
---
.../transport/CommSystemFacadeImpl.java | 4 +++
.../i2p/router/transport/TransportImpl.java | 34 ++++++++++++-------
.../router/transport/TransportManager.java | 15 +++++++-
.../router/transport/ntcp/EstablishState.java | 6 +++-
.../router/transport/ntcp/EventPumper.java | 11 +++---
.../router/transport/ntcp/NTCPTransport.java | 7 +++-
.../transport/udp/EstablishmentManager.java | 2 ++
.../router/transport/udp/UDPTransport.java | 3 ++
8 files changed, 62 insertions(+), 20 deletions(-)
diff --git a/router/java/src/net/i2p/router/transport/CommSystemFacadeImpl.java b/router/java/src/net/i2p/router/transport/CommSystemFacadeImpl.java
index c94178004c..0eafb8fa97 100644
--- a/router/java/src/net/i2p/router/transport/CommSystemFacadeImpl.java
+++ b/router/java/src/net/i2p/router/transport/CommSystemFacadeImpl.java
@@ -133,6 +133,10 @@ public class CommSystemFacadeImpl extends CommSystemFacade {
return _manager.wasUnreachable(dest);
}
+ public byte[] getIP(Hash dest) {
+ return _manager.getIP(dest);
+ }
+
public List getMostRecentErrorMessages() {
return _manager.getMostRecentErrorMessages();
}
diff --git a/router/java/src/net/i2p/router/transport/TransportImpl.java b/router/java/src/net/i2p/router/transport/TransportImpl.java
index 04a2cde914..1dffde7995 100644
--- a/router/java/src/net/i2p/router/transport/TransportImpl.java
+++ b/router/java/src/net/i2p/router/transport/TransportImpl.java
@@ -20,6 +20,7 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Vector;
+import java.util.concurrent.ConcurrentHashMap;
import net.i2p.data.Hash;
import net.i2p.data.RouterAddress;
@@ -34,6 +35,7 @@ import net.i2p.router.OutNetMessage;
import net.i2p.router.Router;
import net.i2p.router.RouterContext;
import net.i2p.router.networkdb.kademlia.FloodfillNetworkDatabaseFacade;
+import net.i2p.util.ConcurrentHashSet;
import net.i2p.util.Log;
/**
@@ -47,8 +49,10 @@ public abstract class TransportImpl implements Transport {
private List _sendPool;
protected RouterContext _context;
/** map from routerIdentHash to timestamp (Long) that the peer was last unreachable */
- private Map _unreachableEntries;
- private Set _wasUnreachableEntries;
+ private Map _unreachableEntries;
+ private Set _wasUnreachableEntries;
+ /** global router ident -> IP */
+ private static Map _IPMap = new ConcurrentHashMap(128);
/**
* Initialize the new transport
@@ -67,7 +71,7 @@ public abstract class TransportImpl implements Transport {
_context.statManager().createRateStat("transport.expiredOnQueueLifetime", "How long a message that expires on our outbound queue is processed", "Transport", new long[] { 60*1000l, 10*60*1000l, 60*60*1000l, 24*60*60*1000l } );
_sendPool = new ArrayList(16);
_unreachableEntries = new HashMap(16);
- _wasUnreachableEntries = new HashSet(16);
+ _wasUnreachableEntries = new ConcurrentHashSet(16);
_currentAddress = null;
}
@@ -483,10 +487,8 @@ public abstract class TransportImpl implements Transport {
* This is NOT reset if the peer contacts us and it is never expired.
*/
public boolean wasUnreachable(Hash peer) {
- synchronized (_wasUnreachableEntries) {
- if (_wasUnreachableEntries.contains(peer))
- return true;
- }
+ if (_wasUnreachableEntries.contains(peer))
+ return true;
RouterInfo ri = _context.netDb().lookupRouterInfoLocally(peer);
if (ri == null)
return false;
@@ -496,16 +498,22 @@ public abstract class TransportImpl implements Transport {
* Maintain the WasUnreachable list
*/
public void markWasUnreachable(Hash peer, boolean yes) {
- synchronized (_wasUnreachableEntries) {
- if (yes)
- _wasUnreachableEntries.add(peer);
- else
- _wasUnreachableEntries.remove(peer);
- }
+ if (yes)
+ _wasUnreachableEntries.add(peer);
+ else
+ _wasUnreachableEntries.remove(peer);
if (_log.shouldLog(Log.WARN))
_log.warn(this.getStyle() + " setting wasUnreachable to " + yes + " for " + peer);
}
+ public static void setIP(Hash peer, byte[] ip) {
+ _IPMap.put(peer, ip);
+ }
+
+ public static byte[] getIP(Hash peer) {
+ return _IPMap.get(peer);
+ }
+
public static boolean isPubliclyRoutable(byte addr[]) {
if (addr.length == 4) {
if ((addr[0]&0xFF) == 127) return false;
diff --git a/router/java/src/net/i2p/router/transport/TransportManager.java b/router/java/src/net/i2p/router/transport/TransportManager.java
index bade759130..112f51efae 100644
--- a/router/java/src/net/i2p/router/transport/TransportManager.java
+++ b/router/java/src/net/i2p/router/transport/TransportManager.java
@@ -33,7 +33,7 @@ import net.i2p.util.Log;
public class TransportManager implements TransportEventListener {
private Log _log;
- private List _transports;
+ private List _transports;
private RouterContext _context;
private final static String PROP_ENABLE_UDP = "i2np.udp.enable";
@@ -229,6 +229,19 @@ public class TransportManager implements TransportEventListener {
return true;
}
+ /**
+ * IP of the peer from the last connection (in or out, any transport).
+ * This may be different from that advertised in the netDb,
+ * as the peer may be hidden, or connect from a different IP, or
+ * change his netDb later, in an attempt to avoid restrictions.
+ *
+ * For blocking purposes, etc. it's worth checking both
+ * the netDb addresses and this address.
+ */
+ public byte[] getIP(Hash dest) {
+ return TransportImpl.getIP(dest);
+ }
+
Map getAddresses() {
Map rv = new HashMap(_transports.size());
for (int i = 0; i < _transports.size(); i++) {
diff --git a/router/java/src/net/i2p/router/transport/ntcp/EstablishState.java b/router/java/src/net/i2p/router/transport/ntcp/EstablishState.java
index d18cc1ad3a..942d6cbc99 100644
--- a/router/java/src/net/i2p/router/transport/ntcp/EstablishState.java
+++ b/router/java/src/net/i2p/router/transport/ntcp/EstablishState.java
@@ -472,6 +472,8 @@ public class EstablishState {
byte nextReadIV[] = new byte[16];
System.arraycopy(_e_bobSig, _e_bobSig.length-16, nextReadIV, 0, nextReadIV.length);
_con.finishOutboundEstablishment(_dh.getSessionKey(), (_tsA-_tsB), nextWriteIV, nextReadIV); // skew in seconds
+ _transport.setIP(_con.getRemotePeer().calculateHash(),
+ _con.getChannel().socket().getInetAddress().getAddress());
return;
}
}
@@ -546,15 +548,17 @@ public class EstablishState {
Signature sig = new Signature(s);
_verified = _context.dsa().verifySignature(sig, toVerify, alice.getSigningPublicKey());
if (_verified) {
+ byte[] ip = _con.getChannel().socket().getInetAddress().getAddress();
if (_context.shitlist().isShitlistedForever(alice.calculateHash())) {
if (_log.shouldLog(Log.WARN))
_log.warn("Dropping inbound connection from permanently shitlisted peer: " + alice.calculateHash().toBase64());
// So next time we will not accept the con from this IP,
// rather than doing the whole handshake
- _context.blocklist().add(_con.getChannel().socket().getInetAddress().getAddress());
+ _context.blocklist().add(ip);
fail("Peer is shitlisted forever: " + alice.calculateHash().toBase64());
return;
}
+ _transport.setIP(alice.calculateHash(), ip);
if (_log.shouldLog(Log.DEBUG))
_log.debug(prefix() + "verification successful for " + _con);
diff --git a/router/java/src/net/i2p/router/transport/ntcp/EventPumper.java b/router/java/src/net/i2p/router/transport/ntcp/EventPumper.java
index 9c75f53283..0c062fa6cf 100644
--- a/router/java/src/net/i2p/router/transport/ntcp/EventPumper.java
+++ b/router/java/src/net/i2p/router/transport/ntcp/EventPumper.java
@@ -66,22 +66,25 @@ public class EventPumper implements Runnable {
public void startPumping() {
if (_log.shouldLog(Log.INFO))
_log.info("Starting pumper");
- _alive = true;
_wantsRead = new ArrayList(16);
_wantsWrite = new ArrayList(4);
_wantsRegister = new ArrayList(1);
_wantsConRegister = new ArrayList(4);
try {
_selector = Selector.open();
+ _alive = true;
+ new I2PThread(this, "NTCP Pumper", true).start();
} catch (IOException ioe) {
- _log.error("Error opening the selector", ioe);
+ _log.log(Log.CRIT, "Error opening the NTCP selector", ioe);
+ } catch (java.lang.InternalError jlie) {
+ // "unable to get address of epoll functions, pre-2.6 kernel?"
+ _log.log(Log.CRIT, "Error opening the NTCP selector", jlie);
}
- new I2PThread(this, "NTCP Pumper", true).start();
}
public void stopPumping() {
_alive = false;
- if (_selector.isOpen())
+ if (_selector != null && _selector.isOpen())
_selector.wakeup();
}
diff --git a/router/java/src/net/i2p/router/transport/ntcp/NTCPTransport.java b/router/java/src/net/i2p/router/transport/ntcp/NTCPTransport.java
index c23245bae4..103b46b153 100644
--- a/router/java/src/net/i2p/router/transport/ntcp/NTCPTransport.java
+++ b/router/java/src/net/i2p/router/transport/ntcp/NTCPTransport.java
@@ -241,6 +241,8 @@ public class NTCPTransport extends TransportImpl {
super.afterSend(msg, sendSuccessful, allowRequeue, msToSend);
}
public TransportBid bid(RouterInfo toAddress, long dataSize) {
+ if (!isAlive())
+ return null;
Hash peer = toAddress.getIdentity().calculateHash();
if (_context.shitlist().isShitlisted(peer, STYLE)) {
// we aren't shitlisted in general (since we are trying to get a bid), but we have
@@ -591,7 +593,10 @@ public class NTCPTransport extends TransportImpl {
for (Iterator iter = peers.iterator(); iter.hasNext(); ) {
NTCPConnection con = (NTCPConnection)iter.next();
String name = con.getRemotePeer().calculateHash().toBase64().substring(0,6);
- buf.append("