Skip to content

RakNet times out when querying any hostname on Windows #51

@thegamecracks

Description

@thegamecracks

When trying to pass a domain name like mc.advancius.net on Windows to the RakNet protocol, the library does not receive any response and times out. This can be reproduced with the example main function in raknet.py:

if __name__ == "__main__":
import asyncio
async def main_async():
raknet = RakNet(host="mc.advancius.net", port=19132, timeout=5.0)
status = await raknet.get_status()
print(status)
asyncio.run(main_async())

When running this module, the following traceback is printed:

(opengsq-python) C:\Users\home\Documents\GitHub\opengsq-python>py -m opengsq.protocols.raknet
<frozen runpy>:128: RuntimeWarning: 'opengsq.protocols.raknet' found in sys.modules after import of package 'opengsq.protocols', but prior to execution of 'opengsq.protocols.raknet'; this may result in unpredictable behaviour
Traceback (most recent call last):
  File "C:\Users\home\AppData\Local\Python\pythoncore-3.14-64\Lib\asyncio\tasks.py", line 488, in wait_for
    return await fut
           ^^^^^^^^^
  File "C:\Users\home\AppData\Local\Python\pythoncore-3.14-64\Lib\asyncio\queues.py", line 186, in get
    await getter
asyncio.exceptions.CancelledError

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "<frozen runpy>", line 198, in _run_module_as_main
  File "<frozen runpy>", line 88, in _run_code
  File "C:\Users\home\Documents\GitHub\opengsq-python\opengsq\protocols\raknet.py", line 88, in <module>
    asyncio.run(main_async())
    ~~~~~~~~~~~^^^^^^^^^^^^^^
  File "C:\Users\home\AppData\Local\Python\pythoncore-3.14-64\Lib\asyncio\runners.py", line 204, in run
    return runner.run(main)
           ~~~~~~~~~~^^^^^^
  File "C:\Users\home\AppData\Local\Python\pythoncore-3.14-64\Lib\asyncio\runners.py", line 127, in run
    return self._loop.run_until_complete(task)
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "C:\Users\home\AppData\Local\Python\pythoncore-3.14-64\Lib\asyncio\base_events.py", line 719, in run_until_complete
    return future.result()
           ~~~~~~~~~~~~~^^
  File "C:\Users\home\Documents\GitHub\opengsq-python\opengsq\protocols\raknet.py", line 85, in main_async
    status = await raknet.get_status()
             ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\home\Documents\GitHub\opengsq-python\opengsq\protocols\raknet.py", line 36, in get_status
    response = await UdpClient.communicate(self, request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\home\Documents\GitHub\opengsq-python\opengsq\protocol_socket.py", line 165, in communicate
    return await protocol_instance.recv()
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\home\Documents\GitHub\opengsq-python\opengsq\protocol_socket.py", line 24, in recv
    return await asyncio.wait_for(self.__packets.get(), timeout=self.__timeout)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\home\AppData\Local\Python\pythoncore-3.14-64\Lib\asyncio\tasks.py", line 487, in wait_for
    async with timeouts.timeout(timeout):
               ~~~~~~~~~~~~~~~~^^^^^^^^^
  File "C:\Users\home\AppData\Local\Python\pythoncore-3.14-64\Lib\asyncio\timeouts.py", line 114, in __aexit__
    raise TimeoutError from exc_val
TimeoutError

But when I tested this on a Linux system, this issue was not present:

~$ uv run --with opengsq -m opengsq.protocols.raknet
Installed 11 packages in 8ms
<frozen runpy>:128: RuntimeWarning: 'opengsq.protocols.raknet' found in sys.modules after import of package 'opengsq.protocols', but prior to execution of 'opengsq.protocols.raknet'; this may result in unpredictable behaviour
Status(edition='MCPE', motd_line1='Advancius Network', protocol_version=844, version_name='1.21.111', num_players=161, max_players=500, server_unique_id='12947326039399818065', motd_line2='www.advancius.net', game_mode='Survival', game_mode_numeric=1, port_ipv4=19132, port_ipv6=19132)

And if the IP address of mc.advancius.net is explicitly given (currently 142.44.218.185), it works fine on Windows:

# main.py
import asyncio
from opengsq import RakNet

async def main_async():
    raknet = RakNet(host="142.44.218.185", port=19132, timeout=5.0)
    status = await raknet.get_status()
    print(status)

asyncio.run(main_async())
(opengsq-python) C:\Users\home\Documents\GitHub\opengsq-python>py main.py
Status(edition='MCPE', motd_line1='Advancius Network', protocol_version=844, version_name='1.21.111', num_players=158, max_players=500, server_unique_id='12947326039399818065', motd_line2='www.advancius.net', game_mode='Survival', game_mode_numeric=1, port_ipv4=19132, port_ipv6=19132)

From what I can tell after an hour of debugging, there's a quirk with the UdpClient.communicate() method which ignores the default Socket transport and always passes the local_addr= argument to loop.create_datagram_endpoint(), even when the static method is passed source_port=None and protocol._allow_broadcast is False:

class UdpClient(Socket):
@staticmethod
async def communicate(protocol: ProtocolBase, data: bytes, source_port: int = None):
with UdpClient() as udpClient:
if source_port:
udpClient.bind_port(source_port)
udpClient.settimeout(protocol._timeout)
loop = asyncio.get_running_loop()
transport, protocol_instance = await loop.create_datagram_endpoint(
lambda: Socket.Protocol(protocol._timeout), # Use public Protocol class
local_addr=('0.0.0.0', source_port if source_port else 0),
allow_broadcast=protocol._allow_broadcast
)
try:
transport.sendto(data, (protocol._host, protocol._port))
return await protocol_instance.recv()
finally:
transport.close()

If I change the source code to pass the remote_addr argument exclusively, then the hostname query works on Windows:

# opengsq/protocol_socket.py
transport, protocol_instance = await loop.create_datagram_endpoint(
    lambda: Socket.Protocol(protocol._timeout),  # Use public Protocol class
-   local_addr=('0.0.0.0', source_port if source_port else 0),
+   remote_addr=(protocol._host, protocol._port),
    allow_broadcast=protocol._allow_broadcast
)

try:
-   transport.sendto(data, (protocol._host, protocol._port))
+   transport.sendto(data)
    return await protocol_instance.recv()
finally:
    transport.close()
(opengsq-python) C:\Users\home\Documents\GitHub\opengsq-python>py -m opengsq.protocols.raknet
<frozen runpy>:128: RuntimeWarning: 'opengsq.protocols.raknet' found in sys.modules after import of package 'opengsq.protocols', but prior to execution of 'opengsq.protocols.raknet'; this may result in unpredictable behaviour
Status(edition='MCPE', motd_line1='Advancius Network', protocol_version=844, version_name='1.21.111', num_players=162, max_players=500, server_unique_id='12947326039399818065', motd_line2='www.advancius.net', game_mode='Survival', game_mode_numeric=1, port_ipv4=19132, port_ipv6=19132)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions