godot: UPNP add_port_mapping() returns error 26 even though discover() returns 0 beforehand

Godot version

4.0 beta 9

System information

Windows 10, Ryzen 5 3600, RTX 2060. Godot 4 beta 9 Forward+

Issue description

When I use the code on the latest version of the Godot Docs the upnp.discover() function returns 0 saying that it was successfull. But upnp.add_port_mapping() returns 26 stating that I need to use upnp.discover() first. Even though I already have and it was successful.

Steps to reproduce

I simply ran this code from the Godot Latest Docs and tried to find what was going wrong by just printing it.

func _upnp_setup(port):
	var upnp = UPNP.new()
	var err = upnp.discover()
	
	print(err) #Prints 0 for me showing it was a success
	
	if err != OK:
		push_error(str(err))
		emit_signal("upnp_completed", err)
		print(err)
		return
	
	print(upnp.get_gateway()) #Prints 26 saying I need to run discover first
	
	if upnp.get_gateway() and upnp.get_gateway().is_valid_gateway():
		upnp.add_port_mapping(port, port, ProjectSettings.get_setting("application/config/name"), "UDP")
		upnp.add_port_mapping(port, port, ProjectSettings.get_setting("application/config/name"), "TCP")
		emit_signal("upnp_completed", OK)
		print(OK)
		upnp.delete_port_mapping(port)

Minimal reproduction project

N/A

About this issue

  • Original URL
  • State: open
  • Created 2 years ago
  • Comments: 22 (12 by maintainers)

Most upvoted comments

FWIW, I also have a TP-link router and have faced similar issues. I tracked it down to the fact that TP-link routers don’t correctly implement the GetStatusInfo action (bug report), despite the router-provided XML declaring that it is supported. When miniupnp tries to invoke that action, it receives an HTTP 500 response, and treats the device as disconnected.

Edit: So after parsing the XML, Godot calls UPNP_GetValidIGD, which eventually calls UPNPIGD_IsConnected. This invokes the GetStatusInfo action, which responds with HTTP 500 on TP-link devices.

miniupnpc provides the -i argument to work around issues like this. (Example) Perhaps Godot could implement something similar to accommodate some non-compliant devices.

In general, UPnP in 2023 is a lot less worthwhile than it was back in 2010-2012. The fact that it’s disabled by default in most routers now and the rise of mobile connections (and home CGNAT connections) make UPnP rarely usable, since there is simply no way to directly reach an user’s IP address in a lot of cases.

Something like https://github.com/godotengine/godot-proposals/issues/434 should be implemented to replace it entirely at some point.

I took a look on this one, I don’t think this is a regression, nor a bug necessarily for that matter.

upnp.discover() may return 0 (success) if it found any device even if their igd_status is invalid thus, upnp.get_gateway will return null and upnp.add_port_mapping will return 26 and display this message:

No gateway available. You may need to call [method discover] first, or discovery didn't detect any valid IGDs (InternetGatewayDevices).

suggesting one may need run upnp.discover()

There is no significant change between 3.5.1 and 4.x on the related source files and using the same code in 3.5.1 retuns 0 for upnp.discover() and returns [Object:null] for upnp.get_gateway() pretty much says the behaviour is the same there

@Citonaa I think this line in your steps to reproduce is not correct print(upnp.get_gateway()) #Prints 26 saying I need to run discover first this function should return either a device or null in either 4.x or 3.5.1


I guess the only question is if this situation should be made more clear and if discover should return success in the case of devices found that fail is_valid_gateway() check.

Thanks for that testing, I’ll investigate it (althought thats a bit hard without a TP device for testing) - at least its a direction to look into.

@akien-mga thanks for pointing that out, sorry I missed it. Is it possible then that we are running into the same statusinfo() exception that I was encountering in Python, and perhaps that is why we are not able to use the IGD correctly in Godot?

using a NAT server in godot would be great

@ywmaa Could you post your router model (and possibly firmware version)?

Note that just because the router is found when looking for UPnP devices, that doesn’t mean its a valid UPnP internet gateway device, or that it’s compatible with MiniUPnPc, which is what Godot uses under the hood.

Could you also verify adding ports via UPnP is enabled in the router settings?

I have one device that I can get using :

upnp.get_device(0)

if I execute add_port_mapping on it I get error code 16, which says : UPNP_RESULT_INVALID_GATEWAY = 16 Invalid gateway.

very strange, because if I get the device description using this command

print(upnp.get_device(0).description_url)

I get this line : http://192.168.1.1:37215/upnpdev.xml

which should mean that this is the router, because it has the IP 192.168.1.1

Tried again on latest Godot 4 and print(upnp.get_gateway()) does return null. Not sure what was happening before as I was getting 0 and then 26 printed one after the other when I made the issue and assumed that print(upnp.get_gateway()) was what printed it.