SAM v3.3:

- More master session option checks
- Add support for SEND_TAGS, TAG_THRESHOLD, EXPIRES, and SEND_LEASESET
  (untested)
- Consolidate dup code in SAMv1Handler
- Change Session to extend SAMMessageSess
- Pass options down to v1 handlers in case we need it later
This commit is contained in:
zzz
2016-02-07 18:45:26 +00:00
parent b6deae9b23
commit d962be9d7e
12 changed files with 187 additions and 181 deletions

View File

@ -42,7 +42,8 @@ class MasterSession extends SAMv3StreamSession implements SAMDatagramReceiver, S
private final SAMv3DatagramServer dgs; private final SAMv3DatagramServer dgs;
private final Map<String, SAMMessageSess> sessions; private final Map<String, SAMMessageSess> sessions;
private final StreamAcceptor streamAcceptor; private final StreamAcceptor streamAcceptor;
private static final String[] INVALID_OPTS = { "PORT", "HOST", "FROM_PORT", "TO_PORT", "PROTOCOL" }; private static final String[] INVALID_OPTS = { "PORT", "HOST", "FROM_PORT", "TO_PORT",
"PROTOCOL", "LISTEN_PORT", "LISTEN_PROTOCOL" };
/** /**
* Build a Session according to information * Build a Session according to information

View File

@ -32,7 +32,6 @@ class SAMDatagramSession extends SAMMessageSession {
// FIXME make final after fixing SAMv3DatagramSession override // FIXME make final after fixing SAMv3DatagramSession override
protected SAMDatagramReceiver recv; protected SAMDatagramReceiver recv;
private final I2PDatagramMaker dgramMaker; private final I2PDatagramMaker dgramMaker;
private final I2PDatagramDissector dgramDissector = new I2PDatagramDissector(); private final I2PDatagramDissector dgramDissector = new I2PDatagramDissector();
@ -50,7 +49,6 @@ class SAMDatagramSession extends SAMMessageSession {
SAMDatagramReceiver recv) throws IOException, SAMDatagramReceiver recv) throws IOException,
DataFormatException, I2PSessionException { DataFormatException, I2PSessionException {
super(dest, props); super(dest, props);
this.recv = recv; this.recv = recv;
dgramMaker = new I2PDatagramMaker(getI2PSession()); dgramMaker = new I2PDatagramMaker(getI2PSession());
} }
@ -71,7 +69,6 @@ class SAMDatagramSession extends SAMMessageSession {
SAMDatagramReceiver recv) throws IOException, SAMDatagramReceiver recv) throws IOException,
DataFormatException, I2PSessionException { DataFormatException, I2PSessionException {
super(destStream, props); super(destStream, props);
this.recv = recv; this.recv = recv;
dgramMaker = new I2PDatagramMaker(getI2PSession()); dgramMaker = new I2PDatagramMaker(getI2PSession());
} }
@ -79,13 +76,13 @@ class SAMDatagramSession extends SAMMessageSession {
/** /**
* Create a new SAM DATAGRAM session on an existing I2P session. * Create a new SAM DATAGRAM session on an existing I2P session.
* *
* @param props unused for now
* @since 0.9.25 * @since 0.9.25
*/ */
protected SAMDatagramSession(I2PSession sess, int listenPort, protected SAMDatagramSession(I2PSession sess, Properties props, int listenPort,
SAMDatagramReceiver recv) throws IOException, SAMDatagramReceiver recv) throws IOException,
DataFormatException, I2PSessionException { DataFormatException, I2PSessionException {
super(sess, I2PSession.PROTO_DATAGRAM, listenPort); super(sess, I2PSession.PROTO_DATAGRAM, listenPort);
this.recv = recv; this.recv = recv;
dgramMaker = new I2PDatagramMaker(getI2PSession()); dgramMaker = new I2PDatagramMaker(getI2PSession());
} }
@ -107,11 +104,31 @@ class SAMDatagramSession extends SAMMessageSession {
throw new DataFormatException("Datagram size exceeded (" + data.length + ")"); throw new DataFormatException("Datagram size exceeded (" + data.length + ")");
byte[] dgram ; byte[] dgram ;
synchronized (dgramMaker) { synchronized (dgramMaker) {
dgram = dgramMaker.makeI2PDatagram(data); dgram = dgramMaker.makeI2PDatagram(data);
} }
return sendBytesThroughMessageSession(dest, dgram, I2PSession.PROTO_DATAGRAM, fromPort, toPort); return sendBytesThroughMessageSession(dest, dgram, I2PSession.PROTO_DATAGRAM, fromPort, toPort);
} }
/**
* Send bytes through a SAM DATAGRAM session.
*
* @since 0.9.25
*/
public boolean sendBytes(String dest, byte[] data, int proto,
int fromPort, int toPort,
boolean sendLeaseSet, int sendTags,
int tagThreshold, int expiration)
throws DataFormatException, I2PSessionException {
if (data.length > DGRAM_SIZE_MAX)
throw new DataFormatException("Datagram size exceeded (" + data.length + ")");
byte[] dgram ;
synchronized (dgramMaker) {
dgram = dgramMaker.makeI2PDatagram(data);
}
return sendBytesThroughMessageSession(dest, dgram, I2PSession.PROTO_DATAGRAM, fromPort, toPort,
sendLeaseSet, sendTags,tagThreshold, expiration);
}
protected void messageReceived(byte[] msg, int proto, int fromPort, int toPort) { protected void messageReceived(byte[] msg, int proto, int fromPort, int toPort) {
byte[] payload; byte[] payload;
Destination sender; Destination sender;

View File

@ -46,6 +46,17 @@ interface SAMMessageSess extends Closeable {
public boolean sendBytes(String dest, byte[] data, int proto, public boolean sendBytes(String dest, byte[] data, int proto,
int fromPort, int toPort) throws DataFormatException, I2PSessionException; int fromPort, int toPort) throws DataFormatException, I2PSessionException;
/**
* Send bytes through a SAM message-based session.
*
* @since 0.9.25
*/
public boolean sendBytes(String dest, byte[] data, int proto,
int fromPort, int toPort,
boolean sendLeaseSet, int sendTags,
int tagThreshold, int expiration)
throws DataFormatException, I2PSessionException;
public int getListenProtocol(); public int getListenProtocol();
public int getListenPort(); public int getListenPort();

View File

@ -37,6 +37,7 @@ abstract class SAMMessageSession implements SAMMessageSess {
protected final Log _log; protected final Log _log;
private final I2PSession session; private final I2PSession session;
protected final boolean _isOwnSession;
private final SAMMessageSessionHandler handler; private final SAMMessageSessionHandler handler;
private final int listenProtocol; private final int listenProtocol;
private final int listenPort; private final int listenPort;
@ -69,6 +70,7 @@ abstract class SAMMessageSession implements SAMMessageSess {
_log.debug("Initializing SAM message-based session"); _log.debug("Initializing SAM message-based session");
listenProtocol = I2PSession.PROTO_ANY; listenProtocol = I2PSession.PROTO_ANY;
listenPort = I2PSession.PORT_ANY; listenPort = I2PSession.PORT_ANY;
_isOwnSession = true;
handler = new SAMMessageSessionHandler(destStream, props); handler = new SAMMessageSessionHandler(destStream, props);
session = handler.getSession(); session = handler.getSession();
} }
@ -90,6 +92,7 @@ abstract class SAMMessageSession implements SAMMessageSess {
_log.debug("Initializing SAM message-based session"); _log.debug("Initializing SAM message-based session");
this.listenProtocol = listenProtocol; this.listenProtocol = listenProtocol;
this.listenPort = listenPort; this.listenPort = listenPort;
_isOwnSession = false;
session = sess; session = sess;
handler = new SAMMessageSessionHandler(session); handler = new SAMMessageSessionHandler(session);
} }
@ -165,14 +168,19 @@ abstract class SAMMessageSession implements SAMMessageSess {
} }
/** /**
* Actually send bytes through the SAM message-based session I2PSession. * Actually send bytes through the SAM message-based session I2PSession,
* TODO unused, umimplemented in the sessions and handlers * using per-message extended options.
* For efficiency, use the method without all the extra options if they are all defaults.
* *
* @param dest Destination * @param dest Destination
* @param data Bytes to be sent * @param data Bytes to be sent
* @param proto I2CP protocol * @param proto I2CP protocol
* @param fromPort I2CP from port * @param fromPort I2CP from port
* @param toPort I2CP to port * @param toPort I2CP to port
* @param sendLeaseSet true is the usual setting and the I2CP default
* @param sendTags 0 to leave as default
* @param tagThreshold 0 to leave as default
* @param expiration SECONDS from now, NOT absolute time, 0 to leave as default
* *
* @return True if the data was sent, false otherwise * @return True if the data was sent, false otherwise
* @throws DataFormatException on unknown / bad dest * @throws DataFormatException on unknown / bad dest
@ -182,7 +190,7 @@ abstract class SAMMessageSession implements SAMMessageSess {
protected boolean sendBytesThroughMessageSession(String dest, byte[] data, protected boolean sendBytesThroughMessageSession(String dest, byte[] data,
int proto, int fromPort, int toPort, int proto, int fromPort, int toPort,
boolean sendLeaseSet, int sendTags, boolean sendLeaseSet, int sendTags,
int tagThreshold, long expires) int tagThreshold, int expiration)
throws DataFormatException, I2PSessionException { throws DataFormatException, I2PSessionException {
Destination d = SAMUtils.getDest(dest); Destination d = SAMUtils.getDest(dest);
@ -190,10 +198,14 @@ abstract class SAMMessageSession implements SAMMessageSess {
_log.debug("Sending " + data.length + " bytes to " + dest); _log.debug("Sending " + data.length + " bytes to " + dest);
} }
SendMessageOptions opts = new SendMessageOptions(); SendMessageOptions opts = new SendMessageOptions();
opts.setSendLeaseSet(sendLeaseSet); if (!sendLeaseSet)
opts.setTagsToSend(sendTags); opts.setSendLeaseSet(false);
opts.setTagThreshold(tagThreshold); if (sendTags > 0)
opts.setDate(expires); opts.setTagsToSend(sendTags);
if (tagThreshold > 0)
opts.setTagThreshold(tagThreshold);
if (expiration > 0)
opts.setDate(I2PAppContext.getGlobalContext().clock().now() + (expiration * 1000));
return session.sendMessage(d, data, 0, data.length, proto, fromPort, toPort, opts); return session.sendMessage(d, data, 0, data.length, proto, fromPort, toPort, opts);
} }
@ -234,7 +246,6 @@ abstract class SAMMessageSession implements SAMMessageSess {
private class SAMMessageSessionHandler implements Runnable, I2PSessionMuxedListener { private class SAMMessageSessionHandler implements Runnable, I2PSessionMuxedListener {
private final I2PSession _session; private final I2PSession _session;
private final boolean _isOwnSession;
private final Object runningLock = new Object(); private final Object runningLock = new Object();
private volatile boolean stillRunning = true; private volatile boolean stillRunning = true;
@ -254,7 +265,6 @@ abstract class SAMMessageSession implements SAMMessageSess {
props.setProperty("inbound.nickname", "SAM UDP Client"); props.setProperty("inbound.nickname", "SAM UDP Client");
props.setProperty("outbound.nickname", "SAM UDP Client"); props.setProperty("outbound.nickname", "SAM UDP Client");
} }
_isOwnSession = true;
_session = client.createSession(destStream, props); _session = client.createSession(destStream, props);
if (_log.shouldLog(Log.DEBUG)) if (_log.shouldLog(Log.DEBUG))
@ -272,7 +282,6 @@ abstract class SAMMessageSession implements SAMMessageSess {
* @since 0.9.25 * @since 0.9.25
*/ */
public SAMMessageSessionHandler(I2PSession sess) throws I2PSessionException { public SAMMessageSessionHandler(I2PSession sess) throws I2PSessionException {
_isOwnSession = false;
_session = sess; _session = sess;
_session.addMuxedSessionListener(this, listenProtocol, listenPort); _session.addMuxedSessionListener(this, listenProtocol, listenPort);
} }

View File

@ -42,7 +42,6 @@ class SAMRawSession extends SAMMessageSession {
protected SAMRawSession(String dest, Properties props, protected SAMRawSession(String dest, Properties props,
SAMRawReceiver recv) throws IOException, DataFormatException, I2PSessionException { SAMRawReceiver recv) throws IOException, DataFormatException, I2PSessionException {
super(dest, props); super(dest, props);
this.recv = recv; this.recv = recv;
} }
@ -61,16 +60,16 @@ class SAMRawSession extends SAMMessageSession {
public SAMRawSession(InputStream destStream, Properties props, public SAMRawSession(InputStream destStream, Properties props,
SAMRawReceiver recv) throws IOException, DataFormatException, I2PSessionException { SAMRawReceiver recv) throws IOException, DataFormatException, I2PSessionException {
super(destStream, props); super(destStream, props);
this.recv = recv; this.recv = recv;
} }
/** /**
* Create a new SAM RAW session on an existing I2P session. * Create a new SAM RAW session on an existing I2P session.
* *
* @param props unused for now
* @since 0.9.25 * @since 0.9.25
*/ */
protected SAMRawSession(I2PSession sess, int listenProtocol, int listenPort, protected SAMRawSession(I2PSession sess, Properties props, int listenProtocol, int listenPort,
SAMRawReceiver recv) throws IOException, SAMRawReceiver recv) throws IOException,
DataFormatException, I2PSessionException { DataFormatException, I2PSessionException {
super(sess, listenProtocol, listenPort); super(sess, listenProtocol, listenPort);
@ -96,6 +95,24 @@ class SAMRawSession extends SAMMessageSession {
return sendBytesThroughMessageSession(dest, data, proto, fromPort, toPort); return sendBytesThroughMessageSession(dest, data, proto, fromPort, toPort);
} }
/**
* Send bytes through a SAM RAW session.
*
* @since 0.9.25
*/
public boolean sendBytes(String dest, byte[] data, int proto,
int fromPort, int toPort,
boolean sendLeaseSet, int sendTags,
int tagThreshold, int expiration)
throws DataFormatException, I2PSessionException {
if (data.length > RAW_SIZE_MAX)
throw new DataFormatException("Data size limit exceeded (" + data.length + ")");
if (proto == I2PSession.PROTO_UNSPECIFIED)
proto = I2PSession.PROTO_DATAGRAM_RAW;
return sendBytesThroughMessageSession(dest, data, proto, fromPort, toPort,
sendLeaseSet, sendTags,tagThreshold, expiration);
}
protected void messageReceived(byte[] msg, int proto, int fromPort, int toPort) { protected void messageReceived(byte[] msg, int proto, int fromPort, int toPort) {
try { try {
recv.receiveRawBytes(msg, proto, fromPort, toPort); recv.receiveRawBytes(msg, proto, fromPort, toPort);

View File

@ -372,7 +372,19 @@ class SAMStreamSession implements SAMMessageSess {
* @since 0.9.25 moved from subclass SAMv3StreamSession to implement SAMMessageSess * @since 0.9.25 moved from subclass SAMv3StreamSession to implement SAMMessageSess
*/ */
public boolean sendBytes(String s, byte[] b, int pr, int fp, int tp) throws I2PSessionException { public boolean sendBytes(String s, byte[] b, int pr, int fp, int tp) throws I2PSessionException {
throw new I2PSessionException("Unsupported in STREAM or MASTER session"); throw new I2PSessionException("Unsupported in STREAM or MASTER session");
}
/**
* Unsupported
* @throws I2PSessionException always
* @since 0.9.25
*/
public boolean sendBytes(String s, byte[] b, int pr, int fp, int tp,
boolean sendLeaseSet, int sendTags,
int tagThreshold, int expiration)
throws I2PSessionException {
throw new I2PSessionException("Unsupported in STREAM or MASTER session");
} }
/** /**

View File

@ -419,102 +419,7 @@ class SAMv1Handler extends SAMHandler implements SAMRawReceiver, SAMDatagramRece
_log.error("DATAGRAM message received, but no DATAGRAM session exists"); _log.error("DATAGRAM message received, but no DATAGRAM session exists");
return false; return false;
} }
return execDgOrRawMessage(false, opcode, props);
if (opcode.equals("SEND")) {
if (props.isEmpty()) {
if (_log.shouldLog(Log.DEBUG))
_log.debug("No parameters specified in DATAGRAM SEND message");
return false;
}
String dest = props.getProperty("DESTINATION");
if (dest == null) {
if (_log.shouldLog(Log.DEBUG))
_log.debug("Destination not specified in DATAGRAM SEND message");
return false;
}
int size;
String strsize = props.getProperty("SIZE");
if (strsize == null) {
if (_log.shouldLog(Log.WARN))
_log.warn("Size not specified in DATAGRAM SEND message");
return false;
}
try {
size = Integer.parseInt(strsize);
} catch (NumberFormatException e) {
if (_log.shouldLog(Log.WARN))
_log.warn("Invalid DATAGRAM SEND size specified: " + strsize);
return false;
}
if (!checkDatagramSize(size)) {
if (_log.shouldLog(Log.WARN))
_log.warn("Specified size (" + size
+ ") is out of protocol limits");
return false;
}
int proto = I2PSession.PROTO_DATAGRAM;
int fromPort = I2PSession.PORT_UNSPECIFIED;
int toPort = I2PSession.PORT_UNSPECIFIED;
String s = props.getProperty("FROM_PORT");
if (s != null) {
try {
fromPort = Integer.parseInt(s);
} catch (NumberFormatException e) {
if (_log.shouldLog(Log.WARN))
_log.warn("Invalid DATAGRAM SEND port specified: " + s);
}
}
s = props.getProperty("TO_PORT");
if (s != null) {
try {
toPort = Integer.parseInt(s);
} catch (NumberFormatException e) {
if (_log.shouldLog(Log.WARN))
_log.warn("Invalid RAW SEND port specified: " + s);
}
}
try {
DataInputStream in = new DataInputStream(getClientSocket().socket().getInputStream());
byte[] data = new byte[size];
in.readFully(data);
if (!datagramSession.sendBytes(dest, data, proto, fromPort, toPort)) {
_log.error("DATAGRAM SEND failed");
// a message send failure is no reason to drop the SAM session
// for raw and repliable datagrams, just carry on our merry way
return true;
}
return true;
} catch (EOFException e) {
if (_log.shouldLog(Log.DEBUG))
_log.debug("Too few bytes with DATAGRAM SEND message (expected: "
+ size);
return false;
} catch (IOException e) {
if (_log.shouldLog(Log.DEBUG))
_log.debug("Caught IOException while parsing DATAGRAM SEND message",
e);
return false;
} catch (DataFormatException e) {
if (_log.shouldLog(Log.DEBUG))
_log.debug("Invalid key specified with DATAGRAM SEND message",
e);
return false;
} catch (I2PSessionException e) {
_log.error("Session error with DATAGRAM SEND message", e);
return false;
}
} else {
if (_log.shouldLog(Log.DEBUG))
_log.debug("Unrecognized DATAGRAM message opcode: \""
+ opcode + "\"");
return false;
}
} }
/* Parse and execute a RAW message */ /* Parse and execute a RAW message */
@ -523,18 +428,33 @@ class SAMv1Handler extends SAMHandler implements SAMRawReceiver, SAMDatagramRece
_log.error("RAW message received, but no RAW session exists"); _log.error("RAW message received, but no RAW session exists");
return false; return false;
} }
return execDgOrRawMessage(true, opcode, props);
}
/*
* Parse and execute a RAW or DATAGRAM SEND message.
* This is for v1/v2 compatible sending only.
* For v3 sending, see SAMv3DatagramServer.
*
* Note that props are from the command line only.
* Session defaults from CREATE are NOT honored here.
* FIXME if we care, but nobody's probably using v3.2 options for v1/v2 sending.
*
* @since 0.9.25 consolidated from execDatagramMessage() and execRawMessage()
*/
private boolean execDgOrRawMessage(boolean isRaw, String opcode, Properties props) {
if (opcode.equals("SEND")) { if (opcode.equals("SEND")) {
if (props.isEmpty()) { if (props.isEmpty()) {
if (_log.shouldLog(Log.DEBUG)) if (_log.shouldLog(Log.DEBUG))
_log.debug("No parameters specified in RAW SEND message"); _log.debug("No parameters specified in SEND message");
return false; return false;
} }
String dest = props.getProperty("DESTINATION"); String dest = props.getProperty("DESTINATION");
if (dest == null) { if (dest == null) {
if (_log.shouldLog(Log.DEBUG)) if (_log.shouldLog(Log.DEBUG))
_log.debug("Destination not specified in RAW SEND message"); _log.debug("Destination not specified in SEND message");
return false; return false;
} }
@ -542,41 +462,47 @@ class SAMv1Handler extends SAMHandler implements SAMRawReceiver, SAMDatagramRece
String strsize = props.getProperty("SIZE"); String strsize = props.getProperty("SIZE");
if (strsize == null) { if (strsize == null) {
if (_log.shouldLog(Log.WARN)) if (_log.shouldLog(Log.WARN))
_log.warn("Size not specified in RAW SEND message"); _log.warn("Size not specified in SEND message");
return false; return false;
} }
try { try {
size = Integer.parseInt(strsize); size = Integer.parseInt(strsize);
} catch (NumberFormatException e) { } catch (NumberFormatException e) {
if (_log.shouldLog(Log.WARN)) if (_log.shouldLog(Log.WARN))
_log.warn("Invalid RAW SEND size specified: " + strsize); _log.warn("Invalid SEND size specified: " + strsize);
return false; return false;
} }
if (!checkSize(size)) { boolean ok = isRaw ? checkSize(size) : checkDatagramSize(size);
if (!ok) {
if (_log.shouldLog(Log.WARN)) if (_log.shouldLog(Log.WARN))
_log.warn("Specified size (" + size _log.warn("Specified size (" + size
+ ") is out of protocol limits"); + ") is out of protocol limits");
return false; return false;
} }
int proto = I2PSession.PROTO_DATAGRAM_RAW;
int fromPort = I2PSession.PORT_UNSPECIFIED; int fromPort = I2PSession.PORT_UNSPECIFIED;
int toPort = I2PSession.PORT_UNSPECIFIED; int toPort = I2PSession.PORT_UNSPECIFIED;
String s = props.getProperty("PROTOCOL"); int proto;
if (s != null) { if (isRaw) {
try { proto = I2PSession.PROTO_DATAGRAM_RAW;
proto = Integer.parseInt(s); String s = props.getProperty("PROTOCOL");
} catch (NumberFormatException e) { if (s != null) {
if (_log.shouldLog(Log.WARN)) try {
_log.warn("Invalid RAW SEND protocol specified: " + s); proto = Integer.parseInt(s);
} catch (NumberFormatException e) {
if (_log.shouldLog(Log.WARN))
_log.warn("Invalid SEND protocol specified: " + s);
}
} }
} else {
proto = I2PSession.PROTO_DATAGRAM;
} }
s = props.getProperty("FROM_PORT"); String s = props.getProperty("FROM_PORT");
if (s != null) { if (s != null) {
try { try {
fromPort = Integer.parseInt(s); fromPort = Integer.parseInt(s);
} catch (NumberFormatException e) { } catch (NumberFormatException e) {
if (_log.shouldLog(Log.WARN)) if (_log.shouldLog(Log.WARN))
_log.warn("Invalid RAW SEND port specified: " + s); _log.warn("Invalid SEND port specified: " + s);
} }
} }
s = props.getProperty("TO_PORT"); s = props.getProperty("TO_PORT");
@ -585,7 +511,7 @@ class SAMv1Handler extends SAMHandler implements SAMRawReceiver, SAMDatagramRece
toPort = Integer.parseInt(s); toPort = Integer.parseInt(s);
} catch (NumberFormatException e) { } catch (NumberFormatException e) {
if (_log.shouldLog(Log.WARN)) if (_log.shouldLog(Log.WARN))
_log.warn("Invalid RAW SEND port specified: " + s); _log.warn("Invalid SEND port specified: " + s);
} }
} }
@ -595,8 +521,9 @@ class SAMv1Handler extends SAMHandler implements SAMRawReceiver, SAMDatagramRece
in.readFully(data); in.readFully(data);
if (!rawSession.sendBytes(dest, data, proto, fromPort, toPort)) { SAMMessageSess sess = isRaw ? rawSession : datagramSession;
_log.error("RAW SEND failed"); if (sess.sendBytes(dest, data, proto, fromPort, toPort)) {
_log.error("SEND failed");
// a message send failure is no reason to drop the SAM session // a message send failure is no reason to drop the SAM session
// for raw and repliable datagrams, just carry on our merry way // for raw and repliable datagrams, just carry on our merry way
return true; return true;
@ -605,26 +532,26 @@ class SAMv1Handler extends SAMHandler implements SAMRawReceiver, SAMDatagramRece
return true; return true;
} catch (EOFException e) { } catch (EOFException e) {
if (_log.shouldLog(Log.DEBUG)) if (_log.shouldLog(Log.DEBUG))
_log.debug("Too few bytes with RAW SEND message (expected: " _log.debug("Too few bytes with SEND message (expected: "
+ size); + size);
return false; return false;
} catch (IOException e) { } catch (IOException e) {
if (_log.shouldLog(Log.DEBUG)) if (_log.shouldLog(Log.DEBUG))
_log.debug("Caught IOException while parsing RAW SEND message", _log.debug("Caught IOException while parsing SEND message",
e); e);
return false; return false;
} catch (DataFormatException e) { } catch (DataFormatException e) {
if (_log.shouldLog(Log.DEBUG)) if (_log.shouldLog(Log.DEBUG))
_log.debug("Invalid key specified with RAW SEND message", _log.debug("Invalid key specified with SEND message",
e); e);
return false; return false;
} catch (I2PSessionException e) { } catch (I2PSessionException e) {
_log.error("Session error with RAW SEND message", e); _log.error("Session error with SEND message", e);
return false; return false;
} }
} else { } else {
if (_log.shouldLog(Log.DEBUG)) if (_log.shouldLog(Log.DEBUG))
_log.debug("Unrecognized RAW message opcode: \"" _log.debug("Unrecognized message opcode: \""
+ opcode + "\""); + opcode + "\"");
return false; return false;
} }
@ -645,7 +572,7 @@ class SAMv1Handler extends SAMHandler implements SAMRawReceiver, SAMDatagramRece
return execStreamClose(props); return execStreamClose(props);
} else { } else {
if (_log.shouldLog(Log.DEBUG)) if (_log.shouldLog(Log.DEBUG))
_log.debug("Unrecognized RAW message opcode: \"" _log.debug("Unrecognized STREAM message opcode: \""
+ opcode + "\""); + opcode + "\"");
return false; return false;
} }

View File

@ -163,54 +163,79 @@ class SAMv3DatagramServer implements Handler {
SessionRecord rec = SAMv3Handler.sSessionsHash.get(nick); SessionRecord rec = SAMv3Handler.sSessionsHash.get(nick);
if (rec!=null) { if (rec!=null) {
Properties sprops = rec.getProps(); Properties sprops = rec.getProps();
// 3.2 props
String pr = sprops.getProperty("PROTOCOL"); String pr = sprops.getProperty("PROTOCOL");
String fp = sprops.getProperty("FROM_PORT"); String fp = sprops.getProperty("FROM_PORT");
String tp = sprops.getProperty("TO_PORT"); String tp = sprops.getProperty("TO_PORT");
// 3.3 props
String st = sprops.getProperty("SEND_TAGS");
String tt = sprops.getProperty("TAG_THRESHOLD");
String ex = sprops.getProperty("EXPIRES");
String sl = sprops.getProperty("SEND_LEASESET");
while (tok.hasMoreTokens()) { while (tok.hasMoreTokens()) {
String t = tok.nextToken(); String t = tok.nextToken();
// 3.2 props
if (t.startsWith("PROTOCOL=")) if (t.startsWith("PROTOCOL="))
pr = t.substring("PROTOCOL=".length()); pr = t.substring("PROTOCOL=".length());
else if (t.startsWith("FROM_PORT=")) else if (t.startsWith("FROM_PORT="))
fp = t.substring("FROM_PORT=".length()); fp = t.substring("FROM_PORT=".length());
else if (t.startsWith("TO_PORT=")) else if (t.startsWith("TO_PORT="))
tp = t.substring("TO_PORT=".length()); tp = t.substring("TO_PORT=".length());
// 3.3 props
else if (t.startsWith("SEND_TAGS="))
st = t.substring("SEND_TAGS=".length());
else if (t.startsWith("TAG_THRESHOLD="))
tt = t.substring("TAG_THRESHOLD=".length());
else if (t.startsWith("EXPIRES="))
ex = t.substring("EXPIRES=".length());
else if (t.startsWith("SEND_LEASESET="))
sl = t.substring("SEND_LEASESET=".length());
} }
// 3.2 props
int proto = I2PSession.PROTO_UNSPECIFIED; int proto = I2PSession.PROTO_UNSPECIFIED;
int fromPort = I2PSession.PORT_UNSPECIFIED; int fromPort = I2PSession.PORT_UNSPECIFIED;
int toPort = I2PSession.PORT_UNSPECIFIED; int toPort = I2PSession.PORT_UNSPECIFIED;
if (pr != null) { // 3.3 props
try { int sendTags = 0;
int tagThreshold = 0;
int expires = 0;
boolean sendLeaseSet = true;
try {
// 3.2 props
if (pr != null)
proto = Integer.parseInt(pr); proto = Integer.parseInt(pr);
} catch (NumberFormatException nfe) { if (fp != null)
warn("Bad datagram header received");
return;
}
}
if (fp != null) {
try {
fromPort = Integer.parseInt(fp); fromPort = Integer.parseInt(fp);
} catch (NumberFormatException nfe) { if (tp != null)
warn("Bad datagram header received");
return;
}
}
if (tp != null) {
try {
toPort = Integer.parseInt(tp); toPort = Integer.parseInt(tp);
} catch (NumberFormatException nfe) { // 3.3 props
warn("Bad datagram header received"); if (st != null)
return; sendTags = Integer.parseInt(st);
} if (tt != null)
tagThreshold = Integer.parseInt(tt);
if (ex != null)
expires = Integer.parseInt(ex);
if (sl != null)
sendLeaseSet = Boolean.parseBoolean(sl);
} catch (NumberFormatException nfe) {
warn("Bad datagram header received");
return;
} }
// TODO too many allocations and copies. One here and one in Listener above. // TODO too many allocations and copies. One here and one in Listener above.
byte[] data = new byte[is.available()]; byte[] data = new byte[is.available()];
is.read(data); is.read(data);
Session sess = rec.getHandler().getSession(); Session sess = rec.getHandler().getSession();
if (sess != null) if (sess != null) {
sess.sendBytes(dest, data, proto, fromPort, toPort); if (sendTags > 0 || tagThreshold > 0 || expires > 0 || !sendLeaseSet) {
else sess.sendBytes(dest, data, proto, fromPort, toPort,
sendLeaseSet, sendTags, tagThreshold, expires);
} else {
sess.sendBytes(dest, data, proto, fromPort, toPort);
}
} else {
warn("Dropping datagram, no session for " + nick); warn("Dropping datagram, no session for " + nick);
}
} else { } else {
warn("Dropping datagram, no session for " + nick); warn("Dropping datagram, no session for " + nick);
} }

View File

@ -74,7 +74,7 @@ class SAMv3DatagramSession extends SAMDatagramSession implements Session, SAMDat
public SAMv3DatagramSession(String nick, Properties props, SAMv3Handler handler, I2PSession isess, public SAMv3DatagramSession(String nick, Properties props, SAMv3Handler handler, I2PSession isess,
int listenPort, SAMv3DatagramServer dgServer) int listenPort, SAMv3DatagramServer dgServer)
throws IOException, DataFormatException, I2PSessionException { throws IOException, DataFormatException, I2PSessionException {
super(isess, listenPort, null); // to be replaced by this super(isess, props, listenPort, null); // to be replaced by this
this.nick = nick ; this.nick = nick ;
this.recv = this ; // replacement this.recv = this ; // replacement
this.server = dgServer; this.server = dgServer;

View File

@ -75,7 +75,7 @@ class SAMv3RawSession extends SAMRawSession implements Session, SAMRawReceiver {
public SAMv3RawSession(String nick, Properties props, SAMv3Handler handler, I2PSession isess, public SAMv3RawSession(String nick, Properties props, SAMv3Handler handler, I2PSession isess,
int listenProtocol, int listenPort, SAMv3DatagramServer dgServer) int listenProtocol, int listenPort, SAMv3DatagramServer dgServer)
throws IOException, DataFormatException, I2PSessionException { throws IOException, DataFormatException, I2PSessionException {
super(isess, listenProtocol, listenPort, null); // to be replace by this super(isess, props, listenProtocol, listenPort, null); // to be replaced by this
this.nick = nick ; this.nick = nick ;
this.recv = this ; // replacement this.recv = this ; // replacement
this.server = dgServer; this.server = dgServer;

View File

@ -131,6 +131,7 @@ class SAMv3StreamSession extends SAMStreamSession implements Session
if (_acceptQueue == null) if (_acceptQueue == null)
throw new IllegalStateException(); throw new IllegalStateException();
try { try {
// TODO there's no CoDel or expiration in this queue
return _acceptQueue.take(); return _acceptQueue.take();
} catch (InterruptedException ie) { } catch (InterruptedException ie) {
ConnectException ce = new ConnectException("interrupted"); ConnectException ce = new ConnectException("interrupted");

View File

@ -1,25 +1,11 @@
package net.i2p.sam; package net.i2p.sam;
/*
* free (adj.): unencumbered; not under the control of others
* Written by human in 2004 and released into the public domain
* with no warranty of any kind, either expressed or implied.
* It probably won't make your computer catch on fire, or eat
* your children, but it might. Use at your own risk.
*
*/
import net.i2p.client.I2PSessionException;
import net.i2p.data.DataFormatException;
/** /**
* A V3 session. * A V3 session.
* *
* @since 0.9.25 moved from SAMv3Handler * @since 0.9.25 moved from SAMv3Handler
*/ */
interface Session { interface Session extends SAMMessageSess {
String getNick(); String getNick();
void close();
boolean sendBytes(String dest, byte[] data, int proto,
int fromPort, int toPort) throws DataFormatException, I2PSessionException;
} }