Skip to content

Commit 3fc1745

Browse files
RaphiMCKas-tle
andauthored
Wait for the client's network settings packet instead of fabricating one (#2)
* Wait for the client's network settings packet instead of fabricating one * Make RakMessage from ByteBuf in RakClientNetworkSettingsHandler if needed --------- Co-authored-by: Kas-tle <26531652+Kas-tle@users.noreply.github.com>
1 parent 78d25c7 commit 3fc1745

File tree

6 files changed

+65
-111
lines changed

6 files changed

+65
-111
lines changed

README.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ You can join the [Discord](https://discord.gg/5z4GuSnqmQ) for help with this for
99
- New incoming connection batches additional packets to more closely imitate the vanilla client:
1010
- A `Connected Ping`
1111
- The first game packet, `Request Network Settings Packet`
12-
- Attempts to detect it from the connection, but uses `RakChannelOption.RAK_CLIENT_BEDROCK_PROTOCOL_VERSION` if it is not detected in the pipeline
1312
- Allows for resetting security state if `Open Connection Reply 1` is resent by the server
1413
- Only do retries with `Open Connection Request 1`, and reserve `Open Connection Request 2` only as a direct response to `Open Connection Reply 1`
1514
- Allows using datagram channel factories for raknet (from [@AlexProgrammerDE](https://github.com/AlexProgrammerDE))
@@ -23,4 +22,4 @@ The library is published to Maven Central. See the [latest release](https://gith
2322

2423
### Snapshots [![](https://jitpack.io/v/dev.kastle/NetworkCompatible.svg)](https://jitpack.io/#dev.kastle/NetworkCompatible)
2524

26-
Snapshots are avaible from [jitpack](https://jitpack.io/#dev.kastle/NetworkCompatible).
25+
Snapshots are avaible from [jitpack](https://jitpack.io/#dev.kastle/NetworkCompatible).

transport-raknet/src/main/java/org/cloudburstmc/netty/channel/raknet/config/DefaultRakClientConfig.java

Lines changed: 3 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,7 @@
2424

2525
import java.util.Map;
2626

27-
import static org.cloudburstmc.netty.channel.raknet.RakConstants.DEFAULT_UNCONNECTED_MAGIC;
28-
import static org.cloudburstmc.netty.channel.raknet.RakConstants.MTU_SIZES;
29-
import static org.cloudburstmc.netty.channel.raknet.RakConstants.SESSION_TIMEOUT_MS;
30-
import static org.cloudburstmc.netty.channel.raknet.RakConstants.TIME_BETWEEN_SEND_CONNECTION_ATTEMPTS_MS;
27+
import static org.cloudburstmc.netty.channel.raknet.RakConstants.*;
3128

3229
/**
3330
* The extended implementation of {@link RakChannelConfig} based on {@link DefaultRakSessionConfig} used by client.
@@ -43,7 +40,6 @@ public class DefaultRakClientConfig extends DefaultRakSessionConfig {
4340
private volatile boolean ipDontFragment = false;
4441
private volatile int clientInternalAddresses = 10;
4542
private volatile int timeBetweenSendConnectionAttemptsMS = TIME_BETWEEN_SEND_CONNECTION_ATTEMPTS_MS;
46-
private volatile int bedrockProtocolVersion;
4743

4844
public DefaultRakClientConfig(Channel channel) {
4945
super(channel);
@@ -52,10 +48,9 @@ public DefaultRakClientConfig(Channel channel) {
5248
@Override
5349
public Map<ChannelOption<?>, Object> getOptions() {
5450
return this.getOptions(
55-
super.getOptions(),
51+
super.getOptions(),
5652
RakChannelOption.RAK_UNCONNECTED_MAGIC, RakChannelOption.RAK_CONNECT_TIMEOUT, RakChannelOption.RAK_REMOTE_GUID, RakChannelOption.RAK_SESSION_TIMEOUT, RakChannelOption.RAK_COMPATIBILITY_MODE,
57-
RakChannelOption.RAK_MTU_SIZES, RakChannelOption.RAK_IP_DONT_FRAGMENT, RakChannelOption.RAK_CLIENT_INTERNAL_ADDRESSES, RakChannelOption.RAK_TIME_BETWEEN_SEND_CONNECTION_ATTEMPTS_MS,
58-
RakChannelOption.RAK_CLIENT_BEDROCK_PROTOCOL_VERSION);
53+
RakChannelOption.RAK_MTU_SIZES, RakChannelOption.RAK_IP_DONT_FRAGMENT, RakChannelOption.RAK_CLIENT_INTERNAL_ADDRESSES, RakChannelOption.RAK_TIME_BETWEEN_SEND_CONNECTION_ATTEMPTS_MS);
5954
}
6055

6156
@SuppressWarnings("unchecked")
@@ -79,8 +74,6 @@ public <T> T getOption(ChannelOption<T> option) {
7974
return (T) Integer.valueOf(this.clientInternalAddresses);
8075
} else if (option == RakChannelOption.RAK_TIME_BETWEEN_SEND_CONNECTION_ATTEMPTS_MS) {
8176
return (T) Integer.valueOf(this.timeBetweenSendConnectionAttemptsMS);
82-
} else if (option == RakChannelOption.RAK_CLIENT_BEDROCK_PROTOCOL_VERSION) {
83-
return (T) Integer.valueOf(this.bedrockProtocolVersion);
8477
}
8578
return super.getOption(option);
8679
}
@@ -116,9 +109,6 @@ public <T> boolean setOption(ChannelOption<T> option, T value) {
116109
} else if (option == RakChannelOption.RAK_TIME_BETWEEN_SEND_CONNECTION_ATTEMPTS_MS) {
117110
this.setTimeBetweenSendConnectionAttemptsMS((Integer) value);
118111
return true;
119-
} else if (option == RakChannelOption.RAK_CLIENT_BEDROCK_PROTOCOL_VERSION) {
120-
this.setBedrockProtocolVersion((Integer) value);
121-
return true;
122112
}
123113
return super.setOption(option, value);
124114
}
@@ -203,12 +193,4 @@ public int getTimeBetweenSendConnectionAttemptsMS() {
203193
public void setTimeBetweenSendConnectionAttemptsMS(int timeBetweenSendConnectionAttemptsMS) {
204194
this.timeBetweenSendConnectionAttemptsMS = timeBetweenSendConnectionAttemptsMS;
205195
}
206-
207-
public int getBedrockProtocolVersion() {
208-
return this.bedrockProtocolVersion;
209-
}
210-
211-
public void setBedrockProtocolVersion(int bedrockProtocolVersion) {
212-
this.bedrockProtocolVersion = bedrockProtocolVersion;
213-
}
214196
}

transport-raknet/src/main/java/org/cloudburstmc/netty/channel/raknet/config/RakChannelOption.java

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -189,12 +189,6 @@ public class RakChannelOption<T> extends ChannelOption<T> {
189189
public static final ChannelOption<Integer> RAK_TIME_BETWEEN_SEND_CONNECTION_ATTEMPTS_MS =
190190
valueOf(RakChannelOption.class, "RAK_TIME_BETWEEN_SEND_CONNECTION_ATTEMPTS_MS");
191191

192-
/**
193-
* The fllback protocol version of the RakNet client for sending RequestNetworkSettingsPacket in compatibility mode if one is not found in the pipeline.
194-
*/
195-
public static final ChannelOption<Integer> RAK_CLIENT_BEDROCK_PROTOCOL_VERSION =
196-
valueOf(RakChannelOption.class, "RAK_CLIENT_BEDROCK_PROTOCOL_VERSION");
197-
198192
@SuppressWarnings("deprecation")
199193
protected RakChannelOption() {
200194
super(null);

transport-raknet/src/main/java/org/cloudburstmc/netty/handler/codec/raknet/client/RakClientNetworkSettingsHandler.java

Lines changed: 36 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -4,42 +4,50 @@
44
import io.netty.channel.ChannelHandlerContext;
55
import io.netty.channel.ChannelOutboundHandlerAdapter;
66
import io.netty.channel.ChannelPromise;
7-
import io.netty.util.AttributeKey;
8-
import io.netty.util.internal.logging.InternalLogger;
9-
import io.netty.util.internal.logging.InternalLoggerFactory;
7+
import io.netty.util.concurrent.Promise;
108
import org.cloudburstmc.netty.channel.raknet.RakChannel;
9+
import org.cloudburstmc.netty.channel.raknet.RakPriority;
10+
import org.cloudburstmc.netty.channel.raknet.RakReliability;
1111
import org.cloudburstmc.netty.channel.raknet.config.RakChannelOption;
12+
import org.cloudburstmc.netty.channel.raknet.packet.RakMessage;
1213

1314
import static org.cloudburstmc.netty.channel.raknet.RakConstants.ID_GAME_PACKET;
1415

1516
public class RakClientNetworkSettingsHandler extends ChannelOutboundHandlerAdapter {
1617
public static final String NAME = "rak-client-network-settings-handler";
17-
public static final AttributeKey<ByteBuf> NETWORK_SETTINGS_PAYLOAD = AttributeKey.valueOf("network-settings-payload");
18-
private static final InternalLogger log = InternalLoggerFactory.getInstance(RakClientNetworkSettingsHandler.class);
1918

2019
private final RakChannel channel;
20+
private final Promise<RakMessage> networkSettingsPacketPromise;
2121

22-
public RakClientNetworkSettingsHandler(RakChannel channel) {
22+
public RakClientNetworkSettingsHandler(RakChannel channel, Promise<RakMessage> networkSettingsPacketPromise) {
2323
this.channel = channel;
24+
this.networkSettingsPacketPromise = networkSettingsPacketPromise;
2425
}
2526

2627
@Override
2728
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
28-
if (!(msg instanceof ByteBuf)) {
29-
ctx.write(msg, promise);
30-
return;
29+
ctx.channel().pipeline().remove(RakClientNetworkSettingsHandler.NAME);
30+
31+
RakMessage packet;
32+
33+
if (!(msg instanceof RakMessage)) {
34+
if (msg instanceof ByteBuf) {
35+
packet = new RakMessage((ByteBuf) msg, RakReliability.RELIABLE_ORDERED, RakPriority.NORMAL);
36+
} else {
37+
throw new IllegalStateException("First packet was not an instance of RakMessage or ByteBuf: class " + msg.getClass().getName());
38+
}
39+
} else {
40+
packet = (RakMessage) msg;
3141
}
3242

33-
ByteBuf packet = (ByteBuf) msg;
43+
ByteBuf content = packet.content();
3444

35-
if (packet.capacity() < 4) {
36-
ctx.write(msg, promise);
37-
return;
45+
if (content.capacity() < 4) {
46+
throw new IllegalStateException("First packet was not a RequestNetworkSettings packet: Content less than 4 bytes");
3847
}
3948

40-
if (packet.getByte(0) != (byte) ID_GAME_PACKET) {
41-
ctx.write(msg, promise);
42-
return;
49+
if (content.getByte(0) != (byte) ID_GAME_PACKET) {
50+
throw new IllegalStateException("First packet was not a RequestNetworkSettings packet: Expected RakNet game packet ID (" + ID_GAME_PACKET + "), but got " + content.getByte(0));
4351
}
4452

4553
int rakVersion = this.channel.config().getOption(RakChannelOption.RAK_PROTOCOL_VERSION);
@@ -48,31 +56,25 @@ public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise)
4856
case 11:
4957
case 10:
5058
case 9:
51-
if (packet.getByte(1) != (byte) 0x06) break;
52-
if (packet.getByte(2) != (byte) 0xc1) break;
53-
if ((packet.getByte(3) & (byte) 0b10000111) != (byte) 0b00000001) break;
54-
onNetworkSettings(ctx, packet);
59+
if (content.getByte(1) != (byte) 0x06) break;
60+
if (content.getByte(2) != (byte) 0xc1) break;
61+
if ((content.getByte(3) & (byte) 0b10000111) != (byte) 0b00000001) break;
62+
this.networkSettingsPacketPromise.setSuccess(packet);
5563
return;
5664
case 8:
57-
if (packet.getByte(1) != (byte) 0x07) break;
58-
if (packet.getByte(2) != 0xc1) break;
59-
onNetworkSettings(ctx, packet);
65+
if (content.getByte(1) != (byte) 0x07) break;
66+
if (content.getByte(2) != (byte) 0xc1) break;
67+
this.networkSettingsPacketPromise.setSuccess(packet);
6068
return;
6169
case 7:
62-
if (packet.getByte(1) != (byte) 0x05) break;
63-
if (packet.getByte(2) != (byte) 0xc1) break;
64-
onNetworkSettings(ctx, packet);
70+
if (content.getByte(1) != (byte) 0x05) break;
71+
if (content.getByte(2) != (byte) 0xc1) break;
72+
this.networkSettingsPacketPromise.setSuccess(packet);
6573
return;
6674
default:
6775
throw new UnsupportedOperationException("Unsupported protocol version: " + rakVersion);
6876
}
6977

70-
ctx.write(msg, promise);
71-
}
72-
73-
private void onNetworkSettings(ChannelHandlerContext ctx, ByteBuf packet) {
74-
log.info("Detected network settings packet, removing handler");
75-
ctx.channel().attr(NETWORK_SETTINGS_PAYLOAD).set(packet.retain());
76-
ctx.channel().pipeline().remove(RakClientNetworkSettingsHandler.NAME);
78+
throw new IllegalStateException("First packet was not a RequestNetworkSettings packet: Invalid Bedrock packet ID");
7779
}
78-
}
80+
}

transport-raknet/src/main/java/org/cloudburstmc/netty/handler/codec/raknet/client/RakClientOfflineHandlerCompatible.java

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,12 @@
44
import io.netty.channel.Channel;
55
import io.netty.channel.ChannelHandlerContext;
66
import io.netty.channel.ChannelPromise;
7+
import io.netty.util.concurrent.Promise;
78
import org.cloudburstmc.netty.channel.raknet.RakChannel;
89
import org.cloudburstmc.netty.channel.raknet.RakOfflineState;
910
import org.cloudburstmc.netty.channel.raknet.config.RakChannelOption;
10-
import org.cloudburstmc.netty.handler.codec.raknet.common.ConnectedPingHandler;
11-
import org.cloudburstmc.netty.handler.codec.raknet.common.ConnectedPongHandler;
12-
import org.cloudburstmc.netty.handler.codec.raknet.common.DisconnectNotificationHandler;
13-
import org.cloudburstmc.netty.handler.codec.raknet.common.EncapsulatedToMessageHandler;
14-
import org.cloudburstmc.netty.handler.codec.raknet.common.RakAcknowledgeHandler;
15-
import org.cloudburstmc.netty.handler.codec.raknet.common.RakDatagramCodec;
16-
import org.cloudburstmc.netty.handler.codec.raknet.common.RakSessionCodec;
17-
import org.cloudburstmc.netty.handler.codec.raknet.common.RakSessionCodecCompatible;
11+
import org.cloudburstmc.netty.channel.raknet.packet.RakMessage;
12+
import org.cloudburstmc.netty.handler.codec.raknet.common.*;
1813
import org.cloudburstmc.netty.util.RakUtils;
1914

2015
public class RakClientOfflineHandlerCompatible extends RakClientOfflineHandler {
@@ -36,17 +31,18 @@ void onRetryAttempt(Channel channel) {
3631
@Override
3732
void onSuccess(ChannelHandlerContext ctx) {
3833
RakSessionCodec sessionCodec = new RakSessionCodecCompatible(this.rakChannel());
34+
Promise<RakMessage> networkSettingsPacketPromise = ctx.executor().newPromise();
3935
ctx.pipeline().addAfter(NAME, RakDatagramCodec.NAME, new RakDatagramCodec());
4036
ctx.pipeline().addAfter(RakDatagramCodec.NAME, RakAcknowledgeHandler.NAME, new RakAcknowledgeHandler(sessionCodec));
4137
ctx.pipeline().addAfter(RakAcknowledgeHandler.NAME, RakSessionCodec.NAME, sessionCodec);
4238
// Ensure new incoming connection batches with request network settings game packet
43-
ctx.pipeline().addAfter(RakSessionCodec.NAME, RakClientNetworkSettingsHandler.NAME, new RakClientNetworkSettingsHandler(this.rakChannel()));
39+
ctx.pipeline().addAfter(RakSessionCodec.NAME, RakClientNetworkSettingsHandler.NAME, new RakClientNetworkSettingsHandler(this.rakChannel(), networkSettingsPacketPromise));
4440
ctx.pipeline().addAfter(RakSessionCodec.NAME, ConnectedPingHandler.NAME, new ConnectedPingHandler());
4541
ctx.pipeline().addAfter(ConnectedPingHandler.NAME, ConnectedPongHandler.NAME, new ConnectedPongHandler(sessionCodec));
4642
ctx.pipeline().addAfter(ConnectedPongHandler.NAME, DisconnectNotificationHandler.NAME, DisconnectNotificationHandler.INSTANCE);
4743
// Replicate server behavior, and transform unhandled encapsulated packets to rakMessage
4844
ctx.pipeline().addAfter(DisconnectNotificationHandler.NAME, EncapsulatedToMessageHandler.NAME, EncapsulatedToMessageHandler.INSTANCE);
49-
ctx.pipeline().addAfter(DisconnectNotificationHandler.NAME, RakClientOnlineInitialHandlerCompatible.NAME, new RakClientOnlineInitialHandlerCompatible(this.rakChannel(), this.successPromise()));
45+
ctx.pipeline().addAfter(DisconnectNotificationHandler.NAME, RakClientOnlineInitialHandlerCompatible.NAME, new RakClientOnlineInitialHandlerCompatible(this.rakChannel(), this.successPromise(), networkSettingsPacketPromise));
5046
}
5147

5248
@Override

transport-raknet/src/main/java/org/cloudburstmc/netty/handler/codec/raknet/client/RakClientOnlineInitialHandlerCompatible.java

Lines changed: 19 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -3,65 +3,46 @@
33
import io.netty.buffer.ByteBuf;
44
import io.netty.channel.ChannelHandlerContext;
55
import io.netty.channel.ChannelPromise;
6+
import io.netty.util.concurrent.Promise;
67
import org.cloudburstmc.netty.channel.raknet.RakChannel;
78
import org.cloudburstmc.netty.channel.raknet.RakPriority;
89
import org.cloudburstmc.netty.channel.raknet.RakReliability;
9-
import org.cloudburstmc.netty.channel.raknet.config.RakChannelOption;
1010
import org.cloudburstmc.netty.channel.raknet.packet.RakMessage;
1111
import org.cloudburstmc.netty.util.RakUtils;
1212

13-
import static org.cloudburstmc.netty.channel.raknet.RakConstants.*;
13+
import static org.cloudburstmc.netty.channel.raknet.RakConstants.ID_CONNECTED_PING;
14+
import static org.cloudburstmc.netty.channel.raknet.RakConstants.IPV4_MESSAGE_SIZE;
1415

1516
public class RakClientOnlineInitialHandlerCompatible extends RakClientOnlineInitialHandler {
1617
public static final String NAME = "rak-client-online-initial-handler";
1718

19+
private final Promise<RakMessage> networkSettingsPacketPromise;
1820
private long pingTime = 0;
1921

20-
public RakClientOnlineInitialHandlerCompatible(RakChannel rakChannel, ChannelPromise promise) {
21-
super(rakChannel, promise);
22+
public RakClientOnlineInitialHandlerCompatible(RakChannel rakChannel, ChannelPromise successPromise, Promise<RakMessage> networkSettingsPacketPromise) {
23+
super(rakChannel, successPromise);
24+
this.networkSettingsPacketPromise = networkSettingsPacketPromise;
2225
}
2326

2427
@Override
2528
void onSuccess(ChannelHandlerContext ctx) {
2629
super.onSuccess(ctx);
2730

28-
ByteBuf incomingBuffer = ctx.alloc().ioBuffer();
29-
this.writeIncomingConnection(ctx, incomingBuffer, pingTime);
30-
ctx.write(new RakMessage(incomingBuffer, RakReliability.RELIABLE_ORDERED, RakPriority.NORMAL));
31+
// Wait for the RequestNetworkSettings packet before sending the final batch
32+
this.networkSettingsPacketPromise.addListener(future -> {
33+
ByteBuf incomingBuffer = ctx.alloc().ioBuffer();
34+
this.writeIncomingConnection(ctx, incomingBuffer, pingTime);
35+
ctx.write(new RakMessage(incomingBuffer, RakReliability.RELIABLE_ORDERED, RakPriority.NORMAL));
3136

32-
ByteBuf pingBuffer = ctx.alloc().ioBuffer();
33-
pingBuffer.writeByte(ID_CONNECTED_PING);
34-
pingBuffer.writeLong(System.currentTimeMillis());
35-
ctx.write(new RakMessage(pingBuffer, RakReliability.UNRELIABLE, RakPriority.NORMAL));
37+
ByteBuf pingBuffer = ctx.alloc().ioBuffer();
38+
pingBuffer.writeByte(ID_CONNECTED_PING);
39+
pingBuffer.writeLong(System.currentTimeMillis());
40+
ctx.write(new RakMessage(pingBuffer, RakReliability.UNRELIABLE, RakPriority.NORMAL));
3641

37-
ByteBuf netSettingsBuffer = ctx.channel().attr(RakClientNetworkSettingsHandler.NETWORK_SETTINGS_PAYLOAD).get();
38-
if (netSettingsBuffer == null) {
39-
netSettingsBuffer = ctx.alloc().ioBuffer();
40-
netSettingsBuffer.writeByte(ID_GAME_PACKET);
41-
int rakVersion = this.rakChannel().config().getOption(RakChannelOption.RAK_PROTOCOL_VERSION);
42-
switch (rakVersion) {
43-
case 11:
44-
case 10:
45-
case 9:
46-
netSettingsBuffer.writeByte(0x06); // length
47-
netSettingsBuffer.writeByte(0xc1).writeByte(0x01); // header
48-
break;
49-
case 8:
50-
netSettingsBuffer.writeByte(0x07); // length
51-
netSettingsBuffer.writeByte(0xc1).writeByte(0x00).writeByte(0x00); // header
52-
break;
53-
case 7:
54-
netSettingsBuffer.writeByte(0x05); // length
55-
netSettingsBuffer.writeByte(0xc1); // header
56-
break;
57-
default:
58-
throw new UnsupportedOperationException("Unsupported protocol version: " + rakVersion);
59-
}
60-
netSettingsBuffer.writeInt(this.rakChannel().config().getOption(RakChannelOption.RAK_CLIENT_BEDROCK_PROTOCOL_VERSION));
61-
}
62-
ctx.write(new RakMessage(netSettingsBuffer, RakReliability.RELIABLE_ORDERED, RakPriority.NORMAL));
42+
ctx.write(future.get());
6343

64-
ctx.flush();
44+
ctx.flush();
45+
});
6546
}
6647

6748
@Override

0 commit comments

Comments
 (0)