1 /* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
2 *
3 * Permission is hereby granted, free of charge, to any person obtaining a copy
4 * of this software and associated documentation files (the "Software"), to
5 * deal in the Software without restriction, including without limitation the
6 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
7 * sell copies of the Software, and to permit persons to whom the Software is
8 * furnished to do so, subject to the following conditions:
9 *
10 * The above copyright notice and this permission notice shall be included in
11 * all copies or substantial portions of the Software.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
19 * IN THE SOFTWARE.
20 */
21
22 #include <assert.h>
23
24 #include "uv.h"
25 #include "internal.h"
26 #include "req-inl.h"
27 #include "idna.h"
28
29 /* EAI_* constants. */
30 #include <winsock2.h>
31
32 /* Needed for ConvertInterfaceIndexToLuid and ConvertInterfaceLuidToNameA */
33 #include <iphlpapi.h>
34
uv__getaddrinfo_translate_error(int sys_err)35 int uv__getaddrinfo_translate_error(int sys_err) {
36 switch (sys_err) {
37 case 0: return 0;
38 case WSATRY_AGAIN: return UV_EAI_AGAIN;
39 case WSAEINVAL: return UV_EAI_BADFLAGS;
40 case WSANO_RECOVERY: return UV_EAI_FAIL;
41 case WSAEAFNOSUPPORT: return UV_EAI_FAMILY;
42 case WSA_NOT_ENOUGH_MEMORY: return UV_EAI_MEMORY;
43 case WSAHOST_NOT_FOUND: return UV_EAI_NONAME;
44 case WSATYPE_NOT_FOUND: return UV_EAI_SERVICE;
45 case WSAESOCKTNOSUPPORT: return UV_EAI_SOCKTYPE;
46 default: return uv_translate_sys_error(sys_err);
47 }
48 }
49
50
51 /*
52 * MinGW is missing this
53 */
54 #if !defined(_MSC_VER) && !defined(__MINGW64_VERSION_MAJOR)
55 typedef struct addrinfoW {
56 int ai_flags;
57 int ai_family;
58 int ai_socktype;
59 int ai_protocol;
60 size_t ai_addrlen;
61 WCHAR* ai_canonname;
62 struct sockaddr* ai_addr;
63 struct addrinfoW* ai_next;
64 } ADDRINFOW, *PADDRINFOW;
65
66 DECLSPEC_IMPORT int WSAAPI GetAddrInfoW(const WCHAR* node,
67 const WCHAR* service,
68 const ADDRINFOW* hints,
69 PADDRINFOW* result);
70
71 DECLSPEC_IMPORT void WSAAPI FreeAddrInfoW(PADDRINFOW pAddrInfo);
72 #endif
73
74
75 /* Adjust size value to be multiple of 4. Use to keep pointer aligned.
76 * Do we need different versions of this for different architectures? */
77 #define ALIGNED_SIZE(X) ((((X) + 3) >> 2) << 2)
78
79 #ifndef NDIS_IF_MAX_STRING_SIZE
80 #define NDIS_IF_MAX_STRING_SIZE IF_MAX_STRING_SIZE
81 #endif
82
uv__getaddrinfo_work(struct uv__work * w)83 static void uv__getaddrinfo_work(struct uv__work* w) {
84 uv_getaddrinfo_t* req;
85 struct addrinfoW* hints;
86 int err;
87
88 req = container_of(w, uv_getaddrinfo_t, work_req);
89 hints = req->addrinfow;
90 req->addrinfow = NULL;
91 err = GetAddrInfoW(req->node, req->service, hints, &req->addrinfow);
92 req->retcode = uv__getaddrinfo_translate_error(err);
93 }
94
95
96 /*
97 * Called from uv_run when complete. Call user specified callback
98 * then free returned addrinfo
99 * Returned addrinfo strings are converted from UTF-16 to UTF-8.
100 *
101 * To minimize allocation we calculate total size required,
102 * and copy all structs and referenced strings into the one block.
103 * Each size calculation is adjusted to avoid unaligned pointers.
104 */
uv__getaddrinfo_done(struct uv__work * w,int status)105 static void uv__getaddrinfo_done(struct uv__work* w, int status) {
106 uv_getaddrinfo_t* req;
107 size_t addrinfo_len = 0;
108 ssize_t name_len = 0;
109 size_t addrinfo_struct_len = ALIGNED_SIZE(sizeof(struct addrinfo));
110 struct addrinfoW* addrinfow_ptr;
111 struct addrinfo* addrinfo_ptr;
112 char* alloc_ptr = NULL;
113 char* cur_ptr = NULL;
114 int r;
115
116 req = container_of(w, uv_getaddrinfo_t, work_req);
117
118 /* release input parameter memory */
119 uv__free(req->alloc);
120 req->alloc = NULL;
121
122 if (status == UV_ECANCELED) {
123 assert(req->retcode == 0);
124 req->retcode = UV_EAI_CANCELED;
125 goto complete;
126 }
127
128 if (req->retcode == 0) {
129 /* Convert addrinfoW to addrinfo. First calculate required length. */
130 addrinfow_ptr = req->addrinfow;
131 while (addrinfow_ptr != NULL) {
132 addrinfo_len += addrinfo_struct_len +
133 ALIGNED_SIZE(addrinfow_ptr->ai_addrlen);
134 if (addrinfow_ptr->ai_canonname != NULL) {
135 name_len = uv_utf16_length_as_wtf8(addrinfow_ptr->ai_canonname, -1);
136 if (name_len < 0) {
137 req->retcode = name_len;
138 goto complete;
139 }
140 addrinfo_len += ALIGNED_SIZE(name_len + 1);
141 }
142 addrinfow_ptr = addrinfow_ptr->ai_next;
143 }
144
145 /* allocate memory for addrinfo results */
146 alloc_ptr = (char*)uv__malloc(addrinfo_len);
147
148 /* do conversions */
149 if (alloc_ptr != NULL) {
150 cur_ptr = alloc_ptr;
151 addrinfow_ptr = req->addrinfow;
152
153 while (addrinfow_ptr != NULL) {
154 /* copy addrinfo struct data */
155 assert(cur_ptr + addrinfo_struct_len <= alloc_ptr + addrinfo_len);
156 addrinfo_ptr = (struct addrinfo*)cur_ptr;
157 addrinfo_ptr->ai_family = addrinfow_ptr->ai_family;
158 addrinfo_ptr->ai_socktype = addrinfow_ptr->ai_socktype;
159 addrinfo_ptr->ai_protocol = addrinfow_ptr->ai_protocol;
160 addrinfo_ptr->ai_flags = addrinfow_ptr->ai_flags;
161 addrinfo_ptr->ai_addrlen = addrinfow_ptr->ai_addrlen;
162 addrinfo_ptr->ai_canonname = NULL;
163 addrinfo_ptr->ai_addr = NULL;
164 addrinfo_ptr->ai_next = NULL;
165
166 cur_ptr += addrinfo_struct_len;
167
168 /* copy sockaddr */
169 if (addrinfo_ptr->ai_addrlen > 0) {
170 assert(cur_ptr + addrinfo_ptr->ai_addrlen <=
171 alloc_ptr + addrinfo_len);
172 memcpy(cur_ptr, addrinfow_ptr->ai_addr, addrinfo_ptr->ai_addrlen);
173 addrinfo_ptr->ai_addr = (struct sockaddr*)cur_ptr;
174 cur_ptr += ALIGNED_SIZE(addrinfo_ptr->ai_addrlen);
175 }
176
177 /* convert canonical name to UTF-8 */
178 if (addrinfow_ptr->ai_canonname != NULL) {
179 name_len = alloc_ptr + addrinfo_len - cur_ptr;
180 r = uv__copy_utf16_to_utf8(addrinfow_ptr->ai_canonname,
181 -1,
182 cur_ptr,
183 (size_t*)&name_len);
184 assert(r == 0);
185 addrinfo_ptr->ai_canonname = cur_ptr;
186 cur_ptr += ALIGNED_SIZE(name_len + 1);
187 }
188 assert(cur_ptr <= alloc_ptr + addrinfo_len);
189
190 /* set next ptr */
191 addrinfow_ptr = addrinfow_ptr->ai_next;
192 if (addrinfow_ptr != NULL) {
193 addrinfo_ptr->ai_next = (struct addrinfo*)cur_ptr;
194 }
195 }
196 req->addrinfo = (struct addrinfo*)alloc_ptr;
197 } else {
198 req->retcode = UV_EAI_MEMORY;
199 }
200 }
201
202 /* return memory to system */
203 if (req->addrinfow != NULL) {
204 FreeAddrInfoW(req->addrinfow);
205 req->addrinfow = NULL;
206 }
207
208 complete:
209 uv__req_unregister(req->loop, req);
210
211 /* finally do callback with converted result */
212 if (req->getaddrinfo_cb)
213 req->getaddrinfo_cb(req, req->retcode, req->addrinfo);
214 }
215
216
uv_freeaddrinfo(struct addrinfo * ai)217 void uv_freeaddrinfo(struct addrinfo* ai) {
218 char* alloc_ptr = (char*)ai;
219
220 /* release copied result memory */
221 uv__free(alloc_ptr);
222 }
223
224
225 /*
226 * Entry point for getaddrinfo
227 * we convert the UTF-8 strings to UNICODE
228 * and save the UNICODE string pointers in the req
229 * We also copy hints so that caller does not need to keep memory until the
230 * callback.
231 * return 0 if a callback will be made
232 * return error code if validation fails
233 *
234 * To minimize allocation we calculate total size required,
235 * and copy all structs and referenced strings into the one block.
236 * Each size calculation is adjusted to avoid unaligned pointers.
237 */
uv_getaddrinfo(uv_loop_t * loop,uv_getaddrinfo_t * req,uv_getaddrinfo_cb getaddrinfo_cb,const char * node,const char * service,const struct addrinfo * hints)238 int uv_getaddrinfo(uv_loop_t* loop,
239 uv_getaddrinfo_t* req,
240 uv_getaddrinfo_cb getaddrinfo_cb,
241 const char* node,
242 const char* service,
243 const struct addrinfo* hints) {
244 char hostname_ascii[256];
245 size_t nodesize = 0;
246 size_t servicesize = 0;
247 size_t hintssize = 0;
248 char* alloc_ptr = NULL;
249 ssize_t rc;
250
251 if (req == NULL || (node == NULL && service == NULL)) {
252 return UV_EINVAL;
253 }
254
255 UV_REQ_INIT(req, UV_GETADDRINFO);
256 req->getaddrinfo_cb = getaddrinfo_cb;
257 req->addrinfo = NULL;
258 req->loop = loop;
259 req->retcode = 0;
260
261 /* calculate required memory size for all input values */
262 if (node != NULL) {
263 rc = uv__idna_toascii(node,
264 node + strlen(node),
265 hostname_ascii,
266 hostname_ascii + sizeof(hostname_ascii));
267 if (rc < 0)
268 return rc;
269 nodesize = strlen(hostname_ascii) + 1;
270 node = hostname_ascii;
271 }
272
273 if (service != NULL) {
274 rc = uv_wtf8_length_as_utf16(service);
275 if (rc < 0)
276 return rc;
277 servicesize = rc;
278 }
279 if (hints != NULL) {
280 hintssize = ALIGNED_SIZE(sizeof(struct addrinfoW));
281 }
282
283 /* allocate memory for inputs, and partition it as needed */
284 alloc_ptr = uv__malloc(ALIGNED_SIZE(nodesize * sizeof(WCHAR)) +
285 ALIGNED_SIZE(servicesize * sizeof(WCHAR)) +
286 hintssize);
287 if (!alloc_ptr)
288 return UV_ENOMEM;
289
290 /* save alloc_ptr now so we can free if error */
291 req->alloc = (void*) alloc_ptr;
292
293 /* Convert node string to UTF16 into allocated memory and save pointer in the
294 * request. The node here has been converted to ascii. */
295 if (node != NULL) {
296 req->node = (WCHAR*) alloc_ptr;
297 uv_wtf8_to_utf16(node, (WCHAR*) alloc_ptr, nodesize);
298 alloc_ptr += ALIGNED_SIZE(nodesize * sizeof(WCHAR));
299 } else {
300 req->node = NULL;
301 }
302
303 /* Convert service string to UTF16 into allocated memory and save pointer in
304 * the req. */
305 if (service != NULL) {
306 req->service = (WCHAR*) alloc_ptr;
307 uv_wtf8_to_utf16(service, (WCHAR*) alloc_ptr, servicesize);
308 alloc_ptr += ALIGNED_SIZE(servicesize * sizeof(WCHAR));
309 } else {
310 req->service = NULL;
311 }
312
313 /* copy hints to allocated memory and save pointer in req */
314 if (hints != NULL) {
315 req->addrinfow = (struct addrinfoW*) alloc_ptr;
316 req->addrinfow->ai_family = hints->ai_family;
317 req->addrinfow->ai_socktype = hints->ai_socktype;
318 req->addrinfow->ai_protocol = hints->ai_protocol;
319 req->addrinfow->ai_flags = hints->ai_flags;
320 req->addrinfow->ai_addrlen = 0;
321 req->addrinfow->ai_canonname = NULL;
322 req->addrinfow->ai_addr = NULL;
323 req->addrinfow->ai_next = NULL;
324 } else {
325 req->addrinfow = NULL;
326 }
327
328 uv__req_register(loop, req);
329
330 if (getaddrinfo_cb) {
331 uv__work_submit(loop,
332 &req->work_req,
333 UV__WORK_SLOW_IO,
334 uv__getaddrinfo_work,
335 uv__getaddrinfo_done);
336 return 0;
337 } else {
338 uv__getaddrinfo_work(&req->work_req);
339 uv__getaddrinfo_done(&req->work_req, 0);
340 return req->retcode;
341 }
342 }
343
uv_if_indextoname(unsigned int ifindex,char * buffer,size_t * size)344 int uv_if_indextoname(unsigned int ifindex, char* buffer, size_t* size) {
345 NET_LUID luid;
346 wchar_t wname[NDIS_IF_MAX_STRING_SIZE + 1]; /* Add one for the NUL. */
347 int r;
348
349 if (buffer == NULL || size == NULL || *size == 0)
350 return UV_EINVAL;
351
352 r = ConvertInterfaceIndexToLuid(ifindex, &luid);
353
354 if (r != 0)
355 return uv_translate_sys_error(r);
356
357 r = ConvertInterfaceLuidToNameW(&luid, wname, ARRAY_SIZE(wname));
358
359 if (r != 0)
360 return uv_translate_sys_error(r);
361
362 return uv__copy_utf16_to_utf8(wname, -1, buffer, size);
363 }
364
uv_if_indextoiid(unsigned int ifindex,char * buffer,size_t * size)365 int uv_if_indextoiid(unsigned int ifindex, char* buffer, size_t* size) {
366 int r;
367
368 if (buffer == NULL || size == NULL || *size == 0)
369 return UV_EINVAL;
370
371 r = snprintf(buffer, *size, "%d", ifindex);
372
373 if (r < 0)
374 return uv_translate_sys_error(r);
375
376 if (r >= (int) *size) {
377 *size = r + 1;
378 return UV_ENOBUFS;
379 }
380
381 *size = r;
382 return 0;
383 }
384