00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
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 
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; 
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; 
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       
00076       
00077       
00078       
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       
00098       enum {
00099         NA, 
00100         LO, 
00101         LL, 
00102         PR, 
00103         MC, 
00104         GL  
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         
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; 
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; 
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       
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 { 
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, 
00170       0 
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 }