Allow skipping UPnP discovery by using cached IGD description URL

This is much faster than running a full discover,
but only works if the user's network hasn't changed.
This commit is contained in:
Yukita Mayako 2022-11-05 19:12:09 -04:00
parent 13f1d80960
commit bb303c1e0f
3 changed files with 43 additions and 0 deletions

View file

@ -66,6 +66,14 @@
Adds the given [UPNPDevice] to the list of discovered devices. Adds the given [UPNPDevice] to the list of discovered devices.
</description> </description>
</method> </method>
<method name="add_device_from_url">
<return type="int" enum="UPNP.UPNPResult" />
<param index="0" name="desc_url" type="String" />
<description>
Discovers a [UPNPDevice] directly from the provided device description URL [code]desc_url[/code], allowing the much slower call to [method discover] to be skipped.
Returns one of the [enum UPNPResult] code constants ([constant UPNP_RESULT_SUCCESS] on success).
</description>
</method>
<method name="add_port_mapping" qualifiers="const"> <method name="add_port_mapping" qualifiers="const">
<return type="int" /> <return type="int" />
<param index="0" name="port" type="int" /> <param index="0" name="port" type="int" />

View file

@ -90,6 +90,39 @@ int UPNP::discover(int timeout, int ttl, const String &device_filter) {
return UPNP_RESULT_SUCCESS; return UPNP_RESULT_SUCCESS;
} }
UPNP::UPNPResult UPNP::add_device_from_url(const String &desc_url) {
ERR_FAIL_COND_V_MSG(desc_url.is_empty(), UPNP_RESULT_INVALID_PARAM, "The description url must not be empty.");
Ref<UPNPDevice> dev;
struct UPNPUrls urls;
struct IGDdatas data;
char addr[16];
int i = UPNP_GetIGDFromUrl(desc_url.utf8().get_data(), &urls, &data, (char *)&addr, 16);
if (i != 1) {
FreeUPNPUrls(&urls);
return UPNP_RESULT_ACTION_FAILED;
}
if (urls.controlURL[0] == '\0') {
FreeUPNPUrls(&urls);
return UPNP_RESULT_INVALID_RESPONSE;
}
dev.instantiate();
dev->set_description_url(desc_url);
dev->set_service_type("urn:schemas-upnp-org:device:InternetGatewayDevice:1");
dev->set_igd_control_url(urls.controlURL);
dev->set_igd_service_type(data.first.servicetype);
dev->set_igd_our_addr(addr);
dev->set_igd_status(UPNPDevice::IGD_STATUS_OK);
FreeUPNPUrls(&urls);
devices.push_back(dev);
return UPNP_RESULT_SUCCESS;
}
void UPNP::add_device_to_list(UPNPDev *dev, UPNPDev *devlist) { void UPNP::add_device_to_list(UPNPDev *dev, UPNPDev *devlist) {
Ref<UPNPDevice> new_device; Ref<UPNPDevice> new_device;
new_device.instantiate(); new_device.instantiate();
@ -343,6 +376,7 @@ void UPNP::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_gateway"), &UPNP::get_gateway); ClassDB::bind_method(D_METHOD("get_gateway"), &UPNP::get_gateway);
ClassDB::bind_method(D_METHOD("discover", "timeout", "ttl", "device_filter"), &UPNP::discover, DEFVAL(2000), DEFVAL(2), DEFVAL("InternetGatewayDevice")); ClassDB::bind_method(D_METHOD("discover", "timeout", "ttl", "device_filter"), &UPNP::discover, DEFVAL(2000), DEFVAL(2), DEFVAL("InternetGatewayDevice"));
ClassDB::bind_method(D_METHOD("add_device_from_url", "desc_url"), &UPNP::add_device_from_url);
ClassDB::bind_method(D_METHOD("query_external_address"), &UPNP::query_external_address); ClassDB::bind_method(D_METHOD("query_external_address"), &UPNP::query_external_address);

View file

@ -100,6 +100,7 @@ public:
Ref<UPNPDevice> get_gateway() const; Ref<UPNPDevice> get_gateway() const;
int discover(int timeout = 2000, int ttl = 2, const String &device_filter = "InternetGatewayDevice"); int discover(int timeout = 2000, int ttl = 2, const String &device_filter = "InternetGatewayDevice");
UPNPResult add_device_from_url(const String &desc_url);
String query_external_address() const; String query_external_address() const;