To use a highly technical term, this is actually a pretty nasty problem or even a couple of nasty problems. Depending on the configuration of the firewall, it usually allows you to respond to requests from another endpoint on the IP endpoint as the request arrives. So ... if your friend gets the UDP datagram using something like the recvfrom() system call, the address parameter will get the IP endpoint information for the response. Therefore, the other end should be able to respond using sendto() using the same addressing information. Sort of:
struct sockaddr_in hisaddr; memset(&hisaddr, 0, sizeof(hisaddr)); hisaddr.sin_addr.s_addr = htonl(target_ip); hisaddr.sin_port = htons(target_port); sendto(sd, msg_ptr, msg_sz, 0, (struct sockaddr*)&hisaddr, sizeof(hisaddr)); struct sockaddr_in peeraddr; socklen_t peer_sz = sizeof(peeraddr); recvfrom(sd, buf_ptr, buf_sz, 0, (struct sockaddr*)&peeraddr, &peer_sz); sendto(sd, msg_ptr, msg_sz, 0, (struct sockaddr*)&peeraddr, peer_sz);
peeraddr on the other hand, will be your external address, or rather, the IP address of your firewall and the port number that he decided to use. The port number that you specified in the code may be completely different than the port to which your friend should send. Ultimately, it doesn't matter which port you are going to use, since the firewall can send and receive on a completely different port - this is what Network Address Translation is all about. I would recommend reading RFC3235 for some tips on how to overcome this obstacle.
IMHO's best approach is as follows:
- Let the OS select the port by calling
bind() with a zero port number or skipping the binding altogether - When the client receives address information from the socket level (for example, the fifth and sixth arguments to
recvfrom() ) - The client sends a response to the endpoint obtained in the previous step.
- Change the firewall settings until the previous steps are completed
Of course, all the magic is at the last step. If you can disable NAT or make sure that the firewall will never switch ports, then smoothing the port number and bind ing will work. You can take a look at %WINDIR%\system32\drivers\etc\services (or /etc/services depending on the tilt of your OS) to find out which port numbers are reserved or even used.