
dorkbox.network.connection.EndPointClient Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of Network Show documentation
Show all versions of Network Show documentation
Encrypted, high-performance, and event-driven/reactive network stack for Java 11+
/*
* 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 dorkbox.network.Client;
import dorkbox.network.Configuration;
import dorkbox.network.connection.bridge.ConnectionBridge;
import dorkbox.util.exceptions.InitializationException;
import dorkbox.util.exceptions.SecurityException;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
import org.slf4j.Logger;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
/**
* This serves the purpose of making sure that specific methods are not available to the end user.
*/
public
class EndPointClient extends EndPoint implements Runnable {
protected C connection;
protected final Object registrationLock = new Object();
protected final AtomicInteger connectingBootstrap = new AtomicInteger(0);
protected List bootstraps = new LinkedList();
protected volatile int connectionTimeout = 5000; // default
protected volatile boolean registrationComplete = false;
private volatile ConnectionBridge connectionBridgeFlushAlways;
public
EndPointClient(Configuration options) throws InitializationException, SecurityException, IOException {
super(Client.class, options);
}
protected
void registerNextProtocol() {
this.registrationComplete = false; // always reset.
new Thread(this, "Bootstrap registration").start();
}
@SuppressWarnings("AutoBoxing")
@Override
public
void run() {
synchronized (this.connectingBootstrap) {
int bootstrapToRegister = this.connectingBootstrap.getAndIncrement();
BootstrapWrapper bootstrapWrapper = this.bootstraps.get(bootstrapToRegister);
ChannelFuture future;
if (this.connectionTimeout != 0) {
// must be before connect
bootstrapWrapper.bootstrap.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, this.connectionTimeout);
}
Logger logger2 = this.logger;
try {
// UDP : When this is CONNECT, a udp socket will ONLY accept UDP traffic from the remote address (ip/port combo).
// If the reply isn't from the correct port, then the other end will receive a "Port Unreachable" exception.
future = bootstrapWrapper.bootstrap.connect();
future.await();
} catch (Exception e) {
String errorMessage = stopWithErrorMessage(logger2,
"Could not connect to the " + bootstrapWrapper.type + " server on port: " +
bootstrapWrapper.port,
e);
throw new IllegalArgumentException(errorMessage);
}
if (!future.isSuccess()) {
String errorMessage = stopWithErrorMessage(logger2,
"Could not connect to the " + bootstrapWrapper.type + " server on port: " +
bootstrapWrapper.port,
future.cause());
throw new IllegalArgumentException(errorMessage);
}
if (logger2.isTraceEnabled()) {
logger2.trace("Waiting for registration from server.");
}
manageForShutdown(future);
}
}
/**
* Internal call by the pipeline to notify the client to continue registering the different session protocols.
*
* @return true if we are done registering bootstraps
*/
@Override
protected
boolean registerNextProtocol0() {
synchronized (this.connectingBootstrap) {
this.registrationComplete = this.connectingBootstrap.get() == this.bootstraps.size();
if (!this.registrationComplete) {
registerNextProtocol();
}
}
Logger logger2 = this.logger;
if (logger2.isTraceEnabled()) {
logger2.trace("Registered protocol from server.");
}
// only let us continue with connections (this starts up the client/server implementations) once ALL of the
// bootstraps have connected
return this.registrationComplete;
}
/**
* Internal (to the networking stack) to notify the client that registration has COMPLETED. This is necessary because the client
* will BLOCK until it has successfully registered it's connections.
*/
@Override
final
void connectionConnected0(final ConnectionImpl connection) {
// invokes the listener.connection() method, and initialize the connection channels with whatever extra info they might need.
super.connectionConnected0(connection);
this.connectionBridgeFlushAlways = new ConnectionBridge() {
@Override
public
void self(Object message) {
connection.self(message);
flush();
}
@Override
public
ConnectionPoint TCP(Object message) {
ConnectionPoint tcp = connection.TCP_backpressure(message);
tcp.flush();
return tcp;
}
@Override
public
ConnectionPoint UDP(Object message) {
ConnectionPoint udp = connection.UDP_backpressure(message);
udp.flush();
return udp;
}
@Override
public
ConnectionPoint UDT(Object message) {
ConnectionPoint udt = connection.UDT_backpressure(message);
udt.flush();
return udt;
}
@Override
public
Ping ping() {
Ping ping = connection.ping();
flush();
return ping;
}
@Override
public
void flush() {
connection.flush();
}
};
// notify the registration we are done!
synchronized (this.registrationLock) {
this.registrationLock.notify();
}
}
/**
* Expose methods to send objects to a destination.
*
* This returns a bridge that will flush after EVERY send! This is because sending data can occur on the client, outside
* of the normal eventloop patterns, and it is confusing to the user to have to manually flush the channel each time.
*/
@Override
public
ConnectionBridge send() {
return this.connectionBridgeFlushAlways;
}
/**
* Closes all connections ONLY (keeps the client running). To STOP the client, use stop().
*
* This is used, for example, when reconnecting to a server.
*/
@Override
public
void closeConnections() {
super.closeConnections();
// for the CLIENT only, we clear these connections! (the server only clears them on shutdown)
shutdownChannels();
// make sure we're not waiting on registration
registrationComplete = true;
synchronized (this.registrationLock) {
this.registrationLock.notify();
}
registrationComplete = false;
}
/**
* Internal call to abort registration if the shutdown command is issued during channel registration.
*/
void abortRegistration() {
synchronized (this.registrationLock) {
this.registrationLock.notify();
}
stop();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy