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