-
-
Notifications
You must be signed in to change notification settings - Fork 22.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add UPnP support (port forwarding, querying external IP) #18780
Conversation
0b12347
to
6dbf050
Compare
It fails building on Linux and macOS:
Shouldn't you use the Godot memory management methods ( |
6931f40
to
1676a54
Compare
@akien-mga Fixed the build, was missing an |
private: | ||
String discover_multicast_if; | ||
int discover_local_port; | ||
bool discover_ipv6; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
UPNP class is missing a contructor where variable are not properly initialized. This causes them to have random initial values causing apparently random failure.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed :)
81ff2f2
to
073b6c2
Compare
101866c
to
7fdac09
Compare
Added docs. Will see about adding support for PCP and NAT-PMP in a seperate PR (using the BSD-licensed https://github.com/libpcp/pcp). Then I'd like to add a "PortForwarder" Godot node on top of these that manages port forwards. You can of course also use the UPNP/UPNPDevice classes directly, if you want to do something custom. You just need to handle threading yourself or live with blocking, which may be fine if done at startup/shutdown or during loading. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great job 🥇 !
There are 2 small issues to fix (see comments).
And the question about javascript is open.
I've tested builds with my usual library schedule (X11-Linux/Server-Linux/Server-OpenBSD/Server-FreeBSD/OSX/iPhone/Android/Win/UWP/Javascript), and they all compile fine.
Also, port mapping seems to okay with my home router (had to enable IGDevice on it because it was factory disabled), as even though I can't see them in the usual router UI the port does get open.
Thank you for this PR! It is almost ready to merge :)
modules/upnp/config.py
Outdated
@@ -0,0 +1,14 @@ | |||
def can_build(platform): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should be:
def can_build(env, platform):
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe also disable it for javascript platform? It doesn't make much sense there, but would it break exports? I never fully understood that, but it is done for things like openSSL/mbedTLS
EDIT: No, now that I think of it is not safe, it works for openSSL/mbedTLS
because we provide an empty interface for that. I guess we can build it in javascript for now, maybe add an empty interface for it in the future
modules/upnp/upnpdevice.cpp
Outdated
int UPNPDevice::add_port_mapping(int port, int port_internal, String desc, String proto, int duration) const { | ||
ERR_FAIL_COND_V(!is_valid_gateway(), UPNP::UPNP_RESULT_INVALID_GATEWAY); | ||
ERR_FAIL_COND_V(port < 1 || port > 65535, UPNP::UPNP_RESULT_INVALID_PORT); | ||
ERR_FAIL_COND_V(port < 0 || port > 65535, UPNP::UPNP_RESULT_INVALID_PORT); // Needs to allow 0 because 0 signifies "use external port as internal port" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you are doing both port < 1
and port < 0
check. Did you want to check for port_internal
instead 😉 ?
Only thing missing was to link against system miniupnpc on linuxbsd if |
And also missing adding the license details to |
I have added a small code sample to show how to automate the process of port forwarding (and closing after you are done). Thanks to @mhilbrunner for explaining how to achieve t0his (see #18780)
I have added a small code sample to show how to automate the process of port forwarding (and closing after you are done). Thanks to @mhilbrunner for explaining how to achieve t0his (see #18780) (cherry picked from commit 2a63853)
I have added a small code sample to show how to automate the process of port forwarding (and closing after you are done). Thanks to @mhilbrunner for explaining how to achieve t0his (see godotengine#18780)
This PR adds support for Universal Plug and Play (UPnP) to Godot's multiplayer capabilities.
This allows:
This is based on the BSD-licensed miniupnpc. The only change to the upstream files was an additional header file that would usually be autogenerated with
cmake
. In our case, I added it manually.Changes
thirdparty/miniupnpc
modules/upnp
Simplest example
This autodetects the router and creates (or overwrites) the port mapping.
You can also customize the UPnP discovery params (by calling
upnp.discover()
yourself) and the way the gateway is chosen by using the methods onUPNP
to iterate theUPNPDevice
s. Once you found the device of your choosing, you can then calladd_port_mapping()
anddelete_port_mapping()
on that device, again providing the parameters of your choice. The methods onUPNP
are just shortcuts. 😄Of course, you can fine tune all relevant settings (like timeouts/ttl, internal and external ports, TCP vs UDP, lease time, description for the port forward etc.) from GDScript.
Glossary
IGD: Internet Gateway Device, the UPnP type for routers
NAT: Network address translation
UPnP: Universal Plug and Play, the protocol
Notes
Not all routers are UPnP compatible. Not all devices support wildcards in port mappings, or a non-infinite duration for the lease, or a description. Look at this list to get an idea of how varied UPnP support is. The default parameters as they are now should maximize compatibility.
Relevant to #13947.
Closes #2970.