diff --git a/apps/jrobin/jrobin-1.4.0.jar b/apps/jrobin/jrobin-1.4.0.jar new file mode 100644 index 000000000..daabacd19 Binary files /dev/null and b/apps/jrobin/jrobin-1.4.0.jar differ diff --git a/apps/routerconsole/java/build.xml b/apps/routerconsole/java/build.xml index 00793a8dc..108e49601 100644 --- a/apps/routerconsole/java/build.xml +++ b/apps/routerconsole/java/build.xml @@ -25,6 +25,7 @@ + @@ -34,6 +35,12 @@ + + + + + + @@ -60,6 +67,7 @@ + @@ -86,6 +94,7 @@ + diff --git a/apps/routerconsole/java/src/net/i2p/router/web/RouterConsoleRunner.java b/apps/routerconsole/java/src/net/i2p/router/web/RouterConsoleRunner.java index ede14994d..75041f735 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/RouterConsoleRunner.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/RouterConsoleRunner.java @@ -25,6 +25,7 @@ public class RouterConsoleRunner { static { System.setProperty("org.mortbay.http.Version.paranoid", "true"); + System.setProperty("java.awt.headless", "true"); } public RouterConsoleRunner(String args[]) { @@ -95,6 +96,10 @@ public class RouterConsoleRunner { I2PThread t = new I2PThread(fetcher, "NewsFetcher"); t.setDaemon(true); t.start(); + + I2PThread st = new I2PThread(new StatSummarizer(), "StatSummarizer"); + st.setDaemon(true); + st.start(); } private void initialize(WebApplicationContext context) { diff --git a/apps/routerconsole/java/src/net/i2p/router/web/StatSummarizer.java b/apps/routerconsole/java/src/net/i2p/router/web/StatSummarizer.java new file mode 100644 index 000000000..50d8ba4f5 --- /dev/null +++ b/apps/routerconsole/java/src/net/i2p/router/web/StatSummarizer.java @@ -0,0 +1,140 @@ +package net.i2p.router.web; + +import java.io.*; +import java.util.*; + +import net.i2p.stat.*; +import net.i2p.router.*; + +/** + * + */ +public class StatSummarizer implements Runnable { + private RouterContext _context; + /** list of SummaryListener instances */ + private List _listeners; + private static StatSummarizer _instance; + + public StatSummarizer() { + _context = (RouterContext)RouterContext.listContexts().get(0); // fuck it, only summarize one per jvm + _listeners = new ArrayList(16); + _instance = this; + } + + public static StatSummarizer instance() { return _instance; } + + public void run() { + String specs = ""; + while (_context.router().isAlive()) { + specs = adjustDatabases(specs); + try { Thread.sleep(60*1000); } catch (InterruptedException ie) {} + } + } + + private static final String DEFAULT_DATABASES = "bw.sendRate.60000" + + ",bw.recvRate.60000" + + ",tunnel.testSuccessTime.60000" + + ",udp.outboundActiveCount.60000" + + ",udp.receivePacketSize.60000" + + ",udp.receivePacketSkew.60000" + + ",udp.sendConfirmTime.60000" + + ",udp.sendPacketSize.60000" + + ",router.activePeers.60000" + + ",router.activeSendPeers.60000"; + + private String adjustDatabases(String oldSpecs) { + String spec = _context.getProperty("stat.summaries", DEFAULT_DATABASES); + if ( ( (spec == null) && (oldSpecs == null) ) || + ( (spec != null) && (oldSpecs != null) && (oldSpecs.equals(spec))) ) + return oldSpecs; + + List old = parseSpecs(oldSpecs); + List newSpecs = parseSpecs(spec); + + // remove old ones + for (int i = 0; i < old.size(); i++) { + Rate r = (Rate)old.get(i); + if (!newSpecs.contains(r)) + removeDb(r); + } + // add new ones + StringBuffer buf = new StringBuffer(); + for (int i = 0; i < newSpecs.size(); i++) { + Rate r = (Rate)newSpecs.get(i); + if (!old.contains(r)) + addDb(r); + buf.append(r.getRateStat().getName()).append(".").append(r.getPeriod()); + if (i + 1 < newSpecs.size()) + buf.append(','); + } + return buf.toString(); + } + + private void removeDb(Rate r) { + for (int i = 0; i < _listeners.size(); i++) { + SummaryListener lsnr = (SummaryListener)_listeners.get(i); + if (lsnr.getRate().equals(r)) { + _listeners.remove(i); + lsnr.stopListening(); + return; + } + } + } + private void addDb(Rate r) { + SummaryListener lsnr = new SummaryListener(r); + _listeners.add(lsnr); + lsnr.startListening(); + //System.out.println("Start listening for " + r.getRateStat().getName() + ": " + r.getPeriod()); + } + public boolean renderPng(Rate rate, OutputStream out) throws IOException { return renderPng(rate, out, -1, -1); } + public boolean renderPng(Rate rate, OutputStream out, int width, int height) throws IOException { + for (int i = 0; i < _listeners.size(); i++) { + SummaryListener lsnr = (SummaryListener)_listeners.get(i); + if (lsnr.getRate().equals(rate)) { + lsnr.renderPng(out, width, height); + return true; + } + } + return false; + } + public boolean getXML(Rate rate, OutputStream out) throws IOException { + for (int i = 0; i < _listeners.size(); i++) { + SummaryListener lsnr = (SummaryListener)_listeners.get(i); + if (lsnr.getRate().equals(rate)) { + lsnr.getData().exportXml(out); + out.write(("\n").getBytes()); + out.write(("\n").getBytes()); + return true; + } + } + return false; + } + + /** + * @param specs statName.period,statName.period,statName.period + * @return list of Rate objects + */ + private List parseSpecs(String specs) { + StringTokenizer tok = new StringTokenizer(specs, ","); + List rv = new ArrayList(); + while (tok.hasMoreTokens()) { + String spec = tok.nextToken(); + int split = spec.lastIndexOf('.'); + if ( (split <= 0) || (split + 1 >= spec.length()) ) + continue; + String name = spec.substring(0, split); + String per = spec.substring(split+1); + long period = -1; + try { + period = Long.parseLong(per); + RateStat rs = _context.statManager().getRate(name); + if (rs != null) { + Rate r = rs.getRate(period); + if (r != null) + rv.add(r); + } + } catch (NumberFormatException nfe) {} + } + return rv; + } +} diff --git a/apps/routerconsole/java/src/net/i2p/router/web/SummaryListener.java b/apps/routerconsole/java/src/net/i2p/router/web/SummaryListener.java new file mode 100644 index 000000000..3d3094b40 --- /dev/null +++ b/apps/routerconsole/java/src/net/i2p/router/web/SummaryListener.java @@ -0,0 +1,182 @@ +package net.i2p.router.web; + +import java.io.*; + +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.RrdDb; +import org.jrobin.core.RrdDef; +import org.jrobin.core.RrdBackendFactory; +import org.jrobin.core.RrdMemoryBackendFactory; +import org.jrobin.core.Sample; + +import java.awt.Color; +import org.jrobin.graph.RrdGraph; +import org.jrobin.graph.RrdGraphDef; +import org.jrobin.core.RrdException; + +class SummaryListener implements RateSummaryListener { + private I2PAppContext _context; + private Log _log; + private Rate _rate; + private String _name; + private String _eventName; + private RrdDb _db; + private Sample _sample; + private RrdMemoryBackendFactory _factory; + private SummaryRenderer _renderer; + + static final int PERIODS = 600; + + static { + try { + RrdBackendFactory.setDefaultFactory("MEMORY"); + } catch (RrdException re) { + re.printStackTrace(); + } + } + + public SummaryListener(Rate r) { + _context = I2PAppContext.getGlobalContext(); + _rate = r; + _log = _context.logManager().getLog(SummaryListener.class); + } + + public void add(double totalValue, long eventCount, double totalEventTime, long period) { + if (_db != null) { + // add one value to the db (the average value for the period) + try { + _sample.setTime(now()/1000); + double val = eventCount > 0 ? (totalValue / (double)eventCount) : 0d; + _sample.setValue(_name, val); + _sample.setValue(_eventName, eventCount); + //_sample.setValue(0, val); + //_sample.setValue(1, eventCount); + _sample.update(); + //String names[] = _sample.getDsNames(); + //System.out.println("Add " + val + " over " + eventCount + " for " + _name + // + " [" + names[0] + ", " + names[1] + "]"); + } catch (IOException ioe) { + _log.error("Error adding", ioe); + } catch (RrdException re) { + _log.error("Error adding", re); + } + } + } + + /** + * JRobin can only deal with 20 character data source names, so we need to create a unique, + * munged version from the user/developer-visible name. + * + */ + private static String createName(I2PAppContext ctx, String wanted) { + return ctx.sha().calculateHash(DataHelper.getUTF8(wanted)).toBase64().substring(0,20); + } + + public Rate getRate() { return _rate; } + public void startListening() { + RateStat rs = _rate.getRateStat(); + long period = _rate.getPeriod(); + String baseName = rs.getName() + "." + period; + _name = createName(_context, baseName); + _eventName = createName(_context, baseName + ".events"); + try { + RrdDef def = new RrdDef(_name, now()/1000, period/1000); + long heartbeat = period*3/1000; // max seconds between events + def.addDatasource(_name, "GAUGE", heartbeat, Double.NaN, Double.NaN); + def.addDatasource(_eventName, "GAUGE", heartbeat, 0, Double.NaN); + double xff = 0.5; + int steps = 1; + int rows = PERIODS; + def.addArchive("AVERAGE", xff, steps, rows); + _factory = (RrdMemoryBackendFactory)RrdBackendFactory.getDefaultFactory(); + _db = new RrdDb(def, _factory); + _sample = _db.createSample(); + _renderer = new SummaryRenderer(_context, this); + _rate.setSummaryListener(this); + } catch (RrdException re) { + _log.error("Error starting", re); + } catch (IOException ioe) { + _log.error("Error starting", ioe); + } + } + public void stopListening() { + if (_db == null) return; + try { + _db.close(); + } catch (IOException ioe) { + _log.error("Error closing", ioe); + } + _rate.setSummaryListener(null); + _factory.delete(_db.getPath()); + _db = null; + } + public void renderPng(OutputStream out, int width, int height) throws IOException { _renderer.render(out, width, height); } + public void renderPng(OutputStream out) throws IOException { _renderer.render(out); } + + String getName() { return _name; } + String getEventName() { return _eventName; } + RrdDb getData() { return _db; } + long now() { return _context.clock().now(); } + + public boolean equals(Object obj) { + return ((obj instanceof SummaryListener) && ((SummaryListener)obj)._rate.equals(_rate)); + } + 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; + } + + public void render(OutputStream out) throws IOException { render(out, -1, -1); } + public void render(OutputStream out, int width, int height) throws IOException { + long end = _listener.now(); + long start = end - _listener.getRate().getPeriod()*SummaryListener.PERIODS; + long begin = System.currentTimeMillis(); + try { + RrdGraphDef def = new RrdGraphDef(); + def.setTimePeriod(start/1000, end/1000); + String title = _listener.getRate().getRateStat().getName() + " averaged for " + + DataHelper.formatDuration(_listener.getRate().getPeriod()); + def.setTitle(title); + String path = _listener.getData().getPath(); + String dsNames[] = _listener.getData().getDsNames(); + def.datasource(_listener.getName(), path, dsNames[0], "AVERAGE", "MEMORY"); + // include the average event count on the plot + //def.datasource(_listener.getName(), path, dsNames[1], "AVERAGE", "MEMORY"); + def.area(dsNames[0], Color.BLUE, _listener.getRate().getRateStat().getDescription()); + //def.line(dsNames[1], Color.RED, "Events per period"); + //System.out.println("rendering: path=" + path + " dsNames[0]=" + dsNames[0] + " dsNames[1]=" + dsNames[1] + " lsnr.getName=" + _listener.getName()); + def.setAntiAliasing(false); + RrdGraph graph = new RrdGraph(def); + //System.out.println("Graph created");em. + 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; + } + } +} \ No newline at end of file diff --git a/apps/routerconsole/jsp/config.jsp b/apps/routerconsole/jsp/config.jsp index 3c0f5f876..97474d63c 100644 --- a/apps/routerconsole/jsp/config.jsp +++ b/apps/routerconsole/jsp/config.jsp @@ -44,6 +44,7 @@ Bandwidth share percentage:
Sharing a higher percentage will improve your anonymity and help the network +

Enable load testing: /> diff --git a/apps/routerconsole/jsp/viewstat.jsp b/apps/routerconsole/jsp/viewstat.jsp new file mode 100644 index 000000000..77e46ee62 --- /dev/null +++ b/apps/routerconsole/jsp/viewstat.jsp @@ -0,0 +1,37 @@ +<% +net.i2p.stat.Rate rate = null; +String stat = request.getParameter("stat"); +String period = request.getParameter("period"); +net.i2p.stat.RateStat rs = net.i2p.I2PAppContext.getGlobalContext().statManager().getRate(stat); +boolean rendered = false; +if (rs != null) { + long per = -1; + try { + per = Long.parseLong(period); + rate = rs.getRate(per); + if (rate != null) { + java.io.OutputStream cout = response.getOutputStream(); + String format = request.getParameter("format"); + if ("xml".equals(format)) { + response.setContentType("text/xml"); + rendered = net.i2p.router.web.StatSummarizer.instance().getXML(rate, cout); + } else { + response.setContentType("image/png"); + int width = -1; + int height = -1; + String str = request.getParameter("width"); + if (str != null) try { width = Integer.parseInt(str); } catch (NumberFormatException nfe) {} + str = request.getParameter("height"); + if (str != null) try { height = Integer.parseInt(str); } catch (NumberFormatException nfe) {} + rendered = net.i2p.router.web.StatSummarizer.instance().renderPng(rate, cout, width, height); + } + if (rendered) + cout.close(); + //System.out.println("Rendered period " + per + " for the stat " + stat + "? " + rendered); + } + } catch (NumberFormatException nfe) {} +} +if (!rendered) { + response.sendError(404, "That stat is not available"); +} +%> \ No newline at end of file diff --git a/core/java/src/gnu/crypto/hash/Sha256Standalone.java b/core/java/src/gnu/crypto/hash/Sha256Standalone.java index b10df43a5..a42742e43 100644 --- a/core/java/src/gnu/crypto/hash/Sha256Standalone.java +++ b/core/java/src/gnu/crypto/hash/Sha256Standalone.java @@ -1,7 +1,7 @@ package gnu.crypto.hash; // ---------------------------------------------------------------------------- -// $Id: Sha256.java,v 1.2 2005/10/06 04:24:14 rsdio Exp $ +// $Id: Sha256Standalone.java,v 1.1 2006/02/26 16:30:59 jrandom Exp $ // // Copyright (C) 2003 Free Software Foundation, Inc. // @@ -59,7 +59,7 @@ package gnu.crypto.hash; * renamed from Sha256 to avoid conflicts with JVMs using gnu-crypto as their JCE * provider. * - * @version $Revision: 1.2 $ + * @version $Revision: 1.1 $ */ public class Sha256Standalone extends BaseHash { // Constants and variables @@ -127,10 +127,12 @@ public class Sha256Standalone extends BaseHash { // Class methods // ------------------------------------------------------------------------- + /* public static final int[] G(int hh0, int hh1, int hh2, int hh3, int hh4, int hh5, int hh6, int hh7, byte[] in, int offset) { return sha(hh0, hh1, hh2, hh3, hh4, hh5, hh6, hh7, in, offset); } + */ // Instance methods // ------------------------------------------------------------------------- @@ -143,17 +145,19 @@ public class Sha256Standalone extends BaseHash { // Implementation of concrete methods in BaseHash -------------------------- + private int transformResult[] = new int[8]; protected void transform(byte[] in, int offset) { - int[] result = sha(h0, h1, h2, h3, h4, h5, h6, h7, in, offset); + //int[] result = sha(h0, h1, h2, h3, h4, h5, h6, h7, in, offset); + sha(h0, h1, h2, h3, h4, h5, h6, h7, in, offset, transformResult); - h0 = result[0]; - h1 = result[1]; - h2 = result[2]; - h3 = result[3]; - h4 = result[4]; - h5 = result[5]; - h6 = result[6]; - h7 = result[7]; + h0 = transformResult[0]; + h1 = transformResult[1]; + h2 = transformResult[2]; + h3 = transformResult[3]; + h4 = transformResult[4]; + h5 = transformResult[5]; + h6 = transformResult[6]; + h7 = transformResult[7]; } protected byte[] padBuffer() { @@ -218,8 +222,8 @@ public class Sha256Standalone extends BaseHash { // SHA specific methods ---------------------------------------------------- - private static final synchronized int[] - sha(int hh0, int hh1, int hh2, int hh3, int hh4, int hh5, int hh6, int hh7, byte[] in, int offset) { + private static final synchronized void + sha(int hh0, int hh1, int hh2, int hh3, int hh4, int hh5, int hh6, int hh7, byte[] in, int offset, int out[]) { int A = hh0; int B = hh1; int C = hh2; @@ -255,8 +259,18 @@ public class Sha256Standalone extends BaseHash { A = T + T2; } + /* return new int[] { hh0 + A, hh1 + B, hh2 + C, hh3 + D, hh4 + E, hh5 + F, hh6 + G, hh7 + H }; + */ + out[0] = hh0 + A; + out[1] = hh1 + B; + out[2] = hh2 + C; + out[3] = hh3 + D; + out[4] = hh4 + E; + out[5] = hh5 + F; + out[6] = hh6 + G; + out[7] = hh7 + H; } } diff --git a/core/java/src/net/i2p/stat/Rate.java b/core/java/src/net/i2p/stat/Rate.java index 74b48ed84..1d7fae51b 100644 --- a/core/java/src/net/i2p/stat/Rate.java +++ b/core/java/src/net/i2p/stat/Rate.java @@ -26,6 +26,8 @@ public class Rate { private volatile double _lifetimeTotalValue; private volatile long _lifetimeEventCount; private volatile long _lifetimeTotalEventTime; + private RateSummaryListener _summaryListener; + private RateStat _stat; private volatile long _lastCoalesceDate; private long _creationDate; @@ -108,6 +110,9 @@ public class Rate { public long getPeriod() { return _period; } + + public RateStat getRateStat() { return _stat; } + public void setRateStat(RateStat rs) { _stat = rs; } /** * @@ -203,8 +208,13 @@ public class Rate { _currentEventCount = 0; _currentTotalEventTime = 0; } + if (_summaryListener != null) + _summaryListener.add(_lastTotalValue, _lastEventCount, _lastTotalEventTime, _period); } + public void setSummaryListener(RateSummaryListener listener) { _summaryListener = listener; } + public RateSummaryListener getSummaryListener() { return _summaryListener; } + /** what was the average value across the events in the last period? */ public double getAverageValue() { if ((_lastTotalValue != 0) && (_lastEventCount > 0)) diff --git a/core/java/src/net/i2p/stat/RateStat.java b/core/java/src/net/i2p/stat/RateStat.java index 960721fa9..dc03072ca 100644 --- a/core/java/src/net/i2p/stat/RateStat.java +++ b/core/java/src/net/i2p/stat/RateStat.java @@ -27,8 +27,10 @@ public class RateStat { _description = description; _groupName = group; _rates = new Rate[periods.length]; - for (int i = 0; i < periods.length; i++) + for (int i = 0; i < periods.length; i++) { _rates[i] = new Rate(periods[i]); + _rates[i].setRateStat(this); + } } public void setStatLog(StatLog sl) { _statLog = sl; } @@ -159,6 +161,7 @@ public class RateStat { _rates[i].load(props, curPrefix, treatAsCurrent); } catch (IllegalArgumentException iae) { _rates[i] = new Rate(period); + _rates[i].setRateStat(this); if (_log.shouldLog(Log.WARN)) _log.warn("Rate for " + prefix + " is corrupt, reinitializing that period"); } diff --git a/history.txt b/history.txt index d4b790d29..b5901c9aa 100644 --- a/history.txt +++ b/history.txt @@ -1,4 +1,16 @@ -$Id: history.txt,v 1.430 2006/03/15 17:26:45 jrandom Exp $ +$Id: history.txt,v 1.431 2006/03/15 19:49:22 complication Exp $ + +2006-03-16 jrandom + * Integrate basic hooks for jrobin (http://jrobin.org) into the router + console. Selected stats can be harvested automatically and fed into + in-memory RRD databases, and those databases can be served up either as + PNG images or as RRDtool compatible XML dumps (see oldstats.jsp for + details). A base set of stats are harvested by default, but an + alternate list can be specified by setting the 'stat.summaries' list on + the advanced config. For instance: + stat.summaries=bw.recvRate.60000,bw.sendRate.60000 + * HTML tweaking for the general config page (thanks void!) + * Odd NPE fix (thanks Complication!) 2006-03-15 Complication * Trim out an old, inactive IP second-guessing method diff --git a/router/java/src/net/i2p/router/Router.java b/router/java/src/net/i2p/router/Router.java index a10644974..1eb8cde1a 100644 --- a/router/java/src/net/i2p/router/Router.java +++ b/router/java/src/net/i2p/router/Router.java @@ -1018,8 +1018,8 @@ class CoalesceStatsJob extends JobImpl { ctx.statManager().createRateStat("bw.sendBps", "How fast we send data (in KBps)", "Bandwidth", new long[] { 60*1000, 5*60*1000, 60*60*1000 }); ctx.statManager().createRateStat("bw.sendRate", "Low level bandwidth send rate, averaged every minute", "Bandwidth", new long[] { 60*1000l, 5*60*1000l, 10*60*1000l, 60*60*1000l }); ctx.statManager().createRateStat("bw.recvRate", "Low level bandwidth receive rate, averaged every minute", "Bandwidth", new long[] { 60*1000l, 5*60*1000l, 10*60*1000l, 60*60*1000l }); - ctx.statManager().createRateStat("router.activePeers", "How many peers we are actively talking with", "Throttle", new long[] { 5*60*1000, 60*60*1000 }); - ctx.statManager().createRateStat("router.activeSendPeers", "How many peers have sent messages to this minute", "Throttle", new long[] { 5*60*1000, 60*60*1000 }); + ctx.statManager().createRateStat("router.activePeers", "How many peers we are actively talking with", "Throttle", new long[] { 60*1000, 5*60*1000, 60*60*1000 }); + ctx.statManager().createRateStat("router.activeSendPeers", "How many peers have sent messages to this minute", "Throttle", new long[] { 60*1000, 5*60*1000, 60*60*1000 }); ctx.statManager().createRateStat("router.highCapacityPeers", "How many high capacity peers we know", "Throttle", new long[] { 5*60*1000, 60*60*1000 }); ctx.statManager().createRateStat("router.fastPeers", "How many fast peers we know", "Throttle", new long[] { 5*60*1000, 60*60*1000 }); } diff --git a/router/java/src/net/i2p/router/RouterVersion.java b/router/java/src/net/i2p/router/RouterVersion.java index cae3287d1..7830e7078 100644 --- a/router/java/src/net/i2p/router/RouterVersion.java +++ b/router/java/src/net/i2p/router/RouterVersion.java @@ -15,9 +15,9 @@ import net.i2p.CoreVersion; * */ public class RouterVersion { - public final static String ID = "$Revision: 1.371 $ $Date: 2006/03/15 17:26:45 $"; + public final static String ID = "$Revision: 1.372 $ $Date: 2006/03/15 19:49:23 $"; public final static String VERSION = "0.6.1.12"; - public final static long BUILD = 9; + public final static long BUILD = 10; public static void main(String args[]) { System.out.println("I2P Router version: " + VERSION + "-" + BUILD); System.out.println("Router ID: " + RouterVersion.ID); diff --git a/router/java/src/net/i2p/router/admin/StatsGenerator.java b/router/java/src/net/i2p/router/admin/StatsGenerator.java index 97932b3c2..1fac4a3a0 100644 --- a/router/java/src/net/i2p/router/admin/StatsGenerator.java +++ b/router/java/src/net/i2p/router/admin/StatsGenerator.java @@ -180,6 +180,15 @@ public class StatsGenerator { buf.append(num(curRate.getExtremeEventCount())); buf.append(")"); } + if (curRate.getSummaryListener() != null) { + buf.append(" render"); + buf.append(" (as XML"); + buf.append(" in a format RRDTool understands)"); + } buf.append(""); if (i + 1 == periods.length) { // last one, so lets display the strict average diff --git a/router/java/src/net/i2p/router/message/OutboundClientMessageOneShotJob.java b/router/java/src/net/i2p/router/message/OutboundClientMessageOneShotJob.java index 747655e2c..4e190491a 100644 --- a/router/java/src/net/i2p/router/message/OutboundClientMessageOneShotJob.java +++ b/router/java/src/net/i2p/router/message/OutboundClientMessageOneShotJob.java @@ -16,6 +16,7 @@ import net.i2p.data.Lease; import net.i2p.data.LeaseSet; import net.i2p.data.PublicKey; import net.i2p.data.SessionKey; +import net.i2p.data.Payload; import net.i2p.data.i2cp.MessageId; import net.i2p.data.i2np.DataMessage; @@ -334,7 +335,11 @@ public class OutboundClientMessageOneShotJob extends JobImpl { if (wantACK) _inTunnel = selectInboundTunnel(); - buildClove(); + boolean ok = buildClove(); + if (!ok) { + dieFatal(); + return; + } if (_log.shouldLog(Log.DEBUG)) _log.debug(getJobId() + ": Clove built to " + _toString); long msgExpiration = _overallExpiration; // getContext().clock().now() + OVERALL_TIMEOUT_MS_DEFAULT; @@ -475,7 +480,7 @@ public class OutboundClientMessageOneShotJob extends JobImpl { } /** build the payload clove that will be used for all of the messages, placing the clove in the status structure */ - private void buildClove() { + private boolean buildClove() { PayloadGarlicConfig clove = new PayloadGarlicConfig(); DeliveryInstructions instructions = new DeliveryInstructions(); @@ -492,7 +497,13 @@ public class OutboundClientMessageOneShotJob extends JobImpl { clove.setId(getContext().random().nextLong(I2NPMessage.MAX_ID_VALUE)); DataMessage msg = new DataMessage(getContext()); - msg.setData(_clientMessage.getPayload().getEncryptedData()); + Payload p = _clientMessage.getPayload(); + if (p == null) + return false; + byte d[] = p.getEncryptedData(); + if (d == null) + return false; + msg.setData(d); msg.setMessageExpiration(clove.getExpiration()); clove.setPayload(msg); @@ -504,6 +515,7 @@ public class OutboundClientMessageOneShotJob extends JobImpl { if (_log.shouldLog(Log.DEBUG)) _log.debug(getJobId() + ": Built payload clove with id " + clove.getId()); + return true; } /** diff --git a/router/java/src/net/i2p/router/transport/FIFOBandwidthLimiter.java b/router/java/src/net/i2p/router/transport/FIFOBandwidthLimiter.java index 7c5a00f01..1ce19db3e 100644 --- a/router/java/src/net/i2p/router/transport/FIFOBandwidthLimiter.java +++ b/router/java/src/net/i2p/router/transport/FIFOBandwidthLimiter.java @@ -64,6 +64,8 @@ public class FIFOBandwidthLimiter { _context.statManager().createRateStat("bwLimiter.pendingInboundRequests", "How many inbound requests are ahead of the current one (ignoring ones with 0)?", "BandwidthLimiter", new long[] { 60*1000l, 5*60*1000l, 10*60*1000l, 60*60*1000l }); _context.statManager().createRateStat("bwLimiter.outboundDelayedTime", "How long it takes to honor an outbound request (ignoring ones with that go instantly)?", "BandwidthLimiter", new long[] { 60*1000l, 5*60*1000l, 10*60*1000l, 60*60*1000l }); _context.statManager().createRateStat("bwLimiter.inboundDelayedTime", "How long it takes to honor an inbound request (ignoring ones with that go instantly)?", "BandwidthLimiter", new long[] { 60*1000l, 5*60*1000l, 10*60*1000l, 60*60*1000l }); + _context.statManager().createRateStat("bw.sendBps1s", "How fast we are transmitting for the 1s quantization (period is the number of bytes transmitted)?", "Bandwidth", new long[] { 60*1000l, 10*60*1000l }); + _context.statManager().createRateStat("bw.recvBps1s", "How fast we are receiving for the 1s quantization (period is the number of bytes transmitted)?", "Bandwidth", new long[] { 60*1000l, 10*60*1000l }); _pendingInboundRequests = new ArrayList(16); _pendingOutboundRequests = new ArrayList(16); _lastTotalSent = _totalAllocatedOutboundBytes; diff --git a/router/java/src/net/i2p/router/transport/udp/OutboundMessageFragments.java b/router/java/src/net/i2p/router/transport/udp/OutboundMessageFragments.java index f70f8e2b5..f61041f84 100644 --- a/router/java/src/net/i2p/router/transport/udp/OutboundMessageFragments.java +++ b/router/java/src/net/i2p/router/transport/udp/OutboundMessageFragments.java @@ -160,7 +160,7 @@ public class OutboundMessageFragments { } _activePeers.notifyAll(); } - msg.timestamp("made active along with: " + active); + //msg.timestamp("made active along with: " + active); _context.statManager().addRateData("udp.outboundActiveCount", active, 0); } else { if (_log.shouldLog(Log.WARN)) diff --git a/router/java/src/net/i2p/router/tunnel/pool/TestJob.java b/router/java/src/net/i2p/router/tunnel/pool/TestJob.java index 0728ee4b3..a593b20ed 100644 --- a/router/java/src/net/i2p/router/tunnel/pool/TestJob.java +++ b/router/java/src/net/i2p/router/tunnel/pool/TestJob.java @@ -42,19 +42,19 @@ class TestJob extends JobImpl { _log.error("Invalid tunnel test configuration: no pool for " + cfg, new Exception("origin")); getTiming().setStartAfter(getDelay() + ctx.clock().now()); ctx.statManager().createRateStat("tunnel.testFailedTime", "How long did the failure take (max of 60s for full timeout)?", "Tunnels", - new long[] { 10*60*1000l, 60*60*1000l, 3*60*60*1000l, 24*60*60*1000l }); + new long[] { 60*1000, 10*60*1000l, 60*60*1000l, 3*60*60*1000l, 24*60*60*1000l }); ctx.statManager().createRateStat("tunnel.testExploratoryFailedTime", "How long did the failure of an exploratory tunnel take (max of 60s for full timeout)?", "Tunnels", - new long[] { 10*60*1000l, 60*60*1000l, 3*60*60*1000l, 24*60*60*1000l }); + new long[] { 60*1000, 10*60*1000l, 60*60*1000l, 3*60*60*1000l, 24*60*60*1000l }); ctx.statManager().createRateStat("tunnel.testFailedCompletelyTime", "How long did the complete failure take (max of 60s for full timeout)?", "Tunnels", - new long[] { 10*60*1000l, 60*60*1000l, 3*60*60*1000l, 24*60*60*1000l }); + new long[] { 60*1000, 10*60*1000l, 60*60*1000l, 3*60*60*1000l, 24*60*60*1000l }); ctx.statManager().createRateStat("tunnel.testExploratoryFailedCompletelyTime", "How long did the complete failure of an exploratory tunnel take (max of 60s for full timeout)?", "Tunnels", - new long[] { 10*60*1000l, 60*60*1000l, 3*60*60*1000l, 24*60*60*1000l }); + new long[] { 60*1000, 10*60*1000l, 60*60*1000l, 3*60*60*1000l, 24*60*60*1000l }); ctx.statManager().createRateStat("tunnel.testSuccessLength", "How long were the tunnels that passed the test?", "Tunnels", - new long[] { 10*60*1000l, 60*60*1000l, 3*60*60*1000l, 24*60*60*1000l }); + new long[] { 60*1000, 10*60*1000l, 60*60*1000l, 3*60*60*1000l, 24*60*60*1000l }); ctx.statManager().createRateStat("tunnel.testSuccessTime", "How long did tunnel testing take?", "Tunnels", - new long[] { 10*60*1000l, 60*60*1000l, 3*60*60*1000l, 24*60*60*1000l }); + new long[] { 60*1000, 10*60*1000l, 60*60*1000l, 3*60*60*1000l, 24*60*60*1000l }); ctx.statManager().createRateStat("tunnel.testAborted", "Tunnel test could not occur, since there weren't any tunnels to test with", "Tunnels", - new long[] { 10*60*1000l, 60*60*1000l, 3*60*60*1000l, 24*60*60*1000l }); + new long[] { 60*1000, 10*60*1000l, 60*60*1000l, 3*60*60*1000l, 24*60*60*1000l }); } public String getName() { return "Test tunnel"; } public void runJob() { diff --git a/router/java/src/net/i2p/router/tunnel/pool/TunnelPoolManager.java b/router/java/src/net/i2p/router/tunnel/pool/TunnelPoolManager.java index e63d4f476..55bf0580c 100644 --- a/router/java/src/net/i2p/router/tunnel/pool/TunnelPoolManager.java +++ b/router/java/src/net/i2p/router/tunnel/pool/TunnelPoolManager.java @@ -58,10 +58,10 @@ public class TunnelPoolManager implements TunnelManagerFacade { ctx.statManager().createRateStat("tunnel.testSuccessTime", "How long do successful tunnel tests take?", "Tunnels", - new long[] { 10*60*1000l, 60*60*1000l, 3*60*60*1000l, 24*60*60*1000l }); + new long[] { 60*1000, 10*60*1000l, 60*60*1000l, 3*60*60*1000l, 24*60*60*1000l }); ctx.statManager().createRateStat("tunnel.participatingTunnels", "How many tunnels are we participating in?", "Tunnels", - new long[] { 10*60*1000l, 60*60*1000l, 3*60*60*1000l, 24*60*60*1000l }); + new long[] { 60*1000, 10*60*1000l, 60*60*1000l, 3*60*60*1000l, 24*60*60*1000l }); } /** pick an inbound tunnel not bound to a particular destination */