win: map 0.0.0.0 and :: addresses to localhost
On Linux when connecting IP addresses 0.0.0.0 and :: are automatically converted to localhost. This adds same functionality to Windows. PR-URL: https://github.com/libuv/libuv/pull/1515 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
This commit is contained in:
parent
cde132631b
commit
2b32e77bb6
@ -159,6 +159,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \
|
||||
test/test-close-fd.c \
|
||||
test/test-close-order.c \
|
||||
test/test-condvar.c \
|
||||
test/test-connect-unspecified.c \
|
||||
test/test-connection-fail.c \
|
||||
test/test-cwd-and-chdir.c \
|
||||
test/test-default-loop-close.c \
|
||||
|
||||
@ -102,7 +102,14 @@ API
|
||||
and an uninitialized :c:type:`uv_connect_t`. `addr` should point to an
|
||||
initialized ``struct sockaddr_in`` or ``struct sockaddr_in6``.
|
||||
|
||||
On Windows if the `addr` is initialized to point to an unspecified address
|
||||
(``0.0.0.0`` or ``::``) it will be changed to point to ``localhost``.
|
||||
This is done to match the behavior of Linux systems.
|
||||
|
||||
The callback is made when the connection has been established or when a
|
||||
connection error happened.
|
||||
|
||||
.. versionchanged:: 1.19.0 added ``0.0.0.0`` and ``::`` to ``localhost``
|
||||
mapping
|
||||
|
||||
.. seealso:: The :c:type:`uv_stream_t` API functions also apply.
|
||||
|
||||
@ -243,6 +243,10 @@ API
|
||||
with :c:func:`uv_udp_bind` it will be bound to 0.0.0.0
|
||||
(the "all interfaces" IPv4 address) and a random port number.
|
||||
|
||||
On Windows if the `addr` is initialized to point to an unspecified address
|
||||
(``0.0.0.0`` or ``::``) it will be changed to point to ``localhost``.
|
||||
This is done to match the behavior of Linux systems.
|
||||
|
||||
:param req: UDP request handle. Need not be initialized.
|
||||
|
||||
:param handle: UDP handle. Should have been initialized with
|
||||
@ -259,6 +263,9 @@ API
|
||||
|
||||
:returns: 0 on success, or an error code < 0 on failure.
|
||||
|
||||
.. versionchanged:: 1.19.0 added ``0.0.0.0`` and ``::`` to ``localhost``
|
||||
mapping
|
||||
|
||||
.. c:function:: int uv_udp_try_send(uv_udp_t* handle, const uv_buf_t bufs[], unsigned int nbufs, const struct sockaddr* addr)
|
||||
|
||||
Same as :c:func:`uv_udp_send`, but won't queue a send request if it can't
|
||||
|
||||
@ -747,10 +747,15 @@ static int uv_tcp_try_connect(uv_connect_t* req,
|
||||
uv_connect_cb cb) {
|
||||
uv_loop_t* loop = handle->loop;
|
||||
const struct sockaddr* bind_addr;
|
||||
struct sockaddr_storage converted;
|
||||
BOOL success;
|
||||
DWORD bytes;
|
||||
int err;
|
||||
|
||||
err = uv__convert_to_localhost_if_unspecified(addr, &converted);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (handle->delayed_error) {
|
||||
return handle->delayed_error;
|
||||
}
|
||||
@ -782,12 +787,12 @@ static int uv_tcp_try_connect(uv_connect_t* req,
|
||||
memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped));
|
||||
|
||||
success = handle->tcp.conn.func_connectex(handle->socket,
|
||||
addr,
|
||||
addrlen,
|
||||
NULL,
|
||||
0,
|
||||
&bytes,
|
||||
&req->u.io.overlapped);
|
||||
(const struct sockaddr*) &converted,
|
||||
addrlen,
|
||||
NULL,
|
||||
0,
|
||||
&bytes,
|
||||
&req->u.io.overlapped);
|
||||
|
||||
if (UV_SUCCEEDED_WITHOUT_IOCP(success)) {
|
||||
/* Process the req without IOCP. */
|
||||
|
||||
@ -923,10 +923,15 @@ int uv__udp_try_send(uv_udp_t* handle,
|
||||
unsigned int addrlen) {
|
||||
DWORD bytes;
|
||||
const struct sockaddr* bind_addr;
|
||||
struct sockaddr_storage converted;
|
||||
int err;
|
||||
|
||||
assert(nbufs > 0);
|
||||
|
||||
err = uv__convert_to_localhost_if_unspecified(addr, &converted);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* Already sending a message.*/
|
||||
if (handle->send_queue_count != 0)
|
||||
return UV_EAGAIN;
|
||||
@ -948,7 +953,7 @@ int uv__udp_try_send(uv_udp_t* handle,
|
||||
nbufs,
|
||||
&bytes,
|
||||
0,
|
||||
addr,
|
||||
(const struct sockaddr*) &converted,
|
||||
addrlen,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
@ -559,3 +559,31 @@ int WSAAPI uv_msafd_poll(SOCKET socket, AFD_POLL_INFO* info_in,
|
||||
return SOCKET_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
int uv__convert_to_localhost_if_unspecified(const struct sockaddr* addr,
|
||||
struct sockaddr_storage* storage) {
|
||||
struct sockaddr_in* dest4;
|
||||
struct sockaddr_in6* dest6;
|
||||
|
||||
if (addr == NULL)
|
||||
return UV_EINVAL;
|
||||
|
||||
switch (addr->sa_family) {
|
||||
case AF_INET:
|
||||
dest4 = (struct sockaddr_in*) storage;
|
||||
memcpy(dest4, addr, sizeof(*dest4));
|
||||
if (dest4->sin_addr.s_addr == 0)
|
||||
dest4->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
||||
return 0;
|
||||
case AF_INET6:
|
||||
dest6 = (struct sockaddr_in6*) storage;
|
||||
memcpy(dest6, addr, sizeof(*dest6));
|
||||
if (memcmp(&dest6->sin6_addr,
|
||||
&uv_addr_ip6_any_.sin6_addr,
|
||||
sizeof(uv_addr_ip6_any_.sin6_addr)) == 0)
|
||||
dest6->sin6_addr = (struct in6_addr) IN6ADDR_LOOPBACK_INIT;
|
||||
return 0;
|
||||
default:
|
||||
return UV_EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
@ -187,4 +187,7 @@ typedef struct _IP_ADAPTER_UNICAST_ADDRESS_LH {
|
||||
|
||||
#endif
|
||||
|
||||
int uv__convert_to_localhost_if_unspecified(const struct sockaddr* addr,
|
||||
struct sockaddr_storage* storage);
|
||||
|
||||
#endif /* UV_WIN_WINSOCK_H_ */
|
||||
|
||||
61
test/test-connect-unspecified.c
Normal file
61
test/test-connect-unspecified.c
Normal file
@ -0,0 +1,61 @@
|
||||
/* Copyright libuv project 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"
|
||||
|
||||
static void connect_4(uv_connect_t* req, int status) {
|
||||
ASSERT(status != UV_EADDRNOTAVAIL);
|
||||
}
|
||||
|
||||
static void connect_6(uv_connect_t* req, int status) {
|
||||
ASSERT(status != UV_EADDRNOTAVAIL);
|
||||
}
|
||||
|
||||
TEST_IMPL(connect_unspecified) {
|
||||
uv_loop_t* loop;
|
||||
uv_tcp_t socket4;
|
||||
struct sockaddr_in addr4;
|
||||
uv_connect_t connect4;
|
||||
uv_tcp_t socket6;
|
||||
struct sockaddr_in6 addr6;
|
||||
uv_connect_t connect6;
|
||||
|
||||
loop = uv_default_loop();
|
||||
|
||||
ASSERT(uv_tcp_init(loop, &socket4) == 0);
|
||||
ASSERT(uv_ip4_addr("0.0.0.0", TEST_PORT, &addr4) == 0);
|
||||
ASSERT(uv_tcp_connect(&connect4,
|
||||
&socket4,
|
||||
(const struct sockaddr*) &addr4,
|
||||
connect_4) == 0);
|
||||
|
||||
ASSERT(uv_tcp_init(loop, &socket6) == 0);
|
||||
ASSERT(uv_ip6_addr("::", TEST_PORT, &addr6) == 0);
|
||||
ASSERT(uv_tcp_connect(&connect6,
|
||||
&socket6,
|
||||
(const struct sockaddr*) &addr6,
|
||||
connect_6) == 0);
|
||||
|
||||
ASSERT(uv_run(loop, UV_RUN_DEFAULT) == 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -55,6 +55,7 @@ TEST_DECLARE (tty_file)
|
||||
TEST_DECLARE (tty_pty)
|
||||
TEST_DECLARE (stdio_over_pipes)
|
||||
TEST_DECLARE (ip6_pton)
|
||||
TEST_DECLARE (connect_unspecified)
|
||||
TEST_DECLARE (ipc_listen_before_write)
|
||||
TEST_DECLARE (ipc_listen_after_write)
|
||||
#ifndef _WIN32
|
||||
@ -468,6 +469,7 @@ TASK_LIST_START
|
||||
TEST_ENTRY (tty_pty)
|
||||
TEST_ENTRY (stdio_over_pipes)
|
||||
TEST_ENTRY (ip6_pton)
|
||||
TEST_ENTRY (connect_unspecified)
|
||||
TEST_ENTRY (ipc_listen_before_write)
|
||||
TEST_ENTRY (ipc_listen_after_write)
|
||||
#ifndef _WIN32
|
||||
|
||||
Loading…
Reference in New Issue
Block a user