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 #include "nacl_io/host_resolver.h"
      6 
      7 #include <stdlib.h>
      8 #include <string.h>
      9 
     10 #include "nacl_io/kernel_proxy.h"
     11 #include "nacl_io/ossocket.h"
     12 #include "nacl_io/pepper_interface.h"
     13 
     14 #ifdef PROVIDES_SOCKET_API
     15 
     16 namespace nacl_io {
     17 
     18 HostResolver::HostResolver() : hostent_(), ppapi_(NULL) {
     19 }
     20 
     21 HostResolver::~HostResolver() {
     22   hostent_cleanup();
     23 }
     24 
     25 void HostResolver::Init(PepperInterface* ppapi) {
     26   ppapi_ = ppapi;
     27 }
     28 
     29 struct hostent* HostResolver::gethostbyname(const char* name) {
     30   h_errno = NETDB_INTERNAL;
     31 
     32   if (NULL == ppapi_)
     33     return NULL;
     34 
     35   HostResolverInterface* resolver_interface =
     36     ppapi_->GetHostResolverInterface();
     37   ScopedResource resolver(ppapi_,
     38                           resolver_interface->Create(ppapi_->GetInstance()));
     39 
     40   struct PP_CompletionCallback callback;
     41   callback.func = NULL;
     42   struct PP_HostResolver_Hint hint;
     43   hint.family = PP_NETADDRESS_FAMILY_IPV4;
     44   hint.flags = PP_HOSTRESOLVER_FLAG_CANONNAME;
     45 
     46   int err = resolver_interface->Resolve(resolver.pp_resource(),
     47                                         name, 0, &hint, callback);
     48   if (err) {
     49     switch (err) {
     50     case PP_ERROR_NOACCESS:
     51       h_errno = NO_RECOVERY;
     52       break;
     53     case PP_ERROR_NAME_NOT_RESOLVED:
     54       h_errno = HOST_NOT_FOUND;
     55       break;
     56     default:
     57       h_errno = NETDB_INTERNAL;
     58       break;
     59     }
     60     return NULL;
     61   }
     62 
     63   // We use a single hostent struct for all calls to to gethostbyname
     64   // (as explicitly permitted by the spec - gethostbyname is NOT supposed to
     65   // be threadsafe!), so the first thing we do is free all the malloced data
     66   // left over from the last call.
     67   hostent_cleanup();
     68 
     69   PP_Var name_var =
     70     resolver_interface->GetCanonicalName(resolver.pp_resource());
     71   if (PP_VARTYPE_STRING != name_var.type)
     72     return NULL;
     73 
     74   uint32_t len;
     75   const char* name_ptr = ppapi_->GetVarInterface()->VarToUtf8(name_var, &len);
     76   if (NULL == name_ptr)
     77     return NULL;
     78   if (0 == len) {
     79     // Sometimes GetCanonicalName gives up more easily than gethostbyname should
     80     // (for example, it returns "" when asked to resolve "localhost"), so if we
     81     // get an empty string we copy over the input string instead.
     82     len = strlen(name);
     83     name_ptr = name;
     84   }
     85   hostent_.h_name = static_cast<char*>(malloc(len + 1));
     86   if (NULL == hostent_.h_name)
     87     return NULL;
     88   memcpy(hostent_.h_name, name_ptr, len);
     89   hostent_.h_name[len] = '\0';
     90 
     91   // Aliases aren't supported at the moment, so we just make an empty list.
     92   hostent_.h_aliases = static_cast<char**>(malloc(sizeof(char*)));
     93   if (NULL == hostent_.h_aliases)
     94     return NULL;
     95   hostent_.h_aliases[0] = NULL;
     96 
     97   NetAddressInterface* netaddr_interface = ppapi_->GetNetAddressInterface();
     98   PP_Resource addr =
     99       resolver_interface->GetNetAddress(resolver.pp_resource(), 0);
    100   if (!PP_ToBool(netaddr_interface->IsNetAddress(addr)))
    101     return NULL;
    102 
    103   switch (netaddr_interface->GetFamily(addr)) {
    104     case PP_NETADDRESS_FAMILY_IPV4:
    105       hostent_.h_addrtype = AF_INET;
    106       hostent_.h_length = 4;
    107       break;
    108     case PP_NETADDRESS_FAMILY_IPV6:
    109       hostent_.h_addrtype = AF_INET6;
    110       hostent_.h_length = 16;
    111       break;
    112     default:
    113       return NULL;
    114   }
    115 
    116   const uint32_t num_addresses =
    117     resolver_interface->GetNetAddressCount(resolver.pp_resource());
    118   if (0 == num_addresses)
    119     return NULL;
    120   hostent_.h_addr_list =
    121     static_cast<char**>(calloc(num_addresses + 1, sizeof(char*)));
    122   if (NULL == hostent_.h_addr_list)
    123     return NULL;
    124 
    125   for (uint32_t i = 0; i < num_addresses; i++) {
    126     PP_Resource addr =
    127       resolver_interface->GetNetAddress(resolver.pp_resource(), i);
    128     if (!PP_ToBool(netaddr_interface->IsNetAddress(addr)))
    129       return NULL;
    130     if (AF_INET == hostent_.h_addrtype) {
    131       struct PP_NetAddress_IPv4 addr_struct;
    132       if (!netaddr_interface->DescribeAsIPv4Address(addr, &addr_struct)) {
    133         return NULL;
    134       }
    135       hostent_.h_addr_list[i] = static_cast<char*>(malloc(hostent_.h_length));
    136       if (NULL == hostent_.h_addr_list[i])
    137         return NULL;
    138       memcpy(hostent_.h_addr_list[i], addr_struct.addr, hostent_.h_length);
    139     } else { // IPv6
    140       struct PP_NetAddress_IPv6 addr_struct;
    141       if (!netaddr_interface->DescribeAsIPv6Address(addr, &addr_struct))
    142         return NULL;
    143       hostent_.h_addr_list[i] = static_cast<char*>(malloc(hostent_.h_length));
    144       if (NULL == hostent_.h_addr_list[i])
    145         return NULL;
    146       memcpy(hostent_.h_addr_list[i], addr_struct.addr, hostent_.h_length);
    147     }
    148   }
    149   return &hostent_;
    150 }
    151 
    152 // Frees all of the deep pointers in a hostent struct. Called between uses of
    153 // gethostbyname, and when the kernel_proxy object is destroyed.
    154 void HostResolver::hostent_cleanup() {
    155   if (NULL != hostent_.h_name) {
    156     free(hostent_.h_name);
    157   }
    158   if (NULL != hostent_.h_aliases) {
    159     for (int i = 0;  NULL != hostent_.h_aliases[i]; i++) {
    160       free(hostent_.h_aliases[i]);
    161     }
    162     free(hostent_.h_aliases);
    163   }
    164   if (NULL != hostent_.h_addr_list) {
    165     for (int i = 0;  NULL != hostent_.h_addr_list[i]; i++) {
    166       free(hostent_.h_addr_list[i]);
    167     }
    168     free(hostent_.h_addr_list);
    169   }
    170   hostent_.h_name = NULL;
    171   hostent_.h_aliases = NULL;
    172   hostent_.h_addr_list = NULL;
    173 }
    174 
    175 }  // namespace nacl_io
    176 
    177 #endif  // PROVIDES_SOCKET_API
    178