blob: b2129b5a7536c8910328cea975d214658abdaeb4 [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
Alexander Afanasyev3b3355c2017-03-26 11:57:13 -050071NDN_LOG_INIT(ndn.NetworkMonitor);
72
Junxiao Shi2dc416d2017-07-03 04:46:16 +000073NetworkMonitorImplOsx::NetworkMonitorImplOsx(boost::asio::io_service& io)
74 : m_scheduler(io)
Davide Pesavento9a8bae52016-02-24 20:33:08 +010075 , m_cfLoopEvent(m_scheduler)
Alexander Afanasyev3b3355c2017-03-26 11:57:13 -050076 , m_context{0, this, nullptr, nullptr, nullptr}
77 , m_scStore(SCDynamicStoreCreate(nullptr, CFSTR("net.named-data.ndn-cxx.NetworkMonitor"),
Junxiao Shi2dc416d2017-07-03 04:46:16 +000078 &NetworkMonitorImplOsx::onConfigChanged, &m_context))
Alexander Afanasyev3b3355c2017-03-26 11:57:13 -050079 , m_loopSource(SCDynamicStoreCreateRunLoopSource(nullptr, m_scStore.get(), 0))
80 , m_nullUdpSocket(io, boost::asio::ip::udp::v4())
81
Davide Pesavento9a8bae52016-02-24 20:33:08 +010082{
83 scheduleCfLoop();
84
Alexander Afanasyev3b3355c2017-03-26 11:57:13 -050085 // Notifications from Darwin Notify Center:
Davide Pesavento9a8bae52016-02-24 20:33:08 +010086 //
87 // com.apple.system.config.network_change
88 //
89 CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(),
90 static_cast<void*>(this),
Junxiao Shi2dc416d2017-07-03 04:46:16 +000091 &NetworkMonitorImplOsx::afterNotificationCenterEvent,
Davide Pesavento9a8bae52016-02-24 20:33:08 +010092 CFSTR("com.apple.system.config.network_change"),
93 nullptr, // object to observe
94 CFNotificationSuspensionBehaviorDeliverImmediately);
Alexander Afanasyev3b3355c2017-03-26 11:57:13 -050095
96 io.post([this] { enumerateInterfaces(); });
97
98 CFRunLoopAddSource(CFRunLoopGetCurrent(), m_loopSource.get(), kCFRunLoopDefaultMode);
99
100 // Notifications from SystemConfiguration:
101 //
102 // State:/Network/Interface/.*/Link
103 // State:/Network/Interface/.*/IPv4
104 // State:/Network/Interface/.*/IPv6
105 // State:/Network/Global/DNS
106 // State:/Network/Global/IPv4
107 //
108 auto patterns = CFArrayCreateMutable(nullptr, 0, &kCFTypeArrayCallBacks);
109 CFArrayAppendValue(patterns, CFSTR("State:/Network/Interface/.*/Link"));
110 CFArrayAppendValue(patterns, CFSTR("State:/Network/Interface/.*/IPv4"));
111 CFArrayAppendValue(patterns, CFSTR("State:/Network/Interface/.*/IPv6"));
112 // CFArrayAppendValue(patterns, CFSTR("State:/Network/Global/DNS"));
113 // CFArrayAppendValue(patterns, CFSTR("State:/Network/Global/IPv4"));
114
115 SCDynamicStoreSetNotificationKeys(m_scStore.get(), nullptr, patterns);
Davide Pesavento9a8bae52016-02-24 20:33:08 +0100116}
117
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000118NetworkMonitorImplOsx::~NetworkMonitorImplOsx()
Davide Pesavento9a8bae52016-02-24 20:33:08 +0100119{
Alexander Afanasyev3b3355c2017-03-26 11:57:13 -0500120 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), m_loopSource.get(), kCFRunLoopDefaultMode);
121
Davide Pesavento9a8bae52016-02-24 20:33:08 +0100122 CFNotificationCenterRemoveEveryObserver(CFNotificationCenterGetDarwinNotifyCenter(),
123 static_cast<void*>(this));
124}
125
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000126shared_ptr<const NetworkInterface>
127NetworkMonitorImplOsx::getNetworkInterface(const std::string& ifname) const
Davide Pesavento2bf35a62017-04-02 00:41:06 -0400128{
Alexander Afanasyev3b3355c2017-03-26 11:57:13 -0500129 auto it = m_interfaces.find(ifname);
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000130 return it == m_interfaces.end() ? nullptr : it->second;
Davide Pesavento2bf35a62017-04-02 00:41:06 -0400131}
132
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000133std::vector<shared_ptr<const NetworkInterface>>
134NetworkMonitorImplOsx::listNetworkInterfaces() const
Davide Pesavento2bf35a62017-04-02 00:41:06 -0400135{
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000136 std::vector<shared_ptr<const NetworkInterface>> v;
Alexander Afanasyev3b3355c2017-03-26 11:57:13 -0500137 v.reserve(m_interfaces.size());
138
139 for (const auto& e : m_interfaces) {
140 v.push_back(e.second);
141 }
142 return v;
Davide Pesavento2bf35a62017-04-02 00:41:06 -0400143}
144
Davide Pesavento9a8bae52016-02-24 20:33:08 +0100145void
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000146NetworkMonitorImplOsx::afterNotificationCenterEvent(CFNotificationCenterRef center,
147 void* observer,
148 CFStringRef name,
149 const void* object,
150 CFDictionaryRef userInfo)
Davide Pesavento9a8bae52016-02-24 20:33:08 +0100151{
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000152 static_cast<NetworkMonitorImplOsx*>(observer)->emitSignal(onNetworkStateChanged);
Davide Pesavento9a8bae52016-02-24 20:33:08 +0100153}
154
155void
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000156NetworkMonitorImplOsx::scheduleCfLoop()
Davide Pesavento9a8bae52016-02-24 20:33:08 +0100157{
158 // poll each second for new events
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000159 m_cfLoopEvent = m_scheduler.scheduleEvent(time::seconds(1), [this] { pollCfLoop(); });
Davide Pesavento9a8bae52016-02-24 20:33:08 +0100160}
161
162void
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000163NetworkMonitorImplOsx::pollCfLoop()
Davide Pesavento9a8bae52016-02-24 20:33:08 +0100164{
165 // this should dispatch ready events and exit
166 CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, true);
167
168 scheduleCfLoop();
169}
170
Alexander Afanasyev3b3355c2017-03-26 11:57:13 -0500171void
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000172NetworkMonitorImplOsx::addNewInterface(const std::string& ifName)
Alexander Afanasyev3b3355c2017-03-26 11:57:13 -0500173{
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000174 shared_ptr<NetworkInterface> interface = makeNetworkInterface();
Alexander Afanasyev3b3355c2017-03-26 11:57:13 -0500175 interface->setName(ifName);
176 interface->setState(getInterfaceState(interface->getName()));
177 updateInterfaceInfo(*interface);
178 if (interface->getType() == InterfaceType::UNKNOWN) {
179 NDN_LOG_DEBUG("ignoring " << ifName << " because it has unhandled interface type");
180 return;
181 }
182
183 NDN_LOG_DEBUG("adding interface " << interface->getName());
184 m_interfaces.insert(make_pair(interface->getName(), interface));
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000185 this->emitSignal(onInterfaceAdded, interface);
Alexander Afanasyev3b3355c2017-03-26 11:57:13 -0500186}
187
188void
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000189NetworkMonitorImplOsx::enumerateInterfaces()
Alexander Afanasyev3b3355c2017-03-26 11:57:13 -0500190{
191 for (const auto& ifName : getInterfaceNames()) {
192 addNewInterface(ifName);
193 }
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000194 this->emitSignal(onEnumerationCompleted);
Alexander Afanasyev3b3355c2017-03-26 11:57:13 -0500195}
196
197static std::string
198convertToStdString(CFStringRef cfString)
199{
200 const char* cStr = CFStringGetCStringPtr(cfString, kCFStringEncodingASCII);
201 if (cStr != nullptr) {
202 return cStr;
203 }
204
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000205 size_t stringSize = CFStringGetLength(cfString);
Alexander Afanasyev3b3355c2017-03-26 11:57:13 -0500206 char* buffer = new char[stringSize + 1];
207 CFStringGetCString(cfString, buffer, sizeof(buffer), kCFStringEncodingASCII);
208 std::string retval = buffer;
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000209 delete[] buffer;
Alexander Afanasyev3b3355c2017-03-26 11:57:13 -0500210 return retval;
211}
212
213std::set<std::string>
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000214NetworkMonitorImplOsx::getInterfaceNames()
Alexander Afanasyev3b3355c2017-03-26 11:57:13 -0500215{
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000216 CFReleaser<CFDictionaryRef> dict =
217 (CFDictionaryRef)SCDynamicStoreCopyValue(m_scStore.get(), CFSTR("State:/Network/Interface"));
Alexander Afanasyev3b3355c2017-03-26 11:57:13 -0500218 CFArrayRef interfaces = (CFArrayRef)CFDictionaryGetValue(dict.get(), CFSTR("Interfaces"));
219
220 std::set<std::string> ifNames;
221 size_t count = CFArrayGetCount(interfaces);
222 for (size_t i = 0; i != count; ++i) {
223 auto ifName = (CFStringRef)CFArrayGetValueAtIndex(interfaces, i);
224 ifNames.insert(convertToStdString(ifName));
225 }
226 return ifNames;
227}
228
229InterfaceState
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000230NetworkMonitorImplOsx::getInterfaceState(const std::string& ifName)
Alexander Afanasyev3b3355c2017-03-26 11:57:13 -0500231{
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000232 CFReleaser<CFStringRef> linkName =
233 CFStringCreateWithCString(nullptr, ("State:/Network/Interface/" + ifName + "/Link").c_str(),
234 kCFStringEncodingASCII);
Alexander Afanasyev3b3355c2017-03-26 11:57:13 -0500235
236 CFReleaser<CFDictionaryRef> dict = (CFDictionaryRef)SCDynamicStoreCopyValue(m_scStore.get(), linkName.get());
237 if (dict.get() == nullptr) {
238 return InterfaceState::UNKNOWN;
239 }
240
241 CFBooleanRef isActive = (CFBooleanRef)CFDictionaryGetValue(dict.get(), CFSTR("Active"));
242 if (isActive == nullptr) {
243 return InterfaceState::UNKNOWN;
244 }
245
246 return CFBooleanGetValue(isActive) ? InterfaceState::RUNNING : InterfaceState::DOWN;
247}
248
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000249template<typename AddressBytes>
250static uint8_t
251computePrefixLength(const AddressBytes& mask)
252{
253 uint8_t prefixLength = 0;
254 for (auto byte : mask) {
255 while (byte != 0) {
256 ++prefixLength;
257 byte <<= 1;
258 }
259 }
260 return prefixLength;
261}
262
Alexander Afanasyev3b3355c2017-03-26 11:57:13 -0500263void
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000264NetworkMonitorImplOsx::updateInterfaceInfo(NetworkInterface& netif)
Alexander Afanasyev3b3355c2017-03-26 11:57:13 -0500265{
266 ifaddrs* ifa_list = nullptr;
267 if (::getifaddrs(&ifa_list) < 0) {
268 BOOST_THROW_EXCEPTION(Error(std::string("getifaddrs() failed: ") + strerror(errno)));
269 }
270
271 for (ifaddrs* ifa = ifa_list; ifa != nullptr; ifa = ifa->ifa_next) {
272 if (ifa->ifa_name != netif.getName()) {
273 continue;
274 }
275
276 netif.setFlags(ifa->ifa_flags);
277 netif.setMtu(getInterfaceMtu(netif.getName()));
278
279 if (ifa->ifa_addr == nullptr)
280 continue;
281
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000282 namespace ip = boost::asio::ip;
283 AddressFamily addressFamily = AddressFamily::UNSPECIFIED;
284 ip::address ipAddr, broadcast;
285 uint8_t prefixLength = 0;
286
Alexander Afanasyev3b3355c2017-03-26 11:57:13 -0500287
288 switch (ifa->ifa_addr->sa_family) {
289 case AF_INET: {
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000290 addressFamily = AddressFamily::V4;
Alexander Afanasyev3b3355c2017-03-26 11:57:13 -0500291
292 const sockaddr_in* sin = reinterpret_cast<sockaddr_in*>(ifa->ifa_addr);
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000293 ip::address_v4::bytes_type bytes;
Alexander Afanasyev3b3355c2017-03-26 11:57:13 -0500294 std::copy_n(reinterpret_cast<const unsigned char*>(&sin->sin_addr), bytes.size(), bytes.begin());
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000295 ipAddr = ip::address_v4(bytes);
Alexander Afanasyev3b3355c2017-03-26 11:57:13 -0500296
297 const sockaddr_in* sinMask = reinterpret_cast<sockaddr_in*>(ifa->ifa_netmask);
298 std::copy_n(reinterpret_cast<const unsigned char*>(&sinMask->sin_addr), bytes.size(), bytes.begin());
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000299 prefixLength = computePrefixLength(bytes);
Alexander Afanasyev3b3355c2017-03-26 11:57:13 -0500300 break;
301 }
302
303 case AF_INET6: {
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000304 addressFamily = AddressFamily::V6;
Alexander Afanasyev3b3355c2017-03-26 11:57:13 -0500305
306 const sockaddr_in6* sin6 = reinterpret_cast<sockaddr_in6*>(ifa->ifa_addr);
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000307 ip::address_v6::bytes_type bytes;
Alexander Afanasyev3b3355c2017-03-26 11:57:13 -0500308 std::copy_n(reinterpret_cast<const unsigned char*>(&sin6->sin6_addr), bytes.size(), bytes.begin());
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000309 ipAddr = ip::address_v6(bytes);
Alexander Afanasyev3b3355c2017-03-26 11:57:13 -0500310
311 const sockaddr_in6* sinMask = reinterpret_cast<sockaddr_in6*>(ifa->ifa_netmask);
312 std::copy_n(reinterpret_cast<const unsigned char*>(&sinMask->sin6_addr), bytes.size(), bytes.begin());
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000313 prefixLength = computePrefixLength(bytes);
Alexander Afanasyev3b3355c2017-03-26 11:57:13 -0500314 break;
315 }
316
317 case AF_LINK: {
318 const sockaddr_dl* sdl = reinterpret_cast<sockaddr_dl*>(ifa->ifa_addr);
319 netif.setIndex(sdl->sdl_index);
320 if (sdl->sdl_type == IFT_ETHER && sdl->sdl_alen == ethernet::ADDR_LEN) {
321 netif.setType(InterfaceType::ETHERNET);
322 netif.setEthernetAddress(ethernet::Address(reinterpret_cast<uint8_t*>(LLADDR(sdl))));
323 NDN_LOG_TRACE(netif.getName() << ": set Ethernet address " << netif.getEthernetAddress());
324 }
325 else if (sdl->sdl_type == IFT_LOOP) {
326 netif.setType(InterfaceType::LOOPBACK);
327 }
328 else {
329 netif.setType(InterfaceType::UNKNOWN);
330 }
331 break;
332 }
333
334 default:
335 continue;
336 }
337
338 if (netif.canBroadcast() && ifa->ifa_broadaddr != nullptr) {
339 const sockaddr_in* sin = reinterpret_cast<sockaddr_in*>(ifa->ifa_broadaddr);
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000340 ip::address_v4::bytes_type bytes;
Alexander Afanasyev3b3355c2017-03-26 11:57:13 -0500341 std::copy_n(reinterpret_cast<const unsigned char*>(&sin->sin_addr), bytes.size(), bytes.begin());
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000342 broadcast = ip::address_v4(bytes);
343 NDN_LOG_TRACE(netif.getName() << ": set IPv4 broadcast address " << broadcast);
Alexander Afanasyev3b3355c2017-03-26 11:57:13 -0500344 }
345
346 if (netif.canBroadcast()) {
347 netif.setEthernetBroadcastAddress(ethernet::getBroadcastAddress());
348 }
349
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000350 netif.addNetworkAddress(NetworkAddress(addressFamily, ipAddr, broadcast, prefixLength,
351 AddressScope::NOWHERE, 0));
352 ///\todo #3817 extract AddressScope from OS
Alexander Afanasyev3b3355c2017-03-26 11:57:13 -0500353 }
354
355 ::freeifaddrs(ifa_list);
356}
357
358size_t
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000359NetworkMonitorImplOsx::getInterfaceMtu(const std::string& ifName)
Alexander Afanasyev3b3355c2017-03-26 11:57:13 -0500360{
361 ifreq ifr{};
362 std::strncpy(ifr.ifr_name, ifName.c_str(), sizeof(ifr.ifr_name) - 1);
363
364 if (::ioctl(m_nullUdpSocket.native_handle(), SIOCGIFMTU, &ifr) == 0) {
365 return static_cast<size_t>(ifr.ifr_mtu);
366 }
367
368 NDN_LOG_WARN("Failed to get interface MTU: " << std::strerror(errno));
369 return ethernet::MAX_DATA_LEN;
370}
371
372void
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000373NetworkMonitorImplOsx::onConfigChanged(SCDynamicStoreRef m_scStore, CFArrayRef changedKeys, void* context)
Alexander Afanasyev3b3355c2017-03-26 11:57:13 -0500374{
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000375 static_cast<NetworkMonitorImplOsx*>(context)->onConfigChanged(changedKeys);
Alexander Afanasyev3b3355c2017-03-26 11:57:13 -0500376}
377
378void
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000379NetworkMonitorImplOsx::onConfigChanged(CFArrayRef changedKeys)
Alexander Afanasyev3b3355c2017-03-26 11:57:13 -0500380{
381 size_t count = CFArrayGetCount(changedKeys);
382 for (size_t i = 0; i != count; ++i) {
383 std::string keyName = convertToStdString((CFStringRef)CFArrayGetValueAtIndex(changedKeys, i));
384 Name key(keyName);
385 std::string ifName = key.at(-2).toUri();
386
387 auto ifIt = m_interfaces.find(ifName);
388 if (ifIt == m_interfaces.end()) {
389 addNewInterface(ifName);
390 return;
391 }
392
393 NetworkInterface& netif = *ifIt->second;
394
395 auto removeInterface = [&] {
396 NDN_LOG_DEBUG("removing interface " << ifName);
397 shared_ptr<NetworkInterface> removedInterface = ifIt->second;
398 m_interfaces.erase(ifIt);
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000399 this->emitSignal(onInterfaceRemoved, removedInterface);
Alexander Afanasyev3b3355c2017-03-26 11:57:13 -0500400 };
401
402 if (key.at(-1).toUri() == "Link") {
403 auto newState = getInterfaceState(ifName);
404
405 if (newState == InterfaceState::UNKNOWN) {
406 // check if it is really unknown or interface removed
407 if (getInterfaceNames().count(ifName) == 0) {
408 // newState = InterfaceState::DOWN;
409 removeInterface();
410 return;
411 }
412 }
413
414 NDN_LOG_TRACE("Status of " << ifName << " changed from " << netif.getState() << " to " << newState);
415 netif.setState(newState);
416 }
417
418 if (key.at(-1).toUri() == "IPv4" || key.at(-1).toUri() == "IPv6") {
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000419 shared_ptr<NetworkInterface> updatedInterface = makeNetworkInterface();
420 updatedInterface->setName(ifName);
421 updateInterfaceInfo(*updatedInterface);
422 if (updatedInterface->getType() == InterfaceType::UNKNOWN) {
Alexander Afanasyev3b3355c2017-03-26 11:57:13 -0500423 // somehow, type of interface changed to unknown
424 NDN_LOG_DEBUG("Removing " << ifName << " because it changed to unhandled interface type");
425 removeInterface();
426 return;
427 }
428
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000429 const auto& newAddrs = updatedInterface->getNetworkAddresses();
Alexander Afanasyev3b3355c2017-03-26 11:57:13 -0500430 const auto& oldAddrs = netif.getNetworkAddresses();
431
432 std::set<NetworkAddress> added;
433 std::set<NetworkAddress> removed;
434
435 std::set_difference(newAddrs.begin(), newAddrs.end(),
436 oldAddrs.begin(), oldAddrs.end(), std::inserter(added, added.end()));
437
438 std::set_difference(oldAddrs.begin(), oldAddrs.end(),
439 newAddrs.begin(), newAddrs.end(), std::inserter(removed, removed.end()));
440
441 for (const auto& addr : removed) {
442 netif.removeNetworkAddress(addr);
443 }
444
445 for (const auto& addr : added) {
446 netif.addNetworkAddress(addr);
447 }
448 }
449 }
450}
451
Junxiao Shi25467942017-06-30 02:53:14 +0000452} // namespace net
Davide Pesavento9a8bae52016-02-24 20:33:08 +0100453} // namespace ndn