LCOV - code coverage report
Current view: top level - DCPS/RTPS - GuidGenerator.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 32 48 66.7 %
Date: 2023-04-30 01:32:43 Functions: 4 4 100.0 %

          Line data    Source code
       1             : /*
       2             :  * Distributed under the OpenDDS License.
       3             :  * See: http://www.opendds.org/license.html
       4             :  */
       5             : 
       6             : #include "GuidGenerator.h"
       7             : 
       8             : #include <dds/DCPS/GuidUtils.h>
       9             : #include <dds/DCPS/TimeTypes.h>
      10             : #include <dds/DCPS/debug.h>
      11             : 
      12             : #include <dds/DdsDcpsGuidTypeSupportImpl.h>
      13             : 
      14             : #include <ace/OS_NS_unistd.h>
      15             : #include <ace/OS_NS_stdlib.h>
      16             : #include <ace/OS_NS_netdb.h>
      17             : #include <ace/OS_NS_sys_socket.h>
      18             : #include <ace/OS_NS_sys_time.h>
      19             : #include <ace/Log_Msg.h>
      20             : #include <ace/os_include/net/os_if.h>
      21             : 
      22             : #include <cstring>
      23             : 
      24             : #ifdef ACE_HAS_CPP11
      25             : #  include <random>
      26             : #endif
      27             : 
      28             : #ifdef ACE_LINUX
      29             : #  include <sys/types.h>
      30             : #  include <ifaddrs.h>
      31             : #endif
      32             : 
      33             : #if defined ACE_WIN32 && !defined ACE_HAS_WINCE
      34             : #  include <winsock2.h>
      35             : #  include <iphlpapi.h>
      36             : #  include <ace/Version.h>
      37             : #endif
      38             : 
      39             : #ifdef ACE_VXWORKS
      40             : #  include <ace/os_include/sys/os_sysctl.h>
      41             : #  include <net/route.h>
      42             : #endif
      43             : 
      44             : OPENDDS_BEGIN_VERSIONED_NAMESPACE_DECL
      45             : 
      46             : namespace OpenDDS {
      47             : namespace RTPS {
      48             : 
      49             : using DCPS::SystemTimePoint;
      50             : 
      51           5 : GuidGenerator::GuidGenerator()
      52           5 :   : pid_(ACE_OS::getpid())
      53             : {
      54           5 :   unsigned seed = static_cast<unsigned>(SystemTimePoint::now().value().usec() + reinterpret_cast<size_t>(this));
      55             : 
      56           5 :   if (pid_ == -1) {
      57           0 :     pid_ = static_cast<pid_t>(ACE_OS::rand_r(&seed));
      58             :   }
      59             : 
      60             : #ifdef ACE_HAS_CPP11
      61           5 :   std::mt19937 generator(seed);
      62           5 :   std::uniform_int_distribution<ACE_UINT16> distribution(0, ACE_UINT16_MAX);
      63           5 :   counter_ = distribution(generator);
      64             : #else
      65             :   counter_ = static_cast<ACE_UINT16>(ACE_OS::rand_r(&seed));
      66             : #endif
      67             : 
      68             :   ACE_OS::macaddr_node_t macaddress;
      69           5 :   const int result = ACE_OS::getmacaddress(&macaddress);
      70             : 
      71             : #ifndef ACE_HAS_IOS
      72           5 :   if (-1 != result) {
      73           5 :     ACE_OS::memcpy(node_id_, macaddress.node, NODE_ID_SIZE);
      74             :   } else {
      75           0 :     for (int i = 0; i < NODE_ID_SIZE; ++i) {
      76           0 :       node_id_[i] = static_cast<unsigned char>(ACE_OS::rand_r(&seed));
      77             :     }
      78             :   }
      79             : #else
      80             :   // iOS has non-unique MAC addresses
      81             :   ACE_UNUSED_ARG(result);
      82             : 
      83             :   for (int i = 0; i < NODE_ID_SIZE; ++i) {
      84             :     node_id_[i] = static_cast<unsigned char>(ACE_OS::rand_r(&seed));
      85             :   }
      86             : #endif /* ACE_HAS_IOS */
      87           5 : }
      88             : 
      89             : ACE_UINT16
      90          93 : GuidGenerator::getCount(bool doIncrement)
      91             : {
      92          93 :   ACE_Guard<ACE_Thread_Mutex> guard(counter_lock_);
      93          93 :   if (doIncrement) {
      94          90 :     ++counter_;
      95             :   }
      96          93 :   return counter_;
      97          93 : }
      98             : 
      99             : int
     100           2 : GuidGenerator::interfaceName(const char* iface)
     101             : {
     102             :   // A shortcut to determine if a *valid* interface was already checked.
     103             :   // The shortcut value (interface_name_) is stored IFF the method returns 0.
     104           2 :   if (interface_name_ == iface) {
     105           0 :     return 0;
     106             :   }
     107             : 
     108             :   // See ace/OS_NS_netdb.cpp ACE_OS::getmacaddress()
     109             : #if defined ACE_WIN32 && !defined ACE_HAS_WINCE
     110             :   ULONG size;
     111             :   if (::GetAdaptersAddresses(AF_UNSPEC, 0, 0, 0, &size)
     112             :       != ERROR_BUFFER_OVERFLOW) {
     113             :     return -1;
     114             :   }
     115             :   ACE_Allocator* const alloc = DCPS::SafetyProfilePool::instance();
     116             :   IP_ADAPTER_ADDRESSES* const addrs =
     117             :     static_cast<IP_ADAPTER_ADDRESSES*>(alloc->malloc(size));
     118             :   if (!addrs) {
     119             :     return -1;
     120             :   }
     121             :   if (::GetAdaptersAddresses(AF_UNSPEC, 0, 0, addrs, &size) != NO_ERROR) {
     122             :     alloc->free(addrs);
     123             :     return -1;
     124             :   }
     125             : 
     126             :   bool found = false;
     127             :   for (IP_ADAPTER_ADDRESSES* iter = addrs; iter && !found; iter = iter->Next) {
     128             :     if (ACE_Wide_To_Ascii(iter->FriendlyName).char_rep() == iface) {
     129             :       std::memcpy(node_id_, iter->PhysicalAddress,
     130             :                   std::min(static_cast<size_t>(iter->PhysicalAddressLength),
     131             :                            sizeof node_id_));
     132             :       found = true;
     133             :     }
     134             :   }
     135             : 
     136             :   alloc->free(addrs);
     137             :   if (found) {
     138             :     interface_name_ = iface;
     139             :     return 0;
     140             :   } else {
     141             :     return -1;
     142             :   }
     143             : 
     144             : #elif defined ACE_LINUX || defined ACE_ANDROID
     145             :   ifreq ifr;
     146             :   // Guarantee that iface will fit in ifr.ifr_name and still be null terminated
     147             :   // ifr.ifr_name is sized to IFNAMSIZ
     148           2 :   if (std::strlen(iface) >= sizeof(ifr.ifr_name)) {
     149           2 :     if (DCPS::log_level >= DCPS::LogLevel::Error) {
     150           0 :       ACE_ERROR((LM_ERROR, "(%P|%t) ERROR: GuidGenerator::interfaceName: "
     151             :         "Interface name %C exceeds max allowable length, must be < %d.\n",
     152             :         iface, IFNAMSIZ));
     153             :     }
     154           2 :     return -1;
     155             :   }
     156           0 :   std::strncpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name));
     157           0 :   const ACE_HANDLE h = ACE_OS::socket(PF_INET, SOCK_DGRAM, 0);
     158           0 :   if (h == ACE_INVALID_HANDLE) {
     159           0 :     return -1;
     160             :   }
     161           0 :   if (ACE_OS::ioctl(h, SIOCGIFHWADDR, &ifr) < 0) {
     162           0 :     ACE_OS::close(h);
     163           0 :     return -1;
     164             :   }
     165           0 :   ACE_OS::close(h);
     166           0 :   std::memcpy(node_id_, ifr.ifr_addr.sa_data, sizeof node_id_);
     167             : 
     168           0 :   interface_name_ = iface;
     169           0 :   return 0;
     170             : #elif defined ACE_HAS_SIOCGIFCONF || defined ACE_HAS_MAC_OSX
     171             :   const ACE_HANDLE h = ACE_OS::socket(AF_INET, SOCK_DGRAM, 0);
     172             :   if (h == ACE_INVALID_HANDLE) {
     173             :     return -1;
     174             :   }
     175             : 
     176             :   const int BUFFERSIZE = 4000;
     177             :   char buffer[BUFFERSIZE];
     178             :   ifconf ifc;
     179             :   ifc.ifc_len = BUFFERSIZE;
     180             :   ifc.ifc_buf = buffer;
     181             : 
     182             :   if (ACE_OS::ioctl(h, SIOCGIFCONF, &ifc) < 0) {
     183             :     ACE_OS::close(h);
     184             :     return -1;
     185             :   }
     186             : 
     187             :   bool found = false;
     188             :   for (const char* ptr = buffer; !found && ptr < buffer + ifc.ifc_len;) {
     189             :     const ifreq* ifr = reinterpret_cast<const ifreq*>(ptr);
     190             :     if (ifr->ifr_addr.sa_family == AF_LINK && ifr->ifr_name == interface_name_) {
     191             :       const sockaddr_dl* sdl =
     192             :         reinterpret_cast<const sockaddr_dl*>(&ifr->ifr_addr);
     193             :       std::memcpy(node_id_, LLADDR(sdl), sizeof node_id_);
     194             :       found = true;
     195             :     }
     196             : 
     197             :     ptr += sizeof ifr->ifr_name + std::max(sizeof ifr->ifr_addr,
     198             :       static_cast<size_t>(ifr->ifr_addr.sa_len));
     199             :   }
     200             : 
     201             :   ACE_OS::close(h);
     202             : 
     203             :   if (found) {
     204             :     interface_name_ = iface;
     205             :     return 0;
     206             :   } else {
     207             :     return -1;
     208             :   }
     209             : #elif defined ACE_VXWORKS
     210             :   int name[] = {CTL_NET, AF_ROUTE, 0, 0, NET_RT_IFLIST, 0};
     211             :   static const size_t name_elts = sizeof name / sizeof name[0];
     212             : 
     213             :   size_t result_sz = 0u;
     214             :   if (sysctl(name, name_elts, 0, &result_sz, 0, 0u) != 0) {
     215             :     return -1;
     216             :   }
     217             : 
     218             :   ACE_Allocator* const alloc = DCPS::SafetyProfilePool::instance();
     219             :   char* const result = static_cast<char*>(alloc->malloc(result_sz));
     220             : 
     221             :   if (sysctl(name, name_elts, result, &result_sz, 0, 0u) != 0) {
     222             :     alloc->free(result);
     223             :     return -1;
     224             :   }
     225             : 
     226             :   for (size_t pos = 0, n; pos + sizeof(if_msghdr) < result_sz; pos += n) {
     227             :     if_msghdr* const hdr = reinterpret_cast<if_msghdr*>(result + pos);
     228             :     n = hdr->ifm_msglen;
     229             :     sockaddr_dl* const addr =
     230             :       reinterpret_cast<sockaddr_dl*>(result + pos + sizeof(if_msghdr));
     231             : 
     232             :     if (hdr->ifm_type == RTM_IFINFO && (hdr->ifm_addrs & RTA_IFP)
     233             :         && std::memcmp(addr->sdl_data, iface, addr->sdl_nlen) == 0
     234             :         && addr->sdl_alen >= sizeof node_id_) {
     235             :       std::memcpy(node_id_, LLADDR(addr), sizeof node_id_);
     236             :       alloc->free(result);
     237             : 
     238             :       interface_name_ = iface;
     239             :       return 0;
     240             :     }
     241             : 
     242             :     while (pos + n < result_sz) {
     243             :       if_msghdr* const nxt = reinterpret_cast<if_msghdr*>(result + pos + n);
     244             :       if (nxt->ifm_type != RTM_NEWADDR) {
     245             :         break;
     246             :       }
     247             :       n += nxt->ifm_msglen;
     248             :     }
     249             :   }
     250             : 
     251             :   alloc->free(result);
     252             :   return -1;
     253             : #else
     254             :   return -1;
     255             : #endif
     256             : }
     257             : 
     258             : void
     259          90 : GuidGenerator::populate(DCPS::GUID_t &container)
     260             : {
     261          90 :   container.guidPrefix[0] = DCPS::VENDORID_OCI[0];
     262          90 :   container.guidPrefix[1] = DCPS::VENDORID_OCI[1];
     263             : 
     264          90 :   const ACE_UINT16 count = getCount();
     265          90 :   ACE_OS::memcpy(&container.guidPrefix[2], node_id_, NODE_ID_SIZE);
     266          90 :   container.guidPrefix[8] = static_cast<CORBA::Octet>(pid_ >> 8);
     267          90 :   container.guidPrefix[9] = static_cast<CORBA::Octet>(pid_ & 0xFF);
     268          90 :   container.guidPrefix[10] = static_cast<CORBA::Octet>(count >> 8);
     269          90 :   container.guidPrefix[11] = static_cast<CORBA::Octet>(count & 0xFF);
     270          90 : }
     271             : 
     272             : } // namespace RTPS
     273             : } // namespace OpenDDS
     274             : 
     275             : OPENDDS_END_VERSIONED_NAMESPACE_DECL

Generated by: LCOV version 1.16