Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
dries-c committed Feb 14, 2024
1 parent 72223ec commit c82ae26
Show file tree
Hide file tree
Showing 3 changed files with 124 additions and 19 deletions.
49 changes: 43 additions & 6 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,30 @@
<version>2.0.2-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.netty.incubator</groupId>
<artifactId>netty-incubator-codec-native-quic</artifactId>
<version>0.0.53.Final</version>
<classifier>linux-x86_64</classifier>
<exclusions>
<exclusion>
<groupId>io.netty</groupId>
<artifactId>netty-common</artifactId>
</exclusion>
<exclusion>
<groupId>io.netty</groupId>
<artifactId>netty-buffer</artifactId>
</exclusion>
<exclusion>
<groupId>io.netty</groupId>
<artifactId>netty-codec</artifactId>
</exclusion>
<exclusion>
<groupId>io.netty</groupId>
<artifactId>netty-transport</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>

<build>
Expand All @@ -59,17 +83,30 @@
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.1</version>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.3.0</version>
<configuration>
<appendAssemblyId>false</appendAssemblyId>
<archive>
<manifest>

</manifest>
<manifestEntries>
<Multi-Release>true</Multi-Release>
</manifestEntries>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>

</configuration>
<executions>
<execution>
<id>assemble-all</id>
<phase>package</phase>
<goals>
<goal>shade</goal>
<goal>single</goal>
</goals>
<configuration>
<createDependencyReducedPom>false</createDependencyReducedPom>
</configuration>
</execution>
</executions>
</plugin>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import io.netty.channel.ChannelInboundHandlerAdapter;

public class CustomClientEventHandler extends ChannelInboundHandlerAdapter {
public static final String NAME = "tcp-client-event-handler";
public static final String NAME = "quic-stream-client-event-handler";

private final ProxiedPlayer player;
private final ClientConnection connection;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,34 +5,38 @@
import dev.waterdog.waterdogpe.network.serverinfo.ServerInfoType;
import dev.waterdog.waterdogpe.player.ProxiedPlayer;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoop;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.*;
import io.netty.channel.epoll.Epoll;
import io.netty.channel.epoll.EpollEventLoopGroup;
import io.netty.channel.epoll.EpollSocketChannel;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
import io.netty.incubator.codec.quic.*;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.Promise;
import net.jodah.expiringmap.internal.NamedThreadFactory;
import org.nethergames.proxytransport.impl.TransportChannelInitializer;

import java.net.InetSocketAddress;
import java.util.HashMap;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;

public class CustomTransportServerInfo extends ServerInfo {
public static final int availableCPU = Runtime.getRuntime().availableProcessors();
public static final ThreadFactory downstreamThreadFactory = new NamedThreadFactory("TCP-Downstream %s");
public static final ThreadFactory downstreamThreadFactory = new NamedThreadFactory("QUIC-Downstream %s");
public static final EventLoopGroup downstreamLoopGroup = Epoll.isAvailable() ? new EpollEventLoopGroup(availableCPU, downstreamThreadFactory) : new NioEventLoopGroup(availableCPU, downstreamThreadFactory);

public static final String TYPE_IDENT = "tcp";
public static final String TYPE_IDENT = "quic";
public static final ServerInfoType TYPE = ServerInfoType.builder()
.identifier(TYPE_IDENT)
.serverInfoFactory(CustomTransportServerInfo::new)
.register();

private final HashMap<InetSocketAddress, QuicChannel> serverConnections = new HashMap<>();

public CustomTransportServerInfo(String serverName, InetSocketAddress address, InetSocketAddress publicAddress) {
super(serverName, address, publicAddress);
}
Expand All @@ -44,19 +48,83 @@ public ServerInfoType getServerType() {

@Override
public Future<ClientConnection> createConnection(ProxiedPlayer proxiedPlayer) {
proxiedPlayer.getLogger().info("Creating connection to " + this.getAddress());
EventLoop eventLoop = proxiedPlayer.getProxy().getWorkerEventLoopGroup().next();
Promise<ClientConnection> promise = eventLoop.newPromise();

this.createServerConnection(eventLoop, this.getAddress()).addListener((Future<QuicChannel> future) -> {
proxiedPlayer.getLogger().info("Created server connection to " + this.getAddress());
if (future.isSuccess()) {
QuicChannel quicChannel = future.getNow();

quicChannel.createStream(QuicStreamType.BIDIRECTIONAL, new TransportChannelInitializer(proxiedPlayer, this, promise)).addListener((Future<QuicStreamChannel> streamFuture) -> {
if (!streamFuture.isSuccess()) {
promise.tryFailure(streamFuture.cause());
quicChannel.close();
}
});
} else {
promise.tryFailure(future.cause());
}
});

return promise;
}

private Future<QuicChannel> createServerConnection(EventLoopGroup eventLoopGroup, InetSocketAddress address) {
EventLoop eventLoop = eventLoopGroup.next();

if (serverConnections.containsKey(address)) {
return eventLoop.newSucceededFuture(serverConnections.get(address));
}

Promise<QuicChannel> promise = eventLoop.newPromise();

QuicSslContext sslContext = QuicSslContextBuilder.forClient().trustManager(InsecureTrustManagerFactory.INSTANCE).applicationProtocols("ng").build();
System.out.println("1 Creating server connection to " + address);
ChannelHandler codec = new QuicClientCodecBuilder()
.sslContext(sslContext)
.maxIdleTimeout(5000, TimeUnit.MILLISECONDS)
.initialMaxData(10000000)
.initialMaxStreamDataBidirectionalLocal(1000000)
.build();

System.out.println("4 Creating server connection to " + address);

new Bootstrap()
.group(downstreamLoopGroup)
.handler(new TransportChannelInitializer(proxiedPlayer, this, promise))
.localAddress(new InetSocketAddress("0.0.0.0", 0))
.handler(codec)
.channel(getProperSocketChannel())
.remoteAddress(this.getAddress())
.connect().addListener((ChannelFuture future) -> {
if (!future.isSuccess()) {
promise.tryFailure(future.cause());
future.channel().close();
.remoteAddress(address)
.bind(0).addListener((ChannelFuture channelFuture) -> {
if (channelFuture.isSuccess()) {
System.out.println("Connected to " + address);
QuicChannel.newBootstrap(channelFuture.channel())
.streamHandler(new ChannelInboundHandlerAdapter() {
@Override
public void channelActive(ChannelHandlerContext ctx) {
ctx.close();
}
})
.remoteAddress(address)
.connect().addListener((Future<QuicChannel> quicChannelFuture) -> {
if (quicChannelFuture.isSuccess()) {
System.out.println("Connected to " + address + " via QUIC");
QuicChannel quicChannel = quicChannelFuture.getNow();
quicChannel.closeFuture().addListener(f -> serverConnections.remove(address));
serverConnections.put(address, quicChannel);

promise.trySuccess(quicChannel);
} else {
System.out.println("Failed to connect to " + address + " via QUIC");
promise.tryFailure(quicChannelFuture.cause());
channelFuture.channel().close();
}
});
} else {
System.out.println("Failed to connect to " + address);
promise.tryFailure(channelFuture.cause());
channelFuture.channel().close();
}
});

Expand Down

0 comments on commit c82ae26

Please sign in to comment.