Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions core/io/ip.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand All @@ -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);
Expand Down
11 changes: 10 additions & 1 deletion core/io/ip.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,16 +73,25 @@ class IP : public Object {

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 = "");
Expand Down
3 changes: 3 additions & 0 deletions core/io/ip_address.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ IP_Address::operator Variant() const {

IP_Address::operator String() const {

if (wildcard)
return "*";

if (!valid)
return "";

Expand Down
2 changes: 2 additions & 0 deletions core/io/net_socket.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ class NetSocket : public Reference {
virtual void set_ipv6_only_enabled(bool p_enabled) = 0;
virtual void set_tcp_no_delay_enabled(bool p_enabled) = 0;
virtual void set_reuse_address_enabled(bool p_enabled) = 0;
virtual Error join_multicast_group(const IP_Address &p_multi_address, String p_if_name) = 0;
virtual Error leave_multicast_group(const IP_Address &p_multi_address, String p_if_name) = 0;
};

#endif // NET_SOCKET_H
23 changes: 23 additions & 0 deletions core/io/packet_peer_udp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,27 @@ void PacketPeerUDP::set_blocking_mode(bool p_enable) {
blocking = p_enable;
}

Error PacketPeerUDP::join_multicast_group(IP_Address p_multi_address, String p_if_name) {

ERR_FAIL_COND_V(!_sock.is_valid(), ERR_UNAVAILABLE);
ERR_FAIL_COND_V(!p_multi_address.is_valid(), ERR_INVALID_PARAMETER);

if (!_sock->is_open()) {
IP::Type ip_type = p_multi_address.is_ipv4() ? IP::TYPE_IPV4 : IP::TYPE_IPV6;
Error err = _sock->open(NetSocket::TYPE_UDP, ip_type);
ERR_FAIL_COND_V(err != OK, err);
_sock->set_blocking_enabled(false);
}
return _sock->join_multicast_group(p_multi_address, p_if_name);
}

Error PacketPeerUDP::leave_multicast_group(IP_Address p_multi_address, String p_if_name) {

ERR_FAIL_COND_V(!_sock.is_valid(), ERR_UNAVAILABLE);
ERR_FAIL_COND_V(!_sock->is_open(), ERR_UNCONFIGURED);
return _sock->leave_multicast_group(p_multi_address, p_if_name);
}

String PacketPeerUDP::_get_packet_ip() const {

return get_packet_address();
Expand Down Expand Up @@ -237,6 +258,8 @@ void PacketPeerUDP::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_packet_ip"), &PacketPeerUDP::_get_packet_ip);
ClassDB::bind_method(D_METHOD("get_packet_port"), &PacketPeerUDP::get_packet_port);
ClassDB::bind_method(D_METHOD("set_dest_address", "host", "port"), &PacketPeerUDP::_set_dest_address);
ClassDB::bind_method(D_METHOD("join_multicast_group", "multicast_address", "interface_name"), &PacketPeerUDP::join_multicast_group);
ClassDB::bind_method(D_METHOD("leave_multicast_group", "multicast_address", "interface_name"), &PacketPeerUDP::leave_multicast_group);
}

PacketPeerUDP::PacketPeerUDP() :
Expand Down
2 changes: 2 additions & 0 deletions core/io/packet_peer_udp.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ class PacketPeerUDP : public PacketPeer {
Error get_packet(const uint8_t **r_buffer, int &r_buffer_size);
int get_available_packet_count() const;
int get_max_packet_size() const;
Error join_multicast_group(IP_Address p_multi_address, String p_if_name);
Error leave_multicast_group(IP_Address p_multi_address, String p_if_name);

PacketPeerUDP();
~PacketPeerUDP();
Expand Down
16 changes: 16 additions & 0 deletions doc/classes/IP.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down
23 changes: 23 additions & 0 deletions doc/classes/PacketPeerUDP.xml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,29 @@
Returns whether this [PacketPeerUDP] is listening.
</description>
</method>
<method name="join_multicast_group">
<return type="int" enum="Error">
</return>
<argument index="0" name="multicast_address" type="String">
</argument>
<argument index="1" name="interface_name" type="String">
</argument>
<description>
Join the multicast group specified by [code]multicast_address[/code] using the interface identified by [code]interface_name[/code].
You can join the same multicast group with multiple interfaces. Use [method IP.get_local_interfaces] to know which are available.
</description>
</method>
<method name="leave_multicast_group">
<return type="int" enum="Error">
</return>
<argument index="0" name="multicast_address" type="String">
</argument>
<argument index="1" name="interface_name" type="String">
</argument>
<description>
Remove the interface identified by [code]interface_name[/code] from the multicast group specified by [code]multicast_address[/code].
</description>
</method>
<method name="listen">
<return type="int" enum="Error">
</return>
Expand Down
78 changes: 51 additions & 27 deletions drivers/unix/ip_unix.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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));
Expand Down Expand Up @@ -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);

if (hostname->Type != HostNameType::Ipv4 && hostname->Type != HostNameType::Ipv6)
continue;

r_addresses->push_back(IP_Address(String(hostnames->GetAt(i)->CanonicalName->Data())));
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;
Expand All @@ -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);
Expand All @@ -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;
Expand All @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion drivers/unix/ip_unix.h
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
Loading