mirror of
https://gitlab.bixilon.de/bixilon/minosoft.git
synced 2025-09-11 16:36:58 -04:00
Remove netty networking (should be rewritten from scratch)
This commit is contained in:
parent
09f22e64a2
commit
a0c39e835d
5
pom.xml
5
pom.xml
@ -99,10 +99,5 @@
|
||||
<artifactId>jcl-core</artifactId>
|
||||
<version>2.8</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.netty</groupId>
|
||||
<artifactId>netty-all</artifactId>
|
||||
<version>4.1.52.Final</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
@ -1,98 +0,0 @@
|
||||
/*
|
||||
* Minosoft
|
||||
* Copyright (C) 2020 Moritz Zwerger
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
|
||||
*/
|
||||
|
||||
package de.bixilon.minosoft.protocol.network.netty;
|
||||
|
||||
import de.bixilon.minosoft.logging.Log;
|
||||
import de.bixilon.minosoft.protocol.network.Connection;
|
||||
import de.bixilon.minosoft.protocol.network.Network;
|
||||
import de.bixilon.minosoft.protocol.packets.ServerboundPacket;
|
||||
import de.bixilon.minosoft.protocol.protocol.ConnectionStates;
|
||||
import de.bixilon.minosoft.util.ServerAddress;
|
||||
import io.netty.bootstrap.Bootstrap;
|
||||
import io.netty.channel.ChannelFuture;
|
||||
import io.netty.channel.EventLoopGroup;
|
||||
import io.netty.channel.nio.NioEventLoopGroup;
|
||||
import io.netty.channel.socket.nio.NioSocketChannel;
|
||||
|
||||
import javax.crypto.SecretKey;
|
||||
|
||||
public class NettyNetwork implements Network {
|
||||
final Connection connection;
|
||||
NioSocketChannel nioSocketChannel;
|
||||
int compressionThreshold = -1;
|
||||
|
||||
public NettyNetwork(Connection connection) {
|
||||
this.connection = connection;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connect(ServerAddress address) {
|
||||
EventLoopGroup eventLoopGroup = new NioEventLoopGroup();
|
||||
|
||||
Bootstrap clientBootstrap = new Bootstrap();
|
||||
clientBootstrap.group(eventLoopGroup).channel(NioSocketChannel.class).handler(new TCPClientChannelInitializer(connection, this));
|
||||
|
||||
try {
|
||||
ChannelFuture channelFuture = clientBootstrap.connect(address.getHostname(), address.getPort()).sync();
|
||||
if (channelFuture.isSuccess()) {
|
||||
connection.setConnectionState(ConnectionStates.HANDSHAKING);
|
||||
}
|
||||
channelFuture.channel().closeFuture().sync();
|
||||
} catch (InterruptedException e) {
|
||||
Log.info(String.format("connection failed: %s", e));
|
||||
connection.setConnectionState(ConnectionStates.FAILED);
|
||||
} finally {
|
||||
connection.setConnectionState(ConnectionStates.DISCONNECTED);
|
||||
eventLoopGroup.shutdownGracefully();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendPacket(ServerboundPacket packet) {
|
||||
if (this.nioSocketChannel.eventLoop().inEventLoop()) {
|
||||
this.nioSocketChannel.writeAndFlush(packet);
|
||||
return;
|
||||
}
|
||||
this.nioSocketChannel.eventLoop().execute(() -> NettyNetwork.this.nioSocketChannel.writeAndFlush(packet));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disconnect() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Exception getLastException() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public int getCompressionThreshold() {
|
||||
return compressionThreshold;
|
||||
}
|
||||
|
||||
public void setNioChannel(NioSocketChannel nioSocketChannel) {
|
||||
this.nioSocketChannel = nioSocketChannel;
|
||||
}
|
||||
|
||||
public void enableEncryption(SecretKey key) {
|
||||
/*
|
||||
this.nioSocketChannel.pipeline().addBefore("decoder", "decrypt", new EncryptionHandler(key));
|
||||
this.nioSocketChannel.pipeline().addBefore("encoder", "encrypt", new DecryptionHandler(key));
|
||||
Log.debug("Encryption enabled!");
|
||||
*/
|
||||
//ToDo
|
||||
Log.fatal("Encryption is not implemented in netty yet!");
|
||||
disconnect();
|
||||
}
|
||||
}
|
@ -1,142 +0,0 @@
|
||||
/*
|
||||
* Minosoft
|
||||
* Copyright (C) 2020 Moritz Zwerger
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
|
||||
*/
|
||||
|
||||
package de.bixilon.minosoft.protocol.network.netty;
|
||||
|
||||
import de.bixilon.minosoft.logging.Log;
|
||||
import de.bixilon.minosoft.logging.LogLevels;
|
||||
import de.bixilon.minosoft.protocol.network.Connection;
|
||||
import de.bixilon.minosoft.protocol.packets.ClientboundPacket;
|
||||
import de.bixilon.minosoft.protocol.packets.clientbound.interfaces.PacketCompressionInterface;
|
||||
import de.bixilon.minosoft.protocol.packets.clientbound.login.PacketEncryptionRequest;
|
||||
import de.bixilon.minosoft.protocol.packets.clientbound.login.PacketLoginSuccess;
|
||||
import de.bixilon.minosoft.protocol.protocol.*;
|
||||
import de.bixilon.minosoft.util.Util;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.ByteToMessageDecoder;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.List;
|
||||
|
||||
public class PacketDecoder extends ByteToMessageDecoder {
|
||||
final Connection connection;
|
||||
final NettyNetwork nettyNetwork;
|
||||
|
||||
public PacketDecoder(Connection connection, NettyNetwork nettyNetwork) {
|
||||
this.connection = connection;
|
||||
this.nettyNetwork = nettyNetwork;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List<Object> list) {
|
||||
byteBuf.markReaderIndex();
|
||||
int numRead = 0;
|
||||
int length = 0;
|
||||
byte read;
|
||||
do
|
||||
{
|
||||
if (!byteBuf.isReadable()) {
|
||||
byteBuf.resetReaderIndex();
|
||||
return;
|
||||
}
|
||||
read = byteBuf.readByte();
|
||||
int value = (read & 0b01111111);
|
||||
length |= (value << (7 * numRead));
|
||||
|
||||
numRead++;
|
||||
if (numRead > 5) {
|
||||
throw new RuntimeException("VarInt is too big");
|
||||
}
|
||||
} while ((read & 0b10000000) != 0);
|
||||
if (length > ProtocolDefinition.PROTOCOL_PACKET_MAX_SIZE) {
|
||||
Log.protocol(String.format("Server sent us a to big packet (%d bytes > %d bytes)", length, ProtocolDefinition.PROTOCOL_PACKET_MAX_SIZE));
|
||||
byteBuf.skipBytes(length);
|
||||
return;
|
||||
}
|
||||
if (byteBuf.readableBytes() < length) {
|
||||
byteBuf.resetReaderIndex();
|
||||
return;
|
||||
}
|
||||
|
||||
byte[] data;
|
||||
ByteBuf dataBuf = byteBuf.readBytes(length);
|
||||
if (dataBuf.hasArray()) {
|
||||
data = dataBuf.array();
|
||||
} else {
|
||||
data = new byte[length];
|
||||
dataBuf.getBytes(0, data);
|
||||
}
|
||||
|
||||
if (nettyNetwork.getCompressionThreshold() >= 0) {
|
||||
// compression is enabled
|
||||
// check if there is a need to decompress it and if so, do it!
|
||||
InByteBuffer rawBuffer = new InByteBuffer(data, connection);
|
||||
int packetSize = rawBuffer.readVarInt();
|
||||
byte[] left = rawBuffer.readBytesLeft();
|
||||
if (packetSize == 0) {
|
||||
// no need
|
||||
data = left;
|
||||
} else {
|
||||
// need to decompress data
|
||||
data = Util.decompress(left, connection).readBytesLeft();
|
||||
}
|
||||
}
|
||||
|
||||
InPacketBuffer inPacketBuffer = new InPacketBuffer(data, connection);
|
||||
Packets.Clientbound packet = null;
|
||||
try {
|
||||
packet = connection.getPacketByCommand(connection.getConnectionState(), inPacketBuffer.getCommand());
|
||||
if (packet == null) {
|
||||
Log.fatal(String.format("Packet mapping does not contain a packet with id 0x%x. The server sends bullshit or your versions.json broken!", inPacketBuffer.getCommand()));
|
||||
nettyNetwork.disconnect();
|
||||
throw new RuntimeException(String.format("Invalid packet 0x%x", inPacketBuffer.getCommand()));
|
||||
}
|
||||
Class<? extends ClientboundPacket> clazz = packet.getClazz();
|
||||
|
||||
if (clazz == null) {
|
||||
Log.warn(String.format("[IN] Received unknown packet (id=0x%x, name=%s, length=%d, dataLength=%d, version=%s, state=%s)", inPacketBuffer.getCommand(), packet, inPacketBuffer.getLength(), inPacketBuffer.getBytesLeft(), connection.getVersion(), connection.getConnectionState()));
|
||||
return;
|
||||
}
|
||||
try {
|
||||
ClientboundPacket packetInstance = clazz.getConstructor().newInstance();
|
||||
boolean success = packetInstance.read(inPacketBuffer);
|
||||
if (inPacketBuffer.getBytesLeft() > 0 || !success) {
|
||||
// warn not all data used
|
||||
Log.warn(String.format("[IN] Could not parse packet %s (used=%d, available=%d, total=%d, success=%s)", packet, inPacketBuffer.getPosition(), inPacketBuffer.getBytesLeft(), inPacketBuffer.getLength(), success));
|
||||
return;
|
||||
}
|
||||
|
||||
//set special settings to avoid miss timing issues
|
||||
if (packetInstance instanceof PacketLoginSuccess) {
|
||||
connection.setConnectionState(ConnectionStates.PLAY);
|
||||
} else if (packetInstance instanceof PacketCompressionInterface) {
|
||||
nettyNetwork.compressionThreshold = ((PacketCompressionInterface) packetInstance).getThreshold();
|
||||
} else if (packetInstance instanceof PacketEncryptionRequest) {
|
||||
// wait until response is ready
|
||||
list.add(packetInstance);
|
||||
return;
|
||||
}
|
||||
list.add(packetInstance);
|
||||
} catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
|
||||
// safety first, but will not occur
|
||||
e.printStackTrace();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.protocol(String.format("An error occurred while parsing an packet (%s): %s", packet, e));
|
||||
if (Log.getLevel().ordinal() >= LogLevels.DEBUG.ordinal()) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,67 +0,0 @@
|
||||
/*
|
||||
* Minosoft
|
||||
* Copyright (C) 2020 Moritz Zwerger
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
|
||||
*/
|
||||
|
||||
package de.bixilon.minosoft.protocol.network.netty;
|
||||
|
||||
import de.bixilon.minosoft.protocol.network.Connection;
|
||||
import de.bixilon.minosoft.protocol.packets.ServerboundPacket;
|
||||
import de.bixilon.minosoft.protocol.packets.serverbound.login.PacketEncryptionResponse;
|
||||
import de.bixilon.minosoft.protocol.protocol.OutByteBuffer;
|
||||
import de.bixilon.minosoft.util.Util;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.MessageToByteEncoder;
|
||||
|
||||
public class PacketEncoder extends MessageToByteEncoder<ServerboundPacket> {
|
||||
final Connection connection;
|
||||
final NettyNetwork nettyNetwork;
|
||||
|
||||
public PacketEncoder(Connection connection, NettyNetwork nettyNetwork) {
|
||||
this.connection = connection;
|
||||
this.nettyNetwork = nettyNetwork;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void encode(ChannelHandlerContext channelHandlerContext, ServerboundPacket packet, ByteBuf byteBuf) throws Exception {
|
||||
packet.log();
|
||||
byte[] data = packet.write(connection).getOutBytes();
|
||||
if (nettyNetwork.getCompressionThreshold() >= 0) {
|
||||
// compression is enabled
|
||||
// check if there is a need to compress it and if so, do it!
|
||||
OutByteBuffer outRawBuffer = new OutByteBuffer(connection);
|
||||
if (data.length >= nettyNetwork.getCompressionThreshold()) {
|
||||
// compress it
|
||||
OutByteBuffer compressedBuffer = new OutByteBuffer(connection);
|
||||
byte[] compressed = Util.compress(data);
|
||||
compressedBuffer.writeVarInt(data.length);
|
||||
compressedBuffer.writeBytes(compressed);
|
||||
outRawBuffer.prefixVarInt(compressedBuffer.getOutBytes().length);
|
||||
} else {
|
||||
outRawBuffer.prefixVarInt(0);
|
||||
outRawBuffer.writeVarInt(data.length + 1); // 1 for the compressed length (0)
|
||||
}
|
||||
data = outRawBuffer.getOutBytes();
|
||||
} else {
|
||||
// append packet length
|
||||
OutByteBuffer bufferWithLengthPrefix = new OutByteBuffer(connection);
|
||||
bufferWithLengthPrefix.writeVarInt(data.length);
|
||||
bufferWithLengthPrefix.writeBytes(data);
|
||||
data = bufferWithLengthPrefix.getOutBytes();
|
||||
}
|
||||
byteBuf.writeBytes(data);
|
||||
if (packet instanceof PacketEncryptionResponse) {
|
||||
// enable encryption
|
||||
nettyNetwork.enableEncryption(((PacketEncryptionResponse) packet).getSecretKey());
|
||||
}
|
||||
}
|
||||
}
|
@ -1,41 +0,0 @@
|
||||
/*
|
||||
* Minosoft
|
||||
* Copyright (C) 2020 Moritz Zwerger
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
|
||||
*/
|
||||
|
||||
package de.bixilon.minosoft.protocol.network.netty;
|
||||
|
||||
import de.bixilon.minosoft.logging.Log;
|
||||
import de.bixilon.minosoft.logging.LogLevels;
|
||||
import de.bixilon.minosoft.protocol.network.Connection;
|
||||
import de.bixilon.minosoft.protocol.packets.ClientboundPacket;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.SimpleChannelInboundHandler;
|
||||
|
||||
public class PacketReceiver extends SimpleChannelInboundHandler<ClientboundPacket> {
|
||||
final Connection connection;
|
||||
|
||||
public PacketReceiver(Connection connection) {
|
||||
this.connection = connection;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void channelRead0(ChannelHandlerContext channelHandlerContext, ClientboundPacket packet) {
|
||||
try {
|
||||
packet.log();
|
||||
packet.handle(connection.getHandler());
|
||||
} catch (Exception e) {
|
||||
if (Log.getLevel().ordinal() >= LogLevels.DEBUG.ordinal()) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,41 +0,0 @@
|
||||
/*
|
||||
* Minosoft
|
||||
* Copyright (C) 2020 Moritz Zwerger
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
|
||||
*/
|
||||
|
||||
package de.bixilon.minosoft.protocol.network.netty;
|
||||
|
||||
import de.bixilon.minosoft.protocol.network.Connection;
|
||||
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition;
|
||||
import io.netty.channel.ChannelInitializer;
|
||||
import io.netty.channel.socket.nio.NioSocketChannel;
|
||||
import io.netty.handler.timeout.ReadTimeoutHandler;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class TCPClientChannelInitializer extends ChannelInitializer<NioSocketChannel> {
|
||||
final Connection connection;
|
||||
final NettyNetwork nettyNetwork;
|
||||
|
||||
public TCPClientChannelInitializer(Connection connection, NettyNetwork nettyNetwork) {
|
||||
this.connection = connection;
|
||||
this.nettyNetwork = nettyNetwork;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initChannel(NioSocketChannel socketChannel) {
|
||||
nettyNetwork.setNioChannel(socketChannel);
|
||||
socketChannel.pipeline().addLast("timeout", new ReadTimeoutHandler(ProtocolDefinition.SOCKET_TIMEOUT, TimeUnit.MILLISECONDS));
|
||||
socketChannel.pipeline().addLast("decoder", new PacketDecoder(connection, nettyNetwork));
|
||||
socketChannel.pipeline().addLast("encoder", new PacketEncoder(connection, nettyNetwork));
|
||||
socketChannel.pipeline().addLast(new PacketReceiver(connection));
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user