- add sources.
[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 #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