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> 68 #include <boost/range/adaptor/map.hpp> 69 #include <boost/range/algorithm_ext/push_back.hpp> 76 using detail::CFReleaser;
83 if (::getifaddrs(&m_ifaList) < 0) {
90 if (m_ifaList !=
nullptr) {
91 ::freeifaddrs(m_ifaList);
102 ifaddrs* m_ifaList =
nullptr;
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)) {
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());
169 boost::push_back(v, m_interfaces | boost::adaptors::map_values);
174 NetworkMonitorImplOsx::afterNotificationCenterEvent(CFNotificationCenterRef center,
178 CFDictionaryRef userInfo)
184 NetworkMonitorImplOsx::scheduleCfLoop()
187 m_cfLoopEvent = m_scheduler.
schedule(1_s, [
this] {
189 CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0,
true);
195 NetworkMonitorImplOsx::enumerateInterfaces()
198 for (
const auto& ifName : getInterfaceNames()) {
199 addNewInterface(ifName, ifaList);
204 std::set<std::string>
205 NetworkMonitorImplOsx::getInterfaceNames()
const 208 (CFDictionaryRef)SCDynamicStoreCopyValue(m_scStore.
get(), CFSTR(
"State:/Network/Interface"));
209 if (dict.
get() ==
nullptr) {
213 CFArrayRef interfaces = (CFArrayRef)CFDictionaryGetValue(dict.
get(), CFSTR(
"Interfaces"));
214 if (interfaces ==
nullptr) {
218 std::set<std::string> ifNames;
219 size_t count = CFArrayGetCount(interfaces);
220 for (
size_t i = 0; i != count; ++i) {
221 auto ifName = (CFStringRef)CFArrayGetValueAtIndex(interfaces, i);
228 NetworkMonitorImplOsx::addNewInterface(
const std::string& ifName,
const IfAddrs& ifaList)
231 interface->setName(ifName);
232 interface->setState(getInterfaceState(*interface));
233 updateInterfaceInfo(*interface, ifaList);
236 NDN_LOG_DEBUG(
"ignoring " << ifName <<
" due to unhandled interface type");
241 m_interfaces[interface->getName()] = interface;
246 NetworkMonitorImplOsx::getInterfaceState(
const NetworkInterface& netif)
const 252 (CFDictionaryRef)SCDynamicStoreCopyValue(m_scStore.
get(), linkName.
get());
253 if (dict.get() ==
nullptr) {
257 CFBooleanRef isActive = (CFBooleanRef)CFDictionaryGetValue(dict.get(), CFSTR(
"Active"));
258 if (isActive ==
nullptr) {
269 std::strncpy(ifr.ifr_name, netif.
getName().data(),
sizeof(ifr.ifr_name) - 1);
271 if (::ioctl(m_ioctlSocket.native_handle(), SIOCGIFMTU, &ifr) == 0) {
272 return static_cast<size_t>(ifr.ifr_mtu);
279 template<
typename AddressBytes>
283 uint8_t prefixLength = 0;
284 for (
auto byte : mask) {
296 BOOST_ASSERT(!netif.
getName().empty());
298 netif.
setMtu(getInterfaceMtu(netif));
300 for (ifaddrs* ifa = ifaList.
get(); ifa !=
nullptr; ifa = ifa->ifa_next) {
301 if (ifa->ifa_name != netif.
getName())
306 if (ifa->ifa_addr ==
nullptr)
309 namespace ip = boost::asio::ip;
311 ip::address ipAddr, broadcastAddr;
312 uint8_t prefixLength = 0;
314 switch (ifa->ifa_addr->sa_family) {
318 const sockaddr_in* sin =
reinterpret_cast<sockaddr_in*
>(ifa->ifa_addr);
319 ip::address_v4::bytes_type bytes;
320 std::copy_n(reinterpret_cast<const unsigned char*>(&sin->sin_addr), bytes.size(), bytes.begin());
321 ipAddr = ip::address_v4(bytes);
323 const sockaddr_in* sinMask =
reinterpret_cast<sockaddr_in*
>(ifa->ifa_netmask);
324 std::copy_n(reinterpret_cast<const unsigned char*>(&sinMask->sin_addr), bytes.size(), bytes.begin());
332 const sockaddr_in6* sin6 =
reinterpret_cast<sockaddr_in6*
>(ifa->ifa_addr);
333 ip::address_v6::bytes_type bytes;
334 std::copy_n(reinterpret_cast<const unsigned char*>(&sin6->sin6_addr), bytes.size(), bytes.begin());
335 ip::address_v6 v6Addr(bytes);
336 if (v6Addr.is_link_local())
337 v6Addr.scope_id(if_nametoindex(netif.
getName().data()));
340 const sockaddr_in6* sinMask =
reinterpret_cast<sockaddr_in6*
>(ifa->ifa_netmask);
341 std::copy_n(reinterpret_cast<const unsigned char*>(&sinMask->sin6_addr), bytes.size(), bytes.begin());
347 const sockaddr_dl* sdl =
reinterpret_cast<sockaddr_dl*
>(ifa->ifa_addr);
355 else if (sdl->sdl_type == IFT_LOOP) {
369 const sockaddr_in* sin =
reinterpret_cast<sockaddr_in*
>(ifa->ifa_broadaddr);
370 ip::address_v4::bytes_type bytes;
371 std::copy_n(reinterpret_cast<const unsigned char*>(&sin->sin_addr), bytes.size(), bytes.begin());
372 broadcastAddr = ip::address_v4(bytes);
380 if (ipAddr.is_loopback()) {
383 else if ((ipAddr.is_v4() && (ipAddr.to_v4().to_ulong() & 0xFFFF0000) == 0xA9FE0000) ||
384 (ipAddr.is_v6() && ipAddr.to_v6().is_link_local())) {
393 NetworkMonitorImplOsx::onConfigChanged(SCDynamicStoreRef m_scStore, CFArrayRef changedKeys,
void* context)
399 NetworkMonitorImplOsx::onConfigChanged(CFArrayRef changedKeys)
403 size_t count = CFArrayGetCount(changedKeys);
404 for (
size_t i = 0; i != count; ++i) {
406 std::string ifName = key.
at(-2).
toUri();
408 auto ifIt = m_interfaces.find(ifName);
409 if (ifIt == m_interfaces.end()) {
410 addNewInterface(ifName, ifaList);
414 auto removeInterface = [&] {
416 shared_ptr<NetworkInterface> removedNetif = ifIt->second;
417 m_interfaces.erase(ifIt);
422 std::string changedItem = key.
at(-1).
toUri();
423 if (changedItem ==
"Link") {
424 auto newState = getInterfaceState(netif);
427 if (getInterfaceNames().count(ifName) == 0) {
435 else if (changedItem ==
"IPv4" || changedItem ==
"IPv6") {
437 updatedNetif->setName(ifName);
438 updateInterfaceInfo(*updatedNetif, ifaList);
445 const auto& newAddrs = updatedNetif->getNetworkAddresses();
447 std::set<NetworkAddress> added;
448 std::set<NetworkAddress> removed;
449 std::set_difference(newAddrs.begin(), newAddrs.end(),
450 oldAddrs.begin(), oldAddrs.end(), std::inserter(added, added.end()));
451 std::set_difference(oldAddrs.begin(), oldAddrs.end(),
452 newAddrs.begin(), newAddrs.end(), std::inserter(removed, removed.end()));
454 for (
const auto& addr : removed) {
457 for (
const auto& addr : added) {
interface is administratively down
CFReleaser< CFStringRef > fromStdString(const std::string &str)
Create a CFString by copying characters from a std::string.
This file contains utilities to deal with Apple Core Foundation's CFString and related types...
Copyright (c) 2011-2015 Regents of the University of California.
std::string toStdString(CFStringRef cfStr)
Convert a CFString to a std::string.
InterfaceState getState() const
Returns the current state of the interface.
interface is in an unknown state
interface can be used to send and receive packets
void setState(InterfaceState state)
static shared_ptr< NetworkInterface > makeNetworkInterface()
std::string getName() const
Returns the name of the interface, unique on the system.
const size_t ADDR_LEN
Octets in one Ethernet address.
#define NDN_LOG_WARN(expression)
void setMtu(uint32_t mtu)
NetworkMonitorImplOsx(boost::asio::io_service &io)
#define NDN_LOG_DEBUG(expression)
#define emitSignal(...)
(implementation detail)
InterfaceState
Indicates the state of a network interface.
bool canBroadcast() const
Returns true if the interface supports broadcast communication.
void setEthernetAddress(const ethernet::Address &address)
EventId schedule(time::nanoseconds after, EventCallback callback)
Schedule a one-time event after the specified delay.
void setEthernetBroadcastAddress(const ethernet::Address &address)
util::Signal< NetworkMonitorImpl > onEnumerationCompleted
Represents one network interface attached to the host.
const Component & at(ssize_t i) const
Returns an immutable reference to the component at the specified index, with bounds checking...
NetworkMonitor::Error Error
Stores one IP address supported by a network interface.
Address getBroadcastAddress()
Returns the Ethernet broadcast address (ff:ff:ff:ff:ff:ff)
std::vector< shared_ptr< const NetworkInterface > > listNetworkInterfaces() const final
bool removeNetworkAddress(const NetworkAddress &address)
util::Signal< NetworkMonitorImpl, shared_ptr< const NetworkInterface > > onInterfaceRemoved
void setFlags(uint32_t flags)
Represents an absolute name.
#define NDN_LOG_TRACE(expression)
util::Signal< NetworkMonitorImpl, shared_ptr< const NetworkInterface > > onInterfaceAdded
Helper class to wrap CoreFoundation object pointers.
bool addNetworkAddress(const NetworkAddress &address)
shared_ptr< const NetworkInterface > getNetworkInterface(const std::string &ifname) const final
represents an Ethernet hardware address
ifaddrs * get() const noexcept
ethernet::Address getEthernetAddress() const
Returns the link-layer (Ethernet) address of the interface.
#define NDN_LOG_INIT(name)
declare a log module
util::Signal< NetworkMonitorImpl > onNetworkStateChanged
void setType(InterfaceType type)
const size_t MAX_DATA_LEN
Max octets in Ethernet payload.
const std::set< NetworkAddress > & getNetworkAddresses() const
Returns a list of all network-layer addresses present on the interface.
#define NDN_THROW_ERRNO(e)
void toUri(std::ostream &os, UriFormat format=UriFormat::DEFAULT) const
Write *this to the output stream, escaping characters according to the NDN URI format.
static uint8_t computePrefixLength(const AddressBytes &mask)