WIP for the DNS server. Restructured to add "endPointBase" so other
types of endpoints (ie: the DnsServer) can be supported for start/shutdown.
This commit is contained in:
parent
8be291608d
commit
b17dfce221
@ -22,7 +22,7 @@ import org.slf4j.Logger;
|
|||||||
|
|
||||||
import dorkbox.network.connection.BootstrapWrapper;
|
import dorkbox.network.connection.BootstrapWrapper;
|
||||||
import dorkbox.network.connection.Connection;
|
import dorkbox.network.connection.Connection;
|
||||||
import dorkbox.network.connection.EndPoint;
|
import dorkbox.network.connection.EndPointBase;
|
||||||
import dorkbox.network.connection.EndPointClient;
|
import dorkbox.network.connection.EndPointClient;
|
||||||
import dorkbox.network.connection.idle.IdleBridge;
|
import dorkbox.network.connection.idle.IdleBridge;
|
||||||
import dorkbox.network.connection.idle.IdleSender;
|
import dorkbox.network.connection.idle.IdleSender;
|
||||||
@ -333,7 +333,7 @@ class Client<C extends Connection> extends EndPointClient<C> implements Connecti
|
|||||||
@SuppressWarnings("rawtypes")
|
@SuppressWarnings("rawtypes")
|
||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
EndPoint getEndPoint() {
|
EndPointBase getEndPoint() {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -450,7 +450,7 @@ class Client<C extends Connection> extends EndPointClient<C> implements Connecti
|
|||||||
* <p/>
|
* <p/>
|
||||||
* Make <b>sure</b> that you only call this <b>after</b> the client connects!
|
* Make <b>sure</b> that you only call this <b>after</b> the client connects!
|
||||||
* <p/>
|
* <p/>
|
||||||
* This is preferred to {@link EndPoint#getConnections()} getConnections()}, as it properly does some error checking
|
* This is preferred to {@link EndPointBase#getConnections()} getConnections()}, as it properly does some error checking
|
||||||
*/
|
*/
|
||||||
public
|
public
|
||||||
C getConnection() {
|
C getConnection() {
|
||||||
|
@ -17,7 +17,7 @@ package dorkbox.network;
|
|||||||
|
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
|
|
||||||
import dorkbox.network.connection.EndPoint;
|
import dorkbox.network.connection.EndPointBase;
|
||||||
import dorkbox.network.store.SettingsStore;
|
import dorkbox.network.store.SettingsStore;
|
||||||
import dorkbox.network.util.CryptoSerializationManager;
|
import dorkbox.network.util.CryptoSerializationManager;
|
||||||
|
|
||||||
@ -76,7 +76,7 @@ class Configuration {
|
|||||||
public static
|
public static
|
||||||
Configuration localOnly() {
|
Configuration localOnly() {
|
||||||
Configuration configuration = new Configuration();
|
Configuration configuration = new Configuration();
|
||||||
configuration.localChannelName = EndPoint.LOCAL_CHANNEL;
|
configuration.localChannelName = EndPointBase.LOCAL_CHANNEL;
|
||||||
|
|
||||||
return configuration;
|
return configuration;
|
||||||
}
|
}
|
||||||
|
@ -22,16 +22,13 @@ import static io.netty.util.internal.ObjectUtil.intValue;
|
|||||||
import java.net.IDN;
|
import java.net.IDN;
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.security.AccessControlException;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
|
|
||||||
@ -88,30 +85,7 @@ import io.netty.util.internal.PlatformDependent;
|
|||||||
*/
|
*/
|
||||||
@SuppressWarnings({"unused", "WeakerAccess"})
|
@SuppressWarnings({"unused", "WeakerAccess"})
|
||||||
public
|
public
|
||||||
class DnsClient {
|
class DnsClient extends EndPoint {
|
||||||
|
|
||||||
// duplicated in EndPoint
|
|
||||||
static {
|
|
||||||
//noinspection Duplicates
|
|
||||||
try {
|
|
||||||
if (PlatformDependent.isAndroid()) {
|
|
||||||
// doesn't work when running from inside eclipse.
|
|
||||||
// Needed for NIO selectors on Android 2.2, and to force IPv4.
|
|
||||||
System.setProperty("java.net.preferIPv4Stack", Boolean.TRUE.toString());
|
|
||||||
System.setProperty("java.net.preferIPv6Addresses", Boolean.FALSE.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
// java6 has stack overflow problems when loading certain classes in it's classloader. The result is a StackOverflow when
|
|
||||||
// loading them normally. This calls AND FIXES this issue.
|
|
||||||
if (OS.javaVersion == 6) {
|
|
||||||
if (PlatformDependent.hasUnsafe()) {
|
|
||||||
//noinspection ResultOfMethodCallIgnored
|
|
||||||
PlatformDependent.newFixedMpscQueue(8);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (AccessControlException ignored) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is a list of all of the public DNS servers to query, when submitting DNS queries
|
* This is a list of all of the public DNS servers to query, when submitting DNS queries
|
||||||
@ -241,13 +215,7 @@ class DnsClient {
|
|||||||
*/
|
*/
|
||||||
public
|
public
|
||||||
DnsClient(Collection<InetSocketAddress> nameServerAddresses) {
|
DnsClient(Collection<InetSocketAddress> nameServerAddresses) {
|
||||||
// setup the thread group to easily ID what the following threads belong to (and their spawned threads...)
|
super(DnsClient.class);
|
||||||
SecurityManager s = System.getSecurityManager();
|
|
||||||
threadGroup = new ThreadGroup(s != null
|
|
||||||
? s.getThreadGroup()
|
|
||||||
: Thread.currentThread()
|
|
||||||
.getThreadGroup(), THREAD_NAME);
|
|
||||||
threadGroup.setDaemon(true);
|
|
||||||
|
|
||||||
if (PlatformDependent.isAndroid()) {
|
if (PlatformDependent.isAndroid()) {
|
||||||
// android ONLY supports OIO (not NIO)
|
// android ONLY supports OIO (not NIO)
|
||||||
@ -264,6 +232,8 @@ class DnsClient {
|
|||||||
channelType = NioDatagramChannel.class;
|
channelType = NioDatagramChannel.class;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
manageForShutdown(eventLoopGroup);
|
||||||
|
|
||||||
// NOTE: A/AAAA use the built-in decoder
|
// NOTE: A/AAAA use the built-in decoder
|
||||||
|
|
||||||
customDecoders.put(DnsRecordType.MX, new MailExchangerDecoder());
|
customDecoders.put(DnsRecordType.MX, new MailExchangerDecoder());
|
||||||
@ -601,6 +571,35 @@ class DnsClient {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears the DNS resolver cache
|
||||||
|
*/
|
||||||
|
public
|
||||||
|
void reset() {
|
||||||
|
if (resolver == null) {
|
||||||
|
start();
|
||||||
|
}
|
||||||
|
|
||||||
|
clearResolver();
|
||||||
|
}
|
||||||
|
|
||||||
|
private
|
||||||
|
void clearResolver() {
|
||||||
|
resolver.resolveCache()
|
||||||
|
.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected
|
||||||
|
void stopExtraActions() {
|
||||||
|
clearResolver();
|
||||||
|
|
||||||
|
if (resolver != null) {
|
||||||
|
resolver.close(); // also closes the UDP channel that DNS client uses
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resolves a specific hostname A record
|
* Resolves a specific hostname A record
|
||||||
*
|
*
|
||||||
@ -720,78 +719,6 @@ class DnsClient {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clears the DNS resolver cache
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
void reset() {
|
|
||||||
if (resolver == null) {
|
|
||||||
start();
|
|
||||||
}
|
|
||||||
|
|
||||||
clearResolver();
|
|
||||||
}
|
|
||||||
|
|
||||||
private
|
|
||||||
void clearResolver() {
|
|
||||||
resolver.resolveCache()
|
|
||||||
.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Safely closes all associated resources/threads/connections
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
void stop() {
|
|
||||||
// we also want to stop the thread group (but NOT in our current thread!)
|
|
||||||
if (Thread.currentThread()
|
|
||||||
.getThreadGroup()
|
|
||||||
.getName()
|
|
||||||
.equals(THREAD_NAME)) {
|
|
||||||
|
|
||||||
Thread thread = new Thread(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public
|
|
||||||
void run() {
|
|
||||||
DnsClient.this.stopInThread();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
thread.setDaemon(false);
|
|
||||||
thread.setName("DnsClient Shutdown");
|
|
||||||
thread.start();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
stopInThread();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private
|
|
||||||
void stopInThread() {
|
|
||||||
clearResolver();
|
|
||||||
|
|
||||||
if (resolver != null) {
|
|
||||||
resolver.close(); // also closes the UDP channel that DNS client uses
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sometimes there might be "lingering" connections (ie, halfway though registration) that need to be closed.
|
|
||||||
long maxShutdownWaitTimeInMilliSeconds = EndPoint.maxShutdownWaitTimeInMilliSeconds;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// we want to WAIT until after the event executors have completed shutting down.
|
|
||||||
List<Future<?>> shutdownThreadList = new LinkedList<Future<?>>();
|
|
||||||
|
|
||||||
// now wait it them to finish!
|
|
||||||
// It can take a few seconds to shut down the executor. This will affect unit testing, where connections are quickly created/stopped
|
|
||||||
eventLoopGroup.shutdownGracefully(maxShutdownWaitTimeInMilliSeconds, maxShutdownWaitTimeInMilliSeconds * 4, TimeUnit.MILLISECONDS)
|
|
||||||
.syncUninterruptibly();
|
|
||||||
|
|
||||||
threadGroup.interrupt();
|
|
||||||
}
|
|
||||||
|
|
||||||
public
|
public
|
||||||
ServiceRecord resolveSRV(final String hostname) {
|
ServiceRecord resolveSRV(final String hostname) {
|
||||||
return resolve(hostname, DnsRecordType.SRV);
|
return resolve(hostname, DnsRecordType.SRV);
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
package dorkbox.network;
|
package dorkbox.network;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
|
|
||||||
@ -83,6 +84,8 @@ class Server<C extends Connection> extends EndPointServer<C> {
|
|||||||
private final String localChannelName;
|
private final String localChannelName;
|
||||||
private final String hostName;
|
private final String hostName;
|
||||||
|
|
||||||
|
private final CountDownLatch blockUntilDone = new CountDownLatch(1);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Starts a LOCAL <b>only</b> server, with the default serialization scheme.
|
* Starts a LOCAL <b>only</b> server, with the default serialization scheme.
|
||||||
*/
|
*/
|
||||||
|
@ -47,7 +47,7 @@ interface Connection {
|
|||||||
* @return the endpoint associated with this connection
|
* @return the endpoint associated with this connection
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("rawtypes")
|
@SuppressWarnings("rawtypes")
|
||||||
EndPoint getEndPoint();
|
EndPointBase getEndPoint();
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -93,7 +93,7 @@ class ConnectionImpl extends ChannelInboundHandlerAdapter implements ICryptoConn
|
|||||||
// while on the CLIENT, if the SERVER's ecc key has changed, the client will abort and show an error.
|
// while on the CLIENT, if the SERVER's ecc key has changed, the client will abort and show an error.
|
||||||
private boolean remoteKeyChanged;
|
private boolean remoteKeyChanged;
|
||||||
|
|
||||||
private final EndPoint<Connection> endPoint;
|
private final EndPointBase<Connection> endPointBaseConnection;
|
||||||
|
|
||||||
// when true, the connection will be closed (either as RMI or as 'normal' listener execution) when the thread execution returns control
|
// when true, the connection will be closed (either as RMI or as 'normal' listener execution) when the thread execution returns control
|
||||||
// back to the network stack
|
// back to the network stack
|
||||||
@ -117,9 +117,9 @@ class ConnectionImpl extends ChannelInboundHandlerAdapter implements ICryptoConn
|
|||||||
*/
|
*/
|
||||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||||
public
|
public
|
||||||
ConnectionImpl(final Logger logger, final EndPoint endPoint, final RmiBridge rmiBridge) {
|
ConnectionImpl(final Logger logger, final EndPointBase endPointBaseConnection, final RmiBridge rmiBridge) {
|
||||||
this.logger = logger;
|
this.logger = logger;
|
||||||
this.endPoint = endPoint;
|
this.endPointBaseConnection = endPointBaseConnection;
|
||||||
this.rmiBridge = rmiBridge;
|
this.rmiBridge = rmiBridge;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -214,8 +214,8 @@ class ConnectionImpl extends ChannelInboundHandlerAdapter implements ICryptoConn
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
EndPoint<Connection> getEndPoint() {
|
EndPointBase<Connection> getEndPoint() {
|
||||||
return this.endPoint;
|
return this.endPointBaseConnection;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -614,7 +614,7 @@ class ConnectionImpl extends ChannelInboundHandlerAdapter implements ICryptoConn
|
|||||||
void close() {
|
void close() {
|
||||||
// only close if we aren't already in the middle of closing.
|
// only close if we aren't already in the middle of closing.
|
||||||
if (this.closeInProgress.compareAndSet(false, true)) {
|
if (this.closeInProgress.compareAndSet(false, true)) {
|
||||||
int idleTimeoutMs = this.endPoint.getIdleTimeout();
|
int idleTimeoutMs = this.endPointBaseConnection.getIdleTimeout();
|
||||||
if (idleTimeoutMs == 0) {
|
if (idleTimeoutMs == 0) {
|
||||||
// default is 2 second timeout, in milliseconds.
|
// default is 2 second timeout, in milliseconds.
|
||||||
idleTimeoutMs = 2000;
|
idleTimeoutMs = 2000;
|
||||||
@ -714,7 +714,7 @@ class ConnectionImpl extends ChannelInboundHandlerAdapter implements ICryptoConn
|
|||||||
@Override
|
@Override
|
||||||
public final
|
public final
|
||||||
Listeners add(Listener listener) {
|
Listeners add(Listener listener) {
|
||||||
if (this.endPoint instanceof EndPointServer) {
|
if (this.endPointBaseConnection instanceof EndPointServer) {
|
||||||
// when we are a server, NORMALLY listeners are added at the GLOBAL level
|
// when we are a server, NORMALLY listeners are added at the GLOBAL level
|
||||||
// meaning --
|
// meaning --
|
||||||
// I add one listener, and ALL connections are notified of that listener.
|
// I add one listener, and ALL connections are notified of that listener.
|
||||||
@ -726,14 +726,14 @@ class ConnectionImpl extends ChannelInboundHandlerAdapter implements ICryptoConn
|
|||||||
// is empty, we can remove it from this connection.
|
// is empty, we can remove it from this connection.
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
if (this.localListenerManager == null) {
|
if (this.localListenerManager == null) {
|
||||||
this.localListenerManager = ((EndPointServer<Connection>) this.endPoint).addListenerManager(this);
|
this.localListenerManager = ((EndPointServer<Connection>) this.endPointBaseConnection).addListenerManager(this);
|
||||||
}
|
}
|
||||||
this.localListenerManager.add(listener);
|
this.localListenerManager.add(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
this.endPoint.listeners()
|
this.endPointBaseConnection.listeners()
|
||||||
.add(listener);
|
.add(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -756,7 +756,7 @@ class ConnectionImpl extends ChannelInboundHandlerAdapter implements ICryptoConn
|
|||||||
@Override
|
@Override
|
||||||
public final
|
public final
|
||||||
Listeners remove(Listener listener) {
|
Listeners remove(Listener listener) {
|
||||||
if (this.endPoint instanceof EndPointServer) {
|
if (this.endPointBaseConnection instanceof EndPointServer) {
|
||||||
// when we are a server, NORMALLY listeners are added at the GLOBAL level
|
// when we are a server, NORMALLY listeners are added at the GLOBAL level
|
||||||
// meaning --
|
// meaning --
|
||||||
// I add one listener, and ALL connections are notified of that listener.
|
// I add one listener, and ALL connections are notified of that listener.
|
||||||
@ -771,13 +771,13 @@ class ConnectionImpl extends ChannelInboundHandlerAdapter implements ICryptoConn
|
|||||||
this.localListenerManager.remove(listener);
|
this.localListenerManager.remove(listener);
|
||||||
|
|
||||||
if (!this.localListenerManager.hasListeners()) {
|
if (!this.localListenerManager.hasListeners()) {
|
||||||
((EndPointServer<Connection>) this.endPoint).removeListenerManager(this);
|
((EndPointServer<Connection>) this.endPointBaseConnection).removeListenerManager(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
this.endPoint.listeners()
|
this.endPointBaseConnection.listeners()
|
||||||
.remove(listener);
|
.remove(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -791,7 +791,7 @@ class ConnectionImpl extends ChannelInboundHandlerAdapter implements ICryptoConn
|
|||||||
@Override
|
@Override
|
||||||
public final
|
public final
|
||||||
Listeners removeAll() {
|
Listeners removeAll() {
|
||||||
if (this.endPoint instanceof EndPointServer) {
|
if (this.endPointBaseConnection instanceof EndPointServer) {
|
||||||
// when we are a server, NORMALLY listeners are added at the GLOBAL level
|
// when we are a server, NORMALLY listeners are added at the GLOBAL level
|
||||||
// meaning --
|
// meaning --
|
||||||
// I add one listener, and ALL connections are notified of that listener.
|
// I add one listener, and ALL connections are notified of that listener.
|
||||||
@ -806,12 +806,12 @@ class ConnectionImpl extends ChannelInboundHandlerAdapter implements ICryptoConn
|
|||||||
this.localListenerManager.removeAll();
|
this.localListenerManager.removeAll();
|
||||||
this.localListenerManager = null;
|
this.localListenerManager = null;
|
||||||
|
|
||||||
((EndPointServer<Connection>) this.endPoint).removeListenerManager(this);
|
((EndPointServer<Connection>) this.endPointBaseConnection).removeListenerManager(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
this.endPoint.listeners()
|
this.endPointBaseConnection.listeners()
|
||||||
.removeAll();
|
.removeAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -826,7 +826,7 @@ class ConnectionImpl extends ChannelInboundHandlerAdapter implements ICryptoConn
|
|||||||
@Override
|
@Override
|
||||||
public final
|
public final
|
||||||
Listeners removeAll(Class<?> classType) {
|
Listeners removeAll(Class<?> classType) {
|
||||||
if (this.endPoint instanceof EndPointServer) {
|
if (this.endPointBaseConnection instanceof EndPointServer) {
|
||||||
// when we are a server, NORMALLY listeners are added at the GLOBAL level
|
// when we are a server, NORMALLY listeners are added at the GLOBAL level
|
||||||
// meaning --
|
// meaning --
|
||||||
// I add one listener, and ALL connections are notified of that listener.
|
// I add one listener, and ALL connections are notified of that listener.
|
||||||
@ -842,13 +842,13 @@ class ConnectionImpl extends ChannelInboundHandlerAdapter implements ICryptoConn
|
|||||||
|
|
||||||
if (!this.localListenerManager.hasListeners()) {
|
if (!this.localListenerManager.hasListeners()) {
|
||||||
this.localListenerManager = null;
|
this.localListenerManager = null;
|
||||||
((EndPointServer<Connection>) this.endPoint).removeListenerManager(this);
|
((EndPointServer<Connection>) this.endPointBaseConnection).removeListenerManager(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
this.endPoint.listeners()
|
this.endPointBaseConnection.listeners()
|
||||||
.removeAll(classType);
|
.removeAll(classType);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1111,7 +1111,7 @@ class ConnectionImpl extends ChannelInboundHandlerAdapter implements ICryptoConn
|
|||||||
public
|
public
|
||||||
<T> int getRegisteredId(final T object) {
|
<T> int getRegisteredId(final T object) {
|
||||||
// always check local before checking global, because less contention on the synchronization
|
// always check local before checking global, because less contention on the synchronization
|
||||||
RmiBridge globalRmiBridge = endPoint.globalRmiBridge;
|
RmiBridge globalRmiBridge = endPointBaseConnection.globalRmiBridge;
|
||||||
|
|
||||||
if (globalRmiBridge == null) {
|
if (globalRmiBridge == null) {
|
||||||
throw new NullPointerException("Unable to call 'getRegisteredId' when the globalRmiBridge is null!");
|
throw new NullPointerException("Unable to call 'getRegisteredId' when the globalRmiBridge is null!");
|
||||||
@ -1155,7 +1155,7 @@ class ConnectionImpl extends ChannelInboundHandlerAdapter implements ICryptoConn
|
|||||||
public
|
public
|
||||||
Object getImplementationObject(final int objectID) {
|
Object getImplementationObject(final int objectID) {
|
||||||
if (RmiBridge.isGlobal(objectID)) {
|
if (RmiBridge.isGlobal(objectID)) {
|
||||||
RmiBridge globalRmiBridge = endPoint.globalRmiBridge;
|
RmiBridge globalRmiBridge = endPointBaseConnection.globalRmiBridge;
|
||||||
|
|
||||||
if (globalRmiBridge == null) {
|
if (globalRmiBridge == null) {
|
||||||
throw new NullPointerException("Unable to call 'getRegisteredId' when the gloablRmiBridge is null!");
|
throw new NullPointerException("Unable to call 'getRegisteredId' when the gloablRmiBridge is null!");
|
||||||
|
@ -294,7 +294,7 @@ class ConnectionManager<C extends Connection> implements Listeners, ISessionMana
|
|||||||
* Invoked when a message object was received from a remote peer.
|
* Invoked when a message object was received from a remote peer.
|
||||||
* <p/>
|
* <p/>
|
||||||
* If data is sent in response to this event, the connection data is automatically flushed to the wire. If the data is sent in a separate thread,
|
* If data is sent in response to this event, the connection data is automatically flushed to the wire. If the data is sent in a separate thread,
|
||||||
* {@link EndPoint#send().flush()} must be called manually.
|
* {@link EndPointBase#send().flush()} must be called manually.
|
||||||
* <p/>
|
* <p/>
|
||||||
* {@link ISessionManager}
|
* {@link ISessionManager}
|
||||||
*/
|
*/
|
||||||
|
@ -1,132 +1,30 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010 dorkbox, llc
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package dorkbox.network.connection;
|
package dorkbox.network.connection;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.security.AccessControlException;
|
import java.security.AccessControlException;
|
||||||
import java.security.SecureRandom;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.CountDownLatch;
|
||||||
import java.util.concurrent.Executor;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
|
|
||||||
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
|
|
||||||
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
|
|
||||||
import dorkbox.network.Configuration;
|
|
||||||
import dorkbox.network.connection.bridge.ConnectionBridgeBase;
|
|
||||||
import dorkbox.network.connection.ping.PingSystemListener;
|
|
||||||
import dorkbox.network.connection.registration.MetaChannel;
|
|
||||||
import dorkbox.network.connection.wrapper.ChannelLocalWrapper;
|
|
||||||
import dorkbox.network.connection.wrapper.ChannelNetworkWrapper;
|
|
||||||
import dorkbox.network.connection.wrapper.ChannelWrapper;
|
|
||||||
import dorkbox.network.pipeline.KryoEncoder;
|
|
||||||
import dorkbox.network.pipeline.KryoEncoderCrypto;
|
|
||||||
import dorkbox.network.rmi.RmiBridge;
|
|
||||||
import dorkbox.network.store.NullSettingsStore;
|
|
||||||
import dorkbox.network.store.SettingsStore;
|
|
||||||
import dorkbox.util.OS;
|
import dorkbox.util.OS;
|
||||||
import dorkbox.util.Property;
|
import dorkbox.util.Property;
|
||||||
import dorkbox.util.crypto.CryptoECC;
|
|
||||||
import dorkbox.util.entropy.Entropy;
|
|
||||||
import dorkbox.util.exceptions.InitializationException;
|
|
||||||
import dorkbox.util.exceptions.SecurityException;
|
|
||||||
import io.netty.channel.Channel;
|
import io.netty.channel.Channel;
|
||||||
import io.netty.channel.ChannelFuture;
|
import io.netty.channel.ChannelFuture;
|
||||||
import io.netty.channel.EventLoopGroup;
|
import io.netty.channel.EventLoopGroup;
|
||||||
import io.netty.util.NetUtil;
|
|
||||||
import io.netty.util.concurrent.EventExecutor;
|
import io.netty.util.concurrent.EventExecutor;
|
||||||
import io.netty.util.concurrent.Future;
|
import io.netty.util.concurrent.Future;
|
||||||
import io.netty.util.internal.PlatformDependent;
|
import io.netty.util.internal.PlatformDependent;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* represents the base of a client/server end point
|
* This is the highest level endpoint, for lifecycle support/management.
|
||||||
*/
|
*/
|
||||||
public abstract
|
public
|
||||||
class EndPoint<C extends Connection> {
|
class EndPoint {
|
||||||
// If TCP and UDP both fill the pipe, THERE WILL BE FRAGMENTATION and dropped UDP packets!
|
|
||||||
// it results in severe UDP packet loss and contention.
|
|
||||||
//
|
|
||||||
// http://www.isoc.org/INET97/proceedings/F3/F3_1.HTM
|
|
||||||
// also, a google search on just "INET97/proceedings/F3/F3_1.HTM" turns up interesting problems.
|
|
||||||
// Usually it's with ISPs.
|
|
||||||
|
|
||||||
// TODO: will also want an UDP keepalive? (TCP is already there b/c of socket options, but might need a heartbeat to detect dead connections?)
|
|
||||||
// routers sometimes need a heartbeat to keep the connection
|
|
||||||
// TODO: maybe some sort of STUN-like connection keep-alive??
|
|
||||||
|
|
||||||
|
|
||||||
public static final String LOCAL_CHANNEL = "local_channel";
|
|
||||||
protected static final String shutdownHookName = "::SHUTDOWN_HOOK::";
|
|
||||||
protected static final String stopTreadName = "::STOP_THREAD::";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The HIGH and LOW watermark points for connections
|
|
||||||
*/
|
|
||||||
@Property
|
|
||||||
public static final int WRITE_BUFF_HIGH = 32 * 1024;
|
|
||||||
@Property
|
|
||||||
public static final int WRITE_BUFF_LOW = 8 * 1024;
|
|
||||||
|
|
||||||
public static final String THREADGROUP_NAME = "(Netty)";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* this can be changed to a more specialized value, if necessary
|
|
||||||
*/
|
|
||||||
@Property
|
|
||||||
public static int DEFAULT_THREAD_POOL_SIZE = Runtime.getRuntime()
|
|
||||||
.availableProcessors() * 2;
|
|
||||||
/**
|
|
||||||
* The amount of time in milli-seconds to wait for this endpoint to close all {@link Channel}s and shutdown gracefully.
|
|
||||||
*/
|
|
||||||
@Property
|
|
||||||
public static long maxShutdownWaitTimeInMilliSeconds = 2000L; // in milliseconds
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The default size for UDP packets is 768 bytes.
|
|
||||||
* <p/>
|
|
||||||
* You could increase or decrease this value to avoid truncated packets
|
|
||||||
* or to improve memory footprint respectively.
|
|
||||||
* <p/>
|
|
||||||
* Please also note that a large UDP packet might be truncated or
|
|
||||||
* dropped by your router no matter how you configured this option.
|
|
||||||
* In UDP, a packet is truncated or dropped if it is larger than a
|
|
||||||
* certain size, depending on router configuration. IPv4 routers
|
|
||||||
* truncate and IPv6 routers drop a large packet. That's why it is
|
|
||||||
* safe to send small packets in UDP.
|
|
||||||
* <p/>
|
|
||||||
* To fit into that magic 576-byte MTU and avoid fragmentation, your
|
|
||||||
* UDP payload should be restricted by 576-60-8=508 bytes.
|
|
||||||
*
|
|
||||||
* This can be set higher on an internal lan!
|
|
||||||
*
|
|
||||||
* DON'T go higher that 1400 over the internet, but 9k is possible
|
|
||||||
* with jumbo frames on a local network (if it's supported)
|
|
||||||
*/
|
|
||||||
@Property
|
|
||||||
public static int udpMaxSize = 508;
|
|
||||||
|
|
||||||
|
|
||||||
// duplicated in DnsClient
|
// duplicated in DnsClient
|
||||||
static {
|
static {
|
||||||
//noinspection Duplicates
|
//noinspection Duplicates
|
||||||
@ -137,9 +35,10 @@ class EndPoint<C extends Connection> {
|
|||||||
System.setProperty("java.net.preferIPv6Addresses", Boolean.FALSE.toString());
|
System.setProperty("java.net.preferIPv6Addresses", Boolean.FALSE.toString());
|
||||||
|
|
||||||
// java6 has stack overflow problems when loading certain classes in it's classloader. The result is a StackOverflow when
|
// java6 has stack overflow problems when loading certain classes in it's classloader. The result is a StackOverflow when
|
||||||
// loading them normally
|
// loading them normally. This calls AND FIXES this issue.
|
||||||
if (OS.javaVersion == 6) {
|
if (OS.javaVersion == 6) {
|
||||||
if (PlatformDependent.hasUnsafe()) {
|
if (PlatformDependent.hasUnsafe()) {
|
||||||
|
//noinspection ResultOfMethodCallIgnored
|
||||||
PlatformDependent.newFixedMpscQueue(8);
|
PlatformDependent.newFixedMpscQueue(8);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -148,26 +47,40 @@ class EndPoint<C extends Connection> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected static final String shutdownHookName = "::SHUTDOWN_HOOK::";
|
||||||
|
protected static final String stopTreadName = "::STOP_THREAD::";
|
||||||
|
|
||||||
|
public static final String THREADGROUP_NAME = "(Netty)";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The HIGH and LOW watermark points for connections
|
||||||
|
*/
|
||||||
|
@Property
|
||||||
|
public static final int WRITE_BUFF_HIGH = 32 * 1024;
|
||||||
|
@Property
|
||||||
|
public static final int WRITE_BUFF_LOW = 8 * 1024;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* this can be changed to a more specialized value, if necessary
|
||||||
|
*/
|
||||||
|
@Property
|
||||||
|
public static int DEFAULT_THREAD_POOL_SIZE = Runtime.getRuntime()
|
||||||
|
.availableProcessors() * 2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The amount of time in milli-seconds to wait for this endpoint to close all {@link Channel}s and shutdown gracefully.
|
||||||
|
*/
|
||||||
|
@Property
|
||||||
|
public static long maxShutdownWaitTimeInMilliSeconds = 2000L; // in milliseconds
|
||||||
|
|
||||||
|
|
||||||
protected final org.slf4j.Logger logger;
|
protected final org.slf4j.Logger logger;
|
||||||
|
|
||||||
protected final ThreadGroup threadGroup;
|
protected final ThreadGroup threadGroup;
|
||||||
protected final Class<? extends EndPoint<C>> type;
|
|
||||||
|
|
||||||
protected final ConnectionManager<C> connectionManager;
|
protected final Class<? extends EndPoint> type;
|
||||||
protected final dorkbox.network.util.CryptoSerializationManager serializationManager;
|
|
||||||
protected final RegistrationWrapper<C> registrationWrapper;
|
|
||||||
|
|
||||||
protected final Object shutdownInProgress = new Object();
|
protected final Object shutdownInProgress = new Object();
|
||||||
final ECPrivateKeyParameters privateKey;
|
|
||||||
final ECPublicKeyParameters publicKey;
|
|
||||||
|
|
||||||
final SecureRandom secureRandom;
|
|
||||||
final RmiBridge globalRmiBridge;
|
|
||||||
|
|
||||||
private final CountDownLatch blockUntilDone = new CountDownLatch(1);
|
|
||||||
|
|
||||||
private final Executor rmiExecutor;
|
|
||||||
private final boolean rmiEnabled;
|
|
||||||
|
|
||||||
// the eventLoop groups are used to track and manage the event loops for startup/shutdown
|
// the eventLoop groups are used to track and manage the event loops for startup/shutdown
|
||||||
private final List<EventLoopGroup> eventLoopGroups = new ArrayList<EventLoopGroup>(8);
|
private final List<EventLoopGroup> eventLoopGroups = new ArrayList<EventLoopGroup>(8);
|
||||||
@ -176,28 +89,13 @@ class EndPoint<C extends Connection> {
|
|||||||
// make sure that the endpoint is closed on JVM shutdown (if it's still open at that point in time)
|
// make sure that the endpoint is closed on JVM shutdown (if it's still open at that point in time)
|
||||||
private Thread shutdownHook;
|
private Thread shutdownHook;
|
||||||
|
|
||||||
|
private final CountDownLatch blockUntilDone = new CountDownLatch(1);
|
||||||
|
|
||||||
private AtomicBoolean stopCalled = new AtomicBoolean(false);
|
private AtomicBoolean stopCalled = new AtomicBoolean(false);
|
||||||
private AtomicBoolean isConnected = new AtomicBoolean(false);
|
|
||||||
|
|
||||||
SettingsStore propertyStore;
|
|
||||||
boolean disableRemoteKeyValidation;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* in milliseconds. default is disabled!
|
|
||||||
*/
|
|
||||||
private volatile int idleTimeoutMs = 0;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param type this is either "Client" or "Server", depending on who is creating this endpoint.
|
|
||||||
* @param options these are the specific connection options
|
|
||||||
* @throws InitializationException
|
|
||||||
* @throws SecurityException
|
|
||||||
*/
|
|
||||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
|
||||||
public
|
public
|
||||||
EndPoint(Class<? extends EndPoint> type, final Configuration options) throws InitializationException, SecurityException, IOException {
|
EndPoint(final Class<? extends EndPoint> type) {
|
||||||
this.type = (Class<? extends EndPoint<C>>) type;
|
this.type = type;
|
||||||
|
|
||||||
// setup the thread group to easily ID what the following threads belong to (and their spawned threads...)
|
// setup the thread group to easily ID what the following threads belong to (and their spawned threads...)
|
||||||
SecurityManager s = System.getSecurityManager();
|
SecurityManager s = System.getSecurityManager();
|
||||||
@ -209,95 +107,12 @@ class EndPoint<C extends Connection> {
|
|||||||
|
|
||||||
this.logger = org.slf4j.LoggerFactory.getLogger(type.getSimpleName());
|
this.logger = org.slf4j.LoggerFactory.getLogger(type.getSimpleName());
|
||||||
|
|
||||||
// make sure that 'localhost' is ALWAYS our specific loopback IP address
|
|
||||||
if (options.host != null && (options.host.equals("localhost") || options.host.startsWith("127."))) {
|
|
||||||
// localhost IP might not always be 127.0.0.1
|
|
||||||
options.host = NetUtil.LOCALHOST.getHostAddress();
|
|
||||||
}
|
|
||||||
|
|
||||||
// serialization stuff
|
|
||||||
if (options.serialization != null) {
|
|
||||||
this.serializationManager = options.serialization;
|
|
||||||
} else {
|
|
||||||
this.serializationManager = CryptoSerializationManager.DEFAULT();
|
|
||||||
}
|
|
||||||
|
|
||||||
// setup our RMI serialization managers. Can only be called once
|
|
||||||
rmiEnabled = serializationManager.initRmiSerialization();
|
|
||||||
rmiExecutor = options.rmiExecutor;
|
|
||||||
|
|
||||||
|
|
||||||
// The registration wrapper permits the registration process to access protected/package fields/methods, that we don't want
|
|
||||||
// to expose to external code. "this" escaping can be ignored, because it is benign.
|
|
||||||
//noinspection ThisEscapedInObjectConstruction
|
|
||||||
this.registrationWrapper = new RegistrationWrapper(this,
|
|
||||||
this.logger,
|
|
||||||
new KryoEncoder(this.serializationManager),
|
|
||||||
new KryoEncoderCrypto(this.serializationManager));
|
|
||||||
|
|
||||||
|
|
||||||
// we have to be able to specify WHAT property store we want to use, since it can change!
|
|
||||||
if (options.settingsStore == null) {
|
|
||||||
this.propertyStore = new PropertyStore();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
this.propertyStore = options.settingsStore;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.propertyStore.init(this.serializationManager, null);
|
|
||||||
|
|
||||||
// null it out, since it is sensitive!
|
|
||||||
options.settingsStore = null;
|
|
||||||
|
|
||||||
|
|
||||||
if (!(this.propertyStore instanceof NullSettingsStore)) {
|
|
||||||
// initialize the private/public keys used for negotiating ECC handshakes
|
|
||||||
// these are ONLY used for IP connections. LOCAL connections do not need a handshake!
|
|
||||||
ECPrivateKeyParameters privateKey = this.propertyStore.getPrivateKey();
|
|
||||||
ECPublicKeyParameters publicKey = this.propertyStore.getPublicKey();
|
|
||||||
|
|
||||||
if (privateKey == null || publicKey == null) {
|
|
||||||
try {
|
|
||||||
// seed our RNG based off of this and create our ECC keys
|
|
||||||
byte[] seedBytes = Entropy.get("There are no ECC keys for the " + type.getSimpleName() + " yet");
|
|
||||||
SecureRandom secureRandom = new SecureRandom(seedBytes);
|
|
||||||
secureRandom.nextBytes(seedBytes);
|
|
||||||
|
|
||||||
this.logger.debug("Now generating ECC (" + CryptoECC.curve25519 + ") keys. Please wait!");
|
|
||||||
AsymmetricCipherKeyPair generateKeyPair = CryptoECC.generateKeyPair(CryptoECC.curve25519, secureRandom);
|
|
||||||
|
|
||||||
privateKey = (ECPrivateKeyParameters) generateKeyPair.getPrivate();
|
|
||||||
publicKey = (ECPublicKeyParameters) generateKeyPair.getPublic();
|
|
||||||
|
|
||||||
// save to properties file
|
|
||||||
this.propertyStore.savePrivateKey(privateKey);
|
|
||||||
this.propertyStore.savePublicKey(publicKey);
|
|
||||||
|
|
||||||
this.logger.debug("Done with ECC keys!");
|
|
||||||
} catch (Exception e) {
|
|
||||||
String message = "Unable to initialize/generate ECC keys. FORCED SHUTDOWN.";
|
|
||||||
this.logger.error(message);
|
|
||||||
throw new InitializationException(message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.privateKey = privateKey;
|
|
||||||
this.publicKey = publicKey;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
this.privateKey = null;
|
|
||||||
this.publicKey = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
this.secureRandom = new SecureRandom(this.propertyStore.getSalt());
|
|
||||||
|
|
||||||
this.shutdownHook = new Thread() {
|
this.shutdownHook = new Thread() {
|
||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
void run() {
|
void run() {
|
||||||
// connectionManager.shutdown accurately reflects the state of the app. Safe to use here
|
if (EndPoint.this.shouldShutdownHookRun()) {
|
||||||
if (EndPoint.this.connectionManager != null && !EndPoint.this.connectionManager.shutdown.get()) {
|
|
||||||
EndPoint.this.stop();
|
EndPoint.this.stop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -309,89 +124,6 @@ class EndPoint<C extends Connection> {
|
|||||||
} catch (Throwable ignored) {
|
} catch (Throwable ignored) {
|
||||||
// if we are in the middle of shutdown, we cannot do this.
|
// if we are in the middle of shutdown, we cannot do this.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// we don't care about un-instantiated/constructed members, since the class type is the only interest.
|
|
||||||
this.connectionManager = new ConnectionManager<C>(type.getSimpleName(), connection0(null).getClass());
|
|
||||||
|
|
||||||
// add the ping listener (internal use only!)
|
|
||||||
this.connectionManager.add(new PingSystemListener());
|
|
||||||
|
|
||||||
if (this.rmiEnabled) {
|
|
||||||
// these register the listener for registering a class implementation for RMI (internal use only)
|
|
||||||
this.connectionManager.add(new RegisterRmiSystemListener());
|
|
||||||
this.globalRmiBridge = new RmiBridge(logger, options.rmiExecutor, true);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
this.globalRmiBridge = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
serializationManager.finishInit();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Disables remote endpoint public key validation when the connection is established. This is not recommended as it is a security risk
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
void disableRemoteKeyValidation() {
|
|
||||||
Logger logger2 = this.logger;
|
|
||||||
|
|
||||||
if (isConnected()) {
|
|
||||||
logger2.error("Cannot disable the remote key validation after this endpoint is connected!");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
logger2.info("WARNING: Disabling remote key validation is a security risk!!");
|
|
||||||
this.disableRemoteKeyValidation = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the property store used by this endpoint. The property store can store via properties,
|
|
||||||
* a database, etc, or can be a "null" property store, which does nothing
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public
|
|
||||||
<S extends SettingsStore> S getPropertyStore() {
|
|
||||||
return (S) this.propertyStore;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Internal call by the pipeline to notify the client to continue registering the different session protocols.
|
|
||||||
* The server does not use this.
|
|
||||||
*/
|
|
||||||
protected
|
|
||||||
boolean registerNextProtocol0() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The amount of milli-seconds that must elapse with no read or write before {@link Listener.OnIdle#idle(Connection)} }
|
|
||||||
* will be triggered
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
int getIdleTimeout() {
|
|
||||||
return this.idleTimeoutMs;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The {@link Listener:idle()} will be triggered when neither read nor write
|
|
||||||
* has happened for the specified period of time (in milli-seconds)
|
|
||||||
* <br>
|
|
||||||
* Specify {@code 0} to disable (default).
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
void setIdleTimeout(int idleTimeoutMs) {
|
|
||||||
this.idleTimeoutMs = idleTimeoutMs;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the connection status of this endpoint.
|
|
||||||
* <p/>
|
|
||||||
* Once a server has connected to ANY client, it will always return true until server.close() is called
|
|
||||||
*/
|
|
||||||
public final
|
|
||||||
boolean isConnected() {
|
|
||||||
return this.isConnected.get();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -414,155 +146,8 @@ class EndPoint<C extends Connection> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the serialization wrapper if there is an object type that needs to be added outside of the basics.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
dorkbox.network.util.CryptoSerializationManager getSerialization() {
|
|
||||||
return this.serializationManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method allows the connections used by the client/server to be subclassed (custom implementations).
|
|
||||||
* <p/>
|
|
||||||
* As this is for the network stack, the new connection MUST subclass {@link ConnectionImpl}
|
|
||||||
* <p/>
|
|
||||||
* The parameters are ALL NULL when getting the base class, as this instance is just thrown away.
|
|
||||||
*
|
|
||||||
* @return a new network connection
|
|
||||||
*/
|
|
||||||
protected
|
|
||||||
ConnectionImpl newConnection(final Logger logger, final EndPoint<C> endPoint, final RmiBridge rmiBridge) {
|
|
||||||
return new ConnectionImpl(logger, endPoint, rmiBridge);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Internal call by the pipeline when:
|
|
||||||
* - creating a new network connection
|
|
||||||
* - when determining the baseClass for listeners
|
|
||||||
*
|
|
||||||
* @param metaChannel can be NULL (when getting the baseClass)
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
protected final
|
|
||||||
Connection connection0(MetaChannel metaChannel) {
|
|
||||||
ConnectionImpl connection;
|
|
||||||
|
|
||||||
RmiBridge rmiBridge = null;
|
|
||||||
if (metaChannel != null && rmiEnabled) {
|
|
||||||
rmiBridge = new RmiBridge(logger, rmiExecutor, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// setup the extras needed by the network connection.
|
|
||||||
// These properties are ASSIGNED in the same thread that CREATED the object. Only the AES info needs to be
|
|
||||||
// volatile since it is the only thing that changes.
|
|
||||||
if (metaChannel != null) {
|
|
||||||
ChannelWrapper<C> wrapper;
|
|
||||||
|
|
||||||
connection = newConnection(logger, this, rmiBridge);
|
|
||||||
metaChannel.connection = connection;
|
|
||||||
|
|
||||||
if (metaChannel.localChannel != null) {
|
|
||||||
wrapper = new ChannelLocalWrapper(metaChannel);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (this instanceof EndPointServer) {
|
|
||||||
wrapper = new ChannelNetworkWrapper(metaChannel, this.registrationWrapper);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
wrapper = new ChannelNetworkWrapper(metaChannel, null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// now initialize the connection channels with whatever extra info they might need.
|
|
||||||
connection.init(wrapper, (ConnectionManager<Connection>) this.connectionManager);
|
|
||||||
|
|
||||||
if (rmiBridge != null) {
|
|
||||||
// notify our remote object space that it is able to receive method calls.
|
|
||||||
connection.listeners()
|
|
||||||
.add(rmiBridge.getListener());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// getting the connection baseClass
|
|
||||||
|
|
||||||
// have to add the networkAssociate to a map of "connected" computers
|
|
||||||
connection = newConnection(null, null, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
return connection;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Internal call by the pipeline to notify the "Connection" object that it has "connected", meaning that modifications
|
|
||||||
* to the pipeline are finished.
|
|
||||||
* <p/>
|
|
||||||
* Only the CLIENT injects in front of this)
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
void connectionConnected0(ConnectionImpl connection) {
|
|
||||||
this.isConnected.set(true);
|
|
||||||
|
|
||||||
// prep the channel wrapper
|
|
||||||
connection.prep();
|
|
||||||
|
|
||||||
this.connectionManager.onConnected((C) connection);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Expose methods to modify the listeners (connect/disconnect/idle/receive events).
|
|
||||||
*/
|
|
||||||
public final
|
|
||||||
Listeners listeners() {
|
|
||||||
return this.connectionManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a non-modifiable list of active connections
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
List<C> getConnections() {
|
|
||||||
return this.connectionManager.getConnections();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a non-modifiable list of active connections
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public
|
|
||||||
Collection<C> getConnectionsAs() {
|
|
||||||
return this.connectionManager.getConnections();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Expose methods to send objects to a destination.
|
|
||||||
*/
|
|
||||||
public abstract
|
|
||||||
ConnectionBridgeBase send();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Closes all connections ONLY (keeps the server/client running). To STOP the client/server, use stop().
|
|
||||||
* <p/>
|
|
||||||
* This is used, for example, when reconnecting to a server.
|
|
||||||
* <p/>
|
|
||||||
* The server should ALWAYS use STOP.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
void closeConnections() {
|
|
||||||
// give a chance to other threads.
|
|
||||||
Thread.yield();
|
|
||||||
|
|
||||||
// stop does the same as this + more
|
|
||||||
this.connectionManager.closeConnections();
|
|
||||||
|
|
||||||
// Sometimes there might be "lingering" connections (ie, halfway though registration) that need to be closed.
|
|
||||||
this.registrationWrapper.closeChannels(maxShutdownWaitTimeInMilliSeconds);
|
|
||||||
|
|
||||||
this.isConnected.set(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// server only does this on stop. Client does this on closeConnections
|
// server only does this on stop. Client does this on closeConnections
|
||||||
protected void shutdownChannels() {
|
void shutdownChannels() {
|
||||||
synchronized (shutdownChannelList) {
|
synchronized (shutdownChannelList) {
|
||||||
// now we stop all of our channels
|
// now we stop all of our channels
|
||||||
for (ChannelFuture f : this.shutdownChannelList) {
|
for (ChannelFuture f : this.shutdownChannelList) {
|
||||||
@ -579,6 +164,7 @@ class EndPoint<C extends Connection> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected final
|
protected final
|
||||||
String stopWithErrorMessage(Logger logger2, String errorMessage, Throwable throwable) {
|
String stopWithErrorMessage(Logger logger2, String errorMessage, Throwable throwable) {
|
||||||
if (logger2.isDebugEnabled() && throwable != null) {
|
if (logger2.isDebugEnabled() && throwable != null) {
|
||||||
@ -593,6 +179,16 @@ class EndPoint<C extends Connection> {
|
|||||||
return errorMessage;
|
return errorMessage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts the shutdown process during JVM shutdown, if necessary.
|
||||||
|
* </p>
|
||||||
|
* By default, we always can shutdown via the JVM shutdown hook.
|
||||||
|
*/
|
||||||
|
protected
|
||||||
|
boolean shouldShutdownHookRun() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Safely closes all associated resources/threads/connections.
|
* Safely closes all associated resources/threads/connections.
|
||||||
* <p/>
|
* <p/>
|
||||||
@ -653,6 +249,28 @@ class EndPoint<C extends Connection> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extra EXTERNAL actions to perform when stopping this endpoint.
|
||||||
|
*/
|
||||||
|
protected
|
||||||
|
void stopExtraActions() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Actions that happen by the endpoint before the channels are shutdown
|
||||||
|
*/
|
||||||
|
protected
|
||||||
|
void shutdownChannelsPre() {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Actions that happen by the endpoint before any extra actions are run.
|
||||||
|
*/
|
||||||
|
protected
|
||||||
|
void stopExtraActionsInternal() {
|
||||||
|
}
|
||||||
|
|
||||||
// This actually does the "stopping", since there is some logic to making sure we don't deadlock, this is important
|
// This actually does the "stopping", since there is some logic to making sure we don't deadlock, this is important
|
||||||
private
|
private
|
||||||
void stopInThread() {
|
void stopInThread() {
|
||||||
@ -676,14 +294,11 @@ class EndPoint<C extends Connection> {
|
|||||||
Thread.yield();
|
Thread.yield();
|
||||||
}
|
}
|
||||||
|
|
||||||
closeConnections();
|
shutdownChannelsPre();
|
||||||
|
|
||||||
// this does a closeConnections + clear_listeners
|
|
||||||
this.connectionManager.stop();
|
|
||||||
|
|
||||||
shutdownChannels();
|
shutdownChannels();
|
||||||
|
|
||||||
this.logger.info("Stopping endpoint");
|
this.logger.info("Stopping endpoint.");
|
||||||
|
|
||||||
// there is no need to call "stop" again if we close the connection.
|
// there is no need to call "stop" again if we close the connection.
|
||||||
// however, if this is called WHILE from the shutdown hook, blammo! problems!
|
// however, if this is called WHILE from the shutdown hook, blammo! problems!
|
||||||
@ -701,10 +316,7 @@ class EndPoint<C extends Connection> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
stopExtraActionsInternal();
|
||||||
// shutdown the database store
|
|
||||||
this.propertyStore.close();
|
|
||||||
|
|
||||||
|
|
||||||
// when the eventloop closes, the associated selectors are ALSO closed!
|
// when the eventloop closes, the associated selectors are ALSO closed!
|
||||||
stopExtraActions();
|
stopExtraActions();
|
||||||
@ -717,13 +329,6 @@ class EndPoint<C extends Connection> {
|
|||||||
this.blockUntilDone.countDown();
|
this.blockUntilDone.countDown();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Extra EXTERNAL actions to perform when stopping this endpoint.
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
void stopExtraActions() {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Blocks the current thread until the endpoint has been stopped. If the endpoint is already stopped, this do nothing.
|
* Blocks the current thread until the endpoint has been stopped. If the endpoint is already stopped, this do nothing.
|
||||||
*/
|
*/
|
||||||
@ -737,50 +342,6 @@ class EndPoint<C extends Connection> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public
|
|
||||||
int hashCode() {
|
|
||||||
final int prime = 31;
|
|
||||||
int result = 1;
|
|
||||||
result = prime * result + (this.privateKey == null ? 0 : this.privateKey.hashCode());
|
|
||||||
result = prime * result + (this.publicKey == null ? 0 : this.publicKey.hashCode());
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("rawtypes")
|
|
||||||
@Override
|
|
||||||
public
|
|
||||||
boolean equals(Object obj) {
|
|
||||||
if (this == obj) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (obj == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (getClass() != obj.getClass()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
EndPoint other = (EndPoint) obj;
|
|
||||||
|
|
||||||
if (this.privateKey == null) {
|
|
||||||
if (other.privateKey != null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (!CryptoECC.compare(this.privateKey, other.privateKey)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (this.publicKey == null) {
|
|
||||||
if (other.publicKey != null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (!CryptoECC.compare(this.publicKey, other.publicKey)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
String toString() {
|
String toString() {
|
||||||
@ -791,15 +352,4 @@ class EndPoint<C extends Connection> {
|
|||||||
String getName() {
|
String getName() {
|
||||||
return this.type.getSimpleName();
|
return this.type.getSimpleName();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a "global" RMI object for use by multiple connections.
|
|
||||||
* @return the ID assigned to this RMI object
|
|
||||||
*/
|
|
||||||
public
|
|
||||||
<T> int createGlobalObject(final T globalObject) {
|
|
||||||
int globalObjectId = globalRmiBridge.nextObjectId();
|
|
||||||
globalRmiBridge.register(globalObjectId, globalObject);
|
|
||||||
return globalObjectId;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
523
src/dorkbox/network/connection/EndPointBase.java
Normal file
523
src/dorkbox/network/connection/EndPointBase.java
Normal file
@ -0,0 +1,523 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010 dorkbox, llc
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package dorkbox.network.connection;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.security.SecureRandom;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
|
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
|
||||||
|
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
|
||||||
|
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
|
||||||
|
import dorkbox.network.Configuration;
|
||||||
|
import dorkbox.network.connection.bridge.ConnectionBridgeBase;
|
||||||
|
import dorkbox.network.connection.ping.PingSystemListener;
|
||||||
|
import dorkbox.network.connection.registration.MetaChannel;
|
||||||
|
import dorkbox.network.connection.wrapper.ChannelLocalWrapper;
|
||||||
|
import dorkbox.network.connection.wrapper.ChannelNetworkWrapper;
|
||||||
|
import dorkbox.network.connection.wrapper.ChannelWrapper;
|
||||||
|
import dorkbox.network.pipeline.KryoEncoder;
|
||||||
|
import dorkbox.network.pipeline.KryoEncoderCrypto;
|
||||||
|
import dorkbox.network.rmi.RmiBridge;
|
||||||
|
import dorkbox.network.store.NullSettingsStore;
|
||||||
|
import dorkbox.network.store.SettingsStore;
|
||||||
|
import dorkbox.util.Property;
|
||||||
|
import dorkbox.util.crypto.CryptoECC;
|
||||||
|
import dorkbox.util.entropy.Entropy;
|
||||||
|
import dorkbox.util.exceptions.InitializationException;
|
||||||
|
import dorkbox.util.exceptions.SecurityException;
|
||||||
|
import io.netty.util.NetUtil;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* represents the base of a client/server end point
|
||||||
|
*/
|
||||||
|
public abstract
|
||||||
|
class EndPointBase<C extends Connection> extends EndPoint {
|
||||||
|
// If TCP and UDP both fill the pipe, THERE WILL BE FRAGMENTATION and dropped UDP packets!
|
||||||
|
// it results in severe UDP packet loss and contention.
|
||||||
|
//
|
||||||
|
// http://www.isoc.org/INET97/proceedings/F3/F3_1.HTM
|
||||||
|
// also, a google search on just "INET97/proceedings/F3/F3_1.HTM" turns up interesting problems.
|
||||||
|
// Usually it's with ISPs.
|
||||||
|
|
||||||
|
// TODO: will also want an UDP keepalive? (TCP is already there b/c of socket options, but might need a heartbeat to detect dead connections?)
|
||||||
|
// routers sometimes need a heartbeat to keep the connection
|
||||||
|
// TODO: maybe some sort of STUN-like connection keep-alive??
|
||||||
|
|
||||||
|
|
||||||
|
public static final String LOCAL_CHANNEL = "local_channel";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default size for UDP packets is 768 bytes.
|
||||||
|
* <p/>
|
||||||
|
* You could increase or decrease this value to avoid truncated packets
|
||||||
|
* or to improve memory footprint respectively.
|
||||||
|
* <p/>
|
||||||
|
* Please also note that a large UDP packet might be truncated or
|
||||||
|
* dropped by your router no matter how you configured this option.
|
||||||
|
* In UDP, a packet is truncated or dropped if it is larger than a
|
||||||
|
* certain size, depending on router configuration. IPv4 routers
|
||||||
|
* truncate and IPv6 routers drop a large packet. That's why it is
|
||||||
|
* safe to send small packets in UDP.
|
||||||
|
* <p/>
|
||||||
|
* To fit into that magic 576-byte MTU and avoid fragmentation, your
|
||||||
|
* UDP payload should be restricted by 576-60-8=508 bytes.
|
||||||
|
*
|
||||||
|
* This can be set higher on an internal lan!
|
||||||
|
*
|
||||||
|
* DON'T go higher that 1400 over the internet, but 9k is possible
|
||||||
|
* with jumbo frames on a local network (if it's supported)
|
||||||
|
*/
|
||||||
|
@Property
|
||||||
|
public static int udpMaxSize = 508;
|
||||||
|
|
||||||
|
protected final ConnectionManager<C> connectionManager;
|
||||||
|
protected final dorkbox.network.util.CryptoSerializationManager serializationManager;
|
||||||
|
protected final RegistrationWrapper<C> registrationWrapper;
|
||||||
|
|
||||||
|
final ECPrivateKeyParameters privateKey;
|
||||||
|
final ECPublicKeyParameters publicKey;
|
||||||
|
|
||||||
|
final SecureRandom secureRandom;
|
||||||
|
final RmiBridge globalRmiBridge;
|
||||||
|
|
||||||
|
private final Executor rmiExecutor;
|
||||||
|
private final boolean rmiEnabled;
|
||||||
|
|
||||||
|
SettingsStore propertyStore;
|
||||||
|
boolean disableRemoteKeyValidation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* in milliseconds. default is disabled!
|
||||||
|
*/
|
||||||
|
private volatile int idleTimeoutMs = 0;
|
||||||
|
|
||||||
|
private AtomicBoolean isConnected = new AtomicBoolean(false);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param type this is either "Client" or "Server", depending on who is creating this endpoint.
|
||||||
|
* @param options these are the specific connection options
|
||||||
|
*
|
||||||
|
* @throws InitializationException
|
||||||
|
* @throws SecurityException
|
||||||
|
*/
|
||||||
|
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||||
|
public
|
||||||
|
EndPointBase(Class<? extends EndPointBase> type, final Configuration options) throws InitializationException, SecurityException, IOException {
|
||||||
|
super(type);
|
||||||
|
|
||||||
|
// make sure that 'localhost' is ALWAYS our specific loopback IP address
|
||||||
|
if (options.host != null && (options.host.equals("localhost") || options.host.startsWith("127."))) {
|
||||||
|
// localhost IP might not always be 127.0.0.1
|
||||||
|
options.host = NetUtil.LOCALHOST.getHostAddress();
|
||||||
|
}
|
||||||
|
|
||||||
|
// serialization stuff
|
||||||
|
if (options.serialization != null) {
|
||||||
|
this.serializationManager = options.serialization;
|
||||||
|
} else {
|
||||||
|
this.serializationManager = CryptoSerializationManager.DEFAULT();
|
||||||
|
}
|
||||||
|
|
||||||
|
// setup our RMI serialization managers. Can only be called once
|
||||||
|
rmiEnabled = serializationManager.initRmiSerialization();
|
||||||
|
rmiExecutor = options.rmiExecutor;
|
||||||
|
|
||||||
|
|
||||||
|
// The registration wrapper permits the registration process to access protected/package fields/methods, that we don't want
|
||||||
|
// to expose to external code. "this" escaping can be ignored, because it is benign.
|
||||||
|
//noinspection ThisEscapedInObjectConstruction
|
||||||
|
this.registrationWrapper = new RegistrationWrapper(this,
|
||||||
|
this.logger,
|
||||||
|
new KryoEncoder(this.serializationManager),
|
||||||
|
new KryoEncoderCrypto(this.serializationManager));
|
||||||
|
|
||||||
|
|
||||||
|
// we have to be able to specify WHAT property store we want to use, since it can change!
|
||||||
|
if (options.settingsStore == null) {
|
||||||
|
this.propertyStore = new PropertyStore();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.propertyStore = options.settingsStore;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.propertyStore.init(this.serializationManager, null);
|
||||||
|
|
||||||
|
// null it out, since it is sensitive!
|
||||||
|
options.settingsStore = null;
|
||||||
|
|
||||||
|
|
||||||
|
if (!(this.propertyStore instanceof NullSettingsStore)) {
|
||||||
|
// initialize the private/public keys used for negotiating ECC handshakes
|
||||||
|
// these are ONLY used for IP connections. LOCAL connections do not need a handshake!
|
||||||
|
ECPrivateKeyParameters privateKey = this.propertyStore.getPrivateKey();
|
||||||
|
ECPublicKeyParameters publicKey = this.propertyStore.getPublicKey();
|
||||||
|
|
||||||
|
if (privateKey == null || publicKey == null) {
|
||||||
|
try {
|
||||||
|
// seed our RNG based off of this and create our ECC keys
|
||||||
|
byte[] seedBytes = Entropy.get("There are no ECC keys for the " + type.getSimpleName() + " yet");
|
||||||
|
SecureRandom secureRandom = new SecureRandom(seedBytes);
|
||||||
|
secureRandom.nextBytes(seedBytes);
|
||||||
|
|
||||||
|
this.logger.debug("Now generating ECC (" + CryptoECC.curve25519 + ") keys. Please wait!");
|
||||||
|
AsymmetricCipherKeyPair generateKeyPair = CryptoECC.generateKeyPair(CryptoECC.curve25519, secureRandom);
|
||||||
|
|
||||||
|
privateKey = (ECPrivateKeyParameters) generateKeyPair.getPrivate();
|
||||||
|
publicKey = (ECPublicKeyParameters) generateKeyPair.getPublic();
|
||||||
|
|
||||||
|
// save to properties file
|
||||||
|
this.propertyStore.savePrivateKey(privateKey);
|
||||||
|
this.propertyStore.savePublicKey(publicKey);
|
||||||
|
|
||||||
|
this.logger.debug("Done with ECC keys!");
|
||||||
|
} catch (Exception e) {
|
||||||
|
String message = "Unable to initialize/generate ECC keys. FORCED SHUTDOWN.";
|
||||||
|
this.logger.error(message);
|
||||||
|
throw new InitializationException(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.privateKey = privateKey;
|
||||||
|
this.publicKey = publicKey;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.privateKey = null;
|
||||||
|
this.publicKey = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
this.secureRandom = new SecureRandom(this.propertyStore.getSalt());
|
||||||
|
|
||||||
|
// we don't care about un-instantiated/constructed members, since the class type is the only interest.
|
||||||
|
this.connectionManager = new ConnectionManager<C>(type.getSimpleName(), connection0(null).getClass());
|
||||||
|
|
||||||
|
// add the ping listener (internal use only!)
|
||||||
|
this.connectionManager.add(new PingSystemListener());
|
||||||
|
|
||||||
|
if (this.rmiEnabled) {
|
||||||
|
// these register the listener for registering a class implementation for RMI (internal use only)
|
||||||
|
this.connectionManager.add(new RegisterRmiSystemListener());
|
||||||
|
this.globalRmiBridge = new RmiBridge(logger, options.rmiExecutor, true);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.globalRmiBridge = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
serializationManager.finishInit();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disables remote endpoint public key validation when the connection is established. This is not recommended as it is a security risk
|
||||||
|
*/
|
||||||
|
public
|
||||||
|
void disableRemoteKeyValidation() {
|
||||||
|
Logger logger2 = this.logger;
|
||||||
|
|
||||||
|
if (isConnected()) {
|
||||||
|
logger2.error("Cannot disable the remote key validation after this endpoint is connected!");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
logger2.info("WARNING: Disabling remote key validation is a security risk!!");
|
||||||
|
this.disableRemoteKeyValidation = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the property store used by this endpoint. The property store can store via properties,
|
||||||
|
* a database, etc, or can be a "null" property store, which does nothing
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public
|
||||||
|
<S extends SettingsStore> S getPropertyStore() {
|
||||||
|
return (S) this.propertyStore;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal call by the pipeline to notify the client to continue registering the different session protocols.
|
||||||
|
* The server does not use this.
|
||||||
|
*/
|
||||||
|
protected
|
||||||
|
boolean registerNextProtocol0() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The amount of milli-seconds that must elapse with no read or write before {@link Listener.OnIdle#idle(Connection)} }
|
||||||
|
* will be triggered
|
||||||
|
*/
|
||||||
|
public
|
||||||
|
int getIdleTimeout() {
|
||||||
|
return this.idleTimeoutMs;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link Listener:idle()} will be triggered when neither read nor write
|
||||||
|
* has happened for the specified period of time (in milli-seconds)
|
||||||
|
* <br>
|
||||||
|
* Specify {@code 0} to disable (default).
|
||||||
|
*/
|
||||||
|
public
|
||||||
|
void setIdleTimeout(int idleTimeoutMs) {
|
||||||
|
this.idleTimeoutMs = idleTimeoutMs;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the connection status of this endpoint.
|
||||||
|
* <p/>
|
||||||
|
* Once a server has connected to ANY client, it will always return true until server.close() is called
|
||||||
|
*/
|
||||||
|
public final
|
||||||
|
boolean isConnected() {
|
||||||
|
return this.isConnected.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the serialization wrapper if there is an object type that needs to be added outside of the basics.
|
||||||
|
*/
|
||||||
|
public
|
||||||
|
dorkbox.network.util.CryptoSerializationManager getSerialization() {
|
||||||
|
return this.serializationManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method allows the connections used by the client/server to be subclassed (custom implementations).
|
||||||
|
* <p/>
|
||||||
|
* As this is for the network stack, the new connection MUST subclass {@link ConnectionImpl}
|
||||||
|
* <p/>
|
||||||
|
* The parameters are ALL NULL when getting the base class, as this instance is just thrown away.
|
||||||
|
*
|
||||||
|
* @return a new network connection
|
||||||
|
*/
|
||||||
|
protected
|
||||||
|
ConnectionImpl newConnection(final Logger logger, final EndPointBase<C> endPointBaseConnection, final RmiBridge rmiBridge) {
|
||||||
|
return new ConnectionImpl(logger, endPointBaseConnection, rmiBridge);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal call by the pipeline when:
|
||||||
|
* - creating a new network connection
|
||||||
|
* - when determining the baseClass for listeners
|
||||||
|
*
|
||||||
|
* @param metaChannel can be NULL (when getting the baseClass)
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
protected final
|
||||||
|
Connection connection0(MetaChannel metaChannel) {
|
||||||
|
ConnectionImpl connection;
|
||||||
|
|
||||||
|
RmiBridge rmiBridge = null;
|
||||||
|
if (metaChannel != null && rmiEnabled) {
|
||||||
|
rmiBridge = new RmiBridge(logger, rmiExecutor, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// setup the extras needed by the network connection.
|
||||||
|
// These properties are ASSIGNED in the same thread that CREATED the object. Only the AES info needs to be
|
||||||
|
// volatile since it is the only thing that changes.
|
||||||
|
if (metaChannel != null) {
|
||||||
|
ChannelWrapper<C> wrapper;
|
||||||
|
|
||||||
|
connection = newConnection(logger, this, rmiBridge);
|
||||||
|
metaChannel.connection = connection;
|
||||||
|
|
||||||
|
if (metaChannel.localChannel != null) {
|
||||||
|
wrapper = new ChannelLocalWrapper(metaChannel);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (this instanceof EndPointServer) {
|
||||||
|
wrapper = new ChannelNetworkWrapper(metaChannel, this.registrationWrapper);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
wrapper = new ChannelNetworkWrapper(metaChannel, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// now initialize the connection channels with whatever extra info they might need.
|
||||||
|
connection.init(wrapper, (ConnectionManager<Connection>) this.connectionManager);
|
||||||
|
|
||||||
|
if (rmiBridge != null) {
|
||||||
|
// notify our remote object space that it is able to receive method calls.
|
||||||
|
connection.listeners()
|
||||||
|
.add(rmiBridge.getListener());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// getting the connection baseClass
|
||||||
|
|
||||||
|
// have to add the networkAssociate to a map of "connected" computers
|
||||||
|
connection = newConnection(null, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
return connection;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal call by the pipeline to notify the "Connection" object that it has "connected", meaning that modifications
|
||||||
|
* to the pipeline are finished.
|
||||||
|
* <p/>
|
||||||
|
* Only the CLIENT injects in front of this)
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
void connectionConnected0(ConnectionImpl connection) {
|
||||||
|
this.isConnected.set(true);
|
||||||
|
|
||||||
|
// prep the channel wrapper
|
||||||
|
connection.prep();
|
||||||
|
|
||||||
|
this.connectionManager.onConnected((C) connection);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Expose methods to modify the listeners (connect/disconnect/idle/receive events).
|
||||||
|
*/
|
||||||
|
public final
|
||||||
|
Listeners listeners() {
|
||||||
|
return this.connectionManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a non-modifiable list of active connections
|
||||||
|
*/
|
||||||
|
public
|
||||||
|
List<C> getConnections() {
|
||||||
|
return this.connectionManager.getConnections();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a non-modifiable list of active connections
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public
|
||||||
|
Collection<C> getConnectionsAs() {
|
||||||
|
return this.connectionManager.getConnections();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Expose methods to send objects to a destination.
|
||||||
|
*/
|
||||||
|
public abstract
|
||||||
|
ConnectionBridgeBase send();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Closes all connections ONLY (keeps the server/client running). To STOP the client/server, use stop().
|
||||||
|
* <p/>
|
||||||
|
* This is used, for example, when reconnecting to a server.
|
||||||
|
* <p/>
|
||||||
|
* The server should ALWAYS use STOP.
|
||||||
|
*/
|
||||||
|
public
|
||||||
|
void closeConnections() {
|
||||||
|
// give a chance to other threads.
|
||||||
|
Thread.yield();
|
||||||
|
|
||||||
|
// stop does the same as this + more
|
||||||
|
this.connectionManager.closeConnections();
|
||||||
|
|
||||||
|
// Sometimes there might be "lingering" connections (ie, halfway though registration) that need to be closed.
|
||||||
|
this.registrationWrapper.closeChannels(maxShutdownWaitTimeInMilliSeconds);
|
||||||
|
|
||||||
|
this.isConnected.set(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts the shutdown process during JVM shutdown, if necessary.
|
||||||
|
* </p>
|
||||||
|
* By default, we always can shutdown via the JVM shutdown hook.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected
|
||||||
|
boolean shouldShutdownHookRun() {
|
||||||
|
// connectionManager.shutdown accurately reflects the state of the app. Safe to use here
|
||||||
|
return (this.connectionManager != null && !this.connectionManager.shutdown.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected
|
||||||
|
void shutdownChannelsPre() {
|
||||||
|
closeConnections();
|
||||||
|
|
||||||
|
// this does a closeConnections + clear_listeners
|
||||||
|
this.connectionManager.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected
|
||||||
|
void stopExtraActionsInternal() {
|
||||||
|
// shutdown the database store
|
||||||
|
this.propertyStore.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public
|
||||||
|
int hashCode() {
|
||||||
|
final int prime = 31;
|
||||||
|
int result = 1;
|
||||||
|
result = prime * result + (this.privateKey == null ? 0 : this.privateKey.hashCode());
|
||||||
|
result = prime * result + (this.publicKey == null ? 0 : this.publicKey.hashCode());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
|
@Override
|
||||||
|
public
|
||||||
|
boolean equals(Object obj) {
|
||||||
|
if (this == obj) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (obj == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (getClass() != obj.getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
EndPointBase other = (EndPointBase) obj;
|
||||||
|
|
||||||
|
if (this.privateKey == null) {
|
||||||
|
if (other.privateKey != null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!CryptoECC.compare(this.privateKey, other.privateKey)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (this.publicKey == null) {
|
||||||
|
if (other.publicKey != null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!CryptoECC.compare(this.publicKey, other.publicKey)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a "global" RMI object for use by multiple connections.
|
||||||
|
* @return the ID assigned to this RMI object
|
||||||
|
*/
|
||||||
|
public
|
||||||
|
<T> int createGlobalObject(final T globalObject) {
|
||||||
|
int globalObjectId = globalRmiBridge.nextObjectId();
|
||||||
|
globalRmiBridge.register(globalObjectId, globalObject);
|
||||||
|
return globalObjectId;
|
||||||
|
}
|
||||||
|
}
|
@ -34,7 +34,7 @@ import io.netty.channel.ChannelOption;
|
|||||||
* This serves the purpose of making sure that specific methods are not available to the end user.
|
* This serves the purpose of making sure that specific methods are not available to the end user.
|
||||||
*/
|
*/
|
||||||
public
|
public
|
||||||
class EndPointClient<C extends Connection> extends EndPoint<C> implements Runnable {
|
class EndPointClient<C extends Connection> extends EndPointBase<C> implements Runnable {
|
||||||
|
|
||||||
protected C connection;
|
protected C connection;
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@ import dorkbox.util.exceptions.SecurityException;
|
|||||||
* This serves the purpose of making sure that specific methods are not available to the end user.
|
* This serves the purpose of making sure that specific methods are not available to the end user.
|
||||||
*/
|
*/
|
||||||
public
|
public
|
||||||
class EndPointServer<C extends Connection> extends EndPoint<C> {
|
class EndPointServer<C extends Connection> extends EndPointBase<C> {
|
||||||
|
|
||||||
public
|
public
|
||||||
EndPointServer(final Configuration options) throws InitializationException, SecurityException, IOException {
|
EndPointServer(final Configuration options) throws InitializationException, SecurityException, IOException {
|
||||||
|
@ -61,7 +61,7 @@ class KryoExtra<C extends ICryptoConnection> extends Kryo {
|
|||||||
|
|
||||||
|
|
||||||
// writing data
|
// writing data
|
||||||
private final ByteBuf tempBuffer = Unpooled.buffer(EndPoint.udpMaxSize);
|
private final ByteBuf tempBuffer = Unpooled.buffer(EndPointBase.udpMaxSize);
|
||||||
private LZ4Compressor compressor = factory.fastCompressor();
|
private LZ4Compressor compressor = factory.fastCompressor();
|
||||||
|
|
||||||
private int inputArrayLength = -1;
|
private int inputArrayLength = -1;
|
||||||
|
@ -62,12 +62,12 @@ interface Listener {
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when the connection is idle for longer than the {@link EndPoint#setIdleTimeout(int)} idle threshold.
|
* Called when the connection is idle for longer than the {@link EndPointBase#setIdleTimeout(int)} idle threshold.
|
||||||
*/
|
*/
|
||||||
interface OnIdle<C extends Connection> extends Listener {
|
interface OnIdle<C extends Connection> extends Listener {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when the connection is idle for longer than the {@link EndPoint#setIdleTimeout(int)} idle threshold.
|
* Called when the connection is idle for longer than the {@link EndPointBase#setIdleTimeout(int)} idle threshold.
|
||||||
*/
|
*/
|
||||||
void idle(C connection) throws IOException;
|
void idle(C connection) throws IOException;
|
||||||
}
|
}
|
||||||
|
@ -80,7 +80,7 @@ class PropertyStore extends SettingsStore {
|
|||||||
@Override
|
@Override
|
||||||
public synchronized
|
public synchronized
|
||||||
ECPrivateKeyParameters getPrivateKey() throws dorkbox.util.exceptions.SecurityException {
|
ECPrivateKeyParameters getPrivateKey() throws dorkbox.util.exceptions.SecurityException {
|
||||||
checkAccess(EndPoint.class);
|
checkAccess(EndPointBase.class);
|
||||||
|
|
||||||
return servers.get(DB_Server.IP_SELF)
|
return servers.get(DB_Server.IP_SELF)
|
||||||
.getPrivateKey();
|
.getPrivateKey();
|
||||||
@ -92,7 +92,7 @@ class PropertyStore extends SettingsStore {
|
|||||||
@Override
|
@Override
|
||||||
public synchronized
|
public synchronized
|
||||||
void savePrivateKey(final ECPrivateKeyParameters serverPrivateKey) throws SecurityException {
|
void savePrivateKey(final ECPrivateKeyParameters serverPrivateKey) throws SecurityException {
|
||||||
checkAccess(EndPoint.class);
|
checkAccess(EndPointBase.class);
|
||||||
|
|
||||||
servers.get(DB_Server.IP_SELF)
|
servers.get(DB_Server.IP_SELF)
|
||||||
.setPrivateKey(serverPrivateKey);
|
.setPrivateKey(serverPrivateKey);
|
||||||
@ -107,7 +107,7 @@ class PropertyStore extends SettingsStore {
|
|||||||
@Override
|
@Override
|
||||||
public synchronized
|
public synchronized
|
||||||
ECPublicKeyParameters getPublicKey() throws SecurityException {
|
ECPublicKeyParameters getPublicKey() throws SecurityException {
|
||||||
checkAccess(EndPoint.class);
|
checkAccess(EndPointBase.class);
|
||||||
|
|
||||||
return servers.get(DB_Server.IP_SELF)
|
return servers.get(DB_Server.IP_SELF)
|
||||||
.getPublicKey();
|
.getPublicKey();
|
||||||
@ -119,7 +119,7 @@ class PropertyStore extends SettingsStore {
|
|||||||
@Override
|
@Override
|
||||||
public synchronized
|
public synchronized
|
||||||
void savePublicKey(final ECPublicKeyParameters serverPublicKey) throws SecurityException {
|
void savePublicKey(final ECPublicKeyParameters serverPublicKey) throws SecurityException {
|
||||||
checkAccess(EndPoint.class);
|
checkAccess(EndPointBase.class);
|
||||||
|
|
||||||
servers.get(DB_Server.IP_SELF)
|
servers.get(DB_Server.IP_SELF)
|
||||||
.setPublicKey(serverPublicKey);
|
.setPublicKey(serverPublicKey);
|
||||||
|
@ -53,7 +53,7 @@ class RegistrationWrapper<C extends Connection> implements UdpServer {
|
|||||||
private final KryoEncoder kryoEncoder;
|
private final KryoEncoder kryoEncoder;
|
||||||
private final KryoEncoderCrypto kryoEncoderCrypto;
|
private final KryoEncoderCrypto kryoEncoderCrypto;
|
||||||
|
|
||||||
private final EndPoint<C> endPoint;
|
private final EndPointBase<C> endPointBaseConnection;
|
||||||
|
|
||||||
// keeps track of connections (TCP/UDP-client)
|
// keeps track of connections (TCP/UDP-client)
|
||||||
private final ReentrantLock channelMapLock = new ReentrantLock();
|
private final ReentrantLock channelMapLock = new ReentrantLock();
|
||||||
@ -77,16 +77,16 @@ class RegistrationWrapper<C extends Connection> implements UdpServer {
|
|||||||
|
|
||||||
|
|
||||||
public
|
public
|
||||||
RegistrationWrapper(final EndPoint<C> endPoint,
|
RegistrationWrapper(final EndPointBase<C> endPointBaseConnection,
|
||||||
final Logger logger,
|
final Logger logger,
|
||||||
final KryoEncoder kryoEncoder,
|
final KryoEncoder kryoEncoder,
|
||||||
final KryoEncoderCrypto kryoEncoderCrypto) {
|
final KryoEncoderCrypto kryoEncoderCrypto) {
|
||||||
this.endPoint = endPoint;
|
this.endPointBaseConnection = endPointBaseConnection;
|
||||||
this.logger = logger;
|
this.logger = logger;
|
||||||
this.kryoEncoder = kryoEncoder;
|
this.kryoEncoder = kryoEncoder;
|
||||||
this.kryoEncoderCrypto = kryoEncoderCrypto;
|
this.kryoEncoderCrypto = kryoEncoderCrypto;
|
||||||
|
|
||||||
if (endPoint instanceof EndPointServer) {
|
if (endPointBaseConnection instanceof EndPointServer) {
|
||||||
this.udpRemoteMap = new ObjectMap<InetSocketAddress, ConnectionImpl>(32, ConnectionManager.LOAD_FACTOR);
|
this.udpRemoteMap = new ObjectMap<InetSocketAddress, ConnectionImpl>(32, ConnectionManager.LOAD_FACTOR);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -99,7 +99,7 @@ class RegistrationWrapper<C extends Connection> implements UdpServer {
|
|||||||
*/
|
*/
|
||||||
public
|
public
|
||||||
boolean rmiEnabled() {
|
boolean rmiEnabled() {
|
||||||
return endPoint.globalRmiBridge != null;
|
return endPointBaseConnection.globalRmiBridge != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public
|
public
|
||||||
@ -135,7 +135,7 @@ class RegistrationWrapper<C extends Connection> implements UdpServer {
|
|||||||
*/
|
*/
|
||||||
public
|
public
|
||||||
int getIdleTimeout() {
|
int getIdleTimeout() {
|
||||||
return this.endPoint.getIdleTimeout();
|
return this.endPointBaseConnection.getIdleTimeout();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -146,7 +146,7 @@ class RegistrationWrapper<C extends Connection> implements UdpServer {
|
|||||||
*/
|
*/
|
||||||
public
|
public
|
||||||
boolean registerNextProtocol0() {
|
boolean registerNextProtocol0() {
|
||||||
return this.endPoint.registerNextProtocol0();
|
return this.endPointBaseConnection.registerNextProtocol0();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -155,7 +155,7 @@ class RegistrationWrapper<C extends Connection> implements UdpServer {
|
|||||||
*/
|
*/
|
||||||
public
|
public
|
||||||
void connectionConnected0(ConnectionImpl networkConnection) {
|
void connectionConnected0(ConnectionImpl networkConnection) {
|
||||||
this.endPoint.connectionConnected0(networkConnection);
|
this.endPointBaseConnection.connectionConnected0(networkConnection);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -166,22 +166,22 @@ class RegistrationWrapper<C extends Connection> implements UdpServer {
|
|||||||
*/
|
*/
|
||||||
public
|
public
|
||||||
Connection connection0(MetaChannel metaChannel) {
|
Connection connection0(MetaChannel metaChannel) {
|
||||||
return this.endPoint.connection0(metaChannel);
|
return this.endPointBaseConnection.connection0(metaChannel);
|
||||||
}
|
}
|
||||||
|
|
||||||
public
|
public
|
||||||
SecureRandom getSecureRandom() {
|
SecureRandom getSecureRandom() {
|
||||||
return this.endPoint.secureRandom;
|
return this.endPointBaseConnection.secureRandom;
|
||||||
}
|
}
|
||||||
|
|
||||||
public
|
public
|
||||||
ECPublicKeyParameters getPublicKey() {
|
ECPublicKeyParameters getPublicKey() {
|
||||||
return this.endPoint.publicKey;
|
return this.endPointBaseConnection.publicKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
public
|
public
|
||||||
CipherParameters getPrivateKey() {
|
CipherParameters getPrivateKey() {
|
||||||
return this.endPoint.privateKey;
|
return this.endPointBaseConnection.privateKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -197,13 +197,13 @@ class RegistrationWrapper<C extends Connection> implements UdpServer {
|
|||||||
InetAddress address = tcpRemoteServer.getAddress();
|
InetAddress address = tcpRemoteServer.getAddress();
|
||||||
byte[] hostAddress = address.getAddress();
|
byte[] hostAddress = address.getAddress();
|
||||||
|
|
||||||
ECPublicKeyParameters savedPublicKey = this.endPoint.propertyStore.getRegisteredServerKey(hostAddress);
|
ECPublicKeyParameters savedPublicKey = this.endPointBaseConnection.propertyStore.getRegisteredServerKey(hostAddress);
|
||||||
Logger logger2 = this.logger;
|
Logger logger2 = this.logger;
|
||||||
if (savedPublicKey == null) {
|
if (savedPublicKey == null) {
|
||||||
if (logger2.isDebugEnabled()) {
|
if (logger2.isDebugEnabled()) {
|
||||||
logger2.debug("Adding new remote IP address key for {}", address.getHostAddress());
|
logger2.debug("Adding new remote IP address key for {}", address.getHostAddress());
|
||||||
}
|
}
|
||||||
this.endPoint.propertyStore.addRegisteredServerKey(hostAddress, publicKey);
|
this.endPointBaseConnection.propertyStore.addRegisteredServerKey(hostAddress, publicKey);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// COMPARE!
|
// COMPARE!
|
||||||
@ -216,7 +216,7 @@ class RegistrationWrapper<C extends Connection> implements UdpServer {
|
|||||||
byAddress = "Unknown Address";
|
byAddress = "Unknown Address";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.endPoint.disableRemoteKeyValidation) {
|
if (this.endPointBaseConnection.disableRemoteKeyValidation) {
|
||||||
logger2.warn("Invalid or non-matching public key from remote server. Their public key has changed. To fix, remove entry for: {}", byAddress);
|
logger2.warn("Invalid or non-matching public key from remote server. Their public key has changed. To fix, remove entry for: {}", byAddress);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -234,7 +234,7 @@ class RegistrationWrapper<C extends Connection> implements UdpServer {
|
|||||||
@SuppressWarnings("AutoBoxing")
|
@SuppressWarnings("AutoBoxing")
|
||||||
public
|
public
|
||||||
void removeRegisteredServerKey(final byte[] hostAddress) throws SecurityException {
|
void removeRegisteredServerKey(final byte[] hostAddress) throws SecurityException {
|
||||||
ECPublicKeyParameters savedPublicKey = this.endPoint.propertyStore.getRegisteredServerKey(hostAddress);
|
ECPublicKeyParameters savedPublicKey = this.endPointBaseConnection.propertyStore.getRegisteredServerKey(hostAddress);
|
||||||
if (savedPublicKey != null) {
|
if (savedPublicKey != null) {
|
||||||
Logger logger2 = this.logger;
|
Logger logger2 = this.logger;
|
||||||
if (logger2.isDebugEnabled()) {
|
if (logger2.isDebugEnabled()) {
|
||||||
@ -244,7 +244,7 @@ class RegistrationWrapper<C extends Connection> implements UdpServer {
|
|||||||
hostAddress[2],
|
hostAddress[2],
|
||||||
hostAddress[3]);
|
hostAddress[3]);
|
||||||
}
|
}
|
||||||
this.endPoint.propertyStore.removeRegisteredServerKey(hostAddress);
|
this.endPointBaseConnection.propertyStore.removeRegisteredServerKey(hostAddress);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -316,8 +316,8 @@ class RegistrationWrapper<C extends Connection> implements UdpServer {
|
|||||||
|
|
||||||
public
|
public
|
||||||
void abortRegistrationIfClient() {
|
void abortRegistrationIfClient() {
|
||||||
if (this.endPoint instanceof EndPointClient) {
|
if (this.endPointBaseConnection instanceof EndPointClient) {
|
||||||
((EndPointClient<C>) this.endPoint).abortRegistration();
|
((EndPointClient<C>) this.endPointBaseConnection).abortRegistration();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
package dorkbox.network.connection.registration;
|
package dorkbox.network.connection.registration;
|
||||||
|
|
||||||
import dorkbox.network.connection.Connection;
|
import dorkbox.network.connection.Connection;
|
||||||
import dorkbox.network.connection.EndPoint;
|
import dorkbox.network.connection.EndPointBase;
|
||||||
import dorkbox.network.connection.RegistrationWrapper;
|
import dorkbox.network.connection.RegistrationWrapper;
|
||||||
import io.netty.channel.Channel;
|
import io.netty.channel.Channel;
|
||||||
import io.netty.channel.ChannelHandler.Sharable;
|
import io.netty.channel.ChannelHandler.Sharable;
|
||||||
@ -94,7 +94,7 @@ class RegistrationHandler<C extends Connection> extends ChannelInboundHandlerAda
|
|||||||
|
|
||||||
// also, once we notify, we unregister this.
|
// also, once we notify, we unregister this.
|
||||||
if (registrationWrapper != null) {
|
if (registrationWrapper != null) {
|
||||||
MetaChannel metaChannel = registrationWrapper.closeChannel(channel, EndPoint.maxShutdownWaitTimeInMilliSeconds);
|
MetaChannel metaChannel = registrationWrapper.closeChannel(channel, EndPointBase.maxShutdownWaitTimeInMilliSeconds);
|
||||||
registrationWrapper.abortRegistrationIfClient();
|
registrationWrapper.abortRegistrationIfClient();
|
||||||
|
|
||||||
return metaChannel;
|
return metaChannel;
|
||||||
|
@ -15,6 +15,10 @@
|
|||||||
*/
|
*/
|
||||||
package dorkbox.network.connection.registration.local;
|
package dorkbox.network.connection.registration.local;
|
||||||
|
|
||||||
|
import static dorkbox.network.connection.EndPointBase.maxShutdownWaitTimeInMilliSeconds;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
|
||||||
import dorkbox.network.connection.Connection;
|
import dorkbox.network.connection.Connection;
|
||||||
import dorkbox.network.connection.RegistrationWrapper;
|
import dorkbox.network.connection.RegistrationWrapper;
|
||||||
import dorkbox.network.connection.registration.MetaChannel;
|
import dorkbox.network.connection.registration.MetaChannel;
|
||||||
@ -23,9 +27,6 @@ import dorkbox.network.pipeline.LocalRmiDecoder;
|
|||||||
import dorkbox.network.pipeline.LocalRmiEncoder;
|
import dorkbox.network.pipeline.LocalRmiEncoder;
|
||||||
import io.netty.channel.Channel;
|
import io.netty.channel.Channel;
|
||||||
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
import org.slf4j.Logger;
|
|
||||||
|
|
||||||
import static dorkbox.network.connection.EndPoint.maxShutdownWaitTimeInMilliSeconds;
|
|
||||||
|
|
||||||
public abstract
|
public abstract
|
||||||
class RegistrationLocalHandler<C extends Connection> extends RegistrationHandler<C> {
|
class RegistrationLocalHandler<C extends Connection> extends RegistrationHandler<C> {
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
package dorkbox.network.connection.registration.remote;
|
package dorkbox.network.connection.registration.remote;
|
||||||
|
|
||||||
import static dorkbox.network.connection.EndPoint.maxShutdownWaitTimeInMilliSeconds;
|
import static dorkbox.network.connection.EndPointBase.maxShutdownWaitTimeInMilliSeconds;
|
||||||
|
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
|
@ -26,7 +26,7 @@ import dorkbox.network.Broadcast;
|
|||||||
import dorkbox.network.connection.Connection;
|
import dorkbox.network.connection.Connection;
|
||||||
import dorkbox.network.connection.ConnectionImpl;
|
import dorkbox.network.connection.ConnectionImpl;
|
||||||
import dorkbox.network.connection.CryptoSerializationManager;
|
import dorkbox.network.connection.CryptoSerializationManager;
|
||||||
import dorkbox.network.connection.EndPoint;
|
import dorkbox.network.connection.EndPointBase;
|
||||||
import dorkbox.network.connection.RegistrationWrapper;
|
import dorkbox.network.connection.RegistrationWrapper;
|
||||||
import dorkbox.network.connection.registration.MetaChannel;
|
import dorkbox.network.connection.registration.MetaChannel;
|
||||||
import dorkbox.network.connection.registration.Registration;
|
import dorkbox.network.connection.registration.Registration;
|
||||||
@ -266,7 +266,7 @@ class RegistrationRemoteHandlerServerUDP<C extends Connection> extends MessageTo
|
|||||||
|
|
||||||
// also, once we notify, we unregister this.
|
// also, once we notify, we unregister this.
|
||||||
if (registrationWrapper != null) {
|
if (registrationWrapper != null) {
|
||||||
return registrationWrapper.closeChannel(channel, EndPoint.maxShutdownWaitTimeInMilliSeconds);
|
return registrationWrapper.closeChannel(channel, EndPointBase.maxShutdownWaitTimeInMilliSeconds);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
@ -21,7 +21,7 @@ import org.bouncycastle.crypto.params.ParametersWithIV;
|
|||||||
|
|
||||||
import dorkbox.network.connection.Connection;
|
import dorkbox.network.connection.Connection;
|
||||||
import dorkbox.network.connection.ConnectionPointWriter;
|
import dorkbox.network.connection.ConnectionPointWriter;
|
||||||
import dorkbox.network.connection.EndPoint;
|
import dorkbox.network.connection.EndPointBase;
|
||||||
import dorkbox.network.connection.ISessionManager;
|
import dorkbox.network.connection.ISessionManager;
|
||||||
import dorkbox.network.connection.registration.MetaChannel;
|
import dorkbox.network.connection.registration.MetaChannel;
|
||||||
import io.netty.channel.Channel;
|
import io.netty.channel.Channel;
|
||||||
@ -120,7 +120,7 @@ class ChannelLocalWrapper<C extends Connection> implements ChannelWrapper<C>, Co
|
|||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
void close(Connection connection, ISessionManager<C> sessionManager) {
|
void close(Connection connection, ISessionManager<C> sessionManager) {
|
||||||
long maxShutdownWaitTimeInMilliSeconds = EndPoint.maxShutdownWaitTimeInMilliSeconds;
|
long maxShutdownWaitTimeInMilliSeconds = EndPointBase.maxShutdownWaitTimeInMilliSeconds;
|
||||||
|
|
||||||
this.shouldFlush.set(false);
|
this.shouldFlush.set(false);
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ import org.bouncycastle.crypto.params.ParametersWithIV;
|
|||||||
|
|
||||||
import dorkbox.network.connection.Connection;
|
import dorkbox.network.connection.Connection;
|
||||||
import dorkbox.network.connection.ConnectionPointWriter;
|
import dorkbox.network.connection.ConnectionPointWriter;
|
||||||
import dorkbox.network.connection.EndPoint;
|
import dorkbox.network.connection.EndPointBase;
|
||||||
import dorkbox.network.connection.ISessionManager;
|
import dorkbox.network.connection.ISessionManager;
|
||||||
import dorkbox.network.connection.UdpServer;
|
import dorkbox.network.connection.UdpServer;
|
||||||
import dorkbox.network.connection.registration.MetaChannel;
|
import dorkbox.network.connection.registration.MetaChannel;
|
||||||
@ -166,7 +166,7 @@ class ChannelNetworkWrapper<C extends Connection> implements ChannelWrapper<C> {
|
|||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
void close(final Connection connection, final ISessionManager<C> sessionManager) {
|
void close(final Connection connection, final ISessionManager<C> sessionManager) {
|
||||||
long maxShutdownWaitTimeInMilliSeconds = EndPoint.maxShutdownWaitTimeInMilliSeconds;
|
long maxShutdownWaitTimeInMilliSeconds = EndPointBase.maxShutdownWaitTimeInMilliSeconds;
|
||||||
|
|
||||||
this.tcp.close(maxShutdownWaitTimeInMilliSeconds);
|
this.tcp.close(maxShutdownWaitTimeInMilliSeconds);
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ import java.util.WeakHashMap;
|
|||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
import dorkbox.network.connection.ConnectionImpl;
|
import dorkbox.network.connection.ConnectionImpl;
|
||||||
import dorkbox.network.connection.EndPoint;
|
import dorkbox.network.connection.EndPointBase;
|
||||||
import dorkbox.network.rmi.Rmi;
|
import dorkbox.network.rmi.Rmi;
|
||||||
import dorkbox.util.FastThreadLocal;
|
import dorkbox.util.FastThreadLocal;
|
||||||
import io.netty.channel.ChannelHandler.Sharable;
|
import io.netty.channel.ChannelHandler.Sharable;
|
||||||
@ -33,7 +33,7 @@ import io.netty.handler.codec.MessageToMessageEncoder;
|
|||||||
public
|
public
|
||||||
class LocalRmiEncoder extends MessageToMessageEncoder<Object> {
|
class LocalRmiEncoder extends MessageToMessageEncoder<Object> {
|
||||||
|
|
||||||
private static final Map<Class<?>, Boolean> transformObjectCache = new ConcurrentHashMap<Class<?>, Boolean>(EndPoint.DEFAULT_THREAD_POOL_SIZE);
|
private static final Map<Class<?>, Boolean> transformObjectCache = new ConcurrentHashMap<Class<?>, Boolean>(EndPointBase.DEFAULT_THREAD_POOL_SIZE);
|
||||||
private static final RmiFieldCache fieldCache = RmiFieldCache.INSTANCE();
|
private static final RmiFieldCache fieldCache = RmiFieldCache.INSTANCE();
|
||||||
|
|
||||||
private final FastThreadLocal<Map<Object, Integer>> objectThreadLocals = new FastThreadLocal<Map<Object, Integer>>() {
|
private final FastThreadLocal<Map<Object, Integer>> objectThreadLocals = new FastThreadLocal<Map<Object, Integer>>() {
|
||||||
|
@ -15,7 +15,13 @@
|
|||||||
*/
|
*/
|
||||||
package dorkbox.network.pipeline.udp;
|
package dorkbox.network.pipeline.udp;
|
||||||
|
|
||||||
import dorkbox.network.connection.EndPoint;
|
import java.io.IOException;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import dorkbox.network.connection.EndPointBase;
|
||||||
import dorkbox.network.util.CryptoSerializationManager;
|
import dorkbox.network.util.CryptoSerializationManager;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import io.netty.buffer.Unpooled;
|
import io.netty.buffer.Unpooled;
|
||||||
@ -23,11 +29,6 @@ import io.netty.channel.ChannelHandler.Sharable;
|
|||||||
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
import io.netty.channel.socket.DatagramPacket;
|
import io.netty.channel.socket.DatagramPacket;
|
||||||
import io.netty.handler.codec.MessageToMessageEncoder;
|
import io.netty.handler.codec.MessageToMessageEncoder;
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.InetSocketAddress;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
@Sharable
|
@Sharable
|
||||||
// UDP uses messages --- NOT bytebuf!
|
// UDP uses messages --- NOT bytebuf!
|
||||||
@ -35,7 +36,7 @@ import java.util.List;
|
|||||||
public
|
public
|
||||||
class KryoEncoderUdp extends MessageToMessageEncoder<Object> {
|
class KryoEncoderUdp extends MessageToMessageEncoder<Object> {
|
||||||
|
|
||||||
private static final int maxSize = EndPoint.udpMaxSize;
|
private static final int maxSize = EndPointBase.udpMaxSize;
|
||||||
private final CryptoSerializationManager serializationManager;
|
private final CryptoSerializationManager serializationManager;
|
||||||
|
|
||||||
|
|
||||||
|
@ -53,7 +53,7 @@ import com.esotericsoftware.kryo.util.Util;
|
|||||||
import com.esotericsoftware.reflectasm.MethodAccess;
|
import com.esotericsoftware.reflectasm.MethodAccess;
|
||||||
|
|
||||||
import dorkbox.network.connection.Connection;
|
import dorkbox.network.connection.Connection;
|
||||||
import dorkbox.network.connection.EndPoint;
|
import dorkbox.network.connection.EndPointBase;
|
||||||
import dorkbox.network.connection.KryoExtra;
|
import dorkbox.network.connection.KryoExtra;
|
||||||
import dorkbox.network.util.CryptoSerializationManager;
|
import dorkbox.network.util.CryptoSerializationManager;
|
||||||
import dorkbox.network.util.RmiSerializationManager;
|
import dorkbox.network.util.RmiSerializationManager;
|
||||||
@ -101,7 +101,7 @@ class CachedMethod {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// the purpose of the method cache, is to accelerate looking up methods for specific class
|
// the purpose of the method cache, is to accelerate looking up methods for specific class
|
||||||
private static final Map<Class<?>, CachedMethod[]> methodCache = new ConcurrentHashMap<Class<?>, CachedMethod[]>(EndPoint.DEFAULT_THREAD_POOL_SIZE);
|
private static final Map<Class<?>, CachedMethod[]> methodCache = new ConcurrentHashMap<Class<?>, CachedMethod[]>(EndPointBase.DEFAULT_THREAD_POOL_SIZE);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -49,7 +49,7 @@ import com.esotericsoftware.kryo.util.IntMap;
|
|||||||
|
|
||||||
import dorkbox.network.connection.Connection;
|
import dorkbox.network.connection.Connection;
|
||||||
import dorkbox.network.connection.ConnectionImpl;
|
import dorkbox.network.connection.ConnectionImpl;
|
||||||
import dorkbox.network.connection.EndPoint;
|
import dorkbox.network.connection.EndPointBase;
|
||||||
import dorkbox.network.connection.Listener;
|
import dorkbox.network.connection.Listener;
|
||||||
import dorkbox.network.util.RmiSerializationManager;
|
import dorkbox.network.util.RmiSerializationManager;
|
||||||
import dorkbox.util.collections.ObjectIntMap;
|
import dorkbox.util.collections.ObjectIntMap;
|
||||||
@ -197,7 +197,7 @@ class RmiBridge {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Invokes the method on the object and, if necessary, sends the result back to the connection that made the invocation request. This
|
* Invokes the method on the object and, if necessary, sends the result back to the connection that made the invocation request. This
|
||||||
* method is invoked on the update thread of the {@link EndPoint} for this RmiBridge and unless an executor has been set.
|
* method is invoked on the update thread of the {@link EndPointBase} for this RmiBridge and unless an executor has been set.
|
||||||
*
|
*
|
||||||
* @param connection
|
* @param connection
|
||||||
* The remote side of this connection requested the invocation.
|
* The remote side of this connection requested the invocation.
|
||||||
|
@ -47,7 +47,7 @@ import org.slf4j.Logger;
|
|||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import dorkbox.network.connection.Connection;
|
import dorkbox.network.connection.Connection;
|
||||||
import dorkbox.network.connection.EndPoint;
|
import dorkbox.network.connection.EndPointBase;
|
||||||
import dorkbox.network.util.RmiSerializationManager;
|
import dorkbox.network.util.RmiSerializationManager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -195,8 +195,8 @@ class RmiProxyHandler implements InvocationHandler {
|
|||||||
return proxyString;
|
return proxyString;
|
||||||
}
|
}
|
||||||
|
|
||||||
EndPoint endPoint = this.connection.getEndPoint();
|
EndPointBase endPointBaseConnection = this.connection.getEndPoint();
|
||||||
final RmiSerializationManager serializationManager = endPoint.getSerialization();
|
final RmiSerializationManager serializationManager = endPointBaseConnection.getSerialization();
|
||||||
|
|
||||||
InvokeMethod invokeMethod = new InvokeMethod();
|
InvokeMethod invokeMethod = new InvokeMethod();
|
||||||
invokeMethod.objectID = this.objectID;
|
invokeMethod.objectID = this.objectID;
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
package dorkbox.network;
|
package dorkbox.network;
|
||||||
|
|
||||||
|
|
||||||
import static dorkbox.network.connection.EndPoint.THREADGROUP_NAME;
|
import static dorkbox.network.connection.EndPointBase.THREADGROUP_NAME;
|
||||||
import static org.junit.Assert.fail;
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -34,7 +34,7 @@ import ch.qos.logback.classic.encoder.PatternLayoutEncoder;
|
|||||||
import ch.qos.logback.classic.joran.JoranConfigurator;
|
import ch.qos.logback.classic.joran.JoranConfigurator;
|
||||||
import ch.qos.logback.classic.spi.ILoggingEvent;
|
import ch.qos.logback.classic.spi.ILoggingEvent;
|
||||||
import ch.qos.logback.core.ConsoleAppender;
|
import ch.qos.logback.core.ConsoleAppender;
|
||||||
import dorkbox.network.connection.EndPoint;
|
import dorkbox.network.connection.EndPointBase;
|
||||||
import dorkbox.util.entropy.Entropy;
|
import dorkbox.util.entropy.Entropy;
|
||||||
import dorkbox.util.entropy.SimpleEntropy;
|
import dorkbox.util.entropy.SimpleEntropy;
|
||||||
import dorkbox.util.exceptions.InitializationException;
|
import dorkbox.util.exceptions.InitializationException;
|
||||||
@ -57,7 +57,7 @@ class BaseTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
volatile boolean fail_check;
|
volatile boolean fail_check;
|
||||||
private final ArrayList<EndPoint> endPoints = new ArrayList<EndPoint>();
|
private final ArrayList<EndPointBase> endPointBaseConnections = new ArrayList<EndPointBase>();
|
||||||
|
|
||||||
public
|
public
|
||||||
BaseTest() {
|
BaseTest() {
|
||||||
@ -107,8 +107,8 @@ class BaseTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public
|
public
|
||||||
void addEndPoint(final EndPoint endPoint) {
|
void addEndPoint(final EndPointBase endPointBaseConnection) {
|
||||||
this.endPoints.add(endPoint);
|
this.endPointBaseConnections.add(endPointBaseConnection);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -157,12 +157,12 @@ class BaseTest {
|
|||||||
|
|
||||||
private
|
private
|
||||||
void stopEndPoints_outsideThread() {
|
void stopEndPoints_outsideThread() {
|
||||||
synchronized (BaseTest.this.endPoints) {
|
synchronized (BaseTest.this.endPointBaseConnections) {
|
||||||
for (EndPoint endPoint : BaseTest.this.endPoints) {
|
for (EndPointBase endPointBaseConnection : BaseTest.this.endPointBaseConnections) {
|
||||||
endPoint.stop();
|
endPointBaseConnection.stop();
|
||||||
endPoint.waitForShutdown();
|
endPointBaseConnection.waitForShutdown();
|
||||||
}
|
}
|
||||||
BaseTest.this.endPoints.clear();
|
BaseTest.this.endPointBaseConnections.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -226,8 +226,8 @@ class BaseTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
synchronized (this.endPoints) {
|
synchronized (this.endPointBaseConnections) {
|
||||||
if (this.endPoints.isEmpty()) {
|
if (this.endPointBaseConnections.isEmpty()) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,7 @@ import org.junit.Test;
|
|||||||
|
|
||||||
import dorkbox.network.connection.Connection;
|
import dorkbox.network.connection.Connection;
|
||||||
import dorkbox.network.connection.CryptoSerializationManager;
|
import dorkbox.network.connection.CryptoSerializationManager;
|
||||||
import dorkbox.network.connection.EndPoint;
|
import dorkbox.network.connection.EndPointBase;
|
||||||
import dorkbox.network.connection.Listener;
|
import dorkbox.network.connection.Listener;
|
||||||
import dorkbox.util.SerializationManager;
|
import dorkbox.util.SerializationManager;
|
||||||
import dorkbox.util.exceptions.InitializationException;
|
import dorkbox.util.exceptions.InitializationException;
|
||||||
@ -42,7 +42,7 @@ class ConnectionTest extends BaseTest {
|
|||||||
System.out.println("---- " + "Local");
|
System.out.println("---- " + "Local");
|
||||||
|
|
||||||
Configuration configuration = new Configuration();
|
Configuration configuration = new Configuration();
|
||||||
configuration.localChannelName = EndPoint.LOCAL_CHANNEL;
|
configuration.localChannelName = EndPointBase.LOCAL_CHANNEL;
|
||||||
configuration.serialization = CryptoSerializationManager.DEFAULT();
|
configuration.serialization = CryptoSerializationManager.DEFAULT();
|
||||||
register(configuration.serialization);
|
register(configuration.serialization);
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ import org.slf4j.Logger;
|
|||||||
|
|
||||||
import dorkbox.network.connection.Connection;
|
import dorkbox.network.connection.Connection;
|
||||||
import dorkbox.network.connection.ConnectionImpl;
|
import dorkbox.network.connection.ConnectionImpl;
|
||||||
import dorkbox.network.connection.EndPoint;
|
import dorkbox.network.connection.EndPointBase;
|
||||||
import dorkbox.network.connection.Listener;
|
import dorkbox.network.connection.Listener;
|
||||||
import dorkbox.network.connection.Listeners;
|
import dorkbox.network.connection.Listeners;
|
||||||
import dorkbox.network.rmi.RmiBridge;
|
import dorkbox.network.rmi.RmiBridge;
|
||||||
@ -64,8 +64,8 @@ class ListenerTest extends BaseTest {
|
|||||||
// quick and dirty test to also test connection sub-classing
|
// quick and dirty test to also test connection sub-classing
|
||||||
class TestConnectionA extends ConnectionImpl {
|
class TestConnectionA extends ConnectionImpl {
|
||||||
public
|
public
|
||||||
TestConnectionA(final Logger logger, final EndPoint endPoint, final RmiBridge rmiBridge) {
|
TestConnectionA(final Logger logger, final EndPointBase endPointBaseConnection, final RmiBridge rmiBridge) {
|
||||||
super(logger, endPoint, rmiBridge);
|
super(logger, endPointBaseConnection, rmiBridge);
|
||||||
}
|
}
|
||||||
|
|
||||||
public
|
public
|
||||||
@ -77,8 +77,8 @@ class ListenerTest extends BaseTest {
|
|||||||
|
|
||||||
class TestConnectionB extends TestConnectionA {
|
class TestConnectionB extends TestConnectionA {
|
||||||
public
|
public
|
||||||
TestConnectionB(final Logger logger, final EndPoint endPoint, final RmiBridge rmiBridge) {
|
TestConnectionB(final Logger logger, final EndPointBase endPointBaseConnection, final RmiBridge rmiBridge) {
|
||||||
super(logger, endPoint, rmiBridge);
|
super(logger, endPointBaseConnection, rmiBridge);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -109,7 +109,7 @@ class ListenerTest extends BaseTest {
|
|||||||
Server server = new Server(configuration) {
|
Server server = new Server(configuration) {
|
||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
TestConnectionA newConnection(final Logger logger, final EndPoint endPoint, final RmiBridge rmiBridge) {
|
TestConnectionA newConnection(final Logger logger, final EndPointBase endPoint, final RmiBridge rmiBridge) {
|
||||||
return new TestConnectionA(logger, endPoint, rmiBridge);
|
return new TestConnectionA(logger, endPoint, rmiBridge);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -30,7 +30,7 @@ import org.junit.Test;
|
|||||||
|
|
||||||
import dorkbox.network.connection.Connection;
|
import dorkbox.network.connection.Connection;
|
||||||
import dorkbox.network.connection.CryptoSerializationManager;
|
import dorkbox.network.connection.CryptoSerializationManager;
|
||||||
import dorkbox.network.connection.EndPoint;
|
import dorkbox.network.connection.EndPointBase;
|
||||||
import dorkbox.network.connection.Listener;
|
import dorkbox.network.connection.Listener;
|
||||||
import dorkbox.network.connection.Listeners;
|
import dorkbox.network.connection.Listeners;
|
||||||
import dorkbox.util.SerializationManager;
|
import dorkbox.util.SerializationManager;
|
||||||
@ -52,8 +52,8 @@ class PingPongTest extends BaseTest {
|
|||||||
public
|
public
|
||||||
void pingPong() throws InitializationException, SecurityException, IOException, InterruptedException {
|
void pingPong() throws InitializationException, SecurityException, IOException, InterruptedException {
|
||||||
// UDP data is kinda big. Make sure it fits into one packet.
|
// UDP data is kinda big. Make sure it fits into one packet.
|
||||||
int origSize = EndPoint.udpMaxSize;
|
int origSize = EndPointBase.udpMaxSize;
|
||||||
EndPoint.udpMaxSize = 2048;
|
EndPointBase.udpMaxSize = 2048;
|
||||||
|
|
||||||
this.fail = "Data not received.";
|
this.fail = "Data not received.";
|
||||||
|
|
||||||
@ -192,7 +192,7 @@ class PingPongTest extends BaseTest {
|
|||||||
fail(this.fail);
|
fail(this.fail);
|
||||||
}
|
}
|
||||||
|
|
||||||
EndPoint.udpMaxSize = origSize;
|
EndPointBase.udpMaxSize = origSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static
|
private static
|
||||||
|
@ -30,7 +30,7 @@ import org.junit.Test;
|
|||||||
|
|
||||||
import dorkbox.network.connection.Connection;
|
import dorkbox.network.connection.Connection;
|
||||||
import dorkbox.network.connection.CryptoSerializationManager;
|
import dorkbox.network.connection.CryptoSerializationManager;
|
||||||
import dorkbox.network.connection.EndPoint;
|
import dorkbox.network.connection.EndPointBase;
|
||||||
import dorkbox.network.connection.Listener;
|
import dorkbox.network.connection.Listener;
|
||||||
import dorkbox.network.connection.Listeners;
|
import dorkbox.network.connection.Listeners;
|
||||||
import dorkbox.util.exceptions.InitializationException;
|
import dorkbox.util.exceptions.InitializationException;
|
||||||
@ -47,8 +47,8 @@ class UnregisteredClassTest extends BaseTest {
|
|||||||
@Test
|
@Test
|
||||||
public
|
public
|
||||||
void unregisteredClasses() throws InitializationException, SecurityException, IOException, InterruptedException {
|
void unregisteredClasses() throws InitializationException, SecurityException, IOException, InterruptedException {
|
||||||
int origSize = EndPoint.udpMaxSize;
|
int origSize = EndPointBase.udpMaxSize;
|
||||||
EndPoint.udpMaxSize = 2048;
|
EndPointBase.udpMaxSize = 2048;
|
||||||
|
|
||||||
Configuration configuration = new Configuration();
|
Configuration configuration = new Configuration();
|
||||||
configuration.tcpPort = tcpPort;
|
configuration.tcpPort = tcpPort;
|
||||||
@ -179,7 +179,7 @@ class UnregisteredClassTest extends BaseTest {
|
|||||||
fail(this.fail);
|
fail(this.fail);
|
||||||
}
|
}
|
||||||
|
|
||||||
EndPoint.udpMaxSize = origSize;
|
EndPointBase.udpMaxSize = origSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
private
|
private
|
||||||
|
Loading…
Reference in New Issue
Block a user