forked from I2P_Developers/i2p.i2p
More SAM client cleanup and fixes, beginning of v3 support
v3 unfinished, does not work yet
This commit is contained in:
@ -7,7 +7,7 @@ import java.util.Properties;
|
||||
*/
|
||||
public class SAMClientEventListenerImpl implements SAMReader.SAMClientEventListener {
|
||||
public void destReplyReceived(String publicKey, String privateKey) {}
|
||||
public void helloReplyReceived(boolean ok) {}
|
||||
public void helloReplyReceived(boolean ok, String version) {}
|
||||
public void namingReplyReceived(String name, String result, String value, String message) {}
|
||||
public void sessionStatusReceived(String result, String destination, String message) {}
|
||||
public void streamClosedReceived(String result, int id, String message) {}
|
||||
|
@ -15,6 +15,7 @@ public class SAMEventHandler extends SAMClientEventListenerImpl {
|
||||
//private I2PAppContext _context;
|
||||
private final Log _log;
|
||||
private Boolean _helloOk;
|
||||
private String _version;
|
||||
private final Object _helloLock = new Object();
|
||||
private Boolean _sessionCreateOk;
|
||||
private final Object _sessionCreateLock = new Object();
|
||||
@ -27,12 +28,13 @@ public class SAMEventHandler extends SAMClientEventListenerImpl {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void helloReplyReceived(boolean ok) {
|
||||
public void helloReplyReceived(boolean ok, String version) {
|
||||
synchronized (_helloLock) {
|
||||
if (ok)
|
||||
_helloOk = Boolean.TRUE;
|
||||
else
|
||||
_helloOk = Boolean.FALSE;
|
||||
_version = version;
|
||||
_helloLock.notifyAll();
|
||||
}
|
||||
}
|
||||
@ -61,7 +63,7 @@ public class SAMEventHandler extends SAMClientEventListenerImpl {
|
||||
|
||||
@Override
|
||||
public void unknownMessageReceived(String major, String minor, Properties params) {
|
||||
_log.error("wrt, [" + major + "] [" + minor + "] [" + params + "]");
|
||||
_log.error("Unhandled message: [" + major + "] [" + minor + "] [" + params + "]");
|
||||
}
|
||||
|
||||
|
||||
@ -70,18 +72,18 @@ public class SAMEventHandler extends SAMClientEventListenerImpl {
|
||||
//
|
||||
|
||||
/**
|
||||
* Wait for the connection to be established, returning true if everything
|
||||
* Wait for the connection to be established, returning the server version if everything
|
||||
* went ok
|
||||
* @return true if everything ok
|
||||
* @return SAM server version if everything ok, or null on failure
|
||||
*/
|
||||
public boolean waitForHelloReply() {
|
||||
public String waitForHelloReply() {
|
||||
while (true) {
|
||||
try {
|
||||
synchronized (_helloLock) {
|
||||
if (_helloOk == null)
|
||||
_helloLock.wait();
|
||||
else
|
||||
return _helloOk.booleanValue();
|
||||
return _helloOk.booleanValue() ? _version : null;
|
||||
}
|
||||
} catch (InterruptedException ie) {}
|
||||
}
|
||||
|
@ -71,7 +71,7 @@ public class SAMReader {
|
||||
public static final String NAMING_REPLY_INVALID_KEY = "INVALID_KEY";
|
||||
public static final String NAMING_REPLY_KEY_NOT_FOUND = "KEY_NOT_FOUND";
|
||||
|
||||
public void helloReplyReceived(boolean ok);
|
||||
public void helloReplyReceived(boolean ok, String version);
|
||||
public void sessionStatusReceived(String result, String destination, String message);
|
||||
public void streamStatusReceived(String result, int id, String message);
|
||||
public void streamConnectedReceived(String remoteDestination, int id);
|
||||
@ -159,10 +159,11 @@ public class SAMReader {
|
||||
if ("HELLO".equals(major)) {
|
||||
if ("REPLY".equals(minor)) {
|
||||
String result = params.getProperty("RESULT");
|
||||
if ("OK".equals(result))
|
||||
_listener.helloReplyReceived(true);
|
||||
String version= params.getProperty("VERSION");
|
||||
if ("OK".equals(result) && version != null)
|
||||
_listener.helloReplyReceived(true, version);
|
||||
else
|
||||
_listener.helloReplyReceived(false);
|
||||
_listener.helloReplyReceived(false, version);
|
||||
} else {
|
||||
_listener.unknownMessageReceived(major, minor, params);
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
package net.i2p.sam.client;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
@ -9,9 +10,11 @@ import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.data.Base32;
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.util.I2PAppThread;
|
||||
import net.i2p.util.Log;
|
||||
import net.i2p.util.VersionComparator;
|
||||
|
||||
/**
|
||||
* Send a file to a peer
|
||||
@ -26,7 +29,7 @@ public class SAMStreamSend {
|
||||
private final String _samPort;
|
||||
private final String _destFile;
|
||||
private final String _dataFile;
|
||||
private final String _conOptions;
|
||||
private String _conOptions;
|
||||
private Socket _samSocket;
|
||||
private OutputStream _samOut;
|
||||
private InputStream _samIn;
|
||||
@ -38,13 +41,14 @@ public class SAMStreamSend {
|
||||
|
||||
public static void main(String args[]) {
|
||||
if (args.length < 4) {
|
||||
System.err.println("Usage: SAMStreamSend samHost samPort peerDestFile dataFile");
|
||||
System.err.println("Usage: SAMStreamSend samHost samPort peerDestFile dataFile [version]");
|
||||
return;
|
||||
}
|
||||
I2PAppContext ctx = new I2PAppContext();
|
||||
I2PAppContext ctx = I2PAppContext.getGlobalContext();
|
||||
//String files[] = new String[args.length - 3];
|
||||
SAMStreamSend sender = new SAMStreamSend(ctx, args[0], args[1], args[2], args[3]);
|
||||
sender.startup();
|
||||
String version = (args.length >= 5) ? args[4] : "1.0";
|
||||
sender.startup(version);
|
||||
}
|
||||
|
||||
public SAMStreamSend(I2PAppContext ctx, String samHost, String samPort, String destFile, String dataFile) {
|
||||
@ -60,7 +64,7 @@ public class SAMStreamSend {
|
||||
_remotePeers = new HashMap<Integer,Sender>();
|
||||
}
|
||||
|
||||
public void startup() {
|
||||
public void startup(String version) {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Starting up");
|
||||
boolean ok = connect();
|
||||
@ -71,7 +75,7 @@ public class SAMStreamSend {
|
||||
_reader.startReading();
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Reader created");
|
||||
String ourDest = handshake();
|
||||
String ourDest = handshake(version);
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Handshake complete. we are " + ourDest);
|
||||
if (ourDest != null) {
|
||||
@ -82,6 +86,8 @@ public class SAMStreamSend {
|
||||
|
||||
private class SendEventHandler extends SAMEventHandler {
|
||||
public SendEventHandler(I2PAppContext ctx) { super(ctx); }
|
||||
|
||||
@Override
|
||||
public void streamClosedReceived(String result, int id, String message) {
|
||||
Sender sender = null;
|
||||
synchronized (_remotePeers) {
|
||||
@ -92,7 +98,7 @@ public class SAMStreamSend {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Connection " + sender.getConnectionId() + " closed to " + sender.getDestination());
|
||||
} else {
|
||||
_log.error("wtf, not connected to " + id + " but we were just closed?");
|
||||
_log.error("not connected to " + id + " but we were just closed?");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -109,24 +115,32 @@ public class SAMStreamSend {
|
||||
}
|
||||
}
|
||||
|
||||
private String handshake() {
|
||||
private String handshake(String version) {
|
||||
synchronized (_samOut) {
|
||||
try {
|
||||
_samOut.write("HELLO VERSION MIN=1.0 MAX=1.0\n".getBytes());
|
||||
_samOut.write(("HELLO VERSION MIN=1.0 MAX=" + version + '\n').getBytes());
|
||||
_samOut.flush();
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Hello sent");
|
||||
boolean ok = _eventHandler.waitForHelloReply();
|
||||
String hisVersion = _eventHandler.waitForHelloReply();
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Hello reply found: " + ok);
|
||||
if (!ok)
|
||||
throw new IOException("wtf, hello failed?");
|
||||
_log.debug("Hello reply found: " + hisVersion);
|
||||
if (hisVersion == null)
|
||||
throw new IOException("Hello failed");
|
||||
boolean isV3 = VersionComparator.comp(hisVersion, "3") >= 0;
|
||||
if (isV3) {
|
||||
byte[] id = new byte[5];
|
||||
_context.random().nextBytes(id);
|
||||
_conOptions = "ID=" + Base32.encode(id);
|
||||
}
|
||||
String req = "SESSION CREATE STYLE=STREAM DESTINATION=TRANSIENT " + _conOptions + "\n";
|
||||
_samOut.write(req.getBytes());
|
||||
_samOut.flush();
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Session create sent");
|
||||
ok = _eventHandler.waitForSessionCreateReply();
|
||||
boolean ok = _eventHandler.waitForSessionCreateReply();
|
||||
if (!ok)
|
||||
throw new IOException("Session create failed");
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Session create reply found: " + ok);
|
||||
|
||||
@ -222,6 +236,7 @@ public class SAMStreamSend {
|
||||
public void run() {
|
||||
_started = _context.clock().now();
|
||||
_context.statManager().addRateData("send." + _connectionId + ".started", 1, 0);
|
||||
final long toSend = (new File(_dataFile)).length();
|
||||
byte data[] = new byte[1024];
|
||||
long lastSend = _context.clock().now();
|
||||
while (!_closed) {
|
||||
@ -249,6 +264,7 @@ public class SAMStreamSend {
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
_log.error("Error sending", ioe);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -259,12 +275,14 @@ public class SAMStreamSend {
|
||||
_samOut.flush();
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
_log.error("Error closing", ioe);
|
||||
_log.info("Error closing", ioe);
|
||||
}
|
||||
|
||||
closed();
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Runner exiting");
|
||||
if (toSend != _totalSent)
|
||||
_log.error("Only sent " + _totalSent + " of " + toSend + " bytes");
|
||||
// stop the reader, since we're only doing this once for testing
|
||||
// you wouldn't do this in a real application
|
||||
_reader.stopReading();
|
||||
|
@ -8,9 +8,13 @@ import java.io.OutputStream;
|
||||
import java.net.Socket;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.data.Base32;
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.util.Log;
|
||||
import net.i2p.util.VersionComparator;
|
||||
|
||||
/**
|
||||
* Sit around on a SAM destination, receiving lots of data and
|
||||
@ -26,7 +30,7 @@ public class SAMStreamSink {
|
||||
private final String _samPort;
|
||||
private final String _destFile;
|
||||
private final String _sinkDir;
|
||||
private final String _conOptions;
|
||||
private String _conOptions;
|
||||
private Socket _samSocket;
|
||||
private OutputStream _samOut;
|
||||
private InputStream _samIn;
|
||||
@ -38,12 +42,13 @@ public class SAMStreamSink {
|
||||
|
||||
public static void main(String args[]) {
|
||||
if (args.length < 4) {
|
||||
System.err.println("Usage: SAMStreamSink samHost samPort myDestFile sinkDir");
|
||||
System.err.println("Usage: SAMStreamSink samHost samPort myDestFile sinkDir [version]");
|
||||
return;
|
||||
}
|
||||
I2PAppContext ctx = new I2PAppContext();
|
||||
I2PAppContext ctx = I2PAppContext.getGlobalContext();
|
||||
SAMStreamSink sink = new SAMStreamSink(ctx, args[0], args[1], args[2], args[3]);
|
||||
sink.startup();
|
||||
String version = (args.length >= 5) ? args[4] : "1.0";
|
||||
sink.startup(version);
|
||||
}
|
||||
|
||||
public SAMStreamSink(I2PAppContext ctx, String samHost, String samPort, String destFile, String sinkDir) {
|
||||
@ -59,7 +64,7 @@ public class SAMStreamSink {
|
||||
_remotePeers = new HashMap<Integer,Sink>();
|
||||
}
|
||||
|
||||
public void startup() {
|
||||
public void startup(String version) {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Starting up");
|
||||
boolean ok = connect();
|
||||
@ -70,14 +75,14 @@ public class SAMStreamSink {
|
||||
_reader.startReading();
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Reader created");
|
||||
String ourDest = handshake();
|
||||
String ourDest = handshake(version);
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Handshake complete. we are " + ourDest);
|
||||
if (ourDest != null) {
|
||||
//boolean written =
|
||||
writeDest(ourDest);
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("My destination written to " + _destFile);
|
||||
} else {
|
||||
_reader.stopReading();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -97,7 +102,7 @@ public class SAMStreamSink {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Connection " + sink.getConnectionId() + " closed to " + sink.getDestination());
|
||||
} else {
|
||||
_log.error("wtf, not connected to " + id + " but we were just closed?");
|
||||
_log.error("not connected to " + id + " but we were just closed?");
|
||||
}
|
||||
}
|
||||
|
||||
@ -110,7 +115,7 @@ public class SAMStreamSink {
|
||||
if (sink != null) {
|
||||
sink.received(data, offset, length);
|
||||
} else {
|
||||
_log.error("wtf, not connected to " + id + " but we received " + length + "?");
|
||||
_log.error("not connected to " + id + " but we received " + length + "?");
|
||||
}
|
||||
}
|
||||
|
||||
@ -142,24 +147,58 @@ public class SAMStreamSink {
|
||||
}
|
||||
}
|
||||
|
||||
private String handshake() {
|
||||
private String handshake(String version) {
|
||||
synchronized (_samOut) {
|
||||
try {
|
||||
_samOut.write("HELLO VERSION MIN=1.0 MAX=1.0\n".getBytes());
|
||||
_samOut.write(("HELLO VERSION MIN=1.0 MAX=" + version + '\n').getBytes());
|
||||
_samOut.flush();
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Hello sent");
|
||||
boolean ok = _eventHandler.waitForHelloReply();
|
||||
String hisVersion = _eventHandler.waitForHelloReply();
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Hello reply found: " + ok);
|
||||
if (!ok)
|
||||
throw new IOException("wtf, hello failed?");
|
||||
String req = "SESSION CREATE STYLE=STREAM DESTINATION=" + _destFile + " " + _conOptions + "\n";
|
||||
_log.debug("Hello reply found: " + hisVersion);
|
||||
if (hisVersion == null)
|
||||
throw new IOException("Hello failed");
|
||||
boolean isV3 = VersionComparator.comp(hisVersion, "3") >= 0;
|
||||
String dest;
|
||||
if (isV3) {
|
||||
// we use the filename as the name in sam.keys
|
||||
// and read it in ourselves
|
||||
File keys = new File("sam.keys");
|
||||
if (keys.exists()) {
|
||||
Properties opts = new Properties();
|
||||
DataHelper.loadProps(opts, keys);
|
||||
String s = opts.getProperty(_destFile);
|
||||
if (s != null) {
|
||||
dest = s;
|
||||
} else {
|
||||
dest = "TRANSIENT";
|
||||
(new File(_destFile)).delete();
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Requesting new transient destination");
|
||||
}
|
||||
} else {
|
||||
dest = "TRANSIENT";
|
||||
(new File(_destFile)).delete();
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Requesting new transient destination");
|
||||
}
|
||||
byte[] id = new byte[5];
|
||||
_context.random().nextBytes(id);
|
||||
_conOptions = "ID=" + Base32.encode(id);
|
||||
} else {
|
||||
// we use the filename as the name in sam.keys
|
||||
// and give it to the SAM server
|
||||
dest = _destFile;
|
||||
}
|
||||
String req = "SESSION CREATE STYLE=STREAM DESTINATION=" + dest + " " + _conOptions + "\n";
|
||||
_samOut.write(req.getBytes());
|
||||
_samOut.flush();
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Session create sent");
|
||||
ok = _eventHandler.waitForSessionCreateReply();
|
||||
boolean ok = _eventHandler.waitForSessionCreateReply();
|
||||
if (!ok)
|
||||
throw new IOException("Session create failed");
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Session create reply found: " + ok);
|
||||
|
||||
@ -175,6 +214,7 @@ public class SAMStreamSink {
|
||||
_log.error("No naming lookup reply found!");
|
||||
return null;
|
||||
} else {
|
||||
if (_log.shouldInfo())
|
||||
_log.info(_destFile + " is located at " + destination);
|
||||
}
|
||||
return destination;
|
||||
@ -186,10 +226,18 @@ public class SAMStreamSink {
|
||||
}
|
||||
|
||||
private boolean writeDest(String dest) {
|
||||
File f = new File(_destFile);
|
||||
if (f.exists()) {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Destination file exists, not overwriting:" + _destFile);
|
||||
return false;
|
||||
}
|
||||
FileOutputStream fos = null;
|
||||
try {
|
||||
fos = new FileOutputStream(_destFile);
|
||||
fos = new FileOutputStream(f);
|
||||
fos.write(dest.getBytes());
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("My destination written to " + _destFile);
|
||||
} catch (Exception e) {
|
||||
_log.error("Error writing to " + _destFile, e);
|
||||
return false;
|
||||
@ -236,7 +284,7 @@ public class SAMStreamSink {
|
||||
try {
|
||||
_out.close();
|
||||
} catch (IOException ioe) {
|
||||
_log.error("Error closing", ioe);
|
||||
_log.info("Error closing", ioe);
|
||||
}
|
||||
}
|
||||
public void received(byte data[], int offset, int len) {
|
||||
|
Reference in New Issue
Block a user