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