Implement IP.get_local_interfaces.
Allow getting interfaces names and assigned names. On UWP this is not supported, and the function will return one interface for each local address (with interface name the local address itself).
This commit is contained in:
parent
d6f8a43b60
commit
b574e476ec
6 changed files with 117 additions and 29 deletions
|
@ -234,6 +234,41 @@ Array IP::_get_local_addresses() const {
|
|||
return addresses;
|
||||
}
|
||||
|
||||
Array IP::_get_local_interfaces() const {
|
||||
|
||||
Array results;
|
||||
Map<String, Interface_Info> interfaces;
|
||||
get_local_interfaces(&interfaces);
|
||||
for (Map<String, Interface_Info>::Element *E = interfaces.front(); E; E = E->next()) {
|
||||
Interface_Info &c = E->get();
|
||||
Dictionary rc;
|
||||
rc["name"] = c.name;
|
||||
rc["friendly"] = c.name_friendly;
|
||||
rc["index"] = c.index;
|
||||
|
||||
Array ips;
|
||||
for (const List<IP_Address>::Element *F = c.ip_addresses.front(); F; F = F->next()) {
|
||||
ips.push_front(F->get());
|
||||
}
|
||||
rc["addresses"] = ips;
|
||||
|
||||
results.push_front(rc);
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
void IP::get_local_addresses(List<IP_Address> *r_addresses) const {
|
||||
|
||||
Map<String, Interface_Info> interfaces;
|
||||
get_local_interfaces(&interfaces);
|
||||
for (Map<String, Interface_Info>::Element *E = interfaces.front(); E; E = E->next()) {
|
||||
for (const List<IP_Address>::Element *F = E->get().ip_addresses.front(); F; F = F->next()) {
|
||||
r_addresses->push_front(F->get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void IP::_bind_methods() {
|
||||
|
||||
ClassDB::bind_method(D_METHOD("resolve_hostname", "host", "ip_type"), &IP::resolve_hostname, DEFVAL(IP::TYPE_ANY));
|
||||
|
@ -242,6 +277,7 @@ void IP::_bind_methods() {
|
|||
ClassDB::bind_method(D_METHOD("get_resolve_item_address", "id"), &IP::get_resolve_item_address);
|
||||
ClassDB::bind_method(D_METHOD("erase_resolve_item", "id"), &IP::erase_resolve_item);
|
||||
ClassDB::bind_method(D_METHOD("get_local_addresses"), &IP::_get_local_addresses);
|
||||
ClassDB::bind_method(D_METHOD("get_local_interfaces"), &IP::_get_local_interfaces);
|
||||
ClassDB::bind_method(D_METHOD("clear_cache", "hostname"), &IP::clear_cache, DEFVAL(""));
|
||||
|
||||
BIND_ENUM_CONSTANT(RESOLVER_STATUS_NONE);
|
||||
|
|
11
core/io/ip.h
11
core/io/ip.h
|
@ -73,16 +73,25 @@ protected:
|
|||
|
||||
virtual IP_Address _resolve_hostname(const String &p_hostname, Type p_type = TYPE_ANY) = 0;
|
||||
Array _get_local_addresses() const;
|
||||
Array _get_local_interfaces() const;
|
||||
|
||||
static IP *(*_create)();
|
||||
|
||||
public:
|
||||
struct Interface_Info {
|
||||
String name;
|
||||
String name_friendly;
|
||||
String index;
|
||||
List<IP_Address> ip_addresses;
|
||||
};
|
||||
|
||||
IP_Address resolve_hostname(const String &p_hostname, Type p_type = TYPE_ANY);
|
||||
// async resolver hostname
|
||||
ResolverID resolve_hostname_queue_item(const String &p_hostname, Type p_type = TYPE_ANY);
|
||||
ResolverStatus get_resolve_item_status(ResolverID p_id) const;
|
||||
IP_Address get_resolve_item_address(ResolverID p_id) const;
|
||||
virtual void get_local_addresses(List<IP_Address> *r_addresses) const = 0;
|
||||
virtual void get_local_addresses(List<IP_Address> *r_addresses) const;
|
||||
virtual void get_local_interfaces(Map<String, Interface_Info> *r_interfaces) const = 0;
|
||||
void erase_resolve_item(ResolverID p_id);
|
||||
|
||||
void clear_cache(const String &p_hostname = "");
|
||||
|
|
|
@ -40,6 +40,9 @@ IP_Address::operator Variant() const {
|
|||
|
||||
IP_Address::operator String() const {
|
||||
|
||||
if (wildcard)
|
||||
return "*";
|
||||
|
||||
if (!valid)
|
||||
return "";
|
||||
|
||||
|
|
|
@ -34,6 +34,22 @@
|
|||
Returns all of the user's current IPv4 and IPv6 addresses as an array.
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_local_interfaces" qualifiers="const">
|
||||
<return type="Array">
|
||||
</return>
|
||||
<description>
|
||||
Returns all network adapters as an array.
|
||||
Each adapter is a dictionary of the form:
|
||||
[codeblock]
|
||||
{
|
||||
"index": "1", # Interface index.
|
||||
"name": "eth0", # Interface name.
|
||||
"friendly": "Ethernet One", # A friendly name (might be empty).
|
||||
"addresses": ["192.168.1.101"], # An array of IP addresses associated to this interface.
|
||||
}
|
||||
[/codeblock]
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_resolve_item_address" qualifiers="const">
|
||||
<return type="String">
|
||||
</return>
|
||||
|
|
|
@ -56,6 +56,7 @@
|
|||
#endif // MINGW hack
|
||||
#endif
|
||||
#else // UNIX
|
||||
#include <net/if.h>
|
||||
#include <netdb.h>
|
||||
#ifdef ANDROID_ENABLED
|
||||
// We could drop this file once we up our API level to 24,
|
||||
|
@ -77,6 +78,7 @@
|
|||
static IP_Address _sockaddr2ip(struct sockaddr *p_addr) {
|
||||
|
||||
IP_Address ip;
|
||||
|
||||
if (p_addr->sa_family == AF_INET) {
|
||||
struct sockaddr_in *addr = (struct sockaddr_in *)p_addr;
|
||||
ip.set_ipv4((uint8_t *)&(addr->sin_addr));
|
||||
|
@ -129,24 +131,42 @@ IP_Address IP_Unix::_resolve_hostname(const String &p_hostname, Type p_type) {
|
|||
|
||||
#if defined(UWP_ENABLED)
|
||||
|
||||
void IP_Unix::get_local_addresses(List<IP_Address> *r_addresses) const {
|
||||
void IP_Unix::get_local_interfaces(Map<String, Interface_Info> *r_interfaces) const {
|
||||
|
||||
using namespace Windows::Networking;
|
||||
using namespace Windows::Networking::Connectivity;
|
||||
|
||||
// Returns addresses, not interfaces.
|
||||
auto hostnames = NetworkInformation::GetHostNames();
|
||||
|
||||
for (int i = 0; i < hostnames->Size; i++) {
|
||||
|
||||
if (hostnames->GetAt(i)->Type == HostNameType::Ipv4 || hostnames->GetAt(i)->Type == HostNameType::Ipv6 && hostnames->GetAt(i)->IPInformation != nullptr) {
|
||||
auto hostname = hostnames->GetAt(i);
|
||||
|
||||
r_addresses->push_back(IP_Address(String(hostnames->GetAt(i)->CanonicalName->Data())));
|
||||
if (hostname->Type != HostNameType::Ipv4 && hostname->Type != HostNameType::Ipv6)
|
||||
continue;
|
||||
|
||||
String name = hostname->RawName->Data();
|
||||
Map<String, Interface_Info>::Element *E = r_interfaces->find(name);
|
||||
if (!E) {
|
||||
Interface_Info info;
|
||||
info.name = name;
|
||||
info.name_friendly = hostname->DisplayName->Data();
|
||||
info.index = 0;
|
||||
E = r_interfaces->insert(name, info);
|
||||
ERR_CONTINUE(!E);
|
||||
}
|
||||
|
||||
Interface_Info &info = E->get();
|
||||
|
||||
IP_Address ip = IP_Address(hostname->CanonicalName->Data());
|
||||
info.ip_addresses.push_front(ip);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void IP_Unix::get_local_addresses(List<IP_Address> *r_addresses) const {
|
||||
void IP_Unix::get_local_interfaces(Map<String, Interface_Info> *r_interfaces) const {
|
||||
|
||||
ULONG buf_size = 1024;
|
||||
IP_ADAPTER_ADDRESSES *addrs;
|
||||
|
@ -173,29 +193,23 @@ void IP_Unix::get_local_addresses(List<IP_Address> *r_addresses) const {
|
|||
|
||||
while (adapter != NULL) {
|
||||
|
||||
Interface_Info info;
|
||||
info.name = adapter->AdapterName;
|
||||
info.name_friendly = adapter->FriendlyName;
|
||||
info.index = String::num_uint64(adapter->IfIndex);
|
||||
|
||||
IP_ADAPTER_UNICAST_ADDRESS *address = adapter->FirstUnicastAddress;
|
||||
while (address != NULL) {
|
||||
|
||||
IP_Address ip;
|
||||
|
||||
if (address->Address.lpSockaddr->sa_family == AF_INET) {
|
||||
|
||||
SOCKADDR_IN *ipv4 = reinterpret_cast<SOCKADDR_IN *>(address->Address.lpSockaddr);
|
||||
|
||||
ip.set_ipv4((uint8_t *)&(ipv4->sin_addr));
|
||||
r_addresses->push_back(ip);
|
||||
|
||||
} else if (address->Address.lpSockaddr->sa_family == AF_INET6) { // ipv6
|
||||
|
||||
SOCKADDR_IN6 *ipv6 = reinterpret_cast<SOCKADDR_IN6 *>(address->Address.lpSockaddr);
|
||||
|
||||
ip.set_ipv6(ipv6->sin6_addr.s6_addr);
|
||||
r_addresses->push_back(ip);
|
||||
};
|
||||
|
||||
int family = address->Address.lpSockaddr->sa_family;
|
||||
if (family != AF_INET && family != AF_INET6)
|
||||
continue;
|
||||
info.ip_addresses.push_front(_sockaddr2ip(address->Address.lpSockaddr));
|
||||
address = address->Next;
|
||||
};
|
||||
}
|
||||
adapter = adapter->Next;
|
||||
// Only add interface if it has at least one IP
|
||||
if (info.ip_addresses.size() > 0)
|
||||
r_interfaces->insert(info.name, info);
|
||||
};
|
||||
|
||||
memfree(addrs);
|
||||
|
@ -205,7 +219,7 @@ void IP_Unix::get_local_addresses(List<IP_Address> *r_addresses) const {
|
|||
|
||||
#else // UNIX
|
||||
|
||||
void IP_Unix::get_local_addresses(List<IP_Address> *r_addresses) const {
|
||||
void IP_Unix::get_local_interfaces(Map<String, Interface_Info> *r_interfaces) const {
|
||||
|
||||
struct ifaddrs *ifAddrStruct = NULL;
|
||||
struct ifaddrs *ifa = NULL;
|
||||
|
@ -222,8 +236,18 @@ void IP_Unix::get_local_addresses(List<IP_Address> *r_addresses) const {
|
|||
if (family != AF_INET && family != AF_INET6)
|
||||
continue;
|
||||
|
||||
IP_Address ip = _sockaddr2ip(ifa->ifa_addr);
|
||||
r_addresses->push_back(ip);
|
||||
Map<String, Interface_Info>::Element *E = r_interfaces->find(ifa->ifa_name);
|
||||
if (!E) {
|
||||
Interface_Info info;
|
||||
info.name = ifa->ifa_name;
|
||||
info.name_friendly = ifa->ifa_name;
|
||||
info.index = String::num_uint64(if_nametoindex(ifa->ifa_name));
|
||||
E = r_interfaces->insert(ifa->ifa_name, info);
|
||||
ERR_CONTINUE(!E);
|
||||
}
|
||||
|
||||
Interface_Info &info = E->get();
|
||||
info.ip_addresses.push_front(_sockaddr2ip(ifa->ifa_addr));
|
||||
}
|
||||
|
||||
if (ifAddrStruct != NULL) freeifaddrs(ifAddrStruct);
|
||||
|
|
|
@ -43,7 +43,7 @@ class IP_Unix : public IP {
|
|||
static IP *_create_unix();
|
||||
|
||||
public:
|
||||
virtual void get_local_addresses(List<IP_Address> *r_addresses) const;
|
||||
virtual void get_local_interfaces(Map<String, Interface_Info> *r_interfaces) const;
|
||||
|
||||
static void make_default();
|
||||
IP_Unix();
|
||||
|
|
Loading…
Reference in a new issue