Simplify packet reading

Signed-off-by: TheMode <themode@outlook.fr>
This commit is contained in:
TheMode 2021-09-11 03:39:59 +02:00
parent 0c5b37ed18
commit ee95015ed3
3 changed files with 28 additions and 32 deletions

View File

@ -37,6 +37,7 @@ import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.zip.DataFormatException;
import java.util.zip.Inflater;
/**
* Represents a socket connection.
@ -88,7 +89,7 @@ public class PlayerSocketConnection extends PlayerConnection {
}
public void processPackets(Worker.Context workerContext, PacketProcessor packetProcessor) {
final var readBuffer = workerContext.readBuffer;
final BinaryBuffer readBuffer = workerContext.readBuffer;
// Decrypt data
if (encrypted) {
final Cipher cipher = decryptCipher;
@ -104,7 +105,6 @@ public class PlayerSocketConnection extends PlayerConnection {
readBuffer.clear();
readBuffer.writeBytes(output);
}
final int limit = readBuffer.writerOffset();
// Read all packets
while (readBuffer.readableBytes() > 0) {
final var beginMark = readBuffer.mark();
@ -112,42 +112,35 @@ public class PlayerSocketConnection extends PlayerConnection {
// Ensure that the buffer contains the full packet (or wait for next socket read)
final int packetLength = readBuffer.readVarInt();
final int readerStart = readBuffer.readerOffset();
final int packetEnd = readerStart + packetLength;
if (packetEnd > readBuffer.writerOffset()) {
if (!readBuffer.canRead(packetLength)) {
// Integrity fail
throw new BufferUnderflowException();
}
// Read packet https://wiki.vg/Protocol#Packet_format
BinaryBuffer content;
int payloadLength;
if (!compressed) {
// Compression disabled, payload is following
content = readBuffer;
payloadLength = packetLength;
} else {
BinaryBuffer content = readBuffer;
int decompressedSize = packetLength;
if (compressed) {
final int dataLength = readBuffer.readVarInt();
final int payloadLength = packetLength - (readBuffer.readerOffset() - readerStart);
if (dataLength == 0) {
// Data is too small to be compressed, payload is following
content = readBuffer;
payloadLength = packetLength - (content.readerOffset() - readerStart);
decompressedSize = payloadLength;
} else {
// Decompress to content buffer
content = workerContext.contentBuffer;
payloadLength = dataLength;
final var contentStartMark = content.mark();
content = workerContext.contentBuffer.clear();
decompressedSize = dataLength;
try {
final var inflater = workerContext.inflater;
inflater.setInput(readBuffer.asByteBuffer(readBuffer.readerOffset(), packetEnd));
inflater.inflate(content.asByteBuffer(0, content.capacity()));
Inflater inflater = workerContext.inflater;
inflater.setInput(readBuffer.asByteBuffer(readBuffer.readerOffset(), payloadLength));
inflater.inflate(content.asByteBuffer(0, dataLength));
inflater.reset();
} catch (DataFormatException e) {
MinecraftServer.getExceptionManager().handleException(e);
}
content.reset(contentStartMark);
}
}
// Process packet
ByteBuffer payload = content.asByteBuffer(content.readerOffset(), payloadLength);
ByteBuffer payload = content.asByteBuffer(content.readerOffset(), decompressedSize);
final int packetId = Utils.readVarInt(payload);
try {
packetProcessor.process(this, packetId, payload);
@ -162,7 +155,7 @@ public class PlayerSocketConnection extends PlayerConnection {
}
}
// Position buffer to read the next packet
readBuffer.reset(packetEnd, limit);
readBuffer.readerOffset(readerStart + packetLength);
} catch (BufferUnderflowException e) {
readBuffer.reset(beginMark);
this.cacheBuffer = BinaryBuffer.copy(readBuffer);

View File

@ -8,6 +8,7 @@ import net.minestom.server.utils.binary.BinaryBuffer;
import org.jetbrains.annotations.ApiStatus;
import java.io.IOException;
import java.net.Socket;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
@ -42,7 +43,7 @@ public final class Worker extends Thread {
if (!key.isReadable()) return;
PlayerSocketConnection connection = connectionMap.get(channel);
try {
var readBuffer = context.readBuffer;
BinaryBuffer readBuffer = context.readBuffer.clear();
// Consume last incomplete packet
connection.consumeCache(readBuffer);
// Read & process
@ -51,8 +52,6 @@ public final class Worker extends Thread {
} catch (IOException e) {
// TODO print exception? (should ignore disconnection)
connection.disconnect();
} finally {
context.clearBuffers();
}
});
} catch (IOException e) {
@ -80,7 +79,7 @@ public final class Worker extends Thread {
this.connectionMap.put(channel, new PlayerSocketConnection(this, channel, channel.getRemoteAddress()));
channel.configureBlocking(false);
channel.register(selector, SelectionKey.OP_READ);
var socket = channel.socket();
Socket socket = channel.socket();
socket.setSendBufferSize(Server.SOCKET_SEND_BUFFER_SIZE);
socket.setReceiveBufferSize(Server.SOCKET_RECEIVE_BUFFER_SIZE);
socket.setTcpNoDelay(Server.NO_DELAY);
@ -95,10 +94,5 @@ public final class Worker extends Thread {
public final BinaryBuffer readBuffer = BinaryBuffer.ofSize(Server.MAX_PACKET_SIZE);
public final BinaryBuffer contentBuffer = BinaryBuffer.ofSize(Server.MAX_PACKET_SIZE);
public final Inflater inflater = new Inflater();
void clearBuffers() {
this.readBuffer.clear();
this.contentBuffer.clear();
}
}
}

View File

@ -78,6 +78,10 @@ public final class BinaryBuffer {
reset(marker.readerOffset(), marker.writerOffset());
}
public boolean canRead(int size) {
return readerOffset + size < capacity;
}
public boolean canWrite(int size) {
return writerOffset + size < capacity;
}
@ -90,6 +94,10 @@ public final class BinaryBuffer {
return readerOffset;
}
public void readerOffset(int offset) {
this.readerOffset = offset;
}
public int writerOffset() {
return writerOffset;
}
@ -114,9 +122,10 @@ public final class BinaryBuffer {
return readBytes(readableBytes());
}
public void clear() {
public BinaryBuffer clear() {
this.readerOffset = 0;
this.writerOffset = 0;
return this;
}
public ByteBuffer asByteBuffer(int reader, int writer) {