From 6bf0a5cb5034a7e684dcc3500e841785237ce2dd Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 19:32:43 +0200 Subject: Adding upstream version 1:115.7.0. Signed-off-by: Daniel Baumann --- .../webrtc/transport/nrinterfaceprioritizer.cpp | 258 +++++++++++++++++++++ 1 file changed, 258 insertions(+) create mode 100644 dom/media/webrtc/transport/nrinterfaceprioritizer.cpp (limited to 'dom/media/webrtc/transport/nrinterfaceprioritizer.cpp') diff --git a/dom/media/webrtc/transport/nrinterfaceprioritizer.cpp b/dom/media/webrtc/transport/nrinterfaceprioritizer.cpp new file mode 100644 index 0000000000..f022f8c29a --- /dev/null +++ b/dom/media/webrtc/transport/nrinterfaceprioritizer.cpp @@ -0,0 +1,258 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include +#include +#include +#include +#include +#include "logging.h" +#include "nr_api.h" +#include "nrinterfaceprioritizer.h" + +MOZ_MTLOG_MODULE("mtransport") + +namespace { + +class LocalAddress { + public: + LocalAddress() + : ifname_(), + addr_(), + key_(), + is_vpn_(-1), + estimated_speed_(-1), + type_preference_(-1), + ip_version_(-1) {} + + bool Init(const nr_local_addr& local_addr) { + ifname_ = local_addr.addr.ifname; + + char buf[MAXIFNAME + 47]; + int r = nr_transport_addr_fmt_ifname_addr_string(&local_addr.addr, buf, + sizeof(buf)); + if (r) { + MOZ_MTLOG(ML_ERROR, "Error formatting interface key."); + return false; + } + key_ = buf; + + r = nr_transport_addr_get_addrstring(&local_addr.addr, buf, sizeof(buf)); + if (r) { + MOZ_MTLOG(ML_ERROR, "Error formatting address string."); + return false; + } + addr_ = buf; + + is_vpn_ = (local_addr.interface.type & NR_INTERFACE_TYPE_VPN) != 0 ? 1 : 0; + estimated_speed_ = local_addr.interface.estimated_speed; + type_preference_ = GetNetworkTypePreference(local_addr.interface.type); + ip_version_ = local_addr.addr.ip_version; + return true; + } + + bool operator<(const LocalAddress& rhs) const { + // Interface that is "less" here is preferred. + // If type preferences are different, we should simply sort by + // |type_preference_|. + if (type_preference_ != rhs.type_preference_) { + return type_preference_ < rhs.type_preference_; + } + + // If type preferences are the same, the next thing we use to sort is vpn. + // If two LocalAddress are different in |is_vpn_|, the LocalAddress that is + // not in vpn gets priority. + if (is_vpn_ != rhs.is_vpn_) { + return is_vpn_ < rhs.is_vpn_; + } + + // Compare estimated speed. + if (estimated_speed_ != rhs.estimated_speed_) { + return estimated_speed_ > rhs.estimated_speed_; + } + + // See if our hard-coded pref list helps us. + auto thisindex = std::find(interface_preference_list().begin(), + interface_preference_list().end(), ifname_); + auto rhsindex = std::find(interface_preference_list().begin(), + interface_preference_list().end(), rhs.ifname_); + if (thisindex != rhsindex) { + return thisindex < rhsindex; + } + + // Prefer IPV6 over IPV4 + if (ip_version_ != rhs.ip_version_) { + return ip_version_ > rhs.ip_version_; + } + + // Now we start getting into arbitrary stuff + if (ifname_ != rhs.ifname_) { + return ifname_ < rhs.ifname_; + } + + return addr_ < rhs.addr_; + } + + const std::string& GetKey() const { return key_; } + + private: + // Getting the preference corresponding to a type. Getting lower number here + // means the type of network is preferred. + static inline int GetNetworkTypePreference(int type) { + if (type & NR_INTERFACE_TYPE_WIRED) { + return 1; + } + if (type & NR_INTERFACE_TYPE_WIFI) { + return 2; + } + if (type & NR_INTERFACE_TYPE_MOBILE) { + return 3; + } + if (type & NR_INTERFACE_TYPE_TEREDO) { + // Teredo gets penalty because it's IP relayed + return 5; + } + return 4; + } + + // TODO(bug 895790): Once we can get useful interface properties on Darwin, + // we should remove this stuff. + static const std::vector& interface_preference_list() { + static std::vector list(build_interface_preference_list()); + return list; + } + + static std::vector build_interface_preference_list() { + std::vector result; + result.push_back("rl0"); + result.push_back("wi0"); + result.push_back("en0"); + result.push_back("enp2s0"); + result.push_back("enp3s0"); + result.push_back("en1"); + result.push_back("en2"); + result.push_back("en3"); + result.push_back("eth0"); + result.push_back("eth1"); + result.push_back("eth2"); + result.push_back("em1"); + result.push_back("em0"); + result.push_back("ppp"); + result.push_back("ppp0"); + result.push_back("vmnet1"); + result.push_back("vmnet0"); + result.push_back("vmnet3"); + result.push_back("vmnet4"); + result.push_back("vmnet5"); + result.push_back("vmnet6"); + result.push_back("vmnet7"); + result.push_back("vmnet8"); + result.push_back("virbr0"); + result.push_back("wlan0"); + result.push_back("lo0"); + return result; + } + + std::string ifname_; + std::string addr_; + std::string key_; + int is_vpn_; + int estimated_speed_; + int type_preference_; + int ip_version_; +}; + +class InterfacePrioritizer { + public: + InterfacePrioritizer() : local_addrs_(), preference_map_(), sorted_(false) {} + + int add(const nr_local_addr* iface) { + LocalAddress addr; + if (!addr.Init(*iface)) { + return R_FAILED; + } + std::pair::iterator, bool> r = + local_addrs_.insert(addr); + if (!r.second) { + return R_ALREADY; // This address is already in the set. + } + sorted_ = false; + return 0; + } + + int sort() { + UCHAR tmp_pref = 127; + preference_map_.clear(); + for (const auto& local_addr : local_addrs_) { + if (tmp_pref == 0) { + return R_FAILED; + } + preference_map_.insert(make_pair(local_addr.GetKey(), tmp_pref--)); + } + sorted_ = true; + return 0; + } + + int getPreference(const char* key, UCHAR* pref) { + if (!sorted_) { + return R_FAILED; + } + std::map::iterator i = preference_map_.find(key); + if (i == preference_map_.end()) { + return R_NOT_FOUND; + } + *pref = i->second; + return 0; + } + + private: + std::set local_addrs_; + std::map preference_map_; + bool sorted_; +}; + +} // anonymous namespace + +static int add_interface(void* obj, nr_local_addr* iface) { + InterfacePrioritizer* ip = static_cast(obj); + return ip->add(iface); +} + +static int get_priority(void* obj, const char* key, UCHAR* pref) { + InterfacePrioritizer* ip = static_cast(obj); + return ip->getPreference(key, pref); +} + +static int sort_preference(void* obj) { + InterfacePrioritizer* ip = static_cast(obj); + return ip->sort(); +} + +static int destroy(void** objp) { + if (!objp || !*objp) { + return 0; + } + + InterfacePrioritizer* ip = static_cast(*objp); + *objp = nullptr; + delete ip; + + return 0; +} + +static nr_interface_prioritizer_vtbl priorizer_vtbl = { + add_interface, get_priority, sort_preference, destroy}; + +namespace mozilla { + +nr_interface_prioritizer* CreateInterfacePrioritizer() { + nr_interface_prioritizer* ip; + int r = nr_interface_prioritizer_create_int(new InterfacePrioritizer(), + &priorizer_vtbl, &ip); + if (r != 0) { + return nullptr; + } + return ip; +} + +} // namespace mozilla -- cgit v1.2.3