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

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 = static_cast<addrinfo*>(malloc(sizeof(addrinfo)));
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 static_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 static_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 hints.ai_family = AF_INET;
37 VarInterface* var_interface = ppapi_->GetVarInterface(); 107 int err = getaddrinfo(name, NULL, &hints, &ai);
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) { 108 if (err) {
57 switch (err) { 109 switch (err) {
58 case PP_ERROR_NOACCESS: 110 case EAI_SYSTEM:
59 h_errno = NO_RECOVERY; 111 h_errno = NO_RECOVERY;
60 break; 112 break;
61 case PP_ERROR_NAME_NOT_RESOLVED: 113 case EAI_NONAME:
62 h_errno = HOST_NOT_FOUND; 114 h_errno = HOST_NOT_FOUND;
63 break; 115 break;
64 default: 116 default:
65 h_errno = NETDB_INTERNAL; 117 h_errno = NETDB_INTERNAL;
66 break; 118 break;
67 } 119 }
68 return NULL; 120 return NULL;
69 } 121 }
70 122
71 // We use a single hostent struct for all calls to to gethostbyname 123 // We use a single hostent struct for all calls to to gethostbyname
72 // (as explicitly permitted by the spec - gethostbyname is NOT supposed to 124 // (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 125 // be threadsafe!). However by using a lock around all the global data
74 // left over from the last call. 126 // manipulation we can at least ensure that the call doesn't crash.
127 AUTO_LOCK(gethostbyname_lock_);
128
129 // The first thing we do is free any malloced data left over from
130 // the last call.
75 hostent_cleanup(); 131 hostent_cleanup();
76 132
77 PP_Var name_var = 133 switch (ai->ai_family) {
78 resolver_interface->GetCanonicalName(resolver.pp_resource()); 134 case AF_INET:
79 if (PP_VARTYPE_STRING != name_var.type) 135 hostent_.h_addrtype = AF_INET;
80 return NULL; 136 hostent_.h_length = sizeof(in_addr);
137 break;
138 case AF_INET6:
139 hostent_.h_addrtype = AF_INET6;
140 hostent_.h_length = sizeof(in6_addr);
141 break;
142 default:
143 return NULL;
144 }
81 145
82 uint32_t len; 146 if (ai->ai_canonname != NULL)
83 const char* name_ptr = var_interface->VarToUtf8(name_var, &len); 147 hostent_.h_name = strdup(ai->ai_canonname);
84 if (NULL == name_ptr) 148 else
85 return NULL; 149 hostent_.h_name = strdup(name);
86 if (0 == len) {
87 // Sometimes GetCanonicalName gives up more easily than gethostbyname should
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 }
93 hostent_.h_name = static_cast<char*>(malloc(len + 1));
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 150
101 // Aliases aren't supported at the moment, so we just make an empty list. 151 // Aliases aren't supported at the moment, so we just make an empty list.
102 hostent_.h_aliases = static_cast<char**>(malloc(sizeof(char*))); 152 hostent_.h_aliases = static_cast<char**>(malloc(sizeof(char*)));
103 if (NULL == hostent_.h_aliases) 153 if (NULL == hostent_.h_aliases)
104 return NULL; 154 return NULL;
105 hostent_.h_aliases[0] = NULL; 155 hostent_.h_aliases[0] = NULL;
106 156
107 ScopedResource addr(ppapi_); 157 // Count number of address in list
108 addr.Reset(resolver_interface->GetNetAddress(resolver.pp_resource(), 0)); 158 int num_addresses = 0;
109 if (!PP_ToBool(netaddr_iface->IsNetAddress(addr.pp_resource()))) 159 struct addrinfo* current = ai;
160 while (current != NULL) {
161 // Only count address that have the same type as first address
162 if (current->ai_family == hostent_.h_addrtype)
163 num_addresses++;
164 current = current->ai_next;
165 }
166
167 // Allocate address list
168 hostent_.h_addr_list = static_cast<char**>(calloc(num_addresses + 1,
169 sizeof(char*)));
170 if (NULL == hostent_.h_addr_list)
110 return NULL; 171 return NULL;
111 172
112 switch (netaddr_iface->GetFamily(addr.pp_resource())) { 173 // Copy all addresses of the relevant family.
113 case PP_NETADDRESS_FAMILY_IPV4: 174 current = ai;
114 hostent_.h_addrtype = AF_INET; 175 char** hostent_addr = hostent_.h_addr_list;
115 hostent_.h_length = 4; 176 while (current != NULL) {
116 break; 177 if (current->ai_family != hostent_.h_addrtype) {
117 case PP_NETADDRESS_FAMILY_IPV6: 178 current = current->ai_next;
118 hostent_.h_addrtype = AF_INET6; 179 continue;
119 hostent_.h_length = 16; 180 }
181 *hostent_addr = static_cast<char*>(malloc(hostent_.h_length));
182 switch (current->ai_family) {
183 case AF_INET: {
184 sockaddr_in* in = reinterpret_cast<sockaddr_in*>(current->ai_addr);
185 memcpy(*hostent_addr, &in->sin_addr.s_addr, hostent_.h_length);
186 break;
187 }
188 case AF_INET6: {
189 sockaddr_in6* in6 = reinterpret_cast<sockaddr_in6*>(current->ai_addr);
190 memcpy(*hostent_addr, &in6->sin6_addr.s6_addr, hostent_.h_length);
191 break;
192 }
193 }
194 current = current->ai_next;
195 hostent_addr++;
196 }
197
198 freeaddrinfo(ai);
199 return &hostent_;
200 }
201
202 void HostResolver::freeaddrinfo(struct addrinfo *res) {
203 while (res) {
204 struct addrinfo* cur = res;
205 res = res->ai_next;
206 free(cur->ai_addr);
207 free(cur->ai_canonname);
208 free(cur);
209 }
210 }
211
212 int HostResolver::getaddrinfo(const char* node, const char* service,
213 const struct addrinfo* hints_in,
214 struct addrinfo** result) {
215 *result = NULL;
216 struct addrinfo* end = NULL;
217
218 if (node == NULL && service == NULL)
219 return EAI_NONAME;
220
221 // Check the service name (port). Currently we only handle numeric
222 // services.
223 long port = 0;
224 if (service != NULL) {
225 char* cp;
226 port = strtol(service, &cp, 10);
227 if (port > 0 && port <= 65535 && *cp == '\0') {
228 port = htons(port);
229 } else {
230 return EAI_SERVICE;
231 }
232 }
233
234 struct addrinfo default_hints;
235 memset(&default_hints, 0, sizeof(default_hints));
236 const struct addrinfo* hints = hints_in ? hints_in : &default_hints;
237
238 // Verify values passed in hints structure
239 switch (hints->ai_family) {
240 case AF_INET6:
241 case AF_INET:
242 case AF_UNSPEC:
120 break; 243 break;
121 default: 244 default:
122 return NULL; 245 return EAI_FAMILY;
123 } 246 }
124 247
125 const uint32_t num_addresses = 248 struct sockaddr_in addr_in;
126 resolver_interface->GetNetAddressCount(resolver.pp_resource()); 249 memset(&addr_in, 0, sizeof(addr_in));
250 addr_in.sin_family = AF_INET;
251 addr_in.sin_port = port;
252
253 struct sockaddr_in6 addr_in6;
254 memset(&addr_in6, 0, sizeof(addr_in6));
255 addr_in6.sin6_family = AF_INET6;
256 addr_in6.sin6_port = port;
257
258 if (node) {
259 // Handle numeric node name.
260 if (hints->ai_family == AF_INET || hints->ai_family == AF_UNSPEC) {
261 in_addr in;
262 if (inet_pton(AF_INET, node, &in)) {
263 addr_in.sin_addr = in;
264 CreateAddrInfo(hints, (sockaddr*)&addr_in, node, result, &end);
265 return 0;
266 }
267 }
268
269 if (hints->ai_family == AF_INET6 || hints->ai_family == AF_UNSPEC) {
270 in6_addr in6;
271 if (inet_pton(AF_INET6, node, &in6)) {
272 addr_in6.sin6_addr = in6;
273 CreateAddrInfo(hints, (sockaddr*)&addr_in6, node, result, &end);
274 return 0;
275 }
276 }
277 }
278
279 // Handle AI_PASSIVE (used for listening sockets, e.g. INADDR_ANY)
280 if (node == NULL && (hints->ai_flags & AI_PASSIVE)) {
281 if (hints->ai_family == AF_INET6 || hints->ai_family == AF_UNSPEC) {
282 const in6_addr in6addr_any = IN6ADDR_ANY_INIT;
283 memcpy(&addr_in6.sin6_addr.s6_addr, &in6addr_any, sizeof(in6addr_any));
284 CreateAddrInfo(hints, (sockaddr*)&addr_in6, NULL, result, &end);
285 }
286
287 if (hints->ai_family == AF_INET || hints->ai_family == AF_UNSPEC) {
288 addr_in.sin_addr.s_addr = INADDR_ANY;
289 CreateAddrInfo(hints, (sockaddr*)&addr_in, NULL, result, &end);
290 }
291 return 0;
292 }
293
294 if (NULL == ppapi_)
295 return EAI_SYSTEM;
296
297 // Use PPAPI interface to resolve nodename
298 HostResolverInterface* resolver_iface = ppapi_->GetHostResolverInterface();
299 VarInterface* var_interface = ppapi_->GetVarInterface();
300 NetAddressInterface* netaddr_iface = ppapi_->GetNetAddressInterface();
301
302 if (NULL == resolver_iface || NULL == var_interface || NULL == netaddr_iface)
303 return EAI_SYSTEM;
304
305 ScopedResource scoped_resolver(ppapi_,
306 resolver_iface->Create(ppapi_->GetInstance()));
307 PP_Resource resolver = scoped_resolver.pp_resource();
308
309 struct PP_HostResolver_Hint pp_hints;
310 HintsToPPHints(hints, &pp_hints);
311
312 int err = resolver_iface->Resolve(resolver,
313 node,
314 0,
315 &pp_hints,
316 PP_BlockUntilComplete());
317 if (err) {
318 switch (err) {
319 case PP_ERROR_NOACCESS:
320 return EAI_SYSTEM;
321 case PP_ERROR_NAME_NOT_RESOLVED:
322 return EAI_NONAME;
323 default:
324 return EAI_SYSTEM;
325 }
326 }
327
328 char* canon_name = NULL;
329 if (hints->ai_flags & AI_CANONNAME) {
330 PP_Var name_var = resolver_iface->GetCanonicalName(resolver);
331 if (PP_VARTYPE_STRING == name_var.type) {
332 uint32_t len = 0;
333 const char* tmp = var_interface->VarToUtf8(name_var, &len);
334 // For some reason GetCanonicalName alway returns an empty
335 // string so this condition is never true.
336 // TODO(sbc): investigate this issue with PPAPI team.
337 if (len > 0) {
338 // Copy and NULL-terminate the UTF8 string var.
339 canon_name = static_cast<char*>(malloc(len+1));
340 strncpy(canon_name, tmp, len);
341 canon_name[len] = '\0';
342 }
343 }
344 if (!canon_name)
345 canon_name = strdup(node);
346 var_interface->Release(name_var);
347 }
348
349 int num_addresses = resolver_iface->GetNetAddressCount(resolver);
127 if (0 == num_addresses) 350 if (0 == num_addresses)
128 return NULL; 351 return EAI_NODATA;
129 hostent_.h_addr_list = 352
130 static_cast<char**>(calloc(num_addresses + 1, sizeof(char*))); 353 // Convert address to sockaddr struct.
131 if (NULL == hostent_.h_addr_list) 354 for (int i = 0; i < num_addresses; i++) {
132 return NULL; 355 ScopedResource addr(ppapi_, resolver_iface->GetNetAddress(resolver, i));
133 356 PP_Resource resource = addr.pp_resource();
134 for (uint32_t i = 0; i < num_addresses; i++) { 357 assert(resource != 0);
135 addr.Reset(resolver_interface->GetNetAddress(resolver.pp_resource(), i)); 358 assert(PP_ToBool(netaddr_iface->IsNetAddress(resource)));
136 if (!PP_ToBool(netaddr_iface->IsNetAddress(addr.pp_resource()))) 359 struct sockaddr* sockaddr = NULL;
137 return NULL; 360 switch (netaddr_iface->GetFamily(resource)) {
138 if (AF_INET == hostent_.h_addrtype) { 361 case PP_NETADDRESS_FAMILY_IPV4: {
139 struct PP_NetAddress_IPv4 addr_struct; 362 struct PP_NetAddress_IPv4 pp_addr;
140 if (!netaddr_iface->DescribeAsIPv4Address(addr.pp_resource(), 363 if (!netaddr_iface->DescribeAsIPv4Address(resource, &pp_addr)) {
141 &addr_struct)) 364 assert(false);
142 return NULL; 365 break;
143 hostent_.h_addr_list[i] = static_cast<char*>(malloc(hostent_.h_length)); 366 }
144 if (NULL == hostent_.h_addr_list[i]) 367 memcpy(&addr_in.sin_addr.s_addr, pp_addr.addr, sizeof(in_addr_t));
145 return NULL; 368 sockaddr = (struct sockaddr*)&addr_in;
146 memcpy(hostent_.h_addr_list[i], addr_struct.addr, hostent_.h_length); 369 break;
147 } else { // IPv6 370 }
148 struct PP_NetAddress_IPv6 addr_struct; 371 case PP_NETADDRESS_FAMILY_IPV6: {
149 if (!netaddr_iface->DescribeAsIPv6Address(addr.pp_resource(), 372 struct PP_NetAddress_IPv6 pp_addr;
150 &addr_struct)) 373 if (!netaddr_iface->DescribeAsIPv6Address(resource, &pp_addr)) {
151 return NULL; 374 assert(false);
152 hostent_.h_addr_list[i] = static_cast<char*>(malloc(hostent_.h_length)); 375 break;
153 if (NULL == hostent_.h_addr_list[i]) 376 }
154 return NULL; 377 memcpy(&addr_in6.sin6_addr.s6_addr, pp_addr.addr,
155 memcpy(hostent_.h_addr_list[i], addr_struct.addr, hostent_.h_length); 378 sizeof(in6_addr));
156 } 379 sockaddr = (struct sockaddr*)&addr_in6;
157 } 380 break;
158 381 }
159 return &hostent_; 382 default:
383 return EAI_SYSTEM;
384 }
385
386 if (sockaddr != NULL)
387 CreateAddrInfo(hints, sockaddr, canon_name, result, &end);
388
389 if (canon_name) {
390 free(canon_name);
391 canon_name = NULL;
392 }
393 }
394
395 return 0;
160 } 396 }
161 397
162 // Frees all of the deep pointers in a hostent struct. Called between uses of 398 // Frees all of the deep pointers in a hostent struct. Called between uses of
163 // gethostbyname, and when the kernel_proxy object is destroyed. 399 // gethostbyname, and when the kernel_proxy object is destroyed.
164 void HostResolver::hostent_cleanup() { 400 void HostResolver::hostent_cleanup() {
165 if (NULL != hostent_.h_name) { 401 if (NULL != hostent_.h_name) {
166 free(hostent_.h_name); 402 free(hostent_.h_name);
167 } 403 }
168 if (NULL != hostent_.h_aliases) { 404 if (NULL != hostent_.h_aliases) {
169 for (int i = 0; NULL != hostent_.h_aliases[i]; i++) { 405 for (int i = 0; NULL != hostent_.h_aliases[i]; i++) {
170 free(hostent_.h_aliases[i]); 406 free(hostent_.h_aliases[i]);
171 } 407 }
172 free(hostent_.h_aliases); 408 free(hostent_.h_aliases);
173 } 409 }
174 if (NULL != hostent_.h_addr_list) { 410 if (NULL != hostent_.h_addr_list) {
175 for (int i = 0; NULL != hostent_.h_addr_list[i]; i++) { 411 for (int i = 0; NULL != hostent_.h_addr_list[i]; i++) {
176 free(hostent_.h_addr_list[i]); 412 free(hostent_.h_addr_list[i]);
177 } 413 }
178 free(hostent_.h_addr_list); 414 free(hostent_.h_addr_list);
179 } 415 }
180 hostent_.h_name = NULL; 416 hostent_.h_name = NULL;
181 hostent_.h_aliases = NULL; 417 hostent_.h_aliases = NULL;
182 hostent_.h_addr_list = NULL; 418 hostent_.h_addr_list = NULL;
183 } 419 }
184 420
185 } // namespace nacl_io 421 } // namespace nacl_io
186 422
187 #endif // PROVIDES_SOCKET_API 423 #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