blob: d6367c32b37f3f7574b6a9b1456e607a2d425563 [file] [log] [blame]
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001/*
2 * libjingle
3 * Copyright 2004--2005, Google Inc.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#ifdef HAVE_CONFIG_H
29#include "config.h"
30#endif
31
32#include "talk/base/network.h"
33
34#ifdef POSIX
35#include <sys/socket.h>
36#include <sys/utsname.h>
37#include <sys/ioctl.h>
38#include <net/if.h>
39#include <unistd.h>
40#include <errno.h>
41#ifdef ANDROID
42#include "talk/base/ifaddrs-android.h"
43#else
44#include <ifaddrs.h>
45#endif
46#endif // POSIX
47
48#ifdef WIN32
49#include "talk/base/win32.h"
50#include <Iphlpapi.h>
51#endif
52
53#include <algorithm>
54#include <cstdio>
55
henrike@webrtc.org28e20752013-07-10 00:45:36 +000056#include "talk/base/logging.h"
57#include "talk/base/scoped_ptr.h"
58#include "talk/base/socket.h" // includes something that makes windows happy
59#include "talk/base/stream.h"
60#include "talk/base/stringencode.h"
61#include "talk/base/thread.h"
62
63namespace talk_base {
64namespace {
65
66const uint32 kUpdateNetworksMessage = 1;
67const uint32 kSignalNetworksMessage = 2;
68
69// Fetch list of networks every two seconds.
70const int kNetworksUpdateIntervalMs = 2000;
71
72
73// Makes a string key for this network. Used in the network manager's maps.
74// Network objects are keyed on interface name, network prefix and the
75// length of that prefix.
76std::string MakeNetworkKey(const std::string& name, const IPAddress& prefix,
77 int prefix_length) {
78 std::ostringstream ost;
79 ost << name << "%" << prefix.ToString() << "/" << prefix_length;
80 return ost.str();
81}
82
83bool CompareNetworks(const Network* a, const Network* b) {
84 if (a->prefix_length() == b->prefix_length()) {
85 if (a->name() == b->name()) {
86 return a->prefix() < b->prefix();
87 }
88 }
89 return a->name() < b->name();
90}
91
92
93} // namespace
94
95NetworkManager::NetworkManager() {
96}
97
98NetworkManager::~NetworkManager() {
99}
100
101NetworkManagerBase::NetworkManagerBase() : ipv6_enabled_(true) {
102}
103
104NetworkManagerBase::~NetworkManagerBase() {
105 for (NetworkMap::iterator i = networks_map_.begin();
106 i != networks_map_.end(); ++i) {
107 delete i->second;
108 }
109}
110
111void NetworkManagerBase::GetNetworks(NetworkList* result) const {
112 *result = networks_;
113}
114
115void NetworkManagerBase::MergeNetworkList(const NetworkList& new_networks,
116 bool* changed) {
117 // Sort the list so that we can detect when it changes.
118 typedef std::pair<Network*, std::vector<IPAddress> > address_list;
119 std::map<std::string, address_list> address_map;
120 NetworkList list(new_networks);
121 NetworkList merged_list;
122 std::sort(list.begin(), list.end(), CompareNetworks);
123
124 *changed = false;
125
126 if (networks_.size() != list.size())
127 *changed = true;
128
129 // First, build a set of network-keys to the ipaddresses.
130 for (uint32 i = 0; i < list.size(); ++i) {
131 bool might_add_to_merged_list = false;
132 std::string key = MakeNetworkKey(list[i]->name(),
133 list[i]->prefix(),
134 list[i]->prefix_length());
135 if (address_map.find(key) == address_map.end()) {
136 address_map[key] = address_list(list[i], std::vector<IPAddress>());
137 might_add_to_merged_list = true;
138 }
139 const std::vector<IPAddress>& addresses = list[i]->GetIPs();
140 address_list& current_list = address_map[key];
141 for (std::vector<IPAddress>::const_iterator it = addresses.begin();
142 it != addresses.end();
143 ++it) {
144 current_list.second.push_back(*it);
145 }
146 if (!might_add_to_merged_list) {
147 delete list[i];
148 }
149 }
150
151 // Next, look for existing network objects to re-use.
152 for (std::map<std::string, address_list >::iterator it = address_map.begin();
153 it != address_map.end();
154 ++it) {
155 const std::string& key = it->first;
156 Network* net = it->second.first;
157 NetworkMap::iterator existing = networks_map_.find(key);
158 if (existing == networks_map_.end()) {
159 // This network is new. Place it in the network map.
160 merged_list.push_back(net);
161 networks_map_[key] = net;
162 *changed = true;
163 } else {
164 // This network exists in the map already. Reset its IP addresses.
165 *changed = existing->second->SetIPs(it->second.second, *changed);
166 merged_list.push_back(existing->second);
167 if (existing->second != net) {
168 delete net;
169 }
170 }
171 }
172 networks_ = merged_list;
173}
174
175BasicNetworkManager::BasicNetworkManager()
wu@webrtc.orgd64719d2013-08-01 00:00:07 +0000176 : thread_(NULL), sent_first_update_(false), start_count_(0) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000177}
178
179BasicNetworkManager::~BasicNetworkManager() {
180}
181
182#if defined(POSIX)
183void BasicNetworkManager::ConvertIfAddrs(struct ifaddrs* interfaces,
184 bool include_ignored,
185 NetworkList* networks) const {
186 NetworkMap current_networks;
187 for (struct ifaddrs* cursor = interfaces;
188 cursor != NULL; cursor = cursor->ifa_next) {
189 IPAddress prefix;
190 IPAddress mask;
191 IPAddress ip;
192 int scope_id = 0;
193
194 // Some interfaces may not have address assigned.
195 if (!cursor->ifa_addr || !cursor->ifa_netmask)
196 continue;
197
198 switch (cursor->ifa_addr->sa_family) {
199 case AF_INET: {
200 ip = IPAddress(
201 reinterpret_cast<sockaddr_in*>(cursor->ifa_addr)->sin_addr);
202 mask = IPAddress(
203 reinterpret_cast<sockaddr_in*>(cursor->ifa_netmask)->sin_addr);
204 break;
205 }
206 case AF_INET6: {
207 if (ipv6_enabled()) {
208 ip = IPAddress(
209 reinterpret_cast<sockaddr_in6*>(cursor->ifa_addr)->sin6_addr);
210 mask = IPAddress(
211 reinterpret_cast<sockaddr_in6*>(cursor->ifa_netmask)->sin6_addr);
212 scope_id =
213 reinterpret_cast<sockaddr_in6*>(cursor->ifa_addr)->sin6_scope_id;
214 break;
215 } else {
216 continue;
217 }
218 }
219 default: {
220 continue;
221 }
222 }
223 int prefix_length = CountIPMaskBits(mask);
224 prefix = TruncateIP(ip, prefix_length);
225 std::string key = MakeNetworkKey(std::string(cursor->ifa_name),
226 prefix, prefix_length);
227 NetworkMap::iterator existing_network = current_networks.find(key);
228 if (existing_network == current_networks.end()) {
229 scoped_ptr<Network> network(new Network(cursor->ifa_name,
230 cursor->ifa_name,
231 prefix,
232 prefix_length));
233 network->set_scope_id(scope_id);
234 network->AddIP(ip);
235 bool ignored = ((cursor->ifa_flags & IFF_LOOPBACK) ||
236 IsIgnoredNetwork(*network));
237 network->set_ignored(ignored);
238 if (include_ignored || !network->ignored()) {
239 networks->push_back(network.release());
240 }
241 } else {
242 (*existing_network).second->AddIP(ip);
243 }
244 }
245}
246
247bool BasicNetworkManager::CreateNetworks(bool include_ignored,
248 NetworkList* networks) const {
249 struct ifaddrs* interfaces;
250 int error = getifaddrs(&interfaces);
251 if (error != 0) {
252 LOG_ERR(LERROR) << "getifaddrs failed to gather interface data: " << error;
253 return false;
254 }
255
256 ConvertIfAddrs(interfaces, include_ignored, networks);
257
258 freeifaddrs(interfaces);
259 return true;
260}
261
262#elif defined(WIN32)
263
264unsigned int GetPrefix(PIP_ADAPTER_PREFIX prefixlist,
265 const IPAddress& ip, IPAddress* prefix) {
266 IPAddress current_prefix;
267 IPAddress best_prefix;
268 unsigned int best_length = 0;
269 while (prefixlist) {
270 // Look for the longest matching prefix in the prefixlist.
271 if (prefixlist->Address.lpSockaddr == NULL ||
272 prefixlist->Address.lpSockaddr->sa_family != ip.family()) {
273 prefixlist = prefixlist->Next;
274 continue;
275 }
276 switch (prefixlist->Address.lpSockaddr->sa_family) {
277 case AF_INET: {
278 sockaddr_in* v4_addr =
279 reinterpret_cast<sockaddr_in*>(prefixlist->Address.lpSockaddr);
280 current_prefix = IPAddress(v4_addr->sin_addr);
281 break;
282 }
283 case AF_INET6: {
284 sockaddr_in6* v6_addr =
285 reinterpret_cast<sockaddr_in6*>(prefixlist->Address.lpSockaddr);
286 current_prefix = IPAddress(v6_addr->sin6_addr);
287 break;
288 }
289 default: {
290 prefixlist = prefixlist->Next;
291 continue;
292 }
293 }
294 if (TruncateIP(ip, prefixlist->PrefixLength) == current_prefix &&
295 prefixlist->PrefixLength > best_length) {
296 best_prefix = current_prefix;
297 best_length = prefixlist->PrefixLength;
298 }
299 prefixlist = prefixlist->Next;
300 }
301 *prefix = best_prefix;
302 return best_length;
303}
304
305bool BasicNetworkManager::CreateNetworks(bool include_ignored,
306 NetworkList* networks) const {
307 NetworkMap current_networks;
308 // MSDN recommends a 15KB buffer for the first try at GetAdaptersAddresses.
309 size_t buffer_size = 16384;
310 scoped_array<char> adapter_info(new char[buffer_size]);
311 PIP_ADAPTER_ADDRESSES adapter_addrs =
312 reinterpret_cast<PIP_ADAPTER_ADDRESSES>(adapter_info.get());
313 int adapter_flags = (GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_ANYCAST |
314 GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_INCLUDE_PREFIX);
315 int ret = 0;
316 do {
317 adapter_info.reset(new char[buffer_size]);
318 adapter_addrs = reinterpret_cast<PIP_ADAPTER_ADDRESSES>(adapter_info.get());
319 ret = GetAdaptersAddresses(AF_UNSPEC, adapter_flags,
320 0, adapter_addrs,
321 reinterpret_cast<PULONG>(&buffer_size));
322 } while (ret == ERROR_BUFFER_OVERFLOW);
323 if (ret != ERROR_SUCCESS) {
324 return false;
325 }
326 int count = 0;
327 while (adapter_addrs) {
328 if (adapter_addrs->OperStatus == IfOperStatusUp) {
329 PIP_ADAPTER_UNICAST_ADDRESS address = adapter_addrs->FirstUnicastAddress;
330 PIP_ADAPTER_PREFIX prefixlist = adapter_addrs->FirstPrefix;
331 std::string name;
332 std::string description;
333#ifdef _DEBUG
334 name = ToUtf8(adapter_addrs->FriendlyName,
335 wcslen(adapter_addrs->FriendlyName));
336#endif
337 description = ToUtf8(adapter_addrs->Description,
338 wcslen(adapter_addrs->Description));
339 for (; address; address = address->Next) {
340#ifndef _DEBUG
341 name = talk_base::ToString(count);
342#endif
343
344 IPAddress ip;
345 int scope_id = 0;
346 scoped_ptr<Network> network;
347 switch (address->Address.lpSockaddr->sa_family) {
348 case AF_INET: {
349 sockaddr_in* v4_addr =
350 reinterpret_cast<sockaddr_in*>(address->Address.lpSockaddr);
351 ip = IPAddress(v4_addr->sin_addr);
352 break;
353 }
354 case AF_INET6: {
355 if (ipv6_enabled()) {
356 sockaddr_in6* v6_addr =
357 reinterpret_cast<sockaddr_in6*>(address->Address.lpSockaddr);
358 scope_id = v6_addr->sin6_scope_id;
359 ip = IPAddress(v6_addr->sin6_addr);
360 break;
361 } else {
362 continue;
363 }
364 }
365 default: {
366 continue;
367 }
368 }
369 IPAddress prefix;
370 int prefix_length = GetPrefix(prefixlist, ip, &prefix);
371 std::string key = MakeNetworkKey(name, prefix, prefix_length);
372 NetworkMap::iterator existing_network = current_networks.find(key);
373 if (existing_network == current_networks.end()) {
374 scoped_ptr<Network> network(new Network(name,
375 description,
376 prefix,
377 prefix_length));
378 network->set_scope_id(scope_id);
379 network->AddIP(ip);
380 bool ignore = ((adapter_addrs->IfType == IF_TYPE_SOFTWARE_LOOPBACK) ||
381 IsIgnoredNetwork(*network));
382 network->set_ignored(ignore);
383 if (include_ignored || !network->ignored()) {
384 networks->push_back(network.release());
385 }
386 } else {
387 (*existing_network).second->AddIP(ip);
388 }
389 }
390 // Count is per-adapter - all 'Networks' created from the same
391 // adapter need to have the same name.
392 ++count;
393 }
394 adapter_addrs = adapter_addrs->Next;
395 }
396 return true;
397}
398#endif // WIN32
399
400bool BasicNetworkManager::IsIgnoredNetwork(const Network& network) {
401#ifdef POSIX
402 // Ignore local networks (lo, lo0, etc)
403 // Also filter out VMware interfaces, typically named vmnet1 and vmnet8
404 if (strncmp(network.name().c_str(), "vmnet", 5) == 0 ||
405 strncmp(network.name().c_str(), "vnic", 4) == 0) {
406 return true;
407 }
408#elif defined(WIN32)
409 // Ignore any HOST side vmware adapters with a description like:
410 // VMware Virtual Ethernet Adapter for VMnet1
411 // but don't ignore any GUEST side adapters with a description like:
412 // VMware Accelerated AMD PCNet Adapter #2
413 if (strstr(network.description().c_str(), "VMnet") != NULL) {
414 return true;
415 }
416#endif
417
418 // Ignore any networks with a 0.x.y.z IP
419 if (network.prefix().family() == AF_INET) {
420 return (network.prefix().v4AddressAsHostOrderInteger() < 0x01000000);
421 }
422 return false;
423}
424
425void BasicNetworkManager::StartUpdating() {
426 thread_ = Thread::Current();
427 if (start_count_) {
428 // If network interfaces are already discovered and signal is sent,
429 // we should trigger network signal immediately for the new clients
430 // to start allocating ports.
431 if (sent_first_update_)
432 thread_->Post(this, kSignalNetworksMessage);
433 } else {
434 thread_->Post(this, kUpdateNetworksMessage);
435 }
436 ++start_count_;
437}
438
439void BasicNetworkManager::StopUpdating() {
440 ASSERT(Thread::Current() == thread_);
441 if (!start_count_)
442 return;
443
444 --start_count_;
445 if (!start_count_) {
446 thread_->Clear(this);
447 sent_first_update_ = false;
448 }
449}
450
451void BasicNetworkManager::OnMessage(Message* msg) {
452 switch (msg->message_id) {
453 case kUpdateNetworksMessage: {
454 DoUpdateNetworks();
455 break;
456 }
457 case kSignalNetworksMessage: {
458 SignalNetworksChanged();
459 break;
460 }
461 default:
462 ASSERT(false);
463 }
464}
465
466void BasicNetworkManager::DoUpdateNetworks() {
467 if (!start_count_)
468 return;
469
470 ASSERT(Thread::Current() == thread_);
471
472 NetworkList list;
473 if (!CreateNetworks(false, &list)) {
474 SignalError();
475 } else {
476 bool changed;
477 MergeNetworkList(list, &changed);
478 if (changed || !sent_first_update_) {
479 SignalNetworksChanged();
480 sent_first_update_ = true;
481 }
482 }
483
484 thread_->PostDelayed(kNetworksUpdateIntervalMs, this, kUpdateNetworksMessage);
485}
486
487void BasicNetworkManager::DumpNetworks(bool include_ignored) {
488 NetworkList list;
489 CreateNetworks(include_ignored, &list);
490 LOG(LS_INFO) << "NetworkManager detected " << list.size() << " networks:";
491 for (size_t i = 0; i < list.size(); ++i) {
492 const Network* network = list[i];
493 if (!network->ignored() || include_ignored) {
494 LOG(LS_INFO) << network->ToString() << ": "
495 << network->description()
496 << ((network->ignored()) ? ", Ignored" : "");
497 }
498 }
henrike@webrtc.org723d6832013-07-12 16:04:50 +0000499 // Release the network list created previously.
500 // Do this in a seperated for loop for better readability.
501 for (size_t i = 0; i < list.size(); ++i) {
502 delete list[i];
503 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000504}
505
506Network::Network(const std::string& name, const std::string& desc,
507 const IPAddress& prefix, int prefix_length)
508 : name_(name), description_(desc), prefix_(prefix),
509 prefix_length_(prefix_length), scope_id_(0), ignored_(false),
510 uniform_numerator_(0), uniform_denominator_(0), exponential_numerator_(0),
511 exponential_denominator_(0) {
512}
513
514std::string Network::ToString() const {
515 std::stringstream ss;
516 // Print out the first space-terminated token of the network desc, plus
517 // the IP address.
518 ss << "Net[" << description_.substr(0, description_.find(' '))
519 << ":" << prefix_.ToSensitiveString() << "/" << prefix_length_ << "]";
520 return ss.str();
521}
522
523// Sets the addresses of this network. Returns true if the address set changed.
524// Change detection is short circuited if the changed argument is true.
525bool Network::SetIPs(const std::vector<IPAddress>& ips, bool changed) {
526 changed = changed || ips.size() != ips_.size();
527 // Detect changes with a nested loop; n-squared but we expect on the order
528 // of 2-3 addresses per network.
529 for (std::vector<IPAddress>::const_iterator it = ips.begin();
530 !changed && it != ips.end();
531 ++it) {
532 bool found = false;
533 for (std::vector<IPAddress>::iterator inner_it = ips_.begin();
534 !found && inner_it != ips_.end();
535 ++inner_it) {
536 if (*it == *inner_it) {
537 found = true;
538 }
539 }
540 changed = !found;
541 }
542 ips_ = ips;
543 return changed;
544}
545} // namespace talk_base