Skip to content

Commit b86e238

Browse files
committed
Initial commit
1 parent 72223ec commit b86e238

File tree

3 files changed

+88
-13
lines changed

3 files changed

+88
-13
lines changed

pom.xml

+7
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
<maven.compiler.source>17</maven.compiler.source>
1515
<maven.compiler.target>17</maven.compiler.target>
16+
<netty.version>4.1.106.Final</netty.version>
1617
</properties>
1718

1819
<distributionManagement>
@@ -42,6 +43,12 @@
4243
<version>2.0.2-SNAPSHOT</version>
4344
<scope>provided</scope>
4445
</dependency>
46+
<dependency>
47+
<groupId>io.netty.incubator</groupId>
48+
<artifactId>netty-incubator-codec-native-quic</artifactId>
49+
<version>0.0.57.Final</version>
50+
<classifier>linux-x86_64</classifier>
51+
</dependency>
4552
</dependencies>
4653

4754
<build>

src/main/java/org/nethergames/proxytransport/integration/CustomClientEventHandler.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import io.netty.channel.ChannelInboundHandlerAdapter;
77

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

1111
private final ProxiedPlayer player;
1212
private final ClientConnection connection;

src/main/java/org/nethergames/proxytransport/integration/CustomTransportServerInfo.java

+80-12
Original file line numberDiff line numberDiff line change
@@ -5,34 +5,38 @@
55
import dev.waterdog.waterdogpe.network.serverinfo.ServerInfoType;
66
import dev.waterdog.waterdogpe.player.ProxiedPlayer;
77
import io.netty.bootstrap.Bootstrap;
8-
import io.netty.channel.ChannelFuture;
9-
import io.netty.channel.EventLoop;
10-
import io.netty.channel.EventLoopGroup;
8+
import io.netty.channel.*;
119
import io.netty.channel.epoll.Epoll;
1210
import io.netty.channel.epoll.EpollEventLoopGroup;
1311
import io.netty.channel.epoll.EpollSocketChannel;
1412
import io.netty.channel.nio.NioEventLoopGroup;
1513
import io.netty.channel.socket.SocketChannel;
1614
import io.netty.channel.socket.nio.NioSocketChannel;
15+
import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
16+
import io.netty.incubator.codec.quic.*;
1717
import io.netty.util.concurrent.Future;
1818
import io.netty.util.concurrent.Promise;
1919
import net.jodah.expiringmap.internal.NamedThreadFactory;
2020
import org.nethergames.proxytransport.impl.TransportChannelInitializer;
2121

2222
import java.net.InetSocketAddress;
23+
import java.util.HashMap;
2324
import java.util.concurrent.ThreadFactory;
25+
import java.util.concurrent.TimeUnit;
2426

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

30-
public static final String TYPE_IDENT = "tcp";
32+
public static final String TYPE_IDENT = "quic";
3133
public static final ServerInfoType TYPE = ServerInfoType.builder()
3234
.identifier(TYPE_IDENT)
3335
.serverInfoFactory(CustomTransportServerInfo::new)
3436
.register();
3537

38+
private final HashMap<InetSocketAddress, QuicChannel> serverConnections = new HashMap<>();
39+
3640
public CustomTransportServerInfo(String serverName, InetSocketAddress address, InetSocketAddress publicAddress) {
3741
super(serverName, address, publicAddress);
3842
}
@@ -44,19 +48,83 @@ public ServerInfoType getServerType() {
4448

4549
@Override
4650
public Future<ClientConnection> createConnection(ProxiedPlayer proxiedPlayer) {
51+
proxiedPlayer.getLogger().info("Creating connection to " + this.getAddress());
4752
EventLoop eventLoop = proxiedPlayer.getProxy().getWorkerEventLoopGroup().next();
4853
Promise<ClientConnection> promise = eventLoop.newPromise();
54+
55+
this.createServerConnection(eventLoop, this.getAddress()).addListener((Future<QuicChannel> future) -> {
56+
proxiedPlayer.getLogger().info("Created server connection to " + this.getAddress());
57+
if (future.isSuccess()) {
58+
QuicChannel quicChannel = future.getNow();
59+
60+
quicChannel.createStream(QuicStreamType.BIDIRECTIONAL, new TransportChannelInitializer(proxiedPlayer, this, promise)).addListener((Future<QuicStreamChannel> streamFuture) -> {
61+
if (!streamFuture.isSuccess()) {
62+
promise.tryFailure(streamFuture.cause());
63+
quicChannel.close();
64+
}
65+
});
66+
} else {
67+
promise.tryFailure(future.cause());
68+
}
69+
});
70+
71+
return promise;
72+
}
73+
74+
private Future<QuicChannel> createServerConnection(EventLoopGroup eventLoopGroup, InetSocketAddress address) {
75+
EventLoop eventLoop = eventLoopGroup.next();
76+
77+
if (serverConnections.containsKey(address)) {
78+
return eventLoop.newSucceededFuture(serverConnections.get(address));
79+
}
80+
81+
Promise<QuicChannel> promise = eventLoop.newPromise();
82+
83+
QuicSslContext sslContext = QuicSslContextBuilder.forClient().trustManager(InsecureTrustManagerFactory.INSTANCE).applicationProtocols("ng").build();
84+
System.out.println("1 Creating server connection to " + address);
85+
ChannelHandler codec = new QuicClientCodecBuilder()
86+
.sslContext(sslContext)
87+
.maxIdleTimeout(5000, TimeUnit.MILLISECONDS)
88+
.initialMaxData(10000000)
89+
.initialMaxStreamDataBidirectionalLocal(1000000)
90+
.build();
91+
92+
System.out.println("4 Creating server connection to " + address);
4993

5094
new Bootstrap()
5195
.group(downstreamLoopGroup)
52-
.handler(new TransportChannelInitializer(proxiedPlayer, this, promise))
53-
.localAddress(new InetSocketAddress("0.0.0.0", 0))
96+
.handler(codec)
5497
.channel(getProperSocketChannel())
55-
.remoteAddress(this.getAddress())
56-
.connect().addListener((ChannelFuture future) -> {
57-
if (!future.isSuccess()) {
58-
promise.tryFailure(future.cause());
59-
future.channel().close();
98+
.remoteAddress(address)
99+
.bind(0).addListener((ChannelFuture channelFuture) -> {
100+
if (channelFuture.isSuccess()) {
101+
System.out.println("Connected to " + address);
102+
QuicChannel.newBootstrap(channelFuture.channel())
103+
.streamHandler(new ChannelInboundHandlerAdapter() {
104+
@Override
105+
public void channelActive(ChannelHandlerContext ctx) {
106+
ctx.close();
107+
}
108+
})
109+
.remoteAddress(address)
110+
.connect().addListener((Future<QuicChannel> quicChannelFuture) -> {
111+
if (quicChannelFuture.isSuccess()) {
112+
System.out.println("Connected to " + address + " via QUIC");
113+
QuicChannel quicChannel = quicChannelFuture.getNow();
114+
quicChannel.closeFuture().addListener(f -> serverConnections.remove(address));
115+
serverConnections.put(address, quicChannel);
116+
117+
promise.trySuccess(quicChannel);
118+
} else {
119+
System.out.println("Failed to connect to " + address + " via QUIC");
120+
promise.tryFailure(quicChannelFuture.cause());
121+
channelFuture.channel().close();
122+
}
123+
});
124+
} else {
125+
System.out.println("Failed to connect to " + address);
126+
promise.tryFailure(channelFuture.cause());
127+
channelFuture.channel().close();
60128
}
61129
});
62130

0 commit comments

Comments
 (0)