forked from I2P_Developers/i2p.i2p
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:
@ -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
|
||||||
|
@ -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());
|
||||||
}
|
}
|
||||||
@ -112,6 +109,26 @@ class SAMDatagramSession extends SAMMessageSession {
|
|||||||
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;
|
||||||
|
@ -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();
|
||||||
|
@ -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.setSendLeaseSet(false);
|
||||||
|
if (sendTags > 0)
|
||||||
opts.setTagsToSend(sendTags);
|
opts.setTagsToSend(sendTags);
|
||||||
|
if (tagThreshold > 0)
|
||||||
opts.setTagThreshold(tagThreshold);
|
opts.setTagThreshold(tagThreshold);
|
||||||
opts.setDate(expires);
|
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);
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
@ -375,6 +375,18 @@ class SAMStreamSession implements SAMMessageSess {
|
|||||||
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");
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new SAM STREAM session socket handler, detaching its thread.
|
* Create a new SAM STREAM session socket handler, detaching its thread.
|
||||||
*
|
*
|
||||||
|
@ -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;
|
||||||
|
int proto;
|
||||||
|
if (isRaw) {
|
||||||
|
proto = I2PSession.PROTO_DATAGRAM_RAW;
|
||||||
String s = props.getProperty("PROTOCOL");
|
String s = props.getProperty("PROTOCOL");
|
||||||
if (s != null) {
|
if (s != null) {
|
||||||
try {
|
try {
|
||||||
proto = Integer.parseInt(s);
|
proto = Integer.parseInt(s);
|
||||||
} catch (NumberFormatException e) {
|
} catch (NumberFormatException e) {
|
||||||
if (_log.shouldLog(Log.WARN))
|
if (_log.shouldLog(Log.WARN))
|
||||||
_log.warn("Invalid RAW SEND protocol specified: " + s);
|
_log.warn("Invalid SEND protocol specified: " + s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
s = props.getProperty("FROM_PORT");
|
} else {
|
||||||
|
proto = I2PSession.PROTO_DATAGRAM;
|
||||||
|
}
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
int sendTags = 0;
|
||||||
|
int tagThreshold = 0;
|
||||||
|
int expires = 0;
|
||||||
|
boolean sendLeaseSet = true;
|
||||||
try {
|
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);
|
||||||
|
// 3.3 props
|
||||||
|
if (st != null)
|
||||||
|
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) {
|
} catch (NumberFormatException nfe) {
|
||||||
warn("Bad datagram header received");
|
warn("Bad datagram header received");
|
||||||
return;
|
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) {
|
||||||
|
if (sendTags > 0 || tagThreshold > 0 || expires > 0 || !sendLeaseSet) {
|
||||||
|
sess.sendBytes(dest, data, proto, fromPort, toPort,
|
||||||
|
sendLeaseSet, sendTags, tagThreshold, expires);
|
||||||
|
} else {
|
||||||
sess.sendBytes(dest, data, proto, fromPort, toPort);
|
sess.sendBytes(dest, data, proto, fromPort, toPort);
|
||||||
else
|
}
|
||||||
|
} 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);
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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");
|
||||||
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user