unix, win: add synchronous uv_get{addr,name}info

PR-URL: https://github.com/libuv/libuv/pull/156
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Bert Belder <bertbelder@gmail.com>
This commit is contained in:
Saúl Ibarra Corretgé 2015-01-20 09:43:57 +01:00
parent 0b9ee2cf00
commit f2bb8d394c
11 changed files with 156 additions and 64 deletions

View File

@ -39,6 +39,13 @@ Public members
Loop that started this getaddrinfo request and where completion will be Loop that started this getaddrinfo request and where completion will be
reported. Readonly. reported. Readonly.
.. c:member:: struct addrinfo* uv_getaddrinfo_t.addrinfo
Pointer to a `struct addrinfo` containing the result. Must be freed by the user
with :c:func:`uv_freeaddrinfo`.
.. versionchanged:: 1.3.0 the field is declared as public.
.. c:member:: uv_loop_t* uv_getnameinfo_t.loop .. c:member:: uv_loop_t* uv_getnameinfo_t.loop
Loop that started this getnameinfo request and where completion will be Loop that started this getnameinfo request and where completion will be
@ -68,6 +75,9 @@ API
Call :c:func:`uv_freeaddrinfo` to free the addrinfo structure. Call :c:func:`uv_freeaddrinfo` to free the addrinfo structure.
.. versionchanged:: 1.3.0 the callback parameter is now allowed to be NULL,
in which case the request will run **synchronously**.
.. c:function:: void uv_freeaddrinfo(struct addrinfo* ai) .. c:function:: void uv_freeaddrinfo(struct addrinfo* ai)
Free the struct addrinfo. Passing NULL is allowed and is a no-op. Free the struct addrinfo. Passing NULL is allowed and is a no-op.
@ -80,4 +90,7 @@ API
callback will get called sometime in the future with the lookup result. callback will get called sometime in the future with the lookup result.
Consult `man -s 3 getnameinfo` for more details. Consult `man -s 3 getnameinfo` for more details.
.. versionchanged:: 1.3.0 the callback parameter is now allowed to be NULL,
in which case the request will run **synchronously**.
.. seealso:: The :c:type:`uv_req_t` API functions also apply. .. seealso:: The :c:type:`uv_req_t` API functions also apply.

View File

@ -326,7 +326,7 @@ typedef struct {
struct addrinfo* hints; \ struct addrinfo* hints; \
char* hostname; \ char* hostname; \
char* service; \ char* service; \
struct addrinfo* res; \ struct addrinfo* addrinfo; \
int retcode; int retcode;
#define UV_GETNAMEINFO_PRIVATE_FIELDS \ #define UV_GETNAMEINFO_PRIVATE_FIELDS \

View File

@ -565,8 +565,11 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s);
void* alloc; \ void* alloc; \
WCHAR* node; \ WCHAR* node; \
WCHAR* service; \ WCHAR* service; \
struct addrinfoW* hints; \ /* The addrinfoW field is used to store a pointer to the hints, and */ \
struct addrinfoW* res; \ /* later on to store the result of GetAddrInfoW. The final result will */ \
/* be converted to struct addrinfo* and stored in the addrinfo field. */ \
struct addrinfoW* addrinfow; \
struct addrinfo* addrinfo; \
int retcode; int retcode;
#define UV_GETNAMEINFO_PRIVATE_FIELDS \ #define UV_GETNAMEINFO_PRIVATE_FIELDS \

View File

@ -772,6 +772,7 @@ struct uv_getaddrinfo_s {
UV_REQ_FIELDS UV_REQ_FIELDS
/* read-only */ /* read-only */
uv_loop_t* loop; uv_loop_t* loop;
/* struct addrinfo* addrinfo is marked as private, but it really isn't. */
UV_GETADDRINFO_PRIVATE_FIELDS UV_GETADDRINFO_PRIVATE_FIELDS
}; };

View File

@ -99,21 +99,17 @@ static void uv__getaddrinfo_work(struct uv__work* w) {
int err; int err;
req = container_of(w, uv_getaddrinfo_t, work_req); req = container_of(w, uv_getaddrinfo_t, work_req);
err = getaddrinfo(req->hostname, req->service, req->hints, &req->res); err = getaddrinfo(req->hostname, req->service, req->hints, &req->addrinfo);
req->retcode = uv__getaddrinfo_translate_error(err); req->retcode = uv__getaddrinfo_translate_error(err);
} }
static void uv__getaddrinfo_done(struct uv__work* w, int status) { static void uv__getaddrinfo_done(struct uv__work* w, int status) {
uv_getaddrinfo_t* req; uv_getaddrinfo_t* req;
struct addrinfo *res;
req = container_of(w, uv_getaddrinfo_t, work_req); req = container_of(w, uv_getaddrinfo_t, work_req);
uv__req_unregister(req->loop, req); uv__req_unregister(req->loop, req);
res = req->res;
req->res = NULL;
/* See initialization in uv_getaddrinfo(). */ /* See initialization in uv_getaddrinfo(). */
if (req->hints) if (req->hints)
free(req->hints); free(req->hints);
@ -133,7 +129,8 @@ static void uv__getaddrinfo_done(struct uv__work* w, int status) {
req->retcode = UV_EAI_CANCELED; req->retcode = UV_EAI_CANCELED;
} }
req->cb(req, req->retcode, res); if (req->cb)
req->cb(req, req->retcode, req->addrinfo);
} }
@ -149,7 +146,7 @@ int uv_getaddrinfo(uv_loop_t* loop,
size_t len; size_t len;
char* buf; char* buf;
if (req == NULL || cb == NULL || (hostname == NULL && service == NULL)) if (req == NULL || (hostname == NULL && service == NULL))
return -EINVAL; return -EINVAL;
hostname_len = hostname ? strlen(hostname) + 1 : 0; hostname_len = hostname ? strlen(hostname) + 1 : 0;
@ -163,7 +160,7 @@ int uv_getaddrinfo(uv_loop_t* loop,
uv__req_init(loop, req, UV_GETADDRINFO); uv__req_init(loop, req, UV_GETADDRINFO);
req->loop = loop; req->loop = loop;
req->cb = cb; req->cb = cb;
req->res = NULL; req->addrinfo = NULL;
req->hints = NULL; req->hints = NULL;
req->service = NULL; req->service = NULL;
req->hostname = NULL; req->hostname = NULL;
@ -185,12 +182,17 @@ int uv_getaddrinfo(uv_loop_t* loop,
if (hostname) if (hostname)
req->hostname = memcpy(buf + len, hostname, hostname_len); req->hostname = memcpy(buf + len, hostname, hostname_len);
uv__work_submit(loop, if (cb) {
&req->work_req, uv__work_submit(loop,
uv__getaddrinfo_work, &req->work_req,
uv__getaddrinfo_done); uv__getaddrinfo_work,
uv__getaddrinfo_done);
return 0; return 0;
} else {
uv__getaddrinfo_work(&req->work_req);
uv__getaddrinfo_done(&req->work_req, 0);
return req->retcode;
}
} }

View File

@ -69,7 +69,8 @@ static void uv__getnameinfo_done(struct uv__work* w, int status) {
service = req->service; service = req->service;
} }
req->getnameinfo_cb(req, req->retcode, host, service); if (req->getnameinfo_cb)
req->getnameinfo_cb(req, req->retcode, host, service);
} }
/* /*
@ -82,7 +83,7 @@ int uv_getnameinfo(uv_loop_t* loop,
uv_getnameinfo_cb getnameinfo_cb, uv_getnameinfo_cb getnameinfo_cb,
const struct sockaddr* addr, const struct sockaddr* addr,
int flags) { int flags) {
if (req == NULL || getnameinfo_cb == NULL || addr == NULL) if (req == NULL || addr == NULL)
return UV_EINVAL; return UV_EINVAL;
if (addr->sa_family == AF_INET) { if (addr->sa_family == AF_INET) {
@ -105,10 +106,15 @@ int uv_getnameinfo(uv_loop_t* loop,
req->loop = loop; req->loop = loop;
req->retcode = 0; req->retcode = 0;
uv__work_submit(loop, if (getnameinfo_cb) {
&req->work_req, uv__work_submit(loop,
uv__getnameinfo_work, &req->work_req,
uv__getnameinfo_done); uv__getnameinfo_work,
uv__getnameinfo_done);
return 0; return 0;
} else {
uv__getnameinfo_work(&req->work_req);
uv__getnameinfo_done(&req->work_req, 0);
return req->retcode;
}
} }

View File

@ -77,10 +77,13 @@ int uv__getaddrinfo_translate_error(int sys_err) {
static void uv__getaddrinfo_work(struct uv__work* w) { static void uv__getaddrinfo_work(struct uv__work* w) {
uv_getaddrinfo_t* req; uv_getaddrinfo_t* req;
struct addrinfoW* hints;
int err; int err;
req = container_of(w, uv_getaddrinfo_t, work_req); req = container_of(w, uv_getaddrinfo_t, work_req);
err = GetAddrInfoW(req->node, req->service, req->hints, &req->res); hints = req->addrinfow;
req->addrinfow = NULL;
err = GetAddrInfoW(req->node, req->service, hints, &req->addrinfow);
req->retcode = uv__getaddrinfo_translate_error(err); req->retcode = uv__getaddrinfo_translate_error(err);
} }
@ -115,17 +118,13 @@ static void uv__getaddrinfo_done(struct uv__work* w, int status) {
if (status == UV_ECANCELED) { if (status == UV_ECANCELED) {
assert(req->retcode == 0); assert(req->retcode == 0);
req->retcode = UV_EAI_CANCELED; req->retcode = UV_EAI_CANCELED;
if (req->res != NULL) {
FreeAddrInfoW(req->res);
req->res = NULL;
}
goto complete; goto complete;
} }
if (req->retcode == 0) { if (req->retcode == 0) {
/* convert addrinfoW to addrinfo */ /* convert addrinfoW to addrinfo */
/* first calculate required length */ /* first calculate required length */
addrinfow_ptr = req->res; addrinfow_ptr = req->addrinfow;
while (addrinfow_ptr != NULL) { while (addrinfow_ptr != NULL) {
addrinfo_len += addrinfo_struct_len + addrinfo_len += addrinfo_struct_len +
ALIGNED_SIZE(addrinfow_ptr->ai_addrlen); ALIGNED_SIZE(addrinfow_ptr->ai_addrlen);
@ -146,7 +145,7 @@ static void uv__getaddrinfo_done(struct uv__work* w, int status) {
/* do conversions */ /* do conversions */
if (alloc_ptr != NULL) { if (alloc_ptr != NULL) {
cur_ptr = alloc_ptr; cur_ptr = alloc_ptr;
addrinfow_ptr = req->res; addrinfow_ptr = req->addrinfow;
while (addrinfow_ptr != NULL) { while (addrinfow_ptr != NULL) {
/* copy addrinfo struct data */ /* copy addrinfo struct data */
@ -196,22 +195,24 @@ static void uv__getaddrinfo_done(struct uv__work* w, int status) {
addrinfo_ptr->ai_next = (struct addrinfo*)cur_ptr; addrinfo_ptr->ai_next = (struct addrinfo*)cur_ptr;
} }
} }
req->addrinfo = (struct addrinfo*)alloc_ptr;
} else { } else {
req->retcode = UV_EAI_MEMORY; req->retcode = UV_EAI_MEMORY;
} }
} }
complete:
/* return memory to system */ /* return memory to system */
if (req->res != NULL) { if (req->addrinfow != NULL) {
FreeAddrInfoW(req->res); FreeAddrInfoW(req->addrinfow);
req->res = NULL; req->addrinfow = NULL;
} }
complete:
uv__req_unregister(req->loop, req); uv__req_unregister(req->loop, req);
/* finally do callback with converted result */ /* finally do callback with converted result */
req->getaddrinfo_cb(req, req->retcode, (struct addrinfo*)alloc_ptr); if (req->getaddrinfo_cb)
req->getaddrinfo_cb(req, req->retcode, req->addrinfo);
} }
@ -250,8 +251,7 @@ int uv_getaddrinfo(uv_loop_t* loop,
char* alloc_ptr = NULL; char* alloc_ptr = NULL;
int err; int err;
if (req == NULL || getaddrinfo_cb == NULL || if (req == NULL || (node == NULL && service == NULL)) {
(node == NULL && service == NULL)) {
err = WSAEINVAL; err = WSAEINVAL;
goto error; goto error;
} }
@ -259,7 +259,7 @@ int uv_getaddrinfo(uv_loop_t* loop,
uv_req_init(loop, (uv_req_t*)req); uv_req_init(loop, (uv_req_t*)req);
req->getaddrinfo_cb = getaddrinfo_cb; req->getaddrinfo_cb = getaddrinfo_cb;
req->res = NULL; req->addrinfo = NULL;
req->type = UV_GETADDRINFO; req->type = UV_GETADDRINFO;
req->loop = loop; req->loop = loop;
req->retcode = 0; req->retcode = 0;
@ -327,27 +327,32 @@ int uv_getaddrinfo(uv_loop_t* loop,
/* copy hints to allocated memory and save pointer in req */ /* copy hints to allocated memory and save pointer in req */
if (hints != NULL) { if (hints != NULL) {
req->hints = (struct addrinfoW*)alloc_ptr; req->addrinfow = (struct addrinfoW*)alloc_ptr;
req->hints->ai_family = hints->ai_family; req->addrinfow->ai_family = hints->ai_family;
req->hints->ai_socktype = hints->ai_socktype; req->addrinfow->ai_socktype = hints->ai_socktype;
req->hints->ai_protocol = hints->ai_protocol; req->addrinfow->ai_protocol = hints->ai_protocol;
req->hints->ai_flags = hints->ai_flags; req->addrinfow->ai_flags = hints->ai_flags;
req->hints->ai_addrlen = 0; req->addrinfow->ai_addrlen = 0;
req->hints->ai_canonname = NULL; req->addrinfow->ai_canonname = NULL;
req->hints->ai_addr = NULL; req->addrinfow->ai_addr = NULL;
req->hints->ai_next = NULL; req->addrinfow->ai_next = NULL;
} else { } else {
req->hints = NULL; req->addrinfow = NULL;
} }
uv__work_submit(loop,
&req->work_req,
uv__getaddrinfo_work,
uv__getaddrinfo_done);
uv__req_register(loop, req); uv__req_register(loop, req);
return 0; if (getaddrinfo_cb) {
uv__work_submit(loop,
&req->work_req,
uv__getaddrinfo_work,
uv__getaddrinfo_done);
return 0;
} else {
uv__getaddrinfo_work(&req->work_req);
uv__getaddrinfo_done(&req->work_req, 0);
return req->retcode;
}
error: error:
if (req != NULL && req->alloc != NULL) { if (req != NULL && req->alloc != NULL) {

View File

@ -98,7 +98,8 @@ static void uv__getnameinfo_done(struct uv__work* w, int status) {
service = req->service; service = req->service;
} }
req->getnameinfo_cb(req, req->retcode, host, service); if (req->getnameinfo_cb)
req->getnameinfo_cb(req, req->retcode, host, service);
} }
@ -112,7 +113,7 @@ int uv_getnameinfo(uv_loop_t* loop,
uv_getnameinfo_cb getnameinfo_cb, uv_getnameinfo_cb getnameinfo_cb,
const struct sockaddr* addr, const struct sockaddr* addr,
int flags) { int flags) {
if (req == NULL || getnameinfo_cb == NULL || addr == NULL) if (req == NULL || addr == NULL)
return UV_EINVAL; return UV_EINVAL;
if (addr->sa_family == AF_INET) { if (addr->sa_family == AF_INET) {
@ -136,10 +137,15 @@ int uv_getnameinfo(uv_loop_t* loop,
req->loop = loop; req->loop = loop;
req->retcode = 0; req->retcode = 0;
uv__work_submit(loop, if (getnameinfo_cb) {
&req->work_req, uv__work_submit(loop,
uv__getnameinfo_work, &req->work_req,
uv__getnameinfo_done); uv__getnameinfo_work,
uv__getnameinfo_done);
return 0; return 0;
} else {
uv__getnameinfo_work(&req->work_req);
uv__getnameinfo_done(&req->work_req, 0);
return req->retcode;
}
} }

View File

@ -97,6 +97,22 @@ TEST_IMPL(getaddrinfo_fail) {
} }
TEST_IMPL(getaddrinfo_fail_sync) {
uv_getaddrinfo_t req;
ASSERT(0 > uv_getaddrinfo(uv_default_loop(),
&req,
NULL,
"xyzzy.xyzzy.xyzzy",
NULL,
NULL));
uv_freeaddrinfo(req.addrinfo);
MAKE_VALGRIND_HAPPY();
return 0;
}
TEST_IMPL(getaddrinfo_basic) { TEST_IMPL(getaddrinfo_basic) {
int r; int r;
getaddrinfo_handle = (uv_getaddrinfo_t*)malloc(sizeof(uv_getaddrinfo_t)); getaddrinfo_handle = (uv_getaddrinfo_t*)malloc(sizeof(uv_getaddrinfo_t));
@ -118,6 +134,22 @@ TEST_IMPL(getaddrinfo_basic) {
} }
TEST_IMPL(getaddrinfo_basic_sync) {
uv_getaddrinfo_t req;
ASSERT(0 == uv_getaddrinfo(uv_default_loop(),
&req,
NULL,
name,
NULL,
NULL));
uv_freeaddrinfo(req.addrinfo);
MAKE_VALGRIND_HAPPY();
return 0;
}
TEST_IMPL(getaddrinfo_concurrent) { TEST_IMPL(getaddrinfo_concurrent) {
int i, r; int i, r;
int* data; int* data;

View File

@ -44,6 +44,7 @@ static void getnameinfo_req(uv_getnameinfo_t* handle,
ASSERT(service != NULL); ASSERT(service != NULL);
} }
TEST_IMPL(getnameinfo_basic_ip4) { TEST_IMPL(getnameinfo_basic_ip4) {
int r; int r;
@ -63,6 +64,23 @@ TEST_IMPL(getnameinfo_basic_ip4) {
return 0; return 0;
} }
TEST_IMPL(getnameinfo_basic_ip4_sync) {
ASSERT(0 == uv_ip4_addr(address_ip4, port, &addr4));
ASSERT(0 == uv_getnameinfo(uv_default_loop(),
&req,
NULL,
(const struct sockaddr*)&addr4,
0));
ASSERT(req.host != NULL);
ASSERT(req.service != NULL);
MAKE_VALGRIND_HAPPY();
return 0;
}
TEST_IMPL(getnameinfo_basic_ip6) { TEST_IMPL(getnameinfo_basic_ip6) {
int r; int r;

View File

@ -180,9 +180,12 @@ TEST_DECLARE (get_memory)
TEST_DECLARE (handle_fileno) TEST_DECLARE (handle_fileno)
TEST_DECLARE (hrtime) TEST_DECLARE (hrtime)
TEST_DECLARE (getaddrinfo_fail) TEST_DECLARE (getaddrinfo_fail)
TEST_DECLARE (getaddrinfo_fail_sync)
TEST_DECLARE (getaddrinfo_basic) TEST_DECLARE (getaddrinfo_basic)
TEST_DECLARE (getaddrinfo_basic_sync)
TEST_DECLARE (getaddrinfo_concurrent) TEST_DECLARE (getaddrinfo_concurrent)
TEST_DECLARE (getnameinfo_basic_ip4) TEST_DECLARE (getnameinfo_basic_ip4)
TEST_DECLARE (getnameinfo_basic_ip4_sync)
TEST_DECLARE (getnameinfo_basic_ip6) TEST_DECLARE (getnameinfo_basic_ip6)
TEST_DECLARE (getsockname_tcp) TEST_DECLARE (getsockname_tcp)
TEST_DECLARE (getsockname_udp) TEST_DECLARE (getsockname_udp)
@ -524,11 +527,14 @@ TASK_LIST_START
TEST_ENTRY (hrtime) TEST_ENTRY (hrtime)
TEST_ENTRY_CUSTOM (getaddrinfo_fail, 0, 0, 10000) TEST_ENTRY_CUSTOM (getaddrinfo_fail, 0, 0, 10000)
TEST_ENTRY (getaddrinfo_fail_sync)
TEST_ENTRY (getaddrinfo_basic) TEST_ENTRY (getaddrinfo_basic)
TEST_ENTRY (getaddrinfo_basic_sync)
TEST_ENTRY (getaddrinfo_concurrent) TEST_ENTRY (getaddrinfo_concurrent)
TEST_ENTRY (getnameinfo_basic_ip4) TEST_ENTRY (getnameinfo_basic_ip4)
TEST_ENTRY (getnameinfo_basic_ip4_sync)
TEST_ENTRY (getnameinfo_basic_ip6) TEST_ENTRY (getnameinfo_basic_ip6)
TEST_ENTRY (getsockname_tcp) TEST_ENTRY (getsockname_tcp)