merge of '6ac923b4b6f858e909094ff3d0fbfbbfba7ff9d4'

and '8b279c27b4d263a1c9cc02ab7fe2e448e652f469'
This commit is contained in:
m1xxy
2010-12-31 01:52:45 +00:00
30 changed files with 674 additions and 209 deletions

View File

@ -329,14 +329,18 @@ public class I2PSnarkServlet extends Default {
// Opera and text-mode browsers: no   and no input type=image values submitted // Opera and text-mode browsers: no   and no input type=image values submitted
String ua = req.getHeader("User-Agent"); String ua = req.getHeader("User-Agent");
boolean isDegraded = ua != null && (ua.startsWith("Opera") || ua.startsWith("Lynx") || boolean isDegraded = ua != null && (ua.startsWith("Lynx") ||
ua.startsWith("ELinks") || ua.startsWith("Dillo")); ua.startsWith("ELinks") || ua.startsWith("Dillo"));
boolean noThinsp = isDegraded || ua.startsWith("Opera");
if (_manager.util().connected()) { if (_manager.util().connected()) {
if (isDegraded) if (isDegraded)
out.write("<a href=\"/i2psnark/?action=StopAll&amp;nonce=" + _nonce + "\"><img title=\""); out.write("<a href=\"/i2psnark/?action=StopAll&amp;nonce=" + _nonce + "\"><img title=\"");
else else {
out.write("<input type=\"image\" name=\"action\" value=\"StopAll\" title=\""); // http://www.onenaught.com/posts/382/firefox-4-change-input-type-image-only-submits-x-and-y-not-name
//out.write("<input type=\"image\" name=\"action\" value=\"StopAll\" title=\"");
out.write("<input type=\"image\" name=\"action_StopAll\" value=\"foo\" title=\"");
}
out.write(_("Stop all torrents and the I2P tunnel")); out.write(_("Stop all torrents and the I2P tunnel"));
out.write("\" src=\"" + _imgPath + "stop_all.png\" alt=\""); out.write("\" src=\"" + _imgPath + "stop_all.png\" alt=\"");
out.write(_("Stop All")); out.write(_("Stop All"));
@ -347,7 +351,7 @@ public class I2PSnarkServlet extends Default {
if (isDegraded) if (isDegraded)
out.write("<a href=\"/i2psnark/?action=StartAll&amp;nonce=" + _nonce + "\"><img title=\""); out.write("<a href=\"/i2psnark/?action=StartAll&amp;nonce=" + _nonce + "\"><img title=\"");
else else
out.write("<input type=\"image\" name=\"action\" value=\"StartAll\" title=\""); out.write("<input type=\"image\" name=\"action_StartAll\" value=\"foo\" title=\"");
out.write(_("Start all torrents and the I2P tunnel")); out.write(_("Start all torrents and the I2P tunnel"));
out.write("\" src=\"" + _imgPath + "start_all.png\" alt=\""); out.write("\" src=\"" + _imgPath + "start_all.png\" alt=\"");
out.write(_("Start All")); out.write(_("Start All"));
@ -362,7 +366,7 @@ public class I2PSnarkServlet extends Default {
Snark snark = (Snark)snarks.get(i); Snark snark = (Snark)snarks.get(i);
boolean showDebug = "2".equals(peerParam); boolean showDebug = "2".equals(peerParam);
boolean showPeers = showDebug || "1".equals(peerParam) || Base64.encode(snark.meta.getInfoHash()).equals(peerParam); boolean showPeers = showDebug || "1".equals(peerParam) || Base64.encode(snark.meta.getInfoHash()).equals(peerParam);
displaySnark(out, snark, uri, i, stats, showPeers, isDegraded, showDebug); displaySnark(out, snark, uri, i, stats, showPeers, isDegraded, noThinsp, showDebug);
} }
if (snarks.isEmpty()) { if (snarks.isEmpty()) {
@ -403,10 +407,21 @@ public class I2PSnarkServlet extends Default {
*/ */
private void processRequest(HttpServletRequest req) { private void processRequest(HttpServletRequest req) {
String action = req.getParameter("action"); String action = req.getParameter("action");
if (action == null) {
// http://www.onenaught.com/posts/382/firefox-4-change-input-type-image-only-submits-x-and-y-not-name
Map params = req.getParameterMap();
for (Object o : params.keySet()) {
String key = (String) o;
if (key.startsWith("action_") && key.endsWith(".x")) {
action = key.substring(0, key.length() - 2).substring(7);
break;
}
}
if (action == null) { if (action == null) {
_manager.addMessage("No action specified"); _manager.addMessage("No action specified");
return; return;
} }
}
// sadly, Opera doesn't send value with input type=image, so we have to use GET there // sadly, Opera doesn't send value with input type=image, so we have to use GET there
//if (!"POST".equals(req.getMethod())) { //if (!"POST".equals(req.getMethod())) {
// _manager.addMessage("Action must be with POST"); // _manager.addMessage("Action must be with POST");
@ -698,7 +713,7 @@ public class I2PSnarkServlet extends Default {
private static final int MAX_DISPLAYED_FILENAME_LENGTH = 50; private static final int MAX_DISPLAYED_FILENAME_LENGTH = 50;
private static final int MAX_DISPLAYED_ERROR_LENGTH = 43; private static final int MAX_DISPLAYED_ERROR_LENGTH = 43;
private void displaySnark(PrintWriter out, Snark snark, String uri, int row, long stats[], boolean showPeers, private void displaySnark(PrintWriter out, Snark snark, String uri, int row, long stats[], boolean showPeers,
boolean isDegraded, boolean showDebug) throws IOException { boolean isDegraded, boolean noThinsp, boolean showDebug) throws IOException {
String filename = snark.torrent; String filename = snark.torrent;
File f = new File(filename); File f = new File(filename);
filename = f.getName(); // the torrent may be the canonical name, so lets just grab the local name filename = f.getName(); // the torrent may be the canonical name, so lets just grab the local name
@ -758,11 +773,11 @@ public class I2PSnarkServlet extends Default {
if (isRunning && curPeers > 0 && !showPeers) if (isRunning && curPeers > 0 && !showPeers)
statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "trackererror.png\" title=\"" + err + "\"></td><td class=\"snarkTorrentStatus " + rowClass + "\">" + _("Tracker Error") + statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "trackererror.png\" title=\"" + err + "\"></td><td class=\"snarkTorrentStatus " + rowClass + "\">" + _("Tracker Error") +
": <a href=\"" + uri + "?p=" + Base64.encode(snark.meta.getInfoHash()) + "\">" + ": <a href=\"" + uri + "?p=" + Base64.encode(snark.meta.getInfoHash()) + "\">" +
curPeers + thinsp(isDegraded) + curPeers + thinsp(noThinsp) +
ngettext("1 peer", "{0} peers", knownPeers) + "</a>"; ngettext("1 peer", "{0} peers", knownPeers) + "</a>";
else if (isRunning) else if (isRunning)
statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "trackererror.png\" title=\"" + err + "\"></td><td class=\"snarkTorrentStatus " + rowClass + "\">" + _("Tracker Error") + statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "trackererror.png\" title=\"" + err + "\"></td><td class=\"snarkTorrentStatus " + rowClass + "\">" + _("Tracker Error") +
": " + curPeers + thinsp(isDegraded) + ": " + curPeers + thinsp(noThinsp) +
ngettext("1 peer", "{0} peers", knownPeers); ngettext("1 peer", "{0} peers", knownPeers);
else { else {
if (err.length() > MAX_DISPLAYED_ERROR_LENGTH) if (err.length() > MAX_DISPLAYED_ERROR_LENGTH)
@ -774,11 +789,11 @@ public class I2PSnarkServlet extends Default {
if (isRunning && curPeers > 0 && !showPeers) if (isRunning && curPeers > 0 && !showPeers)
statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "seeding.png\" ></td><td class=\"snarkTorrentStatus " + rowClass + "\">" + _("Seeding") + statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "seeding.png\" ></td><td class=\"snarkTorrentStatus " + rowClass + "\">" + _("Seeding") +
": <a href=\"" + uri + "?p=" + Base64.encode(snark.meta.getInfoHash()) + "\">" + ": <a href=\"" + uri + "?p=" + Base64.encode(snark.meta.getInfoHash()) + "\">" +
curPeers + thinsp(isDegraded) + curPeers + thinsp(noThinsp) +
ngettext("1 peer", "{0} peers", knownPeers) + "</a>"; ngettext("1 peer", "{0} peers", knownPeers) + "</a>";
else if (isRunning) else if (isRunning)
statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "seeding.png\" ></td><td class=\"snarkTorrentStatus " + rowClass + "\">" + _("Seeding") + statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "seeding.png\" ></td><td class=\"snarkTorrentStatus " + rowClass + "\">" + _("Seeding") +
": " + curPeers + thinsp(isDegraded) + ": " + curPeers + thinsp(noThinsp) +
ngettext("1 peer", "{0} peers", knownPeers); ngettext("1 peer", "{0} peers", knownPeers);
else else
statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "complete.png\" ></td><td class=\"snarkTorrentStatus " + rowClass + "\">" + _("Complete"); statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "complete.png\" ></td><td class=\"snarkTorrentStatus " + rowClass + "\">" + _("Complete");
@ -786,24 +801,24 @@ public class I2PSnarkServlet extends Default {
if (isRunning && curPeers > 0 && downBps > 0 && !showPeers) if (isRunning && curPeers > 0 && downBps > 0 && !showPeers)
statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "downloading.png\" ></td><td class=\"snarkTorrentStatus " + rowClass + "\">" + _("OK") + statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "downloading.png\" ></td><td class=\"snarkTorrentStatus " + rowClass + "\">" + _("OK") +
": <a href=\"" + uri + "?p=" + Base64.encode(snark.meta.getInfoHash()) + "\">" + ": <a href=\"" + uri + "?p=" + Base64.encode(snark.meta.getInfoHash()) + "\">" +
curPeers + thinsp(isDegraded) + curPeers + thinsp(noThinsp) +
ngettext("1 peer", "{0} peers", knownPeers) + "</a>"; ngettext("1 peer", "{0} peers", knownPeers) + "</a>";
else if (isRunning && curPeers > 0 && downBps > 0) else if (isRunning && curPeers > 0 && downBps > 0)
statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "downloading.png\" ></td><td class=\"snarkTorrentStatus " + rowClass + "\">" + _("OK") + statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "downloading.png\" ></td><td class=\"snarkTorrentStatus " + rowClass + "\">" + _("OK") +
": " + curPeers + thinsp(isDegraded) + ": " + curPeers + thinsp(noThinsp) +
ngettext("1 peer", "{0} peers", knownPeers); ngettext("1 peer", "{0} peers", knownPeers);
else if (isRunning && curPeers > 0 && !showPeers) else if (isRunning && curPeers > 0 && !showPeers)
statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "stalled.png\" ></td><td class=\"snarkTorrentStatus " + rowClass + "\">" + _("Stalled") + statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "stalled.png\" ></td><td class=\"snarkTorrentStatus " + rowClass + "\">" + _("Stalled") +
": <a href=\"" + uri + "?p=" + Base64.encode(snark.meta.getInfoHash()) + "\">" + ": <a href=\"" + uri + "?p=" + Base64.encode(snark.meta.getInfoHash()) + "\">" +
curPeers + thinsp(isDegraded) + curPeers + thinsp(noThinsp) +
ngettext("1 peer", "{0} peers", knownPeers) + "</a>"; ngettext("1 peer", "{0} peers", knownPeers) + "</a>";
else if (isRunning && curPeers > 0) else if (isRunning && curPeers > 0)
statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "stalled.png\" ></td><td class=\"snarkTorrentStatus " + rowClass + "\">" + _("Stalled") + statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "stalled.png\" ></td><td class=\"snarkTorrentStatus " + rowClass + "\">" + _("Stalled") +
": " + curPeers + thinsp(isDegraded) + ": " + curPeers + thinsp(noThinsp) +
ngettext("1 peer", "{0} peers", knownPeers); ngettext("1 peer", "{0} peers", knownPeers);
else if (isRunning && knownPeers > 0) else if (isRunning && knownPeers > 0)
statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "nopeers.png\" ></td><td class=\"snarkTorrentStatus " + rowClass + "\">" + _("No Peers") + statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "nopeers.png\" ></td><td class=\"snarkTorrentStatus " + rowClass + "\">" + _("No Peers") +
": 0" + thinsp(isDegraded) + knownPeers ; ": 0" + thinsp(noThinsp) + knownPeers ;
else if (isRunning) else if (isRunning)
statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "nopeers.png\" ></td><td class=\"snarkTorrentStatus " + rowClass + "\">" + _("No Peers"); statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "nopeers.png\" ></td><td class=\"snarkTorrentStatus " + rowClass + "\">" + _("No Peers");
else else
@ -880,7 +895,7 @@ public class I2PSnarkServlet extends Default {
out.write("</td>\n\t"); out.write("</td>\n\t");
out.write("<td align=\"right\" class=\"snarkTorrentDownloaded " + rowClass + "\">"); out.write("<td align=\"right\" class=\"snarkTorrentDownloaded " + rowClass + "\">");
if (remaining > 0) if (remaining > 0)
out.write(formatSize(total-remaining) + thinsp(isDegraded) + formatSize(total)); out.write(formatSize(total-remaining) + thinsp(noThinsp) + formatSize(total));
else else
out.write(formatSize(total)); // 3GB out.write(formatSize(total)); // 3GB
out.write("</td>\n\t"); out.write("</td>\n\t");
@ -905,7 +920,7 @@ public class I2PSnarkServlet extends Default {
if (isDegraded) if (isDegraded)
out.write("<a href=\"/i2psnark/?action=Stop_" + b64 + "&amp;nonce=" + _nonce + "\"><img title=\""); out.write("<a href=\"/i2psnark/?action=Stop_" + b64 + "&amp;nonce=" + _nonce + "\"><img title=\"");
else else
out.write("<input type=\"image\" name=\"action\" value=\"Stop_" + b64 + "\" title=\""); out.write("<input type=\"image\" name=\"action_Stop_" + b64 + "\" value=\"foo\" title=\"");
out.write(_("Stop the torrent")); out.write(_("Stop the torrent"));
out.write("\" src=\"" + _imgPath + "stop.png\" alt=\""); out.write("\" src=\"" + _imgPath + "stop.png\" alt=\"");
out.write(_("Stop")); out.write(_("Stop"));
@ -917,7 +932,7 @@ public class I2PSnarkServlet extends Default {
if (isDegraded) if (isDegraded)
out.write("<a href=\"/i2psnark/?action=Start_" + b64 + "&amp;nonce=" + _nonce + "\"><img title=\""); out.write("<a href=\"/i2psnark/?action=Start_" + b64 + "&amp;nonce=" + _nonce + "\"><img title=\"");
else else
out.write("<input type=\"image\" name=\"action\" value=\"Start_" + b64 + "\" title=\""); out.write("<input type=\"image\" name=\"action_Start_" + b64 + "\" value=\"foo\" title=\"");
out.write(_("Start the torrent")); out.write(_("Start the torrent"));
out.write("\" src=\"" + _imgPath + "start.png\" alt=\""); out.write("\" src=\"" + _imgPath + "start.png\" alt=\"");
out.write(_("Start")); out.write(_("Start"));
@ -929,7 +944,7 @@ public class I2PSnarkServlet extends Default {
if (isDegraded) if (isDegraded)
out.write("<a href=\"/i2psnark/?action=Remove_" + b64 + "&amp;nonce=" + _nonce + "\"><img title=\""); out.write("<a href=\"/i2psnark/?action=Remove_" + b64 + "&amp;nonce=" + _nonce + "\"><img title=\"");
else else
out.write("<input type=\"image\" name=\"action\" value=\"Remove_" + b64 + "\" title=\""); out.write("<input type=\"image\" name=\"action_Remove_" + b64 + "\" value=\"foo\" title=\"");
out.write(_("Remove the torrent from the active list, deleting the .torrent file")); out.write(_("Remove the torrent from the active list, deleting the .torrent file"));
out.write("\" onclick=\"if (!confirm('"); out.write("\" onclick=\"if (!confirm('");
// Can't figure out how to escape double quotes inside the onclick string. // Can't figure out how to escape double quotes inside the onclick string.
@ -946,7 +961,7 @@ public class I2PSnarkServlet extends Default {
if (isDegraded) if (isDegraded)
out.write("<a href=\"/i2psnark/?action=Delete_" + b64 + "&amp;nonce=" + _nonce + "\"><img title=\""); out.write("<a href=\"/i2psnark/?action=Delete_" + b64 + "&amp;nonce=" + _nonce + "\"><img title=\"");
else else
out.write("<input type=\"image\" name=\"action\" value=\"Delete_" + b64 + "\" title=\""); out.write("<input type=\"image\" name=\"action_Delete_" + b64 + "\" value=\"foo\" title=\"");
out.write(_("Delete the .torrent file and the associated data file(s)")); out.write(_("Delete the .torrent file and the associated data file(s)"));
out.write("\" onclick=\"if (!confirm('"); out.write("\" onclick=\"if (!confirm('");
// Can't figure out how to escape double quotes inside the onclick string. // Can't figure out how to escape double quotes inside the onclick string.
@ -1384,7 +1399,7 @@ public class I2PSnarkServlet extends Default {
private static String urlify(String s) { private static String urlify(String s) {
StringBuilder buf = new StringBuilder(256); StringBuilder buf = new StringBuilder(256);
// browsers seem to work without doing this but let's be strict // browsers seem to work without doing this but let's be strict
String link = s.replace("&", "&amp;"); String link = s.replace("&", "&amp;").replace(" ", "%20");
buf.append("<a href=\"").append(link).append("\">").append(link).append("</a>"); buf.append("<a href=\"").append(link).append("\">").append(link).append("</a>");
return buf.toString(); return buf.toString();
} }

View File

@ -259,10 +259,9 @@ public class TunnelController implements Logging {
/* /*
* Streamr client is a UDP server, use the listenPort field for targetPort * Streamr client is a UDP server, use the listenPort field for targetPort
* and the listenOnInterface field for the targetHost
*/ */
private void startStreamrClient() { private void startStreamrClient() {
String targetHost = getListenOnInterface(); String targetHost = getTargetHost();
String targetPort = getListenPort(); String targetPort = getListenPort();
String dest = getTargetDestination(); String dest = getTargetDestination();
_tunnel.runStreamrClient(new String[] { targetHost, targetPort, dest }, this); _tunnel.runStreamrClient(new String[] { targetHost, targetPort, dest }, this);
@ -270,10 +269,9 @@ public class TunnelController implements Logging {
/** /**
* 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() { private void startStreamrServer() {
String listenOn = getTargetHost(); String listenOn = getListenOnInterface();
if ( (listenOn != null) && (listenOn.length() > 0) ) { if ( (listenOn != null) && (listenOn.length() > 0) ) {
_tunnel.runListenOn(new String[] { listenOn }, this); _tunnel.runListenOn(new String[] { listenOn }, this);
} }

View File

@ -12,6 +12,7 @@ import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Properties; import java.util.Properties;
import java.util.StringTokenizer; import java.util.StringTokenizer;
import java.util.Set;
import net.i2p.data.Base64; import net.i2p.data.Base64;
import net.i2p.data.Destination; import net.i2p.data.Destination;
@ -22,6 +23,7 @@ import net.i2p.i2ptunnel.I2PTunnelHTTPClient;
import net.i2p.i2ptunnel.I2PTunnelHTTPClientBase; import net.i2p.i2ptunnel.I2PTunnelHTTPClientBase;
import net.i2p.i2ptunnel.TunnelController; import net.i2p.i2ptunnel.TunnelController;
import net.i2p.i2ptunnel.TunnelControllerGroup; import net.i2p.i2ptunnel.TunnelControllerGroup;
import net.i2p.util.Addresses;
/** /**
* Ugly little accessor for the edit page * Ugly little accessor for the edit page
@ -314,6 +316,11 @@ public class EditBean extends IndexBean {
return _context.isRouterContext(); return _context.isRouterContext();
} }
/** @since 0.8.3 */
public Set<String> interfaceSet() {
return Addresses.getAllAddresses();
}
public String getI2CPHost(int tunnel) { public String getI2CPHost(int tunnel) {
if (_context.isRouterContext()) if (_context.isRouterContext())
return _("internal"); return _("internal");

View File

@ -63,7 +63,6 @@ public class IndexBean {
private String _proxyList; private String _proxyList;
private String _port; private String _port;
private String _reachableBy; private String _reachableBy;
private String _reachableByOther;
private String _targetDestination; private String _targetDestination;
private String _targetHost; private String _targetHost;
private String _targetPort; private String _targetPort;
@ -432,10 +431,13 @@ public class IndexBean {
public String getClientInterface(int tunnel) { public String getClientInterface(int tunnel) {
TunnelController tun = getController(tunnel); TunnelController tun = getController(tunnel);
if (tun != null) if (tun != null) {
return tun.getListenOnInterface(); if ("streamrclient".equals(tun.getType()))
return tun.getTargetHost();
else else
return ""; return tun.getListenOnInterface();
} else
return "127.0.0.1";
} }
public int getTunnelStatus(int tunnel) { public int getTunnelStatus(int tunnel) {
@ -478,11 +480,38 @@ public class IndexBean {
return rv != null ? rv : ""; return rv != null ? rv : "";
} }
/**
* Call this to see if it is ok to linkify getServerTarget()
* @since 0.8.3
*/
public boolean isServerTargetLinkValid(int tunnel) {
TunnelController tun = getController(tunnel);
return tun != null &&
"httpserver".equals(tun.getType()) &&
tun.getTargetHost() != null &&
tun.getTargetPort() != null;
}
/**
* @return valid host:port only if isServerTargetLinkValid() is true
*/
public String getServerTarget(int tunnel) { public String getServerTarget(int tunnel) {
TunnelController tun = getController(tunnel); TunnelController tun = getController(tunnel);
if (tun != null) if (tun != null) {
return tun.getTargetHost() + ':' + tun.getTargetPort(); String host;
if ("streamrserver".equals(tun.getType()))
host = tun.getListenOnInterface();
else else
host = tun.getTargetHost();
String port = tun.getTargetPort();
if (host == null)
host = "<font color=\"red\">" + _("Host not set") + "</font>";
else if (host.indexOf(':') >= 0)
host = '[' + host + ']';
if (port == null)
port = "<font color=\"red\">" + _("Port not set") + "</font>";
return host + ':' + port;
} else
return ""; return "";
} }
@ -575,19 +604,11 @@ public class IndexBean {
_port = (port != null ? port.trim() : null); _port = (port != null ? port.trim() : null);
} }
/** /**
* what interface should this client/httpclient/ircclient listen on (unless * what interface should this client/httpclient/ircclient listen on
* overridden by the setReachableByOther() field)
*/ */
public void setReachableBy(String reachableBy) { public void setReachableBy(String reachableBy) {
_reachableBy = (reachableBy != null ? reachableBy.trim() : null); _reachableBy = (reachableBy != null ? reachableBy.trim() : null);
} }
/**
* If specified, defines the exact IP interface to listen for requests
* on (in the case of client/httpclient/ircclient tunnels)
*/
public void setReachableByOther(String reachableByOther) {
_reachableByOther = (reachableByOther != null ? reachableByOther.trim() : null);
}
/** What peer does this client tunnel point at */ /** What peer does this client tunnel point at */
public void setTargetDestination(String dest) { public void setTargetDestination(String dest) {
_targetDestination = (dest != null ? dest.trim() : null); _targetDestination = (dest != null ? dest.trim() : null);
@ -891,17 +912,22 @@ public class IndexBean {
Properties config = new Properties(); Properties config = new Properties();
updateConfigGeneric(config); updateConfigGeneric(config);
if ((isClient(_type) && !"streamrclient".equals(_type)) || "streamrserver".equals(_type)) {
// streamrserver uses interface
if (_reachableBy != null)
config.setProperty("interface", _reachableBy);
else
config.setProperty("interface", "");
} else {
// streamrclient uses targetHost
if (_targetHost != null)
config.setProperty("targetHost", _targetHost);
}
if (isClient(_type)) { if (isClient(_type)) {
// generic client stuff // generic client stuff
if (_port != null) if (_port != null)
config.setProperty("listenPort", _port); config.setProperty("listenPort", _port);
if (_reachableByOther != null)
config.setProperty("interface", _reachableByOther);
else if (_reachableBy != null)
config.setProperty("interface", _reachableBy);
else
config.setProperty("interface", "");
config.setProperty("sharedClient", _sharedClient + ""); config.setProperty("sharedClient", _sharedClient + "");
for (String p : _booleanClientOpts) for (String p : _booleanClientOpts)
config.setProperty("option." + p, "" + _booleanOptions.contains(p)); config.setProperty("option." + p, "" + _booleanOptions.contains(p));
@ -910,8 +936,6 @@ public class IndexBean {
config.setProperty("option." + p, _otherOptions.get(p)); config.setProperty("option." + p, _otherOptions.get(p));
} else { } else {
// generic server stuff // generic server stuff
if (_targetHost != null)
config.setProperty("targetHost", _targetHost);
if (_targetPort != null) if (_targetPort != null)
config.setProperty("targetPort", _targetPort); config.setProperty("targetPort", _targetPort);
for (String p : _booleanServerOpts) for (String p : _booleanServerOpts)
@ -940,9 +964,7 @@ public class IndexBean {
if ("httpbidirserver".equals(_type)) { if ("httpbidirserver".equals(_type)) {
if (_port != null) if (_port != null)
config.setProperty("listenPort", _port); config.setProperty("listenPort", _port);
if (_reachableByOther != null) if (_reachableBy != null)
config.setProperty("interface", _reachableByOther);
else if (_reachableBy != null)
config.setProperty("interface", _reachableBy); config.setProperty("interface", _reachableBy);
else if (_targetHost != null) else if (_targetHost != null)
config.setProperty("interface", _targetHost); config.setProperty("interface", _targetHost);

View File

@ -80,7 +80,7 @@
<label><%=intl._("Target")%>:</label> <label><%=intl._("Target")%>:</label>
<% } else { %> <% } else { %>
<label><%=intl._("Access Point")%>:</label> <label><%=intl._("Access Point")%>:</label>
<% } %> <% } /* streamrclient */ %>
</div> </div>
<div id="portField" class="rowItem"> <div id="portField" class="rowItem">
<label for="port" accesskey="P"> <label for="port" accesskey="P">
@ -95,44 +95,39 @@
</label> </label>
<input type="text" size="6" maxlength="5" id="port" name="port" title="Access Port Number" value="<%=editBean.getClientPort(curTunnel)%>" class="freetext" /> <input type="text" size="6" maxlength="5" id="port" name="port" title="Access Port Number" value="<%=editBean.getClientPort(curTunnel)%>" class="freetext" />
</div> </div>
<% String otherInterface = "";
String clientInterface = editBean.getClientInterface(curTunnel);
if ("streamrclient".equals(tunnelType)) {
otherInterface = clientInterface;
} else { %>
<div id="reachField" class="rowItem"> <div id="reachField" class="rowItem">
<label for="reachableBy" accesskey="r"> <label for="reachableBy" accesskey="r">
<%=intl._("Reachable by")%>(<span class="accessKey">R</span>): <%
</label> if ("streamrclient".equals(tunnelType)) {
<select id="reachableBy" name="reachableBy" title="Valid IP for Client Access" class="selectbox"> out.write("Host:");
<% if (!("127.0.0.1".equals(clientInterface)) && String targetHost = editBean.getTargetHost(curTunnel);
!("0.0.0.0".equals(clientInterface)) && if (targetHost == null || "".equals(targetHost.trim())) {
(clientInterface != null) &&
(clientInterface.trim().length() > 0)) {
otherInterface = clientInterface;
}
%><option value="127.0.0.1"<%=("127.0.0.1".equals(clientInterface) ? " selected=\"selected\"" : "")%>><%=intl._("Locally (127.0.0.1)")%></option>
<option value="0.0.0.0"<%=("0.0.0.0".equals(clientInterface) ? " selected=\"selected\"" : "")%>><%=intl._("Everyone (0.0.0.0)")%></option>
<option value="other"<%=(!("".equals(otherInterface)) ? " selected=\"selected\"" : "")%>><%=intl._("LAN Hosts (Please specify your LAN address)")%></option>
</select>
</div>
<% } // streamrclient %>
<div id="otherField" class="rowItem">
<label for="reachableByOther" accesskey="O">
<% if ("streamrclient".equals(tunnelType)) { %>
Host:
<% String vvv = otherInterface;
if (vvv == null || "".equals(vvv.trim())) {
out.write(" <font color=\"red\">("); out.write(" <font color=\"red\">(");
out.write(intl._("required")); out.write(intl._("required"));
out.write(")</font>"); out.write(")</font>");
} }
%> %>
<% } else { %>
<%=intl._("Other")%>(<span class="accessKey">O</span>):
<% } %>
</label> </label>
<input type="text" size="20" id="reachableByOther" name="reachableByOther" title="Alternative IP for Client Access" value="<%=otherInterface%>" class="freetext" /> <input type="text" size="20" id="targetHost" name="targetHost" title="Target Hostname or IP" value="<%=targetHost%>" class="freetext" />
<% } else { %>
<%=intl._("Reachable by")%>(<span class="accessKey">R</span>):
</label>
<select id="reachableBy" name="reachableBy" title="IP for Client Access" class="selectbox">
<%
String clientInterface = editBean.getClientInterface(curTunnel);
for (String ifc : editBean.interfaceSet()) {
out.write("<option value=\"");
out.write(ifc);
out.write('\"');
if (ifc.equals(clientInterface))
out.write(" selected=\"selected\"");
out.write('>');
out.write(ifc);
out.write("</option>\n");
}
%>
</select>
<% } /* streamrclient */ %>
</div> </div>
<div class="subdivider"> <div class="subdivider">

View File

@ -89,16 +89,14 @@
<label><%=intl._("Target")%>:</label> <label><%=intl._("Target")%>:</label>
<% } %> <% } %>
</div> </div>
<% if (!"streamrserver".equals(tunnelType)) { %>
<div id="hostField" class="rowItem"> <div id="hostField" class="rowItem">
<label for="targetHost" accesskey="H"> <label for="targetHost" accesskey="H">
<% if ("streamrserver".equals(tunnelType)) { %>
<%=intl._("Reachable by")%>(<span class="accessKey">R</span>):
<% } else { %>
<%=intl._("Host")%>(<span class="accessKey">H</span>): <%=intl._("Host")%>(<span class="accessKey">H</span>):
<% } %>
</label> </label>
<input type="text" size="20" id="targetHost" name="targetHost" title="Target Hostname or IP" value="<%=editBean.getTargetHost(curTunnel)%>" class="freetext" /> <input type="text" size="20" id="targetHost" name="targetHost" title="Target Hostname or IP" value="<%=editBean.getTargetHost(curTunnel)%>" class="freetext" />
</div> </div>
<% } /* !streamrserver */ %>
<div id="portField" class="rowItem"> <div id="portField" class="rowItem">
<label for="targetPort" accesskey="P"> <label for="targetPort" accesskey="P">
<%=intl._("Port")%>(<span class="accessKey">P</span>): <%=intl._("Port")%>(<span class="accessKey">P</span>):
@ -113,8 +111,7 @@
<input type="text" size="6" maxlength="5" id="targetPort" name="targetPort" title="Target Port Number" value="<%=editBean.getTargetPort(curTunnel)%>" class="freetext" /> <input type="text" size="6" maxlength="5" id="targetPort" name="targetPort" title="Target Port Number" value="<%=editBean.getTargetPort(curTunnel)%>" class="freetext" />
</div> </div>
<% if ("httpbidirserver".equals(tunnelType)) { <% if ("httpbidirserver".equals(tunnelType)) { %>
%>
<div class="subdivider"> <div class="subdivider">
<hr /> <hr />
</div> </div>
@ -134,32 +131,30 @@
</label> </label>
<input type="text" size="6" maxlength="5" id="port" name="port" title="Access Port Number" value="<%=editBean.getClientPort(curTunnel)%>" class="freetext" /> <input type="text" size="6" maxlength="5" id="port" name="port" title="Access Port Number" value="<%=editBean.getClientPort(curTunnel)%>" class="freetext" />
</div> </div>
<% String otherInterface = ""; <% } /* httpbidirserver */ %>
String clientInterface = editBean.getClientInterface(curTunnel); <% if ("httpbidirserver".equals(tunnelType) || "streamrserver".equals(tunnelType)) { %>
%>
<div id="reachField" class="rowItem"> <div id="reachField" class="rowItem">
<label for="reachableBy" accesskey="r"> <label for="reachableBy" accesskey="r">
<%=intl._("Reachable by")%>(<span class="accessKey">R</span>): <%=intl._("Reachable by")%>(<span class="accessKey">R</span>):
</label> </label>
<select id="reachableBy" name="reachableBy" title="Valid IP for Client Access" class="selectbox"> <select id="reachableBy" name="reachableBy" title="IP for Client Access" class="selectbox">
<% if (!("127.0.0.1".equals(clientInterface)) && <%
!("0.0.0.0".equals(clientInterface)) && String clientInterface = editBean.getClientInterface(curTunnel);
(clientInterface != null) && for (String ifc : editBean.interfaceSet()) {
(clientInterface.trim().length() > 0)) { out.write("<option value=\"");
otherInterface = clientInterface; out.write(ifc);
out.write('\"');
if (ifc.equals(clientInterface))
out.write(" selected=\"selected\"");
out.write('>');
out.write(ifc);
out.write("</option>\n");
} }
%><option value="127.0.0.1"<%=("127.0.0.1".equals(clientInterface) ? " selected=\"selected\"" : "")%>><%=intl._("Locally (127.0.0.1)")%></option> %>
<option value="0.0.0.0"<%=("0.0.0.0".equals(clientInterface) ? " selected=\"selected\"" : "")%>><%=intl._("Everyone (0.0.0.0)")%></option>
<option value="other"<%=(!("".equals(otherInterface)) ? " selected=\"selected\"" : "")%>><%=intl._("LAN Hosts (Please specify your LAN address)")%></option>
</select> </select>
</div> </div>
<div id="otherField" class="rowItem"> <% } /* httpbidirserver || streamrserver */ %>
<label for="reachableByOther" accesskey="O">
<%=intl._("Other")%>(<span class="accessKey">O</span>):
</label>
<input type="text" size="20" id="reachableByOther" name="reachableByOther" title="Alternative IP for Client Access" value="<%=otherInterface%>" class="freetext" />
</div>
<% } %>
<div class="subdivider"> <div class="subdivider">
<hr /> <hr />
</div> </div>
@ -302,7 +297,7 @@
<div class="subdivider"> <div class="subdivider">
<hr /> <hr />
</div> </div>
<% } // !streamrserver %> <% } /* !streamrserver */ %>
<div id="optionsField" class="rowItem"> <div id="optionsField" class="rowItem">
<label><%=intl._("Router I2CP Address")%>:</label> <label><%=intl._("Router I2CP Address")%>:</label>

View File

@ -95,7 +95,7 @@
<label><%=intl._("Points at")%>:</label> <label><%=intl._("Points at")%>:</label>
<span class="text"> <span class="text">
<% <%
if ("httpserver".equals(indexBean.getInternalType(curServer))) { if (indexBean.isServerTargetLinkValid(curServer)) {
%> %>
<a href="http://<%=indexBean.getServerTarget(curServer)%>/" title="Test HTTP server, bypassing I2P"><%=indexBean.getServerTarget(curServer)%></a> <a href="http://<%=indexBean.getServerTarget(curServer)%>/" title="Test HTTP server, bypassing I2P"><%=indexBean.getServerTarget(curServer)%></a>
<% <%
@ -213,7 +213,18 @@
</div> </div>
<div class="portField rowItem"> <div class="portField rowItem">
<label><%=intl._("Port")%>:</label> <label><%=intl._("Port")%>:</label>
<span class="text"><%=indexBean.getClientPort(curClient)%></span> <span class="text">
<%
String cPort= indexBean.getClientPort(curClient);
if ("".equals(cPort)) {
out.write("<font color=\"red\">");
out.write(intl._("Port not set"));
out.write("</font>");
} else {
out.write(cPort);
}
%>
</span>
</div> </div>
<div class="typeField rowItem"> <div class="typeField rowItem">
<label><%=intl._("Type")%>:</label> <label><%=intl._("Type")%>:</label>
@ -221,7 +232,19 @@
</div> </div>
<div class="interfaceField rowItem"> <div class="interfaceField rowItem">
<label><%=intl._("Interface")%>:</label> <label><%=intl._("Interface")%>:</label>
<span class="text"><%=indexBean.getClientInterface(curClient)%></span> <span class="text">
<%
/* should only happen for streamr client */
String cHost= indexBean.getClientInterface(curClient);
if ("".equals(cHost)) {
out.write("<font color=\"red\">");
out.write(intl._("Hort not set"));
out.write("</font>");
} else {
out.write(cHost);
}
%>
</span>
</div> </div>
<div class="statusField rowItem"> <div class="statusField rowItem">
<label><%=intl._("Status")%>:</label> <label><%=intl._("Status")%>:</label>

View File

@ -327,11 +327,12 @@ public class ElGamalAESEngine {
//_log.debug("len: " + len); //_log.debug("len: " + len);
if ((len < 0) || (len > decrypted.length - cur - Hash.HASH_LENGTH - 1)) if ((len < 0) || (len > decrypted.length - cur - Hash.HASH_LENGTH - 1))
throw new Exception("Invalid size of payload (" + len + ", remaining " + (decrypted.length-cur) +")"); throw new Exception("Invalid size of payload (" + len + ", remaining " + (decrypted.length-cur) +")");
byte hashval[] = new byte[Hash.HASH_LENGTH]; //byte hashval[] = new byte[Hash.HASH_LENGTH];
System.arraycopy(decrypted, cur, hashval, 0, Hash.HASH_LENGTH); //System.arraycopy(decrypted, cur, hashval, 0, Hash.HASH_LENGTH);
//readHash = new Hash();
//readHash.setData(hashval);
readHash = Hash.create(decrypted, cur);
cur += Hash.HASH_LENGTH; cur += Hash.HASH_LENGTH;
readHash = new Hash();
readHash.setData(hashval);
byte flag = decrypted[cur++]; byte flag = decrypted[cur++];
if (flag == 0x01) { if (flag == 0x01) {
byte rekeyVal[] = new byte[SessionKey.KEYSIZE_BYTES]; byte rekeyVal[] = new byte[SessionKey.KEYSIZE_BYTES];

View File

@ -202,9 +202,10 @@ public class ElGamalEngine {
} }
//ByteArrayInputStream bais = new ByteArrayInputStream(val, i, val.length - i); //ByteArrayInputStream bais = new ByteArrayInputStream(val, i, val.length - i);
byte hashData[] = new byte[Hash.HASH_LENGTH]; //byte hashData[] = new byte[Hash.HASH_LENGTH];
System.arraycopy(val, i + 1, hashData, 0, Hash.HASH_LENGTH); //System.arraycopy(val, i + 1, hashData, 0, Hash.HASH_LENGTH);
Hash hash = new Hash(hashData); //Hash hash = new Hash(hashData);
Hash hash = Hash.create(val, i + 1);
byte rv[] = new byte[payloadLen]; byte rv[] = new byte[payloadLen];
System.arraycopy(val, i + 1 + Hash.HASH_LENGTH, rv, 0, rv.length); System.arraycopy(val, i + 1 + Hash.HASH_LENGTH, rv, 0, rv.length);

View File

@ -35,7 +35,8 @@ public final class SHA256Generator {
digest.update(source, start, len); digest.update(source, start, len);
byte rv[] = digest.digest(); byte rv[] = digest.digest();
releaseGnu(digest); releaseGnu(digest);
return new Hash(rv); //return new Hash(rv);
return Hash.create(rv);
} }
public final void calculateHash(byte[] source, int start, int len, byte out[], int outOffset) { public final void calculateHash(byte[] source, int start, int len, byte out[], int outOffset) {

View File

@ -25,6 +25,33 @@ public class Hash extends SimpleDataStructure {
public final static int HASH_LENGTH = 32; public final static int HASH_LENGTH = 32;
public final static Hash FAKE_HASH = new Hash(new byte[HASH_LENGTH]); public final static Hash FAKE_HASH = new Hash(new byte[HASH_LENGTH]);
private static final int CACHE_SIZE = 2048;
private static final SDSCache<Hash> _cache = new SDSCache(Hash.class, HASH_LENGTH, CACHE_SIZE);
/**
* Pull from cache or return new
* @since 0.8.3
*/
public static Hash create(byte[] data) {
return _cache.get(data);
}
/**
* Pull from cache or return new
* @since 0.8.3
*/
public static Hash create(byte[] data, int off) {
return _cache.get(data, off);
}
/**
* Pull from cache or return new
* @since 0.8.3
*/
public static Hash create(InputStream in) throws IOException {
return _cache.get(in);
}
public Hash() { public Hash() {
super(); super();

View File

@ -61,10 +61,12 @@ public class KeysAndCert extends DataStructureImpl {
} }
public void readBytes(InputStream in) throws DataFormatException, IOException { public void readBytes(InputStream in) throws DataFormatException, IOException {
_publicKey = new PublicKey(); //_publicKey = new PublicKey();
_publicKey.readBytes(in); //_publicKey.readBytes(in);
_signingKey = new SigningPublicKey(); _publicKey = PublicKey.create(in);
_signingKey.readBytes(in); //_signingKey = new SigningPublicKey();
//_signingKey.readBytes(in);
_signingKey = SigningPublicKey.create(in);
//_certificate = new Certificate(); //_certificate = new Certificate();
//_certificate.readBytes(in); //_certificate.readBytes(in);
_certificate = Certificate.create(in); _certificate = Certificate.create(in);

View File

@ -110,8 +110,9 @@ public class Lease extends DataStructureImpl {
} }
public void readBytes(InputStream in) throws DataFormatException, IOException { public void readBytes(InputStream in) throws DataFormatException, IOException {
_gateway = new Hash(); //_gateway = new Hash();
_gateway.readBytes(in); //_gateway.readBytes(in);
_gateway = Hash.create(in);
_tunnelId = new TunnelId(); _tunnelId = new TunnelId();
_tunnelId.readBytes(in); _tunnelId.readBytes(in);
_end = DataHelper.readDate(in); _end = DataHelper.readDate(in);

View File

@ -9,6 +9,9 @@ package net.i2p.data;
* *
*/ */
import java.io.InputStream;
import java.io.IOException;
/** /**
* Defines the PublicKey as defined by the I2P data structure spec. * Defines the PublicKey as defined by the I2P data structure spec.
* A public key is 256byte Integer. The public key represents only the * A public key is 256byte Integer. The public key represents only the
@ -18,6 +21,17 @@ package net.i2p.data;
*/ */
public class PublicKey extends SimpleDataStructure { public class PublicKey extends SimpleDataStructure {
public final static int KEYSIZE_BYTES = 256; public final static int KEYSIZE_BYTES = 256;
private static final int CACHE_SIZE = 256;
private static final SDSCache<PublicKey> _cache = new SDSCache(PublicKey.class, KEYSIZE_BYTES, CACHE_SIZE);
/**
* Pull from cache or return new
* @since 0.8.3
*/
public static PublicKey create(InputStream in) throws IOException {
return _cache.get(in);
}
public PublicKey() { public PublicKey() {
super(); super();

View File

@ -0,0 +1,175 @@
package net.i2p.data;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.LinkedHashMap;
import java.util.Map;
import net.i2p.I2PAppContext;
import net.i2p.util.Log;
import net.i2p.util.SimpleByteCache;
/**
* A least recently used cache with a max size, for SimpleDataStructures.
* The index to the cache is the first 4 bytes of the data, so
* the data must be sufficiently random.
*
* This caches the SDS objects, and also uses SimpleByteCache to cache
* the unused byte arrays themselves
*
* Following is sample usage:
* <pre>
private static final SDSCache<Foo> _cache = new SDSCache(Foo.class, LENGTH, 1024);
public static Foo create(byte[] data) {
return _cache.get(data);
}
public static Foo create(byte[] data, int off) {
return _cache.get(data, off);
}
public static Foo create(InputStream in) throws IOException {
return _cache.get(in);
}
* </pre>
* @since 0.8.3
* @author zzz
*/
public class SDSCache<V extends SimpleDataStructure> {
private static final Log _log = I2PAppContext.getGlobalContext().logManager().getLog(SDSCache.class);
private static final Class[] conArg = new Class[] { byte[].class };
private static final double MIN_FACTOR = 0.25;
private static final double MAX_FACTOR = 3.0;
private static final double FACTOR;
static {
long maxMemory = Runtime.getRuntime().maxMemory();
FACTOR = Math.max(MIN_FACTOR, Math.min(MAX_FACTOR, maxMemory / (128*1024*1024d)));
}
/** the LRU cache */
private final Map<Integer, V> _cache;
/** the byte array length for the class we are caching */
private final int _datalen;
/** the constructor for the class we are caching */
private final Constructor<V> _rvCon;
private final String _statName;
/**
* @param rvClass the class that we are storing, i.e. an extension of SimpleDataStructure
* @param len the length of the byte array in the SimpleDataStructure
* @param max maximum size of the cache assuming 128MB of mem.
* The actual max size will be scaled based on available memory.
*/
public SDSCache(Class<V> rvClass, int len, int max) {
int size = (int) (max * FACTOR);
_cache = new LHM(size);
_datalen = len;
try {
_rvCon = rvClass.getConstructor(conArg);
} catch (NoSuchMethodException e) {
throw new RuntimeException("SDSCache init error", e);
}
_statName = "SDSCache." + rvClass.getSimpleName();
if (_log.shouldLog(Log.DEBUG))
_log.debug("New SDSCache for " + rvClass + " data size: " + len +
" max: " + size + " max mem: " + (len * size));
I2PAppContext.getGlobalContext().statManager().createRateStat(_statName, "Hit rate", "Router", new long[] { 10*60*1000 });
}
/**
* @param data non-null, the byte array for the SimpleDataStructure
* @return the cached value if available, otherwise
* makes a new object and returns it
* @throws IllegalArgumentException if data is not the correct number of bytes
* @throws NPE
*/
public V get(byte[] data) {
if (data == null)
throw new NullPointerException("Don't pull null data from the cache");
int found;
V rv;
Integer key = hashCodeOf(data);
synchronized(_cache) {
rv = _cache.get(key);
if (rv != null && DataHelper.eq(data, rv.getData())) {
// found it, we don't need the data passed in any more
SimpleByteCache.release(data);
found = 1;
} else {
// make a new one
try {
rv = _rvCon.newInstance(new Object[] { data } );
} catch (InstantiationException e) {
throw new RuntimeException("SDSCache error", e);
} catch (IllegalAccessException e) {
throw new RuntimeException("SDSCache error", e);
} catch (InvocationTargetException e) {
throw new RuntimeException("SDSCache error", e);
}
_cache.put(key, rv);
found = 0;
}
}
I2PAppContext.getGlobalContext().statManager().addRateData(_statName, found, 0);
return rv;
}
/*
* @param b non-null byte array containing the data, data will be copied to not hold the reference
* @param off offset in the array to start reading from
* @return the cached value if available, otherwise
* makes a new object and returns it
* @throws AIOOBE if not enough bytes
* @throws NPE
*/
public V get(byte[] b, int off) {
byte[] data = SimpleByteCache.acquire(_datalen);
System.arraycopy(b, off, data, 0, _datalen);
return get(data);
}
/*
* @param in a stream from which the bytes will be read
* @return the cached value if available, otherwise
* makes a new object and returns it
* @throws IOException if not enough bytes
*/
public V get(InputStream in) throws IOException {
byte[] data = SimpleByteCache.acquire(_datalen);
int read = DataHelper.read(in, data);
if (read != _datalen)
throw new EOFException("Not enough bytes to read the data");
return get(data);
}
/**
* We assume the data has enough randomness in it, so use the first 4 bytes for speed.
*/
private static Integer hashCodeOf(byte[] data) {
int rv = data[0];
for (int i = 1; i < 4; i++)
rv ^= (data[i] << (i*8));
return Integer.valueOf(rv);
}
private static class LHM<K, V> extends LinkedHashMap<K, V> {
private final int _max;
public LHM(int max) {
super(max, 0.75f, true);
_max = max;
}
@Override
protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
return size() > _max;
}
}
}

View File

@ -9,6 +9,9 @@ package net.i2p.data;
* *
*/ */
import java.io.InputStream;
import java.io.IOException;
/** /**
* Defines the SigningPublicKey as defined by the I2P data structure spec. * Defines the SigningPublicKey as defined by the I2P data structure spec.
* A public key is 256byte Integer. The public key represents only the * A public key is 256byte Integer. The public key represents only the
@ -19,6 +22,17 @@ package net.i2p.data;
*/ */
public class SigningPublicKey extends SimpleDataStructure { public class SigningPublicKey extends SimpleDataStructure {
public final static int KEYSIZE_BYTES = 128; public final static int KEYSIZE_BYTES = 128;
private static final int CACHE_SIZE = 256;
private static final SDSCache<SigningPublicKey> _cache = new SDSCache(SigningPublicKey.class, KEYSIZE_BYTES, CACHE_SIZE);
/**
* Pull from cache or return new
* @since 0.8.3
*/
public static SigningPublicKey create(InputStream in) throws IOException {
return _cache.get(in);
}
public SigningPublicKey() { public SigningPublicKey() {
super(); super();

View File

@ -33,13 +33,15 @@ public class DestLookupMessage extends I2CPMessageImpl {
} }
protected void doReadMessage(InputStream in, int size) throws I2CPMessageException, IOException { protected void doReadMessage(InputStream in, int size) throws I2CPMessageException, IOException {
Hash h = new Hash(); //Hash h = new Hash();
try { try {
h.readBytes(in); //h.readBytes(in);
} catch (DataFormatException dfe) { _hash = Hash.create(in);
//} catch (DataFormatException dfe) {
} catch (IllegalArgumentException dfe) {
throw new I2CPMessageException("Unable to load the hash", dfe); throw new I2CPMessageException("Unable to load the hash", dfe);
} }
_hash = h; //_hash = h;
} }
protected byte[] doWriteMessage() throws I2CPMessageException, IOException { protected byte[] doWriteMessage() throws I2CPMessageException, IOException {

View File

@ -86,8 +86,9 @@ public class RequestLeaseSetMessage extends I2CPMessageImpl {
int numTunnels = (int) DataHelper.readLong(in, 1); int numTunnels = (int) DataHelper.readLong(in, 1);
_endpoints.clear(); _endpoints.clear();
for (int i = 0; i < numTunnels; i++) { for (int i = 0; i < numTunnels; i++) {
Hash router = new Hash(); //Hash router = new Hash();
router.readBytes(in); //router.readBytes(in);
Hash router = Hash.create(in);
TunnelId tunnel = new TunnelId(); TunnelId tunnel = new TunnelId();
tunnel.readBytes(in); tunnel.readBytes(in);
_endpoints.add(new TunnelEndpoint(router, tunnel)); _endpoints.add(new TunnelEndpoint(router, tunnel));

View File

@ -1,9 +1,9 @@
package net.i2p.util; package net.i2p.util;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Queue; import java.util.Queue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.LinkedBlockingQueue;
import net.i2p.I2PAppContext; import net.i2p.I2PAppContext;
@ -57,7 +57,8 @@ import net.i2p.data.ByteArray;
*/ */
public final class ByteCache { public final class ByteCache {
private static final Map<Integer, ByteCache> _caches = new HashMap(16); private static final Log _log = I2PAppContext.getGlobalContext().logManager().getLog(ByteCache.class);
private static final Map<Integer, ByteCache> _caches = new ConcurrentHashMap(16);
/** /**
* max size in bytes of each cache * max size in bytes of each cache
@ -74,8 +75,9 @@ public final class ByteCache {
/** /**
* Get a cache responsible for objects of the given size * Get a cache responsible for objects of the given size
* *
* @param cacheSize how large we want the cache to grow before using on * @param cacheSize how large we want the cache to grow
* demand allocation * (number of objects, NOT memory size)
* before discarding released objects.
* Since 0.7.14, a limit of 1MB / size is enforced * Since 0.7.14, a limit of 1MB / size is enforced
* for the typical 128MB max memory JVM * for the typical 128MB max memory JVM
* @param size how large should the objects cached be? * @param size how large should the objects cached be?
@ -84,12 +86,11 @@ public final class ByteCache {
if (cacheSize * size > MAX_CACHE) if (cacheSize * size > MAX_CACHE)
cacheSize = MAX_CACHE / size; cacheSize = MAX_CACHE / size;
Integer sz = Integer.valueOf(size); Integer sz = Integer.valueOf(size);
ByteCache cache = null; ByteCache cache = _caches.get(sz);
synchronized (_caches) { if (cache == null) {
if (!_caches.containsKey(sz)) cache = new ByteCache(cacheSize, size);
_caches.put(sz, new ByteCache(cacheSize, size)); _caches.put(sz, cache);
cache = _caches.get(sz); ; }
}
cache.resize(cacheSize); cache.resize(cacheSize);
//I2PAppContext.getGlobalContext().logManager().getLog(ByteCache.class).error("ByteCache size: " + size + " max: " + cacheSize, new Exception("from")); //I2PAppContext.getGlobalContext().logManager().getLog(ByteCache.class).error("ByteCache size: " + size + " max: " + cacheSize, new Exception("from"));
return cache; return cache;
@ -102,10 +103,9 @@ public final class ByteCache {
public static void clearAll() { public static void clearAll() {
for (ByteCache bc : _caches.values()) for (ByteCache bc : _caches.values())
bc.clear(); bc.clear();
I2PAppContext.getGlobalContext().logManager().getLog(ByteCache.class).warn("WARNING: Low memory, clearing byte caches"); _log.warn("WARNING: Low memory, clearing byte caches");
} }
private Log _log;
/** list of available and available entries */ /** list of available and available entries */
private Queue<ByteArray> _available; private Queue<ByteArray> _available;
private int _maxCached; private int _maxCached;
@ -116,7 +116,7 @@ public final class ByteCache {
private static final boolean _cache = true; private static final boolean _cache = true;
/** how often do we cleanup the cache */ /** how often do we cleanup the cache */
private static final int CLEANUP_FREQUENCY = 30*1000; private static final int CLEANUP_FREQUENCY = 33*1000;
/** if we haven't exceeded the cache size in 2 minutes, cut our cache in half */ /** if we haven't exceeded the cache size in 2 minutes, cut our cache in half */
private static final long EXPIRE_PERIOD = 2*60*1000; private static final long EXPIRE_PERIOD = 2*60*1000;
@ -126,9 +126,8 @@ public final class ByteCache {
_maxCached = maxCachedEntries; _maxCached = maxCachedEntries;
_entrySize = entrySize; _entrySize = entrySize;
_lastOverflow = -1; _lastOverflow = -1;
SimpleScheduler.getInstance().addPeriodicEvent(new Cleanup(), CLEANUP_FREQUENCY); SimpleScheduler.getInstance().addPeriodicEvent(new Cleanup(), CLEANUP_FREQUENCY + (entrySize % 7)); //stagger
_log = I2PAppContext.getGlobalContext().logManager().getLog(ByteCache.class); I2PAppContext.getGlobalContext().statManager().createRateStat("byteCache.memory." + entrySize, "Memory usage (B)", "Router", new long[] { 10*60*1000 });
I2PAppContext.getGlobalContext().statManager().createRateStat("byteCache.memory." + entrySize, "Memory usage (B)", "Router", new long[] { 60*1000 });
} }
private void resize(int maxCachedEntries) { private void resize(int maxCachedEntries) {

View File

@ -0,0 +1,125 @@
package net.i2p.util;
import java.util.Map;
import java.util.Queue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.LinkedBlockingQueue;
import net.i2p.I2PAppContext;
/**
* Like ByteCache but works directly with byte arrays, not ByteArrays.
* These are designed to be small caches, so there's no cleaner task
* like there is in ByteCache. And we don't zero out the arrays here.
* Only the static methods are public here.
*
* @since 0.8.3
*/
public final class SimpleByteCache {
private static final Map<Integer, SimpleByteCache> _caches = new ConcurrentHashMap(8);
private static final int DEFAULT_SIZE = 16;
/**
* Get a cache responsible for arrays of the given size
*
* @param size how large should the objects cached be?
*/
public static SimpleByteCache getInstance(int size) {
return getInstance(DEFAULT_SIZE, size);
}
/**
* Get a cache responsible for objects of the given size
*
* @param cacheSize how large we want the cache to grow
* (number of objects, NOT memory size)
* before discarding released objects.
* @param size how large should the objects cached be?
*/
public static SimpleByteCache getInstance(int cacheSize, int size) {
Integer sz = Integer.valueOf(size);
SimpleByteCache cache = _caches.get(sz);
if (cache == null) {
cache = new SimpleByteCache(cacheSize, size);
_caches.put(sz, cache);
}
cache.resize(cacheSize);
return cache;
}
/**
* Clear everything (memory pressure)
*/
public static void clearAll() {
for (SimpleByteCache bc : _caches.values())
bc.clear();
}
/** list of available and available entries */
private Queue<byte[]> _available;
private int _maxCached;
private int _entrySize;
private SimpleByteCache(int maxCachedEntries, int entrySize) {
_available = new LinkedBlockingQueue(maxCachedEntries);
_maxCached = maxCachedEntries;
_entrySize = entrySize;
}
private void resize(int maxCachedEntries) {
if (_maxCached >= maxCachedEntries) return;
_maxCached = maxCachedEntries;
// make a bigger one, move the cached items over
Queue<byte[]> newLBQ = new LinkedBlockingQueue(maxCachedEntries);
byte[] ba;
while ((ba = _available.poll()) != null)
newLBQ.offer(ba);
_available = newLBQ;
}
/**
* Get the next available array, either from the cache or a brand new one
*/
public static byte[] acquire(int size) {
return getInstance(size).acquire();
}
/**
* Get the next available array, either from the cache or a brand new one
*/
private byte[] acquire() {
byte[] rv = _available.poll();
if (rv == null)
rv = new byte[_entrySize];
return rv;
}
/**
* Put this array back onto the available cache for reuse
*/
public static void release(byte[] entry) {
SimpleByteCache cache = _caches.get(entry.length);
if (cache != null)
cache.releaseIt(entry);
}
/**
* Put this array back onto the available cache for reuse
*/
private void releaseIt(byte[] entry) {
if (entry == null || entry.length != _entrySize)
return;
// should be safe without this
//Arrays.fill(entry, (byte) 0);
_available.offer(entry);
}
/**
* Clear everything (memory pressure)
*/
private void clear() {
_available.clear();
}
}

View File

@ -1,3 +1,15 @@
2010-12-30 zzz
* Data Structures:
- New SDSCache for SimpleDataStructures
- New SimpleByteCache for byte[]
- Cache Hash, PublicKey, and SigningPublicKey
- Remove global lock in ByteCache
* I2CP: Missing piece of parallel naming lookup
* i2psnark: Fix buttons on Firefox 4.0b
* i2ptunnel:
- Use dropdown box to select interface for clients
- Warn on index page if required fields not set
2010-12-29 zzz 2010-12-29 zzz
* Console: Add 500 error page * Console: Add 500 error page
* DSAEngine: Restore variants of methods using a Hash argument, * DSAEngine: Restore variants of methods using a Hash argument,
@ -42,7 +54,9 @@
- Add support for specifying the timeout for DestLookups - Add support for specifying the timeout for DestLookups
(can only be smaller than the router timeout for now) (can only be smaller than the router timeout for now)
- Extend dest lookup router timeout from 10s to 15s - Extend dest lookup router timeout from 10s to 15s
* i2psnark: Backport TrackerClient NPE fix * i2psnark:
- Backport TrackerClient NPE fix
- Fix last piece length calculation for torrents > 2GB (ticket #361)
* i2ptunnel: * i2ptunnel:
- Get Log from the logManager instead of instantiating, - Get Log from the logManager instead of instantiating,
so we may adjust the levels on the fly so we may adjust the levels on the fly

View File

@ -93,9 +93,10 @@ public class BuildRequestRecord {
* the gateway to which the reply should be sent. * the gateway to which the reply should be sent.
*/ */
public Hash readNextIdentity() { public Hash readNextIdentity() {
byte rv[] = new byte[Hash.HASH_LENGTH]; //byte rv[] = new byte[Hash.HASH_LENGTH];
System.arraycopy(_data.getData(), _data.getOffset() + OFF_SEND_IDENT, rv, 0, Hash.HASH_LENGTH); //System.arraycopy(_data.getData(), _data.getOffset() + OFF_SEND_IDENT, rv, 0, Hash.HASH_LENGTH);
return new Hash(rv); //return new Hash(rv);
return Hash.create(_data.getData(), _data.getOffset() + OFF_SEND_IDENT);
} }
/** /**
* Tunnel layer encryption key that the current hop should use * Tunnel layer encryption key that the current hop should use

View File

@ -133,15 +133,17 @@ public class DatabaseLookupMessage extends I2NPMessageImpl {
if (type != MESSAGE_TYPE) throw new I2NPMessageException("Message type is incorrect for this message"); if (type != MESSAGE_TYPE) throw new I2NPMessageException("Message type is incorrect for this message");
int curIndex = offset; int curIndex = offset;
byte keyData[] = new byte[Hash.HASH_LENGTH]; //byte keyData[] = new byte[Hash.HASH_LENGTH];
System.arraycopy(data, curIndex, keyData, 0, Hash.HASH_LENGTH); //System.arraycopy(data, curIndex, keyData, 0, Hash.HASH_LENGTH);
_key = Hash.create(data, curIndex);
curIndex += Hash.HASH_LENGTH; curIndex += Hash.HASH_LENGTH;
_key = new Hash(keyData); //_key = new Hash(keyData);
byte fromData[] = new byte[Hash.HASH_LENGTH]; //byte fromData[] = new byte[Hash.HASH_LENGTH];
System.arraycopy(data, curIndex, fromData, 0, Hash.HASH_LENGTH); //System.arraycopy(data, curIndex, fromData, 0, Hash.HASH_LENGTH);
_fromHash = Hash.create(data, curIndex);
curIndex += Hash.HASH_LENGTH; curIndex += Hash.HASH_LENGTH;
_fromHash = new Hash(fromData); //_fromHash = new Hash(fromData);
boolean tunnelSpecified = false; boolean tunnelSpecified = false;
switch (data[curIndex]) { switch (data[curIndex]) {
@ -168,10 +170,11 @@ public class DatabaseLookupMessage extends I2NPMessageImpl {
throw new I2NPMessageException("Invalid number of peers - " + numPeers); throw new I2NPMessageException("Invalid number of peers - " + numPeers);
Set<Hash> peers = new HashSet(numPeers); Set<Hash> peers = new HashSet(numPeers);
for (int i = 0; i < numPeers; i++) { for (int i = 0; i < numPeers; i++) {
byte peer[] = new byte[Hash.HASH_LENGTH]; //byte peer[] = new byte[Hash.HASH_LENGTH];
System.arraycopy(data, curIndex, peer, 0, Hash.HASH_LENGTH); //System.arraycopy(data, curIndex, peer, 0, Hash.HASH_LENGTH);
Hash p = Hash.create(data, curIndex);
curIndex += Hash.HASH_LENGTH; curIndex += Hash.HASH_LENGTH;
peers.add(new Hash(peer)); peers.add(p);
} }
_dontIncludePeers = peers; _dontIncludePeers = peers;
} }

View File

@ -55,26 +55,29 @@ public class DatabaseSearchReplyMessage extends I2NPMessageImpl {
if (type != MESSAGE_TYPE) throw new I2NPMessageException("Message type is incorrect for this message"); if (type != MESSAGE_TYPE) throw new I2NPMessageException("Message type is incorrect for this message");
int curIndex = offset; int curIndex = offset;
byte keyData[] = new byte[Hash.HASH_LENGTH]; //byte keyData[] = new byte[Hash.HASH_LENGTH];
System.arraycopy(data, curIndex, keyData, 0, Hash.HASH_LENGTH); //System.arraycopy(data, curIndex, keyData, 0, Hash.HASH_LENGTH);
_key = Hash.create(data, curIndex);
curIndex += Hash.HASH_LENGTH; curIndex += Hash.HASH_LENGTH;
_key = new Hash(keyData); //_key = new Hash(keyData);
int num = (int)DataHelper.fromLong(data, curIndex, 1); int num = (int)DataHelper.fromLong(data, curIndex, 1);
curIndex++; curIndex++;
_peerHashes.clear(); _peerHashes.clear();
for (int i = 0; i < num; i++) { for (int i = 0; i < num; i++) {
byte peer[] = new byte[Hash.HASH_LENGTH]; //byte peer[] = new byte[Hash.HASH_LENGTH];
System.arraycopy(data, curIndex, peer, 0, Hash.HASH_LENGTH); //System.arraycopy(data, curIndex, peer, 0, Hash.HASH_LENGTH);
Hash p = Hash.create(data, curIndex);
curIndex += Hash.HASH_LENGTH; curIndex += Hash.HASH_LENGTH;
addReply(new Hash(peer)); addReply(p);
} }
byte from[] = new byte[Hash.HASH_LENGTH]; //byte from[] = new byte[Hash.HASH_LENGTH];
System.arraycopy(data, curIndex, from, 0, Hash.HASH_LENGTH); //System.arraycopy(data, curIndex, from, 0, Hash.HASH_LENGTH);
_from = Hash.create(data, curIndex);
curIndex += Hash.HASH_LENGTH; curIndex += Hash.HASH_LENGTH;
_from = new Hash(from); //_from = new Hash(from);
//_context.statManager().addRateData("netDb.searchReplyMessageReceive", num*32 + 64, 1); //_context.statManager().addRateData("netDb.searchReplyMessageReceive", num*32 + 64, 1);
} }

View File

@ -113,10 +113,11 @@ public class DatabaseStoreMessage extends I2NPMessageImpl {
if (type != MESSAGE_TYPE) throw new I2NPMessageException("Message type is incorrect for this message"); if (type != MESSAGE_TYPE) throw new I2NPMessageException("Message type is incorrect for this message");
int curIndex = offset; int curIndex = offset;
byte keyData[] = new byte[Hash.HASH_LENGTH]; //byte keyData[] = new byte[Hash.HASH_LENGTH];
System.arraycopy(data, curIndex, keyData, 0, Hash.HASH_LENGTH); //System.arraycopy(data, curIndex, keyData, 0, Hash.HASH_LENGTH);
_key = Hash.create(data, curIndex);
curIndex += Hash.HASH_LENGTH; curIndex += Hash.HASH_LENGTH;
_key = new Hash(keyData); //_key = new Hash(keyData);
_type = (int)DataHelper.fromLong(data, curIndex, 1); _type = (int)DataHelper.fromLong(data, curIndex, 1);
curIndex++; curIndex++;
@ -130,10 +131,11 @@ public class DatabaseStoreMessage extends I2NPMessageImpl {
_replyTunnel = new TunnelId(tunnel); _replyTunnel = new TunnelId(tunnel);
curIndex += 4; curIndex += 4;
byte gw[] = new byte[Hash.HASH_LENGTH]; //byte gw[] = new byte[Hash.HASH_LENGTH];
System.arraycopy(data, curIndex, gw, 0, Hash.HASH_LENGTH); //System.arraycopy(data, curIndex, gw, 0, Hash.HASH_LENGTH);
_replyGateway = Hash.create(data, curIndex);
curIndex += Hash.HASH_LENGTH; curIndex += Hash.HASH_LENGTH;
_replyGateway = new Hash(gw); //_replyGateway = new Hash(gw);
} else { } else {
_replyTunnel = null; _replyTunnel = null;
_replyGateway = null; _replyGateway = null;

View File

@ -90,18 +90,21 @@ public class DeliveryInstructions extends DataStructureImpl {
case FLAG_MODE_LOCAL: case FLAG_MODE_LOCAL:
break; break;
case FLAG_MODE_DESTINATION: case FLAG_MODE_DESTINATION:
Hash destHash = new Hash(); //Hash destHash = new Hash();
destHash.readBytes(in); //destHash.readBytes(in);
Hash destHash = Hash.create(in);
setDestination(destHash); setDestination(destHash);
break; break;
case FLAG_MODE_ROUTER: case FLAG_MODE_ROUTER:
Hash routerHash = new Hash(); //Hash routerHash = new Hash();
routerHash.readBytes(in); //routerHash.readBytes(in);
Hash routerHash = Hash.create(in);
setRouter(routerHash); setRouter(routerHash);
break; break;
case FLAG_MODE_TUNNEL: case FLAG_MODE_TUNNEL:
Hash tunnelRouterHash = new Hash(); //Hash tunnelRouterHash = new Hash();
tunnelRouterHash.readBytes(in); //tunnelRouterHash.readBytes(in);
Hash tunnelRouterHash = Hash.create(in);
setRouter(tunnelRouterHash); setRouter(tunnelRouterHash);
TunnelId id = new TunnelId(); TunnelId id = new TunnelId();
id.readBytes(in); id.readBytes(in);
@ -140,22 +143,25 @@ public class DeliveryInstructions extends DataStructureImpl {
case FLAG_MODE_LOCAL: case FLAG_MODE_LOCAL:
break; break;
case FLAG_MODE_DESTINATION: case FLAG_MODE_DESTINATION:
byte destHash[] = new byte[Hash.HASH_LENGTH]; //byte destHash[] = new byte[Hash.HASH_LENGTH];
System.arraycopy(data, cur, destHash, 0, Hash.HASH_LENGTH); //System.arraycopy(data, cur, destHash, 0, Hash.HASH_LENGTH);
Hash dh = Hash.create(data, cur);
cur += Hash.HASH_LENGTH; cur += Hash.HASH_LENGTH;
setDestination(new Hash(destHash)); setDestination(dh);
break; break;
case FLAG_MODE_ROUTER: case FLAG_MODE_ROUTER:
byte routerHash[] = new byte[Hash.HASH_LENGTH]; //byte routerHash[] = new byte[Hash.HASH_LENGTH];
System.arraycopy(data, cur, routerHash, 0, Hash.HASH_LENGTH); //System.arraycopy(data, cur, routerHash, 0, Hash.HASH_LENGTH);
Hash rh = Hash.create(data, cur);
cur += Hash.HASH_LENGTH; cur += Hash.HASH_LENGTH;
setRouter(new Hash(routerHash)); setRouter(rh);
break; break;
case FLAG_MODE_TUNNEL: case FLAG_MODE_TUNNEL:
byte tunnelRouterHash[] = new byte[Hash.HASH_LENGTH]; //byte tunnelRouterHash[] = new byte[Hash.HASH_LENGTH];
System.arraycopy(data, cur, tunnelRouterHash, 0, Hash.HASH_LENGTH); //System.arraycopy(data, cur, tunnelRouterHash, 0, Hash.HASH_LENGTH);
Hash trh = Hash.create(data, cur);
cur += Hash.HASH_LENGTH; cur += Hash.HASH_LENGTH;
setRouter(new Hash(tunnelRouterHash)); setRouter(trh);
setTunnelId(new TunnelId(DataHelper.fromLong(data, cur, 4))); setTunnelId(new TunnelId(DataHelper.fromLong(data, cur, 4)));
cur += 4; cur += 4;
break; break;

View File

@ -18,7 +18,7 @@ public class RouterVersion {
/** deprecated */ /** deprecated */
public final static String ID = "Monotone"; public final static String ID = "Monotone";
public final static String VERSION = CoreVersion.VERSION; public final static String VERSION = CoreVersion.VERSION;
public final static long BUILD = 4; public final static long BUILD = 5;
/** for example "-test" */ /** for example "-test" */
public final static String EXTRA = ""; public final static String EXTRA = "";

View File

@ -28,7 +28,8 @@ class LookupDestJob extends JobImpl {
public String getName() { return "LeaseSet Lookup for Client"; } public String getName() { return "LeaseSet Lookup for Client"; }
public void runJob() { public void runJob() {
DoneJob done = new DoneJob(getContext()); DoneJob done = new DoneJob(getContext());
getContext().netDb().lookupLeaseSet(_hash, done, done, 10*1000); // TODO add support for specifying the timeout in the lookup message
getContext().netDb().lookupLeaseSet(_hash, done, done, 15*1000);
} }
private class DoneJob extends JobImpl { private class DoneJob extends JobImpl {
@ -41,7 +42,7 @@ class LookupDestJob extends JobImpl {
if (ls != null) if (ls != null)
returnDest(ls.getDestination()); returnDest(ls.getDestination());
else else
returnDest(null); returnHash(_hash);
} }
} }
@ -51,4 +52,15 @@ class LookupDestJob extends JobImpl {
_runner.doSend(msg); _runner.doSend(msg);
} catch (I2CPMessageException ime) {} } catch (I2CPMessageException ime) {}
} }
/**
* Return the failed hash so the client can correlate replies with requests
* @since 0.8.3
*/
private void returnHash(Hash h) {
DestReplyMessage msg = new DestReplyMessage(h);
try {
_runner.doSend(msg);
} catch (I2CPMessageException ime) {}
}
} }

View File

@ -13,6 +13,7 @@ import java.util.Set;
import java.util.zip.GZIPInputStream; import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream; import java.util.zip.GZIPOutputStream;
import net.i2p.data.Base64;
import net.i2p.data.DataFormatException; import net.i2p.data.DataFormatException;
import net.i2p.data.DataHelper; import net.i2p.data.DataHelper;
import net.i2p.data.Hash; import net.i2p.data.Hash;
@ -294,11 +295,15 @@ class ProfilePersistenceHelper {
private Hash getHash(String name) { private Hash getHash(String name) {
String key = name.substring("profile-".length()); String key = name.substring("profile-".length());
key = key.substring(0, key.length() - ".dat".length()); key = key.substring(0, key.length() - ".dat".length());
Hash h = new Hash(); //Hash h = new Hash();
try { try {
h.fromBase64(key); //h.fromBase64(key);
byte[] b = Base64.decode(key);
if (b == null)
return null;
Hash h = Hash.create(b);
return h; return h;
} catch (DataFormatException dfe) { } catch (Exception dfe) {
_log.warn("Invalid base64 [" + key + "]", dfe); _log.warn("Invalid base64 [" + key + "]", dfe);
return null; return null;
} }

View File

@ -327,11 +327,12 @@ public class FragmentHandler {
offset += 4; offset += 4;
} }
if ( (type == TYPE_ROUTER) || (type == TYPE_TUNNEL) ) { if ( (type == TYPE_ROUTER) || (type == TYPE_TUNNEL) ) {
byte h[] = new byte[Hash.HASH_LENGTH];
if (offset + Hash.HASH_LENGTH >= preprocessed.length) if (offset + Hash.HASH_LENGTH >= preprocessed.length)
return -1; return -1;
System.arraycopy(preprocessed, offset, h, 0, Hash.HASH_LENGTH); //byte h[] = new byte[Hash.HASH_LENGTH];
router = new Hash(h); //System.arraycopy(preprocessed, offset, h, 0, Hash.HASH_LENGTH);
//router = new Hash(h);
router = Hash.create(preprocessed, offset);
offset += Hash.HASH_LENGTH; offset += Hash.HASH_LENGTH;
} }
if (fragmented) { if (fragmented) {