diff --git a/apps/i2psnark/java/src/org/klomp/snark/PeerCoordinator.java b/apps/i2psnark/java/src/org/klomp/snark/PeerCoordinator.java index c3070913eedfd41601309d730b53ab9e7ec41956..bf869f41294fecff711a287c7e25a120e087030a 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/PeerCoordinator.java +++ b/apps/i2psnark/java/src/org/klomp/snark/PeerCoordinator.java @@ -522,6 +522,11 @@ public class PeerCoordinator implements PeerListener //Only request a piece we've requested before if there's no other choice. if (piece == null) { + // AND if there are almost no wanted pieces left (real end game). + // If we do end game all the time, we generate lots of extra traffic + // when the seeder is super-slow and all the peers are "caught up" + if (wantedPieces.size() > 4) + return -1; // nothing to request and not in end game // let's not all get on the same piece Collections.shuffle(requested); Iterator it2 = requested.iterator(); diff --git a/apps/i2psnark/java/src/org/klomp/snark/Snark.java b/apps/i2psnark/java/src/org/klomp/snark/Snark.java index 12c299840e3e17afef7213e228979ad21af7c985..5b7d32d0e1b37efaa9a9dae959dcfb9007b7ce3e 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/Snark.java +++ b/apps/i2psnark/java/src/org/klomp/snark/Snark.java @@ -734,7 +734,7 @@ public class Snark //if (debug >= INFO && t != null) // t.printStackTrace(); stopTorrent(); - throw new RuntimeException("die bart die"); + throw new RuntimeException(s + (t == null ? "" : ": " + t.getMessage())); } /** diff --git a/apps/i2psnark/java/src/org/klomp/snark/Storage.java b/apps/i2psnark/java/src/org/klomp/snark/Storage.java index 63787fe0530e292da24222ba4f3f2e2ace4147ed..3e341cc09d507909870bbdd7348b395eae92c4b7 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/Storage.java +++ b/apps/i2psnark/java/src/org/klomp/snark/Storage.java @@ -286,6 +286,40 @@ public class Storage return needed == 0; } + /** + * @param file absolute path (non-directory) + * @return number of bytes remaining; -1 if unknown file + * @since 0.7.14 + */ + public long remaining(String file) { + long bytes = 0; + for (int i = 0; i < rafs.length; i++) { + File f = RAFfile[i]; + if (f != null && f.getAbsolutePath().equals(file)) { + if (complete()) + return 0; + int psz = metainfo.getPieceLength(0); + long start = bytes; + long end = start + lengths[i]; + int pc = (int) (bytes / psz); + long rv = 0; + if (!bitfield.get(pc)) + rv = psz - (bytes % psz); + for (int j = pc + 1; j * psz < end; j++) { + if (!bitfield.get(j)) { + if ((j+1)*psz < end) + rv += psz; + else + rv += end - (j * psz); + } + } + return rv; + } + bytes += lengths[i]; + } + return -1; + } + /** * The BitField that tells which pieces this storage contains. * Do not change this since this is the current state of the storage. diff --git a/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java b/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java index a5f33094dca01c9f7fa31533eea77a10cdc5b53e..85c0e917c9b4b1ca45e61da068eed1f6d010aecf 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java +++ b/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java @@ -7,6 +7,7 @@ import java.io.IOException; import java.io.PrintWriter; import java.text.Collator; import java.util.ArrayList; +import java.util.Arrays; import java.util.Comparator; import java.util.Enumeration; import java.util.Iterator; @@ -37,7 +38,10 @@ import org.klomp.snark.SnarkManager; import org.klomp.snark.Storage; import org.klomp.snark.TrackerClient; +import org.mortbay.http.HttpResponse; import org.mortbay.jetty.servlet.Default; +import org.mortbay.util.Resource; +import org.mortbay.util.URI; /** * We extend Default instead of HTTPServlet so we can handle @@ -105,13 +109,52 @@ public class I2PSnarkServlet extends Default { super.destroy(); } + /** + * Some parts modified from: + * <pre> + // ======================================================================== + // $Id: Default.java,v 1.51 2006/10/08 14:13:18 gregwilkins Exp $ + // Copyright 199-2004 Mort Bay Consulting Pty. Ltd. + // ------------------------------------------------------------------------ + // Licensed under the Apache License, Version 2.0 (the "License"); + // you may not use this file except in compliance with the License. + // You may obtain a copy of the License at + // http://www.apache.org/licenses/LICENSE-2.0 + // Unless required by applicable law or agreed to in writing, software + // distributed under the License is distributed on an "AS IS" BASIS, + // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + // See the License for the specific language governing permissions and + // limitations under the License. + // ======================================================================== + * </pre> + * + */ @Override public void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // this is the part after /i2psnark String path = req.getServletPath(); // index.jsp doesn't work, it is grabbed by the war handler before here if (!(path == null || path.equals("/") || path.equals("/index.jsp") || path.equals("/index.html"))) { - super.service(req, resp); + if (path.endsWith("/")) { + // bypass the horrid Resource.getListHTML() + String pathInfo = req.getPathInfo(); + String pathInContext = URI.addPaths(path, pathInfo); + resp.setCharacterEncoding("UTF-8"); + resp.setContentType("text/html; charset=UTF-8"); + Resource resource = getResource(pathInContext); + if (resource == null || (!resource.exists()) || !resource.isDirectory()) { + resp.sendError(HttpResponse.__404_Not_Found); + } else { + String base = URI.addPaths(req.getRequestURI(), "/"); + String listing = getListHTML(resource, base, true); + if (listing != null) + resp.getWriter().write(listing); + else // shouldn't happen + resp.sendError(HttpResponse.__404_Not_Found); + } + } else { + super.service(req, resp); + } return; } @@ -305,7 +348,7 @@ public class I2PSnarkServlet extends Default { } } else if (newURL != null) { if (newURL.startsWith("http://")) { - _manager.addMessage(_("Fetching {0}", newURL)); + _manager.addMessage(_("Fetching {0}", urlify(newURL))); I2PAppThread fetch = new I2PAppThread(new FetchAndAdd(_manager, newURL), "Fetch and add"); fetch.start(); } else { @@ -643,7 +686,7 @@ public class I2PSnarkServlet extends Default { out.write(statusString + "</td>\n\t"); out.write("<td align=\"left\" class=\"snarkTorrentName " + rowClass + "\">"); - if (remaining == 0) { + if (remaining == 0 || snark.meta.getFiles() != null) { out.write("<a href=\"" + snark.meta.getName()); if (snark.meta.getFiles() != null) out.write("/"); @@ -655,7 +698,7 @@ public class I2PSnarkServlet extends Default { out.write("\">"); } out.write(filename); - if (remaining == 0) + if (remaining == 0 || snark.meta.getFiles() != null) out.write("</a>"); // temporarily hardcoded for postman* and anonymity, requires bytemonsoon patch for lookup by info_hash String announce = snark.meta.getAnnounce(); @@ -689,7 +732,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) + "/" + formatSize(total)); // 18MB/3GB + out.write(formatSize(total-remaining) + " / " + formatSize(total)); // 18MB/3GB else out.write(formatSize(total)); // 3GB out.write("</td>\n\t"); @@ -966,14 +1009,14 @@ public class I2PSnarkServlet extends Default { */ out.write("<tr><td>"); out.write(_("Total uploader limit")); - out.write(": <td><input type=\"text\" name=\"upLimit\" value=\"" + out.write(": <td><input type=\"text\" name=\"upLimit\" class=\"r\" value=\"" + _manager.util().getMaxUploaders() + "\" size=\"3\" maxlength=\"3\" > "); out.write(_("peers")); out.write("<br>\n"); out.write("<tr><td>"); out.write(_("Up bandwidth limit")); - out.write(": <td><input type=\"text\" name=\"upBW\" value=\"" + out.write(": <td><input type=\"text\" name=\"upBW\" class=\"r\" value=\"" + _manager.util().getMaxUpBW() + "\" size=\"3\" maxlength=\"3\" > KBps <i>("); out.write(_("Half available bandwidth recommended.")); out.write(" <a href=\"/config.jsp\" target=\"blank\">"); @@ -1020,7 +1063,7 @@ public class I2PSnarkServlet extends Default { out.write("<tr><td>"); out.write(_("I2CP port")); - out.write(": <td><input type=\"text\" name=\"i2cpPort\" value=\"" + + out.write(": <td><input type=\"text\" name=\"i2cpPort\" class=\"r\" value=\"" + + _manager.util().getI2CPPort() + "\" size=\"5\" maxlength=\"5\" > <br>\n"); StringBuilder opts = new StringBuilder(64); @@ -1090,18 +1133,24 @@ public class I2PSnarkServlet extends Default { } // rounding makes us look faster :) - private String formatSize(long bytes) { + private static String formatSize(long bytes) { if (bytes < 5*1024) - return bytes + "B"; + return bytes + " B"; else if (bytes < 5*1024*1024) - return ((bytes + 512)/1024) + "KB"; + return ((bytes + 512)/1024) + " KB"; else if (bytes < 10*1024*1024*1024l) - return ((bytes + 512*1024)/(1024*1024)) + "MB"; + return ((bytes + 512*1024)/(1024*1024)) + " MB"; else - return ((bytes + 512*1024*1024)/(1024*1024*1024)) + "GB"; + return ((bytes + 512*1024*1024)/(1024*1024*1024)) + " GB"; } - private static final String HEADER = "<link href=\"../themes/console/snark.css\" rel=\"stylesheet\" type=\"text/css\" >"; + private static String urlify(String s) { + StringBuilder buf = new StringBuilder(256); + buf.append("<a href=\"").append(s).append("\">").append(s).append("</a>"); + return buf.toString(); + } + + private static final String HEADER = "<link href=\"/themes/console/snark.css\" rel=\"stylesheet\" type=\"text/css\" >"; private static final String TABLE_HEADER = "<table border=\"0\" class=\"snarkTorrents\" width=\"100%\" cellpadding=\"0 10px\">\n" + @@ -1112,6 +1161,169 @@ public class I2PSnarkServlet extends Default { private static final String FOOTER = "</div></div></div></center></body></html>"; + /** + * Modded heavily from the Jetty version in Resource.java, + * pass Resource as 1st param + * All the xxxResource constructors are package local so we can't extend them. + * + * <pre> + // ======================================================================== + // $Id: Resource.java,v 1.32 2009/05/16 01:53:36 gregwilkins Exp $ + // Copyright 1996-2004 Mort Bay Consulting Pty. Ltd. + // ------------------------------------------------------------------------ + // Licensed under the Apache License, Version 2.0 (the "License"); + // you may not use this file except in compliance with the License. + // You may obtain a copy of the License at + // http://www.apache.org/licenses/LICENSE-2.0 + // Unless required by applicable law or agreed to in writing, software + // distributed under the License is distributed on an "AS IS" BASIS, + // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + // See the License for the specific language governing permissions and + // limitations under the License. + // ======================================================================== + * </pre> + * + * Get the resource list as a HTML directory listing. + * @param r The Resource + * @param base The base URL + * @param parent True if the parent directory should be included + * @return String of HTML + */ + private String getListHTML(Resource r, String base, boolean parent) + throws IOException + { + if (!r.isDirectory()) + return null; + + String[] ls = r.list(); + if (ls==null) + return null; + Arrays.sort(ls, Collator.getInstance()); + + StringBuilder buf=new StringBuilder(4096); + buf.append("<HTML><HEAD><TITLE>"); + String title = URI.decodePath(base); + if (title.startsWith("/i2psnark/")) + title = title.substring("/i2psnark/".length()); + + // Get the snark associated with this directory + Snark snark = null; + try { + String torrentName; + int slash = title.indexOf('/'); + if (slash > 0) + torrentName = title.substring(0, slash) + ".torrent"; + else + torrentName = title + ".torrent"; + File dataDir = _manager.getDataDir(); + String torrentAbsPath = (new File(dataDir, torrentName)).getCanonicalPath(); + snark = _manager.getTorrent(torrentAbsPath); + } catch (IOException ioe) {} + if (title.endsWith("/")) + title = title.substring(0, title.length() - 1); + title = _("Torrent") + ": " + title; + buf.append(title); + buf.append("</TITLE>").append(HEADER).append("</HEAD><BODY>\n<div class=\"snarknavbar\">"); + buf.append(title); + + if (parent) + { + buf.append("\n<br><A HREF=\""); + // corrupts utf-8 + //buf.append(URI.encodePath(URI.addPaths(base,"../"))); + buf.append(URI.addPaths(base,"../")); + buf.append("\"><img border=\"0\" src=\"/themes/console/images/outbound.png\"> ") + .append(_("Up to higher level directory")).append("</A>\n"); + } + + buf.append("</div><div class=\"page\"><div class=\"mainsection\">" + + "<TABLE BORDER=0 class=\"snarkTorrents\" cellpadding=\"5px 10px\">" + + "<thead><tr><th>").append(_("File")).append("</th><th>").append(_("Size")) + .append("</th><th>").append(_("Status")).append("</th></tr></thead>"); + //DateFormat dfmt=DateFormat.getDateTimeInstance(DateFormat.MEDIUM, + // DateFormat.MEDIUM); + for (int i=0 ; i< ls.length ; i++) + { + String encoded=URI.encodePath(ls[i]); + // bugfix for I2P - Backport from Jetty 6 (zero file lengths and last-modified times) + // http://jira.codehaus.org/browse/JETTY-361?page=com.atlassian.jira.plugin.system.issuetabpanels%3Achangehistory-tabpanel#issue-tabs + // See resource.diff attachment + //Resource item = addPath(encoded); + Resource item = r.addPath(ls[i]); + + String rowClass = (i % 2 == 0 ? "snarkTorrentEven" : "snarkTorrentOdd"); + buf.append("<TR class=\"").append(rowClass).append("\"><TD class=\"snarkFileName ") + .append(rowClass).append("\">"); + + // Get completeness and status string + boolean complete = false; + String status = ""; + long length = item.length(); + if (item.isDirectory()) { + complete = true; + status = _("Directory"); + } else { + if (snark == null) { + status = "Snark not found?"; + } else { + try { + File f = item.getFile(); + if (f != null) { + long remaining = snark.storage.remaining(f.getCanonicalPath()); + if (remaining == 0) { + complete = true; + status = _("Complete"); + } else if (remaining < 0) { + complete = true; + status = _("File not found in torrent?"); + } else if (length <= 0) { + complete = true; + status = _("Complete"); + } else { + status = (100 - (100 * remaining / length)) + "% " + _("complete") + + " (" + DataHelper.formatSize(remaining) + " bytes remaining)"; + } + } else { + status = "Not a file?"; + } + } catch (IOException ioe) { + status = "Not a file? " + ioe; + } + } + } + + String path=URI.addPaths(base,encoded); + if (item.isDirectory() && !path.endsWith("/")) + path=URI.addPaths(path,"/"); + if (complete) { + // thumbnail ? + String plc = path.toLowerCase(); + if (plc.endsWith(".jpg") || plc.endsWith(".png") || plc.endsWith(".gif")) { + buf.append("<a href=\"").append(path).append("\"><img alt=\"\" border=\"0\" class=\"thumb\" src=\"") + .append(path).append("\"></a> "); + } + buf.append("<A HREF=\""); + buf.append(path); + buf.append("\">"); + } + buf.append(ls[i]); + if (complete) + buf.append("</a>"); + buf.append("</TD><TD ALIGN=right class=\"").append(rowClass).append("\">"); + if (!item.isDirectory()) + buf.append(DataHelper.formatSize(length)).append(' ').append(_("Bytes")); + buf.append("</TD><TD>"); + //buf.append(dfmt.format(new Date(item.lastModified()))); + buf.append(status); + buf.append("</TD></TR>\n"); + } + buf.append("</TABLE>\n"); + buf.append("</div></div></BODY></HTML>\n"); + + return buf.toString(); + } + + /** inner class, don't bother reindenting */ private static class FetchAndAdd implements Runnable { private SnarkManager _manager; @@ -1126,7 +1338,7 @@ private static class FetchAndAdd implements Runnable { File file = _manager.util().get(_url, false, 3); try { if ( (file != null) && (file.exists()) && (file.length() > 0) ) { - _manager.addMessage(_("Torrent fetched from {0}", _url)); + _manager.addMessage(_("Torrent fetched from {0}", urlify(_url))); FileInputStream in = null; try { in = new FileInputStream(file); @@ -1154,12 +1366,12 @@ private static class FetchAndAdd implements Runnable { _manager.addTorrent(canonical); } } catch (IOException ioe) { - _manager.addMessage(_("Torrent at {0} was not valid", _url) + ": " + ioe.getMessage()); + _manager.addMessage(_("Torrent at {0} was not valid", urlify(_url)) + ": " + ioe.getMessage()); } finally { try { in.close(); } catch (IOException ioe) {} } } else { - _manager.addMessage(_("Torrent was not retrieved from {0}", _url)); + _manager.addMessage(_("Torrent was not retrieved from {0}", urlify(_url))); } } finally { if (file != null) file.delete(); diff --git a/apps/routerconsole/java/src/net/i2p/router/web/StatSummarizer.java b/apps/routerconsole/java/src/net/i2p/router/web/StatSummarizer.java index 15232fbcc88574fec2383f93dabe2c8c3a78a9e5..0bcaaf315ae62fe59acd4dd23bfc9db62871442b 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/StatSummarizer.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/StatSummarizer.java @@ -149,6 +149,10 @@ public class StatSummarizer implements Runnable { return false; } + /** + * This does the two-data bandwidth graph only. + * For all other graphs see SummaryRenderer + */ public boolean renderRatePng(OutputStream out, int width, int height, boolean hideLegend, boolean hideGrid, boolean hideTitle, boolean showEvents, int periodCount, boolean showCredit) throws IOException { long end = _context.clock().now() - 60*1000; if (width > GraphHelper.MAX_X) @@ -166,22 +170,22 @@ public class StatSummarizer implements Runnable { def.setTimePeriod(start/1000, 0); def.setLowerLimit(0d); def.setBaseValue(1024); - String title = "Bandwidth usage"; + String title = _("Bandwidth usage"); if (!hideTitle) def.setTitle(title); String sendName = SummaryListener.createName(_context, "bw.sendRate.60000"); String recvName = SummaryListener.createName(_context, "bw.recvRate.60000"); def.datasource(sendName, sendName, sendName, "AVERAGE", "MEMORY"); def.datasource(recvName, recvName, recvName, "AVERAGE", "MEMORY"); - def.area(sendName, Color.BLUE, "Outbound bytes/sec"); + def.area(sendName, Color.BLUE, _("Outbound bytes/sec")); //def.line(sendName, Color.BLUE, "Outbound bytes/sec", 3); - def.line(recvName, Color.RED, "Inbound bytes/sec@r", 3); + def.line(recvName, Color.RED, _("Inbound bytes/sec") + "@r", 3); //def.area(recvName, Color.RED, "Inbound bytes/sec@r"); if (!hideLegend) { - def.gprint(sendName, "AVERAGE", "out average: @2@sbytes/sec"); - def.gprint(sendName, "MAX", " max: @2@sbytes/sec@r"); - def.gprint(recvName, "AVERAGE", "in average: @2@sbytes/sec"); - def.gprint(recvName, "MAX", " max: @2@sbytes/sec@r"); + def.gprint(sendName, "AVERAGE", _("out average") + ": @2@s" + _("bytes/sec")); + def.gprint(sendName, "MAX", ' ' + _("max") + ": @2@s" + _("bytes/sec") + "@r"); + def.gprint(recvName, "AVERAGE", _("in average") + ": @2@s" + _("bytes/sec")); + def.gprint(recvName, "MAX", ' ' + _("max") + ": @2@s" + _("bytes/sec") + "@r"); } if (!showCredit) def.setShowSignature(false); @@ -248,4 +252,12 @@ public class StatSummarizer implements Runnable { } return rv; } + + /** translate a string */ + private String _(String s) { + // the RRD font doesn't have zh chars, at least on my system + if ("zh".equals(Messages.getLanguage(_context))) + return s; + return Messages.getString(s, _context); + } } diff --git a/apps/routerconsole/java/src/net/i2p/router/web/SummaryListener.java b/apps/routerconsole/java/src/net/i2p/router/web/SummaryListener.java index f34659cdbb4f169f5f2a989ed4b876c42f3f6116..0d066233ed80aabc390968a1a9cc4dcd11181a31 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/SummaryListener.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/SummaryListener.java @@ -142,127 +142,3 @@ class SummaryListener implements RateSummaryListener { @Override public int hashCode() { return _rate.hashCode(); } } - -class SummaryRenderer { - private Log _log; - private SummaryListener _listener; - public SummaryRenderer(I2PAppContext ctx, SummaryListener lsnr) { - _log = ctx.logManager().getLog(SummaryRenderer.class); - _listener = lsnr; - } - - /** - * Render the stats as determined by the specified JRobin xml config, - * but note that this doesn't work on stock jvms, as it requires - * DOM level 3 load and store support. Perhaps we can bundle that, or - * specify who can get it from where, etc. - * - */ - public static synchronized void render(I2PAppContext ctx, OutputStream out, String filename) throws IOException { - long end = ctx.clock().now() - 60*1000; - long start = end - 60*1000*SummaryListener.PERIODS; - try { - RrdGraphDefTemplate template = new RrdGraphDefTemplate(filename); - RrdGraphDef def = template.getRrdGraphDef(); - def.setTimePeriod(start/1000, end/1000); // ignore the periods in the template - RrdGraph graph = new RrdGraph(def); - byte img[] = graph.getPNGBytes(); - out.write(img); - } catch (RrdException re) { - //_log.error("Error rendering " + filename, re); - throw new IOException("Error plotting: " + re.getMessage()); - } catch (IOException ioe) { - //_log.error("Error rendering " + filename, ioe); - throw ioe; - } - } - public void render(OutputStream out) throws IOException { render(out, -1, -1, false, false, false, false, -1, false); } - public void render(OutputStream out, int width, int height, boolean hideLegend, boolean hideGrid, boolean hideTitle, boolean showEvents, int periodCount, boolean showCredit) throws IOException { - long end = _listener.now() - 60*1000; - if (periodCount <= 0) periodCount = SummaryListener.PERIODS; - if (periodCount > SummaryListener.PERIODS) - periodCount = SummaryListener.PERIODS; - long start = end - _listener.getRate().getPeriod()*periodCount; - //long begin = System.currentTimeMillis(); - try { - RrdGraphDef def = new RrdGraphDef(); - def.setTimePeriod(start/1000, 0); - def.setLowerLimit(0d); - String name = _listener.getRate().getRateStat().getName(); - // heuristic to set K=1024 - if ((name.startsWith("bw.") || name.indexOf("Size") >= 0 || name.indexOf("Bps") >= 0 || name.indexOf("memory") >= 0) - && !showEvents) - def.setBaseValue(1024); - String title = name; - if (showEvents) - title = title + " events in "; - else - title = title + " averaged for "; - title = title + DataHelper.formatDuration(_listener.getRate().getPeriod()); - if (!hideTitle) - def.setTitle(title); - String path = _listener.getData().getPath(); - String dsNames[] = _listener.getData().getDsNames(); - String plotName = null; - String descr = null; - if (showEvents) { - // include the average event count on the plot - plotName = dsNames[1]; - descr = "Events per period"; - } else { - // include the average value - plotName = dsNames[0]; - descr = _listener.getRate().getRateStat().getDescription(); - } - def.datasource(plotName, path, plotName, "AVERAGE", "MEMORY"); - def.area(plotName, Color.BLUE, descr + "@r"); - if (!hideLegend) { - def.gprint(plotName, "AVERAGE", "avg: @2@s"); - def.gprint(plotName, "MAX", " max: @2@s"); - def.gprint(plotName, "LAST", " now: @2@s@r"); - } - if (!showCredit) - def.setShowSignature(false); - /* - // these four lines set up a graph plotting both values and events on the same chart - // (but with the same coordinates, so the values may look pretty skewed) - def.datasource(dsNames[0], path, dsNames[0], "AVERAGE", "MEMORY"); - def.datasource(dsNames[1], path, dsNames[1], "AVERAGE", "MEMORY"); - def.area(dsNames[0], Color.BLUE, _listener.getRate().getRateStat().getDescription()); - def.line(dsNames[1], Color.RED, "Events per period"); - */ - if (hideLegend) - def.setShowLegend(false); - if (hideGrid) { - def.setGridX(false); - def.setGridY(false); - } - //System.out.println("rendering: path=" + path + " dsNames[0]=" + dsNames[0] + " dsNames[1]=" + dsNames[1] + " lsnr.getName=" + _listener.getName()); - def.setAntiAliasing(false); - //System.out.println("Rendering: \n" + def.exportXmlTemplate()); - //System.out.println("*****************\nData: \n" + _listener.getData().dump()); - RrdGraph graph = new RrdGraph(def); - //System.out.println("Graph created"); - byte data[] = null; - if ( (width <= 0) || (height <= 0) ) - data = graph.getPNGBytes(); - else - data = graph.getPNGBytes(width, height); - //long timeToPlot = System.currentTimeMillis() - begin; - out.write(data); - //File t = File.createTempFile("jrobinData", ".xml"); - //_listener.getData().dumpXml(new FileOutputStream(t)); - //System.out.println("plotted: " + (data != null ? data.length : 0) + " bytes in " + timeToPlot - // ); // + ", data written to " + t.getAbsolutePath()); - } catch (RrdException re) { - _log.error("Error rendering", re); - throw new IOException("Error plotting: " + re.getMessage()); - } catch (IOException ioe) { - _log.error("Error rendering", ioe); - throw ioe; - } catch (OutOfMemoryError oom) { - _log.error("Error rendering", oom); - throw new IOException("Error plotting: " + oom.getMessage()); - } - } -} diff --git a/apps/routerconsole/java/src/net/i2p/router/web/SummaryRenderer.java b/apps/routerconsole/java/src/net/i2p/router/web/SummaryRenderer.java new file mode 100644 index 0000000000000000000000000000000000000000..7ee62510bac4dff2dc28c8db28e2163a6f955a56 --- /dev/null +++ b/apps/routerconsole/java/src/net/i2p/router/web/SummaryRenderer.java @@ -0,0 +1,170 @@ +package net.i2p.router.web; + +import java.awt.Color; +import java.io.IOException; +import java.io.OutputStream; + +import net.i2p.I2PAppContext; +import net.i2p.data.DataHelper; +import net.i2p.stat.Rate; +import net.i2p.stat.RateStat; +import net.i2p.stat.RateSummaryListener; +import net.i2p.util.Log; + +import org.jrobin.core.RrdBackendFactory; +import org.jrobin.core.RrdDb; +import org.jrobin.core.RrdDef; +import org.jrobin.core.RrdException; +import org.jrobin.core.RrdMemoryBackendFactory; +import org.jrobin.core.Sample; +import org.jrobin.graph.RrdGraph; +import org.jrobin.graph.RrdGraphDef; +import org.jrobin.graph.RrdGraphDefTemplate; + +class SummaryRenderer { + private Log _log; + private SummaryListener _listener; + private I2PAppContext _context; + + public SummaryRenderer(I2PAppContext ctx, SummaryListener lsnr) { + _log = ctx.logManager().getLog(SummaryRenderer.class); + _listener = lsnr; + _context = ctx; + } + + /** + * Render the stats as determined by the specified JRobin xml config, + * but note that this doesn't work on stock jvms, as it requires + * DOM level 3 load and store support. Perhaps we can bundle that, or + * specify who can get it from where, etc. + * + */ + public static synchronized void render(I2PAppContext ctx, OutputStream out, String filename) throws IOException { + long end = ctx.clock().now() - 60*1000; + long start = end - 60*1000*SummaryListener.PERIODS; + try { + RrdGraphDefTemplate template = new RrdGraphDefTemplate(filename); + RrdGraphDef def = template.getRrdGraphDef(); + def.setTimePeriod(start/1000, end/1000); // ignore the periods in the template + RrdGraph graph = new RrdGraph(def); + byte img[] = graph.getPNGBytes(); + out.write(img); + } catch (RrdException re) { + //_log.error("Error rendering " + filename, re); + throw new IOException("Error plotting: " + re.getMessage()); + } catch (IOException ioe) { + //_log.error("Error rendering " + filename, ioe); + throw ioe; + } + } + + public void render(OutputStream out) throws IOException { render(out, -1, -1, false, false, false, false, -1, false); } + + public void render(OutputStream out, int width, int height, boolean hideLegend, boolean hideGrid, boolean hideTitle, boolean showEvents, int periodCount, boolean showCredit) throws IOException { + long end = _listener.now() - 60*1000; + if (periodCount <= 0) periodCount = SummaryListener.PERIODS; + if (periodCount > SummaryListener.PERIODS) + periodCount = SummaryListener.PERIODS; + long start = end - _listener.getRate().getPeriod()*periodCount; + //long begin = System.currentTimeMillis(); + try { + RrdGraphDef def = new RrdGraphDef(); + def.setTimePeriod(start/1000, 0); + def.setLowerLimit(0d); + String name = _listener.getRate().getRateStat().getName(); + // heuristic to set K=1024 + if ((name.startsWith("bw.") || name.indexOf("Size") >= 0 || name.indexOf("Bps") >= 0 || name.indexOf("memory") >= 0) + && !showEvents) + def.setBaseValue(1024); + if (!hideTitle) { + String title; + String p = DataHelper.formatDuration(_listener.getRate().getPeriod()); + if (showEvents) + title = name + ' ' + _("events in {0}", p); + else + title = name + ' ' + _("averaged for {0}", p); + def.setTitle(title); + } + String path = _listener.getData().getPath(); + String dsNames[] = _listener.getData().getDsNames(); + String plotName = null; + String descr = null; + if (showEvents) { + // include the average event count on the plot + plotName = dsNames[1]; + descr = _("Events per period"); + } else { + // include the average value + plotName = dsNames[0]; + descr = _listener.getRate().getRateStat().getDescription(); + } + def.datasource(plotName, path, plotName, "AVERAGE", "MEMORY"); + def.area(plotName, Color.BLUE, descr + "@r"); + if (!hideLegend) { + def.gprint(plotName, "AVERAGE", _("avg") + ": @2@s"); + def.gprint(plotName, "MAX", ' ' + _("max") + ": @2@s"); + def.gprint(plotName, "LAST", ' ' + _("now") + ": @2@s@r"); + } + if (!showCredit) + def.setShowSignature(false); + /* + // these four lines set up a graph plotting both values and events on the same chart + // (but with the same coordinates, so the values may look pretty skewed) + def.datasource(dsNames[0], path, dsNames[0], "AVERAGE", "MEMORY"); + def.datasource(dsNames[1], path, dsNames[1], "AVERAGE", "MEMORY"); + def.area(dsNames[0], Color.BLUE, _listener.getRate().getRateStat().getDescription()); + def.line(dsNames[1], Color.RED, "Events per period"); + */ + if (hideLegend) + def.setShowLegend(false); + if (hideGrid) { + def.setGridX(false); + def.setGridY(false); + } + //System.out.println("rendering: path=" + path + " dsNames[0]=" + dsNames[0] + " dsNames[1]=" + dsNames[1] + " lsnr.getName=" + _listener.getName()); + def.setAntiAliasing(false); + //System.out.println("Rendering: \n" + def.exportXmlTemplate()); + //System.out.println("*****************\nData: \n" + _listener.getData().dump()); + RrdGraph graph = new RrdGraph(def); + //System.out.println("Graph created"); + byte data[] = null; + if ( (width <= 0) || (height <= 0) ) + data = graph.getPNGBytes(); + else + data = graph.getPNGBytes(width, height); + //long timeToPlot = System.currentTimeMillis() - begin; + out.write(data); + //File t = File.createTempFile("jrobinData", ".xml"); + //_listener.getData().dumpXml(new FileOutputStream(t)); + //System.out.println("plotted: " + (data != null ? data.length : 0) + " bytes in " + timeToPlot + // ); // + ", data written to " + t.getAbsolutePath()); + } catch (RrdException re) { + _log.error("Error rendering", re); + throw new IOException("Error plotting: " + re.getMessage()); + } catch (IOException ioe) { + _log.error("Error rendering", ioe); + throw ioe; + } catch (OutOfMemoryError oom) { + _log.error("Error rendering", oom); + throw new IOException("Error plotting: " + oom.getMessage()); + } + } + + /** translate a string */ + private String _(String s) { + // the RRD font doesn't have zh chars, at least on my system + if ("zh".equals(Messages.getLanguage(_context))) + return s; + return Messages.getString(s, _context); + } + + /** + * translate a string with a parameter + */ + private String _(String s, String o) { + // the RRD font doesn't have zh chars, at least on my system + if ("zh".equals(Messages.getLanguage(_context))) + return s.replace("{0}", o); + return Messages.getString(s, o, _context); + } +} diff --git a/apps/susidns/src/css.css b/apps/susidns/src/css.css index fae4f94a0bfb11ae7588e01ac1faed6a8d85e630..14ab494b23ba9cd8265b9061b284c2e1a4b64b8f 100644 --- a/apps/susidns/src/css.css +++ b/apps/susidns/src/css.css @@ -150,3 +150,27 @@ input[type=submit]:hover { } +input[type=reset] { + border: 1px outset #999; + background: #ddf; + color: #001; + margin: 5px; + font: bold 8pt "Lucida Sans Unicode", "Bitstream Vera Sans", Verdana, Tahoma, Helvetica, sans-serif; + padding: 1px 2px; + text-decoration: none; + min-width: 110px; + border-radius: 4px; + -moz-border-radius: 4px; + -khtml-border-radius: 4px; + -moz-box-shadow: inset 0px 2px 8px 0px #fff; + color: #006; + opacity: 0.9; +} + +input[type=reset]:hover { + background: #22a; + color: #fff; + border: 1px solid #f60; + opacity: 1.0; + -moz-box-shadow: inset 0px 0px 0px 1px #fff; +} diff --git a/apps/susidns/src/java/src/i2p/susi/dns/AddressbookBean.java b/apps/susidns/src/java/src/i2p/susi/dns/AddressbookBean.java index 443293886fd1eabf3b474b9c9774b5e89d40ffac..63c4db85acb1f61c285ff7b7a2231ee927d552be 100644 --- a/apps/susidns/src/java/src/i2p/susi/dns/AddressbookBean.java +++ b/apps/susidns/src/java/src/i2p/susi/dns/AddressbookBean.java @@ -35,7 +35,9 @@ import java.util.Iterator; import java.util.LinkedList; import java.util.Properties; +import net.i2p.data.DataFormatException; import net.i2p.data.DataHelper; +import net.i2p.data.Destination; public class AddressbookBean { @@ -254,15 +256,40 @@ public class AddressbookBean boolean changed = false; int deleted = 0; String name = null; - if (action.equals(_("Add"))) { + if (action.equals(_("Add")) || action.equals(_("Replace"))) { if( addressbook != null && hostname != null && destination != null ) { - addressbook.put( hostname, destination ); - changed = true; - message = _("Destination added."); - // clear search when adding - search = null; + String oldDest = (String) addressbook.get(hostname); + if (destination.equals(oldDest)) { + message = _("Host name {0} is already in addressbook, unchanged.", hostname); + } else if (oldDest != null && !action.equals(_("Replace"))) { + message = _("Host name {0} is already in addressbook with a different destination. Click \"Replace\" to overwrite.", hostname); + } else { + boolean valid = true; + try { + Destination dest = new Destination(destination); + } catch (DataFormatException dfe) { + valid = false; + } + if (valid) { + addressbook.put( hostname, destination ); + changed = true; + if (oldDest == null) + message = _("Destination added for {0}.", hostname); + else + message = _("Destination changed for {0}.", hostname); + // clear form + hostname = null; + destination = null; + } else { + message = _("Invalid Base 64 destination."); + } + } + } else { + message = _("Please enter a host name and destination"); } - } else if (action.equals(_("Delete"))) { + // clear search when adding + search = null; + } else if (action.equals(_("Delete Selected"))) { Iterator it = deletionMarks.iterator(); while( it.hasNext() ) { name = (String)it.next(); @@ -340,7 +367,7 @@ public class AddressbookBean return destination; } public void setDestination(String destination) { - this.destination = DataHelper.stripHTML(destination); // XSS + this.destination = DataHelper.stripHTML(destination).trim(); // XSS } public String getHostname() { return hostname; @@ -352,7 +379,7 @@ public class AddressbookBean deletionMarks.addLast( name ); } public void setHostname(String hostname) { - this.hostname = DataHelper.stripHTML(hostname); // XSS + this.hostname = DataHelper.stripHTML(hostname).trim(); // XSS } private int getBeginInt() { return Math.max(0, Math.min(entries.length - 1, beginIndex)); diff --git a/apps/susidns/src/jsp/addressbook.jsp b/apps/susidns/src/jsp/addressbook.jsp index ff09b41e023b50048d328729f156c781beaae781..15c76dfc8496054c909c1ff2066b0a08de38583a 100644 --- a/apps/susidns/src/jsp/addressbook.jsp +++ b/apps/susidns/src/jsp/addressbook.jsp @@ -160,7 +160,9 @@ <c:if test="${book.master || book.router || book.published || book.private}"> <div id="buttons"> -<p class="buttons"><input type="submit" name="action" value="<%=intl._("Delete")%>" > +<p class="buttons"> +<input type="reset" value="<%=intl._("Cancel")%>" > +<input type="submit" name="action" value="<%=intl._("Delete Selected")%>" > </p> </div> </c:if> @@ -179,6 +181,7 @@ <b><%=intl._("Hostname")%>:</b> <input type="text" name="hostname" value="${book.hostname}" size="20"> <b><%=intl._("Destination")%>:</b> <textarea name="destination" rows="1" style="height: 3em;" cols="40" wrap="off" >${book.destination}</textarea><br/> </p><p> +<input type="submit" name="action" value="<%=intl._("Replace")%>" > <input type="submit" name="action" value="<%=intl._("Add")%>" > </p> </div> diff --git a/apps/susidns/src/jsp/config.jsp b/apps/susidns/src/jsp/config.jsp index f8b47ab003950fbd3a914cb41049d4615901572a..4ad8b77dbb73b9bd113ded9e4e726e7640e0775d 100644 --- a/apps/susidns/src/jsp/config.jsp +++ b/apps/susidns/src/jsp/config.jsp @@ -69,8 +69,8 @@ <textarea name="config" rows="10" cols="80">${cfg.config}</textarea> </div> <div id="buttons"> -<input type="submit" name="action" value="<%=intl._("Save")%>" > <input type="submit" name="action" value="<%=intl._("Reload")%>" > +<input type="submit" name="action" value="<%=intl._("Save")%>" > </div> </form> <div id="help"> diff --git a/apps/susidns/src/jsp/subscriptions.jsp b/apps/susidns/src/jsp/subscriptions.jsp index 29bad172459f9ed21172bcab51fe6436ad4c19eb..27af719847b3a1167336e9263c7a14f1a82edbba 100644 --- a/apps/susidns/src/jsp/subscriptions.jsp +++ b/apps/susidns/src/jsp/subscriptions.jsp @@ -69,8 +69,8 @@ <textarea name="content" rows="10" cols="80">${subs.content}</textarea> </div> <div id="buttons"> -<input type="submit" name="action" value="<%=intl._("Save")%>" > <input type="submit" name="action" value="<%=intl._("Reload")%>" > +<input type="submit" name="action" value="<%=intl._("Save")%>" > </div> </form> <div id="help"> diff --git a/core/c/jbigi/build.sh b/core/c/jbigi/build.sh index 13678a6d5c223a8b490bf49a9b0c0a947e1bf384..535e451f5286c03a1ea2a6c83fb30ae4ee629517 100755 --- a/core/c/jbigi/build.sh +++ b/core/c/jbigi/build.sh @@ -54,7 +54,7 @@ cp *jbigi???* ../../lib/ echo 'Library copied to lib/' cd ../.. -I2P=~/i2p +I2P=~i2p if [ ! -f $I2P/lib/i2p.jar ] then echo "I2P installation not found in $I2P - correct \$I2P definition in script to run speed test" diff --git a/core/java/src/net/i2p/data/Address.java b/core/java/src/net/i2p/data/Address.java index fb87f988ea3e54c394956d25122604210a797b92..777be8661221c205f4b6c9939bd7aac4b119cf17 100644 --- a/core/java/src/net/i2p/data/Address.java +++ b/core/java/src/net/i2p/data/Address.java @@ -9,8 +9,6 @@ public class Address extends DataStructureImpl { private Destination _destination; public Address() { - _hostname = null; - _destination = null; } public String getHostname() { diff --git a/core/java/src/net/i2p/data/ByteArray.java b/core/java/src/net/i2p/data/ByteArray.java index 1ececc305b11e03555de4a5b23a1991cfb0560b7..7369a27d191c01e63c2d9ca9b4f10807b4f7f344 100644 --- a/core/java/src/net/i2p/data/ByteArray.java +++ b/core/java/src/net/i2p/data/ByteArray.java @@ -22,11 +22,9 @@ public class ByteArray implements Serializable, Comparable { private int _offset; public ByteArray() { - this(null); } public ByteArray(byte[] data) { - _offset = 0; _data = data; _valid = (data != null ? data.length : 0); } @@ -92,4 +90,4 @@ public class ByteArray implements Serializable, Comparable { public final String toBase64() { return Base64.encode(_data, _offset, _valid); } -} \ No newline at end of file +} diff --git a/core/java/src/net/i2p/data/Certificate.java b/core/java/src/net/i2p/data/Certificate.java index 9518baab4374074bf75eb390776bd21e48d4780d..855d474ca7f0f189cd2fd9ab02a74aeebdab0a8a 100644 --- a/core/java/src/net/i2p/data/Certificate.java +++ b/core/java/src/net/i2p/data/Certificate.java @@ -42,8 +42,6 @@ public class Certificate extends DataStructureImpl { public final static int CERTIFICATE_TYPE_MULTIPLE = 4; public Certificate() { - _type = 0; - _payload = null; } public Certificate(int type, byte[] payload) { diff --git a/core/java/src/net/i2p/data/Destination.java b/core/java/src/net/i2p/data/Destination.java index 2e01271e6ac596e61b92e547b79dac8775e6ad5d..4a00d78c914ac5aa763a765198f930bdfe44f2ef 100644 --- a/core/java/src/net/i2p/data/Destination.java +++ b/core/java/src/net/i2p/data/Destination.java @@ -27,10 +27,6 @@ public class Destination extends DataStructureImpl { protected Hash __calculatedHash; public Destination() { - setCertificate(null); - setSigningPublicKey(null); - setPublicKey(null); - __calculatedHash = null; } /** @@ -38,7 +34,6 @@ public class Destination extends DataStructureImpl { * @param s a Base64 representation of the destination, as (eg) is used in hosts.txt */ public Destination(String s) throws DataFormatException { - this(); fromBase64(s); } diff --git a/core/java/src/net/i2p/data/Hash.java b/core/java/src/net/i2p/data/Hash.java index a57f1ef28c86f8388b1589bf01f5db92ce382c2f..83579d11663d2d8f16cb412a079cbab2e24ac115 100644 --- a/core/java/src/net/i2p/data/Hash.java +++ b/core/java/src/net/i2p/data/Hash.java @@ -12,13 +12,6 @@ package net.i2p.data; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Map; -import java.util.Set; - -import net.i2p.util.Log; /** * Defines the hash as defined by the I2P data structure spec. @@ -27,20 +20,15 @@ import net.i2p.util.Log; * @author jrandom */ public class Hash extends DataStructureImpl { - private final static Log _log = new Log(Hash.class); private byte[] _data; private volatile String _stringified; private volatile String _base64ed; - private /* FIXME final FIXME */ Map _xorCache; private int _cachedHashCode; public final static int HASH_LENGTH = 32; public final static Hash FAKE_HASH = new Hash(new byte[HASH_LENGTH]); - private static final int MAX_CACHED_XOR = 1024; - public Hash() { - setData(null); } public Hash(byte data[]) { @@ -58,77 +46,6 @@ public class Hash extends DataStructureImpl { _cachedHashCode = calcHashCode(); } - /** - * Prepare this hash's cache for xor values - very few hashes will need it, - * so we don't want to waste the memory, and lazy initialization would incur - * online overhead to verify the initialization. - * - */ - public void prepareCache() { - synchronized (this) { - if (_xorCache == null) - _xorCache = new HashMap(MAX_CACHED_XOR); - } - } - - /** - * Calculate the xor with the current object and the specified hash, - * caching values where possible. Currently this keeps up to MAX_CACHED_XOR - * (1024) entries, and uses an essentially random ejection policy. Later - * perhaps go for an LRU or FIFO? - * - * @throws IllegalStateException if you try to use the cache without first - * preparing this object's cache via .prepareCache() - */ - public byte[] cachedXor(Hash key) throws IllegalStateException { - if (_xorCache == null) - throw new IllegalStateException("To use the cache, you must first prepare it"); - byte[] distance = (byte[])_xorCache.get(key); - - if (distance == null) { - // not cached, lets cache it - int cached = 0; - synchronized (_xorCache) { - int toRemove = _xorCache.size() + 1 - MAX_CACHED_XOR; - if (toRemove > 0) { - Set keys = new HashSet(toRemove); - // this removes essentially random keys - we dont maintain any sort - // of LRU or age. perhaps we should? - int removed = 0; - for (Iterator iter = _xorCache.keySet().iterator(); iter.hasNext() && removed < toRemove; removed++) - keys.add(iter.next()); - for (Iterator iter = keys.iterator(); iter.hasNext(); ) - _xorCache.remove(iter.next()); - } - distance = DataHelper.xor(key.getData(), getData()); - _xorCache.put(key, (Object) distance); - cached = _xorCache.size(); - } - if (_log.shouldLog(Log.DEBUG)) { - // explicit buffer, since the compiler can't guess how long it'll be - StringBuilder buf = new StringBuilder(128); - buf.append("miss [").append(cached).append("] from "); - buf.append(DataHelper.toHexString(getData())).append(" to "); - buf.append(DataHelper.toHexString(key.getData())); - _log.debug(buf.toString(), new Exception()); - } - } else { - if (_log.shouldLog(Log.DEBUG)) { - // explicit buffer, since the compiler can't guess how long it'll be - StringBuilder buf = new StringBuilder(128); - buf.append("hit from "); - buf.append(DataHelper.toHexString(getData())).append(" to "); - buf.append(DataHelper.toHexString(key.getData())); - _log.debug(buf.toString()); - } - } - return distance; - } - - public void clearXorCache() { - _xorCache = null; - } - public void readBytes(InputStream in) throws DataFormatException, IOException { _data = new byte[HASH_LENGTH]; _stringified = null; @@ -189,98 +106,4 @@ public class Hash extends DataStructureImpl { } return _base64ed; } - -/******** - public static void main(String args[]) { - testFill(); - testOverflow(); - testFillCheck(); - } - - private static void testFill() { - Hash local = new Hash(new byte[HASH_LENGTH]); // all zeroes - local.prepareCache(); - for (int i = 0; i < MAX_CACHED_XOR; i++) { - byte t[] = new byte[HASH_LENGTH]; - for (int j = 0; j < HASH_LENGTH; j++) - t[j] = (byte)((i >> j) & 0xFF); - Hash cur = new Hash(t); - local.cachedXor(cur); - if (local._xorCache.size() != i+1) { - _log.error("xor cache size where i=" + i + " isn't correct! size = " - + local._xorCache.size()); - return; - } - } - _log.debug("Fill test passed"); - } - private static void testOverflow() { - Hash local = new Hash(new byte[HASH_LENGTH]); // all zeroes - local.prepareCache(); - for (int i = 0; i < MAX_CACHED_XOR*2; i++) { - byte t[] = new byte[HASH_LENGTH]; - for (int j = 0; j < HASH_LENGTH; j++) - t[j] = (byte)((i >> j) & 0xFF); - Hash cur = new Hash(t); - local.cachedXor(cur); - if (i < MAX_CACHED_XOR) { - if (local._xorCache.size() != i+1) { - _log.error("xor cache size where i=" + i + " isn't correct! size = " - + local._xorCache.size()); - return; - } - } else { - if (local._xorCache.size() > MAX_CACHED_XOR) { - _log.error("xor cache size where i=" + i + " isn't correct! size = " - + local._xorCache.size()); - return; - } - } - } - _log.debug("overflow test passed"); - } - private static void testFillCheck() { - Set hashes = new HashSet(); - Hash local = new Hash(new byte[HASH_LENGTH]); // all zeroes - local.prepareCache(); - // fill 'er up - for (int i = 0; i < MAX_CACHED_XOR; i++) { - byte t[] = new byte[HASH_LENGTH]; - for (int j = 0; j < HASH_LENGTH; j++) - t[j] = (byte)((i >> j) & 0xFF); - Hash cur = new Hash(t); - hashes.add(cur); - local.cachedXor(cur); - if (local._xorCache.size() != i+1) { - _log.error("xor cache size where i=" + i + " isn't correct! size = " - + local._xorCache.size()); - return; - } - } - // now lets recheck using those same hash objects - // and see if they're cached - for (Iterator iter = hashes.iterator(); iter.hasNext(); ) { - Hash cur = (Hash)iter.next(); - if (!local._xorCache.containsKey(cur)) { - _log.error("checking the cache, we dont have " - + DataHelper.toHexString(cur.getData())); - return; - } - } - // now lets recheck with new objects but the same values - // and see if they'return cached - for (int i = 0; i < MAX_CACHED_XOR; i++) { - byte t[] = new byte[HASH_LENGTH]; - for (int j = 0; j < HASH_LENGTH; j++) - t[j] = (byte)((i >> j) & 0xFF); - Hash cur = new Hash(t); - if (!local._xorCache.containsKey(cur)) { - _log.error("checking the cache, we do NOT have " - + DataHelper.toHexString(cur.getData())); - return; - } - } - _log.debug("Fill check test passed"); - } -*********/ } diff --git a/core/java/src/net/i2p/data/Lease.java b/core/java/src/net/i2p/data/Lease.java index 850763983da2c085a66197398507812ed87f4787..17abdc92b1898c26c9127357d4772c91359ff7a9 100644 --- a/core/java/src/net/i2p/data/Lease.java +++ b/core/java/src/net/i2p/data/Lease.java @@ -30,11 +30,6 @@ public class Lease extends DataStructureImpl { private int _numFailure; public Lease() { - setGateway(null); - setTunnelId(null); - setEndDate(null); - setNumSuccess(0); - setNumFailure(0); } /** Retrieve the router at which the destination can be contacted diff --git a/core/java/src/net/i2p/data/LeaseSet.java b/core/java/src/net/i2p/data/LeaseSet.java index 061091c61fa94d5132e5519c6da8a48450070f8d..81de8e32679f7a6beb137a8b25c44cbb0b0e1775 100644 --- a/core/java/src/net/i2p/data/LeaseSet.java +++ b/core/java/src/net/i2p/data/LeaseSet.java @@ -78,18 +78,8 @@ public class LeaseSet extends DataStructureImpl { public final static int MAX_LEASES = 6; public LeaseSet() { - setDestination(null); - setEncryptionKey(null); - setSigningKey(null); - setSignature(null); - setRoutingKey(null); _leases = new ArrayList(MAX_LEASES); - _routingKeyGenMod = null; - _receivedAsPublished = false; _firstExpiration = Long.MAX_VALUE; - _lastExpiration = 0; - _decrypted = false; - _checked = false; } public Destination getDestination() { diff --git a/core/java/src/net/i2p/data/Payload.java b/core/java/src/net/i2p/data/Payload.java index a16a6441865fd0224d32a558031a51e63c37d457..89cac8ff5dc193bf6c60ffb262c0fdd2bc738f67 100644 --- a/core/java/src/net/i2p/data/Payload.java +++ b/core/java/src/net/i2p/data/Payload.java @@ -27,8 +27,6 @@ public class Payload extends DataStructureImpl { private byte[] _unencryptedData; public Payload() { - setUnencryptedData(null); - setEncryptedData(null); } /** diff --git a/core/java/src/net/i2p/data/PrivateKey.java b/core/java/src/net/i2p/data/PrivateKey.java index c4c34b0e896de39c56da5d37768a88eef8930404..48f8ad8164aa89d9e831b05ba9d70bf26eb3cd04 100644 --- a/core/java/src/net/i2p/data/PrivateKey.java +++ b/core/java/src/net/i2p/data/PrivateKey.java @@ -28,8 +28,8 @@ public class PrivateKey extends DataStructureImpl { public final static int KEYSIZE_BYTES = 256; public PrivateKey() { - setData(null); } + public PrivateKey(byte data[]) { setData(data); } /** constructs from base64 @@ -37,7 +37,6 @@ public class PrivateKey extends DataStructureImpl { * on a prior instance of PrivateKey */ public PrivateKey(String base64Data) throws DataFormatException { - this(); fromBase64(base64Data); } diff --git a/core/java/src/net/i2p/data/PublicKey.java b/core/java/src/net/i2p/data/PublicKey.java index 3496f8d55e3234a24676ae8b3ed3c8915e465636..3d822949e231d70a47d02425ef87f4c2d8ec4b6f 100644 --- a/core/java/src/net/i2p/data/PublicKey.java +++ b/core/java/src/net/i2p/data/PublicKey.java @@ -26,8 +26,8 @@ public class PublicKey extends DataStructureImpl { public final static int KEYSIZE_BYTES = 256; public PublicKey() { - setData(null); } + public PublicKey(byte data[]) { if ( (data == null) || (data.length != KEYSIZE_BYTES) ) throw new IllegalArgumentException("Data must be specified, and the correct size"); @@ -39,7 +39,6 @@ public class PublicKey extends DataStructureImpl { * on a prior instance of PublicKey */ public PublicKey(String base64Data) throws DataFormatException { - this(); fromBase64(base64Data); } diff --git a/core/java/src/net/i2p/data/RouterAddress.java b/core/java/src/net/i2p/data/RouterAddress.java index cc582a358e8765437304b6206f5afd60c2a559ad..9d199e57401add70fb9919555d489ee3e78918fc 100644 --- a/core/java/src/net/i2p/data/RouterAddress.java +++ b/core/java/src/net/i2p/data/RouterAddress.java @@ -29,9 +29,6 @@ public class RouterAddress extends DataStructureImpl { public RouterAddress() { setCost(-1); - setExpiration(null); - setTransportStyle(null); - setOptions(null); } /** diff --git a/core/java/src/net/i2p/data/RouterIdentity.java b/core/java/src/net/i2p/data/RouterIdentity.java index 095b54f449d166a75d5674225383b1c87ba8d04a..310bd11aa6432f28f27c954512076b4771f21d87 100644 --- a/core/java/src/net/i2p/data/RouterIdentity.java +++ b/core/java/src/net/i2p/data/RouterIdentity.java @@ -31,10 +31,6 @@ public class RouterIdentity extends DataStructureImpl { private Hash __calculatedHash; public RouterIdentity() { - setCertificate(null); - setSigningPublicKey(null); - setPublicKey(null); - __calculatedHash = null; } public Certificate getCertificate() { diff --git a/core/java/src/net/i2p/data/RouterInfo.java b/core/java/src/net/i2p/data/RouterInfo.java index 9968a324d7b9156aad76956865e64995d3b63b1f..2d16af82ec84f72ba46855a479e47765f826c55c 100644 --- a/core/java/src/net/i2p/data/RouterInfo.java +++ b/core/java/src/net/i2p/data/RouterInfo.java @@ -60,18 +60,9 @@ public class RouterInfo extends DataStructureImpl { public static final String BW_CAPABILITY_CHARS = "KLMNO"; public RouterInfo() { - setIdentity(null); - setPublished(0); _addresses = new HashSet(2); _peers = new HashSet(0); _options = new OrderedProperties(); - setSignature(null); - _validated = false; - _isValid = false; - _currentRoutingKey = null; - _stringified = null; - _byteified = null; - _hashCodeInitialized = false; } public RouterInfo(RouterInfo old) { diff --git a/core/java/src/net/i2p/data/SessionKey.java b/core/java/src/net/i2p/data/SessionKey.java index deaf292b531eb9d43851a05b77aeb8a30b64f45f..a506c8387d8fde3bb1d650ace969209beac0f1e0 100644 --- a/core/java/src/net/i2p/data/SessionKey.java +++ b/core/java/src/net/i2p/data/SessionKey.java @@ -27,8 +27,8 @@ public class SessionKey extends DataStructureImpl { public static final SessionKey INVALID_KEY = new SessionKey(new byte[KEYSIZE_BYTES]); public SessionKey() { - this(null); } + public SessionKey(byte data[]) { setData(data); } diff --git a/core/java/src/net/i2p/data/Signature.java b/core/java/src/net/i2p/data/Signature.java index 2c35edebc2bc0ea9f335f936ff3232e668d76066..8ed31a5b78da2f1b535e7e4b2abb1769772174dd 100644 --- a/core/java/src/net/i2p/data/Signature.java +++ b/core/java/src/net/i2p/data/Signature.java @@ -30,7 +30,8 @@ public class Signature extends DataStructureImpl { FAKE_SIGNATURE[i] = 0x00; } - public Signature() { this(null); } + public Signature() {} + public Signature(byte data[]) { setData(data); } public byte[] getData() { diff --git a/core/java/src/net/i2p/data/SigningPrivateKey.java b/core/java/src/net/i2p/data/SigningPrivateKey.java index 3c1e71254684062a13b94bb3d165a6dc748d81fb..40fda013aaa9416aaf03baf0b4eb065ea0bc555f 100644 --- a/core/java/src/net/i2p/data/SigningPrivateKey.java +++ b/core/java/src/net/i2p/data/SigningPrivateKey.java @@ -28,7 +28,8 @@ public class SigningPrivateKey extends DataStructureImpl { public final static int KEYSIZE_BYTES = 20; - public SigningPrivateKey() { this((byte[])null); } + public SigningPrivateKey() {} + public SigningPrivateKey(byte data[]) { setData(data); } /** constructs from base64 @@ -36,7 +37,6 @@ public class SigningPrivateKey extends DataStructureImpl { * on a prior instance of SigningPrivateKey */ public SigningPrivateKey(String base64Data) throws DataFormatException { - this(); fromBase64(base64Data); } diff --git a/core/java/src/net/i2p/data/SigningPublicKey.java b/core/java/src/net/i2p/data/SigningPublicKey.java index 2d2cf2f9b93ea167783c0a7e2986646ff45537d6..4f2b68df8268b432e97a6623cd99da8a538d03db 100644 --- a/core/java/src/net/i2p/data/SigningPublicKey.java +++ b/core/java/src/net/i2p/data/SigningPublicKey.java @@ -26,7 +26,8 @@ public class SigningPublicKey extends DataStructureImpl { public final static int KEYSIZE_BYTES = 128; - public SigningPublicKey() { this((byte[])null); } + public SigningPublicKey() {} + public SigningPublicKey(byte data[]) { setData(data); } /** constructs from base64 @@ -34,7 +35,6 @@ public class SigningPublicKey extends DataStructureImpl { * on a prior instance of SigningPublicKey */ public SigningPublicKey(String base64Data) throws DataFormatException { - this(); fromBase64(base64Data); } diff --git a/core/java/src/net/i2p/data/i2cp/AbuseReason.java b/core/java/src/net/i2p/data/i2cp/AbuseReason.java index 58c23d5e83b9dbceefd3c1e71f44e74e923e51f1..f631fa591198c67bbb827b9d47b3af7122bd4018 100644 --- a/core/java/src/net/i2p/data/i2cp/AbuseReason.java +++ b/core/java/src/net/i2p/data/i2cp/AbuseReason.java @@ -27,7 +27,6 @@ public class AbuseReason extends DataStructureImpl { private String _reason; public AbuseReason() { - setReason(null); } public String getReason() { diff --git a/core/java/src/net/i2p/data/i2cp/CreateLeaseSetMessage.java b/core/java/src/net/i2p/data/i2cp/CreateLeaseSetMessage.java index cf6759a26b441c6bba0be3e7e46a462e9748cbf8..4425a8d005f9bc6295d34d5e3cc961b4fbcc7f70 100644 --- a/core/java/src/net/i2p/data/i2cp/CreateLeaseSetMessage.java +++ b/core/java/src/net/i2p/data/i2cp/CreateLeaseSetMessage.java @@ -33,10 +33,6 @@ public class CreateLeaseSetMessage extends I2CPMessageImpl { private PrivateKey _privateKey; public CreateLeaseSetMessage() { - setSessionId(null); - setLeaseSet(null); - setSigningPrivateKey(null); - setPrivateKey(null); } public SessionId getSessionId() { diff --git a/core/java/src/net/i2p/data/i2cp/DestroySessionMessage.java b/core/java/src/net/i2p/data/i2cp/DestroySessionMessage.java index 630e0e71860cc0f6dd879ac82204a23f0bcbabab..8b4db852f77cde845f902025f4aa02a825c7c70c 100644 --- a/core/java/src/net/i2p/data/i2cp/DestroySessionMessage.java +++ b/core/java/src/net/i2p/data/i2cp/DestroySessionMessage.java @@ -27,7 +27,6 @@ public class DestroySessionMessage extends I2CPMessageImpl { private SessionId _sessionId; public DestroySessionMessage() { - setSessionId(null); } public SessionId getSessionId() { diff --git a/core/java/src/net/i2p/data/i2cp/DisconnectMessage.java b/core/java/src/net/i2p/data/i2cp/DisconnectMessage.java index f9c32810d720bcd1fd8386436e13de3e95613f7a..1931fead2f28963658aa777459a7f772f3b5e1fe 100644 --- a/core/java/src/net/i2p/data/i2cp/DisconnectMessage.java +++ b/core/java/src/net/i2p/data/i2cp/DisconnectMessage.java @@ -27,7 +27,6 @@ public class DisconnectMessage extends I2CPMessageImpl { private String _reason; public DisconnectMessage() { - setReason(null); } public String getReason() { diff --git a/core/java/src/net/i2p/data/i2cp/MessagePayloadMessage.java b/core/java/src/net/i2p/data/i2cp/MessagePayloadMessage.java index 6c041f11cba41b81e286c69ef7a15cdbb09abcfb..f06fe86f326cf2b2c945f3d2a44c4846020f55a1 100644 --- a/core/java/src/net/i2p/data/i2cp/MessagePayloadMessage.java +++ b/core/java/src/net/i2p/data/i2cp/MessagePayloadMessage.java @@ -31,7 +31,6 @@ public class MessagePayloadMessage extends I2CPMessageImpl { public MessagePayloadMessage() { setSessionId(-1); setMessageId(-1); - setPayload(null); } public long getSessionId() { diff --git a/core/java/src/net/i2p/data/i2cp/ReconfigureSessionMessage.java b/core/java/src/net/i2p/data/i2cp/ReconfigureSessionMessage.java index 5f7314d648cd2f235d5fff309588ca9dc15df7f0..9400091bede49bd3c7fcef052182e009a0f3710a 100644 --- a/core/java/src/net/i2p/data/i2cp/ReconfigureSessionMessage.java +++ b/core/java/src/net/i2p/data/i2cp/ReconfigureSessionMessage.java @@ -28,8 +28,6 @@ public class ReconfigureSessionMessage extends I2CPMessageImpl { private SessionConfig _sessionConfig; public ReconfigureSessionMessage() { - _sessionId = null; - _sessionConfig = null; } public SessionId getSessionId() { diff --git a/core/java/src/net/i2p/data/i2cp/ReportAbuseMessage.java b/core/java/src/net/i2p/data/i2cp/ReportAbuseMessage.java index 54b90292e7dffbccbc5b4ff81a2a3c0b598b70fa..137d364c7763e455f54adcf4b60ac3324c76cff1 100644 --- a/core/java/src/net/i2p/data/i2cp/ReportAbuseMessage.java +++ b/core/java/src/net/i2p/data/i2cp/ReportAbuseMessage.java @@ -30,10 +30,6 @@ public class ReportAbuseMessage extends I2CPMessageImpl { private MessageId _messageId; public ReportAbuseMessage() { - setSessionId(null); - setSeverity(null); - setReason(null); - setMessageId(null); } public SessionId getSessionId() { diff --git a/core/java/src/net/i2p/data/i2cp/RequestLeaseSetMessage.java b/core/java/src/net/i2p/data/i2cp/RequestLeaseSetMessage.java index 35249c76cd3c2a1a4c4cd5179d0d1d490e0fe8fe..ef877afe5e2c188fbd2524745ee793071722b566 100644 --- a/core/java/src/net/i2p/data/i2cp/RequestLeaseSetMessage.java +++ b/core/java/src/net/i2p/data/i2cp/RequestLeaseSetMessage.java @@ -34,9 +34,7 @@ public class RequestLeaseSetMessage extends I2CPMessageImpl { private Date _end; public RequestLeaseSetMessage() { - setSessionId(null); _endpoints = new ArrayList(); - setEndDate(null); } public SessionId getSessionId() { diff --git a/core/java/src/net/i2p/data/i2cp/SendMessageExpiresMessage.java b/core/java/src/net/i2p/data/i2cp/SendMessageExpiresMessage.java index 770a6777b4552b20f9554008b43ad68e38a195b9..9bcabe2fb77a4fb875d4bf0d38465a9409314008 100644 --- a/core/java/src/net/i2p/data/i2cp/SendMessageExpiresMessage.java +++ b/core/java/src/net/i2p/data/i2cp/SendMessageExpiresMessage.java @@ -34,7 +34,6 @@ public class SendMessageExpiresMessage extends SendMessageMessage { public SendMessageExpiresMessage() { super(); - setExpiration(null); } public Date getExpiration() { diff --git a/core/java/src/net/i2p/data/i2cp/SendMessageMessage.java b/core/java/src/net/i2p/data/i2cp/SendMessageMessage.java index 237306f0dcab756b133b8abbde5e507c42a5c3f7..dc2cef33d03b33d31e7ad5c3796f866102287649 100644 --- a/core/java/src/net/i2p/data/i2cp/SendMessageMessage.java +++ b/core/java/src/net/i2p/data/i2cp/SendMessageMessage.java @@ -32,10 +32,6 @@ public class SendMessageMessage extends I2CPMessageImpl { private long _nonce; public SendMessageMessage() { - setSessionId(null); - setDestination(null); - setPayload(null); - setNonce(0); } public SessionId getSessionId() { diff --git a/core/java/src/net/i2p/data/i2cp/SessionConfig.java b/core/java/src/net/i2p/data/i2cp/SessionConfig.java index 520413620d35ce9a5b483868d4a43b9d0eacfc78..b96918a459d832f544545f929ceb22a95c9bab9f 100644 --- a/core/java/src/net/i2p/data/i2cp/SessionConfig.java +++ b/core/java/src/net/i2p/data/i2cp/SessionConfig.java @@ -51,9 +51,7 @@ public class SessionConfig extends DataStructureImpl { } public SessionConfig(Destination dest) { _destination = dest; - _signature = null; _creationDate = new Date(Clock.getInstance().now()); - _options = null; } /** diff --git a/core/java/src/net/i2p/data/i2cp/SessionStatusMessage.java b/core/java/src/net/i2p/data/i2cp/SessionStatusMessage.java index dab34ed43725da93a344958fab460932aadd6229..b26ec05f0ba48812363fb153bbed01ba832b4318 100644 --- a/core/java/src/net/i2p/data/i2cp/SessionStatusMessage.java +++ b/core/java/src/net/i2p/data/i2cp/SessionStatusMessage.java @@ -33,7 +33,6 @@ public class SessionStatusMessage extends I2CPMessageImpl { public final static int STATUS_INVALID = 3; public SessionStatusMessage() { - setSessionId(null); setStatus(STATUS_INVALID); } diff --git a/core/java/src/net/i2p/stat/Frequency.java b/core/java/src/net/i2p/stat/Frequency.java index 16e4c8f4adfc6d4c10f109a946a483b8e7e96786..6be7dc3c908223df3d9e3079c66864ad53f15def 100644 --- a/core/java/src/net/i2p/stat/Frequency.java +++ b/core/java/src/net/i2p/stat/Frequency.java @@ -15,9 +15,6 @@ public class Frequency { public Frequency(long period) { setPeriod(period); - setLastEvent(0); - setAverageInterval(0); - setMinAverageInterval(0); } /** how long is this frequency averaged over? */ diff --git a/core/java/src/net/i2p/stat/Rate.java b/core/java/src/net/i2p/stat/Rate.java index 764691d6d315ea4937294d0de7f36bc866f11832..25305bce742c51587d41a88f36139327a29d3898 100644 --- a/core/java/src/net/i2p/stat/Rate.java +++ b/core/java/src/net/i2p/stat/Rate.java @@ -120,18 +120,6 @@ public class Rate { */ public Rate(long period) throws IllegalArgumentException { if (period <= 0) throw new IllegalArgumentException("The period must be strictly positive"); - _currentTotalValue = 0.0d; - _currentEventCount = 0; - _currentTotalEventTime = 0; - _lastTotalValue = 0.0d; - _lastEventCount = 0; - _lastTotalEventTime = 0; - _extremeTotalValue = 0.0d; - _extremeEventCount = 0; - _extremeTotalEventTime = 0; - _lifetimeTotalValue = 0.0d; - _lifetimeEventCount = 0; - _lifetimeTotalEventTime = 0; _creationDate = now(); _lastCoalesceDate = _creationDate; diff --git a/core/java/src/net/i2p/util/ByteCache.java b/core/java/src/net/i2p/util/ByteCache.java index 38df7a03982007fb01449e92255bcc6feeffe78d..d05327744cdb58569dba138e47002002a8686959 100644 --- a/core/java/src/net/i2p/util/ByteCache.java +++ b/core/java/src/net/i2p/util/ByteCache.java @@ -15,7 +15,7 @@ import net.i2p.data.ByteArray; * * Heap size control - survey of usage (April 2010) : * - * </pre> + * <pre> Size Max MaxMem From 16 16 256 CryptixAESEngine diff --git a/core/java/src/net/i2p/util/LogManager.java b/core/java/src/net/i2p/util/LogManager.java index 20dcd1fd1cbe3e4e2e57edccdcb401c1f0490db3..8bd344d653de3f2052562f2972b62627d765c6e0 100644 --- a/core/java/src/net/i2p/util/LogManager.java +++ b/core/java/src/net/i2p/util/LogManager.java @@ -625,4 +625,12 @@ public class LogManager { shutdown(); } } + + /** + * Convenience method for LogRecordFormatter + * @since 0.7.14 + */ + I2PAppContext getContext() { + return _context; + } } diff --git a/core/java/src/net/i2p/util/LogRecordFormatter.java b/core/java/src/net/i2p/util/LogRecordFormatter.java index 72d6ef9ee7d694ce3388127a3a3fb8fc60ed8f92..84a1cb6b8cf7a5acbec2e786d4e687de67525047 100644 --- a/core/java/src/net/i2p/util/LogRecordFormatter.java +++ b/core/java/src/net/i2p/util/LogRecordFormatter.java @@ -14,6 +14,8 @@ import java.io.IOException; import java.io.PrintWriter; import java.util.Date; +import net.i2p.I2PAppContext; + /** * Render a log record according to the log manager's settings * @@ -44,7 +46,7 @@ class LogRecordFormatter { buf.append(getThread(rec)); break; case LogManager.PRIORITY: - buf.append(getPriority(rec)); + buf.append(getPriority(rec, manager.getContext())); break; case LogManager.MESSAGE: buf.append(getWhat(rec)); @@ -78,10 +80,23 @@ class LogRecordFormatter { return manager.getDateFormat().format(new Date(logRecord.getDate())); } + /** don't translate */ private static String getPriority(LogRecord rec) { return toString(Log.toLevelString(rec.getPriority()), MAX_PRIORITY_LENGTH); } + private static final String BUNDLE_NAME = "net.i2p.router.web.messages"; + + /** translate @since 0.7.14 */ + private static String getPriority(LogRecord rec, I2PAppContext ctx) { + int len; + if (Translate.getLanguage(ctx).equals("de")) + len = 8; // KRITISCH + else + len = MAX_PRIORITY_LENGTH; + return toString(Translate.getString(Log.toLevelString(rec.getPriority()), ctx, BUNDLE_NAME), len); + } + private static String getWhat(LogRecord rec) { return rec.getMessage(); } @@ -92,6 +107,7 @@ class LogRecordFormatter { return toString(src, MAX_WHERE_LENGTH); } + /** truncates or pads to the specified size */ private static String toString(String str, int size) { StringBuilder buf = new StringBuilder(); if (str == null) str = ""; @@ -101,4 +117,4 @@ class LogRecordFormatter { buf.append(' '); return buf.toString(); } -} \ No newline at end of file +} diff --git a/history.txt b/history.txt index b728a9f3a7049336eb01b9e984fa66f95052c72f..42ff77f53302fd455fd3e2c9816c1b6f6895fed5 100644 --- a/history.txt +++ b/history.txt @@ -1,3 +1,23 @@ +2010-05-21 zzz + * i2psnark: + - Spiff up dir listings + - Urlify some messages + - Only go into end game at the end + +2010-05-19 zzz + * Data: Remove lots of unnecessary initializers + * susidns: More validataion when adding entry + +2010-05-15 zzz + * Console: + - Tag text in graphs + - Move SummaryRenderer to its own file + * Eepsite: Set no-cache in redirecting page + * Hash: Move caching XOR methods only used by KBucket + into netdb + * i2psnark: CSS tweaks + * Log: Translate priority + 2010-05-13 zzz * netdb.jsp debug tweaks * Plugins: Try to prevent ZipErrors after upgrade diff --git a/installer/resources/eepsite.help/index.html b/installer/resources/eepsite.help/index.html index 295ff07b5cc659668db41bca49eee1a1408d1372..89fc457916d2f1b81c4b4d57bd649214e93ec9e4 100644 --- a/installer/resources/eepsite.help/index.html +++ b/installer/resources/eepsite.help/index.html @@ -7,8 +7,10 @@ # --> <head> -<!-- remove the following line to stop redirecting to the help page --> +<!-- remove the following three lines to stop redirecting to the help page --> <meta http-equiv="refresh" content="1;url=/help/" /> +<meta http-equiv="pragma" content="no-cache"> +<meta http-equiv="cache-control" content="no-cache"> <title>I2P Anonymous Webserver</title> </head> <body> diff --git a/installer/resources/themes/console/snark.css b/installer/resources/themes/console/snark.css index 25872cb55dba346ee0398904c005e1ce2cd5ebe5..70091b13f9fc32745f7d63dd3e56c675d5236e55 100644 --- a/installer/resources/themes/console/snark.css +++ b/installer/resources/themes/console/snark.css @@ -108,6 +108,15 @@ td { font-size: 8pt; } +.snarkFileName { + min-width: 25em; +} + +.thumb { + max-height: 64px; + max-width: 96px; +} + .snarkNewTorrent { font-size: 9pt; } @@ -185,13 +194,33 @@ input { font-size: 9pt; font-weight: bold; text-align: left; - padding: 2px; + padding: 2px 4px; + -moz-border-radius: 4px; + border-radius: 4px; + border: 1px; +} + +input.r { + text-align: right; } select { background: #ffe; color: #310; font: 9pt "Lucida Sans Unicode","Bitstream Vera Sans",Verdana,Tahoma,Helvetica,sans-serif; + font-weight: bold; + padding: 2px 2px 2px 3px; + -moz-border-radius: 4px; + border-radius: 4px; +} + +textarea { + background: #ffe; + color: #310; + font-weight: bold; + padding: 1px 4px 0px; + -moz-border-radius: 4px; + border-radius: 4px; } img { diff --git a/router/java/src/net/i2p/data/i2np/DataMessage.java b/router/java/src/net/i2p/data/i2np/DataMessage.java index e98630bc8c1a3167cd2d7fc74e8d98a4dac3f36a..dcfff1805bdd52918092841700405a4cfdb3f28d 100644 --- a/router/java/src/net/i2p/data/i2np/DataMessage.java +++ b/router/java/src/net/i2p/data/i2np/DataMessage.java @@ -24,7 +24,6 @@ public class DataMessage extends I2NPMessageImpl { public DataMessage(I2PAppContext context) { super(context); - _data = null; } public byte[] getData() { diff --git a/router/java/src/net/i2p/data/i2np/DatabaseSearchReplyMessage.java b/router/java/src/net/i2p/data/i2np/DatabaseSearchReplyMessage.java index 085edc5a01c82ba2186504192f145a1bc5ef0493..08f5511dfdeb6dc13da4b44fa903ca9b2028ba66 100644 --- a/router/java/src/net/i2p/data/i2np/DatabaseSearchReplyMessage.java +++ b/router/java/src/net/i2p/data/i2np/DatabaseSearchReplyMessage.java @@ -34,9 +34,7 @@ public class DatabaseSearchReplyMessage extends I2NPMessageImpl { // do this in netdb if we need it //_context.statManager().createRateStat("netDb.searchReplyMessageSend", "How many search reply messages we send", "NetworkDatabase", new long[] { 60*1000, 5*60*1000, 10*60*1000, 60*60*1000 }); //_context.statManager().createRateStat("netDb.searchReplyMessageReceive", "How many search reply messages we receive", "NetworkDatabase", new long[] { 60*1000, 5*60*1000, 10*60*1000, 60*60*1000 }); - setSearchKey(null); _peerHashes = new ArrayList(3); - setFromHash(null); } /** diff --git a/router/java/src/net/i2p/data/i2np/DatabaseStoreMessage.java b/router/java/src/net/i2p/data/i2np/DatabaseStoreMessage.java index 1e90ec716105cb887a79341bdeb163654be19f70..f85ecce23772e15fdd2c6a1cb21d6fe8d080b4bc 100644 --- a/router/java/src/net/i2p/data/i2np/DatabaseStoreMessage.java +++ b/router/java/src/net/i2p/data/i2np/DatabaseStoreMessage.java @@ -43,12 +43,6 @@ public class DatabaseStoreMessage extends I2NPMessageImpl { public DatabaseStoreMessage(I2PAppContext context) { super(context); setValueType(-1); - setKey(null); - setLeaseSet(null); - setRouterInfo(null); - setReplyToken(0); - setReplyTunnel(null); - setReplyGateway(null); } /** diff --git a/router/java/src/net/i2p/data/i2np/DeliveryInstructions.java b/router/java/src/net/i2p/data/i2np/DeliveryInstructions.java index 98935a3947ae3e0d666ce5d1037d4cf38236d118..6c9ddb154da78e54d4f493cc20b89e616ebae08b 100644 --- a/router/java/src/net/i2p/data/i2np/DeliveryInstructions.java +++ b/router/java/src/net/i2p/data/i2np/DeliveryInstructions.java @@ -51,14 +51,7 @@ public class DeliveryInstructions extends DataStructureImpl { private final static long FLAG_DELAY = 16; public DeliveryInstructions() { - setEncrypted(false); - setEncryptionKey(null); setDeliveryMode(-1); - setDestination(null); - setRouter(null); - setTunnelId(null); - setDelayRequested(false); - setDelaySeconds(0); } public boolean getEncrypted() { return _encrypted; } diff --git a/router/java/src/net/i2p/data/i2np/GarlicClove.java b/router/java/src/net/i2p/data/i2np/GarlicClove.java index b9bc3d4e766e0112ea2c30d7a165c7e247aed584..1380dfd6044e5a96036b063c6886d34fb5480e13 100644 --- a/router/java/src/net/i2p/data/i2np/GarlicClove.java +++ b/router/java/src/net/i2p/data/i2np/GarlicClove.java @@ -40,11 +40,7 @@ public class GarlicClove extends DataStructureImpl { _context = context; _log = context.logManager().getLog(GarlicClove.class); _handler = new I2NPMessageHandler(context); - setInstructions(null); - setData(null); setCloveId(-1); - setExpiration(null); - setCertificate(null); } public DeliveryInstructions getInstructions() { return _instructions; } diff --git a/router/java/src/net/i2p/data/i2np/GarlicMessage.java b/router/java/src/net/i2p/data/i2np/GarlicMessage.java index 72d7e5d06963c0c33cb4fd3326f4d1bf747bebee..cf92ce7589dc95a8320fb510e3d48d17b8c9d050 100644 --- a/router/java/src/net/i2p/data/i2np/GarlicMessage.java +++ b/router/java/src/net/i2p/data/i2np/GarlicMessage.java @@ -26,7 +26,6 @@ public class GarlicMessage extends I2NPMessageImpl { public GarlicMessage(I2PAppContext context) { super(context); - setData(null); } public byte[] getData() { diff --git a/router/java/src/net/i2p/data/i2np/I2NPMessageHandler.java b/router/java/src/net/i2p/data/i2np/I2NPMessageHandler.java index 814443cb0105a282456f19d3c20cd969a1a13fe2..00493c9b47e9a882b292f301aef37bd81101b0ad 100644 --- a/router/java/src/net/i2p/data/i2np/I2NPMessageHandler.java +++ b/router/java/src/net/i2p/data/i2np/I2NPMessageHandler.java @@ -33,7 +33,6 @@ public class I2NPMessageHandler { public I2NPMessageHandler(I2PAppContext context) { _context = context; _log = context.logManager().getLog(I2NPMessageHandler.class); - _messageBuffer = null; _lastSize = -1; } diff --git a/router/java/src/net/i2p/data/i2np/I2NPMessageImpl.java b/router/java/src/net/i2p/data/i2np/I2NPMessageImpl.java index 6dd63a6abdea5d4b67e679d161b2cf0129c111bf..108ee0eb05d816d114ae7ac1d01bf9eeb854a9ff 100644 --- a/router/java/src/net/i2p/data/i2np/I2NPMessageImpl.java +++ b/router/java/src/net/i2p/data/i2np/I2NPMessageImpl.java @@ -54,8 +54,6 @@ public abstract class I2NPMessageImpl extends DataStructureImpl implements I2NPM _log = context.logManager().getLog(I2NPMessageImpl.class); _expiration = _context.clock().now() + DEFAULT_EXPIRATION_MS; _uniqueId = _context.random().nextLong(MAX_ID_VALUE); - _written = false; - _read = false; //_context.statManager().createRateStat("i2np.writeTime", "How long it takes to write an I2NP message", "I2NP", new long[] { 10*60*1000, 60*60*1000 }); //_context.statManager().createRateStat("i2np.readTime", "How long it takes to read an I2NP message", "I2NP", new long[] { 10*60*1000, 60*60*1000 }); } diff --git a/router/java/src/net/i2p/router/JobImpl.java b/router/java/src/net/i2p/router/JobImpl.java index 38aa860259c4a94ecea3904965e26ab4668a925b..b122d3674afa78cf1d31732544066a1d7579d362 100644 --- a/router/java/src/net/i2p/router/JobImpl.java +++ b/router/java/src/net/i2p/router/JobImpl.java @@ -24,8 +24,6 @@ public abstract class JobImpl implements Job { _context = context; _timing = new JobTiming(context); _id = ++_idSrc; - _addedBy = null; - _madeReadyOn = 0; } public long getJobId() { return _id; } diff --git a/router/java/src/net/i2p/router/JobStats.java b/router/java/src/net/i2p/router/JobStats.java index 148fb7410f096a99d7b59f2ef2a245b42c95e25f..19362cff371a623abc7a16067756f965fda0c775 100644 --- a/router/java/src/net/i2p/router/JobStats.java +++ b/router/java/src/net/i2p/router/JobStats.java @@ -15,11 +15,8 @@ class JobStats { public JobStats(String name) { _job = name; - _numRuns = 0; - _totalTime = 0; _maxTime = -1; _minTime = -1; - _totalPendingTime = 0; _maxPendingTime = -1; _minPendingTime = -1; } diff --git a/router/java/src/net/i2p/router/JobTiming.java b/router/java/src/net/i2p/router/JobTiming.java index 366587eaa49a4620aeab563d07282d2761f52044..d979074a6968c70f79e2d368caed3c9e565ba492 100644 --- a/router/java/src/net/i2p/router/JobTiming.java +++ b/router/java/src/net/i2p/router/JobTiming.java @@ -23,8 +23,6 @@ public class JobTiming implements Clock.ClockUpdateListener { public JobTiming(RouterContext context) { _context = context; _start = context.clock().now(); - _actualStart = 0; - _actualEnd = 0; //context.clock().addUpdateListener(this); } diff --git a/router/java/src/net/i2p/router/OutNetMessage.java b/router/java/src/net/i2p/router/OutNetMessage.java index 10aa6ec152961724bfea368b6d7c8d3b7c37fd6e..72f262cc5613084f9a6ecbdd78d057757854f4a1 100644 --- a/router/java/src/net/i2p/router/OutNetMessage.java +++ b/router/java/src/net/i2p/router/OutNetMessage.java @@ -66,18 +66,8 @@ public class OutNetMessage { public OutNetMessage(RouterContext context) { _context = context; _log = context.logManager().getLog(OutNetMessage.class); - setTarget(null); - _message = null; - _messageSize = 0; setPriority(-1); setExpiration(-1); - setOnSendJob(null); - setOnFailedSendJob(null); - setOnReplyJob(null); - setOnFailedReplyJob(null); - setReplySelector(null); - _failedTransports = null; - _sendBegin = 0; //_createdBy = new Exception("Created by"); _created = context.clock().now(); timestamp("Created"); diff --git a/router/java/src/net/i2p/router/RouterVersion.java b/router/java/src/net/i2p/router/RouterVersion.java index c10128fe6223a59f4fa2320e38c3309487438a87..f2522cd4ed540000a936a603d4922f4a287ece1f 100644 --- a/router/java/src/net/i2p/router/RouterVersion.java +++ b/router/java/src/net/i2p/router/RouterVersion.java @@ -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 = 6; + public final static long BUILD = 9; /** for example "-test" */ public final static String EXTRA = ""; diff --git a/router/java/src/net/i2p/router/TunnelPoolSettings.java b/router/java/src/net/i2p/router/TunnelPoolSettings.java index ceb3814a976d43a34ce4bcdeae7d8d6098ca86a3..ae894cf14f694e1c960d24bfe3ccb075a874c0ef 100644 --- a/router/java/src/net/i2p/router/TunnelPoolSettings.java +++ b/router/java/src/net/i2p/router/TunnelPoolSettings.java @@ -60,12 +60,7 @@ public class TunnelPoolSettings { _duration = DEFAULT_DURATION; _length = DEFAULT_LENGTH; _lengthVariance = DEFAULT_LENGTH_VARIANCE; - _lengthOverride = 0; _allowZeroHop = DEFAULT_ALLOW_ZERO_HOP; - _isInbound = false; - _isExploratory = false; - _destination = null; - _destinationNickname = null; _IPRestriction = DEFAULT_IP_RESTRICTION; _unknownOptions = new Properties(); _randomKey = generateRandomKey(); diff --git a/router/java/src/net/i2p/router/TunnelSelectionCriteria.java b/router/java/src/net/i2p/router/TunnelSelectionCriteria.java deleted file mode 100644 index e06f1976d098c7634c3796affaa73137357604a5..0000000000000000000000000000000000000000 --- a/router/java/src/net/i2p/router/TunnelSelectionCriteria.java +++ /dev/null @@ -1,47 +0,0 @@ -package net.i2p.router; -/* - * free (adj.): unencumbered; not under the control of others - * Written by jrandom in 2003 and released into the public domain - * with no warranty of any kind, either expressed or implied. - * It probably won't make your computer catch on fire, or eat - * your children, but it might. Use at your own risk. - * - */ - -/** - * Set of criteria for finding a tunnel from the Tunnel Manager - * - */ -public class TunnelSelectionCriteria { - public final static int MAX_PRIORITY = 100; - public final static int MIN_PRIORITY = 0; - private int _latencyPriority; - private int _anonymityPriority; - private int _reliabilityPriority; - private int _maxNeeded; - private int _minNeeded; - - public TunnelSelectionCriteria() { - setLatencyPriority(0); - setAnonymityPriority(0); - setReliabilityPriority(0); - setMinimumTunnelsRequired(0); - setMaximumTunnelsRequired(0); - } - - /** priority of the latency for the tunnel */ - public int getLatencyPriority() { return _latencyPriority; } - public void setLatencyPriority(int latencyPriority) { _latencyPriority = latencyPriority; } - /** priority of the anonymity for the tunnel */ - public int getAnonymityPriority() { return _anonymityPriority; } - public void setAnonymityPriority(int anonPriority) { _anonymityPriority = anonPriority; } - /** priority of the reliability for the tunnel */ - public int getReliabilityPriority() { return _reliabilityPriority; } - public void setReliabilityPriority(int reliabilityPriority) { _reliabilityPriority = reliabilityPriority; } - /** max # of tunnels to return */ - public int getMaximumTunnelsRequired() { return _maxNeeded; } - public void setMaximumTunnelsRequired(int maxNeeded) { _maxNeeded = maxNeeded; } - /** minimum # of tunnels to return */ - public int getMinimumTunnelsRequired() { return _minNeeded; } - public void setMinimumTunnelsRequired(int minNeeded) { _minNeeded = minNeeded; } -} diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/KBucket.java b/router/java/src/net/i2p/router/networkdb/kademlia/KBucket.java index 5c3c7b0e208f6f0de6bdd555560b1b1754c8dee4..4804f5da536755d593705e363094da745b492949 100644 --- a/router/java/src/net/i2p/router/networkdb/kademlia/KBucket.java +++ b/router/java/src/net/i2p/router/networkdb/kademlia/KBucket.java @@ -76,5 +76,5 @@ interface KBucket { */ public Hash generateRandomKey(); - public Hash getLocal(); + public LocalHash getLocal(); } diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/KBucketImpl.java b/router/java/src/net/i2p/router/networkdb/kademlia/KBucketImpl.java index 2ef143fee97b1f934808618bd873be431589a693..568a283f9b17eabda7f203bf2a03ecdc81cb0b19 100644 --- a/router/java/src/net/i2p/router/networkdb/kademlia/KBucketImpl.java +++ b/router/java/src/net/i2p/router/networkdb/kademlia/KBucketImpl.java @@ -39,7 +39,7 @@ class KBucketImpl implements KBucket { */ private final Set<Hash> _entries; /** we center the kbucket set on the given hash, and derive distances from this */ - private Hash _local; + private LocalHash _local; /** include if any bits equal or higher to this bit (in big endian order) */ private int _begin; /** include if no bits higher than this bit (inclusive) are set */ @@ -49,7 +49,7 @@ class KBucketImpl implements KBucket { private static final int SHUFFLE_DELAY = 10*60*1000; private I2PAppContext _context; - public KBucketImpl(I2PAppContext context, Hash local) { + public KBucketImpl(I2PAppContext context, LocalHash local) { _context = context; _log = context.logManager().getLog(KBucketImpl.class); _entries = new ConcurrentHashSet(2); //all but the last 1 or 2 buckets will be empty @@ -57,6 +57,11 @@ class KBucketImpl implements KBucket { setLocal(local); } + /** for testing - use above constructor for production to get common caching */ + public KBucketImpl(I2PAppContext context, Hash local) { + this(context, new LocalHash(local)); + } + public int getRangeBegin() { return _begin; } public int getRangeEnd() { return _end; } public void setRange(int lowOrderBitLimit, int highOrderBitLimit) { @@ -67,8 +72,8 @@ class KBucketImpl implements KBucket { return _entries.size(); } - public Hash getLocal() { return _local; } - private void setLocal(Hash local) { + public LocalHash getLocal() { return _local; } + private void setLocal(LocalHash local) { _local = local; // we want to make sure we've got the cache in place before calling cachedXor _local.prepareCache(); @@ -378,7 +383,7 @@ class KBucketImpl implements KBucket { int low = 1; int high = 3; Log log = I2PAppContext.getGlobalContext().logManager().getLog(KBucketImpl.class); - Hash local = Hash.FAKE_HASH; + LocalHash local = new LocalHash(Hash.FAKE_HASH); local.prepareCache(); KBucketImpl bucket = new KBucketImpl(I2PAppContext.getGlobalContext(), local); bucket.setRange(low, high); @@ -415,7 +420,7 @@ class KBucketImpl implements KBucket { int high = 200; byte hash[] = new byte[Hash.HASH_LENGTH]; RandomSource.getInstance().nextBytes(hash); - Hash local = new Hash(hash); + LocalHash local = new LocalHash(hash); local.prepareCache(); KBucketImpl bucket = new KBucketImpl(I2PAppContext.getGlobalContext(), local); bucket.setRange(low, high); diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/KBucketSet.java b/router/java/src/net/i2p/router/networkdb/kademlia/KBucketSet.java index 0b8fce229a86aaf2b4cca249bc88058a8f110f25..f576d967c7952b7f79a913fce4ddc0128016be6a 100644 --- a/router/java/src/net/i2p/router/networkdb/kademlia/KBucketSet.java +++ b/router/java/src/net/i2p/router/networkdb/kademlia/KBucketSet.java @@ -27,7 +27,7 @@ import net.i2p.util.Log; class KBucketSet { private Log _log; private I2PAppContext _context; - private Hash _us; + private LocalHash _us; private KBucket _buckets[]; private volatile int _size; @@ -38,7 +38,7 @@ class KBucketSet { public final static int BUCKET_SIZE = 500; // # values at which we start periodic trimming (500 ~= 250Kb) public KBucketSet(I2PAppContext context, Hash us) { - _us = us; + _us = new LocalHash(us); _context = context; _log = context.logManager().getLog(KBucketSet.class); createBuckets(); diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/LocalHash.java b/router/java/src/net/i2p/router/networkdb/kademlia/LocalHash.java new file mode 100644 index 0000000000000000000000000000000000000000..890d4300fac27a3c50ee0851eca0b46e99164cd8 --- /dev/null +++ b/router/java/src/net/i2p/router/networkdb/kademlia/LocalHash.java @@ -0,0 +1,208 @@ +package net.i2p.router.networkdb.kademlia; + +/* + * free (adj.): unencumbered; not under the control of others + * Written by jrandom in 2003 and released into the public domain + * with no warranty of any kind, either expressed or implied. + * It probably won't make your computer catch on fire, or eat + * your children, but it might. Use at your own risk. + * + */ + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +import net.i2p.data.DataHelper; +import net.i2p.data.Hash; +import net.i2p.util.Log; + +/** + * Pull the caching used only by KBucketImpl out of Hash and put it here. + * + * @since 0.7.14 + * @author jrandom + * @author moved from Hash.java by zzz + */ +class LocalHash extends Hash { + private final static Log _log = new Log(LocalHash.class); + private /* FIXME final FIXME */ Map _xorCache; + + private static final int MAX_CACHED_XOR = 1024; + + public LocalHash(Hash h) { + super(h.getData()); + } + + public LocalHash(byte[] b) { + super(b); + } + + /** + * Prepare this hash's cache for xor values - very few hashes will need it, + * so we don't want to waste the memory, and lazy initialization would incur + * online overhead to verify the initialization. + * + */ + public void prepareCache() { + synchronized (this) { + if (_xorCache == null) + _xorCache = new HashMap(MAX_CACHED_XOR); + } + } + + /** + * Calculate the xor with the current object and the specified hash, + * caching values where possible. Currently this keeps up to MAX_CACHED_XOR + * (1024) entries, and uses an essentially random ejection policy. Later + * perhaps go for an LRU or FIFO? + * + * @throws IllegalStateException if you try to use the cache without first + * preparing this object's cache via .prepareCache() + */ + public byte[] cachedXor(Hash key) throws IllegalStateException { + if (_xorCache == null) + throw new IllegalStateException("To use the cache, you must first prepare it"); + byte[] distance = (byte[])_xorCache.get(key); + + if (distance == null) { + // not cached, lets cache it + int cached = 0; + synchronized (_xorCache) { + int toRemove = _xorCache.size() + 1 - MAX_CACHED_XOR; + if (toRemove > 0) { + Set keys = new HashSet(toRemove); + // this removes essentially random keys - we dont maintain any sort + // of LRU or age. perhaps we should? + int removed = 0; + for (Iterator iter = _xorCache.keySet().iterator(); iter.hasNext() && removed < toRemove; removed++) + keys.add(iter.next()); + for (Iterator iter = keys.iterator(); iter.hasNext(); ) + _xorCache.remove(iter.next()); + } + distance = DataHelper.xor(key.getData(), getData()); + _xorCache.put(key, (Object) distance); + cached = _xorCache.size(); + } + if (_log.shouldLog(Log.DEBUG)) { + // explicit buffer, since the compiler can't guess how long it'll be + StringBuilder buf = new StringBuilder(128); + buf.append("miss [").append(cached).append("] from "); + buf.append(DataHelper.toHexString(getData())).append(" to "); + buf.append(DataHelper.toHexString(key.getData())); + _log.debug(buf.toString(), new Exception()); + } + } else { + if (_log.shouldLog(Log.DEBUG)) { + // explicit buffer, since the compiler can't guess how long it'll be + StringBuilder buf = new StringBuilder(128); + buf.append("hit from "); + buf.append(DataHelper.toHexString(getData())).append(" to "); + buf.append(DataHelper.toHexString(key.getData())); + _log.debug(buf.toString()); + } + } + return distance; + } + + /** @deprecated unused */ + public void clearXorCache() { + _xorCache = null; + } + +/******** + public static void main(String args[]) { + testFill(); + testOverflow(); + testFillCheck(); + } + + private static void testFill() { + Hash local = new Hash(new byte[HASH_LENGTH]); // all zeroes + local.prepareCache(); + for (int i = 0; i < MAX_CACHED_XOR; i++) { + byte t[] = new byte[HASH_LENGTH]; + for (int j = 0; j < HASH_LENGTH; j++) + t[j] = (byte)((i >> j) & 0xFF); + Hash cur = new Hash(t); + local.cachedXor(cur); + if (local._xorCache.size() != i+1) { + _log.error("xor cache size where i=" + i + " isn't correct! size = " + + local._xorCache.size()); + return; + } + } + _log.debug("Fill test passed"); + } + private static void testOverflow() { + Hash local = new Hash(new byte[HASH_LENGTH]); // all zeroes + local.prepareCache(); + for (int i = 0; i < MAX_CACHED_XOR*2; i++) { + byte t[] = new byte[HASH_LENGTH]; + for (int j = 0; j < HASH_LENGTH; j++) + t[j] = (byte)((i >> j) & 0xFF); + Hash cur = new Hash(t); + local.cachedXor(cur); + if (i < MAX_CACHED_XOR) { + if (local._xorCache.size() != i+1) { + _log.error("xor cache size where i=" + i + " isn't correct! size = " + + local._xorCache.size()); + return; + } + } else { + if (local._xorCache.size() > MAX_CACHED_XOR) { + _log.error("xor cache size where i=" + i + " isn't correct! size = " + + local._xorCache.size()); + return; + } + } + } + _log.debug("overflow test passed"); + } + private static void testFillCheck() { + Set hashes = new HashSet(); + Hash local = new Hash(new byte[HASH_LENGTH]); // all zeroes + local.prepareCache(); + // fill 'er up + for (int i = 0; i < MAX_CACHED_XOR; i++) { + byte t[] = new byte[HASH_LENGTH]; + for (int j = 0; j < HASH_LENGTH; j++) + t[j] = (byte)((i >> j) & 0xFF); + Hash cur = new Hash(t); + hashes.add(cur); + local.cachedXor(cur); + if (local._xorCache.size() != i+1) { + _log.error("xor cache size where i=" + i + " isn't correct! size = " + + local._xorCache.size()); + return; + } + } + // now lets recheck using those same hash objects + // and see if they're cached + for (Iterator iter = hashes.iterator(); iter.hasNext(); ) { + Hash cur = (Hash)iter.next(); + if (!local._xorCache.containsKey(cur)) { + _log.error("checking the cache, we dont have " + + DataHelper.toHexString(cur.getData())); + return; + } + } + // now lets recheck with new objects but the same values + // and see if they'return cached + for (int i = 0; i < MAX_CACHED_XOR; i++) { + byte t[] = new byte[HASH_LENGTH]; + for (int j = 0; j < HASH_LENGTH; j++) + t[j] = (byte)((i >> j) & 0xFF); + Hash cur = new Hash(t); + if (!local._xorCache.containsKey(cur)) { + _log.error("checking the cache, we do NOT have " + + DataHelper.toHexString(cur.getData())); + return; + } + } + _log.debug("Fill check test passed"); + } +*********/ +} diff --git a/router/java/src/net/i2p/router/transport/ntcp/NTCPTransport.java b/router/java/src/net/i2p/router/transport/ntcp/NTCPTransport.java index fea56423b65ba3674d294a9a2908296652a767b7..9d1c3a432df6e0d62e734cad6ee10bd2222bb4cc 100644 --- a/router/java/src/net/i2p/router/transport/ntcp/NTCPTransport.java +++ b/router/java/src/net/i2p/router/transport/ntcp/NTCPTransport.java @@ -2,6 +2,8 @@ package net.i2p.router.transport.ntcp; import java.io.IOException; import java.net.InetSocketAddress; +import java.net.InetAddress; +import java.net.UnknownHostException; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; import java.text.DecimalFormat; @@ -54,6 +56,9 @@ public class NTCPTransport extends TransportImpl { */ private final List<NTCPConnection> _establishing; + /** this is rarely if ever used, default is to bind to wildcard address */ + public static final String PROP_BIND_INTERFACE = "i2np.ntcp.bindInterface"; + private final NTCPSendFinisher _finisher; private long _lastBadSkew; private static final long[] RATES = { 10*60*1000 }; @@ -486,15 +491,29 @@ public class NTCPTransport extends TransportImpl { /** call from synchronized method */ private RouterAddress bindAddress() { if (_myAddress != null) { + InetAddress bindToAddr = null; + String bindTo = _context.getProperty(PROP_BIND_INTERFACE); + if (bindTo != null) { + try { + bindToAddr = InetAddress.getByName(bindTo); + } catch (UnknownHostException uhe) { + _log.log(Log.CRIT, "Invalid SSU bind interface specified [" + bindTo + "]", uhe); + // this can be implemented later, just updates some stats + // see udp/UDPTransport.java + //setReachabilityStatus(CommSystemFacade.STATUS_HOSED); + return null; + } + } + try { ServerSocketChannel chan = ServerSocketChannel.open(); chan.configureBlocking(false); InetSocketAddress addr = null; - //if (bindAllInterfaces()) + if(bindToAddr==null) addr = new InetSocketAddress(_myAddress.getPort()); - //else - // addr = new InetSocketAddress(_myAddress.getAddress(), _myAddress.getPort()); + else + addr = new InetSocketAddress(bindToAddr, _myAddress.getPort()); chan.socket().bind(addr); if (_log.shouldLog(Log.INFO)) _log.info("Listening on " + addr);