#πŸ”’ Trying to establish a connection through UDP Hole Punching: failing miserably.

97 messages Β· Page 1 of 1 (latest)

fervent glen
#

Im trying to build a P2P communication program that establishes a connection through UDP Hole punching. I already have a signaling server and I'm able to send and receive messages to and from it, so I can exchange IPs and ports, but I can't get it working,

open ventureBOT
#

@fervent glen

Python help channel opened

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.

fervent glen
drowsy sinew
#

If you can send and receive data over UDP, what exactly isn't working, that's supposed to work?

fervent glen
#

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)
fervent glen
#

As i was recommended i opened an issue in the repo.

drowsy sinew
#

Great.

fervent glen
#

Were you able to replicate it yet?

drowsy sinew
#

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)
fervent glen
#

Wait i coulda been testing using localhost

drowsy sinew
#

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.

fervent glen
#

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

drowsy sinew
#

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

fervent glen
#

Instead of sock.bind(("0.0.0.0", 0)) I should do sock.bind(("0.0.0.0", SERVER_PORT))

fervent glen
#

And would the fixes i just proposed work?

drowsy sinew
#

Yeah, definitely include the port in that asyncio.run(

fervent glen
#

Alright ill try it now

drowsy sinew
# fervent glen Why did it complain?

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

fervent glen
#

I chose .download so i doubt ill have problems like this

#

It was the cheapest one listed

drowsy sinew
#

I just choose whatever's cheapest

fervent glen
#

Yeah me too

drowsy sinew
#

I can't imagine the registry for the .download TLD will complain much.

fervent glen
#

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?

drowsy sinew
#

I'd recommend different ports for different connections with any protocol. But it's essential for UDP.

fervent glen
#

Well i still cant get an answer from the server

#

Which i used to get before

drowsy sinew
#

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?

fervent glen
#

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

drowsy sinew
#

Ah, right. What port does the tunnel end point you're running forward it to though?

fervent glen
drowsy sinew
#

Is the port the user is requesting for their P2P connection getting confused with the port the signalling server is listening on?

fervent glen
#

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

drowsy sinew
#

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).

fervent glen
#

So the client listens on that

fervent glen
#

And if i send the message without specifying the port i do receive it

drowsy sinew
#

OK, cool. Good to know

fervent glen
#

Alright so now the server is sending back await ws.send_str(f"ROOM_CREATED {room_code} {peer_addr}")

fervent glen
#

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

drowsy sinew
#

Great work - well done! Networking is definitely tricky.

fervent glen
#

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

drowsy sinew
#

That seems to be working?

#

Oh right, maybe Windows doesn't like the low level networking processes?

fervent glen
#

For "Drago" it is but for "Term" its not

drowsy sinew
#

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.

fervent glen
#

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

drowsy sinew
#

Awesome! Fantastic work.

open ventureBOT
#
Python help channel closed for inactivity

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.