Mercurial
comparison third_party/libuv/src/win/getaddrinfo.c @ 160:948de3f54cea
[ThirdParty] Added libuv
| author | June Park <parkjune1995@gmail.com> |
|---|---|
| date | Wed, 14 Jan 2026 19:39:52 -0800 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 159:05cf9467a1c3 | 160:948de3f54cea |
|---|---|
| 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 static size_t align_offset(size_t off, size_t alignment) { | |
| 75 return ((off + alignment - 1) / alignment) * alignment; | |
| 76 } | |
| 77 | |
| 78 #ifndef NDIS_IF_MAX_STRING_SIZE | |
| 79 #define NDIS_IF_MAX_STRING_SIZE IF_MAX_STRING_SIZE | |
| 80 #endif | |
| 81 | |
| 82 static void uv__getaddrinfo_work(struct uv__work* w) { | |
| 83 uv_getaddrinfo_t* req; | |
| 84 struct addrinfoW* hints; | |
| 85 int err; | |
| 86 | |
| 87 req = container_of(w, uv_getaddrinfo_t, work_req); | |
| 88 hints = req->addrinfow; | |
| 89 req->addrinfow = NULL; | |
| 90 err = GetAddrInfoW(req->node, req->service, hints, &req->addrinfow); | |
| 91 req->retcode = uv__getaddrinfo_translate_error(err); | |
| 92 } | |
| 93 | |
| 94 | |
| 95 /* | |
| 96 * Called from uv_run when complete. Call user specified callback | |
| 97 * then free returned addrinfo | |
| 98 * Returned addrinfo strings are converted from UTF-16 to UTF-8. | |
| 99 * | |
| 100 * To minimize allocation we calculate total size required, | |
| 101 * and copy all structs and referenced strings into the one block. | |
| 102 * Each size calculation is adjusted to avoid unaligned pointers. | |
| 103 */ | |
| 104 static void uv__getaddrinfo_done(struct uv__work* w, int status) { | |
| 105 uv_getaddrinfo_t* req = container_of(w, uv_getaddrinfo_t, work_req); | |
| 106 | |
| 107 /* release input parameter memory */ | |
| 108 uv__free(req->alloc); | |
| 109 req->alloc = NULL; | |
| 110 | |
| 111 if (status == UV_ECANCELED) { | |
| 112 assert(req->retcode == 0); | |
| 113 req->retcode = UV_EAI_CANCELED; | |
| 114 goto complete; | |
| 115 } | |
| 116 | |
| 117 if (req->retcode == 0) { | |
| 118 char* alloc_ptr = NULL; | |
| 119 size_t cur_off = 0; | |
| 120 size_t addrinfo_len; | |
| 121 /* Convert addrinfoW to addrinfo. First calculate required length. */ | |
| 122 struct addrinfoW* addrinfow_ptr = req->addrinfow; | |
| 123 while (addrinfow_ptr != NULL) { | |
| 124 cur_off = align_offset(cur_off, sizeof(void*)); | |
| 125 cur_off += sizeof(struct addrinfo); | |
| 126 /* TODO: This alignment could be smaller, if we could | |
| 127 portably get the alignment for sockaddr. */ | |
| 128 cur_off = align_offset(cur_off, sizeof(void*)); | |
| 129 cur_off += addrinfow_ptr->ai_addrlen; | |
| 130 if (addrinfow_ptr->ai_canonname != NULL) { | |
| 131 ssize_t name_len = | |
| 132 uv_utf16_length_as_wtf8(addrinfow_ptr->ai_canonname, -1); | |
| 133 if (name_len < 0) { | |
| 134 req->retcode = name_len; | |
| 135 goto complete; | |
| 136 } | |
| 137 cur_off += name_len + 1; | |
| 138 } | |
| 139 addrinfow_ptr = addrinfow_ptr->ai_next; | |
| 140 } | |
| 141 | |
| 142 /* allocate memory for addrinfo results */ | |
| 143 addrinfo_len = cur_off; | |
| 144 alloc_ptr = uv__malloc(addrinfo_len); | |
| 145 | |
| 146 /* do conversions */ | |
| 147 if (alloc_ptr != NULL) { | |
| 148 struct addrinfo *addrinfo_ptr = (struct addrinfo *)alloc_ptr; | |
| 149 cur_off = 0; | |
| 150 addrinfow_ptr = req->addrinfow; | |
| 151 | |
| 152 for (;;) { | |
| 153 cur_off += sizeof(struct addrinfo); | |
| 154 assert(cur_off <= addrinfo_len); | |
| 155 /* copy addrinfo struct data */ | |
| 156 addrinfo_ptr->ai_family = addrinfow_ptr->ai_family; | |
| 157 addrinfo_ptr->ai_socktype = addrinfow_ptr->ai_socktype; | |
| 158 addrinfo_ptr->ai_protocol = addrinfow_ptr->ai_protocol; | |
| 159 addrinfo_ptr->ai_flags = addrinfow_ptr->ai_flags; | |
| 160 addrinfo_ptr->ai_addrlen = addrinfow_ptr->ai_addrlen; | |
| 161 addrinfo_ptr->ai_canonname = NULL; | |
| 162 addrinfo_ptr->ai_addr = NULL; | |
| 163 addrinfo_ptr->ai_next = NULL; | |
| 164 | |
| 165 /* copy sockaddr */ | |
| 166 if (addrinfo_ptr->ai_addrlen > 0) { | |
| 167 cur_off = align_offset(cur_off, sizeof(void *)); | |
| 168 addrinfo_ptr->ai_addr = (struct sockaddr *)(alloc_ptr + cur_off); | |
| 169 cur_off += addrinfo_ptr->ai_addrlen; | |
| 170 assert(cur_off <= addrinfo_len); | |
| 171 memcpy(addrinfo_ptr->ai_addr, | |
| 172 addrinfow_ptr->ai_addr, | |
| 173 addrinfo_ptr->ai_addrlen); | |
| 174 } | |
| 175 | |
| 176 /* convert canonical name to UTF-8 */ | |
| 177 if (addrinfow_ptr->ai_canonname != NULL) { | |
| 178 ssize_t name_len = addrinfo_len - cur_off; | |
| 179 addrinfo_ptr->ai_canonname = alloc_ptr + cur_off; | |
| 180 int r = uv__copy_utf16_to_utf8(addrinfow_ptr->ai_canonname, | |
| 181 -1, | |
| 182 addrinfo_ptr->ai_canonname, | |
| 183 (size_t*)&name_len); | |
| 184 assert(r == 0); | |
| 185 cur_off += name_len + 1; | |
| 186 assert(cur_off <= addrinfo_len); | |
| 187 } | |
| 188 | |
| 189 /* set next ptr */ | |
| 190 addrinfow_ptr = addrinfow_ptr->ai_next; | |
| 191 if (addrinfow_ptr == NULL) | |
| 192 break; | |
| 193 cur_off = align_offset(cur_off, sizeof(void *)); | |
| 194 struct addrinfo *next_addrinfo_ptr = (struct addrinfo *)(alloc_ptr + cur_off); | |
| 195 addrinfo_ptr->ai_next = next_addrinfo_ptr; | |
| 196 addrinfo_ptr = next_addrinfo_ptr; | |
| 197 } | |
| 198 req->addrinfo = (struct addrinfo*)alloc_ptr; | |
| 199 } else { | |
| 200 req->retcode = UV_EAI_MEMORY; | |
| 201 } | |
| 202 } | |
| 203 | |
| 204 /* return memory to system */ | |
| 205 if (req->addrinfow != NULL) { | |
| 206 FreeAddrInfoW(req->addrinfow); | |
| 207 req->addrinfow = NULL; | |
| 208 } | |
| 209 | |
| 210 complete: | |
| 211 uv__req_unregister(req->loop); | |
| 212 | |
| 213 /* finally do callback with converted result */ | |
| 214 if (req->getaddrinfo_cb) | |
| 215 req->getaddrinfo_cb(req, req->retcode, req->addrinfo); | |
| 216 } | |
| 217 | |
| 218 | |
| 219 void uv_freeaddrinfo(struct addrinfo* ai) { | |
| 220 char* alloc_ptr = (char*)ai; | |
| 221 | |
| 222 /* release copied result memory */ | |
| 223 uv__free(alloc_ptr); | |
| 224 } | |
| 225 | |
| 226 | |
| 227 /* | |
| 228 * Entry point for getaddrinfo | |
| 229 * we convert the UTF-8 strings to UNICODE | |
| 230 * and save the UNICODE string pointers in the req | |
| 231 * We also copy hints so that caller does not need to keep memory until the | |
| 232 * callback. | |
| 233 * return 0 if a callback will be made | |
| 234 * return error code if validation fails | |
| 235 * | |
| 236 * To minimize allocation we calculate total size required, | |
| 237 * and copy all structs and referenced strings into the one block. | |
| 238 * Each size calculation is adjusted to avoid unaligned pointers. | |
| 239 */ | |
| 240 int uv_getaddrinfo(uv_loop_t* loop, | |
| 241 uv_getaddrinfo_t* req, | |
| 242 uv_getaddrinfo_cb getaddrinfo_cb, | |
| 243 const char* node, | |
| 244 const char* service, | |
| 245 const struct addrinfo* hints) { | |
| 246 char hostname_ascii[256]; | |
| 247 size_t off = 0; | |
| 248 size_t nodesize = 0; | |
| 249 size_t servicesize = 0; | |
| 250 size_t serviceoff = 0; | |
| 251 size_t hintssize = 0; | |
| 252 size_t hintoff = 0; | |
| 253 ssize_t rc; | |
| 254 | |
| 255 if (req == NULL || (node == NULL && service == NULL)) { | |
| 256 return UV_EINVAL; | |
| 257 } | |
| 258 | |
| 259 UV_REQ_INIT(req, UV_GETADDRINFO); | |
| 260 req->getaddrinfo_cb = getaddrinfo_cb; | |
| 261 req->addrinfo = NULL; | |
| 262 req->loop = loop; | |
| 263 req->retcode = 0; | |
| 264 | |
| 265 /* calculate required memory size for all input values */ | |
| 266 if (node != NULL) { | |
| 267 rc = uv__idna_toascii(node, | |
| 268 node + strlen(node), | |
| 269 hostname_ascii, | |
| 270 hostname_ascii + sizeof(hostname_ascii)); | |
| 271 if (rc < 0) | |
| 272 return rc; | |
| 273 nodesize = strlen(hostname_ascii) + 1; | |
| 274 node = hostname_ascii; | |
| 275 off += nodesize * sizeof(WCHAR); | |
| 276 } | |
| 277 | |
| 278 if (service != NULL) { | |
| 279 rc = uv_wtf8_length_as_utf16(service); | |
| 280 if (rc < 0) | |
| 281 return rc; | |
| 282 servicesize = rc; | |
| 283 off = align_offset(off, sizeof(WCHAR)); | |
| 284 serviceoff = off; | |
| 285 off += servicesize * sizeof(WCHAR); | |
| 286 } | |
| 287 | |
| 288 if (hints != NULL) { | |
| 289 off = align_offset(off, sizeof(void *)); | |
| 290 hintoff = off; | |
| 291 hintssize = sizeof(struct addrinfoW); | |
| 292 off += hintssize; | |
| 293 } | |
| 294 | |
| 295 /* allocate memory for inputs, and partition it as needed */ | |
| 296 req->alloc = uv__malloc(off); | |
| 297 if (!req->alloc) | |
| 298 return UV_ENOMEM; | |
| 299 | |
| 300 /* Convert node string to UTF16 into allocated memory and save pointer in the | |
| 301 * request. The node here has been converted to ascii. */ | |
| 302 if (node != NULL) { | |
| 303 req->node = (WCHAR*) req->alloc; | |
| 304 uv_wtf8_to_utf16(node, req->node, nodesize); | |
| 305 } else { | |
| 306 req->node = NULL; | |
| 307 } | |
| 308 | |
| 309 /* Convert service string to UTF16 into allocated memory and save pointer in | |
| 310 * the req. */ | |
| 311 if (service != NULL) { | |
| 312 req->service = (WCHAR*) ((char*) req->alloc + serviceoff); | |
| 313 uv_wtf8_to_utf16(service, req->service, servicesize); | |
| 314 } else { | |
| 315 req->service = NULL; | |
| 316 } | |
| 317 | |
| 318 /* copy hints to allocated memory and save pointer in req */ | |
| 319 if (hints != NULL) { | |
| 320 req->addrinfow = (struct addrinfoW*) ((char*) req->alloc + hintoff); | |
| 321 req->addrinfow->ai_family = hints->ai_family; | |
| 322 req->addrinfow->ai_socktype = hints->ai_socktype; | |
| 323 req->addrinfow->ai_protocol = hints->ai_protocol; | |
| 324 req->addrinfow->ai_flags = hints->ai_flags; | |
| 325 req->addrinfow->ai_addrlen = 0; | |
| 326 req->addrinfow->ai_canonname = NULL; | |
| 327 req->addrinfow->ai_addr = NULL; | |
| 328 req->addrinfow->ai_next = NULL; | |
| 329 } else { | |
| 330 req->addrinfow = NULL; | |
| 331 } | |
| 332 | |
| 333 uv__req_register(loop); | |
| 334 | |
| 335 if (getaddrinfo_cb) { | |
| 336 uv__work_submit(loop, | |
| 337 &req->work_req, | |
| 338 UV__WORK_SLOW_IO, | |
| 339 uv__getaddrinfo_work, | |
| 340 uv__getaddrinfo_done); | |
| 341 return 0; | |
| 342 } else { | |
| 343 uv__getaddrinfo_work(&req->work_req); | |
| 344 uv__getaddrinfo_done(&req->work_req, 0); | |
| 345 return req->retcode; | |
| 346 } | |
| 347 } | |
| 348 | |
| 349 int uv_if_indextoname(unsigned int ifindex, char* buffer, size_t* size) { | |
| 350 NET_LUID luid; | |
| 351 wchar_t wname[NDIS_IF_MAX_STRING_SIZE + 1]; /* Add one for the NUL. */ | |
| 352 int r; | |
| 353 | |
| 354 if (buffer == NULL || size == NULL || *size == 0) | |
| 355 return UV_EINVAL; | |
| 356 | |
| 357 r = ConvertInterfaceIndexToLuid(ifindex, &luid); | |
| 358 | |
| 359 if (r != 0) | |
| 360 return uv_translate_sys_error(r); | |
| 361 | |
| 362 r = ConvertInterfaceLuidToNameW(&luid, wname, ARRAY_SIZE(wname)); | |
| 363 | |
| 364 if (r != 0) | |
| 365 return uv_translate_sys_error(r); | |
| 366 | |
| 367 return uv__copy_utf16_to_utf8(wname, -1, buffer, size); | |
| 368 } | |
| 369 | |
| 370 int uv_if_indextoiid(unsigned int ifindex, char* buffer, size_t* size) { | |
| 371 int r; | |
| 372 | |
| 373 if (buffer == NULL || size == NULL || *size == 0) | |
| 374 return UV_EINVAL; | |
| 375 | |
| 376 r = snprintf(buffer, *size, "%d", ifindex); | |
| 377 | |
| 378 if (r < 0) | |
| 379 return uv_translate_sys_error(r); | |
| 380 | |
| 381 if (r >= (int) *size) { | |
| 382 *size = r + 1; | |
| 383 return UV_ENOBUFS; | |
| 384 } | |
| 385 | |
| 386 *size = r; | |
| 387 return 0; | |
| 388 } |