Commit before potential bitstream rewrite
This commit is contained in:
parent
0cd474601a
commit
1b78fb98bc
|
@ -13,7 +13,7 @@
|
|||
"host": "0.0.0.0",
|
||||
"port": 7777,
|
||||
"hostname": "Python > C",
|
||||
"password": "",
|
||||
"password": "test",
|
||||
"rcon_password": "changeme",
|
||||
"max_players": 50,
|
||||
"mode": "debug",
|
||||
|
|
|
@ -9,5 +9,4 @@
|
|||
0x25 ID_INVALID_PASSWORD
|
||||
0x27 ID_PONG
|
||||
0x37 ID_ADVERTISE_SYSTEM
|
||||
|
||||
0x26 ID_MODIFIED_PACKET # default behavior (did not find the packet||could not handle because not found)
|
||||
0x26 ID_MODIFIED_PACKET
|
||||
|
|
|
@ -2,13 +2,13 @@ import socket
|
|||
import struct
|
||||
|
||||
from .base import BaseClient
|
||||
from ..raknet.bitstream import Bitstream
|
||||
|
||||
import logging
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
STATE_CONNECTING = 0
|
||||
STATE_AUTH = 1
|
||||
STATE_CONNECTED = 2
|
||||
STATE_CONNECTED = 1
|
||||
|
||||
class PlayerClient(BaseClient):
|
||||
def __init__(self, server: "__ServerInstance__", ip: str, port: int):
|
||||
|
@ -19,29 +19,43 @@ class PlayerClient(BaseClient):
|
|||
|
||||
self.state = STATE_CONNECTING
|
||||
|
||||
# TODO: Make this static
|
||||
self.handlers = {
|
||||
STATE_CONNECTING: self.on_connection_request,
|
||||
#0x00: self.on_state_dependent_handle
|
||||
"default": {
|
||||
"default": self.on_unimplemented_state
|
||||
},
|
||||
STATE_CONNECTING: {
|
||||
"default": self.on_unexpected,
|
||||
0x18: self.on_connection_request
|
||||
},
|
||||
STATE_CONNECTED: {
|
||||
"default": self.on_player_packet
|
||||
}
|
||||
}
|
||||
|
||||
async def on_packet(self, packet: bytes):
|
||||
logger.debug("on_packet(%s)" % packet)
|
||||
|
||||
try:
|
||||
packet = self.server.compressor.decompress(packet)
|
||||
await self.handlers.get(self.state, self.on_unimplemented)(packet)
|
||||
except Exception as err:
|
||||
logger.error(err)
|
||||
#try:
|
||||
packet = self.server.compressor.decompress(packet)
|
||||
|
||||
current_handlers = self.handlers.get(self.state, self.handlers["default"])
|
||||
await current_handlers.get(packet[0], current_handlers["default"])(packet)
|
||||
#except Exception as err:
|
||||
#logger.error(err)
|
||||
|
||||
async def on_unexpected(self, packet: bytes):
|
||||
logger.warning("Received unexpected packet: %s" % packet)
|
||||
|
||||
async def on_unimplemented_state(self, packet: bytes):
|
||||
logger.warning("Unimplemented state: %d" % self.state)
|
||||
|
||||
async def on_unimplemented(self, packet: bytes):
|
||||
pass
|
||||
logger.warning("Unimplemented handler for packet: %s" % packet)
|
||||
|
||||
async def on_connection_request(self, packet: bytes):
|
||||
logger.debug("on_connection_request(%s)" % packet)
|
||||
|
||||
if self.state != STATE_CONNECTING: # Client should not send this after it has passed
|
||||
return
|
||||
|
||||
challenge = (self.ip_uint ^ self.server.config.challenge_short) & 0xFFFF
|
||||
challenge_solution = challenge ^ 0x6969 # 0x6969 being client_version?
|
||||
|
||||
|
@ -57,16 +71,42 @@ class PlayerClient(BaseClient):
|
|||
self.state = STATE_CONNECTED
|
||||
await self.send(b"\x19\x00") # Challenge passed
|
||||
|
||||
async def parse_internal_packet(self, packet: bytes):
|
||||
pass
|
||||
async def on_player_packet(self, packet: bytes):
|
||||
bitstream = Bitstream(packet)
|
||||
|
||||
async def on_state_dependent_handle(self, packet: bytes):
|
||||
switch = {
|
||||
STATE_AUTH: self.on_connection_graph_request
|
||||
}
|
||||
await switch.get(self.state, self.on_unimplemented)(packet)
|
||||
has_acks = bitstream.read(0x01)
|
||||
if has_acks:
|
||||
logger.debug("Unfinished code hit; has_acks: True")
|
||||
return
|
||||
|
||||
async def on_connection_graph_request(self, packet: bytes):
|
||||
packet = packet[1:] # Skip first byte (0x00)
|
||||
handled = await self.handle_internal_packet(bitstream)
|
||||
|
||||
if not handled:
|
||||
logger.debug("Internal packet were not handled")
|
||||
|
||||
async def handle_internal_packet(self, bitstream: Bitstream) -> bool:
|
||||
if (len(bitstream.buffer) * 8) - bitstream.offset < 0x10:
|
||||
return False
|
||||
|
||||
message_number = bitstream.read(0x10)
|
||||
reliability = bitstream.read(0x04)
|
||||
isSplitPacket = bitstream.read(0x01)
|
||||
|
||||
if isSplitPacket:
|
||||
logger.warning("Skipping split packet")
|
||||
return
|
||||
|
||||
# Something I dont understand yet
|
||||
# TODO: ReadCompressed
|
||||
bitstream.offset += 1
|
||||
unknown = bitstream.read(0x01)
|
||||
bit_length = bitstream.read(0x08)
|
||||
##
|
||||
|
||||
logger.debug("bit_length: %d" % bit_length)
|
||||
logger.debug("bitstream: %s" % bitstream)
|
||||
|
||||
# TODO: ReadAlignedBytes
|
||||
data = bitstream.read(bit_length)
|
||||
|
||||
logger.debug("data: %s" % data)
|
|
@ -1,9 +1,14 @@
|
|||
import ctypes as c
|
||||
|
||||
from array import array
|
||||
|
||||
import logging
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class Bitstream:
|
||||
def __init__(self):
|
||||
def __init__(self, data: bytes = b""):
|
||||
self.offset = 0
|
||||
self.buffer = array("B")
|
||||
self.buffer = array("B", data)
|
||||
|
||||
# This is not finished.. would like to implement bit_length support
|
||||
def write(self, value: bool):
|
||||
|
@ -43,6 +48,8 @@ class Bitstream:
|
|||
bytes_to_read = byte_read_to - byte_read_from + 1
|
||||
|
||||
if byte_read_to >= len(self.buffer):
|
||||
logger.debug("byte_read_to: %d" % byte_read_to)
|
||||
logger.debug("len(self.buffer): %d" % len(self.buffer))
|
||||
raise Exception("Reading beyond the buffer")
|
||||
|
||||
value = 0
|
||||
|
@ -58,6 +65,29 @@ class Bitstream:
|
|||
self.offset += bit_length
|
||||
return value
|
||||
|
||||
def read_compressed(self, bit_length: int, unsigned: bool):
|
||||
pass
|
||||
|
||||
def read_aligned_bytes(self, byte_length: int) -> bytes:
|
||||
if byte_length <= 0:
|
||||
return b""
|
||||
|
||||
self.align_to_byte()
|
||||
|
||||
if self.offset + (byte_length * 8) > len(self.buffer):
|
||||
logger.debug("Reading beyond the buffer")
|
||||
return b""
|
||||
|
||||
byte_read_from = self.offset // 8
|
||||
byte_read_to = byte_read_from + byte_length
|
||||
self.offset += byte_length
|
||||
|
||||
return self.buffer[byte_read_from:byte_read_to + 1]
|
||||
|
||||
def align_to_byte(self):
|
||||
if self.offset % 8 != 0:
|
||||
self.offset += 8 - (self.offset % 8)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
b = bytearray(" " + " ".join(" ".join(format(c, "08b")) for c in self.buffer) + " ", "ascii")
|
||||
m = self.offset * 2 + (self.offset // 8) - (self.offset // (max(1, len(self.buffer)) * 8))
|
||||
|
|
|
@ -52,7 +52,7 @@ class Server:
|
|||
if addr not in self.clients:
|
||||
ip, port = addr
|
||||
self.clients[addr] = Client(self, ip, port)
|
||||
await (self.clients[addr].onpacket(data)) #await self.clients[addr].on_packet(data)
|
||||
await self.clients[addr].on_packet(data)
|
||||
|
||||
disconnected = [c for c in self.clients.values() if c.connected == False]
|
||||
for c in disconnected: # Remove dead connections
|
||||
|
|
|
@ -1 +1,2 @@
|
|||
from . import server
|
||||
from . import packet
|
Loading…
Reference in New Issue
Block a user