forked from I2P_Developers/i2p.i2p
Remove singleton SAMv3DatagramServer; hang off of SAMBridge
SAMv3DatagramSession whitespace fixes @since change to 0.9.24
This commit is contained in:
@@ -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 {
|
||||||
|
|
||||||
|
@@ -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);
|
||||||
}
|
}
|
||||||
|
@@ -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) {
|
||||||
|
|
||||||
|
@@ -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;
|
||||||
|
@@ -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,
|
||||||
|
@@ -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;
|
||||||
|
@@ -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() ;
|
||||||
|
@@ -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 {
|
||||||
|
|
||||||
|
@@ -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 {
|
||||||
|
|
||||||
|
@@ -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 {
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user