LCOV - code coverage report
Current view: top level - DCPS - LinuxNetworkConfigMonitor.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 131 210 62.4 %
Date: 2023-04-30 01:32:43 Functions: 12 14 85.7 %

          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

Generated by: LCOV version 1.16