1

stackoverflow users!

I have an app that has to deal with p2p, and that's how I get to UDP Hole punching. But I ran into troubles with implementation. Hope, you can give me some tips.

I've got server, which works perfect and introduces clients to eachother, but clients can't connect probably because of my small exp working with sockets. So, client algo is:

  1. Create udp socket (socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);)
  2. Send message to server via sendto function
  3. Use recvfrom locker function to get an answer from server

After those 3 steps I get peer endpoint. Next, I was trying to connect clients in two ways:

Way1:

  1. Use the same socket to send data to peer via sendto function, but passing another sockaddr
  2. Listen with recvfrom locker function (And at that point I'm getting WSAECONNRESET error)

Way2:

  1. Create new socket
  2. Bind it
  3. Use it to send data to peer
  4. Listen

In that way one client fails on binding and another fails on listening with errors WSAEADDRINUSE and WSAECONNRESET. I'm obviously doing something wrong and your help would be highly appreciated. Thanks in advance.

P.S. Wanna share a good article about UDP Hole Punching in order to help those, who is new to this technique: http://www.brynosaurus.com/pub/net/p2pnat/

JacksonRR
  • 227
  • 1
  • 3
  • 12
  • Try to look at this question: http://stackoverflow.com/questions/8819118/tcp-hole-punching Although it must be easier to do this with UDP – Giann Dec 12 '12 at 17:07

1 Answers1

2

If you read the documentation for recvfrom(), it says:

WSAECONNRESET

The virtual circuit was reset by the remote side executing a hard or abortive close. The application should close the socket; it is no longer usable. On a UDP-datagram socket this error indicates a previous send operation resulted in an ICMP Port Unreachable message.

Which means your call to sendto() is failing. That makes sense if one or both clients are behind a router. Based on your description (and lack of code), you are not actually performing any hole punching to open up the router(s) to allow client-to-client packets to pass through. You have only sent a message to your server, which allows for client-to-server and server-to-client packets to pass through. A few more packet exchanges between each client and the server are required to perform the hole punching on each end, as described in detail in the article you linked to. Are you actually doing what the article says to do?

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • What do you mean by "you are not actually performing any hole punching" ? For UDP hole punching, according to articles and wiki, I need 2 clients and server. Clients connects to server and servers shares their public/private endpoints between clients. In next step clients have to initiate connection directly, using those endpoints. First sent data packet will be refused by the peer2's NAT, but will "punch a hole" in peer1's NAT. After that peer2 can connect peer1. – JacksonRR Dec 13 '12 at 08:50
  • @JacksonRR: I missed the part where you were connecting the clients together. However, I think this is correct behavior. `WSAECONNRESET` from `recvfrom()` tells you that a previous `sendto()` on the same socket failed, which is what you want it to do. `sendto()` cannot report the failure. Once the hole has been punched, subsequent sends will succeed. You are supposed to send multiple packets to multiple addresses to punch the hole correctly. Are you stopping after just the first failure? If `recvfrom()` reports `sendto()` failed then it is not an error, just try the next punch step. – Remy Lebeau Dec 13 '12 at 09:42
  • Thanks for your reply. I tried to send more datagrams, ignoring first errors, but still no good result. recvfrom func locks app and ignoring all packets other peer send, even if this peer send outgoing packets to punch hole :/ – JacksonRR Dec 13 '12 at 17:02
  • `recvfrom()` blocks the app only if you are using blocking sockets. In which case, use `select()` to know when there is something to read before calling `recvfrom()` so that you can specify a timeout. Other than that, please update your question with the actual code you are using to punch the hole. – Remy Lebeau Dec 13 '12 at 22:44