win/getaddrinfo.c
Go to the documentation of this file.
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 
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;
60  size_t ai_addrlen;
61  WCHAR* ai_canonname;
62  struct sockaddr* ai_addr;
63  struct addrinfoW* ai_next;
65 
66  DECLSPEC_IMPORT int WSAAPI GetAddrInfoW(const WCHAR* node,
67  const WCHAR* service,
68  const ADDRINFOW* hints,
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) {
85  struct addrinfoW* hints;
86  int err;
87 
89  hints = req->addrinfow;
90  req->addrinfow = NULL;
91  err = GetAddrInfoW(req->node, req->service, hints, &req->addrinfow);
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) {
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 
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  */
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 
377 
378  if (getaddrinfo_cb) {
380  &req->work_req,
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 }
async_greeter_server_with_graceful_shutdown.loop
loop
Definition: async_greeter_server_with_graceful_shutdown.py:59
_gevent_test_main.result
result
Definition: _gevent_test_main.py:96
addrinfo::ai_addrlen
ares_socklen_t ai_addrlen
Definition: ares_ipv6.h:49
uv__work
Definition: third_party/libuv/include/uv/threadpool.h:30
ARRAY_SIZE
#define ARRAY_SIZE(array)
Definition: bloaty.cc:101
uv_if_indextoiid
int uv_if_indextoiid(unsigned int ifindex, char *buffer, size_t *size)
Definition: win/getaddrinfo.c:445
uv__getaddrinfo_work
static void uv__getaddrinfo_work(struct uv__work *w)
Definition: win/getaddrinfo.c:83
uv__malloc
void * uv__malloc(size_t size)
Definition: uv-common.c:75
uv_getaddrinfo_s
Definition: uv.h:871
error
grpc_error_handle error
Definition: retry_filter.cc:499
error_ref_leak.err
err
Definition: error_ref_leak.py:35
status
absl::Status status
Definition: rls.cc:251
ALIGNED_SIZE
#define ALIGNED_SIZE(X)
Definition: win/getaddrinfo.c:77
uv_freeaddrinfo
void uv_freeaddrinfo(struct addrinfo *ai)
Definition: win/getaddrinfo.c:236
uv__getaddrinfo_done
static void uv__getaddrinfo_done(struct uv__work *w, int status)
Definition: win/getaddrinfo.c:105
NDIS_IF_MAX_STRING_SIZE
#define NDIS_IF_MAX_STRING_SIZE
Definition: win/getaddrinfo.c:80
container_of
#define container_of(ptr, type, member)
Definition: uv-common.h:57
addrinfoW::ai_protocol
int ai_protocol
Definition: win/getaddrinfo.c:59
uv__getaddrinfo_translate_error
int uv__getaddrinfo_translate_error(int sys_err)
Definition: win/getaddrinfo.c:35
addrinfoW::ai_family
int ai_family
Definition: win/getaddrinfo.c:57
uv_getaddrinfo_cb
void(* uv_getaddrinfo_cb)(uv_getaddrinfo_t *req, int status, struct addrinfo *res)
Definition: uv.h:328
req-inl.h
memcpy
memcpy(mem, inblock.get(), min(CONTAINING_RECORD(inblock.get(), MEMBLOCK, data) ->size, size))
PADDRINFOW
struct addrinfoW * PADDRINFOW
req
static uv_connect_t req
Definition: test-connection-fail.c:30
uv_translate_sys_error
UV_EXTERN int uv_translate_sys_error(int sys_errno)
Definition: unix/core.c:1244
addrinfoW::ai_addrlen
size_t ai_addrlen
Definition: win/getaddrinfo.c:60
addrinfo::ai_canonname
char * ai_canonname
Definition: ares_ipv6.h:50
addrinfoW::ai_canonname
WCHAR * ai_canonname
Definition: win/getaddrinfo.c:61
addrinfo::ai_addr
struct sockaddr * ai_addr
Definition: ares_ipv6.h:51
uv__free
void uv__free(void *ptr)
Definition: uv-common.c:81
ADDRINFOW
struct addrinfoW ADDRINFOW
buffer
char buffer[1024]
Definition: libuv/docs/code/idle-compute/main.c:8
addrinfo::ai_family
int ai_family
Definition: ares_ipv6.h:46
uv_getaddrinfo
int 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)
Definition: win/getaddrinfo.c:257
uv_if_indextoname
int uv_if_indextoname(unsigned int ifindex, char *buffer, size_t *size)
Definition: win/getaddrinfo.c:399
addrinfo::ai_protocol
int ai_protocol
Definition: ares_ipv6.h:48
addrinfoW::ai_socktype
int ai_socktype
Definition: win/getaddrinfo.c:58
uv.h
addrinfoW
Definition: win/getaddrinfo.c:55
UV_REQ_INIT
#define UV_REQ_INIT(req, typ)
Definition: uv-common.h:305
addrinfo::ai_next
struct addrinfo * ai_next
Definition: ares_ipv6.h:52
UV__WORK_SLOW_IO
@ UV__WORK_SLOW_IO
Definition: uv-common.h:181
FreeAddrInfoW
DECLSPEC_IMPORT void WSAAPI FreeAddrInfoW(PADDRINFOW pAddrInfo)
uv__req_register
#define uv__req_register(loop, req)
Definition: uv-common.h:207
fix_build_deps.r
r
Definition: fix_build_deps.py:491
getaddrinfo_cb
static void getaddrinfo_cb(uv_getaddrinfo_t *handle, int status, struct addrinfo *res)
Definition: benchmark-getaddrinfo.c:44
addrinfo::ai_socktype
int ai_socktype
Definition: ares_ipv6.h:47
addrinfo::ai_flags
int ai_flags
Definition: ares_ipv6.h:45
idna.h
uv_loop_s
Definition: uv.h:1767
internal.h
service
__attribute__((deprecated("Please use GRPCProtoMethod."))) @interface ProtoMethod NSString * service
Definition: ProtoMethod.h:25
work_req
static uv_work_t work_req
Definition: test-loop-alive.c:32
size
voidpf void uLong size
Definition: bloaty/third_party/zlib/contrib/minizip/ioapi.h:136
uv__idna_toascii
long uv__idna_toascii(const char *s, const char *se, char *d, char *de)
Definition: idna.c:250
uv__work_submit
void uv__work_submit(uv_loop_t *loop, struct uv__work *w, enum uv__work_kind kind, void(*work)(struct uv__work *w), void(*done)(struct uv__work *w, int status))
Definition: threadpool.c:256
addrinfo
Definition: ares_ipv6.h:43
addrinfoW::ai_flags
int ai_flags
Definition: win/getaddrinfo.c:56
GetAddrInfoW
DECLSPEC_IMPORT int WSAAPI GetAddrInfoW(const WCHAR *node, const WCHAR *service, const ADDRINFOW *hints, PADDRINFOW *result)
addrinfoW::ai_next
struct addrinfoW * ai_next
Definition: win/getaddrinfo.c:63
uv__req_unregister
#define uv__req_unregister(loop, req)
Definition: uv-common.h:213
addrinfoW::ai_addr
struct sockaddr * ai_addr
Definition: win/getaddrinfo.c:62


grpc
Author(s):
autogenerated on Fri May 16 2025 02:58:28