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.
5 #ifndef __STDC_LIMIT_MACROS
6 #define __STDC_LIMIT_MACROS
9 #include "nacl_io/host_resolver.h"
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"
21 #ifdef PROVIDES_SOCKET_API
25 void HintsToPPHints(const addrinfo
* hints
, PP_HostResolver_Hint
* pp_hints
) {
26 memset(pp_hints
, 0, sizeof(*pp_hints
));
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
;
33 if (hints
->ai_flags
& AI_CANONNAME
)
34 pp_hints
->flags
= PP_HOSTRESOLVER_FLAG_CANONNAME
;
37 void CreateAddrInfo(const addrinfo
* hints
,
38 struct sockaddr
* addr
,
40 addrinfo
** list_start
,
41 addrinfo
** list_end
) {
42 addrinfo
* ai
= static_cast<addrinfo
*>(malloc(sizeof(addrinfo
)));
43 memset(ai
, 0, sizeof(*ai
));
45 if (hints
&& hints
->ai_socktype
)
46 ai
->ai_socktype
= hints
->ai_socktype
;
48 ai
->ai_socktype
= SOCK_STREAM
;
50 if (hints
&& hints
->ai_protocol
)
51 ai
->ai_protocol
= hints
->ai_protocol
;
54 ai
->ai_canonname
= strdup(name
);
56 switch (addr
->sa_family
) {
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
);
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
);
79 if (*list_start
== NULL
) {
85 (*list_end
)->ai_next
= ai
;
93 HostResolver::HostResolver() : hostent_(), ppapi_(NULL
) {
96 HostResolver::~HostResolver() {
100 void HostResolver::Init(PepperInterface
* ppapi
) {
104 struct hostent
* HostResolver::gethostbyname(const char* name
) {
105 h_errno
= NETDB_INTERNAL
;
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
);
116 h_errno
= NO_RECOVERY
;
119 h_errno
= HOST_NOT_FOUND
;
122 h_errno
= NETDB_INTERNAL
;
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_
);
134 // The first thing we do is free any malloced data left over from
138 switch (ai
->ai_family
) {
140 hostent_
.h_addrtype
= AF_INET
;
141 hostent_
.h_length
= sizeof(in_addr
);
144 hostent_
.h_addrtype
= AF_INET6
;
145 hostent_
.h_length
= sizeof(in6_addr
);
151 if (ai
->ai_canonname
!= NULL
)
152 hostent_
.h_name
= strdup(ai
->ai_canonname
);
154 hostent_
.h_name
= strdup(name
);
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
)
160 hostent_
.h_aliases
[0] = NULL
;
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
)
169 current
= current
->ai_next
;
172 // Allocate address list
173 hostent_
.h_addr_list
= static_cast<char**>(calloc(num_addresses
+ 1,
175 if (NULL
== hostent_
.h_addr_list
)
178 // Copy all addresses of the relevant family.
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
;
186 *hostent_addr
= static_cast<char*>(malloc(hostent_
.h_length
));
187 switch (current
->ai_family
) {
189 sockaddr_in
* in
= reinterpret_cast<sockaddr_in
*>(current
->ai_addr
);
190 memcpy(*hostent_addr
, &in
->sin_addr
.s_addr
, hostent_
.h_length
);
194 sockaddr_in6
* in6
= reinterpret_cast<sockaddr_in6
*>(current
->ai_addr
);
195 memcpy(*hostent_addr
, &in6
->sin6_addr
.s6_addr
, hostent_
.h_length
);
199 current
= current
->ai_next
;
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];
214 void HostResolver::freeaddrinfo(struct addrinfo
* res
) {
216 struct addrinfo
* cur
= res
;
219 free(cur
->ai_canonname
);
224 int HostResolver::getnameinfo(const struct sockaddr
*sa
,
234 int HostResolver::getaddrinfo(const char* node
,
236 const struct addrinfo
* hints_in
,
237 struct addrinfo
** result
) {
239 struct addrinfo
* end
= NULL
;
241 if (node
== NULL
&& service
== NULL
) {
242 LOG_TRACE("node and service are NULL.");
246 // Check the service name (port). Currently we only handle numeric
249 if (service
!= NULL
) {
251 port
= strtol(service
, &cp
, 10);
252 if (port
>= 0 && port
<= UINT16_MAX
&& *cp
== '\0') {
255 LOG_TRACE("Service \"%s\" not supported.", service
);
260 struct addrinfo default_hints
;
261 memset(&default_hints
, 0, sizeof(default_hints
));
262 const struct addrinfo
* hints
= hints_in
? hints_in
: &default_hints
;
264 // Verify values passed in hints structure
265 switch (hints
->ai_family
) {
271 LOG_TRACE("Unknown family: %d.", hints
->ai_family
);
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
;
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
;
286 // Handle numeric node name.
287 if (hints
->ai_family
== AF_INET
|| hints
->ai_family
== AF_UNSPEC
) {
289 if (inet_pton(AF_INET
, node
, &in
)) {
290 addr_in
.sin_addr
= in
;
291 CreateAddrInfo(hints
, (sockaddr
*)&addr_in
, node
, result
, &end
);
296 if (hints
->ai_family
== AF_INET6
|| hints
->ai_family
== AF_UNSPEC
) {
298 if (inet_pton(AF_INET6
, node
, &in6
)) {
299 addr_in6
.sin6_addr
= in6
;
300 CreateAddrInfo(hints
, (sockaddr
*)&addr_in6
, node
, result
, &end
);
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
);
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
);
321 if (NULL
== ppapi_
) {
322 LOG_ERROR("ppapi_ is NULL.");
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();
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");
339 ScopedResource
scoped_resolver(ppapi_
,
340 resolver_iface
->Create(ppapi_
->GetInstance()));
341 PP_Resource resolver
= scoped_resolver
.pp_resource();
343 struct PP_HostResolver_Hint pp_hints
;
344 HintsToPPHints(hints
, &pp_hints
);
346 int err
= resolver_iface
->Resolve(resolver
,
350 PP_BlockUntilComplete());
353 case PP_ERROR_NOACCESS
:
355 case PP_ERROR_NAME_NOT_RESOLVED
:
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
) {
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.
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';
379 canon_name
= strdup(node
);
380 var_iface
->Release(name_var
);
383 int num_addresses
= resolver_iface
->GetNetAddressCount(resolver
);
384 if (0 == num_addresses
)
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
)) {
401 memcpy(&addr_in
.sin_addr
.s_addr
, pp_addr
.addr
, sizeof(in_addr_t
));
402 sockaddr
= (struct sockaddr
*)&addr_in
;
405 case PP_NETADDRESS_FAMILY_IPV6
: {
406 struct PP_NetAddress_IPv6 pp_addr
;
407 if (!netaddr_iface
->DescribeAsIPv6Address(resource
, &pp_addr
)) {
411 memcpy(&addr_in6
.sin6_addr
.s6_addr
, pp_addr
.addr
, sizeof(in6_addr
));
412 sockaddr
= (struct sockaddr
*)&addr_in6
;
419 if (sockaddr
!= NULL
)
420 CreateAddrInfo(hints
, sockaddr
, canon_name
, result
, &end
);
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.
433 void HostResolver::hostent_cleanup() {
434 if (NULL
!= hostent_
.h_name
) {
435 free(hostent_
.h_name
);
437 if (NULL
!= hostent_
.h_aliases
) {
438 for (int i
= 0; NULL
!= hostent_
.h_aliases
[i
]; i
++) {
439 free(hostent_
.h_aliases
[i
]);
441 free(hostent_
.h_aliases
);
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
]);
447 free(hostent_
.h_addr_list
);
449 hostent_
.h_name
= NULL
;
450 hostent_
.h_aliases
= NULL
;
451 hostent_
.h_addr_list
= NULL
;
453 // Initialize h_addr separately in the case where it is not a macro.
454 hostent_
.h_addr
= NULL
;
458 } // namespace nacl_io
460 #endif // PROVIDES_SOCKET_API