libuv-svace-build
383 строки · 11.8 Кб
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
35int uv__getaddrinfo_translate_error(int sys_err) {36switch (sys_err) {37case 0: return 0;38case WSATRY_AGAIN: return UV_EAI_AGAIN;39case WSAEINVAL: return UV_EAI_BADFLAGS;40case WSANO_RECOVERY: return UV_EAI_FAIL;41case WSAEAFNOSUPPORT: return UV_EAI_FAMILY;42case WSA_NOT_ENOUGH_MEMORY: return UV_EAI_MEMORY;43case WSAHOST_NOT_FOUND: return UV_EAI_NONAME;44case WSATYPE_NOT_FOUND: return UV_EAI_SERVICE;45case WSAESOCKTNOSUPPORT: return UV_EAI_SOCKTYPE;46default: 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)55typedef struct addrinfoW {56int ai_flags;57int ai_family;58int ai_socktype;59int ai_protocol;60size_t ai_addrlen;61WCHAR* ai_canonname;62struct sockaddr* ai_addr;63struct addrinfoW* ai_next;64} ADDRINFOW, *PADDRINFOW;65
66DECLSPEC_IMPORT int WSAAPI GetAddrInfoW(const WCHAR* node,67const WCHAR* service,68const ADDRINFOW* hints,69PADDRINFOW* result);70
71DECLSPEC_IMPORT void WSAAPI FreeAddrInfoW(PADDRINFOW pAddrInfo);72#endif73
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_SIZE80#define NDIS_IF_MAX_STRING_SIZE IF_MAX_STRING_SIZE81#endif82
83static void uv__getaddrinfo_work(struct uv__work* w) {84uv_getaddrinfo_t* req;85struct addrinfoW* hints;86int err;87
88req = container_of(w, uv_getaddrinfo_t, work_req);89hints = req->addrinfow;90req->addrinfow = NULL;91err = GetAddrInfoW(req->node, req->service, hints, &req->addrinfow);92req->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*/
105static void uv__getaddrinfo_done(struct uv__work* w, int status) {106uv_getaddrinfo_t* req;107size_t addrinfo_len = 0;108ssize_t name_len = 0;109size_t addrinfo_struct_len = ALIGNED_SIZE(sizeof(struct addrinfo));110struct addrinfoW* addrinfow_ptr;111struct addrinfo* addrinfo_ptr;112char* alloc_ptr = NULL;113char* cur_ptr = NULL;114int r;115
116req = container_of(w, uv_getaddrinfo_t, work_req);117
118/* release input parameter memory */119uv__free(req->alloc);120req->alloc = NULL;121
122if (status == UV_ECANCELED) {123assert(req->retcode == 0);124req->retcode = UV_EAI_CANCELED;125goto complete;126}127
128if (req->retcode == 0) {129/* Convert addrinfoW to addrinfo. First calculate required length. */130addrinfow_ptr = req->addrinfow;131while (addrinfow_ptr != NULL) {132addrinfo_len += addrinfo_struct_len +133ALIGNED_SIZE(addrinfow_ptr->ai_addrlen);134if (addrinfow_ptr->ai_canonname != NULL) {135name_len = uv_utf16_length_as_wtf8(addrinfow_ptr->ai_canonname, -1);136if (name_len < 0) {137req->retcode = name_len;138goto complete;139}140addrinfo_len += ALIGNED_SIZE(name_len + 1);141}142addrinfow_ptr = addrinfow_ptr->ai_next;143}144
145/* allocate memory for addrinfo results */146alloc_ptr = (char*)uv__malloc(addrinfo_len);147
148/* do conversions */149if (alloc_ptr != NULL) {150cur_ptr = alloc_ptr;151addrinfow_ptr = req->addrinfow;152
153while (addrinfow_ptr != NULL) {154/* copy addrinfo struct data */155assert(cur_ptr + addrinfo_struct_len <= alloc_ptr + addrinfo_len);156addrinfo_ptr = (struct addrinfo*)cur_ptr;157addrinfo_ptr->ai_family = addrinfow_ptr->ai_family;158addrinfo_ptr->ai_socktype = addrinfow_ptr->ai_socktype;159addrinfo_ptr->ai_protocol = addrinfow_ptr->ai_protocol;160addrinfo_ptr->ai_flags = addrinfow_ptr->ai_flags;161addrinfo_ptr->ai_addrlen = addrinfow_ptr->ai_addrlen;162addrinfo_ptr->ai_canonname = NULL;163addrinfo_ptr->ai_addr = NULL;164addrinfo_ptr->ai_next = NULL;165
166cur_ptr += addrinfo_struct_len;167
168/* copy sockaddr */169if (addrinfo_ptr->ai_addrlen > 0) {170assert(cur_ptr + addrinfo_ptr->ai_addrlen <=171alloc_ptr + addrinfo_len);172memcpy(cur_ptr, addrinfow_ptr->ai_addr, addrinfo_ptr->ai_addrlen);173addrinfo_ptr->ai_addr = (struct sockaddr*)cur_ptr;174cur_ptr += ALIGNED_SIZE(addrinfo_ptr->ai_addrlen);175}176
177/* convert canonical name to UTF-8 */178if (addrinfow_ptr->ai_canonname != NULL) {179name_len = alloc_ptr + addrinfo_len - cur_ptr;180r = uv__copy_utf16_to_utf8(addrinfow_ptr->ai_canonname,181-1,182cur_ptr,183(size_t*)&name_len);184assert(r == 0);185addrinfo_ptr->ai_canonname = cur_ptr;186cur_ptr += ALIGNED_SIZE(name_len + 1);187}188assert(cur_ptr <= alloc_ptr + addrinfo_len);189
190/* set next ptr */191addrinfow_ptr = addrinfow_ptr->ai_next;192if (addrinfow_ptr != NULL) {193addrinfo_ptr->ai_next = (struct addrinfo*)cur_ptr;194}195}196req->addrinfo = (struct addrinfo*)alloc_ptr;197} else {198req->retcode = UV_EAI_MEMORY;199}200}201
202/* return memory to system */203if (req->addrinfow != NULL) {204FreeAddrInfoW(req->addrinfow);205req->addrinfow = NULL;206}207
208complete:209uv__req_unregister(req->loop, req);210
211/* finally do callback with converted result */212if (req->getaddrinfo_cb)213req->getaddrinfo_cb(req, req->retcode, req->addrinfo);214}
215
216
217void uv_freeaddrinfo(struct addrinfo* ai) {218char* alloc_ptr = (char*)ai;219
220/* release copied result memory */221uv__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*/
238int uv_getaddrinfo(uv_loop_t* loop,239uv_getaddrinfo_t* req,240uv_getaddrinfo_cb getaddrinfo_cb,241const char* node,242const char* service,243const struct addrinfo* hints) {244char hostname_ascii[256];245size_t nodesize = 0;246size_t servicesize = 0;247size_t hintssize = 0;248char* alloc_ptr = NULL;249ssize_t rc;250
251if (req == NULL || (node == NULL && service == NULL)) {252return UV_EINVAL;253}254
255UV_REQ_INIT(req, UV_GETADDRINFO);256req->getaddrinfo_cb = getaddrinfo_cb;257req->addrinfo = NULL;258req->loop = loop;259req->retcode = 0;260
261/* calculate required memory size for all input values */262if (node != NULL) {263rc = uv__idna_toascii(node,264node + strlen(node),265hostname_ascii,266hostname_ascii + sizeof(hostname_ascii));267if (rc < 0)268return rc;269nodesize = strlen(hostname_ascii) + 1;270node = hostname_ascii;271}272
273if (service != NULL) {274rc = uv_wtf8_length_as_utf16(service);275if (rc < 0)276return rc;277servicesize = rc;278}279if (hints != NULL) {280hintssize = ALIGNED_SIZE(sizeof(struct addrinfoW));281}282
283/* allocate memory for inputs, and partition it as needed */284alloc_ptr = uv__malloc(ALIGNED_SIZE(nodesize * sizeof(WCHAR)) +285ALIGNED_SIZE(servicesize * sizeof(WCHAR)) +286hintssize);287if (!alloc_ptr)288return UV_ENOMEM;289
290/* save alloc_ptr now so we can free if error */291req->alloc = (void*) alloc_ptr;292
293/* Convert node string to UTF16 into allocated memory and save pointer in the294* request. The node here has been converted to ascii. */
295if (node != NULL) {296req->node = (WCHAR*) alloc_ptr;297uv_wtf8_to_utf16(node, (WCHAR*) alloc_ptr, nodesize);298alloc_ptr += ALIGNED_SIZE(nodesize * sizeof(WCHAR));299} else {300req->node = NULL;301}302
303/* Convert service string to UTF16 into allocated memory and save pointer in304* the req. */
305if (service != NULL) {306req->service = (WCHAR*) alloc_ptr;307uv_wtf8_to_utf16(service, (WCHAR*) alloc_ptr, servicesize);308alloc_ptr += ALIGNED_SIZE(servicesize * sizeof(WCHAR));309} else {310req->service = NULL;311}312
313/* copy hints to allocated memory and save pointer in req */314if (hints != NULL) {315req->addrinfow = (struct addrinfoW*) alloc_ptr;316req->addrinfow->ai_family = hints->ai_family;317req->addrinfow->ai_socktype = hints->ai_socktype;318req->addrinfow->ai_protocol = hints->ai_protocol;319req->addrinfow->ai_flags = hints->ai_flags;320req->addrinfow->ai_addrlen = 0;321req->addrinfow->ai_canonname = NULL;322req->addrinfow->ai_addr = NULL;323req->addrinfow->ai_next = NULL;324} else {325req->addrinfow = NULL;326}327
328uv__req_register(loop, req);329
330if (getaddrinfo_cb) {331uv__work_submit(loop,332&req->work_req,333UV__WORK_SLOW_IO,334uv__getaddrinfo_work,335uv__getaddrinfo_done);336return 0;337} else {338uv__getaddrinfo_work(&req->work_req);339uv__getaddrinfo_done(&req->work_req, 0);340return req->retcode;341}342}
343
344int uv_if_indextoname(unsigned int ifindex, char* buffer, size_t* size) {345NET_LUID luid;346wchar_t wname[NDIS_IF_MAX_STRING_SIZE + 1]; /* Add one for the NUL. */347int r;348
349if (buffer == NULL || size == NULL || *size == 0)350return UV_EINVAL;351
352r = ConvertInterfaceIndexToLuid(ifindex, &luid);353
354if (r != 0)355return uv_translate_sys_error(r);356
357r = ConvertInterfaceLuidToNameW(&luid, wname, ARRAY_SIZE(wname));358
359if (r != 0)360return uv_translate_sys_error(r);361
362return uv__copy_utf16_to_utf8(wname, -1, buffer, size);363}
364
365int uv_if_indextoiid(unsigned int ifindex, char* buffer, size_t* size) {366int r;367
368if (buffer == NULL || size == NULL || *size == 0)369return UV_EINVAL;370
371r = snprintf(buffer, *size, "%d", ifindex);372
373if (r < 0)374return uv_translate_sys_error(r);375
376if (r >= (int) *size) {377*size = r + 1;378return UV_ENOBUFS;379}380
381*size = r;382return 0;383}
384