blob: 57eceeb730c162d2554b932df75fc61ebc2d0dd6 [file] [log] [blame]
Davide Pesavento9a8bae52016-02-24 20:33:08 +01001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
Davide Pesavento2bf35a62017-04-02 00:41:06 -04003 * Copyright (c) 2013-2017 Regents of the University of California.
Davide Pesavento9a8bae52016-02-24 20:33:08 +01004 *
5 * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
6 *
7 * ndn-cxx library is free software: you can redistribute it and/or modify it under the
8 * terms of the GNU Lesser General Public License as published by the Free Software
9 * Foundation, either version 3 of the License, or (at your option) any later version.
10 *
11 * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
13 * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
14 *
15 * You should have received copies of the GNU General Public License and GNU Lesser
16 * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
20 *
21 *
22 * Parts of this implementation is based on daemondo command of MacPorts
23 * (https://www.macports.org/):
24 *
25 * Copyright (c) 2005-2007 James Berry <jberry@macports.org>
26 * All rights reserved.
27 *
28 * Redistribution and use in source and binary forms, with or without
29 * modification, are permitted provided that the following conditions
30 * are met:
31 * 1. Redistributions of source code must retain the above copyright
32 * notice, this list of conditions and the following disclaimer.
33 * 2. Redistributions in binary form must reproduce the above copyright
34 * notice, this list of conditions and the following disclaimer in the
35 * documentation and/or other materials provided with the distribution.
36 * 3. Neither the name of The MacPorts Project nor the names of its contributors
37 * may be used to endorse or promote products derived from this software
38 * without specific prior written permission.
39 *
40 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
41 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
43 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
44 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
45 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
46 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
47 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
48 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
49 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
50 * POSSIBILITY OF SUCH DAMAGE.
51 */
52
53#include "ndn-cxx-config.hpp"
54
Davide Pesavento9a8bae52016-02-24 20:33:08 +010055#include "network-monitor-impl-osx.hpp"
Alexander Afanasyev3b3355c2017-03-26 11:57:13 -050056#include "../../name.hpp"
Junxiao Shi25467942017-06-30 02:53:14 +000057#include "../../util/logger.hpp"
Alexander Afanasyev3b3355c2017-03-26 11:57:13 -050058#include "../network-address.hpp"
59
60#include <ifaddrs.h> // for getifaddrs()
61#include <arpa/inet.h> // for inet_ntop()
62#include <netinet/in.h> // for struct sockaddr_in{,6}
63#include <net/if_dl.h> // for struct sockaddr_dl
64#include <net/if_types.h> // for IFT_* constants
65
66#include <boost/asio.hpp>
Davide Pesavento9a8bae52016-02-24 20:33:08 +010067
68namespace ndn {
Junxiao Shi25467942017-06-30 02:53:14 +000069namespace net {
Davide Pesavento9a8bae52016-02-24 20:33:08 +010070
Junxiao Shi0b1b4672017-07-02 22:02:31 -070071using util::CFReleaser;
72
Alexander Afanasyev3b3355c2017-03-26 11:57:13 -050073NDN_LOG_INIT(ndn.NetworkMonitor);
74
Junxiao Shi2dc416d2017-07-03 04:46:16 +000075NetworkMonitorImplOsx::NetworkMonitorImplOsx(boost::asio::io_service& io)
76 : m_scheduler(io)
Davide Pesavento9a8bae52016-02-24 20:33:08 +010077 , m_cfLoopEvent(m_scheduler)
Alexander Afanasyev3b3355c2017-03-26 11:57:13 -050078 , m_context{0, this, nullptr, nullptr, nullptr}
79 , m_scStore(SCDynamicStoreCreate(nullptr, CFSTR("net.named-data.ndn-cxx.NetworkMonitor"),
Junxiao Shi2dc416d2017-07-03 04:46:16 +000080 &NetworkMonitorImplOsx::onConfigChanged, &m_context))
Alexander Afanasyev3b3355c2017-03-26 11:57:13 -050081 , m_loopSource(SCDynamicStoreCreateRunLoopSource(nullptr, m_scStore.get(), 0))
82 , m_nullUdpSocket(io, boost::asio::ip::udp::v4())
83
Davide Pesavento9a8bae52016-02-24 20:33:08 +010084{
85 scheduleCfLoop();
86
Alexander Afanasyev3b3355c2017-03-26 11:57:13 -050087 // Notifications from Darwin Notify Center:
Davide Pesavento9a8bae52016-02-24 20:33:08 +010088 //
89 // com.apple.system.config.network_change
90 //
91 CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(),
92 static_cast<void*>(this),
Junxiao Shi2dc416d2017-07-03 04:46:16 +000093 &NetworkMonitorImplOsx::afterNotificationCenterEvent,
Davide Pesavento9a8bae52016-02-24 20:33:08 +010094 CFSTR("com.apple.system.config.network_change"),
95 nullptr, // object to observe
96 CFNotificationSuspensionBehaviorDeliverImmediately);
Alexander Afanasyev3b3355c2017-03-26 11:57:13 -050097
98 io.post([this] { enumerateInterfaces(); });
99
100 CFRunLoopAddSource(CFRunLoopGetCurrent(), m_loopSource.get(), kCFRunLoopDefaultMode);
101
102 // Notifications from SystemConfiguration:
103 //
104 // State:/Network/Interface/.*/Link
105 // State:/Network/Interface/.*/IPv4
106 // State:/Network/Interface/.*/IPv6
107 // State:/Network/Global/DNS
108 // State:/Network/Global/IPv4
109 //
110 auto patterns = CFArrayCreateMutable(nullptr, 0, &kCFTypeArrayCallBacks);
111 CFArrayAppendValue(patterns, CFSTR("State:/Network/Interface/.*/Link"));
112 CFArrayAppendValue(patterns, CFSTR("State:/Network/Interface/.*/IPv4"));
113 CFArrayAppendValue(patterns, CFSTR("State:/Network/Interface/.*/IPv6"));
114 // CFArrayAppendValue(patterns, CFSTR("State:/Network/Global/DNS"));
115 // CFArrayAppendValue(patterns, CFSTR("State:/Network/Global/IPv4"));
116
117 SCDynamicStoreSetNotificationKeys(m_scStore.get(), nullptr, patterns);
Davide Pesavento9a8bae52016-02-24 20:33:08 +0100118}
119
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000120NetworkMonitorImplOsx::~NetworkMonitorImplOsx()
Davide Pesavento9a8bae52016-02-24 20:33:08 +0100121{
Alexander Afanasyev3b3355c2017-03-26 11:57:13 -0500122 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), m_loopSource.get(), kCFRunLoopDefaultMode);
123
Davide Pesavento9a8bae52016-02-24 20:33:08 +0100124 CFNotificationCenterRemoveEveryObserver(CFNotificationCenterGetDarwinNotifyCenter(),
125 static_cast<void*>(this));
126}
127
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000128shared_ptr<const NetworkInterface>
129NetworkMonitorImplOsx::getNetworkInterface(const std::string& ifname) const
Davide Pesavento2bf35a62017-04-02 00:41:06 -0400130{
Alexander Afanasyev3b3355c2017-03-26 11:57:13 -0500131 auto it = m_interfaces.find(ifname);
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000132 return it == m_interfaces.end() ? nullptr : it->second;
Davide Pesavento2bf35a62017-04-02 00:41:06 -0400133}
134
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000135std::vector<shared_ptr<const NetworkInterface>>
136NetworkMonitorImplOsx::listNetworkInterfaces() const
Davide Pesavento2bf35a62017-04-02 00:41:06 -0400137{
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000138 std::vector<shared_ptr<const NetworkInterface>> v;
Alexander Afanasyev3b3355c2017-03-26 11:57:13 -0500139 v.reserve(m_interfaces.size());
140
141 for (const auto& e : m_interfaces) {
142 v.push_back(e.second);
143 }
144 return v;
Davide Pesavento2bf35a62017-04-02 00:41:06 -0400145}
146
Davide Pesavento9a8bae52016-02-24 20:33:08 +0100147void
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000148NetworkMonitorImplOsx::afterNotificationCenterEvent(CFNotificationCenterRef center,
149 void* observer,
150 CFStringRef name,
151 const void* object,
152 CFDictionaryRef userInfo)
Davide Pesavento9a8bae52016-02-24 20:33:08 +0100153{
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000154 static_cast<NetworkMonitorImplOsx*>(observer)->emitSignal(onNetworkStateChanged);
Davide Pesavento9a8bae52016-02-24 20:33:08 +0100155}
156
157void
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000158NetworkMonitorImplOsx::scheduleCfLoop()
Davide Pesavento9a8bae52016-02-24 20:33:08 +0100159{
160 // poll each second for new events
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000161 m_cfLoopEvent = m_scheduler.scheduleEvent(time::seconds(1), [this] { pollCfLoop(); });
Davide Pesavento9a8bae52016-02-24 20:33:08 +0100162}
163
164void
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000165NetworkMonitorImplOsx::pollCfLoop()
Davide Pesavento9a8bae52016-02-24 20:33:08 +0100166{
167 // this should dispatch ready events and exit
168 CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, true);
169
170 scheduleCfLoop();
171}
172
Alexander Afanasyev3b3355c2017-03-26 11:57:13 -0500173void
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000174NetworkMonitorImplOsx::addNewInterface(const std::string& ifName)
Alexander Afanasyev3b3355c2017-03-26 11:57:13 -0500175{
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000176 shared_ptr<NetworkInterface> interface = makeNetworkInterface();
Alexander Afanasyev3b3355c2017-03-26 11:57:13 -0500177 interface->setName(ifName);
178 interface->setState(getInterfaceState(interface->getName()));
179 updateInterfaceInfo(*interface);
180 if (interface->getType() == InterfaceType::UNKNOWN) {
181 NDN_LOG_DEBUG("ignoring " << ifName << " because it has unhandled interface type");
182 return;
183 }
184
185 NDN_LOG_DEBUG("adding interface " << interface->getName());
186 m_interfaces.insert(make_pair(interface->getName(), interface));
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000187 this->emitSignal(onInterfaceAdded, interface);
Alexander Afanasyev3b3355c2017-03-26 11:57:13 -0500188}
189
190void
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000191NetworkMonitorImplOsx::enumerateInterfaces()
Alexander Afanasyev3b3355c2017-03-26 11:57:13 -0500192{
193 for (const auto& ifName : getInterfaceNames()) {
194 addNewInterface(ifName);
195 }
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000196 this->emitSignal(onEnumerationCompleted);
Alexander Afanasyev3b3355c2017-03-26 11:57:13 -0500197}
198
199static std::string
200convertToStdString(CFStringRef cfString)
201{
202 const char* cStr = CFStringGetCStringPtr(cfString, kCFStringEncodingASCII);
203 if (cStr != nullptr) {
204 return cStr;
205 }
206
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000207 size_t stringSize = CFStringGetLength(cfString);
Alexander Afanasyev3b3355c2017-03-26 11:57:13 -0500208 char* buffer = new char[stringSize + 1];
209 CFStringGetCString(cfString, buffer, sizeof(buffer), kCFStringEncodingASCII);
210 std::string retval = buffer;
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000211 delete[] buffer;
Alexander Afanasyev3b3355c2017-03-26 11:57:13 -0500212 return retval;
213}
214
215std::set<std::string>
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000216NetworkMonitorImplOsx::getInterfaceNames()
Alexander Afanasyev3b3355c2017-03-26 11:57:13 -0500217{
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000218 CFReleaser<CFDictionaryRef> dict =
219 (CFDictionaryRef)SCDynamicStoreCopyValue(m_scStore.get(), CFSTR("State:/Network/Interface"));
Alexander Afanasyev3b3355c2017-03-26 11:57:13 -0500220 CFArrayRef interfaces = (CFArrayRef)CFDictionaryGetValue(dict.get(), CFSTR("Interfaces"));
221
222 std::set<std::string> ifNames;
223 size_t count = CFArrayGetCount(interfaces);
224 for (size_t i = 0; i != count; ++i) {
225 auto ifName = (CFStringRef)CFArrayGetValueAtIndex(interfaces, i);
226 ifNames.insert(convertToStdString(ifName));
227 }
228 return ifNames;
229}
230
231InterfaceState
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000232NetworkMonitorImplOsx::getInterfaceState(const std::string& ifName)
Alexander Afanasyev3b3355c2017-03-26 11:57:13 -0500233{
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000234 CFReleaser<CFStringRef> linkName =
235 CFStringCreateWithCString(nullptr, ("State:/Network/Interface/" + ifName + "/Link").c_str(),
236 kCFStringEncodingASCII);
Alexander Afanasyev3b3355c2017-03-26 11:57:13 -0500237
238 CFReleaser<CFDictionaryRef> dict = (CFDictionaryRef)SCDynamicStoreCopyValue(m_scStore.get(), linkName.get());
239 if (dict.get() == nullptr) {
240 return InterfaceState::UNKNOWN;
241 }
242
243 CFBooleanRef isActive = (CFBooleanRef)CFDictionaryGetValue(dict.get(), CFSTR("Active"));
244 if (isActive == nullptr) {
245 return InterfaceState::UNKNOWN;
246 }
247
248 return CFBooleanGetValue(isActive) ? InterfaceState::RUNNING : InterfaceState::DOWN;
249}
250
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000251template<typename AddressBytes>
252static uint8_t
253computePrefixLength(const AddressBytes& mask)
254{
255 uint8_t prefixLength = 0;
256 for (auto byte : mask) {
257 while (byte != 0) {
258 ++prefixLength;
259 byte <<= 1;
260 }
261 }
262 return prefixLength;
263}
264
Alexander Afanasyev3b3355c2017-03-26 11:57:13 -0500265void
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000266NetworkMonitorImplOsx::updateInterfaceInfo(NetworkInterface& netif)
Alexander Afanasyev3b3355c2017-03-26 11:57:13 -0500267{
268 ifaddrs* ifa_list = nullptr;
269 if (::getifaddrs(&ifa_list) < 0) {
270 BOOST_THROW_EXCEPTION(Error(std::string("getifaddrs() failed: ") + strerror(errno)));
271 }
272
273 for (ifaddrs* ifa = ifa_list; ifa != nullptr; ifa = ifa->ifa_next) {
274 if (ifa->ifa_name != netif.getName()) {
275 continue;
276 }
277
278 netif.setFlags(ifa->ifa_flags);
279 netif.setMtu(getInterfaceMtu(netif.getName()));
280
281 if (ifa->ifa_addr == nullptr)
282 continue;
283
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000284 namespace ip = boost::asio::ip;
285 AddressFamily addressFamily = AddressFamily::UNSPECIFIED;
286 ip::address ipAddr, broadcast;
287 uint8_t prefixLength = 0;
288
Alexander Afanasyev3b3355c2017-03-26 11:57:13 -0500289
290 switch (ifa->ifa_addr->sa_family) {
291 case AF_INET: {
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000292 addressFamily = AddressFamily::V4;
Alexander Afanasyev3b3355c2017-03-26 11:57:13 -0500293
294 const sockaddr_in* sin = reinterpret_cast<sockaddr_in*>(ifa->ifa_addr);
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000295 ip::address_v4::bytes_type bytes;
Alexander Afanasyev3b3355c2017-03-26 11:57:13 -0500296 std::copy_n(reinterpret_cast<const unsigned char*>(&sin->sin_addr), bytes.size(), bytes.begin());
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000297 ipAddr = ip::address_v4(bytes);
Alexander Afanasyev3b3355c2017-03-26 11:57:13 -0500298
299 const sockaddr_in* sinMask = reinterpret_cast<sockaddr_in*>(ifa->ifa_netmask);
300 std::copy_n(reinterpret_cast<const unsigned char*>(&sinMask->sin_addr), bytes.size(), bytes.begin());
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000301 prefixLength = computePrefixLength(bytes);
Alexander Afanasyev3b3355c2017-03-26 11:57:13 -0500302 break;
303 }
304
305 case AF_INET6: {
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000306 addressFamily = AddressFamily::V6;
Alexander Afanasyev3b3355c2017-03-26 11:57:13 -0500307
308 const sockaddr_in6* sin6 = reinterpret_cast<sockaddr_in6*>(ifa->ifa_addr);
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000309 ip::address_v6::bytes_type bytes;
Alexander Afanasyev3b3355c2017-03-26 11:57:13 -0500310 std::copy_n(reinterpret_cast<const unsigned char*>(&sin6->sin6_addr), bytes.size(), bytes.begin());
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000311 ipAddr = ip::address_v6(bytes);
Alexander Afanasyev3b3355c2017-03-26 11:57:13 -0500312
313 const sockaddr_in6* sinMask = reinterpret_cast<sockaddr_in6*>(ifa->ifa_netmask);
314 std::copy_n(reinterpret_cast<const unsigned char*>(&sinMask->sin6_addr), bytes.size(), bytes.begin());
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000315 prefixLength = computePrefixLength(bytes);
Alexander Afanasyev3b3355c2017-03-26 11:57:13 -0500316 break;
317 }
318
319 case AF_LINK: {
320 const sockaddr_dl* sdl = reinterpret_cast<sockaddr_dl*>(ifa->ifa_addr);
321 netif.setIndex(sdl->sdl_index);
322 if (sdl->sdl_type == IFT_ETHER && sdl->sdl_alen == ethernet::ADDR_LEN) {
323 netif.setType(InterfaceType::ETHERNET);
324 netif.setEthernetAddress(ethernet::Address(reinterpret_cast<uint8_t*>(LLADDR(sdl))));
325 NDN_LOG_TRACE(netif.getName() << ": set Ethernet address " << netif.getEthernetAddress());
326 }
327 else if (sdl->sdl_type == IFT_LOOP) {
328 netif.setType(InterfaceType::LOOPBACK);
329 }
330 else {
331 netif.setType(InterfaceType::UNKNOWN);
332 }
333 break;
334 }
335
336 default:
337 continue;
338 }
339
340 if (netif.canBroadcast() && ifa->ifa_broadaddr != nullptr) {
341 const sockaddr_in* sin = reinterpret_cast<sockaddr_in*>(ifa->ifa_broadaddr);
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000342 ip::address_v4::bytes_type bytes;
Alexander Afanasyev3b3355c2017-03-26 11:57:13 -0500343 std::copy_n(reinterpret_cast<const unsigned char*>(&sin->sin_addr), bytes.size(), bytes.begin());
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000344 broadcast = ip::address_v4(bytes);
345 NDN_LOG_TRACE(netif.getName() << ": set IPv4 broadcast address " << broadcast);
Alexander Afanasyev3b3355c2017-03-26 11:57:13 -0500346 }
347
348 if (netif.canBroadcast()) {
349 netif.setEthernetBroadcastAddress(ethernet::getBroadcastAddress());
350 }
351
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000352 netif.addNetworkAddress(NetworkAddress(addressFamily, ipAddr, broadcast, prefixLength,
353 AddressScope::NOWHERE, 0));
354 ///\todo #3817 extract AddressScope from OS
Alexander Afanasyev3b3355c2017-03-26 11:57:13 -0500355 }
356
357 ::freeifaddrs(ifa_list);
358}
359
360size_t
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000361NetworkMonitorImplOsx::getInterfaceMtu(const std::string& ifName)
Alexander Afanasyev3b3355c2017-03-26 11:57:13 -0500362{
363 ifreq ifr{};
364 std::strncpy(ifr.ifr_name, ifName.c_str(), sizeof(ifr.ifr_name) - 1);
365
366 if (::ioctl(m_nullUdpSocket.native_handle(), SIOCGIFMTU, &ifr) == 0) {
367 return static_cast<size_t>(ifr.ifr_mtu);
368 }
369
370 NDN_LOG_WARN("Failed to get interface MTU: " << std::strerror(errno));
371 return ethernet::MAX_DATA_LEN;
372}
373
374void
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000375NetworkMonitorImplOsx::onConfigChanged(SCDynamicStoreRef m_scStore, CFArrayRef changedKeys, void* context)
Alexander Afanasyev3b3355c2017-03-26 11:57:13 -0500376{
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000377 static_cast<NetworkMonitorImplOsx*>(context)->onConfigChanged(changedKeys);
Alexander Afanasyev3b3355c2017-03-26 11:57:13 -0500378}
379
380void
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000381NetworkMonitorImplOsx::onConfigChanged(CFArrayRef changedKeys)
Alexander Afanasyev3b3355c2017-03-26 11:57:13 -0500382{
383 size_t count = CFArrayGetCount(changedKeys);
384 for (size_t i = 0; i != count; ++i) {
385 std::string keyName = convertToStdString((CFStringRef)CFArrayGetValueAtIndex(changedKeys, i));
386 Name key(keyName);
387 std::string ifName = key.at(-2).toUri();
388
389 auto ifIt = m_interfaces.find(ifName);
390 if (ifIt == m_interfaces.end()) {
391 addNewInterface(ifName);
392 return;
393 }
394
395 NetworkInterface& netif = *ifIt->second;
396
397 auto removeInterface = [&] {
398 NDN_LOG_DEBUG("removing interface " << ifName);
399 shared_ptr<NetworkInterface> removedInterface = ifIt->second;
400 m_interfaces.erase(ifIt);
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000401 this->emitSignal(onInterfaceRemoved, removedInterface);
Alexander Afanasyev3b3355c2017-03-26 11:57:13 -0500402 };
403
404 if (key.at(-1).toUri() == "Link") {
405 auto newState = getInterfaceState(ifName);
406
407 if (newState == InterfaceState::UNKNOWN) {
408 // check if it is really unknown or interface removed
409 if (getInterfaceNames().count(ifName) == 0) {
410 // newState = InterfaceState::DOWN;
411 removeInterface();
412 return;
413 }
414 }
415
416 NDN_LOG_TRACE("Status of " << ifName << " changed from " << netif.getState() << " to " << newState);
417 netif.setState(newState);
418 }
419
420 if (key.at(-1).toUri() == "IPv4" || key.at(-1).toUri() == "IPv6") {
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000421 shared_ptr<NetworkInterface> updatedInterface = makeNetworkInterface();
422 updatedInterface->setName(ifName);
423 updateInterfaceInfo(*updatedInterface);
424 if (updatedInterface->getType() == InterfaceType::UNKNOWN) {
Alexander Afanasyev3b3355c2017-03-26 11:57:13 -0500425 // somehow, type of interface changed to unknown
426 NDN_LOG_DEBUG("Removing " << ifName << " because it changed to unhandled interface type");
427 removeInterface();
428 return;
429 }
430
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000431 const auto& newAddrs = updatedInterface->getNetworkAddresses();
Alexander Afanasyev3b3355c2017-03-26 11:57:13 -0500432 const auto& oldAddrs = netif.getNetworkAddresses();
433
434 std::set<NetworkAddress> added;
435 std::set<NetworkAddress> removed;
436
437 std::set_difference(newAddrs.begin(), newAddrs.end(),
438 oldAddrs.begin(), oldAddrs.end(), std::inserter(added, added.end()));
439
440 std::set_difference(oldAddrs.begin(), oldAddrs.end(),
441 newAddrs.begin(), newAddrs.end(), std::inserter(removed, removed.end()));
442
443 for (const auto& addr : removed) {
444 netif.removeNetworkAddress(addr);
445 }
446
447 for (const auto& addr : added) {
448 netif.addNetworkAddress(addr);
449 }
450 }
451 }
452}
453
Junxiao Shi25467942017-06-30 02:53:14 +0000454} // namespace net
Davide Pesavento9a8bae52016-02-24 20:33:08 +0100455} // namespace ndn