diff --git a/docs/src/dns.rst b/docs/src/dns.rst index d7c889f7a..3b15377f9 100644 --- a/docs/src/dns.rst +++ b/docs/src/dns.rst @@ -39,6 +39,13 @@ Public members Loop that started this getaddrinfo request and where completion will be 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 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. + .. 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) 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. 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. diff --git a/include/uv-unix.h b/include/uv-unix.h index e72492564..82d193bdc 100644 --- a/include/uv-unix.h +++ b/include/uv-unix.h @@ -326,7 +326,7 @@ typedef struct { struct addrinfo* hints; \ char* hostname; \ char* service; \ - struct addrinfo* res; \ + struct addrinfo* addrinfo; \ int retcode; #define UV_GETNAMEINFO_PRIVATE_FIELDS \ diff --git a/include/uv-win.h b/include/uv-win.h index 4abb294c0..b744d624c 100644 --- a/include/uv-win.h +++ b/include/uv-win.h @@ -565,8 +565,11 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s); void* alloc; \ WCHAR* node; \ WCHAR* service; \ - struct addrinfoW* hints; \ - struct addrinfoW* res; \ + /* The addrinfoW field is used to store a pointer to the hints, and */ \ + /* 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; #define UV_GETNAMEINFO_PRIVATE_FIELDS \ diff --git a/include/uv.h b/include/uv.h index a2332504c..f1a952625 100644 --- a/include/uv.h +++ b/include/uv.h @@ -772,6 +772,7 @@ struct uv_getaddrinfo_s { UV_REQ_FIELDS /* read-only */ uv_loop_t* loop; + /* struct addrinfo* addrinfo is marked as private, but it really isn't. */ UV_GETADDRINFO_PRIVATE_FIELDS }; diff --git a/src/unix/getaddrinfo.c b/src/unix/getaddrinfo.c index faf9add92..0d684e24e 100644 --- a/src/unix/getaddrinfo.c +++ b/src/unix/getaddrinfo.c @@ -99,21 +99,17 @@ static void uv__getaddrinfo_work(struct uv__work* w) { int err; 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); } static void uv__getaddrinfo_done(struct uv__work* w, int status) { uv_getaddrinfo_t* req; - struct addrinfo *res; req = container_of(w, uv_getaddrinfo_t, work_req); uv__req_unregister(req->loop, req); - res = req->res; - req->res = NULL; - /* See initialization in uv_getaddrinfo(). */ if (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->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; char* buf; - if (req == NULL || cb == NULL || (hostname == NULL && service == NULL)) + if (req == NULL || (hostname == NULL && service == NULL)) return -EINVAL; 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); req->loop = loop; req->cb = cb; - req->res = NULL; + req->addrinfo = NULL; req->hints = NULL; req->service = NULL; req->hostname = NULL; @@ -185,12 +182,17 @@ int uv_getaddrinfo(uv_loop_t* loop, if (hostname) req->hostname = memcpy(buf + len, hostname, hostname_len); - uv__work_submit(loop, - &req->work_req, - uv__getaddrinfo_work, - uv__getaddrinfo_done); - - return 0; + if (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; + } } diff --git a/src/unix/getnameinfo.c b/src/unix/getnameinfo.c index c3fb9831c..daa798a45 100644 --- a/src/unix/getnameinfo.c +++ b/src/unix/getnameinfo.c @@ -69,7 +69,8 @@ static void uv__getnameinfo_done(struct uv__work* w, int status) { 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, const struct sockaddr* addr, int flags) { - if (req == NULL || getnameinfo_cb == NULL || addr == NULL) + if (req == NULL || addr == NULL) return UV_EINVAL; if (addr->sa_family == AF_INET) { @@ -105,10 +106,15 @@ int uv_getnameinfo(uv_loop_t* loop, req->loop = loop; req->retcode = 0; - uv__work_submit(loop, - &req->work_req, - uv__getnameinfo_work, - uv__getnameinfo_done); - - return 0; + if (getnameinfo_cb) { + uv__work_submit(loop, + &req->work_req, + uv__getnameinfo_work, + uv__getnameinfo_done); + return 0; + } else { + uv__getnameinfo_work(&req->work_req); + uv__getnameinfo_done(&req->work_req, 0); + return req->retcode; + } } diff --git a/src/win/getaddrinfo.c b/src/win/getaddrinfo.c index 53a6084ef..3245c6f58 100644 --- a/src/win/getaddrinfo.c +++ b/src/win/getaddrinfo.c @@ -77,10 +77,13 @@ int uv__getaddrinfo_translate_error(int sys_err) { static void uv__getaddrinfo_work(struct uv__work* w) { uv_getaddrinfo_t* req; + struct addrinfoW* hints; int err; 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); } @@ -115,17 +118,13 @@ static void uv__getaddrinfo_done(struct uv__work* w, int status) { if (status == UV_ECANCELED) { assert(req->retcode == 0); req->retcode = UV_EAI_CANCELED; - if (req->res != NULL) { - FreeAddrInfoW(req->res); - req->res = NULL; - } goto complete; } if (req->retcode == 0) { /* convert addrinfoW to addrinfo */ /* first calculate required length */ - addrinfow_ptr = req->res; + addrinfow_ptr = req->addrinfow; while (addrinfow_ptr != NULL) { addrinfo_len += addrinfo_struct_len + ALIGNED_SIZE(addrinfow_ptr->ai_addrlen); @@ -146,7 +145,7 @@ static void uv__getaddrinfo_done(struct uv__work* w, int status) { /* do conversions */ if (alloc_ptr != NULL) { cur_ptr = alloc_ptr; - addrinfow_ptr = req->res; + addrinfow_ptr = req->addrinfow; while (addrinfow_ptr != NULL) { /* 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; } } + req->addrinfo = (struct addrinfo*)alloc_ptr; } else { req->retcode = UV_EAI_MEMORY; } } +complete: /* return memory to system */ - if (req->res != NULL) { - FreeAddrInfoW(req->res); - req->res = NULL; + if (req->addrinfow != NULL) { + FreeAddrInfoW(req->addrinfow); + req->addrinfow = NULL; } -complete: uv__req_unregister(req->loop, req); /* 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; int err; - if (req == NULL || getaddrinfo_cb == NULL || - (node == NULL && service == NULL)) { + if (req == NULL || (node == NULL && service == NULL)) { err = WSAEINVAL; goto error; } @@ -259,7 +259,7 @@ int uv_getaddrinfo(uv_loop_t* loop, uv_req_init(loop, (uv_req_t*)req); req->getaddrinfo_cb = getaddrinfo_cb; - req->res = NULL; + req->addrinfo = NULL; req->type = UV_GETADDRINFO; req->loop = loop; req->retcode = 0; @@ -327,27 +327,32 @@ int uv_getaddrinfo(uv_loop_t* loop, /* copy hints to allocated memory and save pointer in req */ if (hints != NULL) { - req->hints = (struct addrinfoW*)alloc_ptr; - req->hints->ai_family = hints->ai_family; - req->hints->ai_socktype = hints->ai_socktype; - req->hints->ai_protocol = hints->ai_protocol; - req->hints->ai_flags = hints->ai_flags; - req->hints->ai_addrlen = 0; - req->hints->ai_canonname = NULL; - req->hints->ai_addr = NULL; - req->hints->ai_next = NULL; + req->addrinfow = (struct addrinfoW*)alloc_ptr; + req->addrinfow->ai_family = hints->ai_family; + req->addrinfow->ai_socktype = hints->ai_socktype; + req->addrinfow->ai_protocol = hints->ai_protocol; + req->addrinfow->ai_flags = hints->ai_flags; + req->addrinfow->ai_addrlen = 0; + req->addrinfow->ai_canonname = NULL; + req->addrinfow->ai_addr = NULL; + req->addrinfow->ai_next = NULL; } 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); - 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: if (req != NULL && req->alloc != NULL) { diff --git a/src/win/getnameinfo.c b/src/win/getnameinfo.c index 52cc79088..b1d045c79 100644 --- a/src/win/getnameinfo.c +++ b/src/win/getnameinfo.c @@ -98,7 +98,8 @@ static void uv__getnameinfo_done(struct uv__work* w, int status) { 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, const struct sockaddr* addr, int flags) { - if (req == NULL || getnameinfo_cb == NULL || addr == NULL) + if (req == NULL || addr == NULL) return UV_EINVAL; if (addr->sa_family == AF_INET) { @@ -136,10 +137,15 @@ int uv_getnameinfo(uv_loop_t* loop, req->loop = loop; req->retcode = 0; - uv__work_submit(loop, - &req->work_req, - uv__getnameinfo_work, - uv__getnameinfo_done); - - return 0; + if (getnameinfo_cb) { + uv__work_submit(loop, + &req->work_req, + uv__getnameinfo_work, + uv__getnameinfo_done); + return 0; + } else { + uv__getnameinfo_work(&req->work_req); + uv__getnameinfo_done(&req->work_req, 0); + return req->retcode; + } } diff --git a/test/test-getaddrinfo.c b/test/test-getaddrinfo.c index 32ca91eff..45813c313 100644 --- a/test/test-getaddrinfo.c +++ b/test/test-getaddrinfo.c @@ -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) { int r; 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) { int i, r; int* data; diff --git a/test/test-getnameinfo.c b/test/test-getnameinfo.c index 1ea0f3a43..ebe924669 100644 --- a/test/test-getnameinfo.c +++ b/test/test-getnameinfo.c @@ -44,6 +44,7 @@ static void getnameinfo_req(uv_getnameinfo_t* handle, ASSERT(service != NULL); } + TEST_IMPL(getnameinfo_basic_ip4) { int r; @@ -63,6 +64,23 @@ TEST_IMPL(getnameinfo_basic_ip4) { 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) { int r; diff --git a/test/test-list.h b/test/test-list.h index eb78a43cc..d00d0f262 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -180,9 +180,12 @@ TEST_DECLARE (get_memory) TEST_DECLARE (handle_fileno) TEST_DECLARE (hrtime) TEST_DECLARE (getaddrinfo_fail) +TEST_DECLARE (getaddrinfo_fail_sync) TEST_DECLARE (getaddrinfo_basic) +TEST_DECLARE (getaddrinfo_basic_sync) TEST_DECLARE (getaddrinfo_concurrent) TEST_DECLARE (getnameinfo_basic_ip4) +TEST_DECLARE (getnameinfo_basic_ip4_sync) TEST_DECLARE (getnameinfo_basic_ip6) TEST_DECLARE (getsockname_tcp) TEST_DECLARE (getsockname_udp) @@ -524,11 +527,14 @@ TASK_LIST_START TEST_ENTRY (hrtime) TEST_ENTRY_CUSTOM (getaddrinfo_fail, 0, 0, 10000) + TEST_ENTRY (getaddrinfo_fail_sync) TEST_ENTRY (getaddrinfo_basic) + TEST_ENTRY (getaddrinfo_basic_sync) TEST_ENTRY (getaddrinfo_concurrent) TEST_ENTRY (getnameinfo_basic_ip4) + TEST_ENTRY (getnameinfo_basic_ip4_sync) TEST_ENTRY (getnameinfo_basic_ip6) TEST_ENTRY (getsockname_tcp)