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

Generated on Fri Feb 12 20:05:24 2016 for OpenDDS by  doxygen 1.4.7