Fix connection crash

Signed-off-by: TheMode <themode@outlook.fr>
This commit is contained in:
TheMode 2021-08-04 00:37:17 +02:00
parent 548cee55e0
commit 66b567597a
4 changed files with 37 additions and 44 deletions

View File

@ -8,8 +8,7 @@ import java.nio.ByteBuffer;
* Represents a packet which is already framed. (packet id+payload) + optional compression
* Can be used if you want to send the exact same buffer to multiple clients without processing it more than once.
*/
public class FramedPacket {
public final class FramedPacket {
private final ByteBuffer body;
public FramedPacket(@NotNull ByteBuffer body) {

View File

@ -64,16 +64,12 @@ public class NettyPlayerConnection extends PlayerConnection {
private PlayerSkin bungeeSkin;
private final ByteBuffer tickBuffer = ByteBuffer.allocateDirect(Server.SOCKET_BUFFER_SIZE);
private ByteBuffer cacheBuffer;
private volatile ByteBuffer cacheBuffer;
public NettyPlayerConnection(@NotNull SocketChannel channel) {
public NettyPlayerConnection(@NotNull SocketChannel channel, SocketAddress remoteAddress) {
super();
this.channel = channel;
try {
this.remoteAddress = channel.getRemoteAddress();
} catch (IOException e) {
e.printStackTrace();
}
this.remoteAddress = remoteAddress;
}
public void processPackets(Worker.Context workerContext, PacketProcessor packetProcessor) {
@ -133,8 +129,8 @@ public class NettyPlayerConnection extends PlayerConnection {
readBuffer.limit(limit).position(packetEnd);
} catch (BufferUnderflowException e) {
readBuffer.reset();
this.cacheBuffer = ByteBuffer.allocateDirect(readBuffer.remaining());
this.cacheBuffer.put(readBuffer).flip();
this.cacheBuffer = ByteBuffer.allocateDirect(readBuffer.remaining())
.put(readBuffer).flip();
break;
}
}
@ -191,7 +187,7 @@ public class NettyPlayerConnection extends PlayerConnection {
serverPacket = ((ComponentHoldingServerPacket) serverPacket).copyWithOperator(component ->
GlobalTranslator.render(component, Objects.requireNonNullElseGet(getPlayer().getLocale(), MinestomAdventure::getDefaultLocale)));
}
attemptWrite(PacketUtils.createFramedPacket(serverPacket));
attemptWrite(serverPacket);
} else {
// Player is probably not logged yet
writeAndFlush(serverPacket);
@ -208,17 +204,34 @@ public class NettyPlayerConnection extends PlayerConnection {
}
public void writeAndFlush(@NotNull ServerPacket packet) {
synchronized (tickBuffer){
PacketUtils.writeFramedPacket(tickBuffer, packet, compressed);
synchronized (tickBuffer) {
attemptWrite(packet);
flush();
}
}
public void attemptWrite(ServerPacket packet) {
synchronized (tickBuffer) {
final int position = tickBuffer.position();
try {
PacketUtils.writeFramedPacket(tickBuffer, packet, compressed);
} catch (BufferOverflowException e) {
try {
this.channel.write(tickBuffer.position(position).flip());
this.tickBuffer.clear();
PacketUtils.writeFramedPacket(tickBuffer, packet, compressed);
} catch (IOException ex) {
disconnect();
MinecraftServer.getExceptionManager().handleException(ex);
}
}
}
}
public void attemptWrite(ByteBuffer buffer) {
buffer.flip();
synchronized (tickBuffer) {
try {
this.tickBuffer.put(buffer);
this.tickBuffer.put(buffer.flip());
} catch (BufferOverflowException e) {
try {
this.channel.write(tickBuffer.flip());
@ -235,13 +248,12 @@ public class NettyPlayerConnection extends PlayerConnection {
public void flush() {
synchronized (tickBuffer) {
this.tickBuffer.flip();
if (tickBuffer.remaining() == 0) {
if (tickBuffer.position() == 0) {
// Nothing to write
return;
}
try {
this.channel.write(tickBuffer);
this.channel.write(tickBuffer.flip());
} catch (IOException e) {
MinecraftServer.getExceptionManager().handleException(e);
}
@ -402,9 +414,6 @@ public class NettyPlayerConnection extends PlayerConnection {
}
}
public void releaseTickBuffer() {
}
public byte[] getNonce() {
return nonce;
}

View File

@ -73,8 +73,7 @@ public class Worker {
}
public void receiveConnection(SocketChannel channel) throws IOException {
var connection = new NettyPlayerConnection(channel);
this.connectionMap.put(channel, connection);
this.connectionMap.put(channel, new NettyPlayerConnection(channel, channel.getRemoteAddress()));
register(channel);
this.selector.wakeup();
}
@ -91,7 +90,7 @@ public class Worker {
private void disconnect(NettyPlayerConnection connection, SocketChannel channel) throws IOException {
// Client close
channel.close();
connectionMap.remove(channel);
this.connectionMap.remove(channel);
// Remove the connection
connection.refreshOnline(false);
Player player = connection.getPlayer();

View File

@ -89,7 +89,8 @@ public final class PacketUtils {
// Send grouped packet...
final boolean success = PACKET_LISTENER_MANAGER.processServerPacket(packet, players);
if (success) {
final ByteBuffer finalBuffer = createFramedPacket(packet);
ByteBuffer finalBuffer = ByteBuffer.allocate(2_000_000);
writeFramedPacket(finalBuffer, packet, MinecraftServer.getCompressionThreshold() > 0);
final FramedPacket framedPacket = new FramedPacket(finalBuffer);
// Send packet to all players
for (Player player : players) {
@ -98,7 +99,6 @@ public final class PacketUtils {
// Verify if the player should receive the packet
if (playerValidator != null && !playerValidator.isValid(player))
continue;
final PlayerConnection playerConnection = player.getPlayerConnection();
if (playerConnection instanceof NettyPlayerConnection) {
final NettyPlayerConnection nettyPlayerConnection = (NettyPlayerConnection) playerConnection;
@ -114,8 +114,7 @@ public final class PacketUtils {
// Verify if the player should receive the packet
if (playerValidator != null && !playerValidator.isValid(player))
continue;
final PlayerConnection playerConnection = player.getPlayerConnection();
playerConnection.sendPacket(packet, false);
player.getPlayerConnection().sendPacket(packet, false);
}
}
}
@ -154,11 +153,11 @@ public final class PacketUtils {
// Packet large enough, compress
final int limitCache = buffer.limit();
buffer.position(contentStart).limit(contentStart + packetSize);
var uncompressedCopy = ByteBuffer.allocate(packetSize).put(buffer);
var uncompressedCopy = ByteBuffer.allocate(packetSize).put(buffer).flip();
buffer.position(contentStart).limit(limitCache);
var deflater = COMPRESSOR.get();
deflater.setInput(uncompressedCopy.flip());
deflater.setInput(uncompressedCopy);
deflater.finish();
deflater.deflate(buffer);
deflater.reset();
@ -170,17 +169,4 @@ public final class PacketUtils {
Utils.writeVarIntHeader(buffer, uncompressedIndex, 0);
}
}
/**
* Creates a "framed packet" (packet which can be send and understood by a Minecraft client)
* from a server packet, directly into an output buffer.
* <p>
* Can be used if you want to store a raw buffer and send it later without the additional writing cost.
* Compression is applied if {@link MinecraftServer#getCompressionThreshold()} is greater than 0.
*/
public static @NotNull ByteBuffer createFramedPacket(@NotNull ServerPacket serverPacket) {
ByteBuffer packetBuf = ByteBuffer.allocate(2_000_000);
writeFramedPacket(packetBuf, serverPacket, MinecraftServer.getCompressionThreshold() > 0);
return packetBuf;
}
}