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.Connection;
|
||||
import dorkbox.network.connection.EndPoint;
|
||||
import dorkbox.network.connection.EndPointBase;
|
||||
import dorkbox.network.connection.EndPointClient;
|
||||
import dorkbox.network.connection.idle.IdleBridge;
|
||||
import dorkbox.network.connection.idle.IdleSender;
|
||||
|
@ -333,7 +333,7 @@ class Client<C extends Connection> extends EndPointClient<C> implements Connecti
|
|||
@SuppressWarnings("rawtypes")
|
||||
@Override
|
||||
public
|
||||
EndPoint getEndPoint() {
|
||||
EndPointBase getEndPoint() {
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -450,7 +450,7 @@ class Client<C extends Connection> extends EndPointClient<C> implements Connecti
|
|||
* <p/>
|
||||
* Make <b>sure</b> that you only call this <b>after</b> the client connects!
|
||||
* <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
|
||||
C getConnection() {
|
||||
|
|
|
@ -17,7 +17,7 @@ package dorkbox.network;
|
|||
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
import dorkbox.network.connection.EndPoint;
|
||||
import dorkbox.network.connection.EndPointBase;
|
||||
import dorkbox.network.store.SettingsStore;
|
||||
import dorkbox.network.util.CryptoSerializationManager;
|
||||
|
||||
|
@ -76,7 +76,7 @@ class Configuration {
|
|||
public static
|
||||
Configuration localOnly() {
|
||||
Configuration configuration = new Configuration();
|
||||
configuration.localChannelName = EndPoint.LOCAL_CHANNEL;
|
||||
configuration.localChannelName = EndPointBase.LOCAL_CHANNEL;
|
||||
|
||||
return configuration;
|
||||
}
|
||||
|
|
|
@ -22,16 +22,13 @@ import static io.netty.util.internal.ObjectUtil.intValue;
|
|||
import java.net.IDN;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.security.AccessControlException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
|
||||
|
@ -88,30 +85,7 @@ import io.netty.util.internal.PlatformDependent;
|
|||
*/
|
||||
@SuppressWarnings({"unused", "WeakerAccess"})
|
||||
public
|
||||
class DnsClient {
|
||||
|
||||
// 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) {
|
||||
}
|
||||
}
|
||||
class DnsClient extends EndPoint {
|
||||
|
||||
/**
|
||||
* This is a list of all of the public DNS servers to query, when submitting DNS queries
|
||||
|
@ -241,13 +215,7 @@ class DnsClient {
|
|||
*/
|
||||
public
|
||||
DnsClient(Collection<InetSocketAddress> nameServerAddresses) {
|
||||
// setup the thread group to easily ID what the following threads belong to (and their spawned threads...)
|
||||
SecurityManager s = System.getSecurityManager();
|
||||
threadGroup = new ThreadGroup(s != null
|
||||
? s.getThreadGroup()
|
||||
: Thread.currentThread()
|
||||
.getThreadGroup(), THREAD_NAME);
|
||||
threadGroup.setDaemon(true);
|
||||
super(DnsClient.class);
|
||||
|
||||
if (PlatformDependent.isAndroid()) {
|
||||
// android ONLY supports OIO (not NIO)
|
||||
|
@ -264,6 +232,8 @@ class DnsClient {
|
|||
channelType = NioDatagramChannel.class;
|
||||
}
|
||||
|
||||
manageForShutdown(eventLoopGroup);
|
||||
|
||||
// NOTE: A/AAAA use the built-in decoder
|
||||
|
||||
customDecoders.put(DnsRecordType.MX, new MailExchangerDecoder());
|
||||
|
@ -601,6 +571,35 @@ class DnsClient {
|
|||
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
|
||||
*
|
||||
|
@ -720,78 +719,6 @@ class DnsClient {
|
|||
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
|
||||
ServiceRecord resolveSRV(final String hostname) {
|
||||
return resolve(hostname, DnsRecordType.SRV);
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
package dorkbox.network;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
|
||||
|
@ -83,6 +84,8 @@ class Server<C extends Connection> extends EndPointServer<C> {
|
|||
private final String localChannelName;
|
||||
private final String hostName;
|
||||
|
||||
private final CountDownLatch blockUntilDone = new CountDownLatch(1);
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
@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.
|
||||
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
|
||||
// back to the network stack
|
||||
|
@ -117,9 +117,9 @@ class ConnectionImpl extends ChannelInboundHandlerAdapter implements ICryptoConn
|
|||
*/
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
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.endPoint = endPoint;
|
||||
this.endPointBaseConnection = endPointBaseConnection;
|
||||
this.rmiBridge = rmiBridge;
|
||||
}
|
||||
|
||||
|
@ -214,8 +214,8 @@ class ConnectionImpl extends ChannelInboundHandlerAdapter implements ICryptoConn
|
|||
*/
|
||||
@Override
|
||||
public
|
||||
EndPoint<Connection> getEndPoint() {
|
||||
return this.endPoint;
|
||||
EndPointBase<Connection> getEndPoint() {
|
||||
return this.endPointBaseConnection;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -614,7 +614,7 @@ class ConnectionImpl extends ChannelInboundHandlerAdapter implements ICryptoConn
|
|||
void close() {
|
||||
// only close if we aren't already in the middle of closing.
|
||||
if (this.closeInProgress.compareAndSet(false, true)) {
|
||||
int idleTimeoutMs = this.endPoint.getIdleTimeout();
|
||||
int idleTimeoutMs = this.endPointBaseConnection.getIdleTimeout();
|
||||
if (idleTimeoutMs == 0) {
|
||||
// default is 2 second timeout, in milliseconds.
|
||||
idleTimeoutMs = 2000;
|
||||
|
@ -714,7 +714,7 @@ class ConnectionImpl extends ChannelInboundHandlerAdapter implements ICryptoConn
|
|||
@Override
|
||||
public final
|
||||
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
|
||||
// meaning --
|
||||
// I add one listener, and ALL connections are notified of that listener.
|
||||
|
@ -726,15 +726,15 @@ class ConnectionImpl extends ChannelInboundHandlerAdapter implements ICryptoConn
|
|||
// is empty, we can remove it from this connection.
|
||||
synchronized (this) {
|
||||
if (this.localListenerManager == null) {
|
||||
this.localListenerManager = ((EndPointServer<Connection>) this.endPoint).addListenerManager(this);
|
||||
this.localListenerManager = ((EndPointServer<Connection>) this.endPointBaseConnection).addListenerManager(this);
|
||||
}
|
||||
this.localListenerManager.add(listener);
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
this.endPoint.listeners()
|
||||
.add(listener);
|
||||
this.endPointBaseConnection.listeners()
|
||||
.add(listener);
|
||||
}
|
||||
|
||||
return this;
|
||||
|
@ -756,7 +756,7 @@ class ConnectionImpl extends ChannelInboundHandlerAdapter implements ICryptoConn
|
|||
@Override
|
||||
public final
|
||||
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
|
||||
// meaning --
|
||||
// I add one listener, and ALL connections are notified of that listener.
|
||||
|
@ -771,14 +771,14 @@ class ConnectionImpl extends ChannelInboundHandlerAdapter implements ICryptoConn
|
|||
this.localListenerManager.remove(listener);
|
||||
|
||||
if (!this.localListenerManager.hasListeners()) {
|
||||
((EndPointServer<Connection>) this.endPoint).removeListenerManager(this);
|
||||
((EndPointServer<Connection>) this.endPointBaseConnection).removeListenerManager(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.endPoint.listeners()
|
||||
.remove(listener);
|
||||
this.endPointBaseConnection.listeners()
|
||||
.remove(listener);
|
||||
}
|
||||
|
||||
return this;
|
||||
|
@ -791,7 +791,7 @@ class ConnectionImpl extends ChannelInboundHandlerAdapter implements ICryptoConn
|
|||
@Override
|
||||
public final
|
||||
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
|
||||
// meaning --
|
||||
// I add one listener, and ALL connections are notified of that listener.
|
||||
|
@ -806,13 +806,13 @@ class ConnectionImpl extends ChannelInboundHandlerAdapter implements ICryptoConn
|
|||
this.localListenerManager.removeAll();
|
||||
this.localListenerManager = null;
|
||||
|
||||
((EndPointServer<Connection>) this.endPoint).removeListenerManager(this);
|
||||
((EndPointServer<Connection>) this.endPointBaseConnection).removeListenerManager(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.endPoint.listeners()
|
||||
.removeAll();
|
||||
this.endPointBaseConnection.listeners()
|
||||
.removeAll();
|
||||
}
|
||||
|
||||
return this;
|
||||
|
@ -826,7 +826,7 @@ class ConnectionImpl extends ChannelInboundHandlerAdapter implements ICryptoConn
|
|||
@Override
|
||||
public final
|
||||
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
|
||||
// meaning --
|
||||
// I add one listener, and ALL connections are notified of that listener.
|
||||
|
@ -842,14 +842,14 @@ class ConnectionImpl extends ChannelInboundHandlerAdapter implements ICryptoConn
|
|||
|
||||
if (!this.localListenerManager.hasListeners()) {
|
||||
this.localListenerManager = null;
|
||||
((EndPointServer<Connection>) this.endPoint).removeListenerManager(this);
|
||||
((EndPointServer<Connection>) this.endPointBaseConnection).removeListenerManager(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.endPoint.listeners()
|
||||
.removeAll(classType);
|
||||
this.endPointBaseConnection.listeners()
|
||||
.removeAll(classType);
|
||||
}
|
||||
|
||||
return this;
|
||||
|
@ -1111,7 +1111,7 @@ class ConnectionImpl extends ChannelInboundHandlerAdapter implements ICryptoConn
|
|||
public
|
||||
<T> int getRegisteredId(final T object) {
|
||||
// always check local before checking global, because less contention on the synchronization
|
||||
RmiBridge globalRmiBridge = endPoint.globalRmiBridge;
|
||||
RmiBridge globalRmiBridge = endPointBaseConnection.globalRmiBridge;
|
||||
|
||||
if (globalRmiBridge == null) {
|
||||
throw new NullPointerException("Unable to call 'getRegisteredId' when the globalRmiBridge is null!");
|
||||
|
@ -1155,7 +1155,7 @@ class ConnectionImpl extends ChannelInboundHandlerAdapter implements ICryptoConn
|
|||
public
|
||||
Object getImplementationObject(final int objectID) {
|
||||
if (RmiBridge.isGlobal(objectID)) {
|
||||
RmiBridge globalRmiBridge = endPoint.globalRmiBridge;
|
||||
RmiBridge globalRmiBridge = endPointBaseConnection.globalRmiBridge;
|
||||
|
||||
if (globalRmiBridge == 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.
|
||||
* <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,
|
||||
* {@link EndPoint#send().flush()} must be called manually.
|
||||
* {@link EndPointBase#send().flush()} must be called manually.
|
||||
* <p/>
|
||||
* {@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;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.security.AccessControlException;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
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.OS;
|
||||
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.ChannelFuture;
|
||||
import io.netty.channel.EventLoopGroup;
|
||||
import io.netty.util.NetUtil;
|
||||
import io.netty.util.concurrent.EventExecutor;
|
||||
import io.netty.util.concurrent.Future;
|
||||
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
|
||||
class EndPoint<C extends Connection> {
|
||||
// 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;
|
||||
|
||||
|
||||
public
|
||||
class EndPoint {
|
||||
// duplicated in DnsClient
|
||||
static {
|
||||
//noinspection Duplicates
|
||||
|
@ -137,9 +35,10 @@ class EndPoint<C extends Connection> {
|
|||
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
|
||||
// loading them normally. This calls AND FIXES this issue.
|
||||
if (OS.javaVersion == 6) {
|
||||
if (PlatformDependent.hasUnsafe()) {
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
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 ThreadGroup threadGroup;
|
||||
protected final Class<? extends EndPoint<C>> type;
|
||||
|
||||
protected final ConnectionManager<C> connectionManager;
|
||||
protected final dorkbox.network.util.CryptoSerializationManager serializationManager;
|
||||
protected final RegistrationWrapper<C> registrationWrapper;
|
||||
protected final Class<? extends EndPoint> type;
|
||||
|
||||
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
|
||||
private final List<EventLoopGroup> eventLoopGroups = new ArrayList<EventLoopGroup>(8);
|
||||
|
@ -176,128 +89,30 @@ 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)
|
||||
private Thread shutdownHook;
|
||||
|
||||
private final CountDownLatch blockUntilDone = new CountDownLatch(1);
|
||||
|
||||
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
|
||||
EndPoint(Class<? extends EndPoint> type, final Configuration options) throws InitializationException, SecurityException, IOException {
|
||||
this.type = (Class<? extends EndPoint<C>>) type;
|
||||
EndPoint(final Class<? extends EndPoint> type) {
|
||||
this.type = type;
|
||||
|
||||
// setup the thread group to easily ID what the following threads belong to (and their spawned threads...)
|
||||
SecurityManager s = System.getSecurityManager();
|
||||
threadGroup = new ThreadGroup(s != null
|
||||
? s.getThreadGroup()
|
||||
: Thread.currentThread()
|
||||
.getThreadGroup(), type.getSimpleName() + " " + THREADGROUP_NAME);
|
||||
? s.getThreadGroup()
|
||||
: Thread.currentThread()
|
||||
.getThreadGroup(), type.getSimpleName() + " " + THREADGROUP_NAME);
|
||||
threadGroup.setDaemon(true);
|
||||
|
||||
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() {
|
||||
@Override
|
||||
public
|
||||
void run() {
|
||||
// connectionManager.shutdown accurately reflects the state of the app. Safe to use here
|
||||
if (EndPoint.this.connectionManager != null && !EndPoint.this.connectionManager.shutdown.get()) {
|
||||
if (EndPoint.this.shouldShutdownHookRun()) {
|
||||
EndPoint.this.stop();
|
||||
}
|
||||
}
|
||||
|
@ -309,89 +124,6 @@ class EndPoint<C extends Connection> {
|
|||
} catch (Throwable ignored) {
|
||||
// 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
|
||||
protected void shutdownChannels() {
|
||||
void shutdownChannels() {
|
||||
synchronized (shutdownChannelList) {
|
||||
// now we stop all of our channels
|
||||
for (ChannelFuture f : this.shutdownChannelList) {
|
||||
|
@ -579,6 +164,7 @@ class EndPoint<C extends Connection> {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
protected final
|
||||
String stopWithErrorMessage(Logger logger2, String errorMessage, Throwable throwable) {
|
||||
if (logger2.isDebugEnabled() && throwable != null) {
|
||||
|
@ -593,6 +179,16 @@ class EndPoint<C extends Connection> {
|
|||
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.
|
||||
* <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
|
||||
private
|
||||
void stopInThread() {
|
||||
|
@ -676,14 +294,11 @@ class EndPoint<C extends Connection> {
|
|||
Thread.yield();
|
||||
}
|
||||
|
||||
closeConnections();
|
||||
|
||||
// this does a closeConnections + clear_listeners
|
||||
this.connectionManager.stop();
|
||||
shutdownChannelsPre();
|
||||
|
||||
shutdownChannels();
|
||||
|
||||
this.logger.info("Stopping endpoint");
|
||||
this.logger.info("Stopping endpoint.");
|
||||
|
||||
// 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!
|
||||
|
@ -701,10 +316,7 @@ class EndPoint<C extends Connection> {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
// shutdown the database store
|
||||
this.propertyStore.close();
|
||||
|
||||
stopExtraActionsInternal();
|
||||
|
||||
// when the eventloop closes, the associated selectors are ALSO closed!
|
||||
stopExtraActions();
|
||||
|
@ -717,13 +329,6 @@ class EndPoint<C extends Connection> {
|
|||
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.
|
||||
*/
|
||||
|
@ -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
|
||||
public
|
||||
String toString() {
|
||||
|
@ -791,15 +352,4 @@ class EndPoint<C extends Connection> {
|
|||
String getName() {
|
||||
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.
|
||||
*/
|
||||
public
|
||||
class EndPointClient<C extends Connection> extends EndPoint<C> implements Runnable {
|
||||
class EndPointClient<C extends Connection> extends EndPointBase<C> implements Runnable {
|
||||
|
||||
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.
|
||||
*/
|
||||
public
|
||||
class EndPointServer<C extends Connection> extends EndPoint<C> {
|
||||
class EndPointServer<C extends Connection> extends EndPointBase<C> {
|
||||
|
||||
public
|
||||
EndPointServer(final Configuration options) throws InitializationException, SecurityException, IOException {
|
||||
|
|
|
@ -61,7 +61,7 @@ class KryoExtra<C extends ICryptoConnection> extends Kryo {
|
|||
|
||||
|
||||
// writing data
|
||||
private final ByteBuf tempBuffer = Unpooled.buffer(EndPoint.udpMaxSize);
|
||||
private final ByteBuf tempBuffer = Unpooled.buffer(EndPointBase.udpMaxSize);
|
||||
private LZ4Compressor compressor = factory.fastCompressor();
|
||||
|
||||
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 {
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
|
|
@ -80,7 +80,7 @@ class PropertyStore extends SettingsStore {
|
|||
@Override
|
||||
public synchronized
|
||||
ECPrivateKeyParameters getPrivateKey() throws dorkbox.util.exceptions.SecurityException {
|
||||
checkAccess(EndPoint.class);
|
||||
checkAccess(EndPointBase.class);
|
||||
|
||||
return servers.get(DB_Server.IP_SELF)
|
||||
.getPrivateKey();
|
||||
|
@ -92,7 +92,7 @@ class PropertyStore extends SettingsStore {
|
|||
@Override
|
||||
public synchronized
|
||||
void savePrivateKey(final ECPrivateKeyParameters serverPrivateKey) throws SecurityException {
|
||||
checkAccess(EndPoint.class);
|
||||
checkAccess(EndPointBase.class);
|
||||
|
||||
servers.get(DB_Server.IP_SELF)
|
||||
.setPrivateKey(serverPrivateKey);
|
||||
|
@ -107,7 +107,7 @@ class PropertyStore extends SettingsStore {
|
|||
@Override
|
||||
public synchronized
|
||||
ECPublicKeyParameters getPublicKey() throws SecurityException {
|
||||
checkAccess(EndPoint.class);
|
||||
checkAccess(EndPointBase.class);
|
||||
|
||||
return servers.get(DB_Server.IP_SELF)
|
||||
.getPublicKey();
|
||||
|
@ -119,7 +119,7 @@ class PropertyStore extends SettingsStore {
|
|||
@Override
|
||||
public synchronized
|
||||
void savePublicKey(final ECPublicKeyParameters serverPublicKey) throws SecurityException {
|
||||
checkAccess(EndPoint.class);
|
||||
checkAccess(EndPointBase.class);
|
||||
|
||||
servers.get(DB_Server.IP_SELF)
|
||||
.setPublicKey(serverPublicKey);
|
||||
|
|
|
@ -53,7 +53,7 @@ class RegistrationWrapper<C extends Connection> implements UdpServer {
|
|||
private final KryoEncoder kryoEncoder;
|
||||
private final KryoEncoderCrypto kryoEncoderCrypto;
|
||||
|
||||
private final EndPoint<C> endPoint;
|
||||
private final EndPointBase<C> endPointBaseConnection;
|
||||
|
||||
// keeps track of connections (TCP/UDP-client)
|
||||
private final ReentrantLock channelMapLock = new ReentrantLock();
|
||||
|
@ -77,16 +77,16 @@ class RegistrationWrapper<C extends Connection> implements UdpServer {
|
|||
|
||||
|
||||
public
|
||||
RegistrationWrapper(final EndPoint<C> endPoint,
|
||||
RegistrationWrapper(final EndPointBase<C> endPointBaseConnection,
|
||||
final Logger logger,
|
||||
final KryoEncoder kryoEncoder,
|
||||
final KryoEncoderCrypto kryoEncoderCrypto) {
|
||||
this.endPoint = endPoint;
|
||||
this.endPointBaseConnection = endPointBaseConnection;
|
||||
this.logger = logger;
|
||||
this.kryoEncoder = kryoEncoder;
|
||||
this.kryoEncoderCrypto = kryoEncoderCrypto;
|
||||
|
||||
if (endPoint instanceof EndPointServer) {
|
||||
if (endPointBaseConnection instanceof EndPointServer) {
|
||||
this.udpRemoteMap = new ObjectMap<InetSocketAddress, ConnectionImpl>(32, ConnectionManager.LOAD_FACTOR);
|
||||
}
|
||||
else {
|
||||
|
@ -99,7 +99,7 @@ class RegistrationWrapper<C extends Connection> implements UdpServer {
|
|||
*/
|
||||
public
|
||||
boolean rmiEnabled() {
|
||||
return endPoint.globalRmiBridge != null;
|
||||
return endPointBaseConnection.globalRmiBridge != null;
|
||||
}
|
||||
|
||||
public
|
||||
|
@ -135,7 +135,7 @@ class RegistrationWrapper<C extends Connection> implements UdpServer {
|
|||
*/
|
||||
public
|
||||
int getIdleTimeout() {
|
||||
return this.endPoint.getIdleTimeout();
|
||||
return this.endPointBaseConnection.getIdleTimeout();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -146,7 +146,7 @@ class RegistrationWrapper<C extends Connection> implements UdpServer {
|
|||
*/
|
||||
public
|
||||
boolean registerNextProtocol0() {
|
||||
return this.endPoint.registerNextProtocol0();
|
||||
return this.endPointBaseConnection.registerNextProtocol0();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -155,7 +155,7 @@ class RegistrationWrapper<C extends Connection> implements UdpServer {
|
|||
*/
|
||||
public
|
||||
void connectionConnected0(ConnectionImpl networkConnection) {
|
||||
this.endPoint.connectionConnected0(networkConnection);
|
||||
this.endPointBaseConnection.connectionConnected0(networkConnection);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -166,22 +166,22 @@ class RegistrationWrapper<C extends Connection> implements UdpServer {
|
|||
*/
|
||||
public
|
||||
Connection connection0(MetaChannel metaChannel) {
|
||||
return this.endPoint.connection0(metaChannel);
|
||||
return this.endPointBaseConnection.connection0(metaChannel);
|
||||
}
|
||||
|
||||
public
|
||||
SecureRandom getSecureRandom() {
|
||||
return this.endPoint.secureRandom;
|
||||
return this.endPointBaseConnection.secureRandom;
|
||||
}
|
||||
|
||||
public
|
||||
ECPublicKeyParameters getPublicKey() {
|
||||
return this.endPoint.publicKey;
|
||||
return this.endPointBaseConnection.publicKey;
|
||||
}
|
||||
|
||||
public
|
||||
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();
|
||||
byte[] hostAddress = address.getAddress();
|
||||
|
||||
ECPublicKeyParameters savedPublicKey = this.endPoint.propertyStore.getRegisteredServerKey(hostAddress);
|
||||
ECPublicKeyParameters savedPublicKey = this.endPointBaseConnection.propertyStore.getRegisteredServerKey(hostAddress);
|
||||
Logger logger2 = this.logger;
|
||||
if (savedPublicKey == null) {
|
||||
if (logger2.isDebugEnabled()) {
|
||||
logger2.debug("Adding new remote IP address key for {}", address.getHostAddress());
|
||||
}
|
||||
this.endPoint.propertyStore.addRegisteredServerKey(hostAddress, publicKey);
|
||||
this.endPointBaseConnection.propertyStore.addRegisteredServerKey(hostAddress, publicKey);
|
||||
}
|
||||
else {
|
||||
// COMPARE!
|
||||
|
@ -216,7 +216,7 @@ class RegistrationWrapper<C extends Connection> implements UdpServer {
|
|||
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);
|
||||
return true;
|
||||
}
|
||||
|
@ -234,7 +234,7 @@ class RegistrationWrapper<C extends Connection> implements UdpServer {
|
|||
@SuppressWarnings("AutoBoxing")
|
||||
public
|
||||
void removeRegisteredServerKey(final byte[] hostAddress) throws SecurityException {
|
||||
ECPublicKeyParameters savedPublicKey = this.endPoint.propertyStore.getRegisteredServerKey(hostAddress);
|
||||
ECPublicKeyParameters savedPublicKey = this.endPointBaseConnection.propertyStore.getRegisteredServerKey(hostAddress);
|
||||
if (savedPublicKey != null) {
|
||||
Logger logger2 = this.logger;
|
||||
if (logger2.isDebugEnabled()) {
|
||||
|
@ -244,7 +244,7 @@ class RegistrationWrapper<C extends Connection> implements UdpServer {
|
|||
hostAddress[2],
|
||||
hostAddress[3]);
|
||||
}
|
||||
this.endPoint.propertyStore.removeRegisteredServerKey(hostAddress);
|
||||
this.endPointBaseConnection.propertyStore.removeRegisteredServerKey(hostAddress);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -316,8 +316,8 @@ class RegistrationWrapper<C extends Connection> implements UdpServer {
|
|||
|
||||
public
|
||||
void abortRegistrationIfClient() {
|
||||
if (this.endPoint instanceof EndPointClient) {
|
||||
((EndPointClient<C>) this.endPoint).abortRegistration();
|
||||
if (this.endPointBaseConnection instanceof EndPointClient) {
|
||||
((EndPointClient<C>) this.endPointBaseConnection).abortRegistration();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
package dorkbox.network.connection.registration;
|
||||
|
||||
import dorkbox.network.connection.Connection;
|
||||
import dorkbox.network.connection.EndPoint;
|
||||
import dorkbox.network.connection.EndPointBase;
|
||||
import dorkbox.network.connection.RegistrationWrapper;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelHandler.Sharable;
|
||||
|
@ -94,7 +94,7 @@ class RegistrationHandler<C extends Connection> extends ChannelInboundHandlerAda
|
|||
|
||||
// also, once we notify, we unregister this.
|
||||
if (registrationWrapper != null) {
|
||||
MetaChannel metaChannel = registrationWrapper.closeChannel(channel, EndPoint.maxShutdownWaitTimeInMilliSeconds);
|
||||
MetaChannel metaChannel = registrationWrapper.closeChannel(channel, EndPointBase.maxShutdownWaitTimeInMilliSeconds);
|
||||
registrationWrapper.abortRegistrationIfClient();
|
||||
|
||||
return metaChannel;
|
||||
|
|
|
@ -15,6 +15,10 @@
|
|||
*/
|
||||
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.RegistrationWrapper;
|
||||
import dorkbox.network.connection.registration.MetaChannel;
|
||||
|
@ -23,9 +27,6 @@ import dorkbox.network.pipeline.LocalRmiDecoder;
|
|||
import dorkbox.network.pipeline.LocalRmiEncoder;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import static dorkbox.network.connection.EndPoint.maxShutdownWaitTimeInMilliSeconds;
|
||||
|
||||
public abstract
|
||||
class RegistrationLocalHandler<C extends Connection> extends RegistrationHandler<C> {
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
*/
|
||||
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.InetSocketAddress;
|
||||
|
|
|
@ -26,7 +26,7 @@ import dorkbox.network.Broadcast;
|
|||
import dorkbox.network.connection.Connection;
|
||||
import dorkbox.network.connection.ConnectionImpl;
|
||||
import dorkbox.network.connection.CryptoSerializationManager;
|
||||
import dorkbox.network.connection.EndPoint;
|
||||
import dorkbox.network.connection.EndPointBase;
|
||||
import dorkbox.network.connection.RegistrationWrapper;
|
||||
import dorkbox.network.connection.registration.MetaChannel;
|
||||
import dorkbox.network.connection.registration.Registration;
|
||||
|
@ -266,7 +266,7 @@ class RegistrationRemoteHandlerServerUDP<C extends Connection> extends MessageTo
|
|||
|
||||
// also, once we notify, we unregister this.
|
||||
if (registrationWrapper != null) {
|
||||
return registrationWrapper.closeChannel(channel, EndPoint.maxShutdownWaitTimeInMilliSeconds);
|
||||
return registrationWrapper.closeChannel(channel, EndPointBase.maxShutdownWaitTimeInMilliSeconds);
|
||||
}
|
||||
|
||||
return null;
|
||||
|
|
|
@ -21,7 +21,7 @@ import org.bouncycastle.crypto.params.ParametersWithIV;
|
|||
|
||||
import dorkbox.network.connection.Connection;
|
||||
import dorkbox.network.connection.ConnectionPointWriter;
|
||||
import dorkbox.network.connection.EndPoint;
|
||||
import dorkbox.network.connection.EndPointBase;
|
||||
import dorkbox.network.connection.ISessionManager;
|
||||
import dorkbox.network.connection.registration.MetaChannel;
|
||||
import io.netty.channel.Channel;
|
||||
|
@ -120,7 +120,7 @@ class ChannelLocalWrapper<C extends Connection> implements ChannelWrapper<C>, Co
|
|||
@Override
|
||||
public
|
||||
void close(Connection connection, ISessionManager<C> sessionManager) {
|
||||
long maxShutdownWaitTimeInMilliSeconds = EndPoint.maxShutdownWaitTimeInMilliSeconds;
|
||||
long maxShutdownWaitTimeInMilliSeconds = EndPointBase.maxShutdownWaitTimeInMilliSeconds;
|
||||
|
||||
this.shouldFlush.set(false);
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ import org.bouncycastle.crypto.params.ParametersWithIV;
|
|||
|
||||
import dorkbox.network.connection.Connection;
|
||||
import dorkbox.network.connection.ConnectionPointWriter;
|
||||
import dorkbox.network.connection.EndPoint;
|
||||
import dorkbox.network.connection.EndPointBase;
|
||||
import dorkbox.network.connection.ISessionManager;
|
||||
import dorkbox.network.connection.UdpServer;
|
||||
import dorkbox.network.connection.registration.MetaChannel;
|
||||
|
@ -166,7 +166,7 @@ class ChannelNetworkWrapper<C extends Connection> implements ChannelWrapper<C> {
|
|||
@Override
|
||||
public
|
||||
void close(final Connection connection, final ISessionManager<C> sessionManager) {
|
||||
long maxShutdownWaitTimeInMilliSeconds = EndPoint.maxShutdownWaitTimeInMilliSeconds;
|
||||
long maxShutdownWaitTimeInMilliSeconds = EndPointBase.maxShutdownWaitTimeInMilliSeconds;
|
||||
|
||||
this.tcp.close(maxShutdownWaitTimeInMilliSeconds);
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ import java.util.WeakHashMap;
|
|||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import dorkbox.network.connection.ConnectionImpl;
|
||||
import dorkbox.network.connection.EndPoint;
|
||||
import dorkbox.network.connection.EndPointBase;
|
||||
import dorkbox.network.rmi.Rmi;
|
||||
import dorkbox.util.FastThreadLocal;
|
||||
import io.netty.channel.ChannelHandler.Sharable;
|
||||
|
@ -33,7 +33,7 @@ import io.netty.handler.codec.MessageToMessageEncoder;
|
|||
public
|
||||
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 final FastThreadLocal<Map<Object, Integer>> objectThreadLocals = new FastThreadLocal<Map<Object, Integer>>() {
|
||||
|
|
|
@ -15,7 +15,13 @@
|
|||
*/
|
||||
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 io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
|
@ -23,11 +29,6 @@ import io.netty.channel.ChannelHandler.Sharable;
|
|||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.socket.DatagramPacket;
|
||||
import io.netty.handler.codec.MessageToMessageEncoder;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.List;
|
||||
|
||||
@Sharable
|
||||
// UDP uses messages --- NOT bytebuf!
|
||||
|
@ -35,7 +36,7 @@ import java.util.List;
|
|||
public
|
||||
class KryoEncoderUdp extends MessageToMessageEncoder<Object> {
|
||||
|
||||
private static final int maxSize = EndPoint.udpMaxSize;
|
||||
private static final int maxSize = EndPointBase.udpMaxSize;
|
||||
private final CryptoSerializationManager serializationManager;
|
||||
|
||||
|
||||
|
|
|
@ -53,7 +53,7 @@ import com.esotericsoftware.kryo.util.Util;
|
|||
import com.esotericsoftware.reflectasm.MethodAccess;
|
||||
|
||||
import dorkbox.network.connection.Connection;
|
||||
import dorkbox.network.connection.EndPoint;
|
||||
import dorkbox.network.connection.EndPointBase;
|
||||
import dorkbox.network.connection.KryoExtra;
|
||||
import dorkbox.network.util.CryptoSerializationManager;
|
||||
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
|
||||
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.ConnectionImpl;
|
||||
import dorkbox.network.connection.EndPoint;
|
||||
import dorkbox.network.connection.EndPointBase;
|
||||
import dorkbox.network.connection.Listener;
|
||||
import dorkbox.network.util.RmiSerializationManager;
|
||||
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
|
||||
* 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
|
||||
* The remote side of this connection requested the invocation.
|
||||
|
|
|
@ -47,7 +47,7 @@ import org.slf4j.Logger;
|
|||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import dorkbox.network.connection.Connection;
|
||||
import dorkbox.network.connection.EndPoint;
|
||||
import dorkbox.network.connection.EndPointBase;
|
||||
import dorkbox.network.util.RmiSerializationManager;
|
||||
|
||||
/**
|
||||
|
@ -195,8 +195,8 @@ class RmiProxyHandler implements InvocationHandler {
|
|||
return proxyString;
|
||||
}
|
||||
|
||||
EndPoint endPoint = this.connection.getEndPoint();
|
||||
final RmiSerializationManager serializationManager = endPoint.getSerialization();
|
||||
EndPointBase endPointBaseConnection = this.connection.getEndPoint();
|
||||
final RmiSerializationManager serializationManager = endPointBaseConnection.getSerialization();
|
||||
|
||||
InvokeMethod invokeMethod = new InvokeMethod();
|
||||
invokeMethod.objectID = this.objectID;
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
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 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.spi.ILoggingEvent;
|
||||
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.SimpleEntropy;
|
||||
import dorkbox.util.exceptions.InitializationException;
|
||||
|
@ -57,7 +57,7 @@ class BaseTest {
|
|||
}
|
||||
|
||||
volatile boolean fail_check;
|
||||
private final ArrayList<EndPoint> endPoints = new ArrayList<EndPoint>();
|
||||
private final ArrayList<EndPointBase> endPointBaseConnections = new ArrayList<EndPointBase>();
|
||||
|
||||
public
|
||||
BaseTest() {
|
||||
|
@ -107,8 +107,8 @@ class BaseTest {
|
|||
}
|
||||
|
||||
public
|
||||
void addEndPoint(final EndPoint endPoint) {
|
||||
this.endPoints.add(endPoint);
|
||||
void addEndPoint(final EndPointBase endPointBaseConnection) {
|
||||
this.endPointBaseConnections.add(endPointBaseConnection);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -157,12 +157,12 @@ class BaseTest {
|
|||
|
||||
private
|
||||
void stopEndPoints_outsideThread() {
|
||||
synchronized (BaseTest.this.endPoints) {
|
||||
for (EndPoint endPoint : BaseTest.this.endPoints) {
|
||||
endPoint.stop();
|
||||
endPoint.waitForShutdown();
|
||||
synchronized (BaseTest.this.endPointBaseConnections) {
|
||||
for (EndPointBase endPointBaseConnection : BaseTest.this.endPointBaseConnections) {
|
||||
endPointBaseConnection.stop();
|
||||
endPointBaseConnection.waitForShutdown();
|
||||
}
|
||||
BaseTest.this.endPoints.clear();
|
||||
BaseTest.this.endPointBaseConnections.clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -226,8 +226,8 @@ class BaseTest {
|
|||
}
|
||||
|
||||
while (true) {
|
||||
synchronized (this.endPoints) {
|
||||
if (this.endPoints.isEmpty()) {
|
||||
synchronized (this.endPointBaseConnections) {
|
||||
if (this.endPointBaseConnections.isEmpty()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ import org.junit.Test;
|
|||
|
||||
import dorkbox.network.connection.Connection;
|
||||
import dorkbox.network.connection.CryptoSerializationManager;
|
||||
import dorkbox.network.connection.EndPoint;
|
||||
import dorkbox.network.connection.EndPointBase;
|
||||
import dorkbox.network.connection.Listener;
|
||||
import dorkbox.util.SerializationManager;
|
||||
import dorkbox.util.exceptions.InitializationException;
|
||||
|
@ -42,7 +42,7 @@ class ConnectionTest extends BaseTest {
|
|||
System.out.println("---- " + "Local");
|
||||
|
||||
Configuration configuration = new Configuration();
|
||||
configuration.localChannelName = EndPoint.LOCAL_CHANNEL;
|
||||
configuration.localChannelName = EndPointBase.LOCAL_CHANNEL;
|
||||
configuration.serialization = CryptoSerializationManager.DEFAULT();
|
||||
register(configuration.serialization);
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@ import org.slf4j.Logger;
|
|||
|
||||
import dorkbox.network.connection.Connection;
|
||||
import dorkbox.network.connection.ConnectionImpl;
|
||||
import dorkbox.network.connection.EndPoint;
|
||||
import dorkbox.network.connection.EndPointBase;
|
||||
import dorkbox.network.connection.Listener;
|
||||
import dorkbox.network.connection.Listeners;
|
||||
import dorkbox.network.rmi.RmiBridge;
|
||||
|
@ -64,8 +64,8 @@ class ListenerTest extends BaseTest {
|
|||
// quick and dirty test to also test connection sub-classing
|
||||
class TestConnectionA extends ConnectionImpl {
|
||||
public
|
||||
TestConnectionA(final Logger logger, final EndPoint endPoint, final RmiBridge rmiBridge) {
|
||||
super(logger, endPoint, rmiBridge);
|
||||
TestConnectionA(final Logger logger, final EndPointBase endPointBaseConnection, final RmiBridge rmiBridge) {
|
||||
super(logger, endPointBaseConnection, rmiBridge);
|
||||
}
|
||||
|
||||
public
|
||||
|
@ -77,8 +77,8 @@ class ListenerTest extends BaseTest {
|
|||
|
||||
class TestConnectionB extends TestConnectionA {
|
||||
public
|
||||
TestConnectionB(final Logger logger, final EndPoint endPoint, final RmiBridge rmiBridge) {
|
||||
super(logger, endPoint, rmiBridge);
|
||||
TestConnectionB(final Logger logger, final EndPointBase endPointBaseConnection, final RmiBridge rmiBridge) {
|
||||
super(logger, endPointBaseConnection, rmiBridge);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -109,7 +109,7 @@ class ListenerTest extends BaseTest {
|
|||
Server server = new Server(configuration) {
|
||||
@Override
|
||||
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);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -30,7 +30,7 @@ import org.junit.Test;
|
|||
|
||||
import dorkbox.network.connection.Connection;
|
||||
import dorkbox.network.connection.CryptoSerializationManager;
|
||||
import dorkbox.network.connection.EndPoint;
|
||||
import dorkbox.network.connection.EndPointBase;
|
||||
import dorkbox.network.connection.Listener;
|
||||
import dorkbox.network.connection.Listeners;
|
||||
import dorkbox.util.SerializationManager;
|
||||
|
@ -52,8 +52,8 @@ class PingPongTest extends BaseTest {
|
|||
public
|
||||
void pingPong() throws InitializationException, SecurityException, IOException, InterruptedException {
|
||||
// UDP data is kinda big. Make sure it fits into one packet.
|
||||
int origSize = EndPoint.udpMaxSize;
|
||||
EndPoint.udpMaxSize = 2048;
|
||||
int origSize = EndPointBase.udpMaxSize;
|
||||
EndPointBase.udpMaxSize = 2048;
|
||||
|
||||
this.fail = "Data not received.";
|
||||
|
||||
|
@ -192,7 +192,7 @@ class PingPongTest extends BaseTest {
|
|||
fail(this.fail);
|
||||
}
|
||||
|
||||
EndPoint.udpMaxSize = origSize;
|
||||
EndPointBase.udpMaxSize = origSize;
|
||||
}
|
||||
|
||||
private static
|
||||
|
|
|
@ -30,7 +30,7 @@ import org.junit.Test;
|
|||
|
||||
import dorkbox.network.connection.Connection;
|
||||
import dorkbox.network.connection.CryptoSerializationManager;
|
||||
import dorkbox.network.connection.EndPoint;
|
||||
import dorkbox.network.connection.EndPointBase;
|
||||
import dorkbox.network.connection.Listener;
|
||||
import dorkbox.network.connection.Listeners;
|
||||
import dorkbox.util.exceptions.InitializationException;
|
||||
|
@ -47,8 +47,8 @@ class UnregisteredClassTest extends BaseTest {
|
|||
@Test
|
||||
public
|
||||
void unregisteredClasses() throws InitializationException, SecurityException, IOException, InterruptedException {
|
||||
int origSize = EndPoint.udpMaxSize;
|
||||
EndPoint.udpMaxSize = 2048;
|
||||
int origSize = EndPointBase.udpMaxSize;
|
||||
EndPointBase.udpMaxSize = 2048;
|
||||
|
||||
Configuration configuration = new Configuration();
|
||||
configuration.tcpPort = tcpPort;
|
||||
|
@ -179,7 +179,7 @@ class UnregisteredClassTest extends BaseTest {
|
|||
fail(this.fail);
|
||||
}
|
||||
|
||||
EndPoint.udpMaxSize = origSize;
|
||||
EndPointBase.udpMaxSize = origSize;
|
||||
}
|
||||
|
||||
private
|
||||
|
|
Loading…
Reference in New Issue
Block a user