NS-3 based Named Data Networking (NDN) simulator
ndnSIM 2.0: NDN, CCN, CCNx, content centric networks
API Documentation
network-monitor.cpp
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
53 #include "ndn-cxx-config.hpp"
54 
55 #include "network-monitor.hpp"
56 #include "scheduler.hpp"
58 
59 #if defined(NDN_CXX_HAVE_COREFOUNDATION_COREFOUNDATION_H)
60 
61 #include <CoreFoundation/CoreFoundation.h>
62 #include <SystemConfiguration/SystemConfiguration.h>
63 
64 namespace ndn {
65 namespace util {
66 
67 class NetworkMonitor::Impl
68 {
69 public:
70  Impl(boost::asio::io_service& io)
71  : scheduler(io)
72  , cfLoopEvent(scheduler)
73  {
74  }
75 
76  void
77  scheduleCfLoop()
78  {
79  // poll each second for new events
80  cfLoopEvent = scheduler.scheduleEvent(time::seconds(1), bind(&Impl::pollCfLoop, this));
81  }
82 
83  static void
84  afterNotificationCenterEvent(CFNotificationCenterRef center, void *observer, CFStringRef name,
85  const void *object, CFDictionaryRef userInfo)
86  {
87  static_cast<NetworkMonitor*>(observer)->onNetworkStateChanged();
88  }
89 
90 private:
91 
92  void
93  pollCfLoop()
94  {
95  // this should dispatch ready events and exit
96  CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, true);
97  scheduleCfLoop();
98  }
99 
100 private:
101  Scheduler scheduler;
102  scheduler::ScopedEventId cfLoopEvent;
103 };
104 
105 NetworkMonitor::NetworkMonitor(boost::asio::io_service& io)
106  : m_impl(new Impl(io))
107 {
108  m_impl->scheduleCfLoop();
109 
110  // Potentially useful System Configuration regex patterns:
111  //
112  // State:/Network/Interface/.*/Link
113  // State:/Network/Interface/.*/IPv4
114  // State:/Network/Interface/.*/IPv6
115  //
116  // State:/Network/Global/DNS
117  // State:/Network/Global/IPv4
118  //
119  // Potentially useful notifications from Darwin Notify Center:
120  //
121  // com.apple.system.config.network_change
122 
123  // network change observations
124  CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(),
125  static_cast<void*>(this),
126  &NetworkMonitor::Impl::afterNotificationCenterEvent,
127  CFSTR("com.apple.system.config.network_change"),
128  nullptr, // object to observe
129  CFNotificationSuspensionBehaviorDeliverImmediately);
130 }
131 
132 NetworkMonitor::~NetworkMonitor()
133 {
134  CFNotificationCenterRemoveEveryObserver(CFNotificationCenterGetDarwinNotifyCenter(),
135  static_cast<void*>(this));
136 }
137 
138 } // namespace util
139 } // namespace ndn
140 
141 // done with defined(NDN_CXX_HAVE_COREFOUNDATION_COREFOUNDATION_H)
142 #elif defined(NDN_CXX_HAVE_RTNETLINK)
143 
144 #include <boost/asio.hpp>
145 
146 #include <netinet/in.h>
147 #include <linux/netlink.h>
148 #include <linux/rtnetlink.h>
149 #include <net/if.h>
150 
151 #include <cerrno>
152 #include <cstring>
153 
154 namespace ndn {
155 namespace util {
156 
157 const size_t NETLINK_BUFFER_SIZE = 4096;
158 
159 class NetworkMonitor::Impl
160 {
161 public:
162  Impl(NetworkMonitor& nm, boost::asio::io_service& io)
163  : m_nm(nm)
164  , m_socket(io)
165  {
166  int fd = ::socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
167  if (fd < 0)
168  BOOST_THROW_EXCEPTION(Error(std::string("Cannot create netlink socket (") +
169  std::strerror(errno) + ")"));
170 
171  sockaddr_nl addr{};
172  addr.nl_family = AF_NETLINK;
173  addr.nl_groups = RTMGRP_LINK |
174  RTMGRP_IPV4_IFADDR | RTMGRP_IPV4_ROUTE |
175  RTMGRP_IPV6_IFADDR | RTMGRP_IPV6_ROUTE;
176 
177  if (::bind(fd, reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) == -1) {
178  BOOST_THROW_EXCEPTION(Error(std::string("Cannot bind on netlink socket (") +
179  std::strerror(errno) + ")"));
180  }
181 
182  m_socket.assign(fd);
183 
184  m_socket.async_read_some(boost::asio::buffer(m_buffer, NETLINK_BUFFER_SIZE),
185  bind(&Impl::onReceiveRtNetlink, this, _1, _2));
186  }
187 
188 private:
189  void
190  onReceiveRtNetlink(const boost::system::error_code& error, size_t nBytesReceived)
191  {
192  if (error) {
193  return;
194  }
195 
196  const nlmsghdr* nlh = reinterpret_cast<const nlmsghdr*>(m_buffer);
197  while ((NLMSG_OK(nlh, nBytesReceived)) && (nlh->nlmsg_type != NLMSG_DONE)) {
198  if (nlh->nlmsg_type == RTM_NEWADDR || nlh->nlmsg_type == RTM_DELADDR ||
199  nlh->nlmsg_type == RTM_NEWLINK || nlh->nlmsg_type == RTM_DELLINK ||
200  nlh->nlmsg_type == RTM_NEWROUTE || nlh->nlmsg_type == RTM_DELROUTE) {
201  m_nm.onNetworkStateChanged();
202  break;
203  }
204  nlh = NLMSG_NEXT(nlh, nBytesReceived);
205  }
206 
207  m_socket.async_read_some(boost::asio::buffer(m_buffer, NETLINK_BUFFER_SIZE),
208  bind(&Impl::onReceiveRtNetlink, this, _1, _2));
209  }
210 
211 private:
212  NetworkMonitor& m_nm;
213  uint8_t m_buffer[NETLINK_BUFFER_SIZE];
214 
215  boost::asio::posix::stream_descriptor m_socket;
216 };
217 
218 
219 
220 NetworkMonitor::NetworkMonitor(boost::asio::io_service& io)
221  : m_impl(new Impl(*this, io))
222 {
223 }
224 
225 NetworkMonitor::~NetworkMonitor()
226 {
227 }
228 
229 } // namespace util
230 } // namespace ndn
231 
232 // done with defined(NDN_CXX_HAVE_RTNETLINK)
233 #else // do not support network monitoring operations
234 
235 namespace ndn {
236 namespace util {
237 
239 {
240 };
241 
242 NetworkMonitor::NetworkMonitor(boost::asio::io_service&)
243 {
244  BOOST_THROW_EXCEPTION(Error("Network monitoring is not supported on this platform"));
245 }
246 
248 {
249 }
250 
251 } // namespace util
252 } // namespace ndn
253 
254 #endif // do not support network monitoring operations
Copyright (c) 2011-2015 Regents of the University of California.
NetworkMonitor(boost::asio::io_service &io)
Construct instance and start monitoring for network state changes.
Signal< NetworkMonitor > onNetworkStateChanged
~NetworkMonitor()
Terminate network state monitoring.