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