blob: da162d3629ef941fe5fc11eb93981485e487b7d4 [file] [log] [blame]
Davide Pesavento9a8bae52016-02-24 20:33:08 +01001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Davide Pesaventob2ae3362017-07-13 01:43:14 -04002/*
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) {
Davide Pesaventob2ae3362017-07-13 01:43:14 -0400274 if (ifa->ifa_name != netif.getName())
Alexander Afanasyev3b3355c2017-03-26 11:57:13 -0500275 continue;
Alexander Afanasyev3b3355c2017-03-26 11:57:13 -0500276
277 netif.setFlags(ifa->ifa_flags);
278 netif.setMtu(getInterfaceMtu(netif.getName()));
279
280 if (ifa->ifa_addr == nullptr)
281 continue;
282
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000283 namespace ip = boost::asio::ip;
Davide Pesaventob2ae3362017-07-13 01:43:14 -0400284 AddressFamily addrFamily = AddressFamily::UNSPECIFIED;
285 ip::address ipAddr, broadcastAddr;
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000286 uint8_t prefixLength = 0;
287
Alexander Afanasyev3b3355c2017-03-26 11:57:13 -0500288 switch (ifa->ifa_addr->sa_family) {
289 case AF_INET: {
Davide Pesaventob2ae3362017-07-13 01:43:14 -0400290 addrFamily = 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: {
Davide Pesaventob2ae3362017-07-13 01:43:14 -0400304 addrFamily = 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);
Davide Pesaventob2ae3362017-07-13 01:43:14 -0400320
Alexander Afanasyev3b3355c2017-03-26 11:57:13 -0500321 if (sdl->sdl_type == IFT_ETHER && sdl->sdl_alen == ethernet::ADDR_LEN) {
322 netif.setType(InterfaceType::ETHERNET);
323 netif.setEthernetAddress(ethernet::Address(reinterpret_cast<uint8_t*>(LLADDR(sdl))));
324 NDN_LOG_TRACE(netif.getName() << ": set Ethernet address " << netif.getEthernetAddress());
325 }
326 else if (sdl->sdl_type == IFT_LOOP) {
327 netif.setType(InterfaceType::LOOPBACK);
328 }
329 else {
330 netif.setType(InterfaceType::UNKNOWN);
331 }
332 break;
333 }
Alexander Afanasyev3b3355c2017-03-26 11:57:13 -0500334 }
335
336 if (netif.canBroadcast()) {
337 netif.setEthernetBroadcastAddress(ethernet::getBroadcastAddress());
Davide Pesaventob2ae3362017-07-13 01:43:14 -0400338
339 if (addrFamily == AddressFamily::V4 && ifa->ifa_broadaddr != nullptr) {
340 const sockaddr_in* sin = reinterpret_cast<sockaddr_in*>(ifa->ifa_broadaddr);
341 ip::address_v4::bytes_type bytes;
342 std::copy_n(reinterpret_cast<const unsigned char*>(&sin->sin_addr), bytes.size(), bytes.begin());
343 broadcastAddr = ip::address_v4(bytes);
344 NDN_LOG_TRACE(netif.getName() << ": set IPv4 broadcast address " << broadcastAddr);
345 }
Alexander Afanasyev3b3355c2017-03-26 11:57:13 -0500346 }
347
Davide Pesaventob2ae3362017-07-13 01:43:14 -0400348 AddressScope scope = AddressScope::GLOBAL;
349 if (ipAddr.is_loopback()) {
350 scope = AddressScope::HOST;
351 }
352 else if ((ipAddr.is_v4() && (ipAddr.to_v4().to_ulong() & 0xFFFF0000) == 0xA9FE0000) ||
353 (ipAddr.is_v6() && ipAddr.to_v6().is_link_local())) {
354 scope = AddressScope::LINK;
355 }
356
357 netif.addNetworkAddress(NetworkAddress(addrFamily, ipAddr, broadcastAddr, prefixLength, scope, 0));
Alexander Afanasyev3b3355c2017-03-26 11:57:13 -0500358 }
359
360 ::freeifaddrs(ifa_list);
361}
362
363size_t
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000364NetworkMonitorImplOsx::getInterfaceMtu(const std::string& ifName)
Alexander Afanasyev3b3355c2017-03-26 11:57:13 -0500365{
366 ifreq ifr{};
367 std::strncpy(ifr.ifr_name, ifName.c_str(), sizeof(ifr.ifr_name) - 1);
368
369 if (::ioctl(m_nullUdpSocket.native_handle(), SIOCGIFMTU, &ifr) == 0) {
370 return static_cast<size_t>(ifr.ifr_mtu);
371 }
372
373 NDN_LOG_WARN("Failed to get interface MTU: " << std::strerror(errno));
374 return ethernet::MAX_DATA_LEN;
375}
376
377void
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000378NetworkMonitorImplOsx::onConfigChanged(SCDynamicStoreRef m_scStore, CFArrayRef changedKeys, void* context)
Alexander Afanasyev3b3355c2017-03-26 11:57:13 -0500379{
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000380 static_cast<NetworkMonitorImplOsx*>(context)->onConfigChanged(changedKeys);
Alexander Afanasyev3b3355c2017-03-26 11:57:13 -0500381}
382
383void
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000384NetworkMonitorImplOsx::onConfigChanged(CFArrayRef changedKeys)
Alexander Afanasyev3b3355c2017-03-26 11:57:13 -0500385{
386 size_t count = CFArrayGetCount(changedKeys);
387 for (size_t i = 0; i != count; ++i) {
388 std::string keyName = convertToStdString((CFStringRef)CFArrayGetValueAtIndex(changedKeys, i));
389 Name key(keyName);
390 std::string ifName = key.at(-2).toUri();
391
392 auto ifIt = m_interfaces.find(ifName);
393 if (ifIt == m_interfaces.end()) {
394 addNewInterface(ifName);
395 return;
396 }
397
398 NetworkInterface& netif = *ifIt->second;
399
400 auto removeInterface = [&] {
401 NDN_LOG_DEBUG("removing interface " << ifName);
402 shared_ptr<NetworkInterface> removedInterface = ifIt->second;
403 m_interfaces.erase(ifIt);
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000404 this->emitSignal(onInterfaceRemoved, removedInterface);
Alexander Afanasyev3b3355c2017-03-26 11:57:13 -0500405 };
406
407 if (key.at(-1).toUri() == "Link") {
408 auto newState = getInterfaceState(ifName);
409
410 if (newState == InterfaceState::UNKNOWN) {
411 // check if it is really unknown or interface removed
412 if (getInterfaceNames().count(ifName) == 0) {
413 // newState = InterfaceState::DOWN;
414 removeInterface();
415 return;
416 }
417 }
418
419 NDN_LOG_TRACE("Status of " << ifName << " changed from " << netif.getState() << " to " << newState);
420 netif.setState(newState);
421 }
422
423 if (key.at(-1).toUri() == "IPv4" || key.at(-1).toUri() == "IPv6") {
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000424 shared_ptr<NetworkInterface> updatedInterface = makeNetworkInterface();
425 updatedInterface->setName(ifName);
426 updateInterfaceInfo(*updatedInterface);
427 if (updatedInterface->getType() == InterfaceType::UNKNOWN) {
Alexander Afanasyev3b3355c2017-03-26 11:57:13 -0500428 // somehow, type of interface changed to unknown
429 NDN_LOG_DEBUG("Removing " << ifName << " because it changed to unhandled interface type");
430 removeInterface();
431 return;
432 }
433
Junxiao Shi2dc416d2017-07-03 04:46:16 +0000434 const auto& newAddrs = updatedInterface->getNetworkAddresses();
Alexander Afanasyev3b3355c2017-03-26 11:57:13 -0500435 const auto& oldAddrs = netif.getNetworkAddresses();
436
437 std::set<NetworkAddress> added;
438 std::set<NetworkAddress> removed;
439
440 std::set_difference(newAddrs.begin(), newAddrs.end(),
441 oldAddrs.begin(), oldAddrs.end(), std::inserter(added, added.end()));
442
443 std::set_difference(oldAddrs.begin(), oldAddrs.end(),
444 newAddrs.begin(), newAddrs.end(), std::inserter(removed, removed.end()));
445
446 for (const auto& addr : removed) {
447 netif.removeNetworkAddress(addr);
448 }
449
450 for (const auto& addr : added) {
451 netif.addNetworkAddress(addr);
452 }
453 }
454 }
455}
456
Junxiao Shi25467942017-06-30 02:53:14 +0000457} // namespace net
Davide Pesavento9a8bae52016-02-24 20:33:08 +0100458} // namespace ndn