55 #include "../network-address.hpp" 56 #include "../../name.hpp" 57 #include "../../util/logger.hpp" 61 #include <net/if_dl.h> 62 #include <net/if_types.h> 63 #include <netinet/in.h> 65 #include <boost/asio/io_service.hpp> 66 #include <boost/asio/ip/address.hpp> 67 #include <boost/asio/ip/udp.hpp> 72 using util::CFReleaser;
81 if (::getifaddrs(&m_ifaList) < 0) {
89 if (m_ifaList !=
nullptr) {
90 ::freeifaddrs(m_ifaList);
101 ifaddrs* m_ifaList =
nullptr;
106 , m_cfLoopEvent(m_scheduler)
107 , m_context{0,
this,
nullptr,
nullptr,
nullptr}
108 , m_scStore(SCDynamicStoreCreate(
nullptr, CFSTR(
"net.named-data.ndn-cxx.NetworkMonitor"),
109 &NetworkMonitorImplOsx::onConfigChanged, &m_context))
110 , m_loopSource(SCDynamicStoreCreateRunLoopSource(
nullptr, m_scStore.get(), 0))
111 , m_ioctlSocket(io, boost::asio::ip::udp::v4())
119 CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(),
120 static_cast<void*>(
this),
121 &NetworkMonitorImplOsx::afterNotificationCenterEvent,
122 CFSTR(
"com.apple.system.config.network_change"),
124 CFNotificationSuspensionBehaviorDeliverImmediately);
126 CFRunLoopAddSource(CFRunLoopGetCurrent(), m_loopSource.get(), kCFRunLoopDefaultMode);
137 auto patterns = CFArrayCreateMutable(
nullptr, 0, &kCFTypeArrayCallBacks);
138 CFArrayAppendValue(patterns, CFSTR(
"State:/Network/Interface/.*/Link"));
139 CFArrayAppendValue(patterns, CFSTR(
"State:/Network/Interface/.*/IPv4"));
140 CFArrayAppendValue(patterns, CFSTR(
"State:/Network/Interface/.*/IPv6"));
142 if (!SCDynamicStoreSetNotificationKeys(m_scStore.get(),
nullptr, patterns)) {
143 BOOST_THROW_EXCEPTION(Error(
"SCDynamicStoreSetNotificationKeys failed"));
146 io.post([
this] { enumerateInterfaces(); });
151 CFRunLoopRemoveSource(CFRunLoopGetCurrent(), m_loopSource.
get(), kCFRunLoopDefaultMode);
153 CFNotificationCenterRemoveEveryObserver(CFNotificationCenterGetDarwinNotifyCenter(),
154 static_cast<void*>(
this));
157 shared_ptr<const NetworkInterface>
160 auto it = m_interfaces.find(ifname);
161 return it == m_interfaces.end() ? nullptr : it->second;
164 std::vector<shared_ptr<const NetworkInterface>>
167 std::vector<shared_ptr<const NetworkInterface>> v;
168 v.reserve(m_interfaces.size());
170 for (
const auto& e : m_interfaces) {
171 v.push_back(e.second);
177 NetworkMonitorImplOsx::afterNotificationCenterEvent(CFNotificationCenterRef center,
181 CFDictionaryRef userInfo)
187 NetworkMonitorImplOsx::scheduleCfLoop()
192 CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0,
true);
198 NetworkMonitorImplOsx::enumerateInterfaces()
201 for (
const auto& ifName : getInterfaceNames()) {
202 addNewInterface(ifName, ifaList);
210 const char* cStr = CFStringGetCStringPtr(cfStr, kCFStringEncodingASCII);
211 if (cStr !=
nullptr) {
217 std::string str(CFStringGetLength(cfStr) + 1,
'\0');
218 if (!CFStringGetCString(cfStr, &str.front(), str.size(), kCFStringEncodingASCII)) {
227 std::set<std::string>
228 NetworkMonitorImplOsx::getInterfaceNames()
const 230 CFReleaser<CFDictionaryRef> dict =
231 (CFDictionaryRef)SCDynamicStoreCopyValue(m_scStore.
get(), CFSTR(
"State:/Network/Interface"));
232 if (dict.get() ==
nullptr) {
236 CFArrayRef interfaces = (CFArrayRef)CFDictionaryGetValue(dict.get(), CFSTR(
"Interfaces"));
237 if (interfaces ==
nullptr) {
241 std::set<std::string> ifNames;
242 size_t count = CFArrayGetCount(interfaces);
243 for (
size_t i = 0; i != count; ++i) {
244 auto ifName = (CFStringRef)CFArrayGetValueAtIndex(interfaces, i);
251 NetworkMonitorImplOsx::addNewInterface(
const std::string& ifName,
const IfAddrs& ifaList)
254 interface->setName(ifName);
255 interface->setState(getInterfaceState(*interface));
256 updateInterfaceInfo(*interface, ifaList);
259 NDN_LOG_DEBUG(
"ignoring " << ifName <<
" due to unhandled interface type");
264 m_interfaces[interface->getName()] = interface;
269 NetworkMonitorImplOsx::getInterfaceState(
const NetworkInterface& netif)
const 271 CFReleaser<CFStringRef> linkName =
272 CFStringCreateWithCString(kCFAllocatorDefault,
273 (
"State:/Network/Interface/" + netif.getName() +
"/Link").data(),
274 kCFStringEncodingASCII);
276 CFReleaser<CFDictionaryRef> dict =
277 (CFDictionaryRef)SCDynamicStoreCopyValue(m_scStore.
get(), linkName.get());
278 if (dict.get() ==
nullptr) {
282 CFBooleanRef isActive = (CFBooleanRef)CFDictionaryGetValue(dict.get(), CFSTR(
"Active"));
283 if (isActive ==
nullptr) {
291 NetworkMonitorImplOsx::getInterfaceMtu(
const NetworkInterface& netif)
294 std::strncpy(ifr.ifr_name, netif.getName().data(),
sizeof(ifr.ifr_name) - 1);
296 if (::ioctl(m_ioctlSocket.native_handle(), SIOCGIFMTU, &ifr) == 0) {
297 return static_cast<size_t>(ifr.ifr_mtu);
300 NDN_LOG_WARN(
"failed to get MTU of " << netif.getName() <<
": " << std::strerror(errno));
304 template<
typename AddressBytes>
308 uint8_t prefixLength = 0;
309 for (
auto byte : mask) {
319 NetworkMonitorImplOsx::updateInterfaceInfo(NetworkInterface& netif,
const IfAddrs& ifaList)
321 BOOST_ASSERT(!netif.getName().empty());
323 netif.setMtu(getInterfaceMtu(netif));
325 for (ifaddrs* ifa = ifaList.get(); ifa !=
nullptr; ifa = ifa->ifa_next) {
326 if (ifa->ifa_name != netif.getName())
329 netif.setFlags(ifa->ifa_flags);
331 if (ifa->ifa_addr ==
nullptr)
334 namespace ip = boost::asio::ip;
336 ip::address ipAddr, broadcastAddr;
337 uint8_t prefixLength = 0;
339 switch (ifa->ifa_addr->sa_family) {
343 const sockaddr_in* sin =
reinterpret_cast<sockaddr_in*
>(ifa->ifa_addr);
344 ip::address_v4::bytes_type bytes;
345 std::copy_n(reinterpret_cast<const unsigned char*>(&sin->sin_addr), bytes.size(), bytes.begin());
346 ipAddr = ip::address_v4(bytes);
348 const sockaddr_in* sinMask =
reinterpret_cast<sockaddr_in*
>(ifa->ifa_netmask);
349 std::copy_n(reinterpret_cast<const unsigned char*>(&sinMask->sin_addr), bytes.size(), bytes.begin());
357 const sockaddr_in6* sin6 =
reinterpret_cast<sockaddr_in6*
>(ifa->ifa_addr);
358 ip::address_v6::bytes_type bytes;
359 std::copy_n(reinterpret_cast<const unsigned char*>(&sin6->sin6_addr), bytes.size(), bytes.begin());
360 ip::address_v6 v6Addr(bytes);
361 if (v6Addr.is_link_local())
362 v6Addr.scope_id(if_nametoindex(netif.getName().data()));
365 const sockaddr_in6* sinMask =
reinterpret_cast<sockaddr_in6*
>(ifa->ifa_netmask);
366 std::copy_n(reinterpret_cast<const unsigned char*>(&sinMask->sin6_addr), bytes.size(), bytes.begin());
372 const sockaddr_dl* sdl =
reinterpret_cast<sockaddr_dl*
>(ifa->ifa_addr);
373 netif.setIndex(sdl->sdl_index);
377 netif.setEthernetAddress(ethernet::Address(reinterpret_cast<uint8_t*>(LLADDR(sdl))));
378 NDN_LOG_TRACE(netif.getName() <<
" has Ethernet address " << netif.getEthernetAddress());
380 else if (sdl->sdl_type == IFT_LOOP) {
390 if (netif.canBroadcast()) {
394 const sockaddr_in* sin =
reinterpret_cast<sockaddr_in*
>(ifa->ifa_broadaddr);
395 ip::address_v4::bytes_type bytes;
396 std::copy_n(reinterpret_cast<const unsigned char*>(&sin->sin_addr), bytes.size(), bytes.begin());
397 broadcastAddr = ip::address_v4(bytes);
405 if (ipAddr.is_loopback()) {
408 else if ((ipAddr.is_v4() && (ipAddr.to_v4().to_ulong() & 0xFFFF0000) == 0xA9FE0000) ||
409 (ipAddr.is_v6() && ipAddr.to_v6().is_link_local())) {
413 netif.addNetworkAddress(NetworkAddress(addrFamily, ipAddr, broadcastAddr, prefixLength, scope, 0));
418 NetworkMonitorImplOsx::onConfigChanged(SCDynamicStoreRef m_scStore, CFArrayRef changedKeys,
void* context)
424 NetworkMonitorImplOsx::onConfigChanged(CFArrayRef changedKeys)
428 size_t count = CFArrayGetCount(changedKeys);
429 for (
size_t i = 0; i != count; ++i) {
431 std::string ifName = key.at(-2).toUri();
433 auto ifIt = m_interfaces.find(ifName);
434 if (ifIt == m_interfaces.end()) {
435 addNewInterface(ifName, ifaList);
439 auto removeInterface = [&] {
441 shared_ptr<NetworkInterface> removedNetif = ifIt->second;
442 m_interfaces.erase(ifIt);
446 NetworkInterface& netif = *ifIt->second;
447 std::string changedItem = key.at(-1).toUri();
448 if (changedItem ==
"Link") {
449 auto newState = getInterfaceState(netif);
452 if (getInterfaceNames().count(ifName) == 0) {
457 NDN_LOG_TRACE(ifName <<
" status changed from " << netif.getState() <<
" to " << newState);
458 netif.setState(newState);
460 else if (changedItem ==
"IPv4" || changedItem ==
"IPv6") {
462 updatedNetif->setName(ifName);
463 updateInterfaceInfo(*updatedNetif, ifaList);
470 const auto& newAddrs = updatedNetif->getNetworkAddresses();
471 const auto& oldAddrs = netif.getNetworkAddresses();
472 std::set<NetworkAddress> added;
473 std::set<NetworkAddress> removed;
474 std::set_difference(newAddrs.begin(), newAddrs.end(),
475 oldAddrs.begin(), oldAddrs.end(), std::inserter(added, added.end()));
476 std::set_difference(oldAddrs.begin(), oldAddrs.end(),
477 newAddrs.begin(), newAddrs.end(), std::inserter(removed, removed.end()));
479 for (
const auto& addr : removed) {
480 netif.removeNetworkAddress(addr);
482 for (
const auto& addr : added) {
483 netif.addNetworkAddress(addr);
interface is administratively down
Copyright (c) 2011-2015 Regents of the University of California.
interface is in an unknown state
interface can be used to send and receive packets
static shared_ptr< NetworkInterface > makeNetworkInterface()
const size_t ADDR_LEN
Octets in one Ethernet address.
NetworkMonitorImplOsx(boost::asio::io_service &io)
#define emitSignal(...)
(implementation detail)
InterfaceState
Indicates the state of a network interface.
EventId scheduleEvent(const time::nanoseconds &after, const Event &event)
Schedule a one-time event after the specified delay.
util::Signal< NetworkMonitorImpl > onEnumerationCompleted
#define NDN_LOG_INIT(name)
declare a log module
Address getBroadcastAddress()
Returns the Ethernet broadcast address (ff:ff:ff:ff:ff:ff)
#define NDN_LOG_DEBUG(expression)
std::vector< shared_ptr< const NetworkInterface > > listNetworkInterfaces() const final
util::Signal< NetworkMonitorImpl, shared_ptr< const NetworkInterface > > onInterfaceRemoved
static std::string convertToStdString(CFStringRef cfStr)
util::Signal< NetworkMonitorImpl, shared_ptr< const NetworkInterface > > onInterfaceAdded
shared_ptr< const NetworkInterface > getNetworkInterface(const std::string &ifname) const final
#define NDN_LOG_WARN(expression)
util::Signal< NetworkMonitorImpl > onNetworkStateChanged
#define NDN_LOG_TRACE(expression)
const size_t MAX_DATA_LEN
Max octets in Ethernet payload.
static uint8_t computePrefixLength(const AddressBytes &mask)