Home | History | Annotate | Download | only in nacl_io
      1 // Copyright 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #ifndef __STDC_LIMIT_MACROS
      6 #define __STDC_LIMIT_MACROS
      7 #endif
      8 
      9 #include "nacl_io/host_resolver.h"
     10 
     11 #include <assert.h>
     12 #include <stdint.h>
     13 #include <stdlib.h>
     14 #include <string.h>
     15 
     16 #include "nacl_io/kernel_proxy.h"
     17 #include "nacl_io/ossocket.h"
     18 #include "nacl_io/pepper_interface.h"
     19 
     20 #ifdef PROVIDES_SOCKET_API
     21 
     22 namespace {
     23 
     24 void HintsToPPHints(const addrinfo* hints, PP_HostResolver_Hint* pp_hints) {
     25   memset(pp_hints, 0, sizeof(*pp_hints));
     26 
     27   if (hints->ai_family == AF_INET)
     28     pp_hints->family = PP_NETADDRESS_FAMILY_IPV4;
     29   else if (hints->ai_family == AF_INET6)
     30     pp_hints->family = PP_NETADDRESS_FAMILY_IPV6;
     31 
     32   if (hints->ai_flags & AI_CANONNAME)
     33     pp_hints->flags = PP_HOSTRESOLVER_FLAG_CANONNAME;
     34 }
     35 
     36 void CreateAddrInfo(const addrinfo* hints,
     37                     struct sockaddr* addr,
     38                     const char* name,
     39                     addrinfo** list_start,
     40                     addrinfo** list_end) {
     41   addrinfo* ai = static_cast<addrinfo*>(malloc(sizeof(addrinfo)));
     42   memset(ai, 0, sizeof(*ai));
     43 
     44   if (hints && hints->ai_socktype)
     45     ai->ai_socktype = hints->ai_socktype;
     46   else
     47     ai->ai_socktype = SOCK_STREAM;
     48 
     49   if (hints && hints->ai_protocol)
     50     ai->ai_protocol = hints->ai_protocol;
     51 
     52   if (name)
     53     ai->ai_canonname = strdup(name);
     54 
     55   switch (addr->sa_family) {
     56     case AF_INET6: {
     57       sockaddr_in6* in =
     58           static_cast<sockaddr_in6*>(malloc(sizeof(sockaddr_in6)));
     59       *in = *(sockaddr_in6*)addr;
     60       ai->ai_family = AF_INET6;
     61       ai->ai_addr = reinterpret_cast<sockaddr*>(in);
     62       ai->ai_addrlen = sizeof(*in);
     63       break;
     64     }
     65     case AF_INET: {
     66       sockaddr_in* in = static_cast<sockaddr_in*>(malloc(sizeof(sockaddr_in)));
     67       *in = *(sockaddr_in*)addr;
     68       ai->ai_family = AF_INET;
     69       ai->ai_addr = reinterpret_cast<sockaddr*>(in);
     70       ai->ai_addrlen = sizeof(*in);
     71       break;
     72     }
     73     default:
     74       assert(0);
     75       return;
     76   }
     77 
     78   if (*list_start == NULL) {
     79     *list_start = ai;
     80     *list_end = ai;
     81     return;
     82   }
     83 
     84   (*list_end)->ai_next = ai;
     85   *list_end = ai;
     86 }
     87 
     88 }  // namespace
     89 
     90 namespace nacl_io {
     91 
     92 HostResolver::HostResolver() : hostent_(), ppapi_(NULL) {
     93 }
     94 
     95 HostResolver::~HostResolver() {
     96   hostent_cleanup();
     97 }
     98 
     99 void HostResolver::Init(PepperInterface* ppapi) {
    100   ppapi_ = ppapi;
    101 }
    102 
    103 struct hostent* HostResolver::gethostbyname(const char* name) {
    104   h_errno = NETDB_INTERNAL;
    105 
    106   struct addrinfo* ai;
    107   struct addrinfo hints;
    108   memset(&hints, 0, sizeof(hints));
    109   hints.ai_flags = AI_CANONNAME;
    110   hints.ai_family = AF_INET;
    111   int err = getaddrinfo(name, NULL, &hints, &ai);
    112   if (err) {
    113     switch (err) {
    114       case EAI_SYSTEM:
    115         h_errno = NO_RECOVERY;
    116         break;
    117       case EAI_NONAME:
    118         h_errno = HOST_NOT_FOUND;
    119         break;
    120       default:
    121         h_errno = NETDB_INTERNAL;
    122         break;
    123     }
    124     return NULL;
    125   }
    126 
    127   // We use a single hostent struct for all calls to to gethostbyname
    128   // (as explicitly permitted by the spec - gethostbyname is NOT supposed to
    129   // be threadsafe!).  However by using a lock around all the global data
    130   // manipulation we can at least ensure that the call doesn't crash.
    131   AUTO_LOCK(gethostbyname_lock_);
    132 
    133   // The first thing we do is free any malloced data left over from
    134   // the last call.
    135   hostent_cleanup();
    136 
    137   switch (ai->ai_family) {
    138     case AF_INET:
    139       hostent_.h_addrtype = AF_INET;
    140       hostent_.h_length = sizeof(in_addr);
    141       break;
    142     case AF_INET6:
    143       hostent_.h_addrtype = AF_INET6;
    144       hostent_.h_length = sizeof(in6_addr);
    145       break;
    146     default:
    147       return NULL;
    148   }
    149 
    150   if (ai->ai_canonname != NULL)
    151     hostent_.h_name = strdup(ai->ai_canonname);
    152   else
    153     hostent_.h_name = strdup(name);
    154 
    155   // Aliases aren't supported at the moment, so we just make an empty list.
    156   hostent_.h_aliases = static_cast<char**>(malloc(sizeof(char*)));
    157   if (NULL == hostent_.h_aliases)
    158     return NULL;
    159   hostent_.h_aliases[0] = NULL;
    160 
    161   // Count number of address in list
    162   int num_addresses = 0;
    163   struct addrinfo* current = ai;
    164   while (current != NULL) {
    165     // Only count address that have the same type as first address
    166     if (current->ai_family == hostent_.h_addrtype)
    167       num_addresses++;
    168     current = current->ai_next;
    169   }
    170 
    171   // Allocate address list
    172   hostent_.h_addr_list = static_cast<char**>(calloc(num_addresses + 1,
    173                                                     sizeof(char*)));
    174   if (NULL == hostent_.h_addr_list)
    175     return NULL;
    176 
    177   // Copy all addresses of the relevant family.
    178   current = ai;
    179   char** hostent_addr = hostent_.h_addr_list;
    180   while (current != NULL) {
    181     if (current->ai_family != hostent_.h_addrtype) {
    182       current = current->ai_next;
    183       continue;
    184     }
    185     *hostent_addr = static_cast<char*>(malloc(hostent_.h_length));
    186     switch (current->ai_family) {
    187       case AF_INET: {
    188         sockaddr_in* in = reinterpret_cast<sockaddr_in*>(current->ai_addr);
    189         memcpy(*hostent_addr, &in->sin_addr.s_addr, hostent_.h_length);
    190         break;
    191       }
    192       case AF_INET6: {
    193         sockaddr_in6* in6 = reinterpret_cast<sockaddr_in6*>(current->ai_addr);
    194         memcpy(*hostent_addr, &in6->sin6_addr.s6_addr, hostent_.h_length);
    195         break;
    196       }
    197     }
    198     current = current->ai_next;
    199     hostent_addr++;
    200   }
    201 
    202   freeaddrinfo(ai);
    203 
    204 #if !defined(h_addr)
    205   // Copy element zero of h_addr_list to h_addr when h_addr is not defined
    206   // as in some libc's h_addr may be a separate member instead of a macro.
    207   hostent_.h_addr = hostent_.h_addr_list[0];
    208 #endif
    209 
    210   return &hostent_;
    211 }
    212 
    213 void HostResolver::freeaddrinfo(struct addrinfo* res) {
    214   while (res) {
    215     struct addrinfo* cur = res;
    216     res = res->ai_next;
    217     free(cur->ai_addr);
    218     free(cur->ai_canonname);
    219     free(cur);
    220   }
    221 }
    222 
    223 int HostResolver::getaddrinfo(const char* node,
    224                               const char* service,
    225                               const struct addrinfo* hints_in,
    226                               struct addrinfo** result) {
    227   *result = NULL;
    228   struct addrinfo* end = NULL;
    229 
    230   if (node == NULL && service == NULL)
    231     return EAI_NONAME;
    232 
    233   // Check the service name (port).  Currently we only handle numeric
    234   // services.
    235   long port = 0;
    236   if (service != NULL) {
    237     char* cp;
    238     port = strtol(service, &cp, 10);
    239     if (port >= 0 && port <= UINT16_MAX && *cp == '\0') {
    240       port = htons(port);
    241     } else {
    242       return EAI_SERVICE;
    243     }
    244   }
    245 
    246   struct addrinfo default_hints;
    247   memset(&default_hints, 0, sizeof(default_hints));
    248   const struct addrinfo* hints = hints_in ? hints_in : &default_hints;
    249 
    250   // Verify values passed in hints structure
    251   switch (hints->ai_family) {
    252     case AF_INET6:
    253     case AF_INET:
    254     case AF_UNSPEC:
    255       break;
    256     default:
    257       return EAI_FAMILY;
    258   }
    259 
    260   struct sockaddr_in addr_in;
    261   memset(&addr_in, 0, sizeof(addr_in));
    262   addr_in.sin_family = AF_INET;
    263   addr_in.sin_port = port;
    264 
    265   struct sockaddr_in6 addr_in6;
    266   memset(&addr_in6, 0, sizeof(addr_in6));
    267   addr_in6.sin6_family = AF_INET6;
    268   addr_in6.sin6_port = port;
    269 
    270   if (node) {
    271     // Handle numeric node name.
    272     if (hints->ai_family == AF_INET || hints->ai_family == AF_UNSPEC) {
    273       in_addr in;
    274       if (inet_pton(AF_INET, node, &in)) {
    275         addr_in.sin_addr = in;
    276         CreateAddrInfo(hints, (sockaddr*)&addr_in, node, result, &end);
    277         return 0;
    278       }
    279     }
    280 
    281     if (hints->ai_family == AF_INET6 || hints->ai_family == AF_UNSPEC) {
    282       in6_addr in6;
    283       if (inet_pton(AF_INET6, node, &in6)) {
    284         addr_in6.sin6_addr = in6;
    285         CreateAddrInfo(hints, (sockaddr*)&addr_in6, node, result, &end);
    286         return 0;
    287       }
    288     }
    289   }
    290 
    291   // Handle AI_PASSIVE (used for listening sockets, e.g. INADDR_ANY)
    292   if (node == NULL && (hints->ai_flags & AI_PASSIVE)) {
    293     if (hints->ai_family == AF_INET6 || hints->ai_family == AF_UNSPEC) {
    294       const in6_addr in6addr_any = IN6ADDR_ANY_INIT;
    295       memcpy(&addr_in6.sin6_addr.s6_addr, &in6addr_any, sizeof(in6addr_any));
    296       CreateAddrInfo(hints, (sockaddr*)&addr_in6, NULL, result, &end);
    297     }
    298 
    299     if (hints->ai_family == AF_INET || hints->ai_family == AF_UNSPEC) {
    300       addr_in.sin_addr.s_addr = INADDR_ANY;
    301       CreateAddrInfo(hints, (sockaddr*)&addr_in, NULL, result, &end);
    302     }
    303     return 0;
    304   }
    305 
    306   if (NULL == ppapi_)
    307     return EAI_SYSTEM;
    308 
    309   // Use PPAPI interface to resolve nodename
    310   HostResolverInterface* resolver_iface = ppapi_->GetHostResolverInterface();
    311   VarInterface* var_interface = ppapi_->GetVarInterface();
    312   NetAddressInterface* netaddr_iface = ppapi_->GetNetAddressInterface();
    313 
    314   if (NULL == resolver_iface || NULL == var_interface || NULL == netaddr_iface)
    315     return EAI_SYSTEM;
    316 
    317   ScopedResource scoped_resolver(ppapi_,
    318                                  resolver_iface->Create(ppapi_->GetInstance()));
    319   PP_Resource resolver = scoped_resolver.pp_resource();
    320 
    321   struct PP_HostResolver_Hint pp_hints;
    322   HintsToPPHints(hints, &pp_hints);
    323 
    324   int err = resolver_iface->Resolve(resolver,
    325                                     node,
    326                                     0,
    327                                     &pp_hints,
    328                                     PP_BlockUntilComplete());
    329   if (err) {
    330     switch (err) {
    331       case PP_ERROR_NOACCESS:
    332         return EAI_SYSTEM;
    333       case PP_ERROR_NAME_NOT_RESOLVED:
    334         return EAI_NONAME;
    335       default:
    336         return EAI_SYSTEM;
    337     }
    338   }
    339 
    340   char* canon_name = NULL;
    341   if (hints->ai_flags & AI_CANONNAME) {
    342     PP_Var name_var = resolver_iface->GetCanonicalName(resolver);
    343     if (PP_VARTYPE_STRING == name_var.type) {
    344       uint32_t len = 0;
    345       const char* tmp = var_interface->VarToUtf8(name_var, &len);
    346       // For some reason GetCanonicalName alway returns an empty
    347       // string so this condition is never true.
    348       // TODO(sbc): investigate this issue with PPAPI team.
    349       if (len > 0) {
    350         // Copy and NULL-terminate the UTF8 string var.
    351         canon_name = static_cast<char*>(malloc(len + 1));
    352         strncpy(canon_name, tmp, len);
    353         canon_name[len] = '\0';
    354       }
    355     }
    356     if (!canon_name)
    357       canon_name = strdup(node);
    358     var_interface->Release(name_var);
    359   }
    360 
    361   int num_addresses = resolver_iface->GetNetAddressCount(resolver);
    362   if (0 == num_addresses)
    363     return EAI_NODATA;
    364 
    365   // Convert address to sockaddr struct.
    366   for (int i = 0; i < num_addresses; i++) {
    367     ScopedResource addr(ppapi_, resolver_iface->GetNetAddress(resolver, i));
    368     PP_Resource resource = addr.pp_resource();
    369     assert(resource != 0);
    370     assert(PP_ToBool(netaddr_iface->IsNetAddress(resource)));
    371     struct sockaddr* sockaddr = NULL;
    372     switch (netaddr_iface->GetFamily(resource)) {
    373       case PP_NETADDRESS_FAMILY_IPV4: {
    374         struct PP_NetAddress_IPv4 pp_addr;
    375         if (!netaddr_iface->DescribeAsIPv4Address(resource, &pp_addr)) {
    376           assert(false);
    377           break;
    378         }
    379         memcpy(&addr_in.sin_addr.s_addr, pp_addr.addr, sizeof(in_addr_t));
    380         sockaddr = (struct sockaddr*)&addr_in;
    381         break;
    382       }
    383       case PP_NETADDRESS_FAMILY_IPV6: {
    384         struct PP_NetAddress_IPv6 pp_addr;
    385         if (!netaddr_iface->DescribeAsIPv6Address(resource, &pp_addr)) {
    386           assert(false);
    387           break;
    388         }
    389         memcpy(&addr_in6.sin6_addr.s6_addr, pp_addr.addr, sizeof(in6_addr));
    390         sockaddr = (struct sockaddr*)&addr_in6;
    391         break;
    392       }
    393       default:
    394         return EAI_SYSTEM;
    395     }
    396 
    397     if (sockaddr != NULL)
    398       CreateAddrInfo(hints, sockaddr, canon_name, result, &end);
    399 
    400     if (canon_name) {
    401       free(canon_name);
    402       canon_name = NULL;
    403     }
    404   }
    405 
    406   return 0;
    407 }
    408 
    409 // Frees all of the deep pointers in a hostent struct. Called between uses of
    410 // gethostbyname, and when the kernel_proxy object is destroyed.
    411 void HostResolver::hostent_cleanup() {
    412   if (NULL != hostent_.h_name) {
    413     free(hostent_.h_name);
    414   }
    415   if (NULL != hostent_.h_aliases) {
    416     for (int i = 0; NULL != hostent_.h_aliases[i]; i++) {
    417       free(hostent_.h_aliases[i]);
    418     }
    419     free(hostent_.h_aliases);
    420   }
    421   if (NULL != hostent_.h_addr_list) {
    422     for (int i = 0; NULL != hostent_.h_addr_list[i]; i++) {
    423       free(hostent_.h_addr_list[i]);
    424     }
    425     free(hostent_.h_addr_list);
    426   }
    427   hostent_.h_name = NULL;
    428   hostent_.h_aliases = NULL;
    429   hostent_.h_addr_list = NULL;
    430 #if !defined(h_addr)
    431   // Initialize h_addr separately in the case where it is not a macro.
    432   hostent_.h_addr = NULL;
    433 #endif
    434 }
    435 
    436 }  // namespace nacl_io
    437 
    438 #endif  // PROVIDES_SOCKET_API
    439