OpenDDS  Snapshot(2023/04/28-20:55)
LinuxNetworkConfigMonitor.cpp
Go to the documentation of this file.
1 /*
2  *
3  *
4  * Distributed under the OpenDDS License.
5  * See: http://www.opendds.org/license.html
6  */
7 
8 #include "DCPS/DdsDcps_pch.h" //Only the _pch include should start with DCPS/
9 
10 #include "ace/config.h"
11 
13 
14 #ifdef OPENDDS_LINUX_NETWORK_CONFIG_MONITOR
15 
16 #include "ThreadStatusManager.h"
17 #include "Service_Participant.h"
18 
19 #include <ace/Netlink_Addr.h>
20 
21 #include <linux/rtnetlink.h>
22 #include <net/if.h>
23 
25 
26 namespace OpenDDS {
27 namespace DCPS {
28 
29 const size_t MAX_NETLINK_MESSAGE_SIZE = 4096;
30 
31 LinuxNetworkConfigMonitor::LinuxNetworkConfigMonitor(ReactorInterceptor_rch interceptor)
32  : interceptor_(interceptor)
33 {
34  reactor(interceptor->reactor());
35 }
36 
37 bool LinuxNetworkConfigMonitor::open()
38 {
39  ReactorInterceptor_rch interceptor = interceptor_.lock();
40  if (!interceptor) {
41  return false;
42  }
43 
44  RcHandle<OpenHandler> oh = make_rch<OpenHandler>(rchandle_from(this));
45  interceptor->execute_or_enqueue(oh);
46  return oh->wait();
47 }
48 
49 bool LinuxNetworkConfigMonitor::OpenHandler::wait() const
50 {
51  ACE_GUARD_RETURN(ACE_Thread_Mutex, g, mutex_, false);
52  while (!done_) {
53  condition_.wait(TheServiceParticipant->get_thread_status_manager());
54  }
55  return retval_;
56 }
57 
58 void LinuxNetworkConfigMonitor::OpenHandler::execute()
59 {
60  RcHandle<LinuxNetworkConfigMonitor> lncm = lncm_.lock();
61  if (!lncm) {
62  return;
63  }
64  ACE_GUARD(ACE_Thread_Mutex, g, mutex_);
65  retval_ = lncm->open_i();
66  done_ = true;
67  condition_.notify_all();
68 }
69 
70 bool LinuxNetworkConfigMonitor::open_i()
71 {
72  ACE_GUARD_RETURN(ACE_Thread_Mutex, g, socket_mutex_, false);
73 
74  // Listen to changes in links and IPV4 and IPV6 addresses.
75  const pid_t pid = 0;
76  ACE_Netlink_Addr addr;
77  addr.set(pid, RTMGRP_NOTIFY | RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR);
78  if (socket_.open(addr, AF_NETLINK, NETLINK_ROUTE) != 0) {
79 #ifdef ACE_ANDROID
80  if (log_level >= LogLevel::Warning) {
81  ACE_ERROR((LM_WARNING, "(%P|%t) WARNING: LinuxNetworkConfigMonitor::open_i: could not open socket"
82  " this is expected for API30+\n"));
83  }
84 #else
85  if (log_level >= LogLevel::Error) {
86  ACE_ERROR((LM_ERROR, "(%P|%t) ERROR: LinuxNetworkConfigMonitor::open_i: could not open socket: %m\n"));
87  }
88 #endif
89  return false;
90  }
91 
92  if (socket_.enable(ACE_NONBLOCK) != 0) {
93  if (log_level >= LogLevel::Error) {
94  ACE_ERROR((LM_ERROR, "(%P|%t) ERROR: LinuxNetworkConfigMonitor::open_i: could not set non-blocking: %m\n"));
95  }
96  return false;
97  }
98 
99  struct {
100  nlmsghdr header;
101  rtgenmsg msg;
102  } request;
103  memset(&request, 0, sizeof(request));
104 
105  // Request a dump of the links.
106  request.header.nlmsg_len = NLMSG_LENGTH(sizeof(request.msg));
107  request.header.nlmsg_type = RTM_GETLINK;
108  request.header.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
109  request.header.nlmsg_pid = pid;
110  request.msg.rtgen_family = AF_UNSPEC;
111 
112  if (socket_.send(&request, request.header.nlmsg_len, 0) != static_cast<ssize_t>(request.header.nlmsg_len)) {
113  if (log_level >= LogLevel::Error) {
114  ACE_ERROR((LM_ERROR, "(%P|%t) ERROR: LinuxNetworkConfigMonitor::open_i: could not send request for links: %m\n"));
115  }
116  return false;
117  }
118 
119  read_messages();
120 
121  // Request a dump of the addresses.
122  request.header.nlmsg_len = NLMSG_LENGTH(sizeof(request.msg));
123  request.header.nlmsg_type = RTM_GETADDR;
124  request.header.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
125  request.header.nlmsg_pid = pid;
126  request.msg.rtgen_family = AF_UNSPEC;
127 
128  if (socket_.send(&request, request.header.nlmsg_len, 0) != static_cast<ssize_t>(request.header.nlmsg_len)) {
129  if (log_level >= LogLevel::Error) {
130  ACE_ERROR((LM_ERROR, "(%P|%t) ERROR: LinuxNetworkConfigMonitor::open_i: could not send request for addresses: %m\n"));
131  }
132  return false;
133  }
134 
135  read_messages();
136 
137  if (reactor()->register_handler(this, READ_MASK) != 0) {
138  ACE_ERROR((LM_ERROR, ACE_TEXT("(%P|%t) ERROR: LinuxNetworkConfigMonitor::open_i: could not register for input: %m\n")));
139  }
140 
141  return true;
142 }
143 
144 bool LinuxNetworkConfigMonitor::close()
145 {
146  ReactorInterceptor_rch interceptor = interceptor_.lock();
147  if (!interceptor) {
148  return false;
149  }
150 
151  RcHandle<CloseHandler> ch = make_rch<CloseHandler>(rchandle_from(this));
152  interceptor->execute_or_enqueue(ch);
153  return ch->wait();
154 }
155 
156 bool LinuxNetworkConfigMonitor::CloseHandler::wait() const
157 {
158  ACE_GUARD_RETURN(ACE_Thread_Mutex, g, mutex_, false);
159  while (!done_) {
160  condition_.wait(TheServiceParticipant->get_thread_status_manager());
161  }
162  return retval_;
163 }
164 
165 void LinuxNetworkConfigMonitor::CloseHandler::execute()
166 {
167  RcHandle<LinuxNetworkConfigMonitor> lncm = lncm_.lock();
168  if (!lncm) {
169  return;
170  }
171  ACE_GUARD(ACE_Thread_Mutex, g, mutex_);
172  retval_ = lncm->close_i();
173  done_ = true;
174  condition_.notify_all();
175 }
176 
177 bool LinuxNetworkConfigMonitor::close_i()
178 {
179  ACE_GUARD_RETURN(ACE_Thread_Mutex, g, socket_mutex_, false);
180  reactor()->remove_handler(this, READ_MASK);
181 
182  if (socket_.close() != 0) {
183  if (log_level >= LogLevel::Error) {
184  ACE_ERROR((LM_ERROR, "(%P|%t) ERROR: LinuxNetworkConfigMonitor::close_i: could not close socket: %m\n"));
185  }
186 
187  return false;
188  }
189 
190  return true;
191 }
192 
193 ACE_HANDLE LinuxNetworkConfigMonitor::get_handle() const
194 {
195  return socket_.get_handle();
196 }
197 
198 int LinuxNetworkConfigMonitor::handle_input(ACE_HANDLE)
199 {
200  ThreadStatusManager::Event ev(TheServiceParticipant->get_thread_status_manager());
201 
202  ACE_GUARD_RETURN(ACE_Thread_Mutex, g, socket_mutex_, -1);
203  read_messages();
204  return 0;
205 }
206 
207 void LinuxNetworkConfigMonitor::read_messages()
208 {
209  char buffer[MAX_NETLINK_MESSAGE_SIZE];
210 
211  for (;;) {
212  ssize_t buffer_length;
213  {
214  if (socket_.get_handle() == -1) {
215  return;
216  }
217  buffer_length = socket_.recv(buffer, 4096, 0);
218  }
219  if (buffer_length < 0) {
220  if (errno == EAGAIN || errno == EWOULDBLOCK) {
221  return;
222  }
223  if (log_level >= LogLevel::Error) {
224  ACE_ERROR((LM_ERROR, "(%P|%t) ERROR: LinuxNetworkConfigMonitor::read_messages: could not recv: %m\n"));
225  }
226  return;
227  } else if (buffer_length == 0) {
228  return;
229  }
230 
231  for (const nlmsghdr* header = reinterpret_cast<const nlmsghdr*>(buffer);
232  buffer_length >= 0 && NLMSG_OK(header, static_cast<size_t>(buffer_length));
233  header = NLMSG_NEXT(header, buffer_length)) {
234  process_message(header);
235  }
236  }
237 }
238 
239 void LinuxNetworkConfigMonitor::process_message(const nlmsghdr* header)
240 {
241  switch (header->nlmsg_type) {
242  case NLMSG_ERROR:
243  {
244  const nlmsgerr* msg = reinterpret_cast<nlmsgerr*>(NLMSG_DATA(header));
245  if (log_level >= LogLevel::Error) {
246  ACE_ERROR((LM_ERROR, "(%P|%t) ERROR: LinuxNetworkConfigMonitor::process_message: NETLINK error: %C\n", strerror(-msg->error)));
247  }
248  }
249  break;
250  case RTM_NEWADDR:
251  {
252  const ifaddrmsg* msg = reinterpret_cast<ifaddrmsg*>(NLMSG_DATA(header));
253  size_t address_length = 0;
254  switch (msg->ifa_family) {
255  case AF_INET:
256  address_length = 4;
257  break;
258  case AF_INET6:
259  address_length = 16;
260  break;
261  default:
262  return;
263  }
264  int rta_length = IFA_PAYLOAD(header);
265  for (const rtattr* attr = reinterpret_cast<const rtattr*>(IFA_RTA(msg));
266  RTA_OK(attr, rta_length);
267  attr = RTA_NEXT(attr, rta_length)) {
268  if (attr->rta_type == IFA_ADDRESS) {
269  if (RTA_PAYLOAD(attr) != address_length) {
270  if (log_level >= LogLevel::Warning) {
271  ACE_ERROR((LM_WARNING, "(%P|%t) WARNING: LinuxNetworkConfigMonitor::process_message: incorrect address byte count\n"));
272  }
273  return;
274  }
275  ACE_INET_Addr addr;
276  addr.set_address(reinterpret_cast<const char*>(RTA_DATA(attr)), address_length, 0);
277  NetworkInterfaceMap::const_iterator pos = network_interface_map_.find(msg->ifa_index);
278  if (pos != network_interface_map_.end()) {
279  set(NetworkInterfaceAddress(pos->second.name, pos->second.can_multicast, NetworkAddress(addr)));
280  } else if (log_level >= LogLevel::Warning) {
281  ACE_ERROR((LM_WARNING, "(%P|%t) WARNING: LinuxNetworkConfigMonitor::process_message: cannot find interface for address\n"));
282  }
283  }
284  }
285  }
286  break;
287  case RTM_DELADDR:
288  {
289  const ifaddrmsg* msg = reinterpret_cast<ifaddrmsg*>(NLMSG_DATA(header));
290  size_t address_length = 0;
291  switch (msg->ifa_family) {
292  case AF_INET:
293  address_length = 4;
294  break;
295  case AF_INET6:
296  address_length = 16;
297  break;
298  default:
299  return;
300  }
301  int rta_length = IFA_PAYLOAD(header);
302  for (const rtattr* attr = reinterpret_cast<const rtattr*>(IFA_RTA(msg));
303  RTA_OK(attr, rta_length);
304  attr = RTA_NEXT(attr, rta_length)) {
305  if (attr->rta_type == IFA_ADDRESS) {
306  if (RTA_PAYLOAD(attr) != address_length) {
307  if (log_level >= LogLevel::Warning) {
308  ACE_ERROR((LM_WARNING, "(%P|%t) WARNING: LinuxNetworkConfigMonitor::process_message: incorrect address byte count\n"));
309  }
310  return;
311  }
312 
313  NetworkInterfaceMap::iterator pos = network_interface_map_.find(msg->ifa_index);
314  if (pos != network_interface_map_.end()) {
315  ACE_INET_Addr addr;
316  addr.set_address(reinterpret_cast<const char*>(RTA_DATA(attr)), address_length, 0);
317  remove_address(pos->second.name, NetworkAddress(addr));
318  }
319  }
320  }
321  }
322  break;
323  case RTM_NEWLINK:
324  {
326  const ifinfomsg* msg = reinterpret_cast<ifinfomsg*>(NLMSG_DATA(header));
327  int rta_length = IFLA_PAYLOAD(header);
328  for (const rtattr* attr = reinterpret_cast<const rtattr*>(IFLA_RTA(msg));
329  RTA_OK(attr, rta_length);
330  attr = RTA_NEXT(attr, rta_length)) {
331  if (attr->rta_type == IFLA_IFNAME) {
332  name = reinterpret_cast<const char*>(RTA_DATA(attr));
333  }
334  }
335 
336  // Clean up the old if necessary.
337  NetworkInterfaceMap::iterator pos = network_interface_map_.find(msg->ifi_index);
338  if (pos != network_interface_map_.end()) {
339  remove_interface(pos->second.name);
340  network_interface_map_.erase(pos);
341  }
342  network_interface_map_[msg->ifi_index] = NetworkInterface(name, msg->ifi_flags & (IFF_MULTICAST | IFF_LOOPBACK));
343  }
344  break;
345  case RTM_DELLINK:
346  {
347  const ifinfomsg* msg = reinterpret_cast<ifinfomsg*>(NLMSG_DATA(header));
348  NetworkInterfaceMap::iterator pos = network_interface_map_.find(msg->ifi_index);
349  if (pos != network_interface_map_.end()) {
350  remove_interface(pos->second.name);
351  network_interface_map_.erase(pos);
352  }
353  }
354  break;
355  }
356 }
357 
358 } // DCPS
359 } // OpenDDS
360 
362 
363 #endif // OPENDDS_LINUX_NETWORK_CONFIG_MONITOR
RcHandle< T > rchandle_from(T *pointer)
Definition: RcHandle_T.h:310
#define ACE_ERROR(X)
#define ACE_GUARD(MUTEX, OBJ, LOCK)
char * strerror(int errnum)
CommandPtr execute_or_enqueue(CommandPtr command)
int ssize_t
#define OPENDDS_STRING
#define AF_UNSPEC
Christopher Diggins *renamed files *fixing compilation errors *adding Visual C project file *removed make Max Lybbert *removed references to missing and unused header
Definition: CHANGELOG.txt:8
#define ACE_GUARD_RETURN(MUTEX, OBJ, LOCK, RETURN)
int set_address(const char *ip_addr, int len, int encode=1, int map=0)
#define AF_INET
const char *const name
Definition: debug.cpp:60
ACE_TEXT("TCP_Factory")
OpenDDS_Dcps_Export LogLevel log_level
RcHandle< ReactorInterceptor > ReactorInterceptor_rch
void * memset(void *s, int c, size_t len)
#define OPENDDS_END_VERSIONED_NAMESPACE_DECL
#define TheServiceParticipant
The Internal API and Implementation of OpenDDS.
Definition: AddressCache.h:28