mirror of https://github.com/godotengine/godot
Merge pull request #99597 from Faless/upnp/custom_instance
[UPNP] Allow disabling UPNP implementation on the Web
This commit is contained in:
commit
29e6ef4277
|
|
@ -10,7 +10,7 @@ env_upnp = env_modules.Clone()
|
||||||
|
|
||||||
thirdparty_obj = []
|
thirdparty_obj = []
|
||||||
|
|
||||||
if env["builtin_miniupnpc"]:
|
if env["builtin_miniupnpc"] and env["platform"] != "web":
|
||||||
thirdparty_dir = "#thirdparty/miniupnpc/"
|
thirdparty_dir = "#thirdparty/miniupnpc/"
|
||||||
thirdparty_sources = [
|
thirdparty_sources = [
|
||||||
"igd_desc_parse.c",
|
"igd_desc_parse.c",
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,11 @@
|
||||||
#include "upnp.h"
|
#include "upnp.h"
|
||||||
#include "upnp_device.h"
|
#include "upnp_device.h"
|
||||||
|
|
||||||
|
#ifndef WEB_ENABLED
|
||||||
|
#include "upnp_device_miniupnp.h"
|
||||||
|
#include "upnp_miniupnp.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "core/error/error_macros.h"
|
#include "core/error/error_macros.h"
|
||||||
|
|
||||||
void initialize_upnp_module(ModuleInitializationLevel p_level) {
|
void initialize_upnp_module(ModuleInitializationLevel p_level) {
|
||||||
|
|
@ -40,8 +45,13 @@ void initialize_upnp_module(ModuleInitializationLevel p_level) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
GDREGISTER_CLASS(UPNP);
|
ClassDB::register_custom_instance_class<UPNP>();
|
||||||
GDREGISTER_CLASS(UPNPDevice);
|
ClassDB::register_custom_instance_class<UPNPDevice>();
|
||||||
|
|
||||||
|
#ifndef WEB_ENABLED
|
||||||
|
UPNPMiniUPNP::make_default();
|
||||||
|
UPNPDeviceMiniUPNP::make_default();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void uninitialize_upnp_module(ModuleInitializationLevel p_level) {
|
void uninitialize_upnp_module(ModuleInitializationLevel p_level) {
|
||||||
|
|
|
||||||
|
|
@ -30,298 +30,7 @@
|
||||||
|
|
||||||
#include "upnp.h"
|
#include "upnp.h"
|
||||||
|
|
||||||
#include <miniwget.h>
|
UPNP *(*UPNP::_create)(bool p_notify_postinitialize) = nullptr;
|
||||||
#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);
|
|
||||||
}
|
|
||||||
|
|
||||||
void UPNP::_bind_methods() {
|
void UPNP::_bind_methods() {
|
||||||
ClassDB::bind_method(D_METHOD("get_device_count"), &UPNP::get_device_count);
|
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_NO_DEVICES);
|
||||||
BIND_ENUM_CONSTANT(UPNP_RESULT_UNKNOWN_ERROR);
|
BIND_ENUM_CONSTANT(UPNP_RESULT_UNKNOWN_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
UPNP::UPNP() {
|
|
||||||
}
|
|
||||||
|
|
||||||
UPNP::~UPNP() {
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -35,26 +35,14 @@
|
||||||
|
|
||||||
#include "core/object/ref_counted.h"
|
#include "core/object/ref_counted.h"
|
||||||
|
|
||||||
#include <miniupnpc.h>
|
|
||||||
|
|
||||||
class UPNP : public RefCounted {
|
class UPNP : public RefCounted {
|
||||||
GDCLASS(UPNP, 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:
|
protected:
|
||||||
static void _bind_methods();
|
static void _bind_methods();
|
||||||
|
|
||||||
|
static UPNP *(*_create)(bool p_notify_postinitialize);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum UPNPResult {
|
enum UPNPResult {
|
||||||
UPNP_RESULT_SUCCESS,
|
UPNP_RESULT_SUCCESS,
|
||||||
|
|
@ -88,35 +76,40 @@ public:
|
||||||
UPNP_RESULT_UNKNOWN_ERROR,
|
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;
|
virtual int get_device_count() const = 0;
|
||||||
Ref<UPNPDevice> get_device(int index) const;
|
virtual Ref<UPNPDevice> get_device(int index) const = 0;
|
||||||
void add_device(Ref<UPNPDevice> device);
|
virtual void add_device(Ref<UPNPDevice> device) = 0;
|
||||||
void set_device(int index, Ref<UPNPDevice> device);
|
virtual void set_device(int index, Ref<UPNPDevice> device) = 0;
|
||||||
void remove_device(int index);
|
virtual void remove_device(int index) = 0;
|
||||||
void clear_devices();
|
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;
|
virtual int add_port_mapping(int port, int port_internal = 0, String desc = "", String proto = "UDP", int duration = 0) const = 0;
|
||||||
int delete_port_mapping(int port, String proto = "UDP") const;
|
virtual int delete_port_mapping(int port, String proto = "UDP") const = 0;
|
||||||
|
|
||||||
void set_discover_multicast_if(const String &m_if);
|
virtual void set_discover_multicast_if(const String &m_if) = 0;
|
||||||
String get_discover_multicast_if() const;
|
virtual String get_discover_multicast_if() const = 0;
|
||||||
|
|
||||||
void set_discover_local_port(int port);
|
virtual void set_discover_local_port(int port) = 0;
|
||||||
int get_discover_local_port() const;
|
virtual int get_discover_local_port() const = 0;
|
||||||
|
|
||||||
void set_discover_ipv6(bool ipv6);
|
virtual void set_discover_ipv6(bool ipv6) = 0;
|
||||||
bool is_discover_ipv6() const;
|
virtual bool is_discover_ipv6() const = 0;
|
||||||
|
|
||||||
UPNP();
|
UPNP() {}
|
||||||
~UPNP();
|
virtual ~UPNP() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
VARIANT_ENUM_CAST(UPNP::UPNPResult)
|
VARIANT_ENUM_CAST(UPNP::UPNPResult)
|
||||||
|
|
|
||||||
|
|
@ -30,119 +30,7 @@
|
||||||
|
|
||||||
#include "upnp_device.h"
|
#include "upnp_device.h"
|
||||||
|
|
||||||
#include "upnp.h"
|
UPNPDevice *(*UPNPDevice::_create)(bool p_notify_postinitialize) = nullptr;
|
||||||
|
|
||||||
#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;
|
|
||||||
}
|
|
||||||
|
|
||||||
void UPNPDevice::_bind_methods() {
|
void UPNPDevice::_bind_methods() {
|
||||||
ClassDB::bind_method(D_METHOD("is_valid_gateway"), &UPNPDevice::is_valid_gateway);
|
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_MALLOC_ERROR);
|
||||||
BIND_ENUM_CONSTANT(IGD_STATUS_UNKNOWN_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() {
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,11 @@
|
||||||
class UPNPDevice : public RefCounted {
|
class UPNPDevice : public RefCounted {
|
||||||
GDCLASS(UPNPDevice, RefCounted);
|
GDCLASS(UPNPDevice, RefCounted);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
static void _bind_methods();
|
||||||
|
|
||||||
|
static UPNPDevice *(*_create)(bool p_notify_postinitialize);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum IGDStatus {
|
enum IGDStatus {
|
||||||
IGD_STATUS_OK,
|
IGD_STATUS_OK,
|
||||||
|
|
@ -50,42 +55,38 @@ public:
|
||||||
IGD_STATUS_UNKNOWN_ERROR,
|
IGD_STATUS_UNKNOWN_ERROR,
|
||||||
};
|
};
|
||||||
|
|
||||||
void set_description_url(const String &url);
|
static UPNPDevice *create(bool p_notify_postinitialize = true) {
|
||||||
String get_description_url() const;
|
if (!_create) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return _create(p_notify_postinitialize);
|
||||||
|
}
|
||||||
|
|
||||||
void set_service_type(const String &type);
|
virtual void set_description_url(const String &url) = 0;
|
||||||
String get_service_type() const;
|
virtual String get_description_url() const = 0;
|
||||||
|
|
||||||
void set_igd_control_url(const String &url);
|
virtual void set_service_type(const String &type) = 0;
|
||||||
String get_igd_control_url() const;
|
virtual String get_service_type() const = 0;
|
||||||
|
|
||||||
void set_igd_service_type(const String &type);
|
virtual void set_igd_control_url(const String &url) = 0;
|
||||||
String get_igd_service_type() const;
|
virtual String get_igd_control_url() const = 0;
|
||||||
|
|
||||||
void set_igd_our_addr(const String &addr);
|
virtual void set_igd_service_type(const String &type) = 0;
|
||||||
String get_igd_our_addr() const;
|
virtual String get_igd_service_type() const = 0;
|
||||||
|
|
||||||
void set_igd_status(IGDStatus status);
|
virtual void set_igd_our_addr(const String &addr) = 0;
|
||||||
IGDStatus get_igd_status() const;
|
virtual String get_igd_our_addr() const = 0;
|
||||||
|
|
||||||
bool is_valid_gateway() const;
|
virtual void set_igd_status(IGDStatus status) = 0;
|
||||||
String query_external_address() const;
|
virtual IGDStatus get_igd_status() 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;
|
|
||||||
|
|
||||||
UPNPDevice();
|
virtual bool is_valid_gateway() const = 0;
|
||||||
~UPNPDevice();
|
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;
|
||||||
|
|
||||||
protected:
|
UPNPDevice() {}
|
||||||
static void _bind_methods();
|
virtual ~UPNPDevice() {}
|
||||||
|
|
||||||
private:
|
|
||||||
String description_url;
|
|
||||||
String service_type;
|
|
||||||
String igd_control_url;
|
|
||||||
String igd_service_type;
|
|
||||||
String igd_our_addr;
|
|
||||||
IGDStatus igd_status;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
VARIANT_ENUM_CAST(UPNPDevice::IGDStatus)
|
VARIANT_ENUM_CAST(UPNPDevice::IGDStatus)
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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
|
||||||
Loading…
Reference in New Issue