• Main Page
  • Related Pages
  • Namespaces
  • Data Structures
  • Files
  • File List
  • Globals

Machine.cc

Go to the documentation of this file.
00001 /** @file
00002 
00003   Support class for describing the local machine.
00004 
00005   @section license License
00006 
00007   Licensed to the Apache Software Foundation (ASF) under one
00008   or more contributor license agreements.  See the NOTICE file
00009   distributed with this work for additional information
00010   regarding copyright ownership.  The ASF licenses this file
00011   to you under the Apache License, Version 2.0 (the
00012   "License"); you may not use this file except in compliance
00013   with the License.  You may obtain a copy of the License at
00014 
00015       http://www.apache.org/licenses/LICENSE-2.0
00016 
00017   Unless required by applicable law or agreed to in writing, software
00018   distributed under the License is distributed on an "AS IS" BASIS,
00019   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00020   See the License for the specific language governing permissions and
00021   limitations under the License.
00022  */
00023 
00024 #include "libts.h"
00025 #include "I_Machine.h"
00026 
00027 #if HAVE_IFADDRS_H
00028 #  include <ifaddrs.h>
00029 #endif
00030 
00031 // Singleton
00032 Machine* Machine::_instance = NULL;
00033 
00034 Machine*
00035 Machine::instance() {
00036   ink_assert(_instance || !"Machine instance accessed before initialization");
00037   return Machine::_instance;
00038 }
00039 
00040 Machine*
00041 Machine::init(char const* name, sockaddr const* ip) {
00042   ink_assert(!_instance || !"Machine instance initialized twice.");
00043   Machine::_instance = new Machine(name, ip);
00044   return Machine::_instance;
00045 }
00046 
00047 Machine::Machine(char const* the_hostname, sockaddr const* addr)
00048   : hostname(0), hostname_len(0)
00049   , ip_string_len(0)
00050   , ip_hex_string_len(0)
00051 {
00052   char localhost[1024];
00053   int status; // return for system calls.
00054 
00055   ip_string[0] = 0;
00056   ip_hex_string[0] = 0;
00057   ink_zero(ip);
00058   ink_zero(ip4);
00059   ink_zero(ip6);
00060 
00061   localhost[sizeof(localhost)-1] = 0; // ensure termination.
00062 
00063   if (!ats_is_ip(addr)) {
00064     if (!the_hostname) {
00065       ink_release_assert(!gethostname(localhost, sizeof(localhost)-1));
00066       the_hostname = localhost;
00067     }
00068     hostname = ats_strdup(the_hostname);
00069 
00070 #if HAVE_IFADDRS_H
00071       ifaddrs* ifa_addrs = 0;
00072       status = getifaddrs(&ifa_addrs);
00073 #else
00074       int s = socket(AF_INET, SOCK_DGRAM, 0);
00075       // This number is hard to determine, but needs to be much larger than
00076       // you would expect. On a normal system with just two interfaces and
00077       // one address / interface the return count is 120. Stack space is
00078       // cheap so it's best to go big.
00079       static const int N_REQ = 1024;
00080       ifconf conf;
00081       ifreq req[N_REQ];
00082       if (0 <= s) {
00083         conf.ifc_len = sizeof(req);
00084         conf.ifc_req = req;
00085         status = ioctl(s, SIOCGIFCONF, &conf);
00086       } else {
00087         status = -1;
00088       }
00089 #endif
00090 
00091     if (0 != status) {
00092       Warning("Unable to determine local host '%s' address information - %s"
00093         , hostname
00094         , strerror(errno)
00095       );
00096     } else {
00097       // Loop through the interface addresses and prefer by type.
00098       enum {
00099         NA, // Not an (IP) Address.
00100         LO, // Loopback.
00101         LL, // Link Local
00102         PR, // Private.
00103         MC, // Multicast.
00104         GL  // Global.
00105       } spot_type = NA, ip4_type = NA, ip6_type = NA;
00106       sockaddr const* ifip;
00107       unsigned int ifflags;
00108       for (
00109 #if HAVE_IFADDRS_H
00110         ifaddrs* spot = ifa_addrs ; spot ; spot = spot->ifa_next
00111 #else
00112           ifreq* spot = req, *req_limit = req + (conf.ifc_len/sizeof(*req)) ; spot < req_limit ; ++spot
00113 #endif
00114       ) {
00115 #if HAVE_IFADDRS_H
00116         ifip = spot->ifa_addr;
00117         ifflags = spot->ifa_flags;
00118 #else
00119         ifip = &spot->ifr_addr;
00120 
00121         // get the interface's flags
00122         struct ifreq ifr;
00123         ink_strlcpy(ifr.ifr_name, spot->ifr_name, IFNAMSIZ);
00124         if (ioctl(s, SIOCGIFFLAGS, &ifr) == 0)   ifflags = ifr.ifr_flags;
00125         else ifflags = 0; // flags not available, default to just looking at IP
00126 #endif
00127         if (!ats_is_ip(ifip)) spot_type = NA;
00128         else if (ats_is_ip_loopback(ifip) || (IFF_LOOPBACK & ifflags)) spot_type = LO;
00129         else if (ats_is_ip_linklocal(ifip)) spot_type = LL;
00130         else if (ats_is_ip_private(ifip)) spot_type = PR;
00131         else if (ats_is_ip_multicast(ifip)) spot_type = MC;
00132         else spot_type = GL;
00133         if (spot_type == NA) continue; // Next!
00134 
00135         if (ats_is_ip4(ifip)) {
00136           if (spot_type > ip4_type) {
00137             ats_ip_copy(&ip4, ifip);
00138             ip4_type = spot_type;
00139           }
00140         } else if (ats_is_ip6(ifip)) {
00141           if (spot_type > ip6_type) {
00142             ats_ip_copy(&ip6, ifip);
00143             ip6_type = spot_type;
00144           }
00145         }
00146       }
00147 
00148 #if HAVE_IFADDRS_H
00149       freeifaddrs(ifa_addrs);
00150 #endif
00151 
00152       // What about the general address? Prefer IPv4?
00153       if (ip4_type >= ip6_type)
00154         ats_ip_copy(&ip.sa, &ip4.sa);
00155       else
00156         ats_ip_copy(&ip.sa, &ip6.sa);
00157     }
00158 #if ! HAVE_IFADDRS_H
00159     close(s);
00160 #endif
00161   } else { // address provided.
00162     ats_ip_copy(&ip, addr);
00163     if (ats_is_ip4(addr)) ats_ip_copy(&ip4, addr);
00164     else if (ats_is_ip6(addr)) ats_ip_copy(&ip6, addr);
00165 
00166     status = getnameinfo(
00167       addr, ats_ip_size(addr),
00168       localhost, sizeof(localhost) - 1,
00169       0, 0, // do not request service info
00170       0 // no flags.
00171     );
00172 
00173     if (0 != status) {
00174       ip_text_buffer ipbuff;
00175       Warning("Failed to find hostname for address '%s' - %s"
00176         , ats_ip_ntop(addr, ipbuff, sizeof(ipbuff))
00177         , gai_strerror(status)
00178       );
00179     } else
00180       hostname = ats_strdup(localhost);
00181   }
00182 
00183   hostname_len = hostname ? strlen(hostname) : 0;
00184 
00185   ats_ip_ntop(&ip.sa, ip_string, sizeof(ip_string));
00186   ip_string_len = strlen(ip_string);
00187   ip_hex_string_len = ats_ip_to_hex(&ip.sa, ip_hex_string, sizeof(ip_hex_string));
00188 }
00189 
00190 Machine::~Machine()
00191 {
00192   ats_free(hostname);
00193 }

Generated by  doxygen 1.7.1