Remove Netty

This commit is contained in:
2023-08-02 14:06:27 +02:00
parent 676344a385
commit d3edc547d5
9 changed files with 388 additions and 272 deletions

View File

@@ -1,106 +0,0 @@
package me.unlegitdqrk.fakeminecraftserver;
import com.google.gson.Gson;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import me.unlegitdqrk.fakeminecraftserver.streams.MojewInputStream;
import me.unlegitdqrk.fakeminecraftserver.streams.MojewOutputStream;
/**
* @author UnlegitDqrk
*/
public class BasePacketHandler extends ChannelInboundHandlerAdapter {
private final Gson gson = new Gson();
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
MojewInputStream inputStream = new MojewInputStream((ByteBuf) msg);
// handshake
int length = inputStream.readInt();
int id = inputStream.readInt();
if (id == 0) {
// status request
try {
int version = inputStream.readInt();
String address = inputStream.readUTF();
int port = inputStream.readUnsignedShort();
int state = inputStream.readInt();
System.out.println("Received request: " + length + ", " + id + ", " + version + ", " + address + ", " + port + ", " + state);
} catch (Exception ignored) {
// status request packet is sent inconsistently, so we ignore it
}
inputStream.close();
// status response
String response = gson.toJson(FakeMinecraftServer.response).replace(ChatConverter.ESCAPE + "", "\\u00A7"); // Mojew's parser needs this escaped (classic)
if (FakeMinecraftServer.response.favicon == null)
System.out.println("Sending response: " + response);
else
System.out.println("Sent response with image data.");
MojewOutputStream outputStream = new MojewOutputStream(Unpooled.buffer());
MojewOutputStream dataOutputStream = new MojewOutputStream(Unpooled.buffer());
dataOutputStream.writeInt(0);
dataOutputStream.writeUTF(response);
dataOutputStream.close();
outputStream.writeInt(dataOutputStream.writtenBytes());
outputStream.write(dataOutputStream.getData());
outputStream.close();
ctx.writeAndFlush(outputStream.buffer());
} else if (id == 1) {
// ping request
long time = inputStream.readLong();
System.out.println("Received ping packet: " + length + ", " + id + ", " + time);
// ping response
MojewOutputStream outputStream = new MojewOutputStream(Unpooled.buffer());
MojewOutputStream dataOutputStream = new MojewOutputStream(Unpooled.buffer());
dataOutputStream.writeInt(1);
dataOutputStream.writeLong(time);
dataOutputStream.close();
outputStream.writeInt(dataOutputStream.writtenBytes());
outputStream.write(dataOutputStream.getData());
outputStream.close();
ctx.writeAndFlush(outputStream.buffer());
} else if (id == 2) {
// TODO: Fixing kick message
// login attempt
System.out.println("Received login packet: " + length + ", " + id);
// login response
MojewOutputStream outputStream = new MojewOutputStream(Unpooled.buffer());
MojewOutputStream dataOutputStream = new MojewOutputStream(Unpooled.buffer());
dataOutputStream.writeInt(2);
dataOutputStream.writeUTF("{text:\""+ ChatConverter.replaceColors(FakeMinecraftServer.KICK_MESSAGE).replace("\\n", "\n") + "\", color: white}");
dataOutputStream.close();
outputStream.writeInt(dataOutputStream.writtenBytes());
outputStream.write(dataOutputStream.getData());
outputStream.close();
ctx.writeAndFlush(outputStream.buffer());
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
ctx.close();
}
}

File diff suppressed because one or more lines are too long

View File

@@ -1,41 +0,0 @@
package me.unlegitdqrk.fakeminecraftserver;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
/**
* @author UnlegitDqrk
*/
public class SLPServer {
private int port;
public SLPServer(int port) {
this.port = port;
}
public void run() throws Exception {
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<Channel>() {
@Override
public void initChannel(Channel channel) {
channel.pipeline().addLast(new BasePacketHandler());
}
}).option(ChannelOption.SO_BACKLOG, 128)
.childOption(ChannelOption.SO_KEEPALIVE, true);
ChannelFuture channelFuture = serverBootstrap.bind(port).sync();
channelFuture.channel().closeFuture().sync();
} finally {
workerGroup.shutdownGracefully();
bossGroup.shutdownGracefully();
}
}
}

View File

@@ -0,0 +1,25 @@
package me.unlegitdqrk.fakeminecraftserver;
import java.util.Arrays;
import java.util.List;
public class Settings {
public static final int START_PORT = 25565;
public static final String ENGINE = "classic";
public static final int SOCKET_TIMEOUT_IN_SECONDS = 3;
public static final int MAX_PLAYERS = 100;
public static final int ONLINE_PLAYERS = 10;
public static final int PROTOCOL_VERSION = 47;
public static final String PROTOCOL_TEXT = "1.8.8";
public static final String MOTD_LINE1 = "&4Ein fake Minecraftserver";
public static final String MOTD_LINE2 = "&cDeveloped by UnlegitDqrk";
public static final String KICK_MESSAGE = "&4Just a Fakeserver!\n&aDeveloped by UnlegitDqrk";
public static final List<String> SAMPLES = Arrays.asList("&4Fakeserver", "&5by", "&aUnlegitDqrk");
}

View File

@@ -1,10 +1,12 @@
package me.unlegitdqrk.fakeminecraftserver.data; package me.unlegitdqrk.fakeminecraftserver.data;
import me.unlegitdqrk.fakeminecraftserver.ChatConverter; import me.unlegitdqrk.fakeminecraftserver.ChatConverter;
import me.unlegitdqrk.fakeminecraftserver.FakeMinecraftServer;
import me.unlegitdqrk.fakeminecraftserver.Message; import me.unlegitdqrk.fakeminecraftserver.Message;
import me.unlegitdqrk.fakeminecraftserver.Settings;
import java.util.*; import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
/** /**
* @author UnlegitDqrk * @author UnlegitDqrk
@@ -44,7 +46,7 @@ public class StatusResponse {
this.online = online; this.online = online;
this.sample = new ArrayList<>(); this.sample = new ArrayList<>();
for (String sample : FakeMinecraftServer.SAMPLES) { for (String sample : Settings.SAMPLES) {
this.sample.add(new Sample(ChatConverter.replaceColors(sample))); this.sample.add(new Sample(ChatConverter.replaceColors(sample)));
} }
} }

View File

@@ -0,0 +1,113 @@
package me.unlegitdqrk.fakeminecraftserver.network;
/*
* This file is part of Flow Networking, licensed under the MIT License (MIT).
*
* Copyright (c) 2013 Spout LLC <http://www.spout.org/>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
/**
* A class containing various utility methods that act on byte buffers.
*/
public class ByteBufUtils {
/**
* Reads an UTF8 string from a byte buffer.
*
* @param buf The byte buffer to read from
* @return The read string
* @throws java.io.IOException If the reading fails
*/
public static String readUTF8(DataInput buf) throws IOException {
// Read the string's length
final int len = readVarInt(buf);
final byte[] bytes = new byte[len];
buf.readFully(bytes);
return new String(bytes, StandardCharsets.UTF_8);
}
/**
* Writes an UTF8 string to a byte buffer.
*
* @param buf The byte buffer to write too
* @param value The string to write
* @throws java.io.IOException If the writing fails
*/
public static void writeUTF8(DataOutput buf, String value) throws IOException {
final byte[] bytes = value.getBytes(StandardCharsets.UTF_8);
if (bytes.length >= Short.MAX_VALUE) {
throw new IOException("Attempt to write a string with a length greater than Short.MAX_VALUE to ByteBuf!");
}
// Write the string's length
writeVarInt(buf, bytes.length);
buf.write(bytes);
}
/**
* Reads an integer written into the byte buffer as one of various bit sizes.
*
* @param buf The byte buffer to read from
* @return The read integer
* @throws java.io.IOException If the reading fails
*/
public static int readVarInt(DataInput buf) throws IOException {
int out = 0;
int bytes = 0;
byte in;
while (true) {
in = buf.readByte();
out |= (in & 0x7F) << (bytes * 7);
if (bytes > 32) {
throw new IOException("Attempt to read int bigger than allowed for a varint!");
}
if ((in & 0x80) != 0x80) {
break;
}
}
return out;
}
/**
* Writes an integer into the byte buffer using the least possible amount of bits.
*
* @param buf The byte buffer to write too
* @param value The integer value to write
*/
public static void writeVarInt(DataOutput buf, int value) throws IOException {
int part;
while (true) {
part = value & 0x7F;
value >>>= 7;
if (value != 0) {
part |= 0x80;
}
buf.writeByte(part);
if (value == 0) {
break;
}
}
}
}

View File

@@ -0,0 +1,148 @@
package me.unlegitdqrk.fakeminecraftserver.network;
import com.google.gson.Gson;
import me.unlegitdqrk.fakeminecraftserver.ChatConverter;
import me.unlegitdqrk.fakeminecraftserver.FakeMinecraftServer;
import me.unlegitdqrk.fakeminecraftserver.Settings;
import java.io.*;
import java.net.Socket;
import java.net.SocketException;
import java.net.SocketTimeoutException;
/**
* @author UnlegitDqrk
*/
public class ResponderThread extends Thread {
private final Socket socket;
private final DataInputStream inputStream;
private final DataOutputStream outputStream;
private final String remoteHost;
private int clientProtocolVersion;
private Thread thread = null;
private boolean enabled = false;
public ResponderThread(Socket socket) throws IOException {
this.socket = socket;
this.inputStream = new DataInputStream(socket.getInputStream());
this.outputStream = new DataOutputStream(socket.getOutputStream());
this.remoteHost = socket.getRemoteSocketAddress().toString().substring(1);
socket.setSoTimeout(Settings.SOCKET_TIMEOUT_IN_SECONDS * 1000);
this.enabled = true;
}
@Override
public void run() {
this.thread = Thread.currentThread();
boolean showMotd = false;
try {
while (this.socket.isConnected() && this.enabled) {
final int length = ByteBufUtils.readVarInt(this.inputStream);
final int packetId = ByteBufUtils.readVarInt(this.inputStream);
System.out.println("length: " + length + " packet id: " + packetId);
if (length == 0) return;
// handshake
if (packetId == 0) {
if (!showMotd) {
final int version = ByteBufUtils.readVarInt(this.inputStream);
@SuppressWarnings("unused") final String ip = ByteBufUtils.readUTF8(this.inputStream);
@SuppressWarnings("unused") final int port = this.inputStream.readUnsignedShort();
final int state = ByteBufUtils.readVarInt(this.inputStream);
System.out.println("(State request) length:" + length + " id:" + packetId + " version:" + version + " state:" + state);
clientProtocolVersion = version;
// state 1=status 2=login
if (state == 1) {
// ping / status request
showMotd = true;
System.out.println("ping: " + this.remoteHost);
} else if (state == 2) {
// login attempt
writeData("{text:\"" + ChatConverter.replaceColors(Settings.KICK_MESSAGE) + "\", color: white}");
System.out.println("Kick: " + this.remoteHost + " - " + Settings.KICK_MESSAGE);
return;
}
} else {
// info packet
System.out.println("(Info request) length:" + length + " id:" + packetId);
final String motd = createInfo();
if (motd == null || motd.isEmpty()) {
System.out.println("Info is not initialized!");
return;
}
writeData(motd);
showMotd = false;
}
} else if (packetId == 1) {
long receivedLong = this.inputStream.readLong();
System.out.println("Pong: " + receivedLong);
ByteBufUtils.writeVarInt(this.outputStream, 9);
ByteBufUtils.writeVarInt(this.outputStream, 1);
this.outputStream.writeLong(receivedLong);
this.outputStream.flush();
} else {
System.out.println("Unknown packet: " + packetId);
return;
}
}
}
// Ignore this unnecessary error
catch (EOFException ignored) {
System.out.println("(end of socket)");
} catch (SocketTimeoutException ignored) {
System.out.println("(socket timeout)");
} catch (SocketException ignored) {
System.out.println("(socket closed)");
} catch (IOException exception) {
exception.printStackTrace();
} finally {
closeSocket();
this.thread = null;
}
}
public final int getClientProtocolVersion() {
return clientProtocolVersion;
}
private final void closeSocket() {
this.enabled = false;
FakeMinecraftServer.safeClose(this.inputStream);
FakeMinecraftServer.safeClose(this.outputStream);
FakeMinecraftServer.safeClose(this.socket);
if (this.thread != null) this.thread.interrupt();
}
private final void writeData(final String data) throws IOException {
final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
final DataOutputStream dataOutputStream = new DataOutputStream(byteArrayOutputStream);
ByteBufUtils.writeVarInt(dataOutputStream, 0);
ByteBufUtils.writeUTF8(dataOutputStream, data);
ByteBufUtils.writeVarInt(this.outputStream, byteArrayOutputStream.size());
this.outputStream.write(byteArrayOutputStream.toByteArray());
this.outputStream.flush();
}
private final String createInfo() {
return new Gson().toJson(FakeMinecraftServer.getResponse());
}
}

View File

@@ -1,37 +0,0 @@
package me.unlegitdqrk.fakeminecraftserver.streams;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufInputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
/**
* @author UnlegitDqrk
*/
public class MojewInputStream extends ByteBufInputStream {
public MojewInputStream(ByteBuf buffer) {
super(buffer);
}
@Override
public String readUTF() throws IOException {
byte[] input = new byte[readInt()];
readFully(input);
return new String(input, StandardCharsets.UTF_8);
}
@Override
public int readInt() throws IOException {
int i = 0;
int j = 0;
while (true) {
int k = readByte();
i |= (k & 0x7F) << j++ * 7;
if (j > 5) throw new RuntimeException("VarInt too big");
if ((k & 0x80) != 128) break;
}
return i;
}
}

View File

@@ -1,41 +0,0 @@
package me.unlegitdqrk.fakeminecraftserver.streams;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
/**
* @author UnlegitDqrk
*/
public class MojewOutputStream extends ByteBufOutputStream {
public MojewOutputStream(ByteBuf buffer) {
super(buffer);
}
@Override
public void writeUTF(String s) throws IOException {
byte[] data = s.getBytes(StandardCharsets.UTF_8);
writeInt(s.length());
write(data);
}
@Override
public void writeInt(int paramInt) throws IOException {
while (true) {
if ((paramInt & 0xFFFFFF80) == 0) {
writeByte(paramInt);
return;
}
writeByte(paramInt & 0x7F | 0x80);
paramInt >>>= 7;
}
}
public byte[] getData() {
return Arrays.copyOfRange(buffer().array(), 0, writtenBytes());
}
}