diff --git a/apps/ministreaming/java/src/net/i2p/client/streaming/I2PSocketManager.java b/apps/ministreaming/java/src/net/i2p/client/streaming/I2PSocketManager.java
index 2cd067375..8111d8c74 100644
--- a/apps/ministreaming/java/src/net/i2p/client/streaming/I2PSocketManager.java
+++ b/apps/ministreaming/java/src/net/i2p/client/streaming/I2PSocketManager.java
@@ -13,6 +13,7 @@ import java.net.NoRouteToHostException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
+import java.util.Properties;
import java.util.Set;
import net.i2p.I2PAppContext;
@@ -99,4 +100,6 @@ public interface I2PSocketManager {
public String getName();
public void setName(String name);
+
+ public void init(I2PAppContext context, I2PSession session, Properties opts, String name);
}
diff --git a/apps/ministreaming/java/src/net/i2p/client/streaming/I2PSocketManagerFactory.java b/apps/ministreaming/java/src/net/i2p/client/streaming/I2PSocketManagerFactory.java
index 7cc709479..076ee99fa 100644
--- a/apps/ministreaming/java/src/net/i2p/client/streaming/I2PSocketManagerFactory.java
+++ b/apps/ministreaming/java/src/net/i2p/client/streaming/I2PSocketManagerFactory.java
@@ -6,6 +6,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
+import net.i2p.I2PAppContext;
import net.i2p.I2PException;
import net.i2p.client.I2PClient;
import net.i2p.client.I2PClientFactory;
@@ -23,6 +24,9 @@ import net.i2p.util.Log;
public class I2PSocketManagerFactory {
private final static Log _log = new Log(I2PSocketManagerFactory.class);
+ public static final String PROP_MANAGER = "i2p.streaming.manager";
+ public static final String DEFAULT_MANAGER = "net.i2p.client.streaming.I2PSocketManagerImpl";
+
/**
* Create a socket manager using a brand new destination connected to the
* I2CP router on the local machine on the default port (7654).
@@ -76,23 +80,60 @@ public class I2PSocketManagerFactory {
public static I2PSocketManager createManager(InputStream myPrivateKeyStream, String i2cpHost, int i2cpPort,
Properties opts) {
I2PClient client = I2PClientFactory.createClient();
- opts.setProperty(I2PClient.PROP_RELIABILITY, I2PClient.PROP_RELIABILITY_GUARANTEED);
+ if (true) {
+ // for the old streaming lib
+ opts.setProperty(I2PClient.PROP_RELIABILITY, I2PClient.PROP_RELIABILITY_GUARANTEED);
+ } else {
+ // for new streaming lib:
+ opts.setProperty(I2PClient.PROP_RELIABILITY, I2PClient.PROP_RELIABILITY_BEST_EFFORT);
+ }
+
opts.setProperty(I2PClient.PROP_TCP_HOST, i2cpHost);
opts.setProperty(I2PClient.PROP_TCP_PORT, "" + i2cpPort);
try {
I2PSession session = client.createSession(myPrivateKeyStream, opts);
session.connect();
- return createManager(session);
+ return createManager(session, opts, "manager");
} catch (I2PSessionException ise) {
_log.error("Error creating session for socket manager", ise);
return null;
}
}
- private static I2PSocketManager createManager(I2PSession session) {
- I2PSocketManagerImpl mgr = new I2PSocketManagerImpl();
- mgr.setSession(session);
- mgr.setDefaultOptions(new I2PSocketOptions());
- return mgr;
+ private static I2PSocketManager createManager(I2PSession session, Properties opts, String name) {
+ if (false) {
+ I2PSocketManagerImpl mgr = new I2PSocketManagerImpl();
+ mgr.setSession(session);
+ mgr.setDefaultOptions(new I2PSocketOptions());
+ return mgr;
+ } else {
+ String classname = opts.getProperty(PROP_MANAGER, DEFAULT_MANAGER);
+ if (classname != null) {
+ try {
+ Class cls = Class.forName(classname);
+ Object obj = cls.newInstance();
+ if (obj instanceof I2PSocketManager) {
+ I2PSocketManager mgr = (I2PSocketManager)obj;
+ I2PAppContext context = I2PAppContext.getGlobalContext();
+ mgr.init(context, session, opts, name);
+ return mgr;
+ } else {
+ throw new IllegalStateException("Invalid manager class [" + classname + "]");
+ }
+ } catch (ClassNotFoundException cnfe) {
+ _log.error("Error loading " + classname, cnfe);
+ throw new IllegalStateException("Invalid manager class [" + classname + "] - not found");
+ } catch (InstantiationException ie) {
+ _log.error("Error loading " + classname, ie);
+ throw new IllegalStateException("Invalid manager class [" + classname + "] - unable to instantiate");
+ } catch (IllegalAccessException iae) {
+ _log.error("Error loading " + classname, iae);
+ throw new IllegalStateException("Invalid manager class [" + classname + "] - illegal access");
+ }
+ } else {
+ throw new IllegalStateException("No manager class specified");
+ }
+ }
+
}
}
\ No newline at end of file
diff --git a/apps/ministreaming/java/src/net/i2p/client/streaming/I2PSocketManagerImpl.java b/apps/ministreaming/java/src/net/i2p/client/streaming/I2PSocketManagerImpl.java
index 1165b7b8a..3bfb656a8 100644
--- a/apps/ministreaming/java/src/net/i2p/client/streaming/I2PSocketManagerImpl.java
+++ b/apps/ministreaming/java/src/net/i2p/client/streaming/I2PSocketManagerImpl.java
@@ -13,6 +13,7 @@ import java.net.NoRouteToHostException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
+import java.util.Properties;
import java.util.Set;
import net.i2p.I2PAppContext;
@@ -65,13 +66,18 @@ public class I2PSocketManagerImpl implements I2PSocketManager, I2PSessionListene
this("SocketManager " + (++__managerId));
}
public I2PSocketManagerImpl(String name) {
+ init(I2PAppContext.getGlobalContext(), null, null, name);
+ }
+
+ public void init(I2PAppContext context, I2PSession session, Properties opts, String name) {
_name = name;
- _session = null;
+ _context = context;
+ _log = _context.logManager().getLog(I2PSocketManager.class);
_inSockets = new HashMap(16);
_outSockets = new HashMap(16);
_acceptTimeout = ACCEPT_TIMEOUT_DEFAULT;
- _context = I2PAppContext.getGlobalContext();
- _log = _context.logManager().getLog(I2PSocketManager.class);
+ setSession(session);
+ setDefaultOptions(new I2PSocketOptions());
_context.statManager().createRateStat("streaming.lifetime", "How long before the socket is closed?", "streaming", new long[] { 10*60*1000, 60*60*1000, 24*60*60*1000 });
_context.statManager().createRateStat("streaming.sent", "How many bytes are sent in the stream?", "streaming", new long[] { 10*60*1000, 60*60*1000, 24*60*60*1000 });
_context.statManager().createRateStat("streaming.received", "How many bytes are received in the stream?", "streaming", new long[] { 10*60*1000, 60*60*1000, 24*60*60*1000 });
diff --git a/apps/ministreaming/java/src/net/i2p/client/streaming/StreamSinkSend.java b/apps/ministreaming/java/src/net/i2p/client/streaming/StreamSinkSend.java
new file mode 100644
index 000000000..f56c4c1b2
--- /dev/null
+++ b/apps/ministreaming/java/src/net/i2p/client/streaming/StreamSinkSend.java
@@ -0,0 +1,132 @@
+package net.i2p.client.streaming;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InterruptedIOException;
+import java.io.OutputStream;
+
+import java.net.ConnectException;
+import java.net.NoRouteToHostException;
+
+import java.util.Random;
+
+import net.i2p.I2PAppContext;
+import net.i2p.I2PException;
+import net.i2p.data.Destination;
+import net.i2p.data.DataFormatException;
+import net.i2p.util.Log;
+
+/**
+ * Simple streaming lib test app that connects to a given destination and sends
+ * the contents of a file, then disconnects. See the {@link #main}
+ *
+ */
+public class StreamSinkSend {
+ private Log _log;
+ private String _sendFile;
+ private int _writeDelay;
+ private String _peerDestFile;
+
+ /**
+ * Build the client but don't fire it up.
+ * @param filename file to send
+ * @param writeDelayMs how long to wait between each .write (0 for no delay)
+ * @param serverDestFile file containing the StreamSinkServer's binary Destination
+ */
+ public StreamSinkSend(String filename, int writeDelayMs, String serverDestFile) {
+ _sendFile = filename;
+ _writeDelay = writeDelayMs;
+ _peerDestFile = serverDestFile;
+ _log = I2PAppContext.getGlobalContext().logManager().getLog(StreamSinkClient.class);
+ }
+
+ /**
+ * Actually connect and run the client - this call blocks until completion.
+ *
+ */
+ public void runClient() {
+ I2PSocketManager mgr = I2PSocketManagerFactory.createManager();
+ Destination peer = null;
+ FileInputStream fis = null;
+ try {
+ fis = new FileInputStream(_peerDestFile);
+ peer = new Destination();
+ peer.readBytes(fis);
+ } catch (IOException ioe) {
+ _log.error("Error finding the peer destination to contact in " + _peerDestFile, ioe);
+ return;
+ } catch (DataFormatException dfe) {
+ _log.error("Peer destination is not valid in " + _peerDestFile, dfe);
+ return;
+ } finally {
+ if (fis == null) try { fis.close(); } catch (IOException ioe) {}
+ }
+
+
+ System.out.println("Send " + _sendFile + " to " + peer.calculateHash().toBase64());
+
+ try {
+ I2PSocket sock = mgr.connect(peer);
+ byte buf[] = new byte[32*1024];
+ OutputStream out = sock.getOutputStream();
+ long beforeSending = System.currentTimeMillis();
+ fis = new FileInputStream(_sendFile);
+ long size = 0;
+ while (true) {
+ int read = fis.read(buf);
+ if (read < 0)
+ break;
+ out.write(buf, 0, read);
+ size += read;
+ if (_log.shouldLog(Log.DEBUG))
+ _log.debug("Wrote " + read);
+ if (_writeDelay > 0) {
+ try { Thread.sleep(_writeDelay); } catch (InterruptedException ie) {}
+ }
+ }
+ fis.close();
+ long afterSending = System.currentTimeMillis();
+ System.out.println("Sent " + (size / 1024) + "KB in " + (afterSending-beforeSending) + "ms");
+ sock.close();
+ } catch (InterruptedIOException iie) {
+ _log.error("Timeout connecting to the peer", iie);
+ return;
+ } catch (NoRouteToHostException nrthe) {
+ _log.error("Unable to connect to the peer", nrthe);
+ return;
+ } catch (ConnectException ce) {
+ _log.error("Connection already dropped", ce);
+ return;
+ } catch (I2PException ie) {
+ _log.error("Error connecting to the peer", ie);
+ return;
+ } catch (IOException ioe) {
+ _log.error("IO error sending", ioe);
+ return;
+ }
+ }
+
+ /**
+ * Fire up the client. Usage: StreamSinkClient sendFile writeDelayMs serverDestFile
+ *