blob: 8c84c2e370d3616f247134f7ad65d5ec5bd81af5 [file] [log] [blame]
henrike@webrtc.orgf0488722014-05-13 18:00:26 +00001/*
2 * Copyright 2004 The WebRTC Project Authors. All rights reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11#ifdef HAVE_CONFIG_H
12#include "config.h"
13#endif
14
15#include "webrtc/base/network.h"
16
17#if defined(WEBRTC_POSIX)
18// linux/if.h can't be included at the same time as the posix sys/if.h, and
19// it's transitively required by linux/route.h, so include that version on
20// linux instead of the standard posix one.
21#if defined(WEBRTC_LINUX)
22#include <linux/if.h>
23#include <linux/route.h>
24#elif !defined(__native_client__)
25#include <net/if.h>
26#endif
27#include <sys/socket.h>
28#include <sys/utsname.h>
29#include <sys/ioctl.h>
30#include <unistd.h>
31#include <errno.h>
32
33#if defined(WEBRTC_ANDROID)
34#include "webrtc/base/ifaddrs-android.h"
35#elif !defined(__native_client__)
36#include <ifaddrs.h>
37#endif
38
39#endif // WEBRTC_POSIX
40
41#if defined(WEBRTC_WIN)
42#include "webrtc/base/win32.h"
43#include <Iphlpapi.h>
44#endif
45
46#include <stdio.h>
47
48#include <algorithm>
49
50#include "webrtc/base/logging.h"
51#include "webrtc/base/scoped_ptr.h"
52#include "webrtc/base/socket.h" // includes something that makes windows happy
53#include "webrtc/base/stream.h"
54#include "webrtc/base/stringencode.h"
55#include "webrtc/base/thread.h"
56
57namespace rtc {
58namespace {
59
60const uint32 kUpdateNetworksMessage = 1;
61const uint32 kSignalNetworksMessage = 2;
62
63// Fetch list of networks every two seconds.
64const int kNetworksUpdateIntervalMs = 2000;
65
66const int kHighestNetworkPreference = 127;
67
guoweis@webrtc.org4bbd3c82014-09-09 13:54:45 +000068typedef struct {
69 Network* net;
guoweis@webrtc.orgfa603982014-09-09 23:42:40 +000070 std::vector<InterfaceAddress> ips;
guoweis@webrtc.org4bbd3c82014-09-09 13:54:45 +000071} AddressList;
72
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000073bool CompareNetworks(const Network* a, const Network* b) {
74 if (a->prefix_length() == b->prefix_length()) {
75 if (a->name() == b->name()) {
76 return a->prefix() < b->prefix();
77 }
78 }
79 return a->name() < b->name();
80}
81
82bool SortNetworks(const Network* a, const Network* b) {
83 // Network types will be preferred above everything else while sorting
84 // Networks.
85
86 // Networks are sorted first by type.
87 if (a->type() != b->type()) {
88 return a->type() < b->type();
89 }
90
91 // After type, networks are sorted by IP address precedence values
92 // from RFC 3484-bis
93 if (IPAddressPrecedence(a->ip()) != IPAddressPrecedence(b->ip())) {
94 return IPAddressPrecedence(a->ip()) > IPAddressPrecedence(b->ip());
95 }
96
97 // TODO(mallinath) - Add VPN and Link speed conditions while sorting.
98
99 // Networks are sorted last by key.
100 return a->key() > b->key();
101}
102
103std::string AdapterTypeToString(AdapterType type) {
104 switch (type) {
105 case ADAPTER_TYPE_UNKNOWN:
106 return "Unknown";
107 case ADAPTER_TYPE_ETHERNET:
108 return "Ethernet";
109 case ADAPTER_TYPE_WIFI:
110 return "Wifi";
111 case ADAPTER_TYPE_CELLULAR:
112 return "Cellular";
113 case ADAPTER_TYPE_VPN:
114 return "VPN";
115 default:
116 ASSERT(false);
117 return std::string();
118 }
119}
120
121} // namespace
122
123std::string MakeNetworkKey(const std::string& name, const IPAddress& prefix,
124 int prefix_length) {
125 std::ostringstream ost;
126 ost << name << "%" << prefix.ToString() << "/" << prefix_length;
127 return ost.str();
128}
129
130NetworkManager::NetworkManager() {
131}
132
133NetworkManager::~NetworkManager() {
134}
135
136NetworkManagerBase::NetworkManagerBase() : ipv6_enabled_(true) {
137}
138
139NetworkManagerBase::~NetworkManagerBase() {
140 for (NetworkMap::iterator i = networks_map_.begin();
141 i != networks_map_.end(); ++i) {
142 delete i->second;
143 }
144}
145
146void NetworkManagerBase::GetNetworks(NetworkList* result) const {
147 *result = networks_;
148}
149
150void NetworkManagerBase::MergeNetworkList(const NetworkList& new_networks,
151 bool* changed) {
guoweis@webrtc.org4bbd3c82014-09-09 13:54:45 +0000152 // AddressList in this map will track IP addresses for all Networks
153 // with the same key.
154 std::map<std::string, AddressList> consolidated_address_list;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000155 NetworkList list(new_networks);
guoweis@webrtc.org4bbd3c82014-09-09 13:54:45 +0000156
157 // Result of Network merge. Element in this list should have unique key.
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000158 NetworkList merged_list;
159 std::sort(list.begin(), list.end(), CompareNetworks);
160
161 *changed = false;
162
163 if (networks_.size() != list.size())
164 *changed = true;
165
166 // First, build a set of network-keys to the ipaddresses.
167 for (uint32 i = 0; i < list.size(); ++i) {
168 bool might_add_to_merged_list = false;
169 std::string key = MakeNetworkKey(list[i]->name(),
170 list[i]->prefix(),
171 list[i]->prefix_length());
guoweis@webrtc.org4bbd3c82014-09-09 13:54:45 +0000172 if (consolidated_address_list.find(key) ==
173 consolidated_address_list.end()) {
174 AddressList addrlist;
175 addrlist.net = list[i];
176 consolidated_address_list[key] = addrlist;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000177 might_add_to_merged_list = true;
178 }
guoweis@webrtc.orgfa603982014-09-09 23:42:40 +0000179 const std::vector<InterfaceAddress>& addresses = list[i]->GetIPs();
guoweis@webrtc.org4bbd3c82014-09-09 13:54:45 +0000180 AddressList& current_list = consolidated_address_list[key];
guoweis@webrtc.orgfa603982014-09-09 23:42:40 +0000181 for (std::vector<InterfaceAddress>::const_iterator it = addresses.begin();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000182 it != addresses.end();
183 ++it) {
guoweis@webrtc.org4bbd3c82014-09-09 13:54:45 +0000184 current_list.ips.push_back(*it);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000185 }
186 if (!might_add_to_merged_list) {
187 delete list[i];
188 }
189 }
190
191 // Next, look for existing network objects to re-use.
guoweis@webrtc.org4bbd3c82014-09-09 13:54:45 +0000192 for (std::map<std::string, AddressList>::iterator it =
193 consolidated_address_list.begin();
194 it != consolidated_address_list.end();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000195 ++it) {
196 const std::string& key = it->first;
guoweis@webrtc.org4bbd3c82014-09-09 13:54:45 +0000197 Network* net = it->second.net;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000198 NetworkMap::iterator existing = networks_map_.find(key);
199 if (existing == networks_map_.end()) {
200 // This network is new. Place it in the network map.
201 merged_list.push_back(net);
202 networks_map_[key] = net;
guoweis@webrtc.org4bbd3c82014-09-09 13:54:45 +0000203 // Also, we might have accumulated IPAddresses from the first
204 // step, set it here.
205 net->SetIPs(it->second.ips, true);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000206 *changed = true;
207 } else {
208 // This network exists in the map already. Reset its IP addresses.
guoweis@webrtc.org4bbd3c82014-09-09 13:54:45 +0000209 *changed = existing->second->SetIPs(it->second.ips, *changed);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000210 merged_list.push_back(existing->second);
211 if (existing->second != net) {
212 delete net;
213 }
214 }
215 }
216 networks_ = merged_list;
217
218 // If the network lists changes, we resort it.
219 if (changed) {
220 std::sort(networks_.begin(), networks_.end(), SortNetworks);
221 // Now network interfaces are sorted, we should set the preference value
222 // for each of the interfaces we are planning to use.
223 // Preference order of network interfaces might have changed from previous
224 // sorting due to addition of higher preference network interface.
225 // Since we have already sorted the network interfaces based on our
226 // requirements, we will just assign a preference value starting with 127,
227 // in decreasing order.
228 int pref = kHighestNetworkPreference;
229 for (NetworkList::const_iterator iter = networks_.begin();
230 iter != networks_.end(); ++iter) {
231 (*iter)->set_preference(pref);
232 if (pref > 0) {
233 --pref;
234 } else {
235 LOG(LS_ERROR) << "Too many network interfaces to handle!";
236 break;
237 }
238 }
239 }
240}
241
242BasicNetworkManager::BasicNetworkManager()
243 : thread_(NULL), sent_first_update_(false), start_count_(0),
244 ignore_non_default_routes_(false) {
245}
246
247BasicNetworkManager::~BasicNetworkManager() {
248}
249
250#if defined(__native_client__)
251
252bool BasicNetworkManager::CreateNetworks(bool include_ignored,
253 NetworkList* networks) const {
254 ASSERT(false);
255 LOG(LS_WARNING) << "BasicNetworkManager doesn't work on NaCl yet";
256 return false;
257}
258
259#elif defined(WEBRTC_POSIX)
260void BasicNetworkManager::ConvertIfAddrs(struct ifaddrs* interfaces,
261 bool include_ignored,
262 NetworkList* networks) const {
263 NetworkMap current_networks;
264 for (struct ifaddrs* cursor = interfaces;
265 cursor != NULL; cursor = cursor->ifa_next) {
266 IPAddress prefix;
267 IPAddress mask;
268 IPAddress ip;
269 int scope_id = 0;
270
271 // Some interfaces may not have address assigned.
272 if (!cursor->ifa_addr || !cursor->ifa_netmask)
273 continue;
274
275 switch (cursor->ifa_addr->sa_family) {
276 case AF_INET: {
277 ip = IPAddress(
278 reinterpret_cast<sockaddr_in*>(cursor->ifa_addr)->sin_addr);
279 mask = IPAddress(
280 reinterpret_cast<sockaddr_in*>(cursor->ifa_netmask)->sin_addr);
281 break;
282 }
283 case AF_INET6: {
284 if (ipv6_enabled()) {
285 ip = IPAddress(
286 reinterpret_cast<sockaddr_in6*>(cursor->ifa_addr)->sin6_addr);
287 mask = IPAddress(
288 reinterpret_cast<sockaddr_in6*>(cursor->ifa_netmask)->sin6_addr);
289 scope_id =
290 reinterpret_cast<sockaddr_in6*>(cursor->ifa_addr)->sin6_scope_id;
291 break;
292 } else {
293 continue;
294 }
295 }
296 default: {
297 continue;
298 }
299 }
300
301 int prefix_length = CountIPMaskBits(mask);
302 prefix = TruncateIP(ip, prefix_length);
303 std::string key = MakeNetworkKey(std::string(cursor->ifa_name),
304 prefix, prefix_length);
305 NetworkMap::iterator existing_network = current_networks.find(key);
306 if (existing_network == current_networks.end()) {
307 scoped_ptr<Network> network(new Network(cursor->ifa_name,
308 cursor->ifa_name,
309 prefix,
310 prefix_length));
311 network->set_scope_id(scope_id);
312 network->AddIP(ip);
313 bool ignored = ((cursor->ifa_flags & IFF_LOOPBACK) ||
314 IsIgnoredNetwork(*network));
315 network->set_ignored(ignored);
316 if (include_ignored || !network->ignored()) {
317 networks->push_back(network.release());
318 }
319 } else {
320 (*existing_network).second->AddIP(ip);
321 }
322 }
323}
324
325bool BasicNetworkManager::CreateNetworks(bool include_ignored,
326 NetworkList* networks) const {
327 struct ifaddrs* interfaces;
328 int error = getifaddrs(&interfaces);
329 if (error != 0) {
330 LOG_ERR(LERROR) << "getifaddrs failed to gather interface data: " << error;
331 return false;
332 }
333
334 ConvertIfAddrs(interfaces, include_ignored, networks);
335
336 freeifaddrs(interfaces);
337 return true;
338}
339
340#elif defined(WEBRTC_WIN)
341
342unsigned int GetPrefix(PIP_ADAPTER_PREFIX prefixlist,
343 const IPAddress& ip, IPAddress* prefix) {
344 IPAddress current_prefix;
345 IPAddress best_prefix;
346 unsigned int best_length = 0;
347 while (prefixlist) {
348 // Look for the longest matching prefix in the prefixlist.
349 if (prefixlist->Address.lpSockaddr == NULL ||
350 prefixlist->Address.lpSockaddr->sa_family != ip.family()) {
351 prefixlist = prefixlist->Next;
352 continue;
353 }
354 switch (prefixlist->Address.lpSockaddr->sa_family) {
355 case AF_INET: {
356 sockaddr_in* v4_addr =
357 reinterpret_cast<sockaddr_in*>(prefixlist->Address.lpSockaddr);
358 current_prefix = IPAddress(v4_addr->sin_addr);
359 break;
360 }
361 case AF_INET6: {
362 sockaddr_in6* v6_addr =
363 reinterpret_cast<sockaddr_in6*>(prefixlist->Address.lpSockaddr);
364 current_prefix = IPAddress(v6_addr->sin6_addr);
365 break;
366 }
367 default: {
368 prefixlist = prefixlist->Next;
369 continue;
370 }
371 }
372 if (TruncateIP(ip, prefixlist->PrefixLength) == current_prefix &&
373 prefixlist->PrefixLength > best_length) {
374 best_prefix = current_prefix;
375 best_length = prefixlist->PrefixLength;
376 }
377 prefixlist = prefixlist->Next;
378 }
379 *prefix = best_prefix;
380 return best_length;
381}
382
383bool BasicNetworkManager::CreateNetworks(bool include_ignored,
384 NetworkList* networks) const {
385 NetworkMap current_networks;
386 // MSDN recommends a 15KB buffer for the first try at GetAdaptersAddresses.
387 size_t buffer_size = 16384;
388 scoped_ptr<char[]> adapter_info(new char[buffer_size]);
389 PIP_ADAPTER_ADDRESSES adapter_addrs =
390 reinterpret_cast<PIP_ADAPTER_ADDRESSES>(adapter_info.get());
391 int adapter_flags = (GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_ANYCAST |
392 GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_INCLUDE_PREFIX);
393 int ret = 0;
394 do {
395 adapter_info.reset(new char[buffer_size]);
396 adapter_addrs = reinterpret_cast<PIP_ADAPTER_ADDRESSES>(adapter_info.get());
397 ret = GetAdaptersAddresses(AF_UNSPEC, adapter_flags,
398 0, adapter_addrs,
399 reinterpret_cast<PULONG>(&buffer_size));
400 } while (ret == ERROR_BUFFER_OVERFLOW);
401 if (ret != ERROR_SUCCESS) {
402 return false;
403 }
404 int count = 0;
405 while (adapter_addrs) {
406 if (adapter_addrs->OperStatus == IfOperStatusUp) {
407 PIP_ADAPTER_UNICAST_ADDRESS address = adapter_addrs->FirstUnicastAddress;
408 PIP_ADAPTER_PREFIX prefixlist = adapter_addrs->FirstPrefix;
409 std::string name;
410 std::string description;
411#ifdef _DEBUG
412 name = ToUtf8(adapter_addrs->FriendlyName,
413 wcslen(adapter_addrs->FriendlyName));
414#endif
415 description = ToUtf8(adapter_addrs->Description,
416 wcslen(adapter_addrs->Description));
417 for (; address; address = address->Next) {
418#ifndef _DEBUG
419 name = rtc::ToString(count);
420#endif
421
422 IPAddress ip;
423 int scope_id = 0;
424 scoped_ptr<Network> network;
425 switch (address->Address.lpSockaddr->sa_family) {
426 case AF_INET: {
427 sockaddr_in* v4_addr =
428 reinterpret_cast<sockaddr_in*>(address->Address.lpSockaddr);
429 ip = IPAddress(v4_addr->sin_addr);
430 break;
431 }
432 case AF_INET6: {
433 if (ipv6_enabled()) {
434 sockaddr_in6* v6_addr =
435 reinterpret_cast<sockaddr_in6*>(address->Address.lpSockaddr);
436 scope_id = v6_addr->sin6_scope_id;
437 ip = IPAddress(v6_addr->sin6_addr);
438 break;
439 } else {
440 continue;
441 }
442 }
443 default: {
444 continue;
445 }
446 }
447
448 IPAddress prefix;
449 int prefix_length = GetPrefix(prefixlist, ip, &prefix);
450 std::string key = MakeNetworkKey(name, prefix, prefix_length);
451 NetworkMap::iterator existing_network = current_networks.find(key);
452 if (existing_network == current_networks.end()) {
453 scoped_ptr<Network> network(new Network(name,
454 description,
455 prefix,
456 prefix_length));
457 network->set_scope_id(scope_id);
458 network->AddIP(ip);
459 bool ignore = ((adapter_addrs->IfType == IF_TYPE_SOFTWARE_LOOPBACK) ||
460 IsIgnoredNetwork(*network));
461 network->set_ignored(ignore);
462 if (include_ignored || !network->ignored()) {
463 networks->push_back(network.release());
464 }
465 } else {
466 (*existing_network).second->AddIP(ip);
467 }
468 }
469 // Count is per-adapter - all 'Networks' created from the same
470 // adapter need to have the same name.
471 ++count;
472 }
473 adapter_addrs = adapter_addrs->Next;
474 }
475 return true;
476}
477#endif // WEBRTC_WIN
478
479#if defined(WEBRTC_LINUX)
480bool IsDefaultRoute(const std::string& network_name) {
481 FileStream fs;
482 if (!fs.Open("/proc/net/route", "r", NULL)) {
483 LOG(LS_WARNING) << "Couldn't read /proc/net/route, skipping default "
484 << "route check (assuming everything is a default route).";
485 return true;
486 } else {
487 std::string line;
488 while (fs.ReadLine(&line) == SR_SUCCESS) {
489 char iface_name[256];
490 unsigned int iface_ip, iface_gw, iface_mask, iface_flags;
491 if (sscanf(line.c_str(),
492 "%255s %8X %8X %4X %*d %*u %*d %8X",
493 iface_name, &iface_ip, &iface_gw,
494 &iface_flags, &iface_mask) == 5 &&
495 network_name == iface_name &&
496 iface_mask == 0 &&
497 (iface_flags & (RTF_UP | RTF_HOST)) == RTF_UP) {
498 return true;
499 }
500 }
501 }
502 return false;
503}
504#endif
505
506bool BasicNetworkManager::IsIgnoredNetwork(const Network& network) const {
507 // Ignore networks on the explicit ignore list.
508 for (size_t i = 0; i < network_ignore_list_.size(); ++i) {
509 if (network.name() == network_ignore_list_[i]) {
510 return true;
511 }
512 }
513#if defined(WEBRTC_POSIX)
514 // Filter out VMware interfaces, typically named vmnet1 and vmnet8
515 if (strncmp(network.name().c_str(), "vmnet", 5) == 0 ||
516 strncmp(network.name().c_str(), "vnic", 4) == 0) {
517 return true;
518 }
519#if defined(WEBRTC_LINUX)
520 // Make sure this is a default route, if we're ignoring non-defaults.
521 if (ignore_non_default_routes_ && !IsDefaultRoute(network.name())) {
522 return true;
523 }
524#endif
525#elif defined(WEBRTC_WIN)
526 // Ignore any HOST side vmware adapters with a description like:
527 // VMware Virtual Ethernet Adapter for VMnet1
528 // but don't ignore any GUEST side adapters with a description like:
529 // VMware Accelerated AMD PCNet Adapter #2
530 if (strstr(network.description().c_str(), "VMnet") != NULL) {
531 return true;
532 }
533#endif
534
535 // Ignore any networks with a 0.x.y.z IP
536 if (network.prefix().family() == AF_INET) {
537 return (network.prefix().v4AddressAsHostOrderInteger() < 0x01000000);
538 }
539 return false;
540}
541
542void BasicNetworkManager::StartUpdating() {
543 thread_ = Thread::Current();
544 if (start_count_) {
545 // If network interfaces are already discovered and signal is sent,
546 // we should trigger network signal immediately for the new clients
547 // to start allocating ports.
548 if (sent_first_update_)
549 thread_->Post(this, kSignalNetworksMessage);
550 } else {
551 thread_->Post(this, kUpdateNetworksMessage);
552 }
553 ++start_count_;
554}
555
556void BasicNetworkManager::StopUpdating() {
557 ASSERT(Thread::Current() == thread_);
558 if (!start_count_)
559 return;
560
561 --start_count_;
562 if (!start_count_) {
563 thread_->Clear(this);
564 sent_first_update_ = false;
565 }
566}
567
568void BasicNetworkManager::OnMessage(Message* msg) {
569 switch (msg->message_id) {
570 case kUpdateNetworksMessage: {
571 DoUpdateNetworks();
572 break;
573 }
574 case kSignalNetworksMessage: {
575 SignalNetworksChanged();
576 break;
577 }
578 default:
579 ASSERT(false);
580 }
581}
582
583void BasicNetworkManager::DoUpdateNetworks() {
584 if (!start_count_)
585 return;
586
587 ASSERT(Thread::Current() == thread_);
588
589 NetworkList list;
590 if (!CreateNetworks(false, &list)) {
591 SignalError();
592 } else {
593 bool changed;
594 MergeNetworkList(list, &changed);
595 if (changed || !sent_first_update_) {
596 SignalNetworksChanged();
597 sent_first_update_ = true;
598 }
599 }
600
601 thread_->PostDelayed(kNetworksUpdateIntervalMs, this, kUpdateNetworksMessage);
602}
603
604void BasicNetworkManager::DumpNetworks(bool include_ignored) {
605 NetworkList list;
606 CreateNetworks(include_ignored, &list);
607 LOG(LS_INFO) << "NetworkManager detected " << list.size() << " networks:";
608 for (size_t i = 0; i < list.size(); ++i) {
609 const Network* network = list[i];
610 if (!network->ignored() || include_ignored) {
611 LOG(LS_INFO) << network->ToString() << ": "
612 << network->description()
613 << ((network->ignored()) ? ", Ignored" : "");
614 }
615 }
616 // Release the network list created previously.
617 // Do this in a seperated for loop for better readability.
618 for (size_t i = 0; i < list.size(); ++i) {
619 delete list[i];
620 }
621}
622
623Network::Network(const std::string& name, const std::string& desc,
624 const IPAddress& prefix, int prefix_length)
625 : name_(name), description_(desc), prefix_(prefix),
626 prefix_length_(prefix_length),
627 key_(MakeNetworkKey(name, prefix, prefix_length)), scope_id_(0),
628 ignored_(false), type_(ADAPTER_TYPE_UNKNOWN), preference_(0) {
629}
630
631Network::Network(const std::string& name, const std::string& desc,
632 const IPAddress& prefix, int prefix_length, AdapterType type)
633 : name_(name), description_(desc), prefix_(prefix),
634 prefix_length_(prefix_length),
635 key_(MakeNetworkKey(name, prefix, prefix_length)), scope_id_(0),
636 ignored_(false), type_(type), preference_(0) {
637}
638
639std::string Network::ToString() const {
640 std::stringstream ss;
641 // Print out the first space-terminated token of the network desc, plus
642 // the IP address.
643 ss << "Net[" << description_.substr(0, description_.find(' '))
644 << ":" << prefix_.ToSensitiveString() << "/" << prefix_length_
645 << ":" << AdapterTypeToString(type_) << "]";
646 return ss.str();
647}
648
649// Sets the addresses of this network. Returns true if the address set changed.
650// Change detection is short circuited if the changed argument is true.
guoweis@webrtc.orgfa603982014-09-09 23:42:40 +0000651bool Network::SetIPs(const std::vector<InterfaceAddress>& ips, bool changed) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000652 changed = changed || ips.size() != ips_.size();
653 // Detect changes with a nested loop; n-squared but we expect on the order
654 // of 2-3 addresses per network.
guoweis@webrtc.orgfa603982014-09-09 23:42:40 +0000655 for (std::vector<InterfaceAddress>::const_iterator it = ips.begin();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000656 !changed && it != ips.end();
657 ++it) {
658 bool found = false;
guoweis@webrtc.orgfa603982014-09-09 23:42:40 +0000659 for (std::vector<InterfaceAddress>::iterator inner_it = ips_.begin();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000660 !found && inner_it != ips_.end();
661 ++inner_it) {
662 if (*it == *inner_it) {
663 found = true;
664 }
665 }
666 changed = !found;
667 }
668 ips_ = ips;
669 return changed;
670}
671
guoweis@webrtc.orgfa603982014-09-09 23:42:40 +0000672// TODO(guoweis): will change the name to a more meaningful name as
673// this is not simply return the first address once the logic of ipv6
674// address selection is complete.
675IPAddress Network::ip() const {
676 if (ips_.size() == 0) {
677 return IPAddress();
678 }
679 return static_cast<IPAddress>(ips_.at(0));
680}
681
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000682} // namespace rtc