NetworkAddress.cpp

Go to the documentation of this file.
00001 /*
00002  *
00003  *
00004  * Distributed under the OpenDDS License.
00005  * See: http://www.opendds.org/license.html
00006  */
00007 
00008 #include "DCPS/DdsDcps_pch.h" //Only the _pch include should start with DCPS/
00009 #include "NetworkAddress.h"
00010 #include "ace/OS_NS_netdb.h"
00011 #include "ace/Sock_Connect.h"
00012 #include "ace/OS_NS_sys_socket.h" // For setsockopt()
00013 
00014 #if !defined (__ACE_INLINE__)
00015 # include "NetworkAddress.inl"
00016 #endif /* !__ACE_INLINE__ */
00017 
00018 ACE_BEGIN_VERSIONED_NAMESPACE_DECL
00019 
00020 ACE_CDR::Boolean
00021 operator<< (ACE_OutputCDR& outCdr, OpenDDS::DCPS::NetworkAddress& value)
00022 {
00023   return (outCdr << ACE_OutputCDR::from_boolean(ACE_CDR_BYTE_ORDER)) &&
00024          (outCdr << ACE_OutputCDR::from_octet(value.reserved_)) &&
00025          (outCdr << value.addr_.c_str());
00026 }
00027 
00028 ACE_CDR::Boolean
00029 operator>> (ACE_InputCDR& inCdr, OpenDDS::DCPS::NetworkAddress& value)
00030 {
00031   CORBA::Boolean byte_order;
00032 
00033   if (!(inCdr >> ACE_InputCDR::to_boolean(byte_order)))
00034     return false;
00035 
00036   inCdr.reset_byte_order(byte_order);
00037 
00038   if (!(inCdr >> ACE_InputCDR::to_octet(value.reserved_)))
00039     return false;
00040 
00041   char* buf = 0;
00042 
00043   if (!(inCdr >> buf))
00044     return false;
00045 
00046   value.addr_ = buf;
00047 
00048   delete[] buf;
00049 
00050   return inCdr.good_bit();
00051 }
00052 
00053 ACE_END_VERSIONED_NAMESPACE_DECL
00054 
00055 OPENDDS_BEGIN_VERSIONED_NAMESPACE_DECL
00056 
00057 namespace OpenDDS {
00058 namespace DCPS {
00059 
00060 OPENDDS_STRING get_fully_qualified_hostname(ACE_INET_Addr* addr)
00061 {
00062   // cache the determined fully qualified hostname and its
00063   // address to be used on subsequent calls
00064   static OPENDDS_STRING fullname;
00065   static ACE_INET_Addr selected_address;
00066 
00067   if (fullname.length() == 0) {
00068     size_t addr_count;
00069     ACE_INET_Addr *addr_array = 0;
00070     OpenDDS::DCPS::HostnameInfoVector nonFQDN;
00071 
00072     int result = ACE::get_ip_interfaces(addr_count, addr_array);
00073 
00074     struct Array_Guard {
00075       Array_Guard(ACE_INET_Addr *ptr) : ptr_(ptr) {}
00076       ~Array_Guard() {
00077         delete [] ptr_;
00078       }
00079       ACE_INET_Addr* const ptr_;
00080     } guardObject(addr_array);
00081 
00082     if (result != 0 || addr_count < 1) {
00083       ACE_ERROR((LM_ERROR,
00084                  ACE_TEXT("(%P|%t) ERROR: Unable to probe network. %p\n"),
00085                  ACE_TEXT("ACE::get_ip_interfaces")));
00086 
00087     } else {
00088 #ifdef ACE_HAS_IPV6
00089         //front load IPV6 addresses to give preference to IPV6 interfaces
00090         size_t index_last_non_ipv6 = 0;
00091         for (size_t i = 0; i < addr_count; i++) {
00092           if (addr_array[i].get_type() == AF_INET6) {
00093             if (i == index_last_non_ipv6) {
00094               ++index_last_non_ipv6;
00095             } else {
00096               std::swap(addr_array[i], addr_array[index_last_non_ipv6]);
00097               ++index_last_non_ipv6;
00098             }
00099           }
00100         }
00101 #endif
00102       for (size_t i = 0; i < addr_count; i++) {
00103         char hostname[MAXHOSTNAMELEN+1] = "";
00104 
00105         //Discover the fully qualified hostname
00106 
00107         if (ACE::get_fqdn(addr_array[i], hostname, MAXHOSTNAMELEN+1) == 0) {
00108           if (addr_array[i].is_loopback() == false && ACE_OS::strchr(hostname, '.') != 0) {
00109             VDBG_LVL((LM_DEBUG, "(%P|%t) found fqdn %C from %C:%d\n",
00110                       hostname, addr_array[i].get_host_addr(), addr_array[i].get_port_number()), 2);
00111             selected_address = addr_array[i];
00112             fullname = hostname;
00113             if (addr) {
00114               *addr = selected_address;
00115             }
00116             return fullname;
00117 
00118           } else {
00119             VDBG_LVL((LM_DEBUG, "(%P|%t) ip interface %C:%d maps to hostname %C\n",
00120                       addr_array[i].get_host_addr(), addr_array[i].get_port_number(), hostname), 2);
00121 
00122             if (ACE_OS::strncmp(hostname, "localhost", 9) == 0) {
00123               addr_array[i].get_host_addr(hostname, MAXHOSTNAMELEN);
00124             }
00125 
00126             OpenDDS::DCPS::HostnameInfo info;
00127             info.index_ = i;
00128             info.hostname_ = hostname;
00129             nonFQDN.push_back(info);
00130           }
00131         }
00132       }
00133     }
00134 
00135     OpenDDS::DCPS::HostnameInfoVector::iterator itBegin = nonFQDN.begin();
00136     OpenDDS::DCPS::HostnameInfoVector::iterator itEnd = nonFQDN.end();
00137 
00138     for (OpenDDS::DCPS::HostnameInfoVector::iterator it = itBegin; it != itEnd; ++it) {
00139       if (addr_array[it->index_].is_loopback() == false) {
00140         ACE_DEBUG((LM_WARNING, "(%P|%t) WARNING: Could not find FQDN. Using "
00141                    "\"%C\" as fully qualified hostname, please "
00142                    "correct system configuration.\n", it->hostname_.c_str()));
00143         selected_address = addr_array[it->index_];
00144         fullname = it->hostname_;
00145         if (addr) {
00146           *addr = selected_address;
00147         }
00148         return fullname;
00149       }
00150     }
00151 
00152     if (itBegin != itEnd) {
00153       ACE_DEBUG((LM_WARNING, "(%P|%t) WARNING: Could not find FQDN. Using "
00154                  "\"%C\" as fully qualified hostname, please "
00155                  "correct system configuration.\n", itBegin->hostname_.c_str()));
00156       selected_address = addr_array[itBegin->index_];
00157       fullname = itBegin->hostname_;
00158       if (addr) {
00159         *addr = selected_address;
00160       }
00161       return fullname;
00162     }
00163 
00164 #ifdef OPENDDS_SAFETY_PROFILE
00165     // address resolution may not be available due to safety profile,
00166     // return an address that should work for running tests
00167     if (addr) {
00168       static const char local[] = {1, 0, 0, 127};
00169       addr->set_address(local, sizeof local);
00170     }
00171     return "localhost";
00172 #else
00173     ACE_ERROR((LM_ERROR,
00174                "(%P|%t) ERROR: failed to discover the fully qualified hostname\n"));
00175 #endif
00176   }
00177 
00178   if (addr) {
00179     *addr = selected_address;
00180   }
00181   return fullname;
00182 }
00183 
00184 void get_interface_addrs(OPENDDS_VECTOR(ACE_INET_Addr)& addrs)
00185 {
00186   ACE_INET_Addr *if_addrs = 0;
00187   size_t if_cnt = 0;
00188   size_t endpoint_count = 0;
00189 
00190   int result =
00191 #ifdef OPENDDS_SAFETY_PROFILE
00192     -1;
00193 #else
00194     ACE::get_ip_interfaces(if_cnt, if_addrs);
00195 #endif
00196 
00197   struct Array_Guard {
00198     Array_Guard(ACE_INET_Addr *ptr) : ptr_(ptr) {}
00199     ~Array_Guard() {
00200       delete[] ptr_;
00201     }
00202     ACE_INET_Addr* const ptr_;
00203   } guardObject(if_addrs);
00204 
00205   if (!result) {
00206     size_t lo_cnt = 0;  // Loopback interface count
00207 #if defined (ACE_HAS_IPV6)
00208     size_t ipv4_cnt = 0;
00209     size_t ipv4_lo_cnt = 0;
00210     size_t ipv6_ll = 0;
00211     bool ipv6_non_ll = false;
00212 #endif
00213     for (size_t j = 0; j < if_cnt; ++j) {
00214       // Scan for the loopback interface since it shouldn't be included in
00215       // the list of cached hostnames unless it is the only interface.
00216       if (if_addrs[j].is_loopback())
00217         ++lo_cnt;
00218 #if defined (ACE_HAS_IPV6)
00219       // Scan for IPv4 interfaces since these should not be included
00220       // when IPv6-only is selected.
00221       if (if_addrs[j].get_type() != AF_INET6 ||
00222           if_addrs[j].is_ipv4_mapped_ipv6()) {
00223         ++ipv4_cnt;
00224         if (if_addrs[j].is_loopback())
00225           ++ipv4_lo_cnt;  // keep track of IPv4 loopback ifs
00226       } else if (!if_addrs[j].is_linklocal() &&
00227                  !if_addrs[j].is_loopback()) {
00228         ipv6_non_ll = true; // we have at least 1 non-local IPv6 if
00229       } else if (if_addrs[j].is_linklocal()) {
00230         ++ipv6_ll;  // count link local addrs to exclude them afterwards
00231       }
00232 #endif /* ACE_HAS_IPV6 */
00233     }
00234 
00235     bool ipv4_only = ACE_INET_Addr().get_type() == AF_INET;
00236 
00237 #if defined (ACE_HAS_IPV6)
00238 
00239     // If the loopback interface is the only interface then include it
00240     // in the list of interfaces to query for a hostname, otherwise
00241     // exclude it from the list.
00242     bool ignore_lo;
00243     if (ipv4_only) {
00244       ignore_lo = ipv4_cnt != ipv4_lo_cnt;
00245     } else {
00246       ignore_lo = if_cnt != lo_cnt;
00247     }
00248 
00249     // Adjust counts for IPv4 only if required
00250     size_t if_ok_cnt = if_cnt;
00251     if (ipv4_only) {
00252       if_ok_cnt = ipv4_cnt;
00253       lo_cnt = ipv4_lo_cnt;
00254       ipv6_ll = 0;
00255     }
00256 
00257     // In case there are no non-local IPv6 ifs in the list only exclude
00258     // IPv4 loopback.
00259     // IPv6 loopback will be needed to successfully connect IPv6 clients
00260     // in a localhost environment.
00261     if (!ipv4_only && !ipv6_non_ll)
00262       lo_cnt = ipv4_lo_cnt;
00263 
00264     if (!ignore_lo)
00265       endpoint_count = if_ok_cnt - ipv6_ll;
00266     else
00267       endpoint_count = if_ok_cnt - ipv6_ll - lo_cnt;
00268 #else /* end ACE_HAS_IPV6 begin !ACE_HAS_IPV6*/
00269     // If the loopback interface is the only interface then include it
00270     // in the list of interfaces to query for a hostname, otherwise
00271     // exclude it from the list.
00272     bool ignore_lo;
00273     ignore_lo = if_cnt != lo_cnt;
00274     if (!ignore_lo)
00275       endpoint_count = if_cnt;
00276     else
00277       endpoint_count = if_cnt - lo_cnt;
00278 #endif /* !ACE_HAS_IPV6 */
00279     if (endpoint_count == 0) {
00280       VDBG_LVL((LM_DEBUG,
00281         ACE_TEXT("(%P|%t) get_interface_addrs() - ")
00282         ACE_TEXT("found no usable addresses\n")), 2);
00283     }
00284 
00285     for (size_t i = 0; i < if_cnt; ++i) {
00286       // Ignore any non-IPv4 interfaces when so required.
00287       if (ipv4_only && (if_addrs[i].get_type() != AF_INET))
00288         continue;
00289 #if defined (ACE_HAS_IPV6)
00290       // Ignore any loopback interface if there are other
00291       // non-loopback interfaces.
00292       if (ignore_lo &&
00293           if_addrs[i].is_loopback() &&
00294           (ipv4_only ||
00295           ipv6_non_ll ||
00296           if_addrs[i].get_type() != AF_INET6))
00297         continue;
00298 
00299       // Ignore all IPv6 link local interfaces when so required.
00300       if (ipv6_non_ll && if_addrs[i].is_linklocal())
00301         continue;
00302 #else /* ACE_HAS_IPV6 */
00303       // Ignore any loopback interface if there are other
00304       // non-loopback interfaces.
00305       if (ignore_lo && if_addrs[i].is_loopback())
00306         continue;
00307 #endif /* !ACE_HAS_IPV6 */
00308       addrs.push_back(if_addrs[i]);
00309     }
00310   }
00311 #ifdef ACE_HAS_IPV6
00312   //front load IPV6 addresses to give preference to IPV6 interfaces
00313   size_t index_last_non_ipv6 = 0;
00314   for (size_t i = 0; i < addrs.size(); i++) {
00315     if (addrs.at(i).get_type() == AF_INET6) {
00316       if (i == index_last_non_ipv6) {
00317         ++index_last_non_ipv6;
00318       }
00319       else {
00320         std::swap(addrs.at(i), addrs.at(index_last_non_ipv6));
00321         ++index_last_non_ipv6;
00322       }
00323     }
00324   }
00325 #endif
00326 #ifdef OPENDDS_SAFETY_PROFILE
00327   // address resolution may not be available due to safety profile,
00328   // return an address that should work for running tests
00329   if (addrs.empty()) {
00330     ACE_INET_Addr addr;
00331     static const char local[] = { 1, 0, 0, 127 };
00332     addr.set_address(local, sizeof local);
00333     addrs.push_back(addr);
00334   }
00335 #else
00336   if (addrs.empty()) {
00337     ACE_ERROR((LM_ERROR,
00338       "(%P|%t) ERROR: failed to find usable interface address\n"));
00339   }
00340 #endif
00341 }
00342 
00343 bool set_socket_multicast_ttl(const ACE_SOCK_Dgram& socket, const unsigned char& ttl)
00344 {
00345   ACE_HANDLE handle = socket.get_handle();
00346   const void* ttlp = &ttl;
00347 #if defined(ACE_LINUX) || defined(__linux__)
00348   int ttl_2 = ttl;
00349   ttlp = &ttl_2;
00350 #define TTL ttl_2
00351 #else
00352 #define TTL ttl
00353 #endif
00354 #if defined (ACE_HAS_IPV6)
00355   ACE_INET_Addr local_addr;
00356   if (0 != socket.get_local_addr(local_addr)) {
00357     VDBG((LM_WARNING, "(%P|%t) set_socket_ttl: "
00358           "ACE_SOCK_Dgram::get_local_addr %p\n", ACE_TEXT("")));
00359   }
00360   if (local_addr.get_type () == AF_INET6) {
00361     if (0 != ACE_OS::setsockopt(handle,
00362                                 IPPROTO_IPV6,
00363                                 IPV6_MULTICAST_HOPS,
00364                                 static_cast<const char*>(ttlp),
00365                                 sizeof(TTL))) {
00366       ACE_ERROR_RETURN((LM_ERROR,
00367                         ACE_TEXT("(%P|%t) ERROR: ")
00368                         ACE_TEXT("set_socket_ttl: ")
00369                         ACE_TEXT("failed to set IPV6 TTL: %d %p\n"),
00370                         ttl,
00371                         ACE_TEXT("ACE_OS::setsockopt(TTL)")),
00372                        false);
00373     }
00374   } else
00375 #endif  /* ACE_HAS_IPV6 */
00376   if (0 != ACE_OS::setsockopt(handle,
00377                               IPPROTO_IP,
00378                               IP_MULTICAST_TTL,
00379                               static_cast<const char*>(ttlp),
00380                               sizeof(TTL))) {
00381     ACE_ERROR_RETURN((LM_ERROR,
00382                       ACE_TEXT("(%P|%t) ERROR: ")
00383                       ACE_TEXT("set_socket_ttl: ")
00384                       ACE_TEXT("failed to set TTL: %d %p\n"),
00385                       ttl,
00386                       ACE_TEXT("ACE_OS::setsockopt(TTL)")),
00387                      false);
00388   }
00389   return true;
00390 }
00391 
00392 bool open_appropriate_socket_type(ACE_SOCK_Dgram& socket, const ACE_INET_Addr& local_address)
00393 {
00394 #if defined (ACE_HAS_IPV6) && defined (IPV6_V6ONLY)
00395   int protocol_family = ACE_PROTOCOL_FAMILY_INET;
00396   int protocol = 0;
00397   int reuse_addr = 0;
00398   if (static_cast<ACE_Addr>(local_address) != ACE_Addr::sap_any) {
00399     protocol_family = local_address.get_type();
00400   } else if (protocol_family == PF_UNSPEC) {
00401     protocol_family = ACE::ipv6_enabled() ? PF_INET6 : PF_INET;
00402   }
00403 
00404   int one = 1;
00405   socket.set_handle(ACE_OS::socket(protocol_family,
00406     SOCK_DGRAM,
00407     protocol));
00408 
00409   if (socket.get_handle() == ACE_INVALID_HANDLE) {
00410     ACE_ERROR_RETURN((LM_WARNING,
00411       ACE_TEXT("(%P|%t) WARNING:")
00412       ACE_TEXT("open_appropriate_socket_type: ")
00413       ACE_TEXT("failed to set socket handle\n")),
00414       false);
00415   } else if (protocol_family != PF_UNIX &&
00416              reuse_addr &&
00417              socket.set_option(SOL_SOCKET,
00418                                SO_REUSEADDR,
00419                                &one,
00420                                sizeof one) == -1) {
00421     socket.close();
00422     ACE_ERROR_RETURN((LM_WARNING,
00423       ACE_TEXT("(%P|%t) WARNING: ")
00424       ACE_TEXT("open_appropriate_socket_type: ")
00425       ACE_TEXT("failed to set socket SO_REUSEADDR option\n")),
00426       false);
00427   }
00428   ACE_HANDLE handle = socket.get_handle();
00429   int ipv6_only = 0;
00430   if (protocol_family == PF_INET6 &&
00431       0 != ACE_OS::setsockopt(handle,
00432                               IPPROTO_IPV6,
00433                               IPV6_V6ONLY,
00434                               (char*)&ipv6_only,
00435                               sizeof(ipv6_only))) {
00436     ACE_ERROR_RETURN((LM_WARNING,
00437       ACE_TEXT("(%P|%t) WARNING: ")
00438       ACE_TEXT("open_appropriate_socket_type: ")
00439       ACE_TEXT("failed to set IPV6_V6ONLY to 0: %p\n"),
00440       ACE_TEXT("ACE_OS::setsockopt(IPV6_V6ONLY)")),
00441       false);
00442   }
00443   bool error = false;
00444 
00445   if (static_cast<ACE_Addr>(local_address) == ACE_Addr::sap_any) {
00446     if (protocol_family == PF_INET || protocol_family == PF_INET6) {
00447       if (ACE::bind_port(socket.get_handle(),
00448                          INADDR_ANY,
00449                          protocol_family) == -1) {
00450         error = true;
00451       }
00452     }
00453   } else if (ACE_OS::bind(socket.get_handle(),
00454                           reinterpret_cast<sockaddr *> (local_address.get_addr()),
00455                           local_address.get_size()) == -1) {
00456     error = true;
00457   }
00458 
00459   if (error) {
00460     socket.close();
00461     VDBG_LVL((LM_WARNING, "(%P|%t) WARNING: open_appropriate_socket_type: "
00462                           "failed to bind address to socket\n"), 2);
00463     return false;
00464   }
00465   return true;
00466 #else
00467   return socket.open(local_address) == 0;
00468 #endif
00469 }
00470 }
00471 }
00472 
00473 OPENDDS_END_VERSIONED_NAMESPACE_DECL
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

Generated on 10 Aug 2018 for OpenDDS by  doxygen 1.6.1