Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1054)

Side by Side Diff: native_client_sdk/src/libraries/nacl_io/host_resolver.cc

Issue 99933002: [NaCl SDK] nacl_io: implement getaddrinfo() (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "nacl_io/host_resolver.h" 5 #include "nacl_io/host_resolver.h"
6 6
7 #include <assert.h>
7 #include <stdlib.h> 8 #include <stdlib.h>
8 #include <string.h> 9 #include <string.h>
9 10
10 #include "nacl_io/kernel_proxy.h" 11 #include "nacl_io/kernel_proxy.h"
11 #include "nacl_io/ossocket.h" 12 #include "nacl_io/ossocket.h"
12 #include "nacl_io/pepper_interface.h" 13 #include "nacl_io/pepper_interface.h"
13 14
14 #ifdef PROVIDES_SOCKET_API 15 #ifdef PROVIDES_SOCKET_API
15 16
17 namespace {
18
19 void HintsToPPHints(const addrinfo* hints, PP_HostResolver_Hint* pp_hints) {
20 memset(pp_hints, 0, sizeof(*pp_hints));
21
22 if (hints->ai_family == AF_INET)
23 pp_hints->family = PP_NETADDRESS_FAMILY_IPV4;
24 else if (hints->ai_family == AF_INET6)
25 pp_hints->family = PP_NETADDRESS_FAMILY_IPV6;
26
27 if (hints->ai_flags & AI_CANONNAME)
28 pp_hints->flags = PP_HOSTRESOLVER_FLAG_CANONNAME;
29 }
30
31 void CreateAddrInfo(const addrinfo* hints,
32 struct sockaddr* addr,
33 const char* name,
34 addrinfo** list_start,
35 addrinfo** list_end) {
36 addrinfo* ai = reinterpret_cast<addrinfo*>(malloc(sizeof(addrinfo)));
binji 2014/01/30 00:36:52 this can just be a static_cast
37 memset(ai, 0, sizeof(*ai));
38
39 if (hints && hints->ai_socktype)
40 ai->ai_socktype = hints->ai_socktype;
41 else
42 ai->ai_socktype = SOCK_STREAM;
43
44 if (hints && hints->ai_protocol)
45 ai->ai_protocol = hints->ai_protocol;
46
47 if (name)
48 ai->ai_canonname = strdup(name);
49
50 switch (addr->sa_family) {
51 case AF_INET6: {
52 sockaddr_in6* in =
53 reinterpret_cast<sockaddr_in6*>(malloc(sizeof(sockaddr_in6)));
54 *in = *(sockaddr_in6*)addr;
55 ai->ai_family = AF_INET6;
56 ai->ai_addr = reinterpret_cast<sockaddr*>(in);
57 ai->ai_addrlen = sizeof(*in);
58 break;
59 }
60 case AF_INET: {
61 sockaddr_in* in =
62 reinterpret_cast<sockaddr_in*>(malloc(sizeof(sockaddr_in)));
63 *in = *(sockaddr_in*)addr;
64 ai->ai_family = AF_INET;
65 ai->ai_addr = reinterpret_cast<sockaddr*>(in);
66 ai->ai_addrlen = sizeof(*in);
67 break;
68 }
69 default:
70 assert(0);
71 return;
72 }
73
74 if (*list_start == NULL) {
75 *list_start = ai;
76 *list_end = ai;
77 return;
78 }
79
80 (*list_end)->ai_next = ai;
81 *list_end = ai;
82 }
83
84 } // namespace
85
16 namespace nacl_io { 86 namespace nacl_io {
17 87
18 HostResolver::HostResolver() : hostent_(), ppapi_(NULL) { 88 HostResolver::HostResolver() : hostent_(), ppapi_(NULL) {
19 } 89 }
20 90
21 HostResolver::~HostResolver() { 91 HostResolver::~HostResolver() {
22 hostent_cleanup(); 92 hostent_cleanup();
23 } 93 }
24 94
25 void HostResolver::Init(PepperInterface* ppapi) { 95 void HostResolver::Init(PepperInterface* ppapi) {
26 ppapi_ = ppapi; 96 ppapi_ = ppapi;
27 } 97 }
28 98
29 struct hostent* HostResolver::gethostbyname(const char* name) { 99 struct hostent* HostResolver::gethostbyname(const char* name) {
30 h_errno = NETDB_INTERNAL; 100 h_errno = NETDB_INTERNAL;
31 101
32 if (NULL == ppapi_) 102 struct addrinfo* ai;
33 return NULL; 103 struct addrinfo hints;
34 104 memset(&hints, 0, sizeof(hints));
35 HostResolverInterface* resolver_interface = 105 hints.ai_flags = AI_CANONNAME;
36 ppapi_->GetHostResolverInterface(); 106 int err = getaddrinfo(name, NULL, &hints, &ai);
37 VarInterface* var_interface = ppapi_->GetVarInterface();
38 NetAddressInterface* netaddr_iface = ppapi_->GetNetAddressInterface();
39
40 if (NULL == resolver_interface ||
41 NULL == netaddr_iface ||
42 NULL == var_interface)
43 return NULL;
44
45 ScopedResource resolver(ppapi_,
46 resolver_interface->Create(ppapi_->GetInstance()));
47
48 struct PP_CompletionCallback callback;
49 callback.func = NULL;
50 struct PP_HostResolver_Hint hint;
51 hint.family = PP_NETADDRESS_FAMILY_IPV4;
52 hint.flags = PP_HOSTRESOLVER_FLAG_CANONNAME;
53
54 int err = resolver_interface->Resolve(resolver.pp_resource(),
55 name, 0, &hint, callback);
56 if (err) { 107 if (err) {
57 switch (err) { 108 switch (err) {
58 case PP_ERROR_NOACCESS: 109 case EAI_SYSTEM:
59 h_errno = NO_RECOVERY; 110 h_errno = NO_RECOVERY;
60 break; 111 break;
61 case PP_ERROR_NAME_NOT_RESOLVED: 112 case EAI_NONAME:
62 h_errno = HOST_NOT_FOUND; 113 h_errno = HOST_NOT_FOUND;
63 break; 114 break;
64 default: 115 default:
65 h_errno = NETDB_INTERNAL; 116 h_errno = NETDB_INTERNAL;
66 break; 117 break;
67 } 118 }
68 return NULL; 119 return NULL;
69 } 120 }
70 121
71 // We use a single hostent struct for all calls to to gethostbyname 122 // We use a single hostent struct for all calls to to gethostbyname
72 // (as explicitly permitted by the spec - gethostbyname is NOT supposed to 123 // (as explicitly permitted by the spec - gethostbyname is NOT supposed to
73 // be threadsafe!), so the first thing we do is free all the malloced data 124 // be threadsafe!). However by using a lock around all the global data
74 // left over from the last call. 125 // manipulation we can at least ensure that the call doesn't crash.
126 AUTO_LOCK(gethostbyname_lock_);
127
128 // The first thing we do is free any malloced data left over from
129 // the last call.
75 hostent_cleanup(); 130 hostent_cleanup();
76 131
77 PP_Var name_var = 132 switch (ai->ai_family) {
78 resolver_interface->GetCanonicalName(resolver.pp_resource()); 133 case AF_INET:
79 if (PP_VARTYPE_STRING != name_var.type) 134 hostent_.h_addrtype = AF_INET;
80 return NULL; 135 hostent_.h_length = sizeof(in_addr);
81 136 break;
82 uint32_t len; 137 case AF_INET6:
83 const char* name_ptr = var_interface->VarToUtf8(name_var, &len); 138 hostent_.h_addrtype = AF_INET6;
84 if (NULL == name_ptr) 139 hostent_.h_length = sizeof(in6_addr);
85 return NULL; 140 break;
86 if (0 == len) { 141 default:
87 // Sometimes GetCanonicalName gives up more easily than gethostbyname should 142 return NULL;
88 // (for example, it returns "" when asked to resolve "localhost"), so if we
89 // get an empty string we copy over the input string instead.
90 len = strlen(name);
91 name_ptr = name;
92 } 143 }
93 hostent_.h_name = static_cast<char*>(malloc(len + 1)); 144 hostent_.h_name = strdup(ai->ai_canonname);
94 if (NULL == hostent_.h_name)
95 return NULL;
96 memcpy(hostent_.h_name, name_ptr, len);
97 hostent_.h_name[len] = '\0';
98
99 var_interface->Release(name_var);
100 145
101 // Aliases aren't supported at the moment, so we just make an empty list. 146 // Aliases aren't supported at the moment, so we just make an empty list.
102 hostent_.h_aliases = static_cast<char**>(malloc(sizeof(char*))); 147 hostent_.h_aliases = static_cast<char**>(malloc(sizeof(char*)));
103 if (NULL == hostent_.h_aliases) 148 if (NULL == hostent_.h_aliases)
104 return NULL; 149 return NULL;
105 hostent_.h_aliases[0] = NULL; 150 hostent_.h_aliases[0] = NULL;
106 151
107 ScopedResource addr(ppapi_); 152 // Count number of address in list
108 addr.Reset(resolver_interface->GetNetAddress(resolver.pp_resource(), 0)); 153 int num_addresses = 0;
109 if (!PP_ToBool(netaddr_iface->IsNetAddress(addr.pp_resource()))) 154 struct addrinfo* current = ai;
155 while (current != NULL) {
156 // Only count address that have the same type as first address
157 if (current->ai_family == hostent_.h_addrtype)
158 num_addresses++;
159 current = current->ai_next;
160 }
161
162 // Allocate address list
163 hostent_.h_addr_list = static_cast<char**>(calloc(num_addresses + 1,
164 sizeof(char*)));
165 if (NULL == hostent_.h_addr_list)
110 return NULL; 166 return NULL;
111 167
112 switch (netaddr_iface->GetFamily(addr.pp_resource())) { 168 // Copy all addresses of the relevant family.
113 case PP_NETADDRESS_FAMILY_IPV4: 169 current = ai;
114 hostent_.h_addrtype = AF_INET; 170 char** hostent_addr = hostent_.h_addr_list;
115 hostent_.h_length = 4; 171 while (current != NULL) {
116 break; 172 if (current->ai_family != hostent_.h_addrtype) {
117 case PP_NETADDRESS_FAMILY_IPV6: 173 current = current->ai_next;
118 hostent_.h_addrtype = AF_INET6; 174 continue;
119 hostent_.h_length = 16; 175 }
176 *hostent_addr = static_cast<char*>(malloc(hostent_.h_length));
177 switch (current->ai_family) {
178 case AF_INET: {
179 sockaddr_in* in = reinterpret_cast<sockaddr_in*>(current->ai_addr);
180 memcpy(*hostent_addr, &in->sin_addr.s_addr, hostent_.h_length);
181 break;
182 }
183 case AF_INET6: {
184 sockaddr_in6* in6 = reinterpret_cast<sockaddr_in6*>(current->ai_addr);
185 memcpy(*hostent_addr, &in6->sin6_addr.s6_addr, hostent_.h_length);
186 break;
187 }
188 }
189 current = current->ai_next;
190 hostent_addr++;
191 }
192
193 freeaddrinfo(ai);
194 return &hostent_;
195 }
196
197 void HostResolver::freeaddrinfo(struct addrinfo *res) {
198 while (res) {
199 struct addrinfo* cur = res;
200 res = res->ai_next;
201 free(cur->ai_addr);
202 free(cur->ai_canonname);
203 free(cur);
204 }
205 }
206
207 int HostResolver::getaddrinfo(const char* node, const char* service,
208 const struct addrinfo* hints_in,
209 struct addrinfo** result) {
210 *result = NULL;
211 struct addrinfo* end = NULL;
212
213 if (node == NULL && service == NULL)
214 return EAI_NONAME;
215
216 // Check the service name (port). Currently we only handle numeric
217 // services.
218 long port = 0;
219 if (service != NULL) {
220 char* cp;
221 port = strtol(service, &cp, 10);
222 if (port > 0 && port <= 65535 && *cp == '\0') {
223 port = htons(port);
224 } else {
225 return EAI_SERVICE;
226 }
227 }
228
229 struct addrinfo default_hints;
230 memset(&default_hints, 0, sizeof(default_hints));
231 const struct addrinfo* hints = hints_in ? hints_in : &default_hints;
232
233 // Verify values passed in hints structure
234 switch (hints->ai_family) {
235 case AF_INET6:
236 case AF_INET:
237 case AF_UNSPEC:
120 break; 238 break;
121 default: 239 default:
122 return NULL; 240 return EAI_FAMILY;
123 } 241 }
124 242
125 const uint32_t num_addresses = 243 struct sockaddr_in addr_in;
126 resolver_interface->GetNetAddressCount(resolver.pp_resource()); 244 memset(&addr_in, 0, sizeof(addr_in));
245 addr_in.sin_family = AF_INET;
246 addr_in.sin_port = port;
247
248 struct sockaddr_in6 addr_in6;
249 memset(&addr_in6, 0, sizeof(addr_in6));
250 addr_in6.sin6_family = AF_INET6;
251 addr_in6.sin6_port = port;
252
253 if (node) {
254 // Handle numeric node name.
255 if (hints->ai_family == AF_INET || hints->ai_family == AF_UNSPEC) {
256 in_addr in;
257 if (inet_pton(AF_INET, node, &in)) {
258 addr_in.sin_addr = in;
259 CreateAddrInfo(hints, (sockaddr*)&addr_in, node, result, &end);
260 return 0;
261 }
262 }
263
264 if (hints->ai_family == AF_INET6 || hints->ai_family == AF_UNSPEC) {
265 in6_addr in6;
266 if (inet_pton(AF_INET6, node, &in6)) {
267 addr_in6.sin6_addr = in6;
268 CreateAddrInfo(hints, (sockaddr*)&addr_in6, node, result, &end);
269 return 0;
270 }
271 }
272 }
273
274 // Handle AI_PASSIVE (used for listening sockets, e.g. INADDR_ANY)
275 if (node == NULL && (hints->ai_flags & AI_PASSIVE)) {
276 if (hints->ai_family == AF_INET6 || hints->ai_family == AF_UNSPEC) {
277 const in6_addr in6addr_any = IN6ADDR_ANY_INIT;
278 memcpy(&addr_in6.sin6_addr.s6_addr, &in6addr_any, sizeof(in6addr_any));
279 CreateAddrInfo(hints, (sockaddr*)&addr_in6, NULL, result, &end);
280 }
281
282 if (hints->ai_family == AF_INET || hints->ai_family == AF_UNSPEC) {
283 addr_in.sin_addr.s_addr = INADDR_ANY;
284 CreateAddrInfo(hints, (sockaddr*)&addr_in, NULL, result, &end);
285 }
286 return 0;
287 }
288
289 if (NULL == ppapi_)
290 return EAI_SYSTEM;
291
292 // Use PPAPI interface to resolve nodename
293 HostResolverInterface* resolver_iface = ppapi_->GetHostResolverInterface();
294 VarInterface* var_interface = ppapi_->GetVarInterface();
295 NetAddressInterface* netaddr_iface = ppapi_->GetNetAddressInterface();
296
297 if (NULL == resolver_iface || NULL == var_interface || NULL == netaddr_iface)
298 return EAI_SYSTEM;
299
300 ScopedResource scoped_resolver(ppapi_,
301 resolver_iface->Create(ppapi_->GetInstance()));
302 PP_Resource resolver = scoped_resolver.pp_resource();
303
304 struct PP_HostResolver_Hint pp_hints;
305 HintsToPPHints(hints, &pp_hints);
306
307 int err = resolver_iface->Resolve(resolver,
308 node,
309 0,
310 &pp_hints,
311 PP_BlockUntilComplete());
312 if (err) {
313 switch (err) {
314 case PP_ERROR_NOACCESS:
315 return EAI_SYSTEM;
316 case PP_ERROR_NAME_NOT_RESOLVED:
317 return EAI_NONAME;
318 default:
319 return EAI_SYSTEM;
320 }
321 }
322
323 char* canon_name = NULL;
324 if (hints != NULL && hints->ai_flags & AI_CANONNAME) {
325 PP_Var name_var = resolver_iface->GetCanonicalName(resolver);
326
327 uint32_t len = 0;
328 const char* tmp = var_interface->VarToUtf8(name_var, &len);
329 if (len > 0) {
330 // Copy and NULL-terminate the UTF8 string var.
331 canon_name = static_cast<char*>(alloca(len+1));
332 strncpy(canon_name, tmp, len);
333 canon_name[len] = '\0';
334 }
335 var_interface->Release(name_var);
336 }
337
338 int num_addresses = resolver_iface->GetNetAddressCount(resolver);
127 if (0 == num_addresses) 339 if (0 == num_addresses)
128 return NULL; 340 return EAI_NODATA;
129 hostent_.h_addr_list = 341
130 static_cast<char**>(calloc(num_addresses + 1, sizeof(char*))); 342
131 if (NULL == hostent_.h_addr_list) 343 // Convert address to sockaddr struct.
132 return NULL; 344 for (int i = 0; i < num_addresses; i++) {
133 345 ScopedResource addr(ppapi_, resolver_iface->GetNetAddress(resolver, i));
134 for (uint32_t i = 0; i < num_addresses; i++) { 346 PP_Resource resource = addr.pp_resource();
135 addr.Reset(resolver_interface->GetNetAddress(resolver.pp_resource(), i)); 347 assert(resource != 0);
136 if (!PP_ToBool(netaddr_iface->IsNetAddress(addr.pp_resource()))) 348 assert(PP_ToBool(netaddr_iface->IsNetAddress(resource)));
137 return NULL; 349 struct sockaddr* sockaddr = NULL;
138 if (AF_INET == hostent_.h_addrtype) { 350 switch (netaddr_iface->GetFamily(resource)) {
139 struct PP_NetAddress_IPv4 addr_struct; 351 case PP_NETADDRESS_FAMILY_IPV4: {
140 if (!netaddr_iface->DescribeAsIPv4Address(addr.pp_resource(), 352 struct PP_NetAddress_IPv4 addr_struct;
141 &addr_struct)) 353 if (!netaddr_iface->DescribeAsIPv4Address(resource, &addr_struct)) {
142 return NULL; 354 assert(false);
143 hostent_.h_addr_list[i] = static_cast<char*>(malloc(hostent_.h_length)); 355 break;
144 if (NULL == hostent_.h_addr_list[i]) 356 }
145 return NULL; 357 memcpy(&addr_in.sin_addr, addr_struct.addr, sizeof(addr_in.sin_addr));
146 memcpy(hostent_.h_addr_list[i], addr_struct.addr, hostent_.h_length); 358 sockaddr = (struct sockaddr*)&addr_in;
147 } else { // IPv6 359 break;
148 struct PP_NetAddress_IPv6 addr_struct; 360 }
149 if (!netaddr_iface->DescribeAsIPv6Address(addr.pp_resource(), 361 case PP_NETADDRESS_FAMILY_IPV6: {
150 &addr_struct)) 362 struct PP_NetAddress_IPv6 addr_struct;
151 return NULL; 363 if (!netaddr_iface->DescribeAsIPv6Address(resource, &addr_struct)) {
152 hostent_.h_addr_list[i] = static_cast<char*>(malloc(hostent_.h_length)); 364 assert(false);
153 if (NULL == hostent_.h_addr_list[i]) 365 break;
154 return NULL; 366 }
155 memcpy(hostent_.h_addr_list[i], addr_struct.addr, hostent_.h_length); 367 memcpy(&addr_in6.sin6_addr, addr_struct.addr,
156 } 368 sizeof(addr_in6.sin6_addr));
157 } 369 sockaddr = (struct sockaddr*)&addr_in6;
158 370 break;
159 return &hostent_; 371 }
372 default:
373 return EAI_SYSTEM;
374 }
375
376 if (sockaddr != NULL)
377 CreateAddrInfo(hints, sockaddr, canon_name, result, &end);
378 canon_name = NULL;
379 }
380
381 return 0;
160 } 382 }
161 383
162 // Frees all of the deep pointers in a hostent struct. Called between uses of 384 // Frees all of the deep pointers in a hostent struct. Called between uses of
163 // gethostbyname, and when the kernel_proxy object is destroyed. 385 // gethostbyname, and when the kernel_proxy object is destroyed.
164 void HostResolver::hostent_cleanup() { 386 void HostResolver::hostent_cleanup() {
165 if (NULL != hostent_.h_name) { 387 if (NULL != hostent_.h_name) {
166 free(hostent_.h_name); 388 free(hostent_.h_name);
167 } 389 }
168 if (NULL != hostent_.h_aliases) { 390 if (NULL != hostent_.h_aliases) {
169 for (int i = 0; NULL != hostent_.h_aliases[i]; i++) { 391 for (int i = 0; NULL != hostent_.h_aliases[i]; i++) {
170 free(hostent_.h_aliases[i]); 392 free(hostent_.h_aliases[i]);
171 } 393 }
172 free(hostent_.h_aliases); 394 free(hostent_.h_aliases);
173 } 395 }
174 if (NULL != hostent_.h_addr_list) { 396 if (NULL != hostent_.h_addr_list) {
175 for (int i = 0; NULL != hostent_.h_addr_list[i]; i++) { 397 for (int i = 0; NULL != hostent_.h_addr_list[i]; i++) {
176 free(hostent_.h_addr_list[i]); 398 free(hostent_.h_addr_list[i]);
177 } 399 }
178 free(hostent_.h_addr_list); 400 free(hostent_.h_addr_list);
179 } 401 }
180 hostent_.h_name = NULL; 402 hostent_.h_name = NULL;
181 hostent_.h_aliases = NULL; 403 hostent_.h_aliases = NULL;
182 hostent_.h_addr_list = NULL; 404 hostent_.h_addr_list = NULL;
183 } 405 }
184 406
185 } // namespace nacl_io 407 } // namespace nacl_io
186 408
187 #endif // PROVIDES_SOCKET_API 409 #endif // PROVIDES_SOCKET_API
OLDNEW
« no previous file with comments | « native_client_sdk/src/libraries/nacl_io/host_resolver.h ('k') | native_client_sdk/src/libraries/nacl_io/kernel_intercept.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698