Remove singleton SAMv3DatagramServer; hang off of SAMBridge

SAMv3DatagramSession whitespace fixes
@since change to 0.9.24
This commit is contained in:
zzz
2015-11-23 18:19:17 +00:00
parent c7d68c2a6c
commit 110a0a1b7a
10 changed files with 105 additions and 114 deletions

View File

@@ -11,7 +11,7 @@ import java.net.SocketTimeoutException;
/** /**
* Modified from I2PTunnelHTTPServer * Modified from I2PTunnelHTTPServer
* *
* @since 0.9.22 * @since 0.9.24
*/ */
class ReadLine { class ReadLine {

View File

@@ -60,6 +60,8 @@ public class SAMBridge implements Runnable, ClientApp {
private final boolean _useSSL; private final boolean _useSSL;
private final File _configFile; private final File _configFile;
private volatile Thread _runner; private volatile Thread _runner;
private final Object _v3DGServerLock = new Object();
private SAMv3DatagramServer _v3DGServer;
/** /**
* filename in which the name to private key mapping should * filename in which the name to private key mapping should
@@ -95,7 +97,8 @@ public class SAMBridge implements Runnable, ClientApp {
public static final String PROP_DATAGRAM_HOST = "sam.udp.host"; public static final String PROP_DATAGRAM_HOST = "sam.udp.host";
public static final String PROP_DATAGRAM_PORT = "sam.udp.port"; public static final String PROP_DATAGRAM_PORT = "sam.udp.port";
protected static final String DEFAULT_DATAGRAM_HOST = "127.0.0.1"; protected static final String DEFAULT_DATAGRAM_HOST = "127.0.0.1";
protected static final String DEFAULT_DATAGRAM_PORT = "7655"; protected static final int DEFAULT_DATAGRAM_PORT_INT = 7655;
protected static final String DEFAULT_DATAGRAM_PORT = Integer.toString(DEFAULT_DATAGRAM_PORT_INT);
/** /**
@@ -354,6 +357,40 @@ public class SAMBridge implements Runnable, ClientApp {
} }
} }
/**
* Was a static singleton, now a singleton for this bridge.
* Instantiate and start server if it doesn't exist.
* We only listen on one host and port, as specified in the
* sam.udp.host and sam.udp.port properties.
* TODO we could have multiple servers on different hosts/ports in the future.
*
* @param props non-null instantiate and start server if it doesn't exist
* @param return non-null
* @throws IOException if can't bind to host/port, or if different than existing
* @since 0.9.24
*/
SAMv3DatagramServer getV3DatagramServer(Properties props) throws IOException {
String host = props.getProperty(PROP_DATAGRAM_HOST, DEFAULT_DATAGRAM_HOST);
int port;
String portStr = props.getProperty(PROP_DATAGRAM_PORT, DEFAULT_DATAGRAM_PORT);
try {
port = Integer.parseInt(portStr);
} catch (NumberFormatException e) {
port = DEFAULT_DATAGRAM_PORT_INT;
}
synchronized (_v3DGServerLock) {
if (_v3DGServer == null) {
_v3DGServer = new SAMv3DatagramServer(this, host, port, props);
_v3DGServer.start();
} else {
if (_v3DGServer.getPort() != port || !_v3DGServer.getHost().equals(host))
throw new IOException("Already have V3 DatagramServer with host=" + host + " port=" + port);
}
return _v3DGServer;
}
}
////// begin ClientApp interface, use only if using correct construtor ////// begin ClientApp interface, use only if using correct construtor
/** /**
@@ -750,7 +787,7 @@ public class SAMBridge implements Runnable, ClientApp {
} }
} }
/** @since 0.9.22 */ /** @since 0.9.24 */
public void saveConfig() throws IOException { public void saveConfig() throws IOException {
DataHelper.storeProps(i2cpProps, _configFile); DataHelper.storeProps(i2cpProps, _configFile);
} }

View File

@@ -249,7 +249,7 @@ abstract class SAMMessageSession {
I2PSession.PORT_UNSPECIFIED, I2PSession.PORT_UNSPECIFIED); I2PSession.PORT_UNSPECIFIED, I2PSession.PORT_UNSPECIFIED);
} }
/** @since 0.9.22 */ /** @since 0.9.24 */
public void messageAvailable(I2PSession session, int msgId, long size, public void messageAvailable(I2PSession session, int msgId, long size,
int proto, int fromPort, int toPort) { int proto, int fromPort, int toPort) {

View File

@@ -26,78 +26,42 @@ import net.i2p.util.I2PAppThread;
import net.i2p.util.Log; import net.i2p.util.Log;
/** /**
* This is a singleton listening on 127.0.0.1:7655 or as specified by * This is the thread listening on 127.0.0.1:7655 or as specified by
* sam.udp.host and sam.udp.port properties. * sam.udp.host and sam.udp.port properties.
* This is used for both repliable and raw datagrams. * This is used for both repliable and raw datagrams.
* *
* @since 0.9.22 moved from SAMv3Handler * @since 0.9.24 moved from SAMv3Handler
*/ */
class SAMv3DatagramServer implements Handler { class SAMv3DatagramServer implements Handler {
private static SAMv3DatagramServer _instance; private final DatagramChannel _server;
private static DatagramChannel server;
private final Thread _listener; private final Thread _listener;
private final SAMBridge _parent; private final SAMBridge _parent;
private final String _host;
/** private final int _port;
* Returns the singleton.
* If this is the first call, will be instantiated and will listen
* on the default host:port 127.0.0.1:7655.
* Don't make this the first call.
*/
public static SAMv3DatagramServer getInstance() throws IOException {
return getInstance(null, new Properties());
}
/**
* Returns the singleton.
* If this is the first call, will be instantiated and will listen
* on the specified host:port, default 127.0.0.1:7655.
* Properties are sam.udp.host and sam.udp.port.
*
* @param props ignored unless this is the first call
*/
public static SAMv3DatagramServer getInstance(SAMBridge parent, Properties props) throws IOException {
synchronized(SAMv3DatagramServer.class) {
if (_instance==null) {
_instance = new SAMv3DatagramServer(parent, props);
_instance.start();
}
}
return _instance;
}
/** /**
* Does not start listener. * Does not start listener.
* Caller must call start(). * Caller must call start().
* *
* @param parent may be null * @param parent may be null
* @param props ignored for now
*/ */
private SAMv3DatagramServer(SAMBridge parent, Properties props) throws IOException { public SAMv3DatagramServer(SAMBridge parent, String host, int port, Properties props) throws IOException {
_parent = parent; _parent = parent;
synchronized(SAMv3DatagramServer.class) { _server = DatagramChannel.open();
if (server==null)
server = DatagramChannel.open();
}
String host = props.getProperty(SAMBridge.PROP_DATAGRAM_HOST, SAMBridge.DEFAULT_DATAGRAM_HOST); _server.socket().bind(new InetSocketAddress(host, port));
String portStr = props.getProperty(SAMBridge.PROP_DATAGRAM_PORT, SAMBridge.DEFAULT_DATAGRAM_PORT); _listener = new I2PAppThread(new Listener(_server), "SAM DatagramListener " + port);
int port ; _host = host;
try { _port = port;
port = Integer.parseInt(portStr);
} catch (NumberFormatException e) {
port = Integer.parseInt(SAMBridge.DEFAULT_DATAGRAM_PORT);
}
server.socket().bind(new InetSocketAddress(host, port));
_listener = new I2PAppThread(new Listener(server), "SAM DatagramListener " + port);
} }
/** /**
* Only call once. * Only call once.
* @since 0.9.22 * @since 0.9.22
*/ */
private synchronized void start() { public synchronized void start() {
_listener.start(); _listener.start();
if (_parent != null) if (_parent != null)
_parent.register(this); _parent.register(this);
@@ -108,23 +72,24 @@ class SAMv3DatagramServer implements Handler {
* @since 0.9.22 * @since 0.9.22
*/ */
public synchronized void stopHandling() { public synchronized void stopHandling() {
synchronized(SAMv3DatagramServer.class) { try {
if (server != null) { _server.close();
try { } catch (IOException ioe) {}
server.close();
} catch (IOException ioe) {}
server = null;
}
}
_listener.interrupt(); _listener.interrupt();
if (_parent != null) if (_parent != null)
_parent.unregister(this); _parent.unregister(this);
} }
public void send(SocketAddress addr, ByteBuffer msg) throws IOException { public void send(SocketAddress addr, ByteBuffer msg) throws IOException {
server.send(msg, addr); _server.send(msg, addr);
} }
/** @since 0.9.24 */
public String getHost() { return _host; }
/** @since 0.9.24 */
public int getPort() { return _port; }
private static class Listener implements Runnable { private static class Listener implements Runnable {
private final DatagramChannel server; private final DatagramChannel server;

View File

@@ -30,45 +30,44 @@ class SAMv3DatagramSession extends SAMDatagramSession implements SAMv3Handler.Se
/** /**
* build a DatagramSession according to informations registered * build a DatagramSession according to informations registered
* with the given nickname * with the given nickname
*
* @param nick nickname of the session * @param nick nickname of the session
* @throws IOException * @throws IOException
* @throws DataFormatException * @throws DataFormatException
* @throws I2PSessionException * @throws I2PSessionException
*/ */
public SAMv3DatagramSession(String nick) public SAMv3DatagramSession(String nick, SAMv3DatagramServer dgServer)
throws IOException, DataFormatException, I2PSessionException, SAMException { throws IOException, DataFormatException, I2PSessionException, SAMException {
super(SAMv3Handler.sSessionsHash.get(nick).getDest(), super(SAMv3Handler.sSessionsHash.get(nick).getDest(),
SAMv3Handler.sSessionsHash.get(nick).getProps(), SAMv3Handler.sSessionsHash.get(nick).getProps(),
null // to be replaced by this null // to be replaced by this
); );
this.nick = nick ; this.nick = nick;
this.recv = this ; // replacement this.recv = this; // replacement
this.server = SAMv3DatagramServer.getInstance() ; this.server = dgServer;
SAMv3Handler.SessionRecord rec = SAMv3Handler.sSessionsHash.get(nick); SAMv3Handler.SessionRecord rec = SAMv3Handler.sSessionsHash.get(nick);
if ( rec==null ) throw new SAMException("Record disappeared for nickname : \""+nick+"\"") ; if (rec == null)
throw new SAMException("Record disappeared for nickname : \""+nick+"\"");
this.handler = rec.getHandler(); this.handler = rec.getHandler();
Properties props = rec.getProps(); Properties props = rec.getProps();
String portStr = props.getProperty("PORT") ; String portStr = props.getProperty("PORT");
if ( portStr==null ) { if (portStr == null) {
_log.debug("receiver port not specified. Current socket will be used."); if (_log.shouldDebug())
this.clientAddress = null; _log.debug("receiver port not specified. Current socket will be used.");
} this.clientAddress = null;
else { } else {
int port = Integer.parseInt(portStr); int port = Integer.parseInt(portStr);
String host = props.getProperty("HOST");
String host = props.getProperty("HOST"); if (host == null) {
if ( host==null ) { host = rec.getHandler().getClientIP();
host = rec.getHandler().getClientIP(); if (_log.shouldDebug())
_log.debug("no host specified. Taken from the client socket : " + host+':'+port); _log.debug("no host specified. Taken from the client socket : " + host+':'+port);
} }
this.clientAddress = new InetSocketAddress(host, port);
}
this.clientAddress = new InetSocketAddress(host,port);
}
} }
public void receiveDatagramBytes(Destination sender, byte[] data, int proto, public void receiveDatagramBytes(Destination sender, byte[] data, int proto,

View File

@@ -250,7 +250,7 @@ class SAMv3Handler extends SAMv1Handler
/** /**
* For SAMv3DatagramServer * For SAMv3DatagramServer
* @return may be null * @return may be null
* @since 0.9.22 * @since 0.9.24
*/ */
Session getSession() { Session getSession() {
return session; return session;
@@ -592,13 +592,13 @@ class SAMv3Handler extends SAMv1Handler
// Create the session // Create the session
if (style.equals("RAW")) { if (style.equals("RAW")) {
SAMv3DatagramServer.getInstance(bridge, i2cpProps); SAMv3DatagramServer dgs = bridge.getV3DatagramServer(props);
SAMv3RawSession v3 = newSAMRawSession(nick); SAMv3RawSession v3 = new SAMv3RawSession(nick, dgs);
rawSession = v3; rawSession = v3;
this.session = v3; this.session = v3;
} else if (style.equals("DATAGRAM")) { } else if (style.equals("DATAGRAM")) {
SAMv3DatagramServer.getInstance(bridge, i2cpProps); SAMv3DatagramServer dgs = bridge.getV3DatagramServer(props);
SAMv3DatagramSession v3 = newSAMDatagramSession(nick); SAMv3DatagramSession v3 = new SAMv3DatagramSession(nick, dgs);
datagramSession = v3; datagramSession = v3;
this.session = v3; this.session = v3;
} else if (style.equals("STREAM")) { } else if (style.equals("STREAM")) {
@@ -652,18 +652,6 @@ class SAMv3Handler extends SAMv1Handler
return new SAMv3StreamSession( login ) ; return new SAMv3StreamSession( login ) ;
} }
private static SAMv3RawSession newSAMRawSession(String login )
throws IOException, DataFormatException, SAMException, I2PSessionException
{
return new SAMv3RawSession( login ) ;
}
private static SAMv3DatagramSession newSAMDatagramSession(String login )
throws IOException, DataFormatException, SAMException, I2PSessionException
{
return new SAMv3DatagramSession( login ) ;
}
/* Parse and execute a STREAM message */ /* Parse and execute a STREAM message */
@Override @Override
protected boolean execStreamMessage ( String opcode, Properties props ) protected boolean execStreamMessage ( String opcode, Properties props )
@@ -863,7 +851,7 @@ class SAMv3Handler extends SAMv1Handler
} }
} }
/** @since 0.9.22 */ /** @since 0.9.24 */
public static void notifyStreamIncomingConnection(SocketChannel client, Destination d, public static void notifyStreamIncomingConnection(SocketChannel client, Destination d,
int fromPort, int toPort) throws IOException { int fromPort, int toPort) throws IOException {
if (!writeString(d.toBase64() + " FROM_PORT=" + fromPort + " TO_PORT=" + toPort + '\n', client)) { if (!writeString(d.toBase64() + " FROM_PORT=" + fromPort + " TO_PORT=" + toPort + '\n', client)) {
@@ -871,7 +859,7 @@ class SAMv3Handler extends SAMv1Handler
} }
} }
/** @since 0.9.22 */ /** @since 0.9.24 */
private boolean execAuthMessage(String opcode, Properties props) { private boolean execAuthMessage(String opcode, Properties props) {
if (opcode.equals("ENABLE")) { if (opcode.equals("ENABLE")) {
i2cpProps.setProperty(SAMBridge.PROP_AUTH, "true"); i2cpProps.setProperty(SAMBridge.PROP_AUTH, "true");
@@ -910,7 +898,7 @@ class SAMv3Handler extends SAMv1Handler
/** /**
* Handle a PING. * Handle a PING.
* Send a PONG. * Send a PONG.
* @since 0.9.22 * @since 0.9.24
*/ */
private void execPingMessage(StringTokenizer tok) { private void execPingMessage(StringTokenizer tok) {
StringBuilder buf = new StringBuilder(); StringBuilder buf = new StringBuilder();
@@ -924,7 +912,7 @@ class SAMv3Handler extends SAMv1Handler
/** /**
* Handle a PONG. * Handle a PONG.
* @since 0.9.22 * @since 0.9.24
*/ */
private void execPongMessage(StringTokenizer tok) { private void execPongMessage(StringTokenizer tok) {
String s; String s;

View File

@@ -36,14 +36,16 @@ class SAMv3RawSession extends SAMRawSession implements SAMv3Handler.Session, SA
* @throws DataFormatException * @throws DataFormatException
* @throws I2PSessionException * @throws I2PSessionException
*/ */
public SAMv3RawSession(String nick) throws IOException, DataFormatException, I2PSessionException { public SAMv3RawSession(String nick, SAMv3DatagramServer dgServer)
throws IOException, DataFormatException, I2PSessionException {
super(SAMv3Handler.sSessionsHash.get(nick).getDest(), super(SAMv3Handler.sSessionsHash.get(nick).getDest(),
SAMv3Handler.sSessionsHash.get(nick).getProps(), SAMv3Handler.sSessionsHash.get(nick).getProps(),
SAMv3Handler.sSessionsHash.get(nick).getHandler() // to be replaced by this SAMv3Handler.sSessionsHash.get(nick).getHandler() // to be replaced by this
); );
this.nick = nick ; this.nick = nick ;
this.recv = this ; // replacement this.recv = this ; // replacement
this.server = SAMv3DatagramServer.getInstance() ; this.server = dgServer;
SAMv3Handler.SessionRecord rec = SAMv3Handler.sSessionsHash.get(nick); SAMv3Handler.SessionRecord rec = SAMv3Handler.sSessionsHash.get(nick);
if (rec == null) if (rec == null)
throw new InterruptedIOException() ; throw new InterruptedIOException() ;

View File

@@ -19,7 +19,7 @@ import javax.net.ssl.SSLSocket;
* Simple wrapper for a SSLServerSocket. * Simple wrapper for a SSLServerSocket.
* Cannot be used for asynch ops. * Cannot be used for asynch ops.
* *
* @since 0.9.22 * @since 0.9.24
*/ */
class SSLServerSocketChannel extends ServerSocketChannel { class SSLServerSocketChannel extends ServerSocketChannel {

View File

@@ -18,7 +18,7 @@ import javax.net.ssl.SSLSocket;
* Simple wrapper for a SSLSocket. * Simple wrapper for a SSLSocket.
* Cannot be used for asynch ops. * Cannot be used for asynch ops.
* *
* @since 0.9.22 * @since 0.9.24
*/ */
class SSLSocketChannel extends SocketChannel { class SSLSocketChannel extends SocketChannel {

View File

@@ -20,7 +20,7 @@ import net.i2p.util.SecureDirectory;
/** /**
* Utilities for SAM SSL server sockets. * Utilities for SAM SSL server sockets.
* *
* @since 0.9.22 adopted from net.i2p.i2ptunnel.SSLClientUtil * @since 0.9.24 adopted from net.i2p.i2ptunnel.SSLClientUtil
*/ */
class SSLUtil { class SSLUtil {