LCOV - code coverage report
Current view: top level - DCPS - NetworkResource.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 124 249 49.8 %
Date: 2023-04-30 01:32:43 Functions: 10 20 50.0 %

          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 "NetworkResource.h"
      11             : 
      12             : #include "LogAddr.h"
      13             : #include "TimeTypes.h"
      14             : 
      15             : #include <ace/OS_NS_netdb.h>
      16             : #include <ace/Sock_Connect.h>
      17             : #include <ace/OS_NS_sys_socket.h> // For setsockopt()
      18             : #include <ace/OS_NS_arpa_inet.h>
      19             : 
      20             : #include <cstdlib>
      21             : #include <cstring>
      22             : 
      23             : #if !defined (__ACE_INLINE__)
      24             : # include "NetworkResource.inl"
      25             : #endif /* !__ACE_INLINE__ */
      26             : 
      27             : ACE_BEGIN_VERSIONED_NAMESPACE_DECL
      28             : 
      29             : ACE_CDR::Boolean
      30           0 : operator<< (ACE_OutputCDR& outCdr, OpenDDS::DCPS::NetworkResource& value)
      31             : {
      32           0 :   return (outCdr << ACE_OutputCDR::from_boolean(ACE_CDR_BYTE_ORDER)) &&
      33           0 :          (outCdr << ACE_OutputCDR::from_octet(value.reserved_)) &&
      34           0 :          (outCdr << value.addr_.c_str());
      35             : }
      36             : 
      37             : ACE_CDR::Boolean
      38           0 : operator>> (ACE_InputCDR& inCdr, OpenDDS::DCPS::NetworkResource& value)
      39             : {
      40             :   CORBA::Boolean byte_order;
      41             : 
      42           0 :   if (!(inCdr >> ACE_InputCDR::to_boolean(byte_order)))
      43           0 :     return false;
      44             : 
      45           0 :   inCdr.reset_byte_order(byte_order);
      46             : 
      47           0 :   if (!(inCdr >> ACE_InputCDR::to_octet(value.reserved_)))
      48           0 :     return false;
      49             : 
      50           0 :   char* buf = 0;
      51             : 
      52           0 :   if (!(inCdr >> buf))
      53           0 :     return false;
      54             : 
      55           0 :   value.addr_ = buf;
      56             : 
      57           0 :   delete[] buf;
      58             : 
      59           0 :   return inCdr.good_bit();
      60             : }
      61             : 
      62             : ACE_END_VERSIONED_NAMESPACE_DECL
      63             : 
      64             : OPENDDS_BEGIN_VERSIONED_NAMESPACE_DECL
      65             : 
      66             : namespace OpenDDS {
      67             : namespace DCPS {
      68             : 
      69           2 : bool verify_hostname(const String& hostname, ACE_INET_Addr* addr_array, size_t addr_count,
      70             :                      bool prefer_loopback, bool allow_ipv4_fallback)
      71             : {
      72           2 :   const ACE_INET_Addr addr = choose_single_coherent_address(hostname, prefer_loopback, allow_ipv4_fallback);
      73           3 :   for (size_t i = 0; i < addr_count; ++i) {
      74           3 :     if (addr == addr_array[i]) {
      75           2 :       return true;
      76             :     }
      77             :   }
      78           0 :   return false;
      79           2 : }
      80             : 
      81           2 : String get_fully_qualified_hostname(ACE_INET_Addr* addr)
      82             : {
      83             :   // cache the determined fully qualified hostname and its
      84             :   // address to be used on subsequent calls
      85           2 :   static String fullname;
      86           2 :   static ACE_INET_Addr selected_address;
      87             : 
      88           2 :   if (fullname.length() == 0) {
      89             :     size_t addr_count;
      90           1 :     ACE_INET_Addr *addr_array = 0;
      91           1 :     OpenDDS::DCPS::HostnameInfoVector nonFQDN;
      92             : 
      93           1 :     const int result = ACE::get_ip_interfaces(addr_count, addr_array);
      94             : 
      95             :     struct Array_Guard {
      96           1 :       Array_Guard(ACE_INET_Addr *ptr) : ptr_(ptr) {}
      97           1 :       ~Array_Guard() {
      98          12 :         delete [] ptr_;
      99           1 :       }
     100             :       ACE_INET_Addr* const ptr_;
     101           1 :     } guardObject(addr_array);
     102             : 
     103           1 :     if (result != 0 || addr_count < 1) {
     104           0 :       ACE_ERROR((LM_ERROR,
     105             :                  ACE_TEXT("(%P|%t) ERROR: get_fully_qualified_hostname: Unable to probe network. %p\n"),
     106             :                  ACE_TEXT("ACE::get_ip_interfaces")));
     107             : 
     108           0 :     } else {
     109           5 :       for (size_t i = 0; i < addr_count; i++) {
     110           4 :         VDBG_LVL((LM_DEBUG, "(%P|%t) get_fully_qualified_hostname: Found IP interface %C\n", LogAddr::ip(addr_array[i]).c_str()), 4);
     111             :       }
     112             : 
     113             : #ifdef ACE_HAS_IPV6
     114             :       // Front load IPV6 addresses to give preference to IPV6 interfaces
     115             :       size_t index_last_non_ipv6 = 0;
     116             :       for (size_t i = 0; i < addr_count; i++) {
     117             :         if (addr_array[i].get_type() == AF_INET6) {
     118             :           if (i == index_last_non_ipv6) {
     119             :             ++index_last_non_ipv6;
     120             :           } else {
     121             :             std::swap(addr_array[i], addr_array[index_last_non_ipv6]);
     122             :             ++index_last_non_ipv6;
     123             :           }
     124             :         }
     125             :       }
     126             : #endif
     127           2 :       for (size_t i = 0; i < addr_count; i++) {
     128           2 :         char hostname[MAXHOSTNAMELEN+1] = "";
     129             : 
     130             :         // Discover the fully qualified hostname
     131           2 :         if (ACE::get_fqdn(addr_array[i], hostname, MAXHOSTNAMELEN+1) == 0) {
     132           2 :           VDBG_LVL((LM_DEBUG, "(%P|%t) get_fully_qualified_hostname: Considering fqdn %C\n", hostname), 4);
     133             :           // Find the first FQDN that resolves to an IP interface address.
     134           3 :           if (!addr_array[i].is_loopback() && ACE_OS::strchr(hostname, '.') != 0 &&
     135           3 :               verify_hostname(hostname, addr_array, addr_count, false, false)) {
     136           1 :             VDBG_LVL((LM_DEBUG, "(%P|%t) get_fully_qualified_hostname: Found fqdn %C from %C\n", hostname, LogAddr(addr_array[i]).c_str()), 2);
     137           1 :             selected_address = addr_array[i];
     138           1 :             fullname = hostname;
     139           1 :             if (addr) {
     140           0 :               *addr = selected_address;
     141             :             }
     142           2 :             return fullname;
     143             :           } else {
     144           1 :             VDBG_LVL((LM_DEBUG, "(%P|%t) get_fully_qualified_hostname: IP interface %C maps to hostname %C\n",
     145             :                       LogAddr(addr_array[i]).c_str(), hostname), 2);
     146             : 
     147           1 :             if (ACE_OS::strncmp(hostname, "localhost", 9) == 0) {
     148           1 :               addr_array[i].get_host_addr(hostname, MAXHOSTNAMELEN);
     149             :             }
     150             : 
     151           1 :             if (verify_hostname(hostname, addr_array, addr_count, false, true)) {
     152           1 :               OpenDDS::DCPS::HostnameInfo info;
     153           1 :               info.index_ = i;
     154           1 :               info.hostname_ = hostname;
     155           1 :               nonFQDN.push_back(info);
     156           1 :             }
     157             :           }
     158             :         }
     159             :       }
     160             :     }
     161             : 
     162           0 :     OpenDDS::DCPS::HostnameInfoVector::iterator itBegin = nonFQDN.begin();
     163           0 :     OpenDDS::DCPS::HostnameInfoVector::iterator itEnd = nonFQDN.end();
     164             : 
     165           0 :     for (OpenDDS::DCPS::HostnameInfoVector::iterator it = itBegin; it != itEnd; ++it) {
     166           0 :       if (!addr_array[it->index_].is_loopback()) {
     167           0 :         ACE_DEBUG((LM_WARNING, "(%P|%t) WARNING: get_fully_qualified_hostname: Could not find FQDN. Using "
     168             :                    "\"%C\" as fully qualified hostname, please "
     169             :                    "correct system configuration.\n", it->hostname_.c_str()));
     170           0 :         selected_address = addr_array[it->index_];
     171           0 :         fullname = it->hostname_;
     172           0 :         if (addr) {
     173           0 :           *addr = selected_address;
     174             :         }
     175           0 :         return fullname;
     176             :       }
     177             :     }
     178             : 
     179             :     // If no non-loopback IP is found from the above step, return a non-loopback
     180             :     // address from the IP interfaces list.
     181           0 :     for (size_t i = 0; i < addr_count; ++i) {
     182           0 :       if (!addr_array[i].is_loopback()) {
     183           0 :         char addr_str[MAXHOSTNAMELEN+1] = "";
     184           0 :         addr_array[i].get_host_addr(addr_str, MAXHOSTNAMELEN);
     185           0 :         ACE_DEBUG((LM_WARNING, "(%P|%t) WARNING: get_fully_qualified_hostname: Could not find FQDN. Using "
     186             :                    "\"%C\" as fully qualified hostname, please "
     187             :                    "correct system configuration.\n", addr_str));
     188           0 :         selected_address = addr_array[i];
     189           0 :         fullname = addr_str;
     190           0 :         if (addr) {
     191           0 :           *addr = selected_address;
     192             :         }
     193           0 :         return fullname;
     194             :       }
     195             :     }
     196             : 
     197             :     // As a last resort, return the first loopback address from the non-FQDNs list if not empty.
     198           0 :     if (itBegin != itEnd) {
     199           0 :       ACE_DEBUG((LM_WARNING, "(%P|%t) WARNING: get_fully_qualified_hostname: Could not find FQDN. Using "
     200             :                  "\"%C\" as fully qualified hostname, please "
     201             :                  "correct system configuration.\n", itBegin->hostname_.c_str()));
     202           0 :       selected_address = addr_array[itBegin->index_];
     203           0 :       fullname = itBegin->hostname_;
     204           0 :       if (addr) {
     205           0 :         *addr = selected_address;
     206             :       }
     207           0 :       return fullname;
     208             :     }
     209             : 
     210             : #ifdef OPENDDS_SAFETY_PROFILE
     211             :     // address resolution may not be available due to safety profile,
     212             :     // return an address that should work for running tests
     213             :     if (addr) {
     214             :       static const char local[] = {1, 0, 0, 127};
     215             :       addr->set_address(local, sizeof local);
     216             :     }
     217             :     return "localhost";
     218             : #else
     219           0 :     ACE_ERROR((LM_ERROR,
     220             :                "(%P|%t) ERROR: get_fully_qualified_hostname: Failed to discover the fully qualified hostname\n"));
     221             : #endif
     222           2 :   }
     223             : 
     224           1 :   if (addr) {
     225           0 :     *addr = selected_address;
     226             :   }
     227           1 :   return fullname;
     228             : }
     229             : 
     230           0 : void get_interface_addrs(OPENDDS_VECTOR(ACE_INET_Addr)& addrs)
     231             : {
     232           0 :   ACE_INET_Addr *if_addrs = 0;
     233           0 :   size_t if_cnt = 0;
     234           0 :   size_t endpoint_count = 0;
     235             : 
     236             :   int result =
     237             : #ifdef OPENDDS_SAFETY_PROFILE
     238             :     -1;
     239             : #else
     240           0 :     ACE::get_ip_interfaces(if_cnt, if_addrs);
     241             : #endif
     242             : 
     243             :   struct Array_Guard {
     244           0 :     Array_Guard(ACE_INET_Addr *ptr) : ptr_(ptr) {}
     245           0 :     ~Array_Guard() {
     246           0 :       delete[] ptr_;
     247           0 :     }
     248             :     ACE_INET_Addr* const ptr_;
     249           0 :   } guardObject(if_addrs);
     250             : 
     251           0 :   if (!result) {
     252           0 :     size_t lo_cnt = 0;  // Loopback interface count
     253             : #if defined (ACE_HAS_IPV6)
     254             :     size_t ipv4_cnt = 0;
     255             :     size_t ipv4_lo_cnt = 0;
     256             :     size_t ipv6_ll = 0;
     257             :     bool ipv6_non_ll = false;
     258             : #endif
     259           0 :     for (size_t j = 0; j < if_cnt; ++j) {
     260             :       // Scan for the loopback interface since it shouldn't be included in
     261             :       // the list of cached hostnames unless it is the only interface.
     262           0 :       if (if_addrs[j].is_loopback())
     263           0 :         ++lo_cnt;
     264             : #if defined (ACE_HAS_IPV6)
     265             :       // Scan for IPv4 interfaces since these should not be included
     266             :       // when IPv6-only is selected.
     267             :       if (if_addrs[j].get_type() != AF_INET6 ||
     268             :           if_addrs[j].is_ipv4_mapped_ipv6()) {
     269             :         ++ipv4_cnt;
     270             :         if (if_addrs[j].is_loopback())
     271             :           ++ipv4_lo_cnt;  // keep track of IPv4 loopback ifs
     272             :       } else if (!if_addrs[j].is_linklocal() &&
     273             :                  !if_addrs[j].is_loopback()) {
     274             :         ipv6_non_ll = true; // we have at least 1 non-local IPv6 if
     275             :       } else if (if_addrs[j].is_linklocal()) {
     276             :         ++ipv6_ll;  // count link local addrs to exclude them afterwards
     277             :       }
     278             : #endif /* ACE_HAS_IPV6 */
     279             :     }
     280             : 
     281           0 :     bool ipv4_only = ACE_INET_Addr().get_type() == AF_INET;
     282             : 
     283             : #if defined (ACE_HAS_IPV6)
     284             : 
     285             :     // If the loopback interface is the only interface then include it
     286             :     // in the list of interfaces to query for a hostname, otherwise
     287             :     // exclude it from the list.
     288             :     bool ignore_lo;
     289             :     if (ipv4_only) {
     290             :       ignore_lo = ipv4_cnt != ipv4_lo_cnt;
     291             :     } else {
     292             :       ignore_lo = if_cnt != lo_cnt;
     293             :     }
     294             : 
     295             :     // Adjust counts for IPv4 only if required
     296             :     size_t if_ok_cnt = if_cnt;
     297             :     if (ipv4_only) {
     298             :       if_ok_cnt = ipv4_cnt;
     299             :       lo_cnt = ipv4_lo_cnt;
     300             :       ipv6_ll = 0;
     301             :     }
     302             : 
     303             :     // In case there are no non-local IPv6 ifs in the list only exclude
     304             :     // IPv4 loopback.
     305             :     // IPv6 loopback will be needed to successfully connect IPv6 clients
     306             :     // in a localhost environment.
     307             :     if (!ipv4_only && !ipv6_non_ll)
     308             :       lo_cnt = ipv4_lo_cnt;
     309             : 
     310             :     if (!ignore_lo)
     311             :       endpoint_count = if_ok_cnt - ipv6_ll;
     312             :     else
     313             :       endpoint_count = if_ok_cnt - ipv6_ll - lo_cnt;
     314             : #else /* end ACE_HAS_IPV6 begin !ACE_HAS_IPV6*/
     315             :     // If the loopback interface is the only interface then include it
     316             :     // in the list of interfaces to query for a hostname, otherwise
     317             :     // exclude it from the list.
     318             :     bool ignore_lo;
     319           0 :     ignore_lo = if_cnt != lo_cnt;
     320           0 :     if (!ignore_lo)
     321           0 :       endpoint_count = if_cnt;
     322             :     else
     323           0 :       endpoint_count = if_cnt - lo_cnt;
     324             : #endif /* !ACE_HAS_IPV6 */
     325           0 :     if (endpoint_count == 0) {
     326           0 :       VDBG_LVL((LM_DEBUG,
     327             :         ACE_TEXT("(%P|%t) get_interface_addrs() - ")
     328             :         ACE_TEXT("found no usable addresses\n")), 2);
     329             :     }
     330             : 
     331           0 :     for (size_t i = 0; i < if_cnt; ++i) {
     332             :       // Ignore any non-IPv4 interfaces when so required.
     333           0 :       if (ipv4_only && (if_addrs[i].get_type() != AF_INET))
     334           0 :         continue;
     335             : #if defined (ACE_HAS_IPV6)
     336             :       // Ignore any loopback interface if there are other
     337             :       // non-loopback interfaces.
     338             :       if (ignore_lo &&
     339             :           if_addrs[i].is_loopback() &&
     340             :           (ipv4_only ||
     341             :           ipv6_non_ll ||
     342             :           if_addrs[i].get_type() != AF_INET6))
     343             :         continue;
     344             : 
     345             :       // Ignore all IPv6 link local interfaces when so required.
     346             :       if (ipv6_non_ll && if_addrs[i].is_linklocal())
     347             :         continue;
     348             : #else /* ACE_HAS_IPV6 */
     349             :       // Ignore any loopback interface if there are other
     350             :       // non-loopback interfaces.
     351           0 :       if (ignore_lo && if_addrs[i].is_loopback())
     352           0 :         continue;
     353             : #endif /* !ACE_HAS_IPV6 */
     354           0 :       addrs.push_back(if_addrs[i]);
     355             :     }
     356             :   }
     357             : #ifdef ACE_HAS_IPV6
     358             :   //front load IPV6 addresses to give preference to IPV6 interfaces
     359             :   size_t index_last_non_ipv6 = 0;
     360             :   for (size_t i = 0; i < addrs.size(); i++) {
     361             :     if (addrs.at(i).get_type() == AF_INET6) {
     362             :       if (i == index_last_non_ipv6) {
     363             :         ++index_last_non_ipv6;
     364             :       }
     365             :       else {
     366             :         std::swap(addrs.at(i), addrs.at(index_last_non_ipv6));
     367             :         ++index_last_non_ipv6;
     368             :       }
     369             :     }
     370             :   }
     371             : #endif
     372             : #ifdef OPENDDS_SAFETY_PROFILE
     373             :   // address resolution may not be available due to safety profile,
     374             :   // return an address that should work for running tests
     375             :   if (addrs.empty()) {
     376             :     ACE_INET_Addr addr;
     377             :     static const char local[] = { 1, 0, 0, 127 };
     378             :     addr.set_address(local, sizeof local);
     379             :     addrs.push_back(addr);
     380             :   }
     381             : #else
     382           0 :   if (addrs.empty()) {
     383           0 :     ACE_ERROR((LM_ERROR,
     384             :       "(%P|%t) ERROR: failed to find usable interface address\n"));
     385             :   }
     386             : #endif
     387           0 : }
     388             : 
     389           0 : bool set_socket_multicast_ttl(const ACE_SOCK_Dgram& socket, const unsigned char& ttl)
     390             : {
     391           0 :   ACE_HANDLE handle = socket.get_handle();
     392           0 :   const void* ttlp = &ttl;
     393             : #if defined(ACE_LINUX) || defined(__linux__) || defined(ACE_HAS_MAC_OSX)
     394           0 :   int ttl_2 = ttl;
     395           0 :   ttlp = &ttl_2;
     396             : #define TTL ttl_2
     397             : #else
     398             : #define TTL ttl
     399             : #endif
     400             : #if defined (ACE_HAS_IPV6)
     401             :   ACE_INET_Addr local_addr;
     402             :   if (0 != socket.get_local_addr(local_addr)) {
     403             :     VDBG((LM_WARNING, "(%P|%t) set_socket_ttl: "
     404             :           "ACE_SOCK_Dgram::get_local_addr %p\n", ACE_TEXT("")));
     405             :   }
     406             :   if (local_addr.get_type () == AF_INET6) {
     407             :     if (0 != ACE_OS::setsockopt(handle,
     408             :                                 IPPROTO_IPV6,
     409             :                                 IPV6_MULTICAST_HOPS,
     410             :                                 static_cast<const char*>(ttlp),
     411             :                                 sizeof(TTL))) {
     412             :       ACE_ERROR_RETURN((LM_ERROR,
     413             :                         ACE_TEXT("(%P|%t) ERROR: ")
     414             :                         ACE_TEXT("set_socket_ttl: ")
     415             :                         ACE_TEXT("failed to set IPV6 TTL: %d %p\n"),
     416             :                         ttl,
     417             :                         ACE_TEXT("ACE_OS::setsockopt(TTL)")),
     418             :                        false);
     419             :     }
     420             :   } else
     421             : #endif  /* ACE_HAS_IPV6 */
     422           0 :   if (0 != ACE_OS::setsockopt(handle,
     423             :                               IPPROTO_IP,
     424             :                               IP_MULTICAST_TTL,
     425             :                               static_cast<const char*>(ttlp),
     426             :                               sizeof(TTL))) {
     427           0 :     ACE_ERROR_RETURN((LM_ERROR,
     428             :                       ACE_TEXT("(%P|%t) ERROR: ")
     429             :                       ACE_TEXT("set_socket_ttl: ")
     430             :                       ACE_TEXT("failed to set TTL: %d %p\n"),
     431             :                       ttl,
     432             :                       ACE_TEXT("ACE_OS::setsockopt(TTL)")),
     433             :                      false);
     434             :   }
     435           0 :   return true;
     436             : }
     437             : 
     438           0 : bool open_appropriate_socket_type(ACE_SOCK_Dgram& socket, const ACE_INET_Addr& local_address, int* proto_family)
     439             : {
     440             : #if defined (ACE_HAS_IPV6) && defined (IPV6_V6ONLY)
     441             :   int protocol_family = ACE_PROTOCOL_FAMILY_INET;
     442             :   int protocol = 0;
     443             :   int reuse_addr = 0;
     444             :   if (static_cast<ACE_Addr>(local_address) != ACE_Addr::sap_any) {
     445             :     protocol_family = local_address.get_type();
     446             :   } else if (protocol_family == PF_UNSPEC) {
     447             :     protocol_family = ACE::ipv6_enabled() ? PF_INET6 : PF_INET;
     448             :   }
     449             : 
     450             :   int one = 1;
     451             :   socket.set_handle(ACE_OS::socket(protocol_family,
     452             :     SOCK_DGRAM,
     453             :     protocol));
     454             : 
     455             :   if (socket.get_handle() == ACE_INVALID_HANDLE) {
     456             :     ACE_ERROR_RETURN((LM_WARNING,
     457             :       ACE_TEXT("(%P|%t) WARNING:")
     458             :       ACE_TEXT("open_appropriate_socket_type: ")
     459             :       ACE_TEXT("failed to set socket handle\n")),
     460             :       false);
     461             :   } else if (protocol_family != PF_UNIX &&
     462             :              reuse_addr &&
     463             :              socket.set_option(SOL_SOCKET,
     464             :                                SO_REUSEADDR,
     465             :                                &one,
     466             :                                sizeof one) == -1) {
     467             :     socket.close();
     468             :     ACE_ERROR_RETURN((LM_WARNING,
     469             :       ACE_TEXT("(%P|%t) WARNING: ")
     470             :       ACE_TEXT("open_appropriate_socket_type: ")
     471             :       ACE_TEXT("failed to set socket SO_REUSEADDR option\n")),
     472             :       false);
     473             :   }
     474             :   ACE_HANDLE handle = socket.get_handle();
     475             :   int ipv6_only = 0;
     476             :   if (protocol_family == PF_INET6 &&
     477             :       0 != ACE_OS::setsockopt(handle,
     478             :                               IPPROTO_IPV6,
     479             :                               IPV6_V6ONLY,
     480             :                               (char*)&ipv6_only,
     481             :                               sizeof(ipv6_only))) {
     482             :     ACE_ERROR_RETURN((LM_WARNING,
     483             :       ACE_TEXT("(%P|%t) WARNING: ")
     484             :       ACE_TEXT("open_appropriate_socket_type: ")
     485             :       ACE_TEXT("failed to set IPV6_V6ONLY to 0: %p\n"),
     486             :       ACE_TEXT("ACE_OS::setsockopt(IPV6_V6ONLY)")),
     487             :       false);
     488             :   }
     489             :   bool error = false;
     490             : 
     491             :   if (static_cast<ACE_Addr>(local_address) == ACE_Addr::sap_any) {
     492             :     if (protocol_family == PF_INET || protocol_family == PF_INET6) {
     493             :       if (ACE::bind_port(socket.get_handle(),
     494             :                          INADDR_ANY,
     495             :                          protocol_family) == -1) {
     496             :         error = true;
     497             :       }
     498             :     }
     499             :   } else if (ACE_OS::bind(socket.get_handle(),
     500             :                           reinterpret_cast<sockaddr *> (local_address.get_addr()),
     501             :                           local_address.get_size()) == -1) {
     502             :     error = true;
     503             :   }
     504             : 
     505             :   if (error) {
     506             :     socket.close();
     507             :     VDBG_LVL((LM_WARNING, "(%P|%t) WARNING: open_appropriate_socket_type: "
     508             :                           "failed to bind address to socket\n"), 2);
     509             :     return false;
     510             :   }
     511             :   if (proto_family) {
     512             :     *proto_family = protocol_family;
     513             :   }
     514             :   return true;
     515             : #else
     516           0 :   if (proto_family) {
     517           0 :     *proto_family = PF_INET;
     518             :   }
     519           0 :   return socket.open(local_address) == 0;
     520             : #endif
     521             : }
     522             : 
     523           0 : ACE_INET_Addr choose_single_coherent_address(const ACE_INET_Addr& address, bool prefer_loopback)
     524             : {
     525             : // Check that ACE_INET_Addr supports next()
     526             : #if !(ACE_MAJOR_VERSION < 6 || (ACE_MAJOR_VERSION == 6 && (ACE_MINOR_VERSION < 3 || (ACE_MINOR_VERSION == 3 && ACE_MICRO_VERSION < 1))))
     527           0 :   ACE_INET_Addr copy(address);
     528           0 :   OPENDDS_VECTOR(ACE_INET_Addr) addresses;
     529             :   do {
     530           0 :     ACE_INET_Addr temp;
     531           0 :     temp.set_addr(copy.get_addr(), copy.get_addr_size());
     532           0 :     addresses.push_back(temp);
     533           0 :   } while (copy.next());
     534           0 :   return choose_single_coherent_address(addresses, prefer_loopback);
     535             : #else
     536             :   ACE_UNUSED_ARG(prefer_loopback);
     537             :   return address;
     538             : #endif // !(ACE_MAJOR_VERSION < 6 || (ACE_MAJOR_VERSION == 6 && (ACE_MINOR_VERSION < 3 || (ACE_MINOR_VERSION == 3 && ACE_MICRO_VERSION < 1))))
     539           0 : }
     540             : 
     541             : namespace {
     542             : 
     543             : template <typename T>
     544           7 : ACE_INET_Addr tie_breaker(const T& addrs, const String& name)
     545             : {
     546           7 :   if (!name.empty()) {
     547           5 :     for (typename T::const_iterator it = addrs.begin(); it != addrs.end(); ++it) {
     548           5 :       if (name.compare(LogAddr::host(*it)) == 0) {
     549           5 :         VDBG((LM_DEBUG, "(%P|%t) tie_breaker - Choosing Address %C\n",
     550             :           LogAddr(*it, LogAddr::IpPortHost).c_str()));
     551          10 :         return *it;
     552             :       }
     553             :     }
     554             :   }
     555           2 :   VDBG((LM_DEBUG, "(%P|%t) tie_breaker - Choosing Address %C\n", LogAddr(*(addrs.begin())).c_str()));
     556           4 :   return *addrs.begin();
     557             : }
     558             : 
     559             : }
     560             : 
     561           7 : ACE_INET_Addr choose_single_coherent_address(const OPENDDS_VECTOR(ACE_INET_Addr)& addresses, bool prefer_loopback, const String& name)
     562             : {
     563             : #ifdef ACE_HAS_IPV6
     564             :   OPENDDS_SET(ACE_INET_Addr) set6_loopback;
     565             :   OPENDDS_SET(ACE_INET_Addr) set6_linklocal;
     566             :   OPENDDS_SET(ACE_INET_Addr) set6_mapped_v4;
     567             :   OPENDDS_SET(ACE_INET_Addr) set6;
     568             : #endif // ACE_HAS_IPV6
     569           7 :   OPENDDS_SET(ACE_INET_Addr) set4_loopback;
     570           7 :   OPENDDS_SET(ACE_INET_Addr) set4;
     571             : 
     572          20 :   for (OPENDDS_VECTOR(ACE_INET_Addr)::const_iterator it = addresses.begin(); it != addresses.end(); ++it) {
     573             : #ifdef ACE_HAS_IPV6
     574             :     if (it->get_type() == AF_INET6 && !it->is_multicast()) {
     575             :       if (it->is_loopback()) {
     576             :         VDBG((LM_DEBUG, "(%P|%t) choose_single_coherent_address(list) - "
     577             :           "Considering Address %C - ADDING TO IPv6 LOOPBACK LIST\n", LogAddr(*it).c_str()));
     578             :         set6_loopback.insert(*it);
     579             :       } else if (it->is_ipv4_mapped_ipv6() || it->is_ipv4_compat_ipv6()) {
     580             : #ifndef IPV6_V6ONLY
     581             :         VDBG((LM_DEBUG, "(%P|%t) choose_single_coherent_address(list) - "
     582             :           "Considering Address %C - ADDING TO IPv6 MAPPED / COMPATIBLE IPv4 LIST\n", LogAddr(*it).c_str()));
     583             :         set6_mapped_v4.insert(*it);
     584             : #endif  // ! IPV6_V6ONLY
     585             :       } else if (it->is_linklocal()) {
     586             :         VDBG((LM_DEBUG, "(%P|%t) choose_single_coherent_address(list) - "
     587             :           "Considering Address %C - ADDING TO IPv6 LINK-LOCAL LIST\n", LogAddr(*it).c_str()));
     588             :         set6_linklocal.insert(*it);
     589             :       } else {
     590             :         VDBG((LM_DEBUG, "(%P|%t) choose_single_coherent_address(list) - "
     591             :           "Considering Address %C - ADDING TO IPv6 NORMAL LIST\n", LogAddr(*it).c_str()));
     592             :         set6.insert(*it);
     593             :       }
     594             :     }
     595             : #endif // ACE_HAS_IPV6
     596          13 :     if (it->get_type() == AF_INET && !it->is_multicast()) {
     597          13 :       if (it->is_loopback()) {
     598           4 :         VDBG((LM_DEBUG, "(%P|%t) choose_single_coherent_address(list) - "
     599             :           "Considering Address %C - ADDING TO IPv4 LOOPBACK LIST\n", LogAddr(*it).c_str()));
     600           4 :         set4_loopback.insert(*it);
     601             :       } else {
     602           9 :         VDBG((LM_DEBUG, "(%P|%t) choose_single_coherent_address(list) - "
     603             :           "Considering Address %C - ADDING TO IPv4 NORMAL LIST\n", LogAddr(*it).c_str()));
     604           9 :         set4.insert(*it);
     605             :       }
     606             :     }
     607             :   }
     608             : 
     609             : #ifdef ACE_HAS_IPV6
     610             :   if (prefer_loopback && !set6_loopback.empty()) {
     611             :     return tie_breaker(set6_loopback, name);
     612             :   }
     613             : #endif // ACE_HAS_IPV6
     614             : 
     615           7 :   if (prefer_loopback && !set4_loopback.empty()) {
     616           2 :     return tie_breaker(set4_loopback, name);
     617             :   }
     618             : 
     619             : #ifdef ACE_HAS_IPV6
     620             :   if (prefer_loopback && !set6_linklocal.empty()) {
     621             :     return tie_breaker(set6_linklocal, name);
     622             :   }
     623             :   if (!set6.empty()) {
     624             :     return tie_breaker(set6, name);
     625             :   }
     626             :   if (!set6_mapped_v4.empty()) {
     627             :     return tie_breaker(set6_mapped_v4, name);
     628             :   }
     629             : #endif // ACE_HAS_IPV6
     630             : 
     631           5 :   if (!set4.empty()) {
     632           4 :     return tie_breaker(set4, name);
     633             :   }
     634             : 
     635             : #ifdef ACE_HAS_IPV6
     636             :   if (!set6_linklocal.empty()) {
     637             :     return tie_breaker(set6_linklocal, name);
     638             :   }
     639             :   if (!set6_loopback.empty()) {
     640             :     return tie_breaker(set6_loopback, name);
     641             :   }
     642             : #endif // ACE_HAS_IPV6
     643             : 
     644           1 :   if (!set4_loopback.empty()) {
     645           1 :     return tie_breaker(set4_loopback, name);
     646             :   }
     647             : 
     648           0 :   if (!addresses.empty()) {
     649           0 :     return tie_breaker(addresses, name);
     650             :   }
     651             : 
     652           0 :   return ACE_INET_Addr();
     653           7 : }
     654             : 
     655           9 : ACE_INET_Addr choose_single_coherent_address(const String& address, bool prefer_loopback, bool allow_ipv4_fallback)
     656             : {
     657           9 :   ACE_INET_Addr result;
     658             : 
     659           9 :   if (address.empty()) {
     660           0 :     return ACE_INET_Addr();
     661             :   }
     662             : 
     663           9 :   String host_name_str;
     664           9 :   unsigned short port_number = 0;
     665             : 
     666             : #ifdef ACE_HAS_IPV6
     667             :   const String::size_type openb = address.find_first_of('[');
     668             :   const String::size_type closeb = address.find_first_of(']', openb);
     669             :   const String::size_type last_double = address.rfind("::", closeb);
     670             :   const String::size_type port_div = closeb != String::npos ?
     671             :                                        address.find_first_of(':', closeb + 1u) :
     672             :                                        (last_double != String::npos ?
     673             :                                          address.find_first_of(':', last_double + 2u) :
     674             :                                          address.find_last_of(':'));
     675             : #else
     676           9 :   const String::size_type port_div = address.find_last_of(':');
     677             : #endif
     678             : 
     679           9 :   if (port_div != String::npos) {
     680             : #ifdef ACE_HAS_IPV6
     681             :     if (openb != String::npos && closeb != String::npos) {
     682             :       host_name_str = address.substr(openb + 1u, closeb - 1u - openb);
     683             :     } else
     684             : #endif /* ACE_HAS_IPV6 */
     685             :     {
     686           6 :       host_name_str = address.substr(0, port_div);
     687             :     }
     688           6 :     port_number = static_cast<unsigned short>(std::strtoul(address.substr(port_div + 1u).c_str(), 0, 10));
     689             :   } else {
     690             : #ifdef ACE_HAS_IPV6
     691             :     if (openb != String::npos && closeb != String::npos) {
     692             :       host_name_str = address.substr(openb + 1u, closeb - 1u - openb);
     693             :     } else
     694             : #endif /* ACE_HAS_IPV6 */
     695             :     {
     696           3 :       host_name_str = address;
     697             :     }
     698             :   }
     699             : 
     700           9 :   if (host_name_str.empty()) {
     701           0 :     return ACE_INET_Addr();
     702             :   }
     703             : 
     704           9 :   const char* host_name = host_name_str.c_str();
     705             : 
     706             :   union ip46
     707             :   {
     708             :     sockaddr_in  in4_;
     709             : #ifdef ACE_HAS_IPV6
     710             :     sockaddr_in6 in6_;
     711             : #endif /* ACE_HAS_IPV6 */
     712             :   } inet_addr;
     713           9 :   std::memset(&inet_addr, 0, sizeof inet_addr);
     714             : 
     715           9 :   int address_family = AF_UNSPEC;
     716             : 
     717             : #if defined ACE_HAS_IPV6 && defined ACE_USES_IPV4_IPV6_MIGRATION
     718             :   if (address_family == AF_UNSPEC && !ACE::ipv6_enabled()) {
     719             :     address_family = AF_INET;
     720             :   }
     721             : #endif /* ACE_HAS_IPV6 && ACE_USES_IPV4_IPV6_MIGRATION */
     722             : 
     723             : #ifdef ACE_HAS_IPV6
     724             :   if (address_family == AF_UNSPEC && ACE::ipv6_enabled() && !allow_ipv4_fallback) {
     725             :     address_family = AF_INET6;
     726             :   }
     727             : 
     728             :   if (address_family != AF_INET && ACE_OS::inet_pton(AF_INET6, host_name, &inet_addr.in6_.sin6_addr) == 1) {
     729             : #ifdef ACE_HAS_SOCKADDR_IN6_SIN6_LEN
     730             :     inet_addr.in6_.sin6_len = sizeof inet_addr.in6_;
     731             : #endif /* ACE_HAS_SOCKADDR_IN6_SIN6_LEN */
     732             :     inet_addr.in6_.sin6_family = AF_INET6;
     733             :     result.set_addr(&inet_addr, sizeof inet_addr);
     734             :     result.set_port_number(port_number, 1 /*encode*/);
     735             :     return result;
     736             :   }
     737             : #else
     738             :   ACE_UNUSED_ARG(allow_ipv4_fallback);
     739           9 :   address_family = AF_INET;
     740             : #endif /* ACE_HAS_IPV6 */
     741             : 
     742           9 :   if (ACE_OS::inet_pton(AF_INET, host_name, &inet_addr.in4_.sin_addr) == 1) {
     743             : #ifdef ACE_HAS_SOCKADDR_IN_SIN_LEN
     744             :     inet_addr.in4_.sin_len = sizeof inet_addr.in4_;
     745             : #endif /* ACE_HAS_SOCKADDR_IN_SIN_LEN */
     746           4 :     inet_addr.in4_.sin_family = AF_INET;
     747           4 :     result.set_addr(&inet_addr, sizeof inet_addr);
     748           4 :     result.set_port_number(port_number, 1 /*encode*/);
     749           4 :     return result;
     750             :   }
     751             : 
     752             :   addrinfo hints;
     753           5 :   std::memset(&hints, 0, sizeof hints);
     754           5 :   hints.ai_family = address_family;
     755             : 
     756             :   // The ai_flags used to contain AI_ADDRCONFIG as well but that prevented
     757             :   // lookups from completing if there is no, or only a loopback, IPv6
     758             :   // interface configured. See Bugzilla 4211 for more info.
     759             : 
     760             : #if defined ACE_HAS_IPV6 && !defined IPV6_V6ONLY
     761             :   hints.ai_flags |= AI_V4MAPPED;
     762             : #endif
     763             : 
     764             : #if defined ACE_HAS_IPV6 && defined AI_ALL
     765             :   // Without AI_ALL, Windows machines exhibit inconsistent behaviors on
     766             :   // difference machines we have tested.
     767             :   hints.ai_flags |= AI_ALL;
     768             : #endif
     769             : 
     770             :   // Note - specify the socktype here to avoid getting multiple entries
     771             :   // returned with the same address for different socket types or
     772             :   // protocols. If this causes a problem for some reason (an address that's
     773             :   // available for TCP but not UDP, or vice-versa) this will need to change
     774             :   // back to unrestricted hints and weed out the duplicate addresses by
     775             :   // searching this->inet_addrs_ which would slow things down.
     776           5 :   hints.ai_socktype = SOCK_STREAM;
     777             : 
     778           5 :   addrinfo *res = 0;
     779           5 :   const int error = ACE_OS::getaddrinfo(host_name, 0, &hints, &res);
     780             : 
     781           5 :   if (error) {
     782           0 :     VDBG((LM_WARNING, "(%P|%t) WARNING: choose_single_coherent_address: Call to getaddrinfo for hostname %C returned error: %d\n", host_name, error));
     783           0 :     return ACE_INET_Addr();
     784             :   }
     785             : 
     786             :   struct AddrInfoGuard {
     787           5 :     AddrInfoGuard(addrinfo* ptr) : ptr_(ptr) {}
     788           5 :     ~AddrInfoGuard() {
     789           5 :       ACE_OS::freeaddrinfo(ptr_);
     790           5 :     }
     791             :     addrinfo* const ptr_;
     792           5 :   } guard(res);
     793             : 
     794           5 :   OPENDDS_VECTOR(ACE_INET_Addr) addresses;
     795             : 
     796             : #ifdef ACE_WIN32
     797             :   static ACE_Thread_Mutex addr_cache_map_mutex_;
     798             :   typedef std::pair<SystemTimePoint, OPENDDS_SET(ACE_INET_Addr)> AddrCachePair;
     799             :   typedef OPENDDS_MAP(String, AddrCachePair) AddrCacheMap;
     800             :   static AddrCacheMap addr_cache_map_;
     801             :   ACE_Guard<ACE_Thread_Mutex> g(addr_cache_map_mutex_);
     802             :   const SystemTimePoint now = SystemTimePoint::now();
     803             :   for (AddrCacheMap::iterator it = addr_cache_map_.begin(); it != addr_cache_map_.end(); /* inc in loop */) {
     804             :     if (it->second.first + TimeDuration(3, 0) < now) {
     805             :       addr_cache_map_.erase(it++);
     806             :     } else {
     807             :       ++it;
     808             :     }
     809             :   }
     810             :   AddrCacheMap::iterator it = addr_cache_map_.find(host_name);
     811             :   if (it != addr_cache_map_.end()) {
     812             :     addresses.insert(addresses.end(), it->second.second.begin(), it->second.second.end());
     813             :     it->second.first = now;
     814             :   }
     815             : #endif /* ACE_WIN32 */
     816             : 
     817          10 :   for (addrinfo* curr = res; curr; curr = curr->ai_next) {
     818           5 :     if (curr->ai_family != AF_INET && curr->ai_family != AF_INET6) {
     819           0 :       continue;
     820             :     }
     821             :     ip46 addr;
     822           5 :     std::memset(&addr, 0, sizeof addr);
     823           5 :     std::memcpy(&addr, curr->ai_addr, curr->ai_addrlen);
     824             : #ifdef ACE_HAS_IPV6
     825             :     if (curr->ai_family == AF_INET6) {
     826             :       addr.in6_.sin6_port = ACE_NTOHS(port_number);
     827             :     } else {
     828             : #endif /* ACE_HAS_IPV6 */
     829           5 :       addr.in4_.sin_port = ACE_NTOHS(port_number);;
     830             : #ifdef ACE_HAS_IPV6
     831             :     }
     832             : #endif /* ACE_HAS_IPV6 */
     833             : 
     834           5 :     ACE_INET_Addr temp;
     835           5 :     temp.set_addr(&addr, sizeof addr);
     836           5 :     addresses.push_back(temp);
     837             : #ifdef ACE_WIN32
     838             :     if (it != addr_cache_map_.end()) {
     839             :       it->second.second.insert(temp);
     840             :     } else {
     841             :       OPENDDS_SET(ACE_INET_Addr) my_set;
     842             :       my_set.insert(temp);
     843             :       addr_cache_map_[host_name] = make_pair(now, my_set);
     844             :     }
     845             : #endif /* ACE_WIN32 */
     846           5 :   }
     847             : 
     848             : #ifdef ACE_WIN32
     849             :   g.release();
     850             : #endif /* ACE_WIN32 */
     851             : 
     852           5 :   result = choose_single_coherent_address(addresses, prefer_loopback, host_name);
     853           5 :   result.set_port_number(port_number, 1 /*encode*/);
     854           5 :   return result;
     855           9 : }
     856             : 
     857          16 : int locator_to_address(ACE_INET_Addr& dest,
     858             :                        const DCPS::Locator_t& locator,
     859             :                        bool map /*map IPV4 to IPV6 addr*/)
     860             : {
     861          16 :   switch (locator.kind) {
     862             : #ifdef ACE_HAS_IPV6
     863             :   case LOCATOR_KIND_UDPv6:
     864             :     dest.set_type(AF_INET6);
     865             :     if (dest.set_address(reinterpret_cast<const char*>(locator.address),
     866             :                          16, 0 /*encode*/) == -1) {
     867             :       return -1;
     868             :     }
     869             :     dest.set_port_number(locator.port);
     870             :     return 0;
     871             : #endif
     872          10 :   case LOCATOR_KIND_UDPv4:
     873             : #if !defined (ACE_HAS_IPV6) || !defined (IPV6_V6ONLY)
     874             :     ACE_UNUSED_ARG(map);
     875             : #endif
     876          10 :     dest.set_type(AF_INET);
     877          10 :     if (dest.set_address(reinterpret_cast<const char*>(locator.address)
     878             :                          + 12, 4, 0 /*network order*/
     879             : #if defined (ACE_HAS_IPV6) && defined (IPV6_V6ONLY)
     880             :                          , map ? 1 : 0 /*map IPV4 to IPV6 addr*/
     881             : #endif
     882          10 :     ) == -1) {
     883           0 :       return -1;
     884             :     }
     885          10 :     dest.set_port_number(locator.port);
     886          10 :     return 0;
     887           6 :   default:
     888           6 :     return -1;  // Unknown kind
     889             :   }
     890             : 
     891             :   return -1;
     892             : }
     893             : 
     894             : OpenDDS_Dcps_Export
     895           0 : void address_to_locator(Locator_t& locator,
     896             :                         const ACE_INET_Addr& addr)
     897             : {
     898           0 :   const void* raw = addr.get_addr();
     899           0 :   switch (addr.get_type()) {
     900           0 :   case AF_INET:
     901             :     {
     902           0 :       locator.kind = LOCATOR_KIND_UDPv4;
     903           0 :       const sockaddr_in* in = static_cast<const sockaddr_in*>(raw);
     904           0 :       std::memset(&locator.address[0], 0, 12);
     905           0 :       std::memcpy(&locator.address[12], &in->sin_addr, 4);
     906             :     }
     907           0 :     break;
     908             : #ifdef ACE_HAS_IPV6
     909             :   case AF_INET6:
     910             :     {
     911             :       locator.kind = LOCATOR_KIND_UDPv6;
     912             :       const sockaddr_in6* in = static_cast<const sockaddr_in6*>(raw);
     913             :       std::memcpy(&locator.address[0], &in->sin6_addr, 16);
     914             :     }
     915             :     break;
     916             : #endif
     917           0 :   default:
     918           0 :     locator.kind = LOCATOR_KIND_INVALID;
     919           0 :     std::memset(&locator.address[0], 0, 16);
     920           0 :     break;
     921             :   }
     922           0 :   locator.port = addr.get_port_number();
     923           0 : }
     924             : 
     925             : }
     926             : }
     927             : 
     928             : OPENDDS_END_VERSIONED_NAMESPACE_DECL

Generated by: LCOV version 1.16