Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Kitware
GitHub Repository: Kitware/CMake
Path: blob/master/Utilities/cmlibuv/src/win/getaddrinfo.c
3153 views
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
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
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
*/
105
static void uv__getaddrinfo_done(struct uv__work* w, int status) {
106
uv_getaddrinfo_t* req;
107
int addrinfo_len = 0;
108
int 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
115
req = container_of(w, uv_getaddrinfo_t, work_req);
116
117
/* release input parameter memory */
118
uv__free(req->alloc);
119
req->alloc = NULL;
120
121
if (status == UV_ECANCELED) {
122
assert(req->retcode == 0);
123
req->retcode = UV_EAI_CANCELED;
124
goto complete;
125
}
126
127
if (req->retcode == 0) {
128
/* Convert addrinfoW to addrinfo. First calculate required length. */
129
addrinfow_ptr = req->addrinfow;
130
while (addrinfow_ptr != NULL) {
131
addrinfo_len += addrinfo_struct_len +
132
ALIGNED_SIZE(addrinfow_ptr->ai_addrlen);
133
if (addrinfow_ptr->ai_canonname != NULL) {
134
name_len = WideCharToMultiByte(CP_UTF8,
135
0,
136
addrinfow_ptr->ai_canonname,
137
-1,
138
NULL,
139
0,
140
NULL,
141
NULL);
142
if (name_len == 0) {
143
req->retcode = uv_translate_sys_error(GetLastError());
144
goto complete;
145
}
146
addrinfo_len += ALIGNED_SIZE(name_len);
147
}
148
addrinfow_ptr = addrinfow_ptr->ai_next;
149
}
150
151
/* allocate memory for addrinfo results */
152
alloc_ptr = (char*)uv__malloc(addrinfo_len);
153
154
/* do conversions */
155
if (alloc_ptr != NULL) {
156
cur_ptr = alloc_ptr;
157
addrinfow_ptr = req->addrinfow;
158
159
while (addrinfow_ptr != NULL) {
160
/* copy addrinfo struct data */
161
assert(cur_ptr + addrinfo_struct_len <= alloc_ptr + addrinfo_len);
162
addrinfo_ptr = (struct addrinfo*)cur_ptr;
163
addrinfo_ptr->ai_family = addrinfow_ptr->ai_family;
164
addrinfo_ptr->ai_socktype = addrinfow_ptr->ai_socktype;
165
addrinfo_ptr->ai_protocol = addrinfow_ptr->ai_protocol;
166
addrinfo_ptr->ai_flags = addrinfow_ptr->ai_flags;
167
addrinfo_ptr->ai_addrlen = addrinfow_ptr->ai_addrlen;
168
addrinfo_ptr->ai_canonname = NULL;
169
addrinfo_ptr->ai_addr = NULL;
170
addrinfo_ptr->ai_next = NULL;
171
172
cur_ptr += addrinfo_struct_len;
173
174
/* copy sockaddr */
175
if (addrinfo_ptr->ai_addrlen > 0) {
176
assert(cur_ptr + addrinfo_ptr->ai_addrlen <=
177
alloc_ptr + addrinfo_len);
178
memcpy(cur_ptr, addrinfow_ptr->ai_addr, addrinfo_ptr->ai_addrlen);
179
addrinfo_ptr->ai_addr = (struct sockaddr*)cur_ptr;
180
cur_ptr += ALIGNED_SIZE(addrinfo_ptr->ai_addrlen);
181
}
182
183
/* convert canonical name to UTF-8 */
184
if (addrinfow_ptr->ai_canonname != NULL) {
185
name_len = WideCharToMultiByte(CP_UTF8,
186
0,
187
addrinfow_ptr->ai_canonname,
188
-1,
189
NULL,
190
0,
191
NULL,
192
NULL);
193
assert(name_len > 0);
194
assert(cur_ptr + name_len <= alloc_ptr + addrinfo_len);
195
name_len = WideCharToMultiByte(CP_UTF8,
196
0,
197
addrinfow_ptr->ai_canonname,
198
-1,
199
cur_ptr,
200
name_len,
201
NULL,
202
NULL);
203
assert(name_len > 0);
204
addrinfo_ptr->ai_canonname = cur_ptr;
205
cur_ptr += ALIGNED_SIZE(name_len);
206
}
207
assert(cur_ptr <= alloc_ptr + addrinfo_len);
208
209
/* set next ptr */
210
addrinfow_ptr = addrinfow_ptr->ai_next;
211
if (addrinfow_ptr != NULL) {
212
addrinfo_ptr->ai_next = (struct addrinfo*)cur_ptr;
213
}
214
}
215
req->addrinfo = (struct addrinfo*)alloc_ptr;
216
} else {
217
req->retcode = UV_EAI_MEMORY;
218
}
219
}
220
221
/* return memory to system */
222
if (req->addrinfow != NULL) {
223
FreeAddrInfoW(req->addrinfow);
224
req->addrinfow = NULL;
225
}
226
227
complete:
228
uv__req_unregister(req->loop, req);
229
230
/* finally do callback with converted result */
231
if (req->getaddrinfo_cb)
232
req->getaddrinfo_cb(req, req->retcode, req->addrinfo);
233
}
234
235
236
void uv_freeaddrinfo(struct addrinfo* ai) {
237
char* alloc_ptr = (char*)ai;
238
239
/* release copied result memory */
240
uv__free(alloc_ptr);
241
}
242
243
244
/*
245
* Entry point for getaddrinfo
246
* we convert the UTF-8 strings to UNICODE
247
* and save the UNICODE string pointers in the req
248
* We also copy hints so that caller does not need to keep memory until the
249
* callback.
250
* return 0 if a callback will be made
251
* return error code if validation fails
252
*
253
* To minimize allocation we calculate total size required,
254
* and copy all structs and referenced strings into the one block.
255
* Each size calculation is adjusted to avoid unaligned pointers.
256
*/
257
int uv_getaddrinfo(uv_loop_t* loop,
258
uv_getaddrinfo_t* req,
259
uv_getaddrinfo_cb getaddrinfo_cb,
260
const char* node,
261
const char* service,
262
const struct addrinfo* hints) {
263
char hostname_ascii[256];
264
int nodesize = 0;
265
int servicesize = 0;
266
int hintssize = 0;
267
char* alloc_ptr = NULL;
268
int err;
269
long rc;
270
271
if (req == NULL || (node == NULL && service == NULL)) {
272
return UV_EINVAL;
273
}
274
275
UV_REQ_INIT(req, UV_GETADDRINFO);
276
req->getaddrinfo_cb = getaddrinfo_cb;
277
req->addrinfo = NULL;
278
req->loop = loop;
279
req->retcode = 0;
280
281
/* calculate required memory size for all input values */
282
if (node != NULL) {
283
rc = uv__idna_toascii(node,
284
node + strlen(node),
285
hostname_ascii,
286
hostname_ascii + sizeof(hostname_ascii));
287
if (rc < 0)
288
return rc;
289
nodesize = ALIGNED_SIZE(MultiByteToWideChar(CP_UTF8, 0, hostname_ascii,
290
-1, NULL, 0) * sizeof(WCHAR));
291
if (nodesize == 0) {
292
err = GetLastError();
293
goto error;
294
}
295
node = hostname_ascii;
296
}
297
298
if (service != NULL) {
299
servicesize = ALIGNED_SIZE(MultiByteToWideChar(CP_UTF8,
300
0,
301
service,
302
-1,
303
NULL,
304
0) *
305
sizeof(WCHAR));
306
if (servicesize == 0) {
307
err = GetLastError();
308
goto error;
309
}
310
}
311
if (hints != NULL) {
312
hintssize = ALIGNED_SIZE(sizeof(struct addrinfoW));
313
}
314
315
/* allocate memory for inputs, and partition it as needed */
316
alloc_ptr = (char*)uv__malloc(nodesize + servicesize + hintssize);
317
if (!alloc_ptr) {
318
err = WSAENOBUFS;
319
goto error;
320
}
321
322
/* save alloc_ptr now so we can free if error */
323
req->alloc = (void*)alloc_ptr;
324
325
/* Convert node string to UTF16 into allocated memory and save pointer in the
326
* request. */
327
if (node != NULL) {
328
req->node = (WCHAR*)alloc_ptr;
329
if (MultiByteToWideChar(CP_UTF8,
330
0,
331
node,
332
-1,
333
(WCHAR*) alloc_ptr,
334
nodesize / sizeof(WCHAR)) == 0) {
335
err = GetLastError();
336
goto error;
337
}
338
alloc_ptr += nodesize;
339
} else {
340
req->node = NULL;
341
}
342
343
/* Convert service string to UTF16 into allocated memory and save pointer in
344
* the req. */
345
if (service != NULL) {
346
req->service = (WCHAR*)alloc_ptr;
347
if (MultiByteToWideChar(CP_UTF8,
348
0,
349
service,
350
-1,
351
(WCHAR*) alloc_ptr,
352
servicesize / sizeof(WCHAR)) == 0) {
353
err = GetLastError();
354
goto error;
355
}
356
alloc_ptr += servicesize;
357
} else {
358
req->service = NULL;
359
}
360
361
/* copy hints to allocated memory and save pointer in req */
362
if (hints != NULL) {
363
req->addrinfow = (struct addrinfoW*)alloc_ptr;
364
req->addrinfow->ai_family = hints->ai_family;
365
req->addrinfow->ai_socktype = hints->ai_socktype;
366
req->addrinfow->ai_protocol = hints->ai_protocol;
367
req->addrinfow->ai_flags = hints->ai_flags;
368
req->addrinfow->ai_addrlen = 0;
369
req->addrinfow->ai_canonname = NULL;
370
req->addrinfow->ai_addr = NULL;
371
req->addrinfow->ai_next = NULL;
372
} else {
373
req->addrinfow = NULL;
374
}
375
376
uv__req_register(loop, req);
377
378
if (getaddrinfo_cb) {
379
uv__work_submit(loop,
380
&req->work_req,
381
UV__WORK_SLOW_IO,
382
uv__getaddrinfo_work,
383
uv__getaddrinfo_done);
384
return 0;
385
} else {
386
uv__getaddrinfo_work(&req->work_req);
387
uv__getaddrinfo_done(&req->work_req, 0);
388
return req->retcode;
389
}
390
391
error:
392
if (req != NULL) {
393
uv__free(req->alloc);
394
req->alloc = NULL;
395
}
396
return uv_translate_sys_error(err);
397
}
398
399
int uv_if_indextoname(unsigned int ifindex, char* buffer, size_t* size) {
400
NET_LUID luid;
401
wchar_t wname[NDIS_IF_MAX_STRING_SIZE + 1]; /* Add one for the NUL. */
402
DWORD bufsize;
403
int r;
404
405
if (buffer == NULL || size == NULL || *size == 0)
406
return UV_EINVAL;
407
408
r = ConvertInterfaceIndexToLuid(ifindex, &luid);
409
410
if (r != 0)
411
return uv_translate_sys_error(r);
412
413
r = ConvertInterfaceLuidToNameW(&luid, wname, ARRAY_SIZE(wname));
414
415
if (r != 0)
416
return uv_translate_sys_error(r);
417
418
/* Check how much space we need */
419
bufsize = WideCharToMultiByte(CP_UTF8, 0, wname, -1, NULL, 0, NULL, NULL);
420
421
if (bufsize == 0) {
422
return uv_translate_sys_error(GetLastError());
423
} else if (bufsize > *size) {
424
*size = bufsize;
425
return UV_ENOBUFS;
426
}
427
428
/* Convert to UTF-8 */
429
bufsize = WideCharToMultiByte(CP_UTF8,
430
0,
431
wname,
432
-1,
433
buffer,
434
*size,
435
NULL,
436
NULL);
437
438
if (bufsize == 0)
439
return uv_translate_sys_error(GetLastError());
440
441
*size = bufsize - 1;
442
return 0;
443
}
444
445
int uv_if_indextoiid(unsigned int ifindex, char* buffer, size_t* size) {
446
int r;
447
448
if (buffer == NULL || size == NULL || *size == 0)
449
return UV_EINVAL;
450
451
r = snprintf(buffer, *size, "%d", ifindex);
452
453
if (r < 0)
454
return uv_translate_sys_error(r);
455
456
if (r >= (int) *size) {
457
*size = r + 1;
458
return UV_ENOBUFS;
459
}
460
461
*size = r;
462
return 0;
463
}
464
465