diff --git a/build.xml b/build.xml
index 5c2fff5a7..cf3899795 100644
--- a/build.xml
+++ b/build.xml
@@ -31,6 +31,14 @@
+
+
+
+
+
+
+
+
@@ -367,8 +375,8 @@
-
+
diff --git a/core/java/src/net/i2p/crypto/HMACSHA256Generator.java b/core/java/src/net/i2p/crypto/HMACSHA256Generator.java
index ae1399e22..b9b0109c0 100644
--- a/core/java/src/net/i2p/crypto/HMACSHA256Generator.java
+++ b/core/java/src/net/i2p/crypto/HMACSHA256Generator.java
@@ -28,6 +28,7 @@ public class HMACSHA256Generator {
/** set of available byte[] buffers for verify */
private List _availableTmp;
private boolean _useMD5;
+ private int _macSize;
public static final boolean DEFAULT_USE_MD5 = true;
@@ -39,6 +40,10 @@ public class HMACSHA256Generator {
_useMD5 = true;
else
_useMD5 = false;
+ if ("true".equals(context.getProperty("i2p.HMACBrokenSize", "true")))
+ _macSize = 32;
+ else
+ _macSize = (_useMD5 ? 16 : 32);
}
public static HMACSHA256Generator getInstance() {
diff --git a/history.txt b/history.txt
index 6b6b4e2c3..2c8856cd0 100644
--- a/history.txt
+++ b/history.txt
@@ -1,4 +1,16 @@
-$Id: history.txt,v 1.297 2005/10/14 11:02:38 jrandom Exp $
+$Id: history.txt,v 1.298 2005/10/14 11:26:31 jrandom Exp $
+
+2005-10-17 jrandom
+ * Allow an env prop to configure whether we want to use the backwards
+ compatible (but not standards compliant) HMAC-MD5, or whether we want
+ to use the not-backwards compatible (but standards compliant) one. No
+ one should touch this setting, unless your name is toad or jrandom ;)
+ * Added some new dummy facades
+ * Be more aggressive on loading up the router.config before building the
+ router context
+ * Added new hooks for apps to deal with previously undefined I2NP message
+ types without having to modify any code.
+ * Demo code for using a castrated router for SSU comm (SSUDemo.java)
2005-10-14 jrandom
* More explicit filter for linux/PPC building (thanks anon!)
diff --git a/router/java/src/net/i2p/data/i2np/I2NPMessageImpl.java b/router/java/src/net/i2p/data/i2np/I2NPMessageImpl.java
index 38b86ac91..b5f97c231 100644
--- a/router/java/src/net/i2p/data/i2np/I2NPMessageImpl.java
+++ b/router/java/src/net/i2p/data/i2np/I2NPMessageImpl.java
@@ -12,6 +12,9 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.util.HashMap;
+import java.util.Map;
+
import net.i2p.I2PAppContext;
import net.i2p.data.DataFormatException;
import net.i2p.data.DataHelper;
@@ -36,6 +39,15 @@ public abstract class I2NPMessageImpl extends DataStructureImpl implements I2NPM
private static final boolean RAW_FULL_SIZE = false;
+ /** unsynchronized as its pretty much read only (except at startup) */
+ private static final Map _builders = new HashMap(8);
+ public static final void registerBuilder(Builder builder, int type) { _builders.put(new Integer(type), builder); }
+ /** interface for extending the types of messages handled */
+ public interface Builder {
+ /** instantiate a new I2NPMessage to be populated shortly */
+ public I2NPMessage build(I2PAppContext ctx);
+ }
+
public I2NPMessageImpl(I2PAppContext context) {
_context = context;
_log = context.logManager().getLog(I2NPMessageImpl.class);
@@ -334,7 +346,11 @@ public abstract class I2NPMessageImpl extends DataStructureImpl implements I2NPM
case TunnelCreateStatusMessage.MESSAGE_TYPE:
return new TunnelCreateStatusMessage(context);
default:
- return null;
+ Builder builder = (Builder)_builders.get(new Integer(type));
+ if (builder == null)
+ return null;
+ else
+ return builder.build(context);
}
}
}
diff --git a/router/java/src/net/i2p/router/JobQueue.java b/router/java/src/net/i2p/router/JobQueue.java
index c9f4a423d..6198cfdcf 100644
--- a/router/java/src/net/i2p/router/JobQueue.java
+++ b/router/java/src/net/i2p/router/JobQueue.java
@@ -440,8 +440,8 @@ public class JobQueue {
timeToWait = 10;
else if (timeToWait > 10*1000)
timeToWait = 10*1000;
- if (_log.shouldLog(Log.DEBUG))
- _log.debug("Waiting " + timeToWait + " before rechecking the timed queue");
+ //if (_log.shouldLog(Log.DEBUG))
+ // _log.debug("Waiting " + timeToWait + " before rechecking the timed queue");
try {
_jobLock.wait(timeToWait);
} catch (InterruptedException ie) {}
diff --git a/router/java/src/net/i2p/router/NetworkDatabaseFacade.java b/router/java/src/net/i2p/router/NetworkDatabaseFacade.java
index 7d591800e..3027b66b1 100644
--- a/router/java/src/net/i2p/router/NetworkDatabaseFacade.java
+++ b/router/java/src/net/i2p/router/NetworkDatabaseFacade.java
@@ -10,10 +10,7 @@ package net.i2p.router;
import java.io.IOException;
import java.io.Writer;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
+import java.util.*;
import net.i2p.data.Hash;
import net.i2p.data.LeaseSet;
@@ -68,7 +65,7 @@ class DummyNetworkDatabaseFacade extends NetworkDatabaseFacade {
private RouterContext _context;
public DummyNetworkDatabaseFacade(RouterContext ctx) {
- _routers = new HashMap();
+ _routers = Collections.synchronizedMap(new HashMap());
_context = ctx;
}
@@ -93,11 +90,13 @@ class DummyNetworkDatabaseFacade extends NetworkDatabaseFacade {
public void publish(RouterInfo localRouterInfo) {}
public LeaseSet store(Hash key, LeaseSet leaseSet) { return leaseSet; }
public RouterInfo store(Hash key, RouterInfo routerInfo) {
- _routers.put(key, routerInfo);
- return routerInfo;
+ RouterInfo rv = (RouterInfo)_routers.put(key, routerInfo);
+ return rv;
}
public void unpublish(LeaseSet localLeaseSet) {}
- public void fail(Hash dbEntry) {}
+ public void fail(Hash dbEntry) {
+ _routers.remove(dbEntry);
+ }
public Set findNearestRouters(Hash key, int maxNumRouters, Set peersToIgnore) { return new HashSet(_routers.values()); }
diff --git a/router/java/src/net/i2p/router/Router.java b/router/java/src/net/i2p/router/Router.java
index 1acea8ae1..1702f89b8 100644
--- a/router/java/src/net/i2p/router/Router.java
+++ b/router/java/src/net/i2p/router/Router.java
@@ -106,11 +106,30 @@ public class Router {
}
_config = new Properties();
- _context = new RouterContext(this, envProps);
- if (configFilename == null)
- _configFilename = _context.getProperty(PROP_CONFIG_FILE, "router.config");
- else
+
+ if (configFilename == null) {
+ if (envProps != null) {
+ _configFilename = envProps.getProperty(PROP_CONFIG_FILE);
+ }
+ if (_configFilename == null)
+ _configFilename = System.getProperty(PROP_CONFIG_FILE, "router.config");
+ } else {
_configFilename = configFilename;
+ }
+
+ readConfig();
+ if (envProps == null) {
+ envProps = _config;
+ } else {
+ for (Iterator iter = _config.keySet().iterator(); iter.hasNext(); ) {
+ String k = (String)iter.next();
+ String v = _config.getProperty(k);
+ envProps.setProperty(k, v);
+ }
+ }
+
+
+ _context = new RouterContext(this, envProps);
_routerInfo = null;
_higherVersionSeen = false;
_log = _context.logManager().getLog(Router.class);
@@ -248,9 +267,12 @@ public class Router {
}
private static Properties getConfig(RouterContext ctx, String filename) {
- Log log = ctx.logManager().getLog(Router.class);
- if (log.shouldLog(Log.DEBUG))
- log.debug("Config file: " + filename);
+ Log log = null;
+ if (ctx != null) {
+ log = ctx.logManager().getLog(Router.class);
+ if (log.shouldLog(Log.DEBUG))
+ log.debug("Config file: " + filename, new Exception("location"));
+ }
Properties props = new Properties();
FileInputStream fis = null;
try {
@@ -260,10 +282,12 @@ public class Router {
// dont be a wanker
props.remove(PROP_SHUTDOWN_IN_PROGRESS);
} else {
- log.warn("Configuration file " + filename + " does not exist");
+ if (log != null)
+ log.warn("Configuration file " + filename + " does not exist");
}
} catch (Exception ioe) {
- log.error("Error loading the router configuration from " + filename, ioe);
+ if (log != null)
+ log.error("Error loading the router configuration from " + filename, ioe);
} finally {
if (fis != null) try { fis.close(); } catch (IOException ioe) {}
}
diff --git a/router/java/src/net/i2p/router/RouterContext.java b/router/java/src/net/i2p/router/RouterContext.java
index a5437d959..400213517 100644
--- a/router/java/src/net/i2p/router/RouterContext.java
+++ b/router/java/src/net/i2p/router/RouterContext.java
@@ -90,7 +90,10 @@ public class RouterContext extends I2PAppContext {
}
private void initAll() {
_adminManager = new AdminManager(this);
- _clientManagerFacade = new ClientManagerFacadeImpl(this);
+ if ("false".equals(getProperty("i2p.dummyClientFacade", "false")))
+ _clientManagerFacade = new ClientManagerFacadeImpl(this);
+ else
+ _clientManagerFacade = new DummyClientManagerFacade(this);
_clientMessagePool = new ClientMessagePool(this);
_jobQueue = new JobQueue(this);
_inNetMessagePool = new InNetMessagePool(this);
@@ -98,17 +101,26 @@ public class RouterContext extends I2PAppContext {
_messageHistory = new MessageHistory(this);
_messageRegistry = new OutboundMessageRegistry(this);
_messageStateMonitor = new MessageStateMonitor(this);
- _netDb = new FloodfillNetworkDatabaseFacade(this); // new KademliaNetworkDatabaseFacade(this);
+ if ("false".equals(getProperty("i2p.dummyNetDb", "false")))
+ _netDb = new FloodfillNetworkDatabaseFacade(this); // new KademliaNetworkDatabaseFacade(this);
+ else
+ _netDb = new DummyNetworkDatabaseFacade(this);
_keyManager = new KeyManager(this);
if ("false".equals(getProperty("i2p.vmCommSystem", "false")))
_commSystem = new CommSystemFacadeImpl(this);
else
_commSystem = new VMCommSystem(this);
_profileOrganizer = new ProfileOrganizer(this);
- _peerManagerFacade = new PeerManagerFacadeImpl(this);
+ if ("false".equals(getProperty("i2p.dummyPeerManager", "false")))
+ _peerManagerFacade = new PeerManagerFacadeImpl(this);
+ else
+ _peerManagerFacade = new DummyPeerManagerFacade();
_profileManager = new ProfileManagerImpl(this);
_bandwidthLimiter = new FIFOBandwidthLimiter(this);
- _tunnelManager = new TunnelPoolManager(this);
+ if ("false".equals(getProperty("i2p.dummyTunnelManager", "false")))
+ _tunnelManager = new TunnelPoolManager(this);
+ else
+ _tunnelManager = new DummyTunnelManagerFacade();
_tunnelDispatcher = new TunnelDispatcher(this);
_statPublisher = new StatisticsManager(this);
_shitlist = new Shitlist(this);
diff --git a/router/java/src/net/i2p/router/RouterVersion.java b/router/java/src/net/i2p/router/RouterVersion.java
index 95d4fd6f4..89adea0ea 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.269 $ $Date: 2005/10/13 21:15:40 $";
+ public final static String ID = "$Revision: 1.270 $ $Date: 2005/10/14 08:48:05 $";
public final static String VERSION = "0.6.1.3";
- public final static long BUILD = 0;
+ public final static long BUILD = 1;
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/SSUDemo.java b/router/java/src/net/i2p/router/SSUDemo.java
new file mode 100644
index 000000000..00c848e8d
--- /dev/null
+++ b/router/java/src/net/i2p/router/SSUDemo.java
@@ -0,0 +1,271 @@
+package net.i2p.router;
+
+import java.util.*;
+import java.io.*;
+
+import net.i2p.I2PAppContext;
+import net.i2p.data.*;
+import net.i2p.data.i2np.*;
+
+/**
+ * Demo of a stripped down router - no tunnels, no netDb, no i2cp, no peer profiling,
+ * just the SSU comm layer, crypto, and associated infrastructure, extended to handle
+ * a new type of message ("FooMessage").
+ *
+ */
+public class SSUDemo {
+ RouterContext _us;
+
+ public static void main(String args[]) {
+ SSUDemo demo = new SSUDemo();
+ demo.run();
+ }
+
+ public SSUDemo() {}
+ public void run() {
+ String cfgFile = "router.config";
+ Properties envProps = getEnv();
+ Router r = new Router(cfgFile, envProps);
+ r.runRouter();
+ _us = r.getContext();
+ setupHandlers();
+ // wait for it to warm up a bit
+ try { Thread.sleep(30*1000); } catch (InterruptedException ie) {}
+ // now write out our ident and info
+ RouterInfo myInfo = _us.router().getRouterInfo();
+ storeMyInfo(myInfo);
+ // look for any other peers written to the same directory, and send each
+ // a single Foo message (0x0123), unless they've already contacted us first.
+ // this call never returns
+ loadPeers();
+ }
+
+ private Properties getEnv() {
+ Properties envProps = System.getProperties();
+ // disable the TCP transport, as its deprecated
+ envProps.setProperty("i2np.tcp.disable", "true");
+ // we want SNTP synchronization for replay prevention
+ envProps.setProperty("time.disabled", "false");
+ // allow 127.0.0.1/10.0.0.1/etc (useful for testing). If this is false,
+ // peers who say they're on an invalid IP are shitlisted
+ envProps.setProperty("i2np.udp.allowLocal", "true");
+ // explicit IP+port. at least one router on the net has to have their IP+port
+ // set, since there has to be someone to detect one's IP off. most don't need
+ // to set these though
+ envProps.setProperty("i2np.udp.host", "127.0.0.1");
+ envProps.setProperty("i2np.udp.internalPort", "12000");
+ envProps.setProperty("i2np.udp.port", "12000");
+ // disable I2CP, the netDb, peer testing/profile persistence, and tunnel
+ // creation/management
+ envProps.setProperty("i2p.dummyClientFacade", "true");
+ envProps.setProperty("i2p.dummyNetDb", "true");
+ envProps.setProperty("i2p.dummyPeerManager", "true");
+ envProps.setProperty("i2p.dummyTunnelManager", "true");
+ // set to false if you want to use HMAC-SHA256-128 instead of HMAC-MD5-128 as
+ // the SSU MAC
+ envProps.setProperty("i2p.HMACMD5", "true");
+ // if you're using the HMAC MD5, by default it will use a 32 byte MAC field,
+ // which is a bug, as it doesn't generate the same values as a 16 byte MAC field.
+ // set this to false if you don't want the bug
+ envProps.setProperty("i2p.HMACBrokenSize", "false");
+ // no need to include any stats in the routerInfo we send to people on SSU
+ // session establishment
+ envProps.setProperty("router.publishPeerRankings", "false");
+ // write the logs to ./logs/log-router-*.txt (logger configured with the file
+ // ./logger.config, or another config file specified as
+ // -Dlogger.configLocation=blah)
+ envProps.setProperty("loggerFilenameOverride", "logs/log-router-@.txt");
+ return envProps;
+ }
+
+ private void setupHandlers() {
+ // netDb store is sent on connection establishment, which includes contact info
+ // for the peer. the DBStoreJobBuilder builds a new asynchronous Job to process
+ // each one received (storing it in our in-memory, passive netDb)
+ _us.inNetMessagePool().registerHandlerJobBuilder(DatabaseStoreMessage.MESSAGE_TYPE, new DBStoreJobBuilder());
+ // handle any Foo messages by displaying them on stdout
+ _us.inNetMessagePool().registerHandlerJobBuilder(FooMessage.MESSAGE_TYPE, new FooJobBuilder());
+ }
+
+ /** random place for storing router info files - written as $dir/base64(SHA256(info.getIdentity)) */
+ private File getInfoDir() { return new File("/tmp/ssuDemoInfo/"); }
+
+ private void storeMyInfo(RouterInfo info) {
+ File infoDir = getInfoDir();
+ if (!infoDir.exists())
+ infoDir.mkdirs();
+ FileOutputStream fos = null;
+ File infoFile = new File(infoDir, info.getIdentity().calculateHash().toBase64());
+ try {
+ fos = new FileOutputStream(infoFile);
+ info.writeBytes(fos);
+ } catch (IOException ioe) {
+ ioe.printStackTrace();
+ } catch (DataFormatException dfe) {
+ dfe.printStackTrace();
+ } finally {
+ if (fos != null) try { fos.close(); } catch (IOException ioe) {}
+ }
+
+ System.out.println("Our info stored at: " + infoFile.getAbsolutePath());
+ }
+
+ private void loadPeers() {
+ File infoDir = getInfoDir();
+ if (!infoDir.exists())
+ infoDir.mkdirs();
+ while (true) {
+ File peerFiles[] = infoDir.listFiles();
+ if ( (peerFiles != null) && (peerFiles.length > 0) ) {
+ for (int i = 0; i < peerFiles.length; i++) {
+ if (peerFiles[i].isFile() && !peerFiles[i].isHidden()) {
+ if (!_us.routerHash().toBase64().equals(peerFiles[i].getName())) {
+ System.out.println("Reading info: " + peerFiles[i].getAbsolutePath());
+ try {
+ FileInputStream in = new FileInputStream(peerFiles[i]);
+ RouterInfo ri = new RouterInfo();
+ ri.readBytes(in);
+ peerRead(ri);
+ } catch (IOException ioe) {
+ System.err.println("Error reading " + peerFiles[i].getAbsolutePath());
+ ioe.printStackTrace();
+ } catch (DataFormatException dfe) {
+ System.err.println("Corrupt " + peerFiles[i].getAbsolutePath());
+ dfe.printStackTrace();
+ }
+ }
+ }
+ }
+ }
+ try { Thread.sleep(30*1000); } catch (InterruptedException ie) {}
+ }
+ }
+
+ private void peerRead(RouterInfo ri) {
+ RouterInfo old = _us.netDb().store(ri.getIdentity().calculateHash(), ri);
+ if (old == null)
+ newPeerRead(ri);
+ }
+
+ private void newPeerRead(RouterInfo ri) {
+ OutNetMessage out = new OutNetMessage(_us);
+ // _us.clock() is an ntp synchronized clock. give up on sending this message
+ // if it doesn't get ACKed within the next 10 seconds
+ out.setExpiration(_us.clock().now() + 10*1000);
+ out.setPriority(100);
+ out.setTarget(ri);
+ FooMessage data = new FooMessage(_us, new byte[] { 0x0, 0x1, 0x2, 0x3 });
+ System.out.println("SEND: " + Base64.encode(data.getData()));
+ out.setMessage(data);
+ // job fired if we can't contact them, or if it takes too long to get an ACK
+ out.setOnFailedSendJob(null);
+ // job fired once the transport gets a full ACK of the message
+ out.setOnSendJob(new AfterACK());
+ // queue up the message, establishing a new SSU session if necessary, using
+ // their direct SSU address if they have one, or their indirect SSU addresses
+ // if they don't. If we cannot contact them, we will 'shitlist' their address,
+ // during which time we will not even attempt to send messages to them. We also
+ // drop their netDb info when we shitlist them, in case their info is no longer
+ // correct. Since the netDb is disabled for all meaningful purposes, the SSUDemo
+ // will be responsible for fetching such information.
+ _us.outNetMessagePool().add(out);
+ }
+
+ /** fired if and only if the FooMessage is ACKed before we time out */
+ private class AfterACK extends JobImpl {
+ public AfterACK() { super(_us); }
+ public void runJob() { System.out.println("Foo message sent completely"); }
+ public String getName() { return "After Foo message send"; }
+ }
+
+ ////
+ // Foo and netDb store handling below
+
+ /**
+ * Deal with an Foo message received
+ */
+ private class FooJobBuilder implements HandlerJobBuilder {
+ public FooJobBuilder() {
+ I2NPMessageImpl.registerBuilder(new FooBuilder(), FooMessage.MESSAGE_TYPE);
+ }
+ public Job createJob(I2NPMessage receivedMessage, RouterIdentity from, Hash fromHash) {
+ return new FooHandleJob(_us, receivedMessage, from, fromHash);
+ }
+ }
+ private class FooHandleJob extends JobImpl {
+ private I2NPMessage _msg;
+ public FooHandleJob(RouterContext ctx, I2NPMessage receivedMessage, RouterIdentity from, Hash fromHash) {
+ super(ctx);
+ _msg = receivedMessage;
+ }
+ public void runJob() {
+ // we know its a FooMessage, since thats the type of message that the handler
+ // is registered as
+ FooMessage m = (FooMessage)_msg;
+ System.out.println("RECV: " + Base64.encode(m.getData()));
+ }
+ public String getName() { return "Handle Foo message"; }
+ }
+ private class FooBuilder implements I2NPMessageImpl.Builder {
+ public I2NPMessage build(I2PAppContext ctx) { return new FooMessage(ctx, null); }
+ }
+
+ /**
+ * Just carry some data...
+ */
+ class FooMessage extends I2NPMessageImpl {
+ private byte[] _data;
+ public static final int MESSAGE_TYPE = 17;
+ public FooMessage(I2PAppContext ctx, byte data[]) {
+ super(ctx);
+ _data = data;
+ }
+ /** pull the read data off */
+ public byte[] getData() { return _data; }
+ /** specify the payload to be sent */
+ public void setData(byte data[]) { _data = data; }
+
+ public int getType() { return MESSAGE_TYPE; }
+ protected int calculateWrittenLength() { return _data.length; }
+ public void readMessage(byte[] data, int offset, int dataSize, int type) throws I2NPMessageException, IOException {
+ _data = new byte[dataSize];
+ System.arraycopy(data, offset, _data, 0, dataSize);
+ }
+
+ protected int writeMessageBody(byte[] out, int curIndex) throws I2NPMessageException {
+ System.arraycopy(_data, 0, out, curIndex, _data.length);
+ return curIndex + _data.length;
+ }
+ }
+
+ ////
+ // netDb store handling below
+
+ /**
+ * Handle any netDb stores from the peer - they send us their netDb as part of
+ * their SSU establishment (and we send them ours).
+ */
+ private class DBStoreJobBuilder implements HandlerJobBuilder {
+ public Job createJob(I2NPMessage receivedMessage, RouterIdentity from, Hash fromHash) {
+ return new HandleJob(_us, receivedMessage, from, fromHash);
+ }
+ }
+ private class HandleJob extends JobImpl {
+ private I2NPMessage _msg;
+ public HandleJob(RouterContext ctx, I2NPMessage receivedMessage, RouterIdentity from, Hash fromHash) {
+ super(ctx);
+ _msg = receivedMessage;
+ }
+ public void runJob() {
+ // we know its a DatabaseStoreMessage, since thats the type of message that the handler
+ // is registered as
+ DatabaseStoreMessage m = (DatabaseStoreMessage)_msg;
+ try {
+ _us.netDb().store(m.getKey(), m.getRouterInfo());
+ } catch (IllegalArgumentException iae) {
+ iae.printStackTrace();
+ }
+ }
+ public String getName() { return "Handle netDb store"; }
+ }
+}
\ No newline at end of file
diff --git a/router/java/src/net/i2p/router/TunnelManagerFacade.java b/router/java/src/net/i2p/router/TunnelManagerFacade.java
index a6a6c5b18..67a2c4033 100644
--- a/router/java/src/net/i2p/router/TunnelManagerFacade.java
+++ b/router/java/src/net/i2p/router/TunnelManagerFacade.java
@@ -12,6 +12,9 @@ import net.i2p.data.Destination;
import net.i2p.data.Hash;
import net.i2p.data.TunnelId;
+import java.io.IOException;
+import java.io.Writer;
+
/**
* Build and maintain tunnels throughout the network.
*
@@ -66,3 +69,31 @@ public interface TunnelManagerFacade extends Service {
public void setInboundSettings(Hash client, TunnelPoolSettings settings);
public void setOutboundSettings(Hash client, TunnelPoolSettings settings);
}
+
+class DummyTunnelManagerFacade implements TunnelManagerFacade {
+
+ public TunnelInfo getTunnelInfo(TunnelId id) { return null; }
+ public TunnelInfo selectInboundTunnel() { return null; }
+ public TunnelInfo selectInboundTunnel(Hash destination) { return null; }
+ public TunnelInfo selectOutboundTunnel() { return null; }
+ public TunnelInfo selectOutboundTunnel(Hash destination) { return null; }
+ public boolean isInUse(Hash peer) { return false; }
+ public int getParticipatingCount() { return 0; }
+ public int getFreeTunnelCount() { return 0; }
+ public int getOutboundTunnelCount() { return 0; }
+ public long getLastParticipatingExpiration() { return -1; }
+ public void buildTunnels(Destination client, ClientTunnelSettings settings) {}
+ public TunnelPoolSettings getInboundSettings() { return null; }
+ public TunnelPoolSettings getOutboundSettings() { return null; }
+ public TunnelPoolSettings getInboundSettings(Hash client) { return null; }
+ public TunnelPoolSettings getOutboundSettings(Hash client) { return null; }
+ public void setInboundSettings(TunnelPoolSettings settings) {}
+ public void setOutboundSettings(TunnelPoolSettings settings) {}
+ public void setInboundSettings(Hash client, TunnelPoolSettings settings) {}
+ public void setOutboundSettings(Hash client, TunnelPoolSettings settings) {}
+
+ public void renderStatusHTML(Writer out) throws IOException {}
+ public void restart() {}
+ public void shutdown() {}
+ public void startup() {}
+}