Merge pull request #29935 from Faless/net/get_if_multicast_pr
Multicast, more network interfaces info
This commit is contained in:
commit
1e833cadbc
12 changed files with 238 additions and 29 deletions
|
@ -234,6 +234,41 @@ Array IP::_get_local_addresses() const {
|
||||||
return addresses;
|
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() {
|
void IP::_bind_methods() {
|
||||||
|
|
||||||
ClassDB::bind_method(D_METHOD("resolve_hostname", "host", "ip_type"), &IP::resolve_hostname, DEFVAL(IP::TYPE_ANY));
|
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("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("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_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(""));
|
ClassDB::bind_method(D_METHOD("clear_cache", "hostname"), &IP::clear_cache, DEFVAL(""));
|
||||||
|
|
||||||
BIND_ENUM_CONSTANT(RESOLVER_STATUS_NONE);
|
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;
|
virtual IP_Address _resolve_hostname(const String &p_hostname, Type p_type = TYPE_ANY) = 0;
|
||||||
Array _get_local_addresses() const;
|
Array _get_local_addresses() const;
|
||||||
|
Array _get_local_interfaces() const;
|
||||||
|
|
||||||
static IP *(*_create)();
|
static IP *(*_create)();
|
||||||
|
|
||||||
public:
|
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);
|
IP_Address resolve_hostname(const String &p_hostname, Type p_type = TYPE_ANY);
|
||||||
// async resolver hostname
|
// async resolver hostname
|
||||||
ResolverID resolve_hostname_queue_item(const String &p_hostname, Type p_type = TYPE_ANY);
|
ResolverID resolve_hostname_queue_item(const String &p_hostname, Type p_type = TYPE_ANY);
|
||||||
ResolverStatus get_resolve_item_status(ResolverID p_id) const;
|
ResolverStatus get_resolve_item_status(ResolverID p_id) const;
|
||||||
IP_Address get_resolve_item_address(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 erase_resolve_item(ResolverID p_id);
|
||||||
|
|
||||||
void clear_cache(const String &p_hostname = "");
|
void clear_cache(const String &p_hostname = "");
|
||||||
|
|
|
@ -40,6 +40,9 @@ IP_Address::operator Variant() const {
|
||||||
|
|
||||||
IP_Address::operator String() const {
|
IP_Address::operator String() const {
|
||||||
|
|
||||||
|
if (wildcard)
|
||||||
|
return "*";
|
||||||
|
|
||||||
if (!valid)
|
if (!valid)
|
||||||
return "";
|
return "";
|
||||||
|
|
||||||
|
|
|
@ -74,6 +74,8 @@ public:
|
||||||
virtual void set_ipv6_only_enabled(bool p_enabled) = 0;
|
virtual void set_ipv6_only_enabled(bool p_enabled) = 0;
|
||||||
virtual void set_tcp_no_delay_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 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
|
#endif // NET_SOCKET_H
|
||||||
|
|
|
@ -37,6 +37,27 @@ void PacketPeerUDP::set_blocking_mode(bool p_enable) {
|
||||||
blocking = 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 {
|
String PacketPeerUDP::_get_packet_ip() const {
|
||||||
|
|
||||||
return get_packet_address();
|
return get_packet_address();
|
||||||
|
@ -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_ip"), &PacketPeerUDP::_get_packet_ip);
|
||||||
ClassDB::bind_method(D_METHOD("get_packet_port"), &PacketPeerUDP::get_packet_port);
|
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("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() :
|
PacketPeerUDP::PacketPeerUDP() :
|
||||||
|
|
|
@ -77,6 +77,8 @@ public:
|
||||||
Error get_packet(const uint8_t **r_buffer, int &r_buffer_size);
|
Error get_packet(const uint8_t **r_buffer, int &r_buffer_size);
|
||||||
int get_available_packet_count() const;
|
int get_available_packet_count() const;
|
||||||
int get_max_packet_size() 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();
|
||||||
~PacketPeerUDP();
|
~PacketPeerUDP();
|
||||||
|
|
|
@ -34,6 +34,22 @@
|
||||||
Returns all of the user's current IPv4 and IPv6 addresses as an array.
|
Returns all of the user's current IPv4 and IPv6 addresses as an array.
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</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">
|
<method name="get_resolve_item_address" qualifiers="const">
|
||||||
<return type="String">
|
<return type="String">
|
||||||
</return>
|
</return>
|
||||||
|
|
|
@ -37,6 +37,29 @@
|
||||||
Returns whether this [PacketPeerUDP] is listening.
|
Returns whether this [PacketPeerUDP] is listening.
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</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">
|
<method name="listen">
|
||||||
<return type="int" enum="Error">
|
<return type="int" enum="Error">
|
||||||
</return>
|
</return>
|
||||||
|
|
|
@ -56,6 +56,7 @@
|
||||||
#endif // MINGW hack
|
#endif // MINGW hack
|
||||||
#endif
|
#endif
|
||||||
#else // UNIX
|
#else // UNIX
|
||||||
|
#include <net/if.h>
|
||||||
#include <netdb.h>
|
#include <netdb.h>
|
||||||
#ifdef ANDROID_ENABLED
|
#ifdef ANDROID_ENABLED
|
||||||
// We could drop this file once we up our API level to 24,
|
// 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) {
|
static IP_Address _sockaddr2ip(struct sockaddr *p_addr) {
|
||||||
|
|
||||||
IP_Address ip;
|
IP_Address ip;
|
||||||
|
|
||||||
if (p_addr->sa_family == AF_INET) {
|
if (p_addr->sa_family == AF_INET) {
|
||||||
struct sockaddr_in *addr = (struct sockaddr_in *)p_addr;
|
struct sockaddr_in *addr = (struct sockaddr_in *)p_addr;
|
||||||
ip.set_ipv4((uint8_t *)&(addr->sin_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)
|
#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;
|
||||||
using namespace Windows::Networking::Connectivity;
|
using namespace Windows::Networking::Connectivity;
|
||||||
|
|
||||||
|
// Returns addresses, not interfaces.
|
||||||
auto hostnames = NetworkInformation::GetHostNames();
|
auto hostnames = NetworkInformation::GetHostNames();
|
||||||
|
|
||||||
for (int i = 0; i < hostnames->Size; i++) {
|
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
|
#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;
|
ULONG buf_size = 1024;
|
||||||
IP_ADAPTER_ADDRESSES *addrs;
|
IP_ADAPTER_ADDRESSES *addrs;
|
||||||
|
@ -173,29 +193,23 @@ void IP_Unix::get_local_addresses(List<IP_Address> *r_addresses) const {
|
||||||
|
|
||||||
while (adapter != NULL) {
|
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;
|
IP_ADAPTER_UNICAST_ADDRESS *address = adapter->FirstUnicastAddress;
|
||||||
while (address != NULL) {
|
while (address != NULL) {
|
||||||
|
int family = address->Address.lpSockaddr->sa_family;
|
||||||
IP_Address ip;
|
if (family != AF_INET && family != AF_INET6)
|
||||||
|
continue;
|
||||||
if (address->Address.lpSockaddr->sa_family == AF_INET) {
|
info.ip_addresses.push_front(_sockaddr2ip(address->Address.lpSockaddr));
|
||||||
|
|
||||||
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);
|
|
||||||
};
|
|
||||||
|
|
||||||
address = address->Next;
|
address = address->Next;
|
||||||
};
|
}
|
||||||
adapter = adapter->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);
|
memfree(addrs);
|
||||||
|
@ -205,7 +219,7 @@ void IP_Unix::get_local_addresses(List<IP_Address> *r_addresses) const {
|
||||||
|
|
||||||
#else // UNIX
|
#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 *ifAddrStruct = NULL;
|
||||||
struct ifaddrs *ifa = 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)
|
if (family != AF_INET && family != AF_INET6)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
IP_Address ip = _sockaddr2ip(ifa->ifa_addr);
|
Map<String, Interface_Info>::Element *E = r_interfaces->find(ifa->ifa_name);
|
||||||
r_addresses->push_back(ip);
|
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);
|
if (ifAddrStruct != NULL) freeifaddrs(ifAddrStruct);
|
||||||
|
|
|
@ -43,7 +43,7 @@ class IP_Unix : public IP {
|
||||||
static IP *_create_unix();
|
static IP *_create_unix();
|
||||||
|
|
||||||
public:
|
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();
|
static void make_default();
|
||||||
IP_Unix();
|
IP_Unix();
|
||||||
|
|
|
@ -59,6 +59,14 @@
|
||||||
#define MSG_NOSIGNAL SO_NOSIGPIPE
|
#define MSG_NOSIGNAL SO_NOSIGPIPE
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// BSD calls this flag IPV6_JOIN_GROUP
|
||||||
|
#if !defined(IPV6_ADD_MEMBERSHIP) && defined(IPV6_JOIN_GROUP)
|
||||||
|
#define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP
|
||||||
|
#endif
|
||||||
|
#if !defined(IPV6_DROP_MEMBERSHIP) && defined(IPV6_LEAVE_GROUP)
|
||||||
|
#define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP
|
||||||
|
#endif
|
||||||
|
|
||||||
// Some custom defines to minimize ifdefs
|
// Some custom defines to minimize ifdefs
|
||||||
#define SOCK_EMPTY -1
|
#define SOCK_EMPTY -1
|
||||||
#define SOCK_BUF(x) x
|
#define SOCK_BUF(x) x
|
||||||
|
@ -227,6 +235,58 @@ bool NetSocketPosix::_can_use_ip(const IP_Address p_ip, const bool p_for_bind) c
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_FORCE_INLINE_ Error NetSocketPosix::_change_multicast_group(IP_Address p_ip, String p_if_name, bool p_add) {
|
||||||
|
|
||||||
|
ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED);
|
||||||
|
ERR_FAIL_COND_V(!_can_use_ip(p_ip, false), ERR_INVALID_PARAMETER);
|
||||||
|
|
||||||
|
// Need to force level and af_family to IP(v4) when using dual stacking and provided multicast group is IPv4
|
||||||
|
IP::Type type = _ip_type == IP::TYPE_ANY && p_ip.is_ipv4() ? IP::TYPE_IPV4 : _ip_type;
|
||||||
|
// This needs to be the proper level for the multicast group, no matter if the socket is dual stacking.
|
||||||
|
int level = type == IP::TYPE_IPV4 ? IPPROTO_IP : IPPROTO_IPV6;
|
||||||
|
int ret = -1;
|
||||||
|
|
||||||
|
IP_Address if_ip;
|
||||||
|
uint32_t if_v6id = 0;
|
||||||
|
Map<String, IP::Interface_Info> if_info;
|
||||||
|
IP::get_singleton()->get_local_interfaces(&if_info);
|
||||||
|
for (Map<String, IP::Interface_Info>::Element *E = if_info.front(); E; E = E->next()) {
|
||||||
|
IP::Interface_Info &c = E->get();
|
||||||
|
if (c.name != p_if_name)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if_v6id = (uint32_t)c.index.to_int64();
|
||||||
|
if (type == IP::TYPE_IPV6)
|
||||||
|
break; // IPv6 uses index.
|
||||||
|
|
||||||
|
for (List<IP_Address>::Element *F = c.ip_addresses.front(); F; F = F->next()) {
|
||||||
|
if (!F->get().is_ipv4())
|
||||||
|
continue; // Wrong IP type
|
||||||
|
if_ip = F->get();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (level == IPPROTO_IP) {
|
||||||
|
ERR_FAIL_COND_V(!if_ip.is_valid(), ERR_INVALID_PARAMETER);
|
||||||
|
struct ip_mreq greq;
|
||||||
|
int sock_opt = p_add ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP;
|
||||||
|
copymem(&greq.imr_multiaddr, p_ip.get_ipv4(), 4);
|
||||||
|
copymem(&greq.imr_interface, if_ip.get_ipv4(), 4);
|
||||||
|
ret = setsockopt(_sock, level, sock_opt, (const char *)&greq, sizeof(greq));
|
||||||
|
} else {
|
||||||
|
struct ipv6_mreq greq;
|
||||||
|
int sock_opt = p_add ? IPV6_ADD_MEMBERSHIP : IPV6_DROP_MEMBERSHIP;
|
||||||
|
copymem(&greq.ipv6mr_multiaddr, p_ip.get_ipv6(), 16);
|
||||||
|
greq.ipv6mr_interface = if_v6id;
|
||||||
|
ret = setsockopt(_sock, level, sock_opt, (const char *)&greq, sizeof(greq));
|
||||||
|
}
|
||||||
|
ERR_FAIL_COND_V(ret != 0, FAILED);
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
void NetSocketPosix::_set_socket(SOCKET_TYPE p_sock, IP::Type p_ip_type, bool p_is_stream) {
|
void NetSocketPosix::_set_socket(SOCKET_TYPE p_sock, IP::Type p_ip_type, bool p_is_stream) {
|
||||||
_sock = p_sock;
|
_sock = p_sock;
|
||||||
_ip_type = p_ip_type;
|
_ip_type = p_ip_type;
|
||||||
|
@ -625,3 +685,11 @@ Ref<NetSocket> NetSocketPosix::accept(IP_Address &r_ip, uint16_t &r_port) {
|
||||||
ns->set_blocking_enabled(false);
|
ns->set_blocking_enabled(false);
|
||||||
return Ref<NetSocket>(ns);
|
return Ref<NetSocket>(ns);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Error NetSocketPosix::join_multicast_group(const IP_Address &p_ip, String p_if_name) {
|
||||||
|
return _change_multicast_group(p_ip, p_if_name, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
Error NetSocketPosix::leave_multicast_group(const IP_Address &p_ip, String p_if_name) {
|
||||||
|
return _change_multicast_group(p_ip, p_if_name, false);
|
||||||
|
}
|
||||||
|
|
|
@ -60,6 +60,7 @@ private:
|
||||||
|
|
||||||
NetError _get_socket_error();
|
NetError _get_socket_error();
|
||||||
void _set_socket(SOCKET_TYPE p_sock, IP::Type p_ip_type, bool p_is_stream);
|
void _set_socket(SOCKET_TYPE p_sock, IP::Type p_ip_type, bool p_is_stream);
|
||||||
|
_FORCE_INLINE_ Error _change_multicast_group(IP_Address p_ip, String p_if_name, bool p_add);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
static NetSocket *_create_func();
|
static NetSocket *_create_func();
|
||||||
|
@ -93,6 +94,8 @@ public:
|
||||||
virtual void set_tcp_no_delay_enabled(bool p_enabled);
|
virtual void set_tcp_no_delay_enabled(bool p_enabled);
|
||||||
virtual void set_reuse_address_enabled(bool p_enabled);
|
virtual void set_reuse_address_enabled(bool p_enabled);
|
||||||
virtual void set_reuse_port_enabled(bool p_enabled);
|
virtual void set_reuse_port_enabled(bool p_enabled);
|
||||||
|
virtual Error join_multicast_group(const IP_Address &p_multi_address, String p_if_name);
|
||||||
|
virtual Error leave_multicast_group(const IP_Address &p_multi_address, String p_if_name);
|
||||||
|
|
||||||
NetSocketPosix();
|
NetSocketPosix();
|
||||||
~NetSocketPosix();
|
~NetSocketPosix();
|
||||||
|
|
Loading…
Reference in a new issue