diff options
author | RĂ©mi Verschelde <rverschelde@gmail.com> | 2019-06-21 10:21:01 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-06-21 10:21:01 +0200 |
commit | 1e833cadbcf1403eec85fa85b290328bc1bf5179 (patch) | |
tree | 8c98449750f26d7b411ef2b46164826435bdbe91 /drivers | |
parent | 5c66771e3ebccdfec55bb94ea521d2f24cb6200a (diff) | |
parent | e5e3f866484709f47c97151e99a302206df1d894 (diff) |
Merge pull request #29935 from Faless/net/get_if_multicast_pr
Multicast, more network interfaces info
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/unix/ip_unix.cpp | 78 | ||||
-rw-r--r-- | drivers/unix/ip_unix.h | 2 | ||||
-rw-r--r-- | drivers/unix/net_socket_posix.cpp | 68 | ||||
-rw-r--r-- | drivers/unix/net_socket_posix.h | 3 |
4 files changed, 123 insertions, 28 deletions
diff --git a/drivers/unix/ip_unix.cpp b/drivers/unix/ip_unix.cpp index b5feaabc32..39ca9a823e 100644 --- a/drivers/unix/ip_unix.cpp +++ b/drivers/unix/ip_unix.cpp @@ -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); + + 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; @@ -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); diff --git a/drivers/unix/ip_unix.h b/drivers/unix/ip_unix.h index e36535146e..f9bb626cc4 100644 --- a/drivers/unix/ip_unix.h +++ b/drivers/unix/ip_unix.h @@ -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(); diff --git a/drivers/unix/net_socket_posix.cpp b/drivers/unix/net_socket_posix.cpp index fcd1c3be4b..4bde7789e2 100644 --- a/drivers/unix/net_socket_posix.cpp +++ b/drivers/unix/net_socket_posix.cpp @@ -59,6 +59,14 @@ #define MSG_NOSIGNAL SO_NOSIGPIPE #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 #define SOCK_EMPTY -1 #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; } +_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) { _sock = p_sock; _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); 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); +} diff --git a/drivers/unix/net_socket_posix.h b/drivers/unix/net_socket_posix.h index b7fb3fdc94..cf0412311d 100644 --- a/drivers/unix/net_socket_posix.h +++ b/drivers/unix/net_socket_posix.h @@ -60,6 +60,7 @@ private: NetError _get_socket_error(); 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: static NetSocket *_create_func(); @@ -93,6 +94,8 @@ public: virtual void set_tcp_no_delay_enabled(bool p_enabled); virtual void set_reuse_address_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(); |