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 */