#π Trying to establish a connection through UDP Hole Punching: failing miserably.
97 messages Β· Page 1 of 1 (latest)
@fervent glen
Remember to:
- Ask your Python question, not if you can ask or if there's an expert who can help.
- Show a code sample as text (rather than a screenshot) and the error message, if you've got one.
- Explain what you expect to happen and what actually happens.
:warning: Do not pip install anything that isn't related to your question, especially if asked to over DMs.
Also to understand the context of what I'm doing better if you want you can check out https://github.com/StraReal/Cryptic
If you can send and receive data over UDP, what exactly isn't working, that's supposed to work?
For some reason the ports that get exchanged aren't the ones that get listened to later
# creates local UDP socket
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind(("0.0.0.0", 0)) # 0 = port chosen by the system
my_port = sock.getsockname()[1]
print(f"[UDP] Listening on {my_port}")
Maybe to fix it i could instead forcefully make it use a certain port
Instead of 0 which lets it choose
Also another solution could be changing this function so it sends its command from a certain port or atleast saves which port it sent it through
async def signaling_client(cmd, roomcode, url, username):
async with ClientSession() as session:
async with session.ws_connect(url) as ws:
await ws.send_str(f"{cmd} room{roomcode} {username}")
async for msg in ws:
if msg.type == WSMsgType.TEXT:
print("Received from server:", msg.data)
if msg.data.startswith("PEER"):
# here the server gave you the ip:port of the other peer
_, peer_name, peer_addr = msg.data.split(" ", 2)
udp_start(peer_addr.split(":"), username)
As i was recommended i opened an issue in the repo.
Great.
Were you able to replicate it yet?
Firstly, chat.py ignores the port given to it and tries to connect on port 80.
\Cryptic>python chat.py
Where do you want to connect?
(0) Saved server
(1) Change server
Enter number: 0
Current port is 5000. Change port? (y/n): n
What username do you want to connect with? (No spaces allowed)
oihugy
Do you want to create a room (0) or join one (1)?
0
Session code: ZB7NYU
Traceback (most recent call last):
File "\Cryptic\venv\Lib\site-packages\aiohttp\connector.py", line 1268, in _wrap_create_connection
sock = await aiohappyeyeballs.start_connection(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
...<6 lines>...
)
^
AppData\Roaming\uv\python\cpython-3.13.0-windows-x86_64-none\Lib\asyncio\windows_events.py", line 600, in finish_connect
ov.getresult()
~~~~~~~~~~~~^^
ConnectionRefusedError: [WinError 1225] The remote computer refused the network connection
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "\Cryptic\venv\Lib\site-packages\aiohttp\connector.py", line 1291, in _wrap_create_connection
raise client_error(req.connection_key, exc) from exc
aiohttp.client_exceptions.ClientConnectorError: Cannot connect to host localhost:80 ssl:default [The remote computer refused the network connection]
Similar when I give it http://localhost :\
python chat.py
Where do you want to connect?
(0) Saved server
(1) Change server
Enter number: 1
Enter URL of your Signaling Server: http://localhost
Enter port [5000]:
What username do you want to connect with? (No spaces allowed)
rtyuhjhgf
Do you want to create a room (0) or join one (1)?
0
Session code: XV4E51
Traceback (most recent call last):
File "\Cryptic\venv\Lib\site-packages\aiohttp\connector.py", line 1268, in _wrap_create_connection
sock = await aiohappyeyeballs.start_connection(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
\AppData\Roaming\uv\python\cpython-3.13.0-windows-x86_64-none\Lib\asyncio\windows_events.py", line 600, in finish_connect
ov.getresult()
~~~~~~~~~~~~^^
ConnectionRefusedError: [WinError 1225] The remote computer refused the network connection
The above exception was the direct cause of the following exception:
aiohttp.client_exceptions.ClientConnectorError: Cannot connect to host localhost:80 ssl:default [The remote computer refused the network connection]
But if I include the port in the URL in chat.py:
\Cryptic>python chat.py
Enter URL of your Signaling Server: http://localhost:5000
Enter port [5000]: 5000
What username do you want to connect with? (No spaces allowed)
oiuhui
Do you want to create a room (0) or join one (1)?
0
Session code: L505Z1
Connected to signaling server as oiuhui
The server errors:
$ python signaling_server.py
======== Running on http://localhost:5000 ========
(Press CTRL+C to quit)
Error handling request from ::1
Traceback (most recent call last):
File "\Cryptic\venv\Lib\site-packages\aiohttp\web_protocol.py", line 510, in _handle_request
resp = await request_handler(request)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "\Cryptic\venv\Lib\site-packages\aiohttp\web_app.py", line 569, in _handle
return await handler(request)
^^^^^^^^^^^^^^^^^^^^^^
File "\Cryptic\signaling_server.py", line 10, in websocket_handler
peer_ip, peer_port = request.transport.get_extra_info('peername')
^^^^^^^^^^^^^^^^^^
ValueError: too many values to unpack (expected 2)
Wait i coulda been testing using localhost
I deleted import stun from chat.py, and had to install aiohttp and rsa. You should add the latter two to the dependencies in a pyproject.toml (or even a simple requirements.txt), and stun too if you're going to use it.
damn i bought a domain to do this
Yeah some imports are wrong
Since its all temporary
Also im reading through all the stuff you wrote gimme a sec
Alright i think i know what to do
Instead of asyncio.run(signaling_client('CREATE', session_code, SERVER_URL, name))
I should do asyncio.run(signaling_client('CREATE', session_code, f'{SERVER_URL}:{SERVER_PORT}, name))
To start
Then when i listen
Domains are worthwhile just to spend a few quid on for a year, to learn how to use the DNS system. If you don't need it next year, just don't pay to renew it. You can always reuse it for something else if the registry doesn't complain like Nominet did with me, and isn't satisfied by your ID
Instead of sock.bind(("0.0.0.0", 0)) I should do sock.bind(("0.0.0.0", SERVER_PORT))
Why did it complain?
And would the fixes i just proposed work?
Yeah, definitely include the port in that asyncio.run(
Alright ill try it now
They just wanted to make sure I wasn't sending spam from an admittedly dodgy looking .uk domain. I showed them my passport and we were all good. Nominet just like to reserve .uk for legitimate UK entities
Oh alr
I chose .download so i doubt ill have problems like this
It was the cheapest one listed
I just choose whatever's cheapest
Yeah me too
I can't imagine the registry for the .download TLD will complain much.
For some reason now im having trouble
The server isnt receiving my commands
Maybe because its running on my machine and i cant use the same port?
Like if the server is running on port 5000 i cant use port 5000 for the users too?
No that doesnt seem to be the problem since changing port doesnt fix the problem
@drowsy sinew Do you know what the issue could be?
I'd recommend different ports for different connections with any protocol. But it's essential for UDP.
Oh right, if you're actually running a server on the internet, have you opened up those ports with the cloud provider's settings, or software firewall?
Its on my pc and the domain is connected through a tunnel to it
So any traffic received goes to my pc
So the server too is on there
The reason im not actually contacting the server is because im specifying the port
Ah, right. What port does the tunnel end point you're running forward it to though?
I think 5000
======== Running on http://0.0.0.0:5000 ========
Is the port the user is requesting for their P2P connection getting confused with the port the signalling server is listening on?
I tried entering different ports in the chat.py but none work
Only if i let it do its own thing it works
Which might mean that i shouldnt ask the user for a port
Maybe i could just make it so that the server tells the client the port it contacted it from
So the tunnel entry point with cloudflare or whoever, I don't think listen on every port. I think they're mainly intended for 80 and 443 (http/https).
So the client listens on that
But it does work with 5000 i mean if someone opens the website i do receive it
And if i send the message without specifying the port i do receive it
OK, cool. Good to know
Alright so now the server is sending back await ws.send_str(f"ROOM_CREATED {room_code} {peer_addr}")
I think i got it
Now
during the UDP exchange
The host is sending and actually receiving
While the one who joined isnt receiving anything
Great work - well done! Networking is definitely tricky.
Like look at this:
Received from server: ROOM_CREATED roomI88R61 127.0.0.1:32770
32770
Received from server: PEER Term 127.0.0.1:32776
[UDP] Listening on 32770
[UDP] Sent to 127.0.0.1:32776: b'HELLO from Drago #0'
[UDP] Received from ('127.0.0.1', 32776): HELLO from Term #1
[UDP] Sent to 127.0.0.1:32776: b'HELLO from Drago #1'
[UDP] Received from ('127.0.0.1', 32776): HELLO from Term #2
[UDP] Sent to 127.0.0.1:32776: b'HELLO from Drago #2'
[UDP] Received from ('127.0.0.1', 32776): HELLO from Term #3
[UDP] Sent to 127.0.0.1:32776: b'HELLO from Drago #3'
[UDP] Received from ('127.0.0.1', 32776): HELLO from Term #4
[UDP] Sent to 127.0.0.1:32776: b'HELLO from Drago #4'
[UDP] Received from ('127.0.0.1', 32776): HELLO from Term #5
[UDP] Sent to 127.0.0.1:32776: b'HELLO from Drago #5'
[UDP] Received from ('127.0.0.1', 32776): HELLO from Term #6
[UDP] Sent to 127.0.0.1:32776: b'HELLO from Drago #6'
[UDP] Received from ('127.0.0.1', 32776): HELLO from Term #7
[UDP] Sent to 127.0.0.1:32776: b'HELLO from Drago #7'
[UDP] Received from ('127.0.0.1', 32776): HELLO from Term #8
[UDP] Sent to 127.0.0.1:32776: b'HELLO from Drago #8'
[UDP] Received from ('127.0.0.1', 32776): HELLO from Term #9
[UDP] Sent to 127.0.0.1:32776: b'HELLO from Drago #9'```
This is the host
Its sending and receiving
Received from server: JOIN_ROOM roomI88R61 127.0.0.1:32776
32776
Received from server: PEER Drago 127.0.0.1:32770
[UDP] Listening on 32776
[UDP] Sent to 127.0.0.1:32770: b'HELLO from Term #0'
Exception in thread Thread-1 (udp_listener):
Traceback (most recent call last):
File pathinmypc, line 1073, in _bootstrap_inner
self.run()
File pathinmypc, line 1010, in run
self._target(*self._args, **self._kwargs)
File "D:\chat\chat.py", line 51, in udp_listener
data, addr = sock.recvfrom(1024)
^^^^^^^^^^^^^^^^^^^
ConnectionResetError: [WinError 10054] Connessione in corso interrotta forzatamente dall'host remoto (ongoing connection forcefully interrupted by remote host)
[UDP] Sent to 127.0.0.1:32770: b'HELLO from Term #1'
[UDP] Sent to 127.0.0.1:32770: b'HELLO from Term #2'
[UDP] Sent to 127.0.0.1:32770: b'HELLO from Term #3'
[UDP] Sent to 127.0.0.1:32770: b'HELLO from Term #4'
[UDP] Sent to 127.0.0.1:32770: b'HELLO from Term #5'
[UDP] Sent to 127.0.0.1:32770: b'HELLO from Term #6'
[UDP] Sent to 127.0.0.1:32770: b'HELLO from Term #7'
[UDP] Sent to 127.0.0.1:32770: b'HELLO from Term #8'
[UDP] Sent to 127.0.0.1:32770: b'HELLO from Term #9'```
And this is the one trying to join the room
Theres still much to do i think
That seems to be working?
Oh right, maybe Windows doesn't like the low level networking processes?
For "Drago" it is but for "Term" its not
What does that mean?
just a general observation that things are seldom simple on Windows. When I launched the server app, I had to grant it access to Public and Private networks.
I had previously granted all kinds of access to python and pycharm
But still i didnt understand why the connection didnt work
Wait wait i think i know the problem
Term sent the first package. In UDP hole punching the first message gets rejected, but this happening actually stops the listening function, it makes it crash
So i could simply put error catching and it should work
Right?
Holy shit
I fixed it
It works
Awesome! Fantastic work.
This help channel has been closed. Feel free to create a new post in #1035199133436354600. To maximize your chances of getting a response, check out this guide on asking good questions.