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
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"));
boolean noThinsp = isDegraded || ua.startsWith("Opera");
if (_manager.util().connected()) {
if (isDegraded)
out.write("<a href=\"/i2psnark/?action=StopAll&amp;nonce=" + _nonce + "\"><img title=\"");
else
out.write("<input type=\"image\" name=\"action\" value=\"StopAll\" title=\"");
else {
// 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("\" src=\"" + _imgPath + "stop_all.png\" alt=\"");
out.write(_("Stop All"));
@ -347,7 +351,7 @@ public class I2PSnarkServlet extends Default {
if (isDegraded)
out.write("<a href=\"/i2psnark/?action=StartAll&amp;nonce=" + _nonce + "\"><img title=\"");
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("\" src=\"" + _imgPath + "start_all.png\" alt=\"");
out.write(_("Start All"));
@ -362,7 +366,7 @@ public class I2PSnarkServlet extends Default {
Snark snark = (Snark)snarks.get(i);
boolean showDebug = "2".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()) {
@ -403,10 +407,21 @@ public class I2PSnarkServlet extends Default {
*/
private void processRequest(HttpServletRequest req) {
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) {
_manager.addMessage("No action specified");
return;
}
}
// sadly, Opera doesn't send value with input type=image, so we have to use GET there
//if (!"POST".equals(req.getMethod())) {
// _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_ERROR_LENGTH = 43;
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;
File f = new File(filename);
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)
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()) + "\">" +
curPeers + thinsp(isDegraded) +
curPeers + thinsp(noThinsp) +
ngettext("1 peer", "{0} peers", knownPeers) + "</a>";
else if (isRunning)
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);
else {
if (err.length() > MAX_DISPLAYED_ERROR_LENGTH)
@ -774,11 +789,11 @@ public class I2PSnarkServlet extends Default {
if (isRunning && curPeers > 0 && !showPeers)
statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "seeding.png\" ></td><td class=\"snarkTorrentStatus " + rowClass + "\">" + _("Seeding") +
": <a href=\"" + uri + "?p=" + Base64.encode(snark.meta.getInfoHash()) + "\">" +
curPeers + thinsp(isDegraded) +
curPeers + thinsp(noThinsp) +
ngettext("1 peer", "{0} peers", knownPeers) + "</a>";
else if (isRunning)
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);
else
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)
statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "downloading.png\" ></td><td class=\"snarkTorrentStatus " + rowClass + "\">" + _("OK") +
": <a href=\"" + uri + "?p=" + Base64.encode(snark.meta.getInfoHash()) + "\">" +
curPeers + thinsp(isDegraded) +
curPeers + thinsp(noThinsp) +
ngettext("1 peer", "{0} peers", knownPeers) + "</a>";
else if (isRunning && curPeers > 0 && downBps > 0)
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);
else if (isRunning && curPeers > 0 && !showPeers)
statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "stalled.png\" ></td><td class=\"snarkTorrentStatus " + rowClass + "\">" + _("Stalled") +
": <a href=\"" + uri + "?p=" + Base64.encode(snark.meta.getInfoHash()) + "\">" +
curPeers + thinsp(isDegraded) +
curPeers + thinsp(noThinsp) +
ngettext("1 peer", "{0} peers", knownPeers) + "</a>";
else if (isRunning && curPeers > 0)
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);
else if (isRunning && knownPeers > 0)
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)
statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "nopeers.png\" ></td><td class=\"snarkTorrentStatus " + rowClass + "\">" + _("No Peers");
else
@ -880,7 +895,7 @@ public class I2PSnarkServlet extends Default {
out.write("</td>\n\t");
out.write("<td align=\"right\" class=\"snarkTorrentDownloaded " + rowClass + "\">");
if (remaining > 0)
out.write(formatSize(total-remaining) + thinsp(isDegraded) + formatSize(total));
out.write(formatSize(total-remaining) + thinsp(noThinsp) + formatSize(total));
else
out.write(formatSize(total)); // 3GB
out.write("</td>\n\t");
@ -905,7 +920,7 @@ public class I2PSnarkServlet extends Default {
if (isDegraded)
out.write("<a href=\"/i2psnark/?action=Stop_" + b64 + "&amp;nonce=" + _nonce + "\"><img title=\"");
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("\" src=\"" + _imgPath + "stop.png\" alt=\"");
out.write(_("Stop"));
@ -917,7 +932,7 @@ public class I2PSnarkServlet extends Default {
if (isDegraded)
out.write("<a href=\"/i2psnark/?action=Start_" + b64 + "&amp;nonce=" + _nonce + "\"><img title=\"");
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("\" src=\"" + _imgPath + "start.png\" alt=\"");
out.write(_("Start"));
@ -929,7 +944,7 @@ public class I2PSnarkServlet extends Default {
if (isDegraded)
out.write("<a href=\"/i2psnark/?action=Remove_" + b64 + "&amp;nonce=" + _nonce + "\"><img title=\"");
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("\" onclick=\"if (!confirm('");
// Can't figure out how to escape double quotes inside the onclick string.
@ -946,7 +961,7 @@ public class I2PSnarkServlet extends Default {
if (isDegraded)
out.write("<a href=\"/i2psnark/?action=Delete_" + b64 + "&amp;nonce=" + _nonce + "\"><img title=\"");
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("\" onclick=\"if (!confirm('");
// 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) {
StringBuilder buf = new StringBuilder(256);
// 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>");
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
* and the listenOnInterface field for the targetHost
*/
private void startStreamrClient() {
String targetHost = getListenOnInterface();
String targetHost = getTargetHost();
String targetPort = getListenPort();
String dest = getTargetDestination();
_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
* and the targetHost field for the listenOnInterface
*/
private void startStreamrServer() {
String listenOn = getTargetHost();
String listenOn = getListenOnInterface();
if ( (listenOn != null) && (listenOn.length() > 0) ) {
_tunnel.runListenOn(new String[] { listenOn }, this);
}

View File

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

View File

@ -63,7 +63,6 @@ public class IndexBean {
private String _proxyList;
private String _port;
private String _reachableBy;
private String _reachableByOther;
private String _targetDestination;
private String _targetHost;
private String _targetPort;
@ -432,10 +431,13 @@ public class IndexBean {
public String getClientInterface(int tunnel) {
TunnelController tun = getController(tunnel);
if (tun != null)
return tun.getListenOnInterface();
if (tun != null) {
if ("streamrclient".equals(tun.getType()))
return tun.getTargetHost();
else
return "";
return tun.getListenOnInterface();
} else
return "127.0.0.1";
}
public int getTunnelStatus(int tunnel) {
@ -478,11 +480,38 @@ public class IndexBean {
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) {
TunnelController tun = getController(tunnel);
if (tun != null)
return tun.getTargetHost() + ':' + tun.getTargetPort();
if (tun != null) {
String host;
if ("streamrserver".equals(tun.getType()))
host = tun.getListenOnInterface();
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 "";
}
@ -575,19 +604,11 @@ public class IndexBean {
_port = (port != null ? port.trim() : null);
}
/**
* what interface should this client/httpclient/ircclient listen on (unless
* overridden by the setReachableByOther() field)
* what interface should this client/httpclient/ircclient listen on
*/
public void setReachableBy(String reachableBy) {
_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 */
public void setTargetDestination(String dest) {
_targetDestination = (dest != null ? dest.trim() : null);
@ -891,17 +912,22 @@ public class IndexBean {
Properties config = new Properties();
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)) {
// generic client stuff
if (_port != null)
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 + "");
for (String p : _booleanClientOpts)
config.setProperty("option." + p, "" + _booleanOptions.contains(p));
@ -910,8 +936,6 @@ public class IndexBean {
config.setProperty("option." + p, _otherOptions.get(p));
} else {
// generic server stuff
if (_targetHost != null)
config.setProperty("targetHost", _targetHost);
if (_targetPort != null)
config.setProperty("targetPort", _targetPort);
for (String p : _booleanServerOpts)
@ -940,9 +964,7 @@ public class IndexBean {
if ("httpbidirserver".equals(_type)) {
if (_port != null)
config.setProperty("listenPort", _port);
if (_reachableByOther != null)
config.setProperty("interface", _reachableByOther);
else if (_reachableBy != null)
if (_reachableBy != null)
config.setProperty("interface", _reachableBy);
else if (_targetHost != null)
config.setProperty("interface", _targetHost);

View File

@ -80,7 +80,7 @@
<label><%=intl._("Target")%>:</label>
<% } else { %>
<label><%=intl._("Access Point")%>:</label>
<% } %>
<% } /* streamrclient */ %>
</div>
<div id="portField" class="rowItem">
<label for="port" accesskey="P">
@ -95,44 +95,39 @@
</label>
<input type="text" size="6" maxlength="5" id="port" name="port" title="Access Port Number" value="<%=editBean.getClientPort(curTunnel)%>" class="freetext" />
</div>
<% String otherInterface = "";
String clientInterface = editBean.getClientInterface(curTunnel);
if ("streamrclient".equals(tunnelType)) {
otherInterface = clientInterface;
} else { %>
<div id="reachField" class="rowItem">
<label for="reachableBy" accesskey="r">
<%=intl._("Reachable by")%>(<span class="accessKey">R</span>):
</label>
<select id="reachableBy" name="reachableBy" title="Valid IP for Client Access" class="selectbox">
<% if (!("127.0.0.1".equals(clientInterface)) &&
!("0.0.0.0".equals(clientInterface)) &&
(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())) {
<%
if ("streamrclient".equals(tunnelType)) {
out.write("Host:");
String targetHost = editBean.getTargetHost(curTunnel);
if (targetHost == null || "".equals(targetHost.trim())) {
out.write(" <font color=\"red\">(");
out.write(intl._("required"));
out.write(")</font>");
}
%>
<% } else { %>
<%=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" />
<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 class="subdivider">

View File

@ -89,16 +89,14 @@
<label><%=intl._("Target")%>:</label>
<% } %>
</div>
<% if (!"streamrserver".equals(tunnelType)) { %>
<div id="hostField" class="rowItem">
<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>):
<% } %>
</label>
<input type="text" size="20" id="targetHost" name="targetHost" title="Target Hostname or IP" value="<%=editBean.getTargetHost(curTunnel)%>" class="freetext" />
</div>
<% } /* !streamrserver */ %>
<div id="portField" class="rowItem">
<label for="targetPort" accesskey="P">
<%=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" />
</div>
<% if ("httpbidirserver".equals(tunnelType)) {
%>
<% if ("httpbidirserver".equals(tunnelType)) { %>
<div class="subdivider">
<hr />
</div>
@ -134,32 +131,30 @@
</label>
<input type="text" size="6" maxlength="5" id="port" name="port" title="Access Port Number" value="<%=editBean.getClientPort(curTunnel)%>" class="freetext" />
</div>
<% String otherInterface = "";
String clientInterface = editBean.getClientInterface(curTunnel);
%>
<% } /* httpbidirserver */ %>
<% if ("httpbidirserver".equals(tunnelType) || "streamrserver".equals(tunnelType)) { %>
<div id="reachField" class="rowItem">
<label for="reachableBy" accesskey="r">
<%=intl._("Reachable by")%>(<span class="accessKey">R</span>):
</label>
<select id="reachableBy" name="reachableBy" title="Valid IP for Client Access" class="selectbox">
<% if (!("127.0.0.1".equals(clientInterface)) &&
!("0.0.0.0".equals(clientInterface)) &&
(clientInterface != null) &&
(clientInterface.trim().length() > 0)) {
otherInterface = clientInterface;
<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");
}
%><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>
<div id="otherField" class="rowItem">
<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>
<% } %>
<% } /* httpbidirserver || streamrserver */ %>
<div class="subdivider">
<hr />
</div>
@ -302,7 +297,7 @@
<div class="subdivider">
<hr />
</div>
<% } // !streamrserver %>
<% } /* !streamrserver */ %>
<div id="optionsField" class="rowItem">
<label><%=intl._("Router I2CP Address")%>:</label>

View File

@ -95,7 +95,7 @@
<label><%=intl._("Points at")%>:</label>
<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>
<%
@ -213,7 +213,18 @@
</div>
<div class="portField rowItem">
<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 class="typeField rowItem">
<label><%=intl._("Type")%>:</label>
@ -221,7 +232,19 @@
</div>
<div class="interfaceField rowItem">
<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 class="statusField rowItem">
<label><%=intl._("Status")%>:</label>

View File

@ -327,11 +327,12 @@ public class ElGamalAESEngine {
//_log.debug("len: " + len);
if ((len < 0) || (len > decrypted.length - cur - Hash.HASH_LENGTH - 1))
throw new Exception("Invalid size of payload (" + len + ", remaining " + (decrypted.length-cur) +")");
byte hashval[] = new byte[Hash.HASH_LENGTH];
System.arraycopy(decrypted, cur, hashval, 0, Hash.HASH_LENGTH);
//byte hashval[] = new byte[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;
readHash = new Hash();
readHash.setData(hashval);
byte flag = decrypted[cur++];
if (flag == 0x01) {
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);
byte hashData[] = new byte[Hash.HASH_LENGTH];
System.arraycopy(val, i + 1, hashData, 0, Hash.HASH_LENGTH);
Hash hash = new Hash(hashData);
//byte hashData[] = new byte[Hash.HASH_LENGTH];
//System.arraycopy(val, i + 1, hashData, 0, Hash.HASH_LENGTH);
//Hash hash = new Hash(hashData);
Hash hash = Hash.create(val, i + 1);
byte rv[] = new byte[payloadLen];
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);
byte rv[] = digest.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) {

View File

@ -25,6 +25,33 @@ public class Hash extends SimpleDataStructure {
public final static int HASH_LENGTH = 32;
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() {
super();

View File

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

View File

@ -110,8 +110,9 @@ public class Lease extends DataStructureImpl {
}
public void readBytes(InputStream in) throws DataFormatException, IOException {
_gateway = new Hash();
_gateway.readBytes(in);
//_gateway = new Hash();
//_gateway.readBytes(in);
_gateway = Hash.create(in);
_tunnelId = new TunnelId();
_tunnelId.readBytes(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.
* 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 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() {
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.
* 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 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() {
super();

View File

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

View File

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

View File

@ -1,9 +1,9 @@
package net.i2p.util;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Queue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.LinkedBlockingQueue;
import net.i2p.I2PAppContext;
@ -57,7 +57,8 @@ import net.i2p.data.ByteArray;
*/
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
@ -74,8 +75,9 @@ public final class ByteCache {
/**
* Get a cache responsible for objects of the given size
*
* @param cacheSize how large we want the cache to grow before using on
* demand allocation
* @param cacheSize how large we want the cache to grow
* (number of objects, NOT memory size)
* before discarding released objects.
* Since 0.7.14, a limit of 1MB / size is enforced
* for the typical 128MB max memory JVM
* @param size how large should the objects cached be?
@ -84,12 +86,11 @@ public final class ByteCache {
if (cacheSize * size > MAX_CACHE)
cacheSize = MAX_CACHE / size;
Integer sz = Integer.valueOf(size);
ByteCache cache = null;
synchronized (_caches) {
if (!_caches.containsKey(sz))
_caches.put(sz, new ByteCache(cacheSize, size));
cache = _caches.get(sz);
}
ByteCache cache = _caches.get(sz);
if (cache == null) {
cache = new ByteCache(cacheSize, size);
_caches.put(sz, cache);
; }
cache.resize(cacheSize);
//I2PAppContext.getGlobalContext().logManager().getLog(ByteCache.class).error("ByteCache size: " + size + " max: " + cacheSize, new Exception("from"));
return cache;
@ -102,10 +103,9 @@ public final class ByteCache {
public static void clearAll() {
for (ByteCache bc : _caches.values())
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 */
private Queue<ByteArray> _available;
private int _maxCached;
@ -116,7 +116,7 @@ public final class ByteCache {
private static final boolean _cache = true;
/** 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 */
private static final long EXPIRE_PERIOD = 2*60*1000;
@ -126,9 +126,8 @@ public final class ByteCache {
_maxCached = maxCachedEntries;
_entrySize = entrySize;
_lastOverflow = -1;
SimpleScheduler.getInstance().addPeriodicEvent(new Cleanup(), CLEANUP_FREQUENCY);
_log = I2PAppContext.getGlobalContext().logManager().getLog(ByteCache.class);
I2PAppContext.getGlobalContext().statManager().createRateStat("byteCache.memory." + entrySize, "Memory usage (B)", "Router", new long[] { 60*1000 });
SimpleScheduler.getInstance().addPeriodicEvent(new Cleanup(), CLEANUP_FREQUENCY + (entrySize % 7)); //stagger
I2PAppContext.getGlobalContext().statManager().createRateStat("byteCache.memory." + entrySize, "Memory usage (B)", "Router", new long[] { 10*60*1000 });
}
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
* Console: Add 500 error page
* DSAEngine: Restore variants of methods using a Hash argument,
@ -42,7 +54,9 @@
- Add support for specifying the timeout for DestLookups
(can only be smaller than the router timeout for now)
- 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:
- Get Log from the logManager instead of instantiating,
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.
*/
public Hash readNextIdentity() {
byte rv[] = new byte[Hash.HASH_LENGTH];
System.arraycopy(_data.getData(), _data.getOffset() + OFF_SEND_IDENT, rv, 0, Hash.HASH_LENGTH);
return new Hash(rv);
//byte rv[] = new byte[Hash.HASH_LENGTH];
//System.arraycopy(_data.getData(), _data.getOffset() + OFF_SEND_IDENT, rv, 0, Hash.HASH_LENGTH);
//return new Hash(rv);
return Hash.create(_data.getData(), _data.getOffset() + OFF_SEND_IDENT);
}
/**
* 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");
int curIndex = offset;
byte keyData[] = new byte[Hash.HASH_LENGTH];
System.arraycopy(data, curIndex, keyData, 0, Hash.HASH_LENGTH);
//byte keyData[] = new byte[Hash.HASH_LENGTH];
//System.arraycopy(data, curIndex, keyData, 0, Hash.HASH_LENGTH);
_key = Hash.create(data, curIndex);
curIndex += Hash.HASH_LENGTH;
_key = new Hash(keyData);
//_key = new Hash(keyData);
byte fromData[] = new byte[Hash.HASH_LENGTH];
System.arraycopy(data, curIndex, fromData, 0, Hash.HASH_LENGTH);
//byte fromData[] = new byte[Hash.HASH_LENGTH];
//System.arraycopy(data, curIndex, fromData, 0, Hash.HASH_LENGTH);
_fromHash = Hash.create(data, curIndex);
curIndex += Hash.HASH_LENGTH;
_fromHash = new Hash(fromData);
//_fromHash = new Hash(fromData);
boolean tunnelSpecified = false;
switch (data[curIndex]) {
@ -168,10 +170,11 @@ public class DatabaseLookupMessage extends I2NPMessageImpl {
throw new I2NPMessageException("Invalid number of peers - " + numPeers);
Set<Hash> peers = new HashSet(numPeers);
for (int i = 0; i < numPeers; i++) {
byte peer[] = new byte[Hash.HASH_LENGTH];
System.arraycopy(data, curIndex, peer, 0, Hash.HASH_LENGTH);
//byte peer[] = new byte[Hash.HASH_LENGTH];
//System.arraycopy(data, curIndex, peer, 0, Hash.HASH_LENGTH);
Hash p = Hash.create(data, curIndex);
curIndex += Hash.HASH_LENGTH;
peers.add(new Hash(peer));
peers.add(p);
}
_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");
int curIndex = offset;
byte keyData[] = new byte[Hash.HASH_LENGTH];
System.arraycopy(data, curIndex, keyData, 0, Hash.HASH_LENGTH);
//byte keyData[] = new byte[Hash.HASH_LENGTH];
//System.arraycopy(data, curIndex, keyData, 0, Hash.HASH_LENGTH);
_key = Hash.create(data, curIndex);
curIndex += Hash.HASH_LENGTH;
_key = new Hash(keyData);
//_key = new Hash(keyData);
int num = (int)DataHelper.fromLong(data, curIndex, 1);
curIndex++;
_peerHashes.clear();
for (int i = 0; i < num; i++) {
byte peer[] = new byte[Hash.HASH_LENGTH];
System.arraycopy(data, curIndex, peer, 0, Hash.HASH_LENGTH);
//byte peer[] = new byte[Hash.HASH_LENGTH];
//System.arraycopy(data, curIndex, peer, 0, Hash.HASH_LENGTH);
Hash p = Hash.create(data, curIndex);
curIndex += Hash.HASH_LENGTH;
addReply(new Hash(peer));
addReply(p);
}
byte from[] = new byte[Hash.HASH_LENGTH];
System.arraycopy(data, curIndex, from, 0, Hash.HASH_LENGTH);
//byte from[] = new byte[Hash.HASH_LENGTH];
//System.arraycopy(data, curIndex, from, 0, Hash.HASH_LENGTH);
_from = Hash.create(data, curIndex);
curIndex += Hash.HASH_LENGTH;
_from = new Hash(from);
//_from = new Hash(from);
//_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");
int curIndex = offset;
byte keyData[] = new byte[Hash.HASH_LENGTH];
System.arraycopy(data, curIndex, keyData, 0, Hash.HASH_LENGTH);
//byte keyData[] = new byte[Hash.HASH_LENGTH];
//System.arraycopy(data, curIndex, keyData, 0, Hash.HASH_LENGTH);
_key = Hash.create(data, curIndex);
curIndex += Hash.HASH_LENGTH;
_key = new Hash(keyData);
//_key = new Hash(keyData);
_type = (int)DataHelper.fromLong(data, curIndex, 1);
curIndex++;
@ -130,10 +131,11 @@ public class DatabaseStoreMessage extends I2NPMessageImpl {
_replyTunnel = new TunnelId(tunnel);
curIndex += 4;
byte gw[] = new byte[Hash.HASH_LENGTH];
System.arraycopy(data, curIndex, gw, 0, Hash.HASH_LENGTH);
//byte gw[] = new byte[Hash.HASH_LENGTH];
//System.arraycopy(data, curIndex, gw, 0, Hash.HASH_LENGTH);
_replyGateway = Hash.create(data, curIndex);
curIndex += Hash.HASH_LENGTH;
_replyGateway = new Hash(gw);
//_replyGateway = new Hash(gw);
} else {
_replyTunnel = null;
_replyGateway = null;

View File

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

View File

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

View File

@ -28,7 +28,8 @@ class LookupDestJob extends JobImpl {
public String getName() { return "LeaseSet Lookup for Client"; }
public void runJob() {
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 {
@ -41,7 +42,7 @@ class LookupDestJob extends JobImpl {
if (ls != null)
returnDest(ls.getDestination());
else
returnDest(null);
returnHash(_hash);
}
}
@ -51,4 +52,15 @@ class LookupDestJob extends JobImpl {
_runner.doSend(msg);
} 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.GZIPOutputStream;
import net.i2p.data.Base64;
import net.i2p.data.DataFormatException;
import net.i2p.data.DataHelper;
import net.i2p.data.Hash;
@ -294,11 +295,15 @@ class ProfilePersistenceHelper {
private Hash getHash(String name) {
String key = name.substring("profile-".length());
key = key.substring(0, key.length() - ".dat".length());
Hash h = new Hash();
//Hash h = new Hash();
try {
h.fromBase64(key);
//h.fromBase64(key);
byte[] b = Base64.decode(key);
if (b == null)
return null;
Hash h = Hash.create(b);
return h;
} catch (DataFormatException dfe) {
} catch (Exception dfe) {
_log.warn("Invalid base64 [" + key + "]", dfe);
return null;
}

View File

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