c++linuxsocketsudphole-punching

C++ UDP Socket not working to send back from server to client after receiving first packets from client


Writing a UDP client-server app in C++ (done that lots of times before in many languages in the past 15 years), but somehow this one is not working correctly.

I cannot post actual code nor minimal reproducible app at the moment but I am willing to pay for live help if anyone is available to help solve this quickly with screensharing.

I think this is a particularity with C++ sockets and the way I am using them in this specific app which is quite complex.

Basically the issue is that the packets sent from the server to the client are not received by the client, only when said client is on a separate nat. When both in same local networking and using their local IP, everything works as expected.

Here is what I am doing :

  1. Client sendto(...) packets through UDP to the server using a specific server host and port 12345 (and keeps sending these non-stop)
  2. On another thread, client bind(...) on port 12345 and "0.0.0.0" and tries to poll() and recvfrom() in a loop (poll always returns 0 here when client is on a separate nat)
  3. Server bind() on port 12345 and "0.0.0.0" then poll() and recvfrom() in a loop
  4. Upon receiving the first UDP message from a client, it starts a thread for sending UDP messages back to the client on a new socket, using the sockaddr_in that it got from the recvfrom() to pass in the sendto() commands.

Result : Server perfectly receives ALL messages from all clients, and sends all messages back to all clients, but any client that is not on the same NAT will never receive any messages (poll() always returns 0).

As far as I understand it, when the client sends a UDP message to the server on a specific remote port (12345 in this case), it will punch a hole in its NAT so that it can receive messages back from the remote server on that port...

I tested five different client network configurations :

  1. Local network with the server, using local IP addresses (WORKS)
  2. Local network with the server while client is using a VPN thus going through a remote NAT (DOES NOT WORK)
  3. Local network with the server but client is using the WAN ip address to connect to the server (DOES NOT WORK)
  4. Client at an actual remote network from a friend's connection, behind a router (DOES NOT WORK)
  5. Client going through a wifi hotspot created using my phone (DOES NOT WORK)

For all tests above, the server was correctly receiving all communications from clients.

I also tried forcing the port to 12345 for the sendto() instead of using the sockaddr_in as set from recvfrom(), same issue.

Am I doing anything wrong ?

If you want to help but need to see actual code, I can do that live with screen sharing and I will pay for the help.

Thanks.

Also, if anyone can point me to a great site where I can pay for VERY QUICK help, please let me know, I don't even bother searching google because I really want actual advice from people who tried these services, not ads trying to rip me off...


Solution

  • Only the original receiver socket is allowed to reply to the client, because it's the client request that opens the port in the NAT. So either use the same socket in the server to receive and reply, or get the port that the second server socket was bound to and transfer it with an initial message through the original server port, so that A can send to it and punch the hole.

    It looks so strange to create two half duplex sockets when a socket is a full duplex communication object that I'd go with the first option.