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 * 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. * 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; private final ByteBuffer body;
public FramedPacket(@NotNull ByteBuffer body) { public FramedPacket(@NotNull ByteBuffer body) {

View File

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

View File

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

View File

@ -89,7 +89,8 @@ public final class PacketUtils {
// Send grouped packet... // Send grouped packet...
final boolean success = PACKET_LISTENER_MANAGER.processServerPacket(packet, players); final boolean success = PACKET_LISTENER_MANAGER.processServerPacket(packet, players);
if (success) { 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); final FramedPacket framedPacket = new FramedPacket(finalBuffer);
// Send packet to all players // Send packet to all players
for (Player player : players) { for (Player player : players) {
@ -98,7 +99,6 @@ public final class PacketUtils {
// Verify if the player should receive the packet // Verify if the player should receive the packet
if (playerValidator != null && !playerValidator.isValid(player)) if (playerValidator != null && !playerValidator.isValid(player))
continue; continue;
final PlayerConnection playerConnection = player.getPlayerConnection(); final PlayerConnection playerConnection = player.getPlayerConnection();
if (playerConnection instanceof NettyPlayerConnection) { if (playerConnection instanceof NettyPlayerConnection) {
final NettyPlayerConnection nettyPlayerConnection = (NettyPlayerConnection) playerConnection; final NettyPlayerConnection nettyPlayerConnection = (NettyPlayerConnection) playerConnection;
@ -114,8 +114,7 @@ public final class PacketUtils {
// Verify if the player should receive the packet // Verify if the player should receive the packet
if (playerValidator != null && !playerValidator.isValid(player)) if (playerValidator != null && !playerValidator.isValid(player))
continue; continue;
final PlayerConnection playerConnection = player.getPlayerConnection(); player.getPlayerConnection().sendPacket(packet, false);
playerConnection.sendPacket(packet, false);
} }
} }
} }
@ -154,11 +153,11 @@ public final class PacketUtils {
// Packet large enough, compress // Packet large enough, compress
final int limitCache = buffer.limit(); final int limitCache = buffer.limit();
buffer.position(contentStart).limit(contentStart + packetSize); 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); buffer.position(contentStart).limit(limitCache);
var deflater = COMPRESSOR.get(); var deflater = COMPRESSOR.get();
deflater.setInput(uncompressedCopy.flip()); deflater.setInput(uncompressedCopy);
deflater.finish(); deflater.finish();
deflater.deflate(buffer); deflater.deflate(buffer);
deflater.reset(); deflater.reset();
@ -170,17 +169,4 @@ public final class PacketUtils {
Utils.writeVarIntHeader(buffer, uncompressedIndex, 0); 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;
}
} }