1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/media/mtransport/nrinterfaceprioritizer.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,189 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this file, 1.6 + * You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 +#include <map> 1.8 +#include <set> 1.9 +#include <string> 1.10 +#include "logging.h" 1.11 +#include "nrinterfaceprioritizer.h" 1.12 +#include "nsCOMPtr.h" 1.13 + 1.14 +MOZ_MTLOG_MODULE("mtransport") 1.15 + 1.16 +namespace { 1.17 + 1.18 +class LocalAddress { 1.19 +public: 1.20 + LocalAddress() 1.21 + : key_(), 1.22 + is_vpn_(-1), 1.23 + estimated_speed_(-1), 1.24 + type_preference_(-1) {} 1.25 + 1.26 + bool Init(const nr_local_addr& local_addr) { 1.27 + char buf[MAXIFNAME + 41]; 1.28 + int r = nr_transport_addr_fmt_ifname_addr_string(&local_addr.addr, buf, sizeof(buf)); 1.29 + if (r) { 1.30 + MOZ_MTLOG(PR_LOG_ERROR, "Error formatting interface address string."); 1.31 + return false; 1.32 + } 1.33 + key_ = buf; 1.34 + is_vpn_ = (local_addr.interface.type & NR_INTERFACE_TYPE_VPN) != 0 ? 1 : 0; 1.35 + estimated_speed_ = local_addr.interface.estimated_speed; 1.36 + type_preference_ = GetNetworkTypePreference(local_addr.interface.type); 1.37 + return true; 1.38 + } 1.39 + 1.40 + bool operator<(const LocalAddress& rhs) const { 1.41 + // Interface that is "less" here is preferred. 1.42 + // If type preferences are different, we should simply sort by 1.43 + // |type_preference_|. 1.44 + if (type_preference_ != rhs.type_preference_) { 1.45 + return type_preference_ < rhs.type_preference_; 1.46 + } 1.47 + 1.48 + // If type preferences are the same, the next thing we use to sort is vpn. 1.49 + // If two LocalAddress are different in |is_vpn_|, the LocalAddress that is 1.50 + // not in vpn gets priority. 1.51 + if (is_vpn_ != rhs.is_vpn_) { 1.52 + return is_vpn_ < rhs.is_vpn_; 1.53 + } 1.54 + 1.55 + // Compare estimated speed. 1.56 + if (estimated_speed_ != rhs.estimated_speed_) { 1.57 + return estimated_speed_ > rhs.estimated_speed_; 1.58 + } 1.59 + 1.60 + // All things above are the same, we can at least sort with key. 1.61 + return key_ < rhs.key_; 1.62 + } 1.63 + 1.64 + const std::string& GetKey() const { 1.65 + return key_; 1.66 + } 1.67 + 1.68 +private: 1.69 + // Getting the preference corresponding to a type. Getting lower number here 1.70 + // means the type of network is preferred. 1.71 + static inline int GetNetworkTypePreference(int type) { 1.72 + if (type & NR_INTERFACE_TYPE_WIRED) { 1.73 + return 1; 1.74 + } 1.75 + if (type & NR_INTERFACE_TYPE_WIFI) { 1.76 + return 2; 1.77 + } 1.78 + if (type & NR_INTERFACE_TYPE_MOBILE) { 1.79 + return 3; 1.80 + } 1.81 + return 4; 1.82 + } 1.83 + 1.84 + std::string key_; 1.85 + int is_vpn_; 1.86 + int estimated_speed_; 1.87 + int type_preference_; 1.88 +}; 1.89 + 1.90 +class InterfacePrioritizer { 1.91 +public: 1.92 + InterfacePrioritizer() 1.93 + : local_addrs_(), 1.94 + preference_map_(), 1.95 + sorted_(false) {} 1.96 + 1.97 + int add(const nr_local_addr *iface) { 1.98 + LocalAddress addr; 1.99 + if (!addr.Init(*iface)) { 1.100 + return R_FAILED; 1.101 + } 1.102 + std::pair<std::set<LocalAddress>::iterator, bool> r = 1.103 + local_addrs_.insert(addr); 1.104 + if (!r.second) { 1.105 + return R_ALREADY; // This address is already in the set. 1.106 + } 1.107 + sorted_ = false; 1.108 + return 0; 1.109 + } 1.110 + 1.111 + int sort() { 1.112 + UCHAR tmp_pref = 127; 1.113 + preference_map_.clear(); 1.114 + for (std::set<LocalAddress>::iterator i = local_addrs_.begin(); 1.115 + i != local_addrs_.end(); ++i) { 1.116 + if (tmp_pref == 0) { 1.117 + return R_FAILED; 1.118 + } 1.119 + preference_map_.insert(make_pair(i->GetKey(), tmp_pref--)); 1.120 + } 1.121 + sorted_ = true; 1.122 + return 0; 1.123 + } 1.124 + 1.125 + int getPreference(const char *key, UCHAR *pref) { 1.126 + if (!sorted_) { 1.127 + return R_FAILED; 1.128 + } 1.129 + std::map<std::string, UCHAR>::iterator i = preference_map_.find(key); 1.130 + if (i == preference_map_.end()) { 1.131 + return R_NOT_FOUND; 1.132 + } 1.133 + *pref = i->second; 1.134 + return 0; 1.135 + } 1.136 + 1.137 +private: 1.138 + std::set<LocalAddress> local_addrs_; 1.139 + std::map<std::string, UCHAR> preference_map_; 1.140 + bool sorted_; 1.141 +}; 1.142 + 1.143 +} // anonymous namespace 1.144 + 1.145 +static int add_interface(void *obj, nr_local_addr *iface) { 1.146 + InterfacePrioritizer *ip = static_cast<InterfacePrioritizer*>(obj); 1.147 + return ip->add(iface); 1.148 +} 1.149 + 1.150 +static int get_priority(void *obj, const char *key, UCHAR *pref) { 1.151 + InterfacePrioritizer *ip = static_cast<InterfacePrioritizer*>(obj); 1.152 + return ip->getPreference(key, pref); 1.153 +} 1.154 + 1.155 +static int sort_preference(void *obj) { 1.156 + InterfacePrioritizer *ip = static_cast<InterfacePrioritizer*>(obj); 1.157 + return ip->sort(); 1.158 +} 1.159 + 1.160 +static int destroy(void **objp) { 1.161 + if (!objp || !*objp) { 1.162 + return 0; 1.163 + } 1.164 + 1.165 + InterfacePrioritizer *ip = static_cast<InterfacePrioritizer*>(*objp); 1.166 + *objp = 0; 1.167 + delete ip; 1.168 + 1.169 + return 0; 1.170 +} 1.171 + 1.172 +static nr_interface_prioritizer_vtbl priorizer_vtbl = { 1.173 + add_interface, 1.174 + get_priority, 1.175 + sort_preference, 1.176 + destroy 1.177 +}; 1.178 + 1.179 +namespace mozilla { 1.180 + 1.181 +nr_interface_prioritizer* CreateInterfacePrioritizer() { 1.182 + nr_interface_prioritizer *ip; 1.183 + int r = nr_interface_prioritizer_create_int(new InterfacePrioritizer(), 1.184 + &priorizer_vtbl, 1.185 + &ip); 1.186 + if (r != 0) { 1.187 + return nullptr; 1.188 + } 1.189 + return ip; 1.190 +} 1.191 + 1.192 +} // namespace mozilla