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::getaddrinfo(const char* node
,
226 const struct addrinfo
* hints_in
,
227 struct addrinfo
** result
) {
229 struct addrinfo
* end
= NULL
;
231 if (node
== NULL
&& service
== NULL
) {
232 LOG_TRACE("node and service are NULL.");
236 // Check the service name (port). Currently we only handle numeric
239 if (service
!= NULL
) {
241 port
= strtol(service
, &cp
, 10);
242 if (port
>= 0 && port
<= UINT16_MAX
&& *cp
== '\0') {
245 LOG_TRACE("Service \"%s\" not supported.", service
);
250 struct addrinfo default_hints
;
251 memset(&default_hints
, 0, sizeof(default_hints
));
252 const struct addrinfo
* hints
= hints_in
? hints_in
: &default_hints
;
254 // Verify values passed in hints structure
255 switch (hints
->ai_family
) {
261 LOG_TRACE("Unknown family: %d.", hints
->ai_family
);
265 struct sockaddr_in addr_in
;
266 memset(&addr_in
, 0, sizeof(addr_in
));
267 addr_in
.sin_family
= AF_INET
;
268 addr_in
.sin_port
= port
;
270 struct sockaddr_in6 addr_in6
;
271 memset(&addr_in6
, 0, sizeof(addr_in6
));
272 addr_in6
.sin6_family
= AF_INET6
;
273 addr_in6
.sin6_port
= port
;
276 // Handle numeric node name.
277 if (hints
->ai_family
== AF_INET
|| hints
->ai_family
== AF_UNSPEC
) {
279 if (inet_pton(AF_INET
, node
, &in
)) {
280 addr_in
.sin_addr
= in
;
281 CreateAddrInfo(hints
, (sockaddr
*)&addr_in
, node
, result
, &end
);
286 if (hints
->ai_family
== AF_INET6
|| hints
->ai_family
== AF_UNSPEC
) {
288 if (inet_pton(AF_INET6
, node
, &in6
)) {
289 addr_in6
.sin6_addr
= in6
;
290 CreateAddrInfo(hints
, (sockaddr
*)&addr_in6
, node
, result
, &end
);
296 // Handle AI_PASSIVE (used for listening sockets, e.g. INADDR_ANY)
297 if (node
== NULL
&& (hints
->ai_flags
& AI_PASSIVE
)) {
298 if (hints
->ai_family
== AF_INET6
|| hints
->ai_family
== AF_UNSPEC
) {
299 const in6_addr in6addr_any
= IN6ADDR_ANY_INIT
;
300 memcpy(&addr_in6
.sin6_addr
.s6_addr
, &in6addr_any
, sizeof(in6addr_any
));
301 CreateAddrInfo(hints
, (sockaddr
*)&addr_in6
, NULL
, result
, &end
);
304 if (hints
->ai_family
== AF_INET
|| hints
->ai_family
== AF_UNSPEC
) {
305 addr_in
.sin_addr
.s_addr
= INADDR_ANY
;
306 CreateAddrInfo(hints
, (sockaddr
*)&addr_in
, NULL
, result
, &end
);
311 if (NULL
== ppapi_
) {
312 LOG_ERROR("ppapi_ is NULL.");
316 // Use PPAPI interface to resolve nodename
317 HostResolverInterface
* resolver_iface
= ppapi_
->GetHostResolverInterface();
318 VarInterface
* var_iface
= ppapi_
->GetVarInterface();
319 NetAddressInterface
* netaddr_iface
= ppapi_
->GetNetAddressInterface();
321 if (!(resolver_iface
&& var_iface
&& netaddr_iface
)) {
322 LOG_ERROR("Got NULL interface(s): %s%s%s",
323 resolver_iface
? "" : "HostResolver ",
324 var_iface
? "" : "Var ",
325 netaddr_iface
? "" : "NetAddress");
329 ScopedResource
scoped_resolver(ppapi_
,
330 resolver_iface
->Create(ppapi_
->GetInstance()));
331 PP_Resource resolver
= scoped_resolver
.pp_resource();
333 struct PP_HostResolver_Hint pp_hints
;
334 HintsToPPHints(hints
, &pp_hints
);
336 int err
= resolver_iface
->Resolve(resolver
,
340 PP_BlockUntilComplete());
343 case PP_ERROR_NOACCESS
:
345 case PP_ERROR_NAME_NOT_RESOLVED
:
352 char* canon_name
= NULL
;
353 if (hints
->ai_flags
& AI_CANONNAME
) {
354 PP_Var name_var
= resolver_iface
->GetCanonicalName(resolver
);
355 if (PP_VARTYPE_STRING
== name_var
.type
) {
357 const char* tmp
= var_iface
->VarToUtf8(name_var
, &len
);
358 // For some reason GetCanonicalName alway returns an empty
359 // string so this condition is never true.
360 // TODO(sbc): investigate this issue with PPAPI team.
362 // Copy and NULL-terminate the UTF8 string var.
363 canon_name
= static_cast<char*>(malloc(len
+ 1));
364 strncpy(canon_name
, tmp
, len
);
365 canon_name
[len
] = '\0';
369 canon_name
= strdup(node
);
370 var_iface
->Release(name_var
);
373 int num_addresses
= resolver_iface
->GetNetAddressCount(resolver
);
374 if (0 == num_addresses
)
377 // Convert address to sockaddr struct.
378 for (int i
= 0; i
< num_addresses
; i
++) {
379 ScopedResource
addr(ppapi_
, resolver_iface
->GetNetAddress(resolver
, i
));
380 PP_Resource resource
= addr
.pp_resource();
381 assert(resource
!= 0);
382 assert(PP_ToBool(netaddr_iface
->IsNetAddress(resource
)));
383 struct sockaddr
* sockaddr
= NULL
;
384 switch (netaddr_iface
->GetFamily(resource
)) {
385 case PP_NETADDRESS_FAMILY_IPV4
: {
386 struct PP_NetAddress_IPv4 pp_addr
;
387 if (!netaddr_iface
->DescribeAsIPv4Address(resource
, &pp_addr
)) {
391 memcpy(&addr_in
.sin_addr
.s_addr
, pp_addr
.addr
, sizeof(in_addr_t
));
392 sockaddr
= (struct sockaddr
*)&addr_in
;
395 case PP_NETADDRESS_FAMILY_IPV6
: {
396 struct PP_NetAddress_IPv6 pp_addr
;
397 if (!netaddr_iface
->DescribeAsIPv6Address(resource
, &pp_addr
)) {
401 memcpy(&addr_in6
.sin6_addr
.s6_addr
, pp_addr
.addr
, sizeof(in6_addr
));
402 sockaddr
= (struct sockaddr
*)&addr_in6
;
409 if (sockaddr
!= NULL
)
410 CreateAddrInfo(hints
, sockaddr
, canon_name
, result
, &end
);
421 // Frees all of the deep pointers in a hostent struct. Called between uses of
422 // gethostbyname, and when the kernel_proxy object is destroyed.
423 void HostResolver::hostent_cleanup() {
424 if (NULL
!= hostent_
.h_name
) {
425 free(hostent_
.h_name
);
427 if (NULL
!= hostent_
.h_aliases
) {
428 for (int i
= 0; NULL
!= hostent_
.h_aliases
[i
]; i
++) {
429 free(hostent_
.h_aliases
[i
]);
431 free(hostent_
.h_aliases
);
433 if (NULL
!= hostent_
.h_addr_list
) {
434 for (int i
= 0; NULL
!= hostent_
.h_addr_list
[i
]; i
++) {
435 free(hostent_
.h_addr_list
[i
]);
437 free(hostent_
.h_addr_list
);
439 hostent_
.h_name
= NULL
;
440 hostent_
.h_aliases
= NULL
;
441 hostent_
.h_addr_list
= NULL
;
443 // Initialize h_addr separately in the case where it is not a macro.
444 hostent_
.h_addr
= NULL
;
448 } // namespace nacl_io
450 #endif // PROVIDES_SOCKET_API