GML UDP Hole punching

emicarra

Member
Hello, i'm trying to make a udp hole punching connection, but i can't get the players to receive messages without opening ports. Here's my code:

CREATE EVENT
Code:
txt = "None";
connected = false;
socket = network_create_socket_ext(network_socket_udp,global.myport);
if(socket >= 0){
txt = "Waiting";
}
alarm[0] = 1;
ALARM 0
Code:
if(!connected){
    alarm[0] = 15;   
}
var buff = buffer_create(1, buffer_grow, 1);
buffer_seek(buff,buffer_seek_start,0);
buffer_write(buff, buffer_u8, 1);
network_send_udp(socket, global.otherip, global.otherport, buff, buffer_tell(buff));
buffer_delete(buff);
NETWORKING ASYNC EVENT
Code:
if(async_load[?"type"] == network_type_data){
    var buff =  async_load[?"buffer"];
    var ip = async_load[?"ip"];
    var port = async_load[?"port"];
    
    var s = buffer_read(buff,buffer_u8);
    switch(s){
        case 1:
            txt = "Connected with"+string(ip)+":"+string(port);
            connected = true;
        break;
    }
}
global.myport, global.otherip and global.otherport are manually added at game start, since i'm not using a master server yet.
So, what i do is:

on Player 1:
global.myport = 8303;
global.otherport = 8304;
global.otherip = (external ip);

on Player 2:
global.myport = 8304;
global.otherport = 8303;
global.otherip = (external ip);

But it only works when either i write 'global.otherip' as my local ip, or when i open the ports on my router.
What am i doing wrong? Thanks
 

chamaeleon

Member
What am i doing wrong?
I have not implemented UDP hole punching myself, but I imagine you're not following the protocol flow for making that happen. Looking at the NAT Hole Punching wiki page, I think you need a server in-between that mediates ports on the firewall. I would suspect (but again, I don't have direct hands-on knowledge, someone can correct me if needed) that the port exposed to the outside world on your firewall for the connection is not necessarily the same as any of the ports you use in your code. Essentially, by hard-coding port numbers you are not adhering to step one in the protocol flow, where the Na and Nb NAT devices pick external port numbers, EPa and EPb, that are used in subsequent steps. Your port numbers only means something between your NAT device and your internal computer, not between the NAT device and the outside world unless you open up those ports to be forwarded explicitly.
 
Last edited:

emicarra

Member
I have not implemented UDP hole punching myself, but I imagine you're not following the protocol flow for making that happen. Looking at the NAT Hole Punching wiki page, I think you need a server in-between that mediates ports on the firewall. I would suspect (but again, I don't have direct hands-on knowledge, someone can correct me if needed) that the port exposed to the outside world on your firewall for the connection is not necessarily the same as any of the ports you use in your code. Essentially, by hard-coding port numbers you are not adhering to step one in the protocol flow, where the Na and Nb NAT devices pick external port numbers, EPa and EPb, that are used in subsequent steps. Your port numbers only means something between your NAT device and your internal computer, not between the NAT device and the outside world unless you open up those ports to be forwarded explicitly.
Thanks for your response, what you're saying is that i should create a master server, so that the players connect to that master server, then let the master server retreive both players ip and ports, and send them to both players so that they can connect to each other through their external ips and ports retreieved by the master server? (When you connect to a server, the clients get assigned a random port to communicate, i was manually chosing the ports so that i didnt have to make a master server to retrieve the port that is being used before i got this working because i didnt think it mattered if i manually selected the ports)
 

chamaeleon

Member
Thanks for your response, what you're saying is that i should create a master server, so that the players connect to that master server, then let the master server retreive both players ip and ports, and send them to both players so that they can connect to each other through their external ips and ports retreieved by the master server? (When you connect to a server, the clients get assigned a random port to communicate, i was manually chosing the ports so that i didnt have to make a master server to retrieve the port that is being used before i got this working because i didnt think it mattered if i manually selected the ports)
That is it in a nutshell, I think. The only hard coded ip and port should be for the server. The steps for hole punching then propagates the required information based on the connection made to the server from each client.
 

emicarra

Member
That is it in a nutshell, I think. The only hard coded ip and port should be for the server. The steps for hole punching then propagates the required information based on the connection made to the server from each client.
I'll try with a master server now, i can see how that COULD work, the difference with manually selecting the ports, is that when you connect to the master server, you get a random port to receive data from the master server, right? So that port at least is being used and COULD be used to receive data from the other player, i hope it works, i've been trying for so long
 

chamaeleon

Member
I'll try with a master server now, i can see how that COULD work, the difference with manually selecting the ports, is that when you connect to the master server, you get a random port to receive data from the master server, right? So that port at least is being used and COULD be used to receive data from the other player, i hope it works, i've been trying for so long
The key is that your local nat device (typically your router and firewall combo at home) picks a random (guess on my part) port in its end for its communication with the server. Because your nat device has now communicated with the server on that port, it will allow the server to call back through that port and your nat device sends it on to the client so you get the information needed to communicate the other client (step 3 on the wiki page).
 

emicarra

Member
Welp, didn't work. As you can see i made a master server, both clients connected to the master server, the master server sent them each other's ip and ports, then both clients send messages to each other through those ports using a different socket than the master server (i also tried with the same socket as master server just in case), but they still can't communicate... help please :(?

Sin título.png
 

emicarra

Member
Wait! i just tested with my phone's 4g (i think its called hotspot) and using the same socket that's used to connect to the master server, and it works, both players can send and receive messages to each other, i'm so happy it's working :D
But it only works when i use 4g on my phone, if i'm on my wifi the players dont receive the data they send to each other, is this normal? Can't hole punching work on the same wifi?
 

O.Stogden

Member
It's possible it doesn't work because the IP address of both players are the same, with you being in the same house, some older games used to have trouble with that I believe. Would also make sense with the fact that your phone works when on 4G, as it would have a different IP address to your router.

If you have a friend, you could send them a copy of your program and see if the two of you can connect to each other, that would confirm it.
 

emicarra

Member
It's possible it doesn't work because the IP address of both players are the same, with you being in the same house, some older games used to have trouble with that I believe. Would also make sense with the fact that your phone works when on 4G, as it would have a different IP address to your router.

If you have a friend, you could send them a copy of your program and see if the two of you can connect to each other, that would confirm it.
Thanks, that's exactly what i'm gonna do! And another thing for the record, i tested the ping by sending little balls when you click, when i click on the computer, the balls appears instantly on the phone, and when i tap on the phone, it takes some seconds to appear in the computer, sometimes they dont even appear, it has to be something with the 4g maybe, but i have no idea why it behaves like that
 

O.Stogden

Member
I'm not sure on the stability of 4G. Other things can interfere with it, such as text messages and calls, they'll interrupt the internet of your phone if you send or receive one. I would guess mobile gaming apps probably don't rely so much on real-time data so it's not always apparent.
 

chamaeleon

Member
Wait! i just tested with my phone's 4g (i think its called hotspot) and using the same socket that's used to connect to the master server, and it works, both players can send and receive messages to each other, i'm so happy it's working :D
But it only works when i use 4g on my phone, if i'm on my wifi the players dont receive the data they send to each other, is this normal? Can't hole punching work on the same wifi?
I don't have much more to add at this point, but I do want to congratulate you on making progress on a thorny part of game development even if you haven't solved all issues yet, and wish you great success with your game!
 

emicarra

Member
I don't have much more to add at this point, but I do want to congratulate you on making progress on a thorny part of game development even if you haven't solved all issues yet, and wish you great success with your game!
Thanks! And thanks for your help!
 

Simon Gust

Member
Should work with the ips being the same, you have to create another value that distincts each running programm. In the create Event you can create a variable my_id and set it to something random. Use this id to know which running game really got the message by including it in the hole punch the same way you do with the ip, just check my_id instead of ip. When you release the game or test it with friends, you can revert it back to ip-checking.
 

emicarra

Member
Should work with the ips being the same, you have to create another value that distincts each running programm. In the create Event you can create a variable my_id and set it to something random. Use this id to know which running game really got the message by including it in the hole punch the same way you do with the ip, just check my_id instead of ip. When you release the game or test it with friends, you can revert it back to ip-checking.
Thanks for your response, but i'm not understanding what you mean. I think the problem is not that the clients can't distinct each other because they have the same external ip, because they have different ports, the problem is that when they send data to each other (to the same ip but different ports to difference each other), they don't even receive the message. I've read that apparently most routers don't route data from the same external ip it was sent, only some of the newest routers allow this thing called "hair pinning".

So i'm coming up with a solution, that is to let the clients check if both external ips are the same, then do a local broadcast to get the other player's local ip and connect through LAN, but haven't finished yet
 
Top