LCOV - code coverage report
Current view: top level - media/mtransport - nrinterfaceprioritizer.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 136 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 20 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* This Source Code Form is subject to the terms of the Mozilla Public
       2             :  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
       3             :  * You can obtain one at http://mozilla.org/MPL/2.0/. */
       4             : #include <algorithm>
       5             : #include <map>
       6             : #include <set>
       7             : #include <string>
       8             : #include <vector>
       9             : #include "logging.h"
      10             : #include "nrinterfaceprioritizer.h"
      11             : #include "nsCOMPtr.h"
      12             : 
      13           0 : MOZ_MTLOG_MODULE("mtransport")
      14             : 
      15             : namespace {
      16             : 
      17           0 : class LocalAddress {
      18             : public:
      19           0 :   LocalAddress()
      20           0 :     : ifname_(),
      21             :       addr_(),
      22             :       key_(),
      23             :       is_vpn_(-1),
      24             :       estimated_speed_(-1),
      25             :       type_preference_(-1),
      26           0 :       ip_version_(-1) {}
      27             : 
      28           0 :   bool Init(const nr_local_addr& local_addr) {
      29           0 :     ifname_ = local_addr.addr.ifname;
      30             : 
      31             :     char buf[MAXIFNAME + 41];
      32           0 :     int r = nr_transport_addr_fmt_ifname_addr_string(&local_addr.addr, buf, sizeof(buf));
      33           0 :     if (r) {
      34           0 :       MOZ_MTLOG(ML_ERROR, "Error formatting interface key.");
      35           0 :       return false;
      36             :     }
      37           0 :     key_ = buf;
      38             : 
      39           0 :     r = nr_transport_addr_get_addrstring(&local_addr.addr, buf, sizeof(buf));
      40           0 :     if (r) {
      41           0 :       MOZ_MTLOG(ML_ERROR, "Error formatting address string.");
      42           0 :       return false;
      43             :     }
      44           0 :     addr_ = buf;
      45             : 
      46           0 :     is_vpn_ = (local_addr.interface.type & NR_INTERFACE_TYPE_VPN) != 0 ? 1 : 0;
      47           0 :     estimated_speed_ = local_addr.interface.estimated_speed;
      48           0 :     type_preference_ = GetNetworkTypePreference(local_addr.interface.type);
      49           0 :     ip_version_ = local_addr.addr.ip_version;
      50           0 :     return true;
      51             :   }
      52             : 
      53           0 :   bool operator<(const LocalAddress& rhs) const {
      54             :     // Interface that is "less" here is preferred.
      55             :     // If type preferences are different, we should simply sort by
      56             :     // |type_preference_|.
      57           0 :     if (type_preference_ != rhs.type_preference_) {
      58           0 :       return type_preference_ < rhs.type_preference_;
      59             :     }
      60             : 
      61             :     // If type preferences are the same, the next thing we use to sort is vpn.
      62             :     // If two LocalAddress are different in |is_vpn_|, the LocalAddress that is
      63             :     // not in vpn gets priority.
      64           0 :     if (is_vpn_ != rhs.is_vpn_) {
      65           0 :       return is_vpn_ < rhs.is_vpn_;
      66             :     }
      67             : 
      68             :     // Compare estimated speed.
      69           0 :     if (estimated_speed_ != rhs.estimated_speed_) {
      70           0 :       return estimated_speed_ > rhs.estimated_speed_;
      71             :     }
      72             : 
      73             :     // See if our hard-coded pref list helps us.
      74           0 :     auto thisindex = std::find(interface_preference_list().begin(),
      75           0 :                                interface_preference_list().end(),
      76           0 :                                ifname_);
      77           0 :     auto rhsindex = std::find(interface_preference_list().begin(),
      78           0 :                               interface_preference_list().end(),
      79           0 :                               rhs.ifname_);
      80           0 :     if (thisindex != rhsindex) {
      81           0 :       return thisindex < rhsindex;
      82             :     }
      83             : 
      84             :     // Prefer IPV6 over IPV4
      85           0 :     if (ip_version_ != rhs.ip_version_) {
      86           0 :       return ip_version_ > rhs.ip_version_;
      87             :     }
      88             : 
      89             :     // Now we start getting into arbitrary stuff
      90           0 :     if (ifname_ != rhs.ifname_) {
      91           0 :       return ifname_ < rhs.ifname_;
      92             :     }
      93             : 
      94           0 :     return addr_ < rhs.addr_;
      95             :   }
      96             : 
      97           0 :   const std::string& GetKey() const {
      98           0 :     return key_;
      99             :   }
     100             : 
     101             : private:
     102             :   // Getting the preference corresponding to a type. Getting lower number here
     103             :   // means the type of network is preferred.
     104           0 :   static inline int GetNetworkTypePreference(int type) {
     105           0 :     if (type & NR_INTERFACE_TYPE_WIRED) {
     106           0 :       return 1;
     107             :     }
     108           0 :     if (type & NR_INTERFACE_TYPE_WIFI) {
     109           0 :       return 2;
     110             :     }
     111           0 :     if (type & NR_INTERFACE_TYPE_MOBILE) {
     112           0 :       return 3;
     113             :     }
     114           0 :     return 4;
     115             :   }
     116             : 
     117             :   // TODO(bug 895790): Once we can get useful interface properties on Darwin,
     118             :   // we should remove this stuff.
     119           0 :   static const std::vector<std::string>& interface_preference_list()
     120             :   {
     121           0 :     static std::vector<std::string> list(build_interface_preference_list());
     122           0 :     return list;
     123             :   }
     124             : 
     125           0 :   static std::vector<std::string> build_interface_preference_list()
     126             :   {
     127           0 :     std::vector<std::string> result;
     128           0 :     result.push_back("rl0");
     129           0 :     result.push_back("wi0");
     130           0 :     result.push_back("en0");
     131           0 :     result.push_back("enp2s0");
     132           0 :     result.push_back("enp3s0");
     133           0 :     result.push_back("en1");
     134           0 :     result.push_back("en2");
     135           0 :     result.push_back("en3");
     136           0 :     result.push_back("eth0");
     137           0 :     result.push_back("eth1");
     138           0 :     result.push_back("eth2");
     139           0 :     result.push_back("em1");
     140           0 :     result.push_back("em0");
     141           0 :     result.push_back("ppp");
     142           0 :     result.push_back("ppp0");
     143           0 :     result.push_back("vmnet1");
     144           0 :     result.push_back("vmnet0");
     145           0 :     result.push_back("vmnet3");
     146           0 :     result.push_back("vmnet4");
     147           0 :     result.push_back("vmnet5");
     148           0 :     result.push_back("vmnet6");
     149           0 :     result.push_back("vmnet7");
     150           0 :     result.push_back("vmnet8");
     151           0 :     result.push_back("virbr0");
     152           0 :     result.push_back("wlan0");
     153           0 :     result.push_back("lo0");
     154           0 :     return result;
     155             :   }
     156             : 
     157             :   std::string ifname_;
     158             :   std::string addr_;
     159             :   std::string key_;
     160             :   int is_vpn_;
     161             :   int estimated_speed_;
     162             :   int type_preference_;
     163             :   int ip_version_;
     164             : };
     165             : 
     166           0 : class InterfacePrioritizer {
     167             : public:
     168           0 :   InterfacePrioritizer()
     169           0 :     : local_addrs_(),
     170             :       preference_map_(),
     171           0 :       sorted_(false) {}
     172             : 
     173           0 :   int add(const nr_local_addr *iface) {
     174           0 :     LocalAddress addr;
     175           0 :     if (!addr.Init(*iface)) {
     176           0 :       return R_FAILED;
     177             :     }
     178             :     std::pair<std::set<LocalAddress>::iterator, bool> r =
     179           0 :       local_addrs_.insert(addr);
     180           0 :     if (!r.second) {
     181           0 :       return R_ALREADY; // This address is already in the set.
     182             :     }
     183           0 :     sorted_ = false;
     184           0 :     return 0;
     185             :   }
     186             : 
     187           0 :   int sort() {
     188           0 :     UCHAR tmp_pref = 127;
     189           0 :     preference_map_.clear();
     190           0 :     for (const auto& local_addr : local_addrs_) {
     191           0 :       if (tmp_pref == 0) {
     192           0 :         return R_FAILED;
     193             :       }
     194           0 :       preference_map_.insert(make_pair(local_addr.GetKey(), tmp_pref--));
     195             :     }
     196           0 :     sorted_ = true;
     197           0 :     return 0;
     198             :   }
     199             : 
     200           0 :   int getPreference(const char *key, UCHAR *pref) {
     201           0 :     if (!sorted_) {
     202           0 :       return R_FAILED;
     203             :     }
     204           0 :     std::map<std::string, UCHAR>::iterator i = preference_map_.find(key);
     205           0 :     if (i == preference_map_.end()) {
     206           0 :       return R_NOT_FOUND;
     207             :     }
     208           0 :     *pref = i->second;
     209           0 :     return 0;
     210             :   }
     211             : 
     212             : private:
     213             :   std::set<LocalAddress> local_addrs_;
     214             :   std::map<std::string, UCHAR> preference_map_;
     215             :   bool sorted_;
     216             : };
     217             : 
     218             : } // anonymous namespace
     219             : 
     220           0 : static int add_interface(void *obj, nr_local_addr *iface) {
     221           0 :   InterfacePrioritizer *ip = static_cast<InterfacePrioritizer*>(obj);
     222           0 :   return ip->add(iface);
     223             : }
     224             : 
     225           0 : static int get_priority(void *obj, const char *key, UCHAR *pref) {
     226           0 :   InterfacePrioritizer *ip = static_cast<InterfacePrioritizer*>(obj);
     227           0 :   return ip->getPreference(key, pref);
     228             : }
     229             : 
     230           0 : static int sort_preference(void *obj) {
     231           0 :   InterfacePrioritizer *ip = static_cast<InterfacePrioritizer*>(obj);
     232           0 :   return ip->sort();
     233             : }
     234             : 
     235           0 : static int destroy(void **objp) {
     236           0 :   if (!objp || !*objp) {
     237           0 :     return 0;
     238             :   }
     239             : 
     240           0 :   InterfacePrioritizer *ip = static_cast<InterfacePrioritizer*>(*objp);
     241           0 :   *objp = nullptr;
     242           0 :   delete ip;
     243             : 
     244           0 :   return 0;
     245             : }
     246             : 
     247             : static nr_interface_prioritizer_vtbl priorizer_vtbl = {
     248             :   add_interface,
     249             :   get_priority,
     250             :   sort_preference,
     251             :   destroy
     252             : };
     253             : 
     254             : namespace mozilla {
     255             : 
     256           0 : nr_interface_prioritizer* CreateInterfacePrioritizer() {
     257             :   nr_interface_prioritizer *ip;
     258           0 :   int r = nr_interface_prioritizer_create_int(new InterfacePrioritizer(),
     259             :                                               &priorizer_vtbl,
     260           0 :                                               &ip);
     261           0 :   if (r != 0) {
     262           0 :     return nullptr;
     263             :   }
     264           0 :   return ip;
     265             : }
     266             : 
     267             : } // namespace mozilla

Generated by: LCOV version 1.13