diff --git a/msvs/libuv-benchmark.vcxproj b/msvs/libuv-benchmark.vcxproj index 53d5b526..af788128 100644 --- a/msvs/libuv-benchmark.vcxproj +++ b/msvs/libuv-benchmark.vcxproj @@ -136,6 +136,7 @@ + diff --git a/msvs/libuv-test.vcxproj b/msvs/libuv-test.vcxproj index a32cbe46..d1c80c90 100644 --- a/msvs/libuv-test.vcxproj +++ b/msvs/libuv-test.vcxproj @@ -150,6 +150,7 @@ + diff --git a/test/benchmark-getaddrinfo.c b/test/benchmark-getaddrinfo.c new file mode 100644 index 00000000..d74f4290 --- /dev/null +++ b/test/benchmark-getaddrinfo.c @@ -0,0 +1,96 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "../uv.h" +#include "task.h" + +#include +#include +#include /* strlen */ + + + +static uv_buf_t alloc_cb(uv_handle_t* handle, size_t size) { + uv_buf_t buf; + buf.base = (char*)malloc(size); + buf.len = size; + return buf; +} + + +/* data used for running multiple calls concurrently */ +#define CONCURRENT_COUNT 1000 +int callback_counts[CONCURRENT_COUNT]; +uv_getaddrinfo_t getaddrinfo_handles[CONCURRENT_COUNT]; + + +static void getaddrinfo_cuncurrent_cb(uv_getaddrinfo_t* handle, int status, struct addrinfo* res) { + int i; + for (i = 0; i < CONCURRENT_COUNT; i++) { + if (&getaddrinfo_handles[i] == handle) { + callback_counts[i]++; + break; + } + } + + ASSERT (i < CONCURRENT_COUNT); +} + +static int64_t start_time; +static int64_t end_time; + + +BENCHMARK_IMPL(getaddrinfo) { + + int rc = 0; + char* name = "localhost"; + int i; + + uv_init(); + + uv_update_time(); + start_time = uv_now(); + + for (i = 0; i < CONCURRENT_COUNT; i++) { + callback_counts[i] = 0; + + uv_getaddrinfo(&getaddrinfo_handles[i], + &getaddrinfo_cuncurrent_cb, + name, + NULL, + NULL); + + } + + uv_run(); + + end_time = uv_now(); + + for (i = 0; i < CONCURRENT_COUNT; i++) { + if (callback_counts[i] != 1) { + printf("Not all callbacks were called 1 time\n"); + } + } + + LOGF("getaddrinfo: %d calls in %ld ms \n", CONCURRENT_COUNT, (end_time - start_time)); + + return 0; +} diff --git a/test/benchmark-list.h b/test/benchmark-list.h index ff3421d8..6040e90a 100644 --- a/test/benchmark-list.h +++ b/test/benchmark-list.h @@ -24,6 +24,7 @@ BENCHMARK_DECLARE (ping_pongs) BENCHMARK_DECLARE (pump100_client) BENCHMARK_DECLARE (pump1_client) BENCHMARK_DECLARE (gethostbyname) +BENCHMARK_DECLARE (getaddrinfo) HELPER_DECLARE (pump_server) HELPER_DECLARE (echo_server) HELPER_DECLARE (dns_server) @@ -43,4 +44,5 @@ TASK_LIST_START BENCHMARK_ENTRY (gethostbyname) BENCHMARK_HELPER (gethostbyname, dns_server) + BENCHMARK_ENTRY (getaddrinfo) TASK_LIST_END diff --git a/test/test-getaddrinfo.c b/test/test-getaddrinfo.c new file mode 100644 index 00000000..9477ff6e --- /dev/null +++ b/test/test-getaddrinfo.c @@ -0,0 +1,146 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "../uv.h" +#include "task.h" + +#include +#include +#include /* strlen */ + + + +static uv_buf_t alloc_cb(uv_handle_t* handle, size_t size) { + uv_buf_t buf; + buf.base = (char*)malloc(size); + buf.len = size; + return buf; +} + +int getaddrinfo_callbacks; + +uv_getaddrinfo_t getaddrinfo_handle; + +static void getaddrinfo_callback(uv_getaddrinfo_t* handle, int status, struct addrinfo* res) { + ASSERT(handle == &getaddrinfo_handle); + getaddrinfo_callbacks++; +} + + +/* data used for running multiple calls concurrently */ +#define CONCURRENT_COUNT 10 +int callback_counts[CONCURRENT_COUNT]; +uv_getaddrinfo_t getaddrinfo_handles[CONCURRENT_COUNT]; + + +static void getaddrinfo_cuncurrent_cb(uv_getaddrinfo_t* handle, int status, struct addrinfo* res) { + int i; + for (i = 0; i < CONCURRENT_COUNT; i++) { + if (&getaddrinfo_handles[i] == handle) { + callback_counts[i]++; + break; + } + } + + ASSERT (i < CONCURRENT_COUNT); +} + + +TEST_IMPL(getaddrinfo) { + + int rc = 0; + char* name = "localhost"; + int i; + + uv_init(); + + printf("Start basic getaddrinfo test\n"); + + getaddrinfo_callbacks = 0; + + uv_getaddrinfo(&getaddrinfo_handle, + &getaddrinfo_callback, + name, + NULL, + NULL); + + uv_run(); + + ASSERT(getaddrinfo_callbacks == 1); + + printf("Done basic getaddrinfo test\n"); + + + printf("Start multiple getaddrinfo sequential test\n"); + + getaddrinfo_callbacks = 0; + + uv_getaddrinfo(&getaddrinfo_handle, + &getaddrinfo_callback, + name, + NULL, + NULL); + + uv_run(); + + ASSERT(getaddrinfo_callbacks == 1); + + getaddrinfo_callbacks = 0; + + uv_getaddrinfo(&getaddrinfo_handle, + &getaddrinfo_callback, + name, + NULL, + NULL); + + uv_run(); + + ASSERT(getaddrinfo_callbacks == 1); + + + printf("Done multiple getaddrinfo sequential test test\n"); + + + printf("Start multiple getaddrinfo concurrent test\n"); + + for (i = 0; i < CONCURRENT_COUNT; i++) + { + callback_counts[i] = 0; + + uv_getaddrinfo(&getaddrinfo_handles[i], + &getaddrinfo_cuncurrent_cb, + name, + NULL, + NULL); + + } + + uv_run(); + + for (i = 0; i < CONCURRENT_COUNT; i++) + { + ASSERT(callback_counts[i] == 1); + } + + printf("Done multiple getaddrinfo concurrent test\n"); + + return 0; +} diff --git a/test/test-list.h b/test/test-list.h index 1c692fbf..39a264f1 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -44,6 +44,7 @@ TEST_DECLARE (async) TEST_DECLARE (get_currentexe) TEST_DECLARE (hrtime) TEST_DECLARE (gethostbyname) +TEST_DECLARE (getaddrinfo) TEST_DECLARE (fail_always) TEST_DECLARE (pass_always) HELPER_DECLARE (echo_server) @@ -95,6 +96,7 @@ TASK_LIST_START TEST_ENTRY (get_currentexe) TEST_ENTRY (hrtime) + TEST_ENTRY (getaddrinfo) TEST_ENTRY (gethostbyname) TEST_HELPER (gethostbyname, echo_server) diff --git a/uv-unix.c b/uv-unix.c index b4d1aee3..91ed1274 100644 --- a/uv-unix.c +++ b/uv-unix.c @@ -1303,3 +1303,21 @@ void uv_ares_destroy(ares_channel channel) { } +/* temporary implementation of uv_getaddrinfo +* calls getaddrinfo, then invokes callback and frees addrinfo +*/ +void uv_getaddrinfo(uv_getaddrinfo_t* handle, + uv_getaddrinfo_cb getaddrinfo_cb, + char* node, + char* service, + struct addrinfo* hints) { + int ret; + struct addrinfo* res = NULL; + ret = getaddrinfo(getaddrinfo_cb, node, service, hints, &res); + + /* call user with results */ + (*getaddrinfo_cb)(handle, uv_translate_sys_error(ret), res); + if (ret == 0) { + freeaddrinfo(res); + } +} diff --git a/uv-unix.h b/uv-unix.h index 59fc0974..234059ae 100644 --- a/uv-unix.h +++ b/uv-unix.h @@ -102,4 +102,6 @@ typedef struct { #define UV_ARES_TASK_PRIVATE_FIELDS /* TODO */ +#define UV_GETADDRINFO_PRIVATE_FIELDS /* TODO */ + #endif /* UV_UNIX_H */ diff --git a/uv-win.c b/uv-win.c index cb0eead2..1d56e12f 100644 --- a/uv-win.c +++ b/uv-win.c @@ -106,6 +106,38 @@ #endif +/* + * MinGw is missing this too + */ +#ifndef _MSC_VER +typedef struct addrinfoW { + int ai_flags; + int ai_family; + int ai_socktype; + int ai_protocol; + size_t ai_addrlen; + wchar_t* ai_canonname; + struct sockaddr* ai_addr; + struct addrinfoW* ai_next; +} ADDRINFOW, *PADDRINFOW; + + +DECLSPEC_IMPORT +int +WSAAPI +GetAddrInfoW(const wchar_t* node, + const wchar_t* service, + const ADDRINFOW* hints, + PADDRINFOW* result); + +DECLSPEC_IMPORT +void +WSAAPI +FreeAddrInfoW(PADDRINFOW pAddrInfo); + +#endif + + /* * Pointers to winsock extension functions to be retrieved dynamically */ @@ -210,6 +242,13 @@ static uv_ares_channel_t uv_ares_data = { NULL }; #define ARES_TIMEOUT_MS 20000 +/* getaddrinfo integration */ +static void uv_getaddrinfo_done(uv_getaddrinfo_t* handle, uv_req_t* req); +/* adjust size value to be multiple of 4. Use to keep pointer aligned */ +/* Do we need different versions of this for different architectures? */ +#define ALIGNED_SIZE(X) ((((X) + 3) >> 2) << 2) + + /* Atomic set operation on char */ #ifdef _MSC_VER /* MSVC */ @@ -313,6 +352,10 @@ static uv_err_code uv_translate_sys_error(int sys_errno) { case ERROR_TOO_MANY_OPEN_FILES: return UV_EMFILE; case WSAEMFILE: return UV_EMFILE; case ERROR_OUTOFMEMORY: return UV_ENOMEM; + case ERROR_INSUFFICIENT_BUFFER: return UV_EINVAL; + case ERROR_INVALID_FLAGS: return UV_EBADF; + case ERROR_INVALID_PARAMETER: return UV_EINVAL; + case ERROR_NO_UNICODE_TRANSLATION: return UV_ECHARSET; default: return UV_UNKNOWN; } } @@ -1546,6 +1589,10 @@ static void uv_process_reqs() { uv_ares_task_cleanup((uv_ares_task_t*)handle, req); break; + case UV_GETADDRINFO: + uv_getaddrinfo_done((uv_getaddrinfo_t*)handle, req); + break; + default: assert(0); } @@ -1690,6 +1737,10 @@ int uv_utf16_to_utf8(wchar_t* utf16Buffer, size_t utf16Size, char* utf8Buffer, s return WideCharToMultiByte(CP_UTF8, 0, utf16Buffer, utf16Size, utf8Buffer, utf8Size, NULL, NULL); } +int uv_utf8_to_utf16(const char* utf8Buffer, wchar_t* utf16Buffer, size_t utf16Size) { + return MultiByteToWideChar(CP_UTF8, 0, utf8Buffer, -1, utf16Buffer, utf16Size); +} + int uv_get_exepath(char* buffer, size_t* size) { int retVal; @@ -2000,3 +2051,284 @@ void uv_ares_destroy(ares_channel channel) { } +/* + * getaddrinfo error code mapping + * Falls back to uv_translate_sys_error if no match + */ + +static uv_err_code uv_translate_eai_error(int eai_errno) { + switch (eai_errno) { + case ERROR_SUCCESS: return UV_OK; + case EAI_BADFLAGS: return UV_EBADF; + case EAI_FAIL: return UV_EFAULT; + case EAI_FAMILY: return UV_EAIFAMNOSUPPORT; + case EAI_MEMORY: return UV_ENOMEM; + case EAI_NONAME: return UV_EAINONAME; + case EAI_AGAIN: return UV_EAGAIN; + case EAI_SERVICE: return UV_EAISERVICE; + case EAI_SOCKTYPE: return UV_EAISOCKTYPE; + default: return uv_translate_sys_error(eai_errno); + } +} + +/* getaddrinfo worker thread implementation */ +static DWORD WINAPI getaddrinfo_thread_proc(void* parameter) { + uv_getaddrinfo_t* handle = (uv_getaddrinfo_t*)parameter; + int ret; + + assert(handle != NULL); + + if (handle != NULL) { + /* call OS function on this thread */ + ret = GetAddrInfoW(handle->node, handle->service, handle->hints, &handle->res); + handle->retcode = ret; + + /* post getaddrinfo completed */ + if (!PostQueuedCompletionStatus(uv_iocp_, + 0, + 0, + &handle->getadddrinfo_req.overlapped)) { + uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus"); + } + } + + return 0; +} + +/* + * Called from uv_run when complete. Call user specified callback + * then free returned addrinfo + * Returned addrinfo strings are converted from UTF-16 to UTF-8. + * + * To minimize allocation we calculate total size required, + * and copy all structs and referenced strings into the one block. + * Each size calculation is adjusted to avoid unaligned pointers. + */ +static void uv_getaddrinfo_done(uv_getaddrinfo_t* handle, uv_req_t* req) { + int addrinfo_len = 0; + int name_len = 0; + size_t addrinfo_struct_len = ALIGNED_SIZE(sizeof(struct addrinfo)); + struct addrinfoW* addrinfow_ptr; + struct addrinfo* addrinfo_ptr; + char* alloc_ptr = NULL; + char* cur_ptr = NULL; + uv_err_code uv_ret; + + /* release input parameter memory */ + if (handle->alloc != NULL) { + free(handle->alloc); + handle->alloc = NULL; + } + + uv_ret = uv_translate_eai_error(handle->retcode); + if (handle->retcode == 0) { + /* convert addrinfoW to addrinfo */ + /* first calculate required length */ + addrinfow_ptr = handle->res; + while (addrinfow_ptr != NULL) { + addrinfo_len += addrinfo_struct_len + ALIGNED_SIZE(addrinfow_ptr->ai_addrlen); + if (addrinfow_ptr->ai_canonname != NULL) { + name_len = uv_utf16_to_utf8(addrinfow_ptr->ai_canonname, -1, NULL, 0); + if (name_len == 0) { + uv_ret = uv_translate_sys_error(GetLastError()); + goto complete; + } + addrinfo_len += ALIGNED_SIZE(name_len); + } + addrinfow_ptr = addrinfow_ptr->ai_next; + } + + /* allocate memory for addrinfo results */ + alloc_ptr = (char*)malloc(addrinfo_len); + + /* do conversions */ + if (alloc_ptr != NULL) { + cur_ptr = alloc_ptr; + addrinfow_ptr = handle->res; + + while (addrinfow_ptr != NULL) { + /* copy addrinfo struct data */ + assert(cur_ptr + addrinfo_struct_len <= alloc_ptr + addrinfo_len); + addrinfo_ptr = (struct addrinfo*)cur_ptr; + addrinfo_ptr->ai_family = addrinfow_ptr->ai_family; + addrinfo_ptr->ai_socktype = addrinfow_ptr->ai_socktype; + addrinfo_ptr->ai_protocol = addrinfow_ptr->ai_protocol; + addrinfo_ptr->ai_flags = addrinfow_ptr->ai_flags; + addrinfo_ptr->ai_addrlen = addrinfow_ptr->ai_addrlen; + addrinfo_ptr->ai_canonname = NULL; + addrinfo_ptr->ai_addr = NULL; + addrinfo_ptr->ai_next = NULL; + + cur_ptr += addrinfo_struct_len; + + /* copy sockaddr */ + if (addrinfo_ptr->ai_addrlen > 0) { + assert(cur_ptr + addrinfo_ptr->ai_addrlen <= alloc_ptr + addrinfo_len); + memcpy(cur_ptr, addrinfow_ptr->ai_addr, addrinfo_ptr->ai_addrlen); + addrinfo_ptr->ai_addr = (struct sockaddr*)cur_ptr; + cur_ptr += ALIGNED_SIZE(addrinfo_ptr->ai_addrlen); + } + + /* convert canonical name to UTF-8 */ + if (addrinfow_ptr->ai_canonname != NULL) { + name_len = uv_utf16_to_utf8(addrinfow_ptr->ai_canonname, -1, NULL, 0); + assert(name_len > 0); + assert(cur_ptr + name_len <= alloc_ptr + addrinfo_len); + name_len = uv_utf16_to_utf8(addrinfow_ptr->ai_canonname, -1, cur_ptr, name_len); + assert(name_len > 0); + addrinfo_ptr->ai_canonname = cur_ptr; + cur_ptr += ALIGNED_SIZE(name_len); + } + assert(cur_ptr <= alloc_ptr + addrinfo_len); + + /* set next ptr */ + addrinfow_ptr = addrinfow_ptr->ai_next; + if (addrinfow_ptr != NULL) { + addrinfo_ptr->ai_next = (struct addrinfo*)cur_ptr; + } + } + } else { + uv_ret = UV_ENOMEM; + } + + } + + /* return memory to system */ + if (handle->res != NULL) { + FreeAddrInfoW(handle->res); + handle->res = NULL; + } + +complete: + /* finally do callback with converted result */ + handle->getaddrinfo_cb(handle, uv_ret, (struct addrinfo*)alloc_ptr); + + /* release copied result memory */ + if (alloc_ptr != NULL) { + free(alloc_ptr); + } + + uv_refs_--; +} + +/* + * Entry point for getaddrinfo + * we convert the UTF-8 strings to UNICODE + * and save the UNICODE string pointers in the handle + * We also copy hints so that caller does not need to keep memory until the callback. + * return UV_OK if a callback will be made + * return error code if validation fails + * + * To minimize allocation we calculate total size required, + * and copy all structs and referenced strings into the one block. + * Each size calculation is adjusted to avoid unaligned pointers. + */ +uv_err_code uv_getaddrinfo(uv_getaddrinfo_t* handle, + uv_getaddrinfo_cb getaddrinfo_cb, + const char* node, + const char* service, + const struct addrinfo* hints) { + uv_err_code ret = UV_OK; + int nodesize = 0; + int servicesize = 0; + int hintssize = 0; + char* alloc_ptr = NULL; + + if (handle == NULL || getaddrinfo_cb == NULL || + (node == NULL && service == NULL)) { + ret = UV_EINVAL; + goto error; + } + + handle->getaddrinfo_cb = getaddrinfo_cb; + handle->res = NULL; + handle->type = UV_GETADDRINFO; + + /* calculate required memory size for all input values */ + if (node != NULL) { + nodesize = ALIGNED_SIZE(uv_utf8_to_utf16(node, NULL, 0) * sizeof(wchar_t)); + if (nodesize == 0) { + ret = uv_translate_sys_error(GetLastError()); + goto error; + } + } + + if (service != NULL) { + servicesize = ALIGNED_SIZE(uv_utf8_to_utf16(service, NULL, 0) * sizeof(wchar_t)); + if (servicesize == 0) { + ret = uv_translate_sys_error(GetLastError()); + goto error; + } + } + if (hints != NULL) { + hintssize = ALIGNED_SIZE(sizeof(struct addrinfoW)); + } + + /* allocate memory for inputs, and partition it as needed */ + alloc_ptr = (char*)malloc(nodesize + servicesize + hintssize); + if (!alloc_ptr) { + ret = UV_ENOMEM; + goto error; + } + + /* save alloc_ptr now so we can free if error */ + handle->alloc = (void*)alloc_ptr; + + /* convert node string to UTF16 into allocated memory and save pointer in handle */ + if (node != NULL) { + handle->node = (wchar_t*)alloc_ptr; + if (uv_utf8_to_utf16(node, (wchar_t*)alloc_ptr, nodesize / sizeof(wchar_t)) == 0) { + ret = uv_translate_sys_error(GetLastError()); + goto error; + } + alloc_ptr += nodesize; + } else { + handle->node = NULL; + } + + /* convert service string to UTF16 into allocated memory and save pointer in handle */ + if (service != NULL) { + handle->service = (wchar_t*)alloc_ptr; + if (uv_utf8_to_utf16(service, (wchar_t*)alloc_ptr, servicesize / sizeof(wchar_t)) == 0) { + ret = uv_translate_sys_error(GetLastError()); + goto error; + } + alloc_ptr += servicesize; + } else { + handle->service = NULL; + } + + /* copy hints to allocated memory and save pointer in handle */ + if (hints != NULL) { + handle->hints = (struct addrinfoW*)alloc_ptr; + handle->hints->ai_family = hints->ai_family; + handle->hints->ai_socktype = hints->ai_socktype; + handle->hints->ai_protocol = hints->ai_protocol; + handle->hints->ai_flags = hints->ai_flags; + handle->hints->ai_addrlen = 0; + handle->hints->ai_canonname = NULL; + handle->hints->ai_addr = NULL; + handle->hints->ai_next = NULL; + } else { + handle->hints = NULL; + } + + /* init request for Post handling */ + uv_req_init(&handle->getadddrinfo_req, (uv_handle_t*)handle, NULL); + handle->getadddrinfo_req.type = UV_WAKEUP; + + /* Ask thread to run. Treat this as a long operation */ + if (QueueUserWorkItem(&getaddrinfo_thread_proc, handle, WT_EXECUTELONGFUNCTION) == 0) { + uv_fatal_error(GetLastError(), "QueueUserWorkItem"); + } + + uv_refs_++; + + return UV_OK; + +error: + if (handle != NULL && handle->alloc != NULL) { + free(handle->alloc); + } + return ret; +} diff --git a/uv-win.h b/uv-win.h index fe317faa..8bd41f2b 100644 --- a/uv-win.h +++ b/uv-win.h @@ -31,7 +31,6 @@ #include "tree.h" - /** * It should be possible to cast uv_buf_t[] to WSABUF[] * see http://msdn.microsoft.com/en-us/library/ms741542(v=vs.85).aspx @@ -123,4 +122,16 @@ typedef struct uv_buf_t { WSAEVENT h_event; \ HANDLE h_close_event; +#define UV_GETADDRINFO_PRIVATE_FIELDS \ + struct uv_req_s getadddrinfo_req; \ + uv_getaddrinfo_cb getaddrinfo_cb; \ + void* alloc; \ + wchar_t* node; \ + wchar_t* service; \ + struct addrinfoW* hints; \ + struct addrinfoW* res; \ + int retcode; + + int uv_utf16_to_utf8(wchar_t* utf16Buffer, size_t utf16Size, char* utf8Buffer, size_t utf8Size); +int uv_utf8_to_utf16(const char* utf8Buffer, wchar_t* utf16Buffer, size_t utf16Size); diff --git a/uv.h b/uv.h index f383d57b..fe5eb3f7 100644 --- a/uv.h +++ b/uv.h @@ -50,6 +50,7 @@ typedef struct uv_req_s uv_req_t; typedef struct uv_async_s uv_async_t; typedef struct uv_ares_task_s uv_ares_task_t; typedef struct uv_ares_action_s uv_ares_action_t; +typedef struct uv_getaddrinfo_s uv_getaddrinfo_t; #if defined(__unix__) || defined(__POSIX__) || defined(__APPLE__) @@ -80,6 +81,7 @@ typedef void (*uv_async_cb)(uv_async_t* handle, int status); typedef void (*uv_prepare_cb)(uv_prepare_t* handle, int status); typedef void (*uv_check_cb)(uv_check_t* handle, int status); typedef void (*uv_idle_cb)(uv_idle_t* handle, int status); +typedef void (*uv_getaddrinfo_cb)(uv_getaddrinfo_t* handle, int status, struct addrinfo *res); /* Expand this list if necessary. */ @@ -118,7 +120,12 @@ typedef enum { UV_EPROTO, UV_EPROTONOSUPPORT, UV_EPROTOTYPE, - UV_ETIMEDOUT + UV_ETIMEDOUT, + UV_ECHARSET, + UV_EAIFAMNOSUPPORT, + UV_EAINONAME, + UV_EAISERVICE, + UV_EAISOCKTYPE } uv_err_code; typedef enum { @@ -133,7 +140,8 @@ typedef enum { UV_IDLE, UV_ASYNC, UV_ARES, - UV_ARES_TASK + UV_ARES_TASK, + UV_GETADDRINFO } uv_handle_type; typedef enum { @@ -393,6 +401,29 @@ int uv_ares_init_options(ares_channel *channelptr, void uv_ares_destroy(ares_channel channel); +/* + * Subclass of uv_handle_t. Used for integration of getaddrinfo. + */ +struct uv_getaddrinfo_s { + UV_HANDLE_FIELDS + UV_GETADDRINFO_PRIVATE_FIELDS +}; + + +/* uv_getaddrinfo + * return code of UV_OK means that request is accepted, + * and callback will be called with result. + * Other return codes mean that there will not be a callback. + * Input arguments may be released after return from this call. + * Callback must not call freeaddrinfo + */ + uv_err_code uv_getaddrinfo(uv_getaddrinfo_t* handle, + uv_getaddrinfo_cb getaddrinfo_cb, + const char* node, + const char* service, + const struct addrinfo* hints); + + /* * Most functions return boolean: 0 for success and -1 for failure. * On error the user should then call uv_last_error() to determine @@ -432,6 +463,7 @@ union uv_any_handle { uv_timer_t timer; uv_ares_task_t arest; uv_ares_action_t aresa; + uv_getaddrinfo_t getaddrinfo; }; /* Diagnostic counters */