media/mtransport/nrinterfaceprioritizer.cpp

changeset 0
6474c204b198
     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

mercurial