Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/media/mtransport/nrinterfaceprioritizer.cpp
Line
Count
Source (jump to first uncovered line)
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
MOZ_MTLOG_MODULE("mtransport")
14
15
namespace {
16
17
class LocalAddress {
18
public:
19
  LocalAddress()
20
    : 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
0
31
0
    char buf[MAXIFNAME + 47];
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
0
    }
37
0
    key_ = buf;
38
0
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
0
    }
44
0
    addr_ = buf;
45
0
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
0
  }
52
53
0
  bool operator<(const LocalAddress& rhs) const {
54
0
    // Interface that is "less" here is preferred.
55
0
    // If type preferences are different, we should simply sort by
56
0
    // |type_preference_|.
57
0
    if (type_preference_ != rhs.type_preference_) {
58
0
      return type_preference_ < rhs.type_preference_;
59
0
    }
60
0
61
0
    // If type preferences are the same, the next thing we use to sort is vpn.
62
0
    // If two LocalAddress are different in |is_vpn_|, the LocalAddress that is
63
0
    // not in vpn gets priority.
64
0
    if (is_vpn_ != rhs.is_vpn_) {
65
0
      return is_vpn_ < rhs.is_vpn_;
66
0
    }
67
0
68
0
    // Compare estimated speed.
69
0
    if (estimated_speed_ != rhs.estimated_speed_) {
70
0
      return estimated_speed_ > rhs.estimated_speed_;
71
0
    }
72
0
73
0
    // 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
0
    }
83
0
84
0
    // Prefer IPV6 over IPV4
85
0
    if (ip_version_ != rhs.ip_version_) {
86
0
      return ip_version_ > rhs.ip_version_;
87
0
    }
88
0
89
0
    // Now we start getting into arbitrary stuff
90
0
    if (ifname_ != rhs.ifname_) {
91
0
      return ifname_ < rhs.ifname_;
92
0
    }
93
0
94
0
    return addr_ < rhs.addr_;
95
0
  }
96
97
0
  const std::string& GetKey() const {
98
0
    return key_;
99
0
  }
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
0
    }
108
0
    if (type & NR_INTERFACE_TYPE_WIFI) {
109
0
      return 2;
110
0
    }
111
0
    if (type & NR_INTERFACE_TYPE_MOBILE) {
112
0
      return 3;
113
0
    }
114
0
    if (type & NR_INTERFACE_TYPE_TEREDO) {
115
0
      // Teredo gets penalty because it's IP relayed
116
0
      return 5;
117
0
    }
118
0
    return 4;
119
0
  }
120
121
  // TODO(bug 895790): Once we can get useful interface properties on Darwin,
122
  // we should remove this stuff.
123
  static const std::vector<std::string>& interface_preference_list()
124
0
  {
125
0
    static std::vector<std::string> list(build_interface_preference_list());
126
0
    return list;
127
0
  }
128
129
  static std::vector<std::string> build_interface_preference_list()
130
0
  {
131
0
    std::vector<std::string> result;
132
0
    result.push_back("rl0");
133
0
    result.push_back("wi0");
134
0
    result.push_back("en0");
135
0
    result.push_back("enp2s0");
136
0
    result.push_back("enp3s0");
137
0
    result.push_back("en1");
138
0
    result.push_back("en2");
139
0
    result.push_back("en3");
140
0
    result.push_back("eth0");
141
0
    result.push_back("eth1");
142
0
    result.push_back("eth2");
143
0
    result.push_back("em1");
144
0
    result.push_back("em0");
145
0
    result.push_back("ppp");
146
0
    result.push_back("ppp0");
147
0
    result.push_back("vmnet1");
148
0
    result.push_back("vmnet0");
149
0
    result.push_back("vmnet3");
150
0
    result.push_back("vmnet4");
151
0
    result.push_back("vmnet5");
152
0
    result.push_back("vmnet6");
153
0
    result.push_back("vmnet7");
154
0
    result.push_back("vmnet8");
155
0
    result.push_back("virbr0");
156
0
    result.push_back("wlan0");
157
0
    result.push_back("lo0");
158
0
    return result;
159
0
  }
160
161
  std::string ifname_;
162
  std::string addr_;
163
  std::string key_;
164
  int is_vpn_;
165
  int estimated_speed_;
166
  int type_preference_;
167
  int ip_version_;
168
};
169
170
class InterfacePrioritizer {
171
public:
172
  InterfacePrioritizer()
173
    : local_addrs_(),
174
      preference_map_(),
175
0
      sorted_(false) {}
176
177
0
  int add(const nr_local_addr *iface) {
178
0
    LocalAddress addr;
179
0
    if (!addr.Init(*iface)) {
180
0
      return R_FAILED;
181
0
    }
182
0
    std::pair<std::set<LocalAddress>::iterator, bool> r =
183
0
      local_addrs_.insert(addr);
184
0
    if (!r.second) {
185
0
      return R_ALREADY; // This address is already in the set.
186
0
    }
187
0
    sorted_ = false;
188
0
    return 0;
189
0
  }
190
191
0
  int sort() {
192
0
    UCHAR tmp_pref = 127;
193
0
    preference_map_.clear();
194
0
    for (const auto& local_addr : local_addrs_) {
195
0
      if (tmp_pref == 0) {
196
0
        return R_FAILED;
197
0
      }
198
0
      preference_map_.insert(make_pair(local_addr.GetKey(), tmp_pref--));
199
0
    }
200
0
    sorted_ = true;
201
0
    return 0;
202
0
  }
203
204
0
  int getPreference(const char *key, UCHAR *pref) {
205
0
    if (!sorted_) {
206
0
      return R_FAILED;
207
0
    }
208
0
    std::map<std::string, UCHAR>::iterator i = preference_map_.find(key);
209
0
    if (i == preference_map_.end()) {
210
0
      return R_NOT_FOUND;
211
0
    }
212
0
    *pref = i->second;
213
0
    return 0;
214
0
  }
215
216
private:
217
  std::set<LocalAddress> local_addrs_;
218
  std::map<std::string, UCHAR> preference_map_;
219
  bool sorted_;
220
};
221
222
} // anonymous namespace
223
224
0
static int add_interface(void *obj, nr_local_addr *iface) {
225
0
  InterfacePrioritizer *ip = static_cast<InterfacePrioritizer*>(obj);
226
0
  return ip->add(iface);
227
0
}
228
229
0
static int get_priority(void *obj, const char *key, UCHAR *pref) {
230
0
  InterfacePrioritizer *ip = static_cast<InterfacePrioritizer*>(obj);
231
0
  return ip->getPreference(key, pref);
232
0
}
233
234
0
static int sort_preference(void *obj) {
235
0
  InterfacePrioritizer *ip = static_cast<InterfacePrioritizer*>(obj);
236
0
  return ip->sort();
237
0
}
238
239
0
static int destroy(void **objp) {
240
0
  if (!objp || !*objp) {
241
0
    return 0;
242
0
  }
243
0
244
0
  InterfacePrioritizer *ip = static_cast<InterfacePrioritizer*>(*objp);
245
0
  *objp = nullptr;
246
0
  delete ip;
247
0
248
0
  return 0;
249
0
}
250
251
static nr_interface_prioritizer_vtbl priorizer_vtbl = {
252
  add_interface,
253
  get_priority,
254
  sort_preference,
255
  destroy
256
};
257
258
namespace mozilla {
259
260
0
nr_interface_prioritizer* CreateInterfacePrioritizer() {
261
0
  nr_interface_prioritizer *ip;
262
0
  int r = nr_interface_prioritizer_create_int(new InterfacePrioritizer(),
263
0
                                              &priorizer_vtbl,
264
0
                                              &ip);
265
0
  if (r != 0) {
266
0
    return nullptr;
267
0
  }
268
0
  return ip;
269
0
}
270
271
} // namespace mozilla