diff options
author | Thaddeus Crews <repiteo@outlook.com> | 2024-11-25 13:22:27 -0600 |
---|---|---|
committer | Thaddeus Crews <repiteo@outlook.com> | 2024-11-25 13:22:27 -0600 |
commit | 29e6ef4277e9d43cbffc8a1bd837e97db8bac0f5 (patch) | |
tree | 916e604e7c09aea1fbe3f1560bcdf458da1d65d5 /modules | |
parent | 20d4755c646add8e42470ae7c3471e6b29caa793 (diff) | |
parent | 0df602afed31954086a54b67e1e2c53672aef7d8 (diff) | |
download | redot-engine-29e6ef4277e9d43cbffc8a1bd837e97db8bac0f5.tar.gz |
Merge pull request #99597 from Faless/upnp/custom_instance
[UPNP] Allow disabling UPNP implementation on the Web
Diffstat (limited to 'modules')
-rw-r--r-- | modules/upnp/SCsub | 2 | ||||
-rw-r--r-- | modules/upnp/register_types.cpp | 14 | ||||
-rw-r--r-- | modules/upnp/upnp.cpp | 299 | ||||
-rw-r--r-- | modules/upnp/upnp.h | 61 | ||||
-rw-r--r-- | modules/upnp/upnp_device.cpp | 126 | ||||
-rw-r--r-- | modules/upnp/upnp_device.h | 57 | ||||
-rw-r--r-- | modules/upnp/upnp_device_miniupnp.cpp | 153 | ||||
-rw-r--r-- | modules/upnp/upnp_device_miniupnp.h | 83 | ||||
-rw-r--r-- | modules/upnp/upnp_miniupnp.cpp | 334 | ||||
-rw-r--r-- | modules/upnp/upnp_miniupnp.h | 93 |
10 files changed, 734 insertions, 488 deletions
diff --git a/modules/upnp/SCsub b/modules/upnp/SCsub index 6657d75cae..ba4a842cb6 100644 --- a/modules/upnp/SCsub +++ b/modules/upnp/SCsub @@ -10,7 +10,7 @@ env_upnp = env_modules.Clone() thirdparty_obj = [] -if env["builtin_miniupnpc"]: +if env["builtin_miniupnpc"] and env["platform"] != "web": thirdparty_dir = "#thirdparty/miniupnpc/" thirdparty_sources = [ "igd_desc_parse.c", diff --git a/modules/upnp/register_types.cpp b/modules/upnp/register_types.cpp index f6a34837a2..fdf39c0b33 100644 --- a/modules/upnp/register_types.cpp +++ b/modules/upnp/register_types.cpp @@ -33,6 +33,11 @@ #include "upnp.h" #include "upnp_device.h" +#ifndef WEB_ENABLED +#include "upnp_device_miniupnp.h" +#include "upnp_miniupnp.h" +#endif + #include "core/error/error_macros.h" void initialize_upnp_module(ModuleInitializationLevel p_level) { @@ -40,8 +45,13 @@ void initialize_upnp_module(ModuleInitializationLevel p_level) { return; } - GDREGISTER_CLASS(UPNP); - GDREGISTER_CLASS(UPNPDevice); + ClassDB::register_custom_instance_class<UPNP>(); + ClassDB::register_custom_instance_class<UPNPDevice>(); + +#ifndef WEB_ENABLED + UPNPMiniUPNP::make_default(); + UPNPDeviceMiniUPNP::make_default(); +#endif } void uninitialize_upnp_module(ModuleInitializationLevel p_level) { diff --git a/modules/upnp/upnp.cpp b/modules/upnp/upnp.cpp index 4305bf842a..5ec0b984fc 100644 --- a/modules/upnp/upnp.cpp +++ b/modules/upnp/upnp.cpp @@ -30,298 +30,7 @@ #include "upnp.h" -#include <miniwget.h> -#include <upnpcommands.h> - -#include <stdlib.h> - -bool UPNP::is_common_device(const String &dev) const { - return dev.is_empty() || - dev.contains("InternetGatewayDevice") || - dev.contains("WANIPConnection") || - dev.contains("WANPPPConnection") || - dev.contains("rootdevice"); -} - -int UPNP::discover(int timeout, int ttl, const String &device_filter) { - ERR_FAIL_COND_V_MSG(timeout < 0, UPNP_RESULT_INVALID_PARAM, "The response's wait time can't be negative."); - ERR_FAIL_COND_V_MSG(ttl < 0 || ttl > 255, UPNP_RESULT_INVALID_PARAM, "The time-to-live must be set between 0 and 255 (inclusive)."); - - devices.clear(); - - int error = 0; - struct UPNPDev *devlist; - - CharString cs = discover_multicast_if.utf8(); - const char *m_if = cs.length() ? cs.get_data() : nullptr; - if (is_common_device(device_filter)) { - devlist = upnpDiscover(timeout, m_if, nullptr, discover_local_port, discover_ipv6, ttl, &error); - } else { - devlist = upnpDiscoverAll(timeout, m_if, nullptr, discover_local_port, discover_ipv6, ttl, &error); - } - - if (error != UPNPDISCOVER_SUCCESS) { - switch (error) { - case UPNPDISCOVER_SOCKET_ERROR: - return UPNP_RESULT_SOCKET_ERROR; - case UPNPDISCOVER_MEMORY_ERROR: - return UPNP_RESULT_MEM_ALLOC_ERROR; - default: - return UPNP_RESULT_UNKNOWN_ERROR; - } - } - - if (!devlist) { - return UPNP_RESULT_NO_DEVICES; - } - - struct UPNPDev *dev = devlist; - - while (dev) { - if (device_filter.is_empty() || strstr(dev->st, device_filter.utf8().get_data())) { - add_device_to_list(dev, devlist); - } - - dev = dev->pNext; - } - - freeUPNPDevlist(devlist); - - return UPNP_RESULT_SUCCESS; -} - -void UPNP::add_device_to_list(UPNPDev *dev, UPNPDev *devlist) { - Ref<UPNPDevice> new_device; - new_device.instantiate(); - - new_device->set_description_url(dev->descURL); - new_device->set_service_type(dev->st); - - parse_igd(new_device, devlist); - - devices.push_back(new_device); -} - -char *UPNP::load_description(const String &url, int *size, int *status_code) const { - return (char *)miniwget(url.utf8().get_data(), size, 0, status_code); -} - -void UPNP::parse_igd(Ref<UPNPDevice> dev, UPNPDev *devlist) { - int size = 0; - int status_code = -1; - char *xml = load_description(dev->get_description_url(), &size, &status_code); - - if (status_code != 200) { - dev->set_igd_status(UPNPDevice::IGD_STATUS_HTTP_ERROR); - return; - } - - if (!xml || size < 1) { - dev->set_igd_status(UPNPDevice::IGD_STATUS_HTTP_EMPTY); - return; - } - - struct UPNPUrls urls = {}; - struct IGDdatas data; - - parserootdesc(xml, size, &data); - free(xml); - xml = nullptr; - - GetUPNPUrls(&urls, &data, dev->get_description_url().utf8().get_data(), 0); - - char addr[16]; -#if MINIUPNPC_API_VERSION >= 18 - int i = UPNP_GetValidIGD(devlist, &urls, &data, (char *)&addr, 16, nullptr, 0); -#else - int i = UPNP_GetValidIGD(devlist, &urls, &data, (char *)&addr, 16); -#endif - - if (i != 1) { - FreeUPNPUrls(&urls); - - switch (i) { - case 0: - dev->set_igd_status(UPNPDevice::IGD_STATUS_NO_IGD); - return; - case 2: - dev->set_igd_status(UPNPDevice::IGD_STATUS_DISCONNECTED); - return; - case 3: - dev->set_igd_status(UPNPDevice::IGD_STATUS_UNKNOWN_DEVICE); - return; - default: - dev->set_igd_status(UPNPDevice::IGD_STATUS_UNKNOWN_ERROR); - return; - } - } - - if (urls.controlURL[0] == '\0') { - FreeUPNPUrls(&urls); - dev->set_igd_status(UPNPDevice::IGD_STATUS_INVALID_CONTROL); - return; - } - - 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); -} - -int UPNP::upnp_result(int in) { - switch (in) { - case UPNPCOMMAND_SUCCESS: - return UPNP_RESULT_SUCCESS; - case UPNPCOMMAND_UNKNOWN_ERROR: - return UPNP_RESULT_UNKNOWN_ERROR; - case UPNPCOMMAND_INVALID_ARGS: - return UPNP_RESULT_INVALID_ARGS; - case UPNPCOMMAND_HTTP_ERROR: - return UPNP_RESULT_HTTP_ERROR; - case UPNPCOMMAND_INVALID_RESPONSE: - return UPNP_RESULT_INVALID_RESPONSE; - case UPNPCOMMAND_MEM_ALLOC_ERROR: - return UPNP_RESULT_MEM_ALLOC_ERROR; - - case 402: - return UPNP_RESULT_INVALID_ARGS; - case 403: - return UPNP_RESULT_NOT_AUTHORIZED; - case 501: - return UPNP_RESULT_ACTION_FAILED; - case 606: - return UPNP_RESULT_NOT_AUTHORIZED; - case 714: - return UPNP_RESULT_NO_SUCH_ENTRY_IN_ARRAY; - case 715: - return UPNP_RESULT_SRC_IP_WILDCARD_NOT_PERMITTED; - case 716: - return UPNP_RESULT_EXT_PORT_WILDCARD_NOT_PERMITTED; - case 718: - return UPNP_RESULT_CONFLICT_WITH_OTHER_MAPPING; - case 724: - return UPNP_RESULT_SAME_PORT_VALUES_REQUIRED; - case 725: - return UPNP_RESULT_ONLY_PERMANENT_LEASE_SUPPORTED; - case 726: - return UPNP_RESULT_REMOTE_HOST_MUST_BE_WILDCARD; - case 727: - return UPNP_RESULT_EXT_PORT_MUST_BE_WILDCARD; - case 728: - return UPNP_RESULT_NO_PORT_MAPS_AVAILABLE; - case 729: - return UPNP_RESULT_CONFLICT_WITH_OTHER_MECHANISM; - case 732: - return UPNP_RESULT_INT_PORT_WILDCARD_NOT_PERMITTED; - case 733: - return UPNP_RESULT_INCONSISTENT_PARAMETERS; - } - - return UPNP_RESULT_UNKNOWN_ERROR; -} - -int UPNP::get_device_count() const { - return devices.size(); -} - -Ref<UPNPDevice> UPNP::get_device(int index) const { - ERR_FAIL_INDEX_V(index, devices.size(), nullptr); - - return devices.get(index); -} - -void UPNP::add_device(Ref<UPNPDevice> device) { - ERR_FAIL_COND(device.is_null()); - - devices.push_back(device); -} - -void UPNP::set_device(int index, Ref<UPNPDevice> device) { - ERR_FAIL_INDEX(index, devices.size()); - ERR_FAIL_COND(device.is_null()); - - devices.set(index, device); -} - -void UPNP::remove_device(int index) { - ERR_FAIL_INDEX(index, devices.size()); - - devices.remove_at(index); -} - -void UPNP::clear_devices() { - devices.clear(); -} - -Ref<UPNPDevice> UPNP::get_gateway() const { - ERR_FAIL_COND_V_MSG(devices.is_empty(), nullptr, "Couldn't find any UPNPDevices."); - - for (int i = 0; i < devices.size(); i++) { - Ref<UPNPDevice> dev = get_device(i); - - if (dev.is_valid() && dev->is_valid_gateway()) { - return dev; - } - } - - return nullptr; -} - -void UPNP::set_discover_multicast_if(const String &m_if) { - discover_multicast_if = m_if; -} - -String UPNP::get_discover_multicast_if() const { - return discover_multicast_if; -} - -void UPNP::set_discover_local_port(int port) { - discover_local_port = port; -} - -int UPNP::get_discover_local_port() const { - return discover_local_port; -} - -void UPNP::set_discover_ipv6(bool ipv6) { - discover_ipv6 = ipv6; -} - -bool UPNP::is_discover_ipv6() const { - return discover_ipv6; -} - -String UPNP::query_external_address() const { - Ref<UPNPDevice> dev = get_gateway(); - - if (dev.is_null()) { - return ""; - } - - return dev->query_external_address(); -} - -int UPNP::add_port_mapping(int port, int port_internal, String desc, String proto, int duration) const { - Ref<UPNPDevice> dev = get_gateway(); - - if (dev.is_null()) { - return UPNP_RESULT_NO_GATEWAY; - } - - return dev->add_port_mapping(port, port_internal, desc, proto, duration); -} - -int UPNP::delete_port_mapping(int port, String proto) const { - Ref<UPNPDevice> dev = get_gateway(); - - if (dev.is_null()) { - return UPNP_RESULT_NO_GATEWAY; - } - - return dev->delete_port_mapping(port, proto); -} +UPNP *(*UPNP::_create)(bool p_notify_postinitialize) = nullptr; void UPNP::_bind_methods() { ClassDB::bind_method(D_METHOD("get_device_count"), &UPNP::get_device_count); @@ -382,9 +91,3 @@ void UPNP::_bind_methods() { BIND_ENUM_CONSTANT(UPNP_RESULT_NO_DEVICES); BIND_ENUM_CONSTANT(UPNP_RESULT_UNKNOWN_ERROR); } - -UPNP::UPNP() { -} - -UPNP::~UPNP() { -} diff --git a/modules/upnp/upnp.h b/modules/upnp/upnp.h index dc9bbdbc22..566b01ecdc 100644 --- a/modules/upnp/upnp.h +++ b/modules/upnp/upnp.h @@ -35,26 +35,14 @@ #include "core/object/ref_counted.h" -#include <miniupnpc.h> - class UPNP : public RefCounted { GDCLASS(UPNP, RefCounted); -private: - String discover_multicast_if = ""; - int discover_local_port = 0; - bool discover_ipv6 = false; - - Vector<Ref<UPNPDevice>> devices; - - bool is_common_device(const String &dev) const; - void add_device_to_list(UPNPDev *dev, UPNPDev *devlist); - void parse_igd(Ref<UPNPDevice> dev, UPNPDev *devlist); - char *load_description(const String &url, int *size, int *status_code) const; - protected: static void _bind_methods(); + static UPNP *(*_create)(bool p_notify_postinitialize); + public: enum UPNPResult { UPNP_RESULT_SUCCESS, @@ -88,35 +76,40 @@ public: UPNP_RESULT_UNKNOWN_ERROR, }; - static int upnp_result(int in); + static UPNP *create(bool p_notify_postinitialize = true) { + if (!_create) { + return nullptr; + } + return _create(p_notify_postinitialize); + } - int get_device_count() const; - Ref<UPNPDevice> get_device(int index) const; - void add_device(Ref<UPNPDevice> device); - void set_device(int index, Ref<UPNPDevice> device); - void remove_device(int index); - void clear_devices(); + virtual int get_device_count() const = 0; + virtual Ref<UPNPDevice> get_device(int index) const = 0; + virtual void add_device(Ref<UPNPDevice> device) = 0; + virtual void set_device(int index, Ref<UPNPDevice> device) = 0; + virtual void remove_device(int index) = 0; + virtual void clear_devices() = 0; - Ref<UPNPDevice> get_gateway() const; + virtual Ref<UPNPDevice> get_gateway() const = 0; - int discover(int timeout = 2000, int ttl = 2, const String &device_filter = "InternetGatewayDevice"); + virtual int discover(int timeout = 2000, int ttl = 2, const String &device_filter = "InternetGatewayDevice") = 0; - String query_external_address() const; + virtual String query_external_address() const = 0; - int add_port_mapping(int port, int port_internal = 0, String desc = "", String proto = "UDP", int duration = 0) const; - int delete_port_mapping(int port, String proto = "UDP") const; + virtual int add_port_mapping(int port, int port_internal = 0, String desc = "", String proto = "UDP", int duration = 0) const = 0; + virtual int delete_port_mapping(int port, String proto = "UDP") const = 0; - void set_discover_multicast_if(const String &m_if); - String get_discover_multicast_if() const; + virtual void set_discover_multicast_if(const String &m_if) = 0; + virtual String get_discover_multicast_if() const = 0; - void set_discover_local_port(int port); - int get_discover_local_port() const; + virtual void set_discover_local_port(int port) = 0; + virtual int get_discover_local_port() const = 0; - void set_discover_ipv6(bool ipv6); - bool is_discover_ipv6() const; + virtual void set_discover_ipv6(bool ipv6) = 0; + virtual bool is_discover_ipv6() const = 0; - UPNP(); - ~UPNP(); + UPNP() {} + virtual ~UPNP() {} }; VARIANT_ENUM_CAST(UPNP::UPNPResult) diff --git a/modules/upnp/upnp_device.cpp b/modules/upnp/upnp_device.cpp index 11ee3681af..45766281f1 100644 --- a/modules/upnp/upnp_device.cpp +++ b/modules/upnp/upnp_device.cpp @@ -30,119 +30,7 @@ #include "upnp_device.h" -#include "upnp.h" - -#include <upnpcommands.h> - -String UPNPDevice::query_external_address() const { - ERR_FAIL_COND_V_MSG(!is_valid_gateway(), "", "The Internet Gateway Device must be valid."); - - char addr[16]; - int i = UPNP_GetExternalIPAddress( - igd_control_url.utf8().get_data(), - igd_service_type.utf8().get_data(), - (char *)&addr); - - ERR_FAIL_COND_V_MSG(i != UPNPCOMMAND_SUCCESS, "", "Couldn't get external IP address."); - - return String(addr); -} - -int UPNPDevice::add_port_mapping(int port, int port_internal, String desc, String proto, int duration) const { - ERR_FAIL_COND_V_MSG(!is_valid_gateway(), UPNP::UPNP_RESULT_INVALID_GATEWAY, "The Internet Gateway Device must be valid."); - ERR_FAIL_COND_V_MSG(port < 1 || port > 65535, UPNP::UPNP_RESULT_INVALID_PORT, "The port number must be set between 1 and 65535 (inclusive)."); - ERR_FAIL_COND_V_MSG(port_internal < 0 || port_internal > 65535, UPNP::UPNP_RESULT_INVALID_PORT, "The port number must be set between 0 and 65535 (inclusive)."); // Needs to allow 0 because 0 signifies "use external port as internal port" - ERR_FAIL_COND_V_MSG(proto != "UDP" && proto != "TCP", UPNP::UPNP_RESULT_INVALID_PROTOCOL, "The protocol must be either TCP or UDP."); - ERR_FAIL_COND_V_MSG(duration < 0, UPNP::UPNP_RESULT_INVALID_DURATION, "The port mapping's lease duration can't be negative."); - - if (port_internal < 1) { - port_internal = port; - } - - int i = UPNP_AddPortMapping( - igd_control_url.utf8().get_data(), - igd_service_type.utf8().get_data(), - itos(port).utf8().get_data(), - itos(port_internal).utf8().get_data(), - igd_our_addr.utf8().get_data(), - desc.is_empty() ? nullptr : desc.utf8().get_data(), - proto.utf8().get_data(), - nullptr, // Remote host, always nullptr as IGDs don't support it - duration > 0 ? itos(duration).utf8().get_data() : nullptr); - - ERR_FAIL_COND_V_MSG(i != UPNPCOMMAND_SUCCESS, UPNP::upnp_result(i), "Couldn't add port mapping."); - - return UPNP::UPNP_RESULT_SUCCESS; -} - -int UPNPDevice::delete_port_mapping(int port, String proto) const { - ERR_FAIL_COND_V_MSG(port < 1 || port > 65535, UPNP::UPNP_RESULT_INVALID_PORT, "The port number must be set between 1 and 65535 (inclusive)."); - ERR_FAIL_COND_V_MSG(proto != "UDP" && proto != "TCP", UPNP::UPNP_RESULT_INVALID_PROTOCOL, "The protocol must be either TCP or UDP."); - - int i = UPNP_DeletePortMapping( - igd_control_url.utf8().get_data(), - igd_service_type.utf8().get_data(), - itos(port).utf8().get_data(), - proto.utf8().get_data(), - nullptr // Remote host, always nullptr as IGDs don't support it - ); - - ERR_FAIL_COND_V_MSG(i != UPNPCOMMAND_SUCCESS, UPNP::upnp_result(i), "Couldn't delete port mapping."); - - return UPNP::UPNP_RESULT_SUCCESS; -} - -void UPNPDevice::set_description_url(const String &url) { - description_url = url; -} - -String UPNPDevice::get_description_url() const { - return description_url; -} - -void UPNPDevice::set_service_type(const String &type) { - service_type = type; -} - -String UPNPDevice::get_service_type() const { - return service_type; -} - -void UPNPDevice::set_igd_control_url(const String &url) { - igd_control_url = url; -} - -String UPNPDevice::get_igd_control_url() const { - return igd_control_url; -} - -void UPNPDevice::set_igd_service_type(const String &type) { - igd_service_type = type; -} - -String UPNPDevice::get_igd_service_type() const { - return igd_service_type; -} - -void UPNPDevice::set_igd_our_addr(const String &addr) { - igd_our_addr = addr; -} - -String UPNPDevice::get_igd_our_addr() const { - return igd_our_addr; -} - -void UPNPDevice::set_igd_status(IGDStatus status) { - igd_status = status; -} - -UPNPDevice::IGDStatus UPNPDevice::get_igd_status() const { - return igd_status; -} - -bool UPNPDevice::is_valid_gateway() const { - return igd_status == IGD_STATUS_OK; -} +UPNPDevice *(*UPNPDevice::_create)(bool p_notify_postinitialize) = nullptr; void UPNPDevice::_bind_methods() { ClassDB::bind_method(D_METHOD("is_valid_gateway"), &UPNPDevice::is_valid_gateway); @@ -185,15 +73,3 @@ void UPNPDevice::_bind_methods() { BIND_ENUM_CONSTANT(IGD_STATUS_MALLOC_ERROR); BIND_ENUM_CONSTANT(IGD_STATUS_UNKNOWN_ERROR); } - -UPNPDevice::UPNPDevice() { - description_url = ""; - service_type = ""; - igd_control_url = ""; - igd_service_type = ""; - igd_our_addr = ""; - igd_status = IGD_STATUS_UNKNOWN_ERROR; -} - -UPNPDevice::~UPNPDevice() { -} diff --git a/modules/upnp/upnp_device.h b/modules/upnp/upnp_device.h index a49e574890..fdc5bab110 100644 --- a/modules/upnp/upnp_device.h +++ b/modules/upnp/upnp_device.h @@ -36,6 +36,11 @@ class UPNPDevice : public RefCounted { GDCLASS(UPNPDevice, RefCounted); +protected: + static void _bind_methods(); + + static UPNPDevice *(*_create)(bool p_notify_postinitialize); + public: enum IGDStatus { IGD_STATUS_OK, @@ -50,42 +55,38 @@ public: IGD_STATUS_UNKNOWN_ERROR, }; - void set_description_url(const String &url); - String get_description_url() const; + static UPNPDevice *create(bool p_notify_postinitialize = true) { + if (!_create) { + return nullptr; + } + return _create(p_notify_postinitialize); + } - void set_service_type(const String &type); - String get_service_type() const; + virtual void set_description_url(const String &url) = 0; + virtual String get_description_url() const = 0; - void set_igd_control_url(const String &url); - String get_igd_control_url() const; + virtual void set_service_type(const String &type) = 0; + virtual String get_service_type() const = 0; - void set_igd_service_type(const String &type); - String get_igd_service_type() const; + virtual void set_igd_control_url(const String &url) = 0; + virtual String get_igd_control_url() const = 0; - void set_igd_our_addr(const String &addr); - String get_igd_our_addr() const; + virtual void set_igd_service_type(const String &type) = 0; + virtual String get_igd_service_type() const = 0; - void set_igd_status(IGDStatus status); - IGDStatus get_igd_status() const; + virtual void set_igd_our_addr(const String &addr) = 0; + virtual String get_igd_our_addr() const = 0; - bool is_valid_gateway() const; - String query_external_address() const; - int add_port_mapping(int port, int port_internal = 0, String desc = "", String proto = "UDP", int duration = 0) const; - int delete_port_mapping(int port, String proto = "UDP") const; + virtual void set_igd_status(IGDStatus status) = 0; + virtual IGDStatus get_igd_status() const = 0; - UPNPDevice(); - ~UPNPDevice(); - -protected: - static void _bind_methods(); + virtual bool is_valid_gateway() const = 0; + virtual String query_external_address() const = 0; + virtual int add_port_mapping(int port, int port_internal = 0, String desc = "", String proto = "UDP", int duration = 0) const = 0; + virtual int delete_port_mapping(int port, String proto = "UDP") const = 0; -private: - String description_url; - String service_type; - String igd_control_url; - String igd_service_type; - String igd_our_addr; - IGDStatus igd_status; + UPNPDevice() {} + virtual ~UPNPDevice() {} }; VARIANT_ENUM_CAST(UPNPDevice::IGDStatus) diff --git a/modules/upnp/upnp_device_miniupnp.cpp b/modules/upnp/upnp_device_miniupnp.cpp new file mode 100644 index 0000000000..46319f83d3 --- /dev/null +++ b/modules/upnp/upnp_device_miniupnp.cpp @@ -0,0 +1,153 @@ +/**************************************************************************/ +/* upnp_device_miniupnp.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#ifndef WEB_ENABLED + +#include "upnp_device_miniupnp.h" + +#include "upnp_miniupnp.h" + +#include <upnpcommands.h> + +void UPNPDeviceMiniUPNP::make_default() { + UPNPDevice::_create = UPNPDeviceMiniUPNP::_create; +} + +String UPNPDeviceMiniUPNP::query_external_address() const { + ERR_FAIL_COND_V_MSG(!is_valid_gateway(), "", "The Internet Gateway Device must be valid."); + + char addr[16]; + int i = UPNP_GetExternalIPAddress( + igd_control_url.utf8().get_data(), + igd_service_type.utf8().get_data(), + (char *)&addr); + + ERR_FAIL_COND_V_MSG(i != UPNPCOMMAND_SUCCESS, "", "Couldn't get external IP address."); + + return String(addr); +} + +int UPNPDeviceMiniUPNP::add_port_mapping(int port, int port_internal, String desc, String proto, int duration) const { + ERR_FAIL_COND_V_MSG(!is_valid_gateway(), UPNP::UPNP_RESULT_INVALID_GATEWAY, "The Internet Gateway Device must be valid."); + ERR_FAIL_COND_V_MSG(port < 1 || port > 65535, UPNP::UPNP_RESULT_INVALID_PORT, "The port number must be set between 1 and 65535 (inclusive)."); + ERR_FAIL_COND_V_MSG(port_internal < 0 || port_internal > 65535, UPNP::UPNP_RESULT_INVALID_PORT, "The port number must be set between 0 and 65535 (inclusive)."); // Needs to allow 0 because 0 signifies "use external port as internal port" + ERR_FAIL_COND_V_MSG(proto != "UDP" && proto != "TCP", UPNP::UPNP_RESULT_INVALID_PROTOCOL, "The protocol must be either TCP or UDP."); + ERR_FAIL_COND_V_MSG(duration < 0, UPNP::UPNP_RESULT_INVALID_DURATION, "The port mapping's lease duration can't be negative."); + + if (port_internal < 1) { + port_internal = port; + } + + int i = UPNP_AddPortMapping( + igd_control_url.utf8().get_data(), + igd_service_type.utf8().get_data(), + itos(port).utf8().get_data(), + itos(port_internal).utf8().get_data(), + igd_our_addr.utf8().get_data(), + desc.is_empty() ? nullptr : desc.utf8().get_data(), + proto.utf8().get_data(), + nullptr, // Remote host, always nullptr as IGDs don't support it + duration > 0 ? itos(duration).utf8().get_data() : nullptr); + + ERR_FAIL_COND_V_MSG(i != UPNPCOMMAND_SUCCESS, UPNPMiniUPNP::upnp_result(i), "Couldn't add port mapping."); + + return UPNP::UPNP_RESULT_SUCCESS; +} + +int UPNPDeviceMiniUPNP::delete_port_mapping(int port, String proto) const { + ERR_FAIL_COND_V_MSG(port < 1 || port > 65535, UPNP::UPNP_RESULT_INVALID_PORT, "The port number must be set between 1 and 65535 (inclusive)."); + ERR_FAIL_COND_V_MSG(proto != "UDP" && proto != "TCP", UPNP::UPNP_RESULT_INVALID_PROTOCOL, "The protocol must be either TCP or UDP."); + + int i = UPNP_DeletePortMapping( + igd_control_url.utf8().get_data(), + igd_service_type.utf8().get_data(), + itos(port).utf8().get_data(), + proto.utf8().get_data(), + nullptr // Remote host, always nullptr as IGDs don't support it + ); + + ERR_FAIL_COND_V_MSG(i != UPNPCOMMAND_SUCCESS, UPNPMiniUPNP::upnp_result(i), "Couldn't delete port mapping."); + + return UPNP::UPNP_RESULT_SUCCESS; +} + +void UPNPDeviceMiniUPNP::set_description_url(const String &url) { + description_url = url; +} + +String UPNPDeviceMiniUPNP::get_description_url() const { + return description_url; +} + +void UPNPDeviceMiniUPNP::set_service_type(const String &type) { + service_type = type; +} + +String UPNPDeviceMiniUPNP::get_service_type() const { + return service_type; +} + +void UPNPDeviceMiniUPNP::set_igd_control_url(const String &url) { + igd_control_url = url; +} + +String UPNPDeviceMiniUPNP::get_igd_control_url() const { + return igd_control_url; +} + +void UPNPDeviceMiniUPNP::set_igd_service_type(const String &type) { + igd_service_type = type; +} + +String UPNPDeviceMiniUPNP::get_igd_service_type() const { + return igd_service_type; +} + +void UPNPDeviceMiniUPNP::set_igd_our_addr(const String &addr) { + igd_our_addr = addr; +} + +String UPNPDeviceMiniUPNP::get_igd_our_addr() const { + return igd_our_addr; +} + +void UPNPDeviceMiniUPNP::set_igd_status(IGDStatus status) { + igd_status = status; +} + +UPNPDeviceMiniUPNP::IGDStatus UPNPDeviceMiniUPNP::get_igd_status() const { + return igd_status; +} + +bool UPNPDeviceMiniUPNP::is_valid_gateway() const { + return igd_status == IGD_STATUS_OK; +} + +#endif // WEB_ENABLED diff --git a/modules/upnp/upnp_device_miniupnp.h b/modules/upnp/upnp_device_miniupnp.h new file mode 100644 index 0000000000..bea3b1d542 --- /dev/null +++ b/modules/upnp/upnp_device_miniupnp.h @@ -0,0 +1,83 @@ +/**************************************************************************/ +/* upnp_device_miniupnp.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#ifndef UPNP_DEVICE_MINIUPNP_H +#define UPNP_DEVICE_MINIUPNP_H + +#ifndef WEB_ENABLED + +#include "upnp_device.h" + +class UPNPDeviceMiniUPNP : public UPNPDevice { + GDCLASS(UPNPDeviceMiniUPNP, UPNPDevice); + +private: + static UPNPDevice *_create(bool p_notify_postinitialize) { return static_cast<UPNPDevice *>(ClassDB::creator<UPNPDeviceMiniUPNP>(p_notify_postinitialize)); } + + String description_url; + String service_type; + String igd_control_url; + String igd_service_type; + String igd_our_addr; + IGDStatus igd_status = IGD_STATUS_UNKNOWN_ERROR; + +public: + static void make_default(); + + virtual void set_description_url(const String &url) override; + virtual String get_description_url() const override; + + virtual void set_service_type(const String &type) override; + virtual String get_service_type() const override; + + virtual void set_igd_control_url(const String &url) override; + virtual String get_igd_control_url() const override; + + virtual void set_igd_service_type(const String &type) override; + virtual String get_igd_service_type() const override; + + virtual void set_igd_our_addr(const String &addr) override; + virtual String get_igd_our_addr() const override; + + virtual void set_igd_status(IGDStatus status) override; + virtual IGDStatus get_igd_status() const override; + + virtual bool is_valid_gateway() const override; + virtual String query_external_address() const override; + virtual int add_port_mapping(int port, int port_internal = 0, String desc = "", String proto = "UDP", int duration = 0) const override; + virtual int delete_port_mapping(int port, String proto = "UDP") const override; + + UPNPDeviceMiniUPNP() {} + virtual ~UPNPDeviceMiniUPNP() {} +}; + +#endif // WEB_ENABLED + +#endif // UPNP_DEVICE_MINIUPNP_H diff --git a/modules/upnp/upnp_miniupnp.cpp b/modules/upnp/upnp_miniupnp.cpp new file mode 100644 index 0000000000..0714d56a08 --- /dev/null +++ b/modules/upnp/upnp_miniupnp.cpp @@ -0,0 +1,334 @@ +/**************************************************************************/ +/* upnp_miniupnp.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#ifndef WEB_ENABLED + +#include "upnp_miniupnp.h" + +#include "upnp_device_miniupnp.h" + +#include <miniwget.h> +#include <upnpcommands.h> + +#include <stdlib.h> + +void UPNPMiniUPNP::make_default() { + UPNP::_create = UPNPMiniUPNP::_create; +} + +bool UPNPMiniUPNP::is_common_device(const String &dev) const { + return dev.is_empty() || + dev.contains("InternetGatewayDevice") || + dev.contains("WANIPConnection") || + dev.contains("WANPPPConnection") || + dev.contains("rootdevice"); +} + +int UPNPMiniUPNP::discover(int timeout, int ttl, const String &device_filter) { + ERR_FAIL_COND_V_MSG(timeout < 0, UPNP_RESULT_INVALID_PARAM, "The response's wait time can't be negative."); + ERR_FAIL_COND_V_MSG(ttl < 0 || ttl > 255, UPNP_RESULT_INVALID_PARAM, "The time-to-live must be set between 0 and 255 (inclusive)."); + + devices.clear(); + + int error = 0; + struct UPNPDev *devlist; + + CharString cs = discover_multicast_if.utf8(); + const char *m_if = cs.length() ? cs.get_data() : nullptr; + if (is_common_device(device_filter)) { + devlist = upnpDiscover(timeout, m_if, nullptr, discover_local_port, discover_ipv6, ttl, &error); + } else { + devlist = upnpDiscoverAll(timeout, m_if, nullptr, discover_local_port, discover_ipv6, ttl, &error); + } + + if (error != UPNPDISCOVER_SUCCESS) { + switch (error) { + case UPNPDISCOVER_SOCKET_ERROR: + return UPNP_RESULT_SOCKET_ERROR; + case UPNPDISCOVER_MEMORY_ERROR: + return UPNP_RESULT_MEM_ALLOC_ERROR; + default: + return UPNP_RESULT_UNKNOWN_ERROR; + } + } + + if (!devlist) { + return UPNP_RESULT_NO_DEVICES; + } + + struct UPNPDev *dev = devlist; + + while (dev) { + if (device_filter.is_empty() || strstr(dev->st, device_filter.utf8().get_data())) { + add_device_to_list(dev, devlist); + } + + dev = dev->pNext; + } + + freeUPNPDevlist(devlist); + + return UPNP_RESULT_SUCCESS; +} + +void UPNPMiniUPNP::add_device_to_list(UPNPDev *dev, UPNPDev *devlist) { + Ref<UPNPDeviceMiniUPNP> new_device; + new_device.instantiate(); + + new_device->set_description_url(dev->descURL); + new_device->set_service_type(dev->st); + + parse_igd(new_device, devlist); + + devices.push_back(new_device); +} + +char *UPNPMiniUPNP::load_description(const String &url, int *size, int *status_code) const { + return (char *)miniwget(url.utf8().get_data(), size, 0, status_code); +} + +void UPNPMiniUPNP::parse_igd(Ref<UPNPDevice> dev, UPNPDev *devlist) { + int size = 0; + int status_code = -1; + char *xml = load_description(dev->get_description_url(), &size, &status_code); + + if (status_code != 200) { + dev->set_igd_status(UPNPDevice::IGD_STATUS_HTTP_ERROR); + return; + } + + if (!xml || size < 1) { + dev->set_igd_status(UPNPDevice::IGD_STATUS_HTTP_EMPTY); + return; + } + + struct UPNPUrls urls = {}; + struct IGDdatas data; + + parserootdesc(xml, size, &data); + free(xml); + xml = nullptr; + + GetUPNPUrls(&urls, &data, dev->get_description_url().utf8().get_data(), 0); + + char addr[16]; +#if MINIUPNPC_API_VERSION >= 18 + int i = UPNP_GetValidIGD(devlist, &urls, &data, (char *)&addr, 16, nullptr, 0); +#else + int i = UPNP_GetValidIGD(devlist, &urls, &data, (char *)&addr, 16); +#endif + + if (i != 1) { + FreeUPNPUrls(&urls); + + switch (i) { + case 0: + dev->set_igd_status(UPNPDevice::IGD_STATUS_NO_IGD); + return; + case 2: + dev->set_igd_status(UPNPDevice::IGD_STATUS_DISCONNECTED); + return; + case 3: + dev->set_igd_status(UPNPDevice::IGD_STATUS_UNKNOWN_DEVICE); + return; + default: + dev->set_igd_status(UPNPDevice::IGD_STATUS_UNKNOWN_ERROR); + return; + } + } + + if (urls.controlURL[0] == '\0') { + FreeUPNPUrls(&urls); + dev->set_igd_status(UPNPDevice::IGD_STATUS_INVALID_CONTROL); + return; + } + + 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); +} + +int UPNPMiniUPNP::upnp_result(int in) { + switch (in) { + case UPNPCOMMAND_SUCCESS: + return UPNP_RESULT_SUCCESS; + case UPNPCOMMAND_UNKNOWN_ERROR: + return UPNP_RESULT_UNKNOWN_ERROR; + case UPNPCOMMAND_INVALID_ARGS: + return UPNP_RESULT_INVALID_ARGS; + case UPNPCOMMAND_HTTP_ERROR: + return UPNP_RESULT_HTTP_ERROR; + case UPNPCOMMAND_INVALID_RESPONSE: + return UPNP_RESULT_INVALID_RESPONSE; + case UPNPCOMMAND_MEM_ALLOC_ERROR: + return UPNP_RESULT_MEM_ALLOC_ERROR; + + case 402: + return UPNP_RESULT_INVALID_ARGS; + case 403: + return UPNP_RESULT_NOT_AUTHORIZED; + case 501: + return UPNP_RESULT_ACTION_FAILED; + case 606: + return UPNP_RESULT_NOT_AUTHORIZED; + case 714: + return UPNP_RESULT_NO_SUCH_ENTRY_IN_ARRAY; + case 715: + return UPNP_RESULT_SRC_IP_WILDCARD_NOT_PERMITTED; + case 716: + return UPNP_RESULT_EXT_PORT_WILDCARD_NOT_PERMITTED; + case 718: + return UPNP_RESULT_CONFLICT_WITH_OTHER_MAPPING; + case 724: + return UPNP_RESULT_SAME_PORT_VALUES_REQUIRED; + case 725: + return UPNP_RESULT_ONLY_PERMANENT_LEASE_SUPPORTED; + case 726: + return UPNP_RESULT_REMOTE_HOST_MUST_BE_WILDCARD; + case 727: + return UPNP_RESULT_EXT_PORT_MUST_BE_WILDCARD; + case 728: + return UPNP_RESULT_NO_PORT_MAPS_AVAILABLE; + case 729: + return UPNP_RESULT_CONFLICT_WITH_OTHER_MECHANISM; + case 732: + return UPNP_RESULT_INT_PORT_WILDCARD_NOT_PERMITTED; + case 733: + return UPNP_RESULT_INCONSISTENT_PARAMETERS; + } + + return UPNP_RESULT_UNKNOWN_ERROR; +} + +int UPNPMiniUPNP::get_device_count() const { + return devices.size(); +} + +Ref<UPNPDevice> UPNPMiniUPNP::get_device(int index) const { + ERR_FAIL_INDEX_V(index, devices.size(), nullptr); + + return devices.get(index); +} + +void UPNPMiniUPNP::add_device(Ref<UPNPDevice> device) { + ERR_FAIL_COND(device.is_null()); + + devices.push_back(device); +} + +void UPNPMiniUPNP::set_device(int index, Ref<UPNPDevice> device) { + ERR_FAIL_INDEX(index, devices.size()); + ERR_FAIL_COND(device.is_null()); + + devices.set(index, device); +} + +void UPNPMiniUPNP::remove_device(int index) { + ERR_FAIL_INDEX(index, devices.size()); + + devices.remove_at(index); +} + +void UPNPMiniUPNP::clear_devices() { + devices.clear(); +} + +Ref<UPNPDevice> UPNPMiniUPNP::get_gateway() const { + ERR_FAIL_COND_V_MSG(devices.is_empty(), nullptr, "Couldn't find any UPNPDevices."); + + for (int i = 0; i < devices.size(); i++) { + Ref<UPNPDevice> dev = get_device(i); + + if (dev.is_valid() && dev->is_valid_gateway()) { + return dev; + } + } + + return nullptr; +} + +void UPNPMiniUPNP::set_discover_multicast_if(const String &m_if) { + discover_multicast_if = m_if; +} + +String UPNPMiniUPNP::get_discover_multicast_if() const { + return discover_multicast_if; +} + +void UPNPMiniUPNP::set_discover_local_port(int port) { + discover_local_port = port; +} + +int UPNPMiniUPNP::get_discover_local_port() const { + return discover_local_port; +} + +void UPNPMiniUPNP::set_discover_ipv6(bool ipv6) { + discover_ipv6 = ipv6; +} + +bool UPNPMiniUPNP::is_discover_ipv6() const { + return discover_ipv6; +} + +String UPNPMiniUPNP::query_external_address() const { + Ref<UPNPDevice> dev = get_gateway(); + + if (dev.is_null()) { + return ""; + } + + return dev->query_external_address(); +} + +int UPNPMiniUPNP::add_port_mapping(int port, int port_internal, String desc, String proto, int duration) const { + Ref<UPNPDevice> dev = get_gateway(); + + if (dev.is_null()) { + return UPNP_RESULT_NO_GATEWAY; + } + + return dev->add_port_mapping(port, port_internal, desc, proto, duration); +} + +int UPNPMiniUPNP::delete_port_mapping(int port, String proto) const { + Ref<UPNPDevice> dev = get_gateway(); + + if (dev.is_null()) { + return UPNP_RESULT_NO_GATEWAY; + } + + return dev->delete_port_mapping(port, proto); +} + +#endif // WEB_ENABLED diff --git a/modules/upnp/upnp_miniupnp.h b/modules/upnp/upnp_miniupnp.h new file mode 100644 index 0000000000..0c7dba9d0b --- /dev/null +++ b/modules/upnp/upnp_miniupnp.h @@ -0,0 +1,93 @@ +/**************************************************************************/ +/* upnp_miniupnp.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#ifndef UPNP_MINIUPNP_H +#define UPNP_MINIUPNP_H + +#ifndef WEB_ENABLED + +#include "upnp.h" + +#include <miniupnpc.h> + +class UPNPMiniUPNP : public UPNP { + GDCLASS(UPNPMiniUPNP, UPNP); + +private: + static UPNP *_create(bool p_notify_postinitialize) { return static_cast<UPNP *>(ClassDB::creator<UPNPMiniUPNP>(p_notify_postinitialize)); } + + String discover_multicast_if = ""; + int discover_local_port = 0; + bool discover_ipv6 = false; + + Vector<Ref<UPNPDevice>> devices; + + bool is_common_device(const String &dev) const; + void add_device_to_list(UPNPDev *dev, UPNPDev *devlist); + void parse_igd(Ref<UPNPDevice> dev, UPNPDev *devlist); + char *load_description(const String &url, int *size, int *status_code) const; + +public: + static void make_default(); + + static int upnp_result(int in); + + virtual int get_device_count() const override; + virtual Ref<UPNPDevice> get_device(int index) const override; + virtual void add_device(Ref<UPNPDevice> device) override; + virtual void set_device(int index, Ref<UPNPDevice> device) override; + virtual void remove_device(int index) override; + virtual void clear_devices() override; + + virtual Ref<UPNPDevice> get_gateway() const override; + + virtual int discover(int timeout = 2000, int ttl = 2, const String &device_filter = "InternetGatewayDevice") override; + + virtual String query_external_address() const override; + + virtual int add_port_mapping(int port, int port_internal = 0, String desc = "", String proto = "UDP", int duration = 0) const override; + virtual int delete_port_mapping(int port, String proto = "UDP") const override; + + virtual void set_discover_multicast_if(const String &m_if) override; + virtual String get_discover_multicast_if() const override; + + virtual void set_discover_local_port(int port) override; + virtual int get_discover_local_port() const override; + + virtual void set_discover_ipv6(bool ipv6) override; + virtual bool is_discover_ipv6() const override; + + UPNPMiniUPNP() {} + virtual ~UPNPMiniUPNP() {} +}; + +#endif // WEB_ENABLED + +#endif // UPNP_MINIUPNP_H |