Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / native_client_sdk / src / libraries / nacl_io / host_resolver.cc
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
23 namespace {
24
25 void 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
37 void 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
91 namespace nacl_io {
92
93 HostResolver::HostResolver() : hostent_(), ppapi_(NULL) {
94 }
95
96 HostResolver::~HostResolver() {
97   hostent_cleanup();
98 }
99
100 void HostResolver::Init(PepperInterface* ppapi) {
101   ppapi_ = ppapi;
102 }
103
104 struct 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
214 void 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
224 int 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
234 int 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.
433 void 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