diff --git a/dpnet/netserver.py b/dpnet/netserver.py index f3d1c59..9e4f505 100644 --- a/dpnet/netserver.py +++ b/dpnet/netserver.py @@ -16,20 +16,28 @@ from giants.player import Player, PlayerPhases import time from giants import APPLICATION_GUID from .DN_MSG_INTERNAL_SEND_CONNECT_INFO import DN_MSG_INTERNAl_SEND_CONNECT_INFO +import asyncio logger = setup_logger(__name__) -class Netserver: +class Netserver(asyncio.DatagramProtocol): def __init__(self, server): - self.socket = None + self.remotesocket = None self.statssocket = None self.server = server self.addrs = [] self.guid = uuid.uuid4().bytes self.incoming_packets = [] + super().__init__() + + def connection_made(self, transport): + logger.debug("Connection made") + self.remotesocket = transport def run(self): + logger.debug("Run") + return self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) self.socket.bind((self.server.listen_ip, self.server.listen_port)) logger.debug("Listening to %s:%s", self.server.listen_ip, self.server.listen_port) @@ -57,26 +65,25 @@ class Netserver: def send_packets(self): pass - def handle_packets(self): - while True: - data, addr = self.socket.recvfrom(1024) - logger.debug("%s:%s > %s", addr[0], addr[1], data.hex()) - self.handle_new_packet(addr, data) + def datagram_received(self, data, addr): + logger.debug("%s:%s > %s", addr[0], addr[1], data.hex()) + loop = asyncio.get_event_loop() + loop.create_task(self.handle_new_packet(addr, data)) - def handle_new_packet(self, addr, bData): + async def handle_new_packet(self, addr, bData): pPacket = Packet(bData) first = pPacket.getByte() if len(bData) >= 4 and first & DFrame.PACKET_COMMAND_DATA: - self.handle_new_dframe(addr, pPacket) + await self.handle_new_dframe(addr, pPacket) elif len(bData) >= 12 and first & CFrame.PACKET_COMMAND_FRAME: - self.handle_new_cframe(addr, pPacket) + await self.handle_new_cframe(addr, pPacket) elif first == EnumQuery.LEAD or first == EnumResponse.LEAD: - self.handle_new_enum(addr, pPacket) + await self.handle_new_enum(addr, pPacket) else: logger.error("Unknown frame received") return - def handle_new_enum(self, addr, data): + async def handle_new_enum(self, addr, data): # EnumQuery or EnumResponse second = data.getByte() if second == EnumQuery.COMMAND: @@ -134,7 +141,7 @@ class Netserver: else: logger.error("Unknown DPLHP command: %s", second) - def handle_new_cframe(self, addr, data): + async def handle_new_cframe(self, addr, data): try: cframe = CFrame(data) session = self.get_session(addr) @@ -155,10 +162,11 @@ class Netserver: return else: logger.debug("New connection. Sending a CFRAME CONNECTED.") - session = Session(self.socket) + session = Session(self.remotesocket) session.SessID = cframe.SessID session.ip = addr[0] session.port = addr[1] + await session.lock.acquire() self.addrs.append(session) session.send_cframe_connected(cframe) player = Player("Unknown", session) @@ -207,6 +215,9 @@ class Netserver: session.send_cframe_sack() sack_sent = True + # release lock for new packet to be sent + session.lock.release() + # WIP: The bNSeq, bNRcv, optional selective acknowledgment (SACK), and optional send mask fields are then processed by using the standard rules in sections 3.1.5.2.1 through 3.1.5.2.4 # TODO: A successfully validated SACK packet SHOULD count as a valid receive and thus restart the KeepAlive timer @@ -222,7 +233,7 @@ class Netserver: traceback.print_exc() return - def handle_new_dframe(self, addr, data): + async def handle_new_dframe(self, addr, data): try: dframe = DFrame(data) logger.debug("Received DFRAME") @@ -258,7 +269,7 @@ class Netserver: session.next_expected_seq += 1 if dframe.Payload: - self.handle_game_packet(session, dframe.Payload) + await self.handle_game_packet(session, dframe.Payload) else: pass except Exception as e: @@ -266,7 +277,7 @@ class Netserver: traceback.print_exc() return - def handle_game_packet(self, session, payload): + async def handle_game_packet(self, session, payload): player = self.get_temp_player(session) if payload[0] == 0xc1: @@ -325,10 +336,10 @@ class Netserver: return player.phase = PlayerPhases.DN_ACK_CONNECT_INFO - self.server.add_player(player) + await self.server.add_player(player) #player.session.send_cframe_sack() - player.session.send_gamedata(b'\x3c'+struct.pack("