Add redundancy to PacketServer
This commit is contained in:
parent
7bcb3a755a
commit
c6b8eec4ed
4 changed files with 147 additions and 55 deletions
|
@ -1,3 +1,3 @@
|
||||||
class Constants {
|
class Constants {
|
||||||
static const VERSION = "1.2.082924+0707";
|
static const VERSION = "1.2.082924+0756";
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
import 'dart:typed_data';
|
||||||
|
|
||||||
|
import 'package:libac_dart/utils/Hashing.dart';
|
||||||
|
|
||||||
import '../nbt/NbtIo.dart';
|
import '../nbt/NbtIo.dart';
|
||||||
import '../nbt/Stream.dart';
|
import '../nbt/Stream.dart';
|
||||||
|
@ -20,10 +23,28 @@ class PacketServer {
|
||||||
print(
|
print(
|
||||||
"New connection from ${sock.remoteAddress.address}:${sock.remotePort}");
|
"New connection from ${sock.remoteAddress.address}:${sock.remotePort}");
|
||||||
|
|
||||||
|
ByteLayer layer = ByteLayer();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
sock.listen((data) async {
|
sock.listen((data) {
|
||||||
|
layer.writeBytes(data);
|
||||||
|
}, onDone: () async {
|
||||||
|
layer.resetPosition();
|
||||||
try {
|
try {
|
||||||
CompoundTag tag = await NbtIo.readFromStream(data);
|
List<int> dataHash = layer.readBytes(256);
|
||||||
|
int sequenceID = layer.readLong();
|
||||||
|
print("Sequence ID in request: $sequenceID");
|
||||||
|
|
||||||
|
int numBytes = layer.readLong();
|
||||||
|
|
||||||
|
List<int> remainingBytes = layer.readBytes(numBytes);
|
||||||
|
|
||||||
|
String sha256OriginalHash = Hashing.bytes2Hash(dataHash);
|
||||||
|
String sha256Hash =
|
||||||
|
Hashing.bytes2Hash(Hashing.sha1Sum(remainingBytes));
|
||||||
|
if (sha256OriginalHash == sha256Hash) {
|
||||||
|
CompoundTag tag = await NbtIo.readFromStream(
|
||||||
|
Uint8List.fromList(remainingBytes));
|
||||||
StringBuilder builder = StringBuilder();
|
StringBuilder builder = StringBuilder();
|
||||||
Tag.writeStringifiedNamedTag(tag, builder, 0);
|
Tag.writeStringifiedNamedTag(tag, builder, 0);
|
||||||
|
|
||||||
|
@ -39,7 +60,26 @@ class PacketServer {
|
||||||
Tag.writeStringifiedNamedTag(reply.replyDataTag, builder, 0);
|
Tag.writeStringifiedNamedTag(reply.replyDataTag, builder, 0);
|
||||||
|
|
||||||
print("Response to client: \n${builder}");
|
print("Response to client: \n${builder}");
|
||||||
sock.add(await NbtIo.writeToStream(reply.replyDataTag));
|
Uint8List nbtData = await NbtIo.writeToStream(reply.replyDataTag);
|
||||||
|
|
||||||
|
layer.clear();
|
||||||
|
layer.writeLong(sequenceID);
|
||||||
|
layer.writeByte(0xFF); // Successful receipt
|
||||||
|
layer.writeBytes(Hashing.sha256Sum(nbtData));
|
||||||
|
layer.writeLong(nbtData.lengthInBytes);
|
||||||
|
layer.writeBytes(nbtData);
|
||||||
|
|
||||||
|
sock.add(layer.bytes);
|
||||||
|
} else {
|
||||||
|
// Return a failure packet
|
||||||
|
layer.clear();
|
||||||
|
layer.writeLong(sequenceID);
|
||||||
|
layer.writeByte(0x00);
|
||||||
|
|
||||||
|
sock.add(layer.bytes); // Failure code.
|
||||||
|
print(
|
||||||
|
"ERROR: The inbound hash did not match real hash: $sha256OriginalHash != $sha256Hash\n> REFUSING TO PROCESS PACKET. SENDING ERROR CODE TO CLIENT");
|
||||||
|
}
|
||||||
} catch (E, stack) {
|
} catch (E, stack) {
|
||||||
response.contents
|
response.contents
|
||||||
.put("error", StringTag.valueOf("Malformed request packet"));
|
.put("error", StringTag.valueOf("Malformed request packet"));
|
||||||
|
@ -50,11 +90,11 @@ class PacketServer {
|
||||||
await sock.flush();
|
await sock.flush();
|
||||||
sock.close();
|
sock.close();
|
||||||
}
|
}
|
||||||
}, onDone: () {
|
layer.clear();
|
||||||
sock.close();
|
|
||||||
}, onError: (E) {
|
}, onError: (E) {
|
||||||
print("ERROR: ${E}");
|
print("ERROR: ${E}");
|
||||||
sock.close();
|
sock.close();
|
||||||
|
layer.clear();
|
||||||
});
|
});
|
||||||
} catch (E) {
|
} catch (E) {
|
||||||
sock.close();
|
sock.close();
|
||||||
|
@ -68,6 +108,7 @@ class PacketClient {
|
||||||
bool connected = false;
|
bool connected = false;
|
||||||
String lastIP = "";
|
String lastIP = "";
|
||||||
int port = 25306;
|
int port = 25306;
|
||||||
|
int packetSequence = 0;
|
||||||
|
|
||||||
PacketClient();
|
PacketClient();
|
||||||
|
|
||||||
|
@ -93,45 +134,81 @@ class PacketClient {
|
||||||
C2SRequestPacket request = C2SRequestPacket();
|
C2SRequestPacket request = C2SRequestPacket();
|
||||||
request.payload = packet;
|
request.payload = packet;
|
||||||
request.cap = packet.getChannelID();
|
request.cap = packet.getChannelID();
|
||||||
|
bool success = false;
|
||||||
|
|
||||||
socket!.add(await NbtIo.writeToStream(request.encodeTag().asCompoundTag()));
|
ByteLayer layer = ByteLayer();
|
||||||
CompoundTag ct = CompoundTag();
|
|
||||||
Completer<void> onCompletion = Completer();
|
|
||||||
socket!.listen((data) async {
|
|
||||||
try {
|
|
||||||
CompoundTag result = await NbtIo.readFromStream(data);
|
|
||||||
|
|
||||||
StringBuilder builder = StringBuilder();
|
Uint8List nbtData =
|
||||||
Tag.writeStringifiedNamedTag(result, builder, 0);
|
await NbtIo.writeToStream(request.encodeTag().asCompoundTag());
|
||||||
|
List<int> nbtDataHash = Hashing.sha256Sum(nbtData);
|
||||||
|
|
||||||
print("Response from server: \n${builder}");
|
ByteLayer reply = ByteLayer();
|
||||||
ct.put("result", result);
|
CompoundTag NBTTag = CompoundTag();
|
||||||
} catch (E, S) {
|
|
||||||
print(S);
|
while (!success) {
|
||||||
} finally {
|
layer.clear();
|
||||||
onCompletion.complete();
|
layer.writeBytes(nbtDataHash);
|
||||||
|
layer.writeLong(packetSequence);
|
||||||
|
layer.writeLong(nbtData.lengthInBytes);
|
||||||
|
layer.writeBytes(nbtData);
|
||||||
|
|
||||||
|
Completer responseWait = Completer();
|
||||||
|
|
||||||
|
socket!.add(layer.bytes);
|
||||||
|
|
||||||
|
socket!.listen((data) {
|
||||||
|
reply.writeBytes(data);
|
||||||
|
}, onDone: () async {
|
||||||
|
// Validate response validity
|
||||||
|
reply.resetPosition();
|
||||||
|
int sequence = reply.readLong();
|
||||||
|
int successReceipt = reply.readByte();
|
||||||
|
List<int> serverHash = reply.readBytes(256);
|
||||||
|
String srvHashStr = Hashing.bytes2Hash(serverHash);
|
||||||
|
int numBytes = reply.readLong();
|
||||||
|
List<int> pktBytes = reply.readBytes(numBytes);
|
||||||
|
String pktHash = Hashing.bytes2Hash(Hashing.sha256Sum(pktBytes));
|
||||||
|
|
||||||
|
if (successReceipt == 0xFF &&
|
||||||
|
packetSequence == sequence &&
|
||||||
|
srvHashStr == pktHash) success = true;
|
||||||
|
|
||||||
|
if (success) {
|
||||||
|
NBTTag = await NbtIo.readFromStream(Uint8List.fromList(pktBytes));
|
||||||
}
|
}
|
||||||
}, onError: (E, stack) {
|
|
||||||
print("ERROR: ${E}\n${stack}");
|
responseWait.complete();
|
||||||
if (!onCompletion.isCompleted) onCompletion.complete();
|
}, onError: () {
|
||||||
}, onDone: () {
|
if (!responseWait.isCompleted) responseWait.complete();
|
||||||
print("Request completed");
|
|
||||||
});
|
});
|
||||||
|
|
||||||
await onCompletion.future;
|
await responseWait.future;
|
||||||
await close();
|
|
||||||
|
|
||||||
await startConnect(lastIP, port);
|
packetSequence++;
|
||||||
S2CResponse reply = S2CResponse();
|
if (!success) await Future.delayed(Duration(seconds: 5));
|
||||||
try {
|
|
||||||
reply.decodeTag(ct.get("result")!.asCompoundTag());
|
|
||||||
} catch (E, stack) {
|
|
||||||
reply.contents = CompoundTag(); // This is essentially a null response
|
|
||||||
reply.contents.put("error", StringTag.valueOf(E.toString()));
|
|
||||||
reply.contents.put("stacktrace", StringTag.valueOf(stack.toString()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return reply;
|
CompoundTag ct = CompoundTag();
|
||||||
|
StringBuilder builder = StringBuilder();
|
||||||
|
Tag.writeStringifiedNamedTag(NBTTag, builder, 0);
|
||||||
|
|
||||||
|
print("Response from server: \n${builder}");
|
||||||
|
ct.put("result", NBTTag);
|
||||||
|
|
||||||
|
await close();
|
||||||
|
|
||||||
|
if (shouldReconnect) await startConnect(lastIP, port);
|
||||||
|
|
||||||
|
S2CResponse replyPkt = S2CResponse();
|
||||||
|
try {
|
||||||
|
replyPkt.decodeTag(ct.get("result")!.asCompoundTag());
|
||||||
|
} catch (E, stack) {
|
||||||
|
replyPkt.contents = CompoundTag(); // This is essentially a null response
|
||||||
|
replyPkt.contents.put("error", StringTag.valueOf(E.toString()));
|
||||||
|
replyPkt.contents.put("stacktrace", StringTag.valueOf(stack.toString()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return replyPkt;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> close() async {
|
Future<void> close() async {
|
||||||
|
|
|
@ -5,17 +5,17 @@ import 'package:crypto/crypto.dart';
|
||||||
class Hashing {
|
class Hashing {
|
||||||
/// This will generate the md5 bytes and hash it using #bytes2Hash
|
/// This will generate the md5 bytes and hash it using #bytes2Hash
|
||||||
static String md5Hash(String input) {
|
static String md5Hash(String input) {
|
||||||
return bytes2Hash(md5Sum(input));
|
return bytes2Hash(md5SumStr(input));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This will generate the Sha1 bytes and hash it using #bytes2Hash
|
/// This will generate the Sha1 bytes and hash it using #bytes2Hash
|
||||||
static String sha1Hash(String input) {
|
static String sha1Hash(String input) {
|
||||||
return bytes2Hash(sha1Sum(input));
|
return bytes2Hash(sha1SumStr(input));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This will generate the Sha256 bytes and hash it using #bytes2Hash.
|
/// This will generate the Sha256 bytes and hash it using #bytes2Hash.
|
||||||
static String sha256Hash(String input) {
|
static String sha256Hash(String input) {
|
||||||
return bytes2Hash(sha256Sum(input));
|
return bytes2Hash(sha256SumStr(input));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This function takes a list of bytes and returns a hash string
|
/// This function takes a list of bytes and returns a hash string
|
||||||
|
@ -29,17 +29,32 @@ class Hashing {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This function returns the bytes instead of a hash string
|
/// This function returns the bytes instead of a hash string
|
||||||
static List<int> md5Sum(String input) {
|
static List<int> md5SumStr(String input) {
|
||||||
return md5.convert(utf8.encode(input)).bytes;
|
return md5.convert(utf8.encode(input)).bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This functions returns the bytes instead of a hash string
|
/// This functions returns the bytes instead of a hash string
|
||||||
static List<int> sha1Sum(String input) {
|
static List<int> sha1SumStr(String input) {
|
||||||
return sha1.convert(utf8.encode(input)).bytes;
|
return sha1.convert(utf8.encode(input)).bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This function returns the bytes instead of a hash string
|
/// This function returns the bytes instead of a hash string
|
||||||
static List<int> sha256Sum(String input) {
|
static List<int> sha256SumStr(String input) {
|
||||||
return sha256.convert(utf8.encode(input)).bytes;
|
return sha256.convert(utf8.encode(input)).bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// This function returns the bytes instead of a hash string
|
||||||
|
static List<int> md5Sum(List<int> input) {
|
||||||
|
return md5.convert(input).bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This functions returns the bytes instead of a hash string
|
||||||
|
static List<int> sha1Sum(List<int> input) {
|
||||||
|
return sha1.convert(input).bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This function returns the bytes instead of a hash string
|
||||||
|
static List<int> sha256Sum(List<int> input) {
|
||||||
|
return sha256.convert(input).bytes;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
name: libac_dart
|
name: libac_dart
|
||||||
description: "Aria's Creations code library"
|
description: "Aria's Creations code library"
|
||||||
version: 1.2.082924+0707
|
version: 1.2.082924+0756
|
||||||
homepage: "https://zontreck.com"
|
homepage: "https://zontreck.com"
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue