Merge pull request #2 from yourfriendoss/TCP

TCP Packet Splitting (fixes #1)
This commit is contained in:
yourfriend 2022-07-10 17:32:49 +03:00 committed by GitHub
commit 11700fe211
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 86 additions and 41 deletions

View file

@ -8,6 +8,7 @@ export class Player {
private server: Server; private server: Server;
username: string; username: string;
ip: string;
id: number; id: number;
world = "main"; world = "main";
position: Position; position: Position;
@ -23,15 +24,15 @@ export class Player {
this.username = username; this.username = username;
this.position = position; this.position = position;
this.server = server; this.server = server;
this.ip = (this.socket.remoteAddr as Deno.NetAddr).hostname;
let id = Math.floor(Math.random() * 255);
let id = Math.floor(Math.random() * server.maxUsers);
// reassigns ID until finds available one // reassigns ID until finds available one
// if we reach 255 players this will loop forever
while (server.players.find((e) => e.id == id)) {
id = Math.floor(Math.random() * 255);
}
while (server.players.find((e) => e.id == id)) {
id = Math.floor(Math.random() * server.maxUsers);
}
this.id = id; this.id = id;
} }
@ -54,7 +55,7 @@ export class Player {
}); });
} }
async toWorld(world: World) { toWorld(world: World) {
this.server.broadcastPacket( this.server.broadcastPacket(
(e) => PacketDefinitions.despawn(this.id, e), (e) => PacketDefinitions.despawn(this.id, e),
this, this,
@ -75,6 +76,6 @@ export class Player {
this.message("You have been moved."); this.message("You have been moved.");
await world.save(); //await world.save(); TODO: this causes way too many issues
} }
} }

View file

@ -20,10 +20,16 @@ export class Server {
players: Player[] = []; players: Player[] = [];
plugins: Map<string, PluginUpdateTime> = new Map(); plugins: Map<string, PluginUpdateTime> = new Map();
lengthMap: Map<number, number> = new Map([[0, 131], [5, 9], [8, 10], [
13, lengthMap: Map<number, number> = new Map([
66, [0, 130],
]]); [5, 8],
[8, 9],
[13, 65],
]);
maxUsers = 69
worlds: World[] = [new World({ x: 64, y: 64, z: 64 }, "main")]; worlds: World[] = [new World({ x: 64, y: 64, z: 64 }, "main")];
async start(port: number) { async start(port: number) {
@ -60,9 +66,10 @@ export class Server {
await fetch( await fetch(
"https://www.classicube.net/heartbeat.jsp" + "https://www.classicube.net/heartbeat.jsp" +
`?port=${config.port}` + `?port=${config.port}` +
"&max=255" + `&max=${this.maxUsers}` +
"&name=Cla66ic" + "&name=Cla66ic" +
"&public=True" + "&public=True" +
"&software=Cla66ic" +
`&version=7&salt=${config.hash}` + `&version=7&salt=${config.hash}` +
`&users=${this.players.length}`, `&users=${this.players.length}`,
); );
@ -136,8 +143,13 @@ export class Server {
this.players = this.players.filter((e) => e != player); this.players = this.players.filter((e) => e != player);
try {
conn.close();
} catch {
// whatever
}
this.broadcast(`${player.username} has &cleft`); this.broadcast(`${player.username} has &cleft`);
this.worlds.find((e) => e.name == player.world)!.save();
this.broadcastPacket( this.broadcastPacket(
(e) => PacketDefinitions.despawn(player.id, e), (e) => PacketDefinitions.despawn(player.id, e),
@ -145,14 +157,25 @@ export class Server {
); );
} }
async handlePacket(packet: PacketReader, connection: Deno.Conn) { async handlePacket(
const packetType = packet.readByte(); buffer: Uint8Array,
packetType: number,
connection: Deno.Conn,
) {
const packet = new PacketReader(buffer);
if (packetType == 0x00) { if (packetType == 0x00) {
if (this.players.find((e) => e.socket == connection)) return; if (this.players.find((e) => e.socket == connection)) return;
packet.readByte(); packet.readByte();
const username = packet.readString(); const username = packet.readString();
const verification = packet.readString(); const verification = packet.readString();
if(this.players.length >= this.maxUsers) {
connection.close();
return;
}
const player = new Player( const player = new Player(
connection, connection,
username, username,
@ -281,33 +304,51 @@ export class Server {
player, player,
); );
} }
if (packet.buffer.length - 1 >= packet.pos) { // TODO: This logic is wrong! Sometimes, TCP packets are still dropped. Need to rewrite this properly.
this.handlePacket(packet, connection);
packet.pos += packet.totalPacketSize;
packet.totalPacketSize = 0;
}
} }
async startSocket(connection: Deno.Conn) { async startSocket(connection: Deno.Conn) {
const buffer = new Uint8Array(1024 * 1024 * 10);
while (true) { while (true) {
let count; const packetID = new Uint8Array(1);
let packetIDReadAttempt;
try { try {
count = await connection.read(buffer); packetIDReadAttempt = await connection.read(packetID);
} catch (e) { } catch {
count = 0; this.removeUser(connection); // TODO: add a reason to this
log.critical(e); break;
} }
if (!count) { if (packetIDReadAttempt) {
const packetLength = this.lengthMap.get(packetID[0]);
if (!packetLength) {
log.critical("Unknown Packet: " + packetID[0]);
this.removeUser(connection); // TODO: add a reason to this
break;
}
let rawPacket = new Uint8Array(packetLength);
let packetReadAttempt;
try {
packetReadAttempt = await connection.read(rawPacket);
} catch {
this.removeUser(connection); // TODO: add a reason to this
break;
}
let fullRead = packetReadAttempt!;
while (fullRead < packetLength) {
const halfPacket = new Uint8Array(packetLength - fullRead);
rawPacket = new Uint8Array([...rawPacket, ...halfPacket]);
fullRead += (await connection.read(halfPacket))!;
}
this.handlePacket(rawPacket, packetID[0], connection);
} else {
this.removeUser(connection); this.removeUser(connection);
break; break;
} else {
const packet = new PacketReader(buffer.subarray(0, count));
this.handlePacket(packet, connection);
} }
} }
} }

View file

@ -33,15 +33,18 @@ environment variables
### insipration taken from: ### insipration taken from:
1. mcgalaxy (obviuouuusly!!) 1. https://github.com/Patbox/Cobblestone-Classic (some protocol information and
2. https://github.com/Patbox/Cobblestone-Classic (some protocol information and
worldhandling) worldhandling)
3. cla55ic (world data too) 2. cla55ic (world data too)
### issues: ### issues:
1. tcp packet splitting fails sometimes
2. no cpe support! i want to get all of the above issues fixed before 1. Properly queue up map saves instead of just blantantly saving whenever possible
2. massive performance issues, running more than 100 something accounts makes the server instead insane amounts of cpu (most likely multithreading needed)
3. no cpe support! i want to get all of the above issues fixed before
implementing CPE support implementing CPE support
3. proper rank support (implemented as plugin) 4. no IP cooldown connections (no block cooldown either), no anticheat, no unique IP heartbeats
4. no discord bridge (implemented as plugin) 5. proper rank support (implemented as plugin)
6. no discord bridge (implemented as plugin)
7. no cla66ic/plugins repository