From 09499f580c9bdd5df767711f5cbc0f5ab8ca6a1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Jos=C3=A9=20Arboleda?= Date: Tue, 27 Jan 2026 16:13:29 -0500 Subject: [PATCH 1/4] unix: introduce `uv_socket_get_tos` and `uv_socket_set_tos` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Juan José Arboleda --- CMakeLists.txt | 1 + Makefile.am | 1 + include/uv.h | 3 + src/uv-common.c | 101 +++++++++++++ test/test-list.h | 12 ++ test/test-socket-tos.c | 325 +++++++++++++++++++++++++++++++++++++++++ 6 files changed, 443 insertions(+) create mode 100644 test/test-socket-tos.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 449dc8322..e5e27ae15 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -631,6 +631,7 @@ if(LIBUV_BUILD_TESTS) test/test-signal-pending-on-close.c test/test-signal.c test/test-socket-buffer-size.c + test/test-socket-tos.c test/test-spawn.c test/test-stdio-over-pipes.c test/test-strscpy.c diff --git a/Makefile.am b/Makefile.am index 797efc83e..a0012e212 100644 --- a/Makefile.am +++ b/Makefile.am @@ -256,6 +256,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \ test/test-signal-pending-on-close.c \ test/test-signal.c \ test/test-socket-buffer-size.c \ + test/test-socket-tos.c \ test/test-spawn.c \ test/test-stdio-over-pipes.c \ test/test-strscpy.c \ diff --git a/include/uv.h b/include/uv.h index 41d7acc93..010b52294 100644 --- a/include/uv.h +++ b/include/uv.h @@ -519,6 +519,9 @@ UV_EXTERN int uv_socketpair(int type, int flags0, int flags1); +UV_EXTERN int uv_socket_set_tos(const uv_handle_t* handle, int tos); +UV_EXTERN int uv_socket_get_tos(const uv_handle_t* handle, int* tos); + #define UV_STREAM_FIELDS \ /* number of bytes queued for writing */ \ size_t write_queue_size; \ diff --git a/src/uv-common.c b/src/uv-common.c index e5a763290..06807eea9 100644 --- a/src/uv-common.c +++ b/src/uv-common.c @@ -1062,3 +1062,104 @@ void uv_free_interface_addresses(uv_interface_address_t* addresses, uv__free(addresses); } #endif /* !__MVS__ */ + +int uv_socket_get_tos(const uv_handle_t* handle, int* tos) { + int addrlen; + int fd; + int level; + int option; + int r; + int tos_; + socklen_t optlen; + struct sockaddr_storage storage; + + addrlen = sizeof(storage); + tos_ = 0; + optlen = sizeof(tos_); + + switch (handle->type) { + case UV_TCP: + r = uv_tcp_getsockname((uv_tcp_t*)handle, (struct sockaddr*)&storage, &addrlen); + break; + case UV_UDP: + r = uv_udp_getsockname((uv_udp_t*)handle, (struct sockaddr*)&storage, &addrlen); + break; + default: + return UV_EINVAL; + } + + if (r) + return r; + + r = uv_fileno(handle, &fd); + if (r) + return r; + + switch (storage.ss_family) { + case AF_INET: + level = IPPROTO_IP; + option = IP_TOS; + break; + case AF_INET6: + level = IPPROTO_IPV6; + option = IPV6_TCLASS; + break; + default: + return UV_EAFNOSUPPORT; + } + + r = getsockopt(fd, level, option, &tos_, &optlen); + if (r) + return r; + + *tos = tos_; + + return 0; +} + +int uv_socket_set_tos(const uv_handle_t* handle, int tos) { + int fd; + int r; + struct sockaddr_storage storage; + int addrlen; + int level; + int option; + + addrlen = sizeof(storage); + + if (tos < 0 || tos > 255) + return UV_EINVAL; + + switch (handle->type) { + case UV_TCP: + r = uv_tcp_getsockname((uv_tcp_t*)handle, (struct sockaddr*)&storage, &addrlen); + break; + case UV_UDP: + r = uv_udp_getsockname((uv_udp_t*)handle, (struct sockaddr*)&storage, &addrlen); + break; + default: + return UV_EINVAL; + } + + if (r) + return r; + r = uv_fileno(handle, &fd); + if (r) + return r; + + switch (storage.ss_family) { + case AF_INET: + level = IPPROTO_IP; + option = IP_TOS; + break; + case AF_INET6: + level = IPPROTO_IPV6; + option = IPV6_TCLASS; + break; + default: + return UV_EAFNOSUPPORT; + } + + r = setsockopt(fd, level, option, &tos, sizeof(tos)); + return UV__ERR(r); +} diff --git a/test/test-list.h b/test/test-list.h index 794a2f811..fe3dbf2d0 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -190,6 +190,12 @@ TEST_DECLARE (udp_ipv6_only) TEST_DECLARE (udp_options) TEST_DECLARE (udp_options6) TEST_DECLARE (udp_no_autobind) +TEST_DECLARE (tcp_socket_set_get_tos) +TEST_DECLARE (tcp6_socket_set_get_tos) +TEST_DECLARE (udp_socket_set_get_tos) +TEST_DECLARE (udp6_socket_set_get_tos) +TEST_DECLARE (socket_tos_invalid_handle) +TEST_DECLARE (socket_tos_unbound_tcp) TEST_DECLARE (udp_open) TEST_DECLARE (udp_open_twice) TEST_DECLARE (udp_open_bound) @@ -818,6 +824,12 @@ TASK_LIST_START TEST_ENTRY (udp_options) TEST_ENTRY (udp_options6) TEST_ENTRY (udp_no_autobind) + TEST_ENTRY (tcp_socket_set_get_tos) + TEST_ENTRY (tcp6_socket_set_get_tos) + TEST_ENTRY (udp_socket_set_get_tos) + TEST_ENTRY (udp6_socket_set_get_tos) + TEST_ENTRY (socket_tos_invalid_handle) + TEST_ENTRY (socket_tos_unbound_tcp) TEST_ENTRY (udp_mmsg) TEST_ENTRY (udp_multicast_interface) TEST_ENTRY (udp_multicast_interface6) diff --git a/test/test-socket-tos.c b/test/test-socket-tos.c new file mode 100644 index 000000000..9e7ccf701 --- /dev/null +++ b/test/test-socket-tos.c @@ -0,0 +1,325 @@ +/* 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 + + +TEST_IMPL(tcp_socket_set_get_tos) { + uv_loop_t* loop; + uv_tcp_t tcp; + struct sockaddr_in addr; + int r; + int tos_in; + int tos_out; + + loop = uv_default_loop(); + + r = uv_tcp_init(loop, &tcp); + ASSERT_OK(r); + + r = uv_ip4_addr("0.0.0.0", TEST_PORT, &addr); + ASSERT_OK(r); + + r = uv_tcp_bind(&tcp, (const struct sockaddr*) &addr, 0); + ASSERT_OK(r); + + /* Test valid TOS values */ + tos_in = 0; + r = uv_socket_set_tos((uv_handle_t*) &tcp, tos_in); + ASSERT_OK(r); + + r = uv_socket_get_tos((uv_handle_t*) &tcp, &tos_out); + ASSERT_OK(r); + ASSERT_EQ(tos_out, tos_in); + + tos_in = 128; + r = uv_socket_set_tos((uv_handle_t*) &tcp, tos_in); + ASSERT_OK(r); + + r = uv_socket_get_tos((uv_handle_t*) &tcp, &tos_out); + ASSERT_OK(r); + ASSERT_EQ(tos_out, tos_in); + + tos_in = 255; + r = uv_socket_set_tos((uv_handle_t*) &tcp, tos_in); + ASSERT_OK(r); + + r = uv_socket_get_tos((uv_handle_t*) &tcp, &tos_out); + ASSERT_OK(r); + ASSERT_EQ(tos_out, tos_in); + + /* Test invalid TOS values */ + r = uv_socket_set_tos((uv_handle_t*) &tcp, -1); + ASSERT_EQ(r, UV_EINVAL); + + r = uv_socket_set_tos((uv_handle_t*) &tcp, 256); + ASSERT_EQ(r, UV_EINVAL); + + r = uv_socket_set_tos((uv_handle_t*) &tcp, 1000); + ASSERT_EQ(r, UV_EINVAL); + + uv_close((uv_handle_t*) &tcp, NULL); + r = uv_run(loop, UV_RUN_DEFAULT); + ASSERT_OK(r); + + MAKE_VALGRIND_HAPPY(loop); + return 0; +} + + +TEST_IMPL(tcp6_socket_set_get_tos) { + uv_loop_t* loop; + uv_tcp_t tcp; + struct sockaddr_in6 addr; + int r; + int tos_in; + int tos_out; + + loop = uv_default_loop(); + + r = uv_tcp_init(loop, &tcp); + ASSERT_OK(r); + + r = uv_ip6_addr("::1", TEST_PORT, &addr); + ASSERT_OK(r); + + r = uv_tcp_bind(&tcp, (const struct sockaddr*) &addr, 0); + ASSERT_OK(r); + + /* Test valid TOS values */ + tos_in = 0; + r = uv_socket_set_tos((uv_handle_t*) &tcp, tos_in); + ASSERT_OK(r); + + r = uv_socket_get_tos((uv_handle_t*) &tcp, &tos_out); + ASSERT_OK(r); + ASSERT_EQ(tos_out, tos_in); + + tos_in = 64; + r = uv_socket_set_tos((uv_handle_t*) &tcp, tos_in); + ASSERT_OK(r); + + r = uv_socket_get_tos((uv_handle_t*) &tcp, &tos_out); + ASSERT_OK(r); + ASSERT_EQ(tos_out, tos_in); + + tos_in = 255; + r = uv_socket_set_tos((uv_handle_t*) &tcp, tos_in); + ASSERT_OK(r); + + r = uv_socket_get_tos((uv_handle_t*) &tcp, &tos_out); + ASSERT_OK(r); + ASSERT_EQ(tos_out, tos_in); + + uv_close((uv_handle_t*) &tcp, NULL); + r = uv_run(loop, UV_RUN_DEFAULT); + ASSERT_OK(r); + + MAKE_VALGRIND_HAPPY(loop); + return 0; +} + + +TEST_IMPL(udp_socket_set_get_tos) { + uv_loop_t* loop; + uv_udp_t udp; + struct sockaddr_in addr; + int r; + int tos_in; + int tos_out; + + loop = uv_default_loop(); + + r = uv_udp_init(loop, &udp); + ASSERT_OK(r); + + r = uv_ip4_addr("0.0.0.0", TEST_PORT, &addr); + ASSERT_OK(r); + + r = uv_udp_bind(&udp, (const struct sockaddr*) &addr, 0); + ASSERT_OK(r); + + /* Test valid TOS values */ + tos_in = 0; + r = uv_socket_set_tos((uv_handle_t*) &udp, tos_in); + ASSERT_OK(r); + + r = uv_socket_get_tos((uv_handle_t*) &udp, &tos_out); + ASSERT_OK(r); + ASSERT_EQ(tos_out, tos_in); + + tos_in = 32; + r = uv_socket_set_tos((uv_handle_t*) &udp, tos_in); + ASSERT_OK(r); + + r = uv_socket_get_tos((uv_handle_t*) &udp, &tos_out); + ASSERT_OK(r); + ASSERT_EQ(tos_out, tos_in); + + tos_in = 255; + r = uv_socket_set_tos((uv_handle_t*) &udp, tos_in); + ASSERT_OK(r); + + r = uv_socket_get_tos((uv_handle_t*) &udp, &tos_out); + ASSERT_OK(r); + ASSERT_EQ(tos_out, tos_in); + + /* Test invalid TOS values */ + r = uv_socket_set_tos((uv_handle_t*) &udp, -1); + ASSERT_EQ(r, UV_EINVAL); + + r = uv_socket_set_tos((uv_handle_t*) &udp, 256); + ASSERT_EQ(r, UV_EINVAL); + + uv_close((uv_handle_t*) &udp, NULL); + r = uv_run(loop, UV_RUN_DEFAULT); + ASSERT_OK(r); + + MAKE_VALGRIND_HAPPY(loop); + return 0; +} + + +TEST_IMPL(udp6_socket_set_get_tos) { + uv_loop_t* loop; + uv_udp_t udp; + struct sockaddr_in6 addr; + int r; + int tos_in; + int tos_out; + + loop = uv_default_loop(); + + r = uv_udp_init(loop, &udp); + ASSERT_OK(r); + + r = uv_ip6_addr("::1", TEST_PORT, &addr); + ASSERT_OK(r); + + r = uv_udp_bind(&udp, (const struct sockaddr*) &addr, 0); + ASSERT_OK(r); + + /* Test valid TOS values */ + tos_in = 0; + r = uv_socket_set_tos((uv_handle_t*) &udp, tos_in); + ASSERT_OK(r); + + r = uv_socket_get_tos((uv_handle_t*) &udp, &tos_out); + ASSERT_OK(r); + ASSERT_EQ(tos_out, tos_in); + + tos_in = 96; + r = uv_socket_set_tos((uv_handle_t*) &udp, tos_in); + ASSERT_OK(r); + + r = uv_socket_get_tos((uv_handle_t*) &udp, &tos_out); + ASSERT_OK(r); + ASSERT_EQ(tos_out, tos_in); + + tos_in = 255; + r = uv_socket_set_tos((uv_handle_t*) &udp, tos_in); + ASSERT_OK(r); + + r = uv_socket_get_tos((uv_handle_t*) &udp, &tos_out); + ASSERT_OK(r); + ASSERT_EQ(tos_out, tos_in); + + uv_close((uv_handle_t*) &udp, NULL); + r = uv_run(loop, UV_RUN_DEFAULT); + ASSERT_OK(r); + + MAKE_VALGRIND_HAPPY(loop); + return 0; +} + + +TEST_IMPL(socket_tos_invalid_handle) { + uv_loop_t* loop; + uv_timer_t timer; + uv_pipe_t pipe; + int r; + int tos; + + loop = uv_default_loop(); + + /* Test with invalid handle types */ + r = uv_timer_init(loop, &timer); + ASSERT_OK(r); + + r = uv_socket_set_tos((uv_handle_t*) &timer, 64); + ASSERT_EQ(r, UV_EINVAL); + + r = uv_socket_get_tos((uv_handle_t*) &timer, &tos); + ASSERT_EQ(r, UV_EINVAL); + + uv_close((uv_handle_t*) &timer, NULL); + + /* Test with pipe handle */ + r = uv_pipe_init(loop, &pipe, 0); + ASSERT_OK(r); + + r = uv_socket_set_tos((uv_handle_t*) &pipe, 64); + ASSERT_EQ(r, UV_EINVAL); + + r = uv_socket_get_tos((uv_handle_t*) &pipe, &tos); + ASSERT_EQ(r, UV_EINVAL); + + uv_close((uv_handle_t*) &pipe, NULL); + + r = uv_run(loop, UV_RUN_DEFAULT); + ASSERT_OK(r); + + MAKE_VALGRIND_HAPPY(loop); + return 0; +} + + +TEST_IMPL(socket_tos_unbound_tcp) { + uv_loop_t* loop; + uv_tcp_t tcp; + int r; + int tos; + + loop = uv_default_loop(); + + /* Test with unbound TCP socket - should fail since no address family */ + r = uv_tcp_init(loop, &tcp); + ASSERT_OK(r); + + /* Getting/setting TOS on unbound socket should fail */ + r = uv_socket_set_tos((uv_handle_t*) &tcp, 64); + ASSERT_NE(r, 0); + + r = uv_socket_get_tos((uv_handle_t*) &tcp, &tos); + ASSERT_NE(r, 0); + + uv_close((uv_handle_t*) &tcp, NULL); + r = uv_run(loop, UV_RUN_DEFAULT); + ASSERT_OK(r); + + MAKE_VALGRIND_HAPPY(loop); + return 0; +} From 40a308e2b8c4be6fad624b18c9d7b4e5e0973585 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Jos=C3=A9=20Arboleda?= Date: Tue, 27 Jan 2026 20:17:59 -0500 Subject: [PATCH 2/4] FIXUP MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Juan José Arboleda --- src/uv-common.c | 15 +- test/test-socket-tos.c | 336 +++++++++++++---------------------------- 2 files changed, 117 insertions(+), 234 deletions(-) diff --git a/src/uv-common.c b/src/uv-common.c index 06807eea9..628dd1987 100644 --- a/src/uv-common.c +++ b/src/uv-common.c @@ -1074,20 +1074,24 @@ int uv_socket_get_tos(const uv_handle_t* handle, int* tos) { struct sockaddr_storage storage; addrlen = sizeof(storage); - tos_ = 0; + tos_ = 0; optlen = sizeof(tos_); switch (handle->type) { case UV_TCP: - r = uv_tcp_getsockname((uv_tcp_t*)handle, (struct sockaddr*)&storage, &addrlen); + r = uv_tcp_getsockname((uv_tcp_t*)handle, + (struct sockaddr*)&storage, + &addrlen); break; case UV_UDP: - r = uv_udp_getsockname((uv_udp_t*)handle, (struct sockaddr*)&storage, &addrlen); + r = uv_udp_getsockname((uv_udp_t*)handle, + (struct sockaddr*)&storage, + &addrlen); break; default: return UV_EINVAL; } - + if (r) return r; @@ -1107,7 +1111,7 @@ int uv_socket_get_tos(const uv_handle_t* handle, int* tos) { default: return UV_EAFNOSUPPORT; } - + r = getsockopt(fd, level, option, &tos_, &optlen); if (r) return r; @@ -1143,6 +1147,7 @@ int uv_socket_set_tos(const uv_handle_t* handle, int tos) { if (r) return r; + r = uv_fileno(handle, &fd); if (r) return r; diff --git a/test/test-socket-tos.c b/test/test-socket-tos.c index 9e7ccf701..ba31d59b3 100644 --- a/test/test-socket-tos.c +++ b/test/test-socket-tos.c @@ -19,307 +19,185 @@ * IN THE SOFTWARE. */ -#include "uv.h" #include "task.h" +#include "uv.h" -#include -#include -#include +static void setup_tcp(uv_loop_t* loop, uv_tcp_t* tcp, const char* ip, + int is_ip6) { + struct sockaddr_in addr4; + struct sockaddr_in6 addr6; + int r; + r = uv_tcp_init(loop, tcp); + ASSERT_OK(r); + + if (is_ip6) { + r = uv_ip6_addr(ip, TEST_PORT, &addr6); + ASSERT_OK(r); + r = uv_tcp_bind(tcp, (const struct sockaddr*)&addr6, 0); + } else { + r = uv_ip4_addr(ip, TEST_PORT, &addr4); + ASSERT_OK(r); + r = uv_tcp_bind(tcp, (const struct sockaddr*)&addr4, 0); + } + ASSERT_OK(r); +} + +static void setup_udp(uv_loop_t* loop, uv_udp_t* udp, const char* ip, + int is_ip6) { + struct sockaddr_in addr4; + struct sockaddr_in6 addr6; + int r; + + r = uv_udp_init(loop, udp); + ASSERT_OK(r); + + if (is_ip6) { + r = uv_ip6_addr(ip, TEST_PORT, &addr6); + ASSERT_OK(r); + r = uv_udp_bind(udp, (const struct sockaddr*)&addr6, 0); + } else { + r = uv_ip4_addr(ip, TEST_PORT, &addr4); + ASSERT_OK(r); + r = uv_udp_bind(udp, (const struct sockaddr*)&addr4, 0); + } + ASSERT_OK(r); +} + +static void check_tos(uv_handle_t* handle, int tos) { + int r; + int tos_out; + + r = uv_socket_set_tos(handle, tos); + ASSERT_OK(r); + + r = uv_socket_get_tos(handle, &tos_out); + ASSERT_OK(r); + /* Linux masks the TOS value. Sometimes (?) */ +#if defined(__linux__) + ASSERT((tos_out == tos) || tos_out == (tos & 0xFC)); +#else + ASSERT_EQ(tos_out, tos); +#endif +} + +static void check_tos_fail(uv_handle_t* handle, int tos) { + ASSERT_EQ(uv_socket_set_tos(handle, tos), UV_EINVAL); +} TEST_IMPL(tcp_socket_set_get_tos) { - uv_loop_t* loop; uv_tcp_t tcp; - struct sockaddr_in addr; - int r; - int tos_in; - int tos_out; - loop = uv_default_loop(); + setup_tcp(uv_default_loop(), &tcp, "0.0.0.0", 0); - r = uv_tcp_init(loop, &tcp); - ASSERT_OK(r); + check_tos((uv_handle_t*)&tcp, 0); + check_tos((uv_handle_t*)&tcp, 128); + check_tos((uv_handle_t*)&tcp, 255); - r = uv_ip4_addr("0.0.0.0", TEST_PORT, &addr); - ASSERT_OK(r); + check_tos_fail((uv_handle_t*)&tcp, -1); + check_tos_fail((uv_handle_t*)&tcp, 256); + check_tos_fail((uv_handle_t*)&tcp, 1000); - r = uv_tcp_bind(&tcp, (const struct sockaddr*) &addr, 0); - ASSERT_OK(r); + uv_close((uv_handle_t*)&tcp, NULL); + ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT)); - /* Test valid TOS values */ - tos_in = 0; - r = uv_socket_set_tos((uv_handle_t*) &tcp, tos_in); - ASSERT_OK(r); - - r = uv_socket_get_tos((uv_handle_t*) &tcp, &tos_out); - ASSERT_OK(r); - ASSERT_EQ(tos_out, tos_in); - - tos_in = 128; - r = uv_socket_set_tos((uv_handle_t*) &tcp, tos_in); - ASSERT_OK(r); - - r = uv_socket_get_tos((uv_handle_t*) &tcp, &tos_out); - ASSERT_OK(r); - ASSERT_EQ(tos_out, tos_in); - - tos_in = 255; - r = uv_socket_set_tos((uv_handle_t*) &tcp, tos_in); - ASSERT_OK(r); - - r = uv_socket_get_tos((uv_handle_t*) &tcp, &tos_out); - ASSERT_OK(r); - ASSERT_EQ(tos_out, tos_in); - - /* Test invalid TOS values */ - r = uv_socket_set_tos((uv_handle_t*) &tcp, -1); - ASSERT_EQ(r, UV_EINVAL); - - r = uv_socket_set_tos((uv_handle_t*) &tcp, 256); - ASSERT_EQ(r, UV_EINVAL); - - r = uv_socket_set_tos((uv_handle_t*) &tcp, 1000); - ASSERT_EQ(r, UV_EINVAL); - - uv_close((uv_handle_t*) &tcp, NULL); - r = uv_run(loop, UV_RUN_DEFAULT); - ASSERT_OK(r); - - MAKE_VALGRIND_HAPPY(loop); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } - TEST_IMPL(tcp6_socket_set_get_tos) { - uv_loop_t* loop; uv_tcp_t tcp; - struct sockaddr_in6 addr; - int r; - int tos_in; - int tos_out; - loop = uv_default_loop(); + setup_tcp(uv_default_loop(), &tcp, "::1", 1); - r = uv_tcp_init(loop, &tcp); - ASSERT_OK(r); + check_tos((uv_handle_t*)&tcp, 0); + check_tos((uv_handle_t*)&tcp, 64); + check_tos((uv_handle_t*)&tcp, 255); - r = uv_ip6_addr("::1", TEST_PORT, &addr); - ASSERT_OK(r); + uv_close((uv_handle_t *)&tcp, NULL); + ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT)); - r = uv_tcp_bind(&tcp, (const struct sockaddr*) &addr, 0); - ASSERT_OK(r); - - /* Test valid TOS values */ - tos_in = 0; - r = uv_socket_set_tos((uv_handle_t*) &tcp, tos_in); - ASSERT_OK(r); - - r = uv_socket_get_tos((uv_handle_t*) &tcp, &tos_out); - ASSERT_OK(r); - ASSERT_EQ(tos_out, tos_in); - - tos_in = 64; - r = uv_socket_set_tos((uv_handle_t*) &tcp, tos_in); - ASSERT_OK(r); - - r = uv_socket_get_tos((uv_handle_t*) &tcp, &tos_out); - ASSERT_OK(r); - ASSERT_EQ(tos_out, tos_in); - - tos_in = 255; - r = uv_socket_set_tos((uv_handle_t*) &tcp, tos_in); - ASSERT_OK(r); - - r = uv_socket_get_tos((uv_handle_t*) &tcp, &tos_out); - ASSERT_OK(r); - ASSERT_EQ(tos_out, tos_in); - - uv_close((uv_handle_t*) &tcp, NULL); - r = uv_run(loop, UV_RUN_DEFAULT); - ASSERT_OK(r); - - MAKE_VALGRIND_HAPPY(loop); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } - TEST_IMPL(udp_socket_set_get_tos) { - uv_loop_t* loop; uv_udp_t udp; - struct sockaddr_in addr; - int r; - int tos_in; - int tos_out; - loop = uv_default_loop(); + setup_udp(uv_default_loop(), &udp, "0.0.0.0", 0); - r = uv_udp_init(loop, &udp); - ASSERT_OK(r); + check_tos((uv_handle_t*)&udp, 0); + check_tos((uv_handle_t*)&udp, 32); + check_tos((uv_handle_t*)&udp, 255); - r = uv_ip4_addr("0.0.0.0", TEST_PORT, &addr); - ASSERT_OK(r); + check_tos_fail((uv_handle_t *)&udp, -1); + check_tos_fail((uv_handle_t *)&udp, 256); - r = uv_udp_bind(&udp, (const struct sockaddr*) &addr, 0); - ASSERT_OK(r); + uv_close((uv_handle_t *)&udp, NULL); + ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT)); - /* Test valid TOS values */ - tos_in = 0; - r = uv_socket_set_tos((uv_handle_t*) &udp, tos_in); - ASSERT_OK(r); - - r = uv_socket_get_tos((uv_handle_t*) &udp, &tos_out); - ASSERT_OK(r); - ASSERT_EQ(tos_out, tos_in); - - tos_in = 32; - r = uv_socket_set_tos((uv_handle_t*) &udp, tos_in); - ASSERT_OK(r); - - r = uv_socket_get_tos((uv_handle_t*) &udp, &tos_out); - ASSERT_OK(r); - ASSERT_EQ(tos_out, tos_in); - - tos_in = 255; - r = uv_socket_set_tos((uv_handle_t*) &udp, tos_in); - ASSERT_OK(r); - - r = uv_socket_get_tos((uv_handle_t*) &udp, &tos_out); - ASSERT_OK(r); - ASSERT_EQ(tos_out, tos_in); - - /* Test invalid TOS values */ - r = uv_socket_set_tos((uv_handle_t*) &udp, -1); - ASSERT_EQ(r, UV_EINVAL); - - r = uv_socket_set_tos((uv_handle_t*) &udp, 256); - ASSERT_EQ(r, UV_EINVAL); - - uv_close((uv_handle_t*) &udp, NULL); - r = uv_run(loop, UV_RUN_DEFAULT); - ASSERT_OK(r); - - MAKE_VALGRIND_HAPPY(loop); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } - TEST_IMPL(udp6_socket_set_get_tos) { - uv_loop_t* loop; uv_udp_t udp; - struct sockaddr_in6 addr; - int r; - int tos_in; - int tos_out; - loop = uv_default_loop(); + setup_udp(uv_default_loop(), &udp, "::1", 1); - r = uv_udp_init(loop, &udp); - ASSERT_OK(r); + check_tos((uv_handle_t*)&udp, 0); + check_tos((uv_handle_t*)&udp, 96); + check_tos((uv_handle_t*)&udp, 255); - r = uv_ip6_addr("::1", TEST_PORT, &addr); - ASSERT_OK(r); + uv_close((uv_handle_t*)&udp, NULL); + ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT)); - r = uv_udp_bind(&udp, (const struct sockaddr*) &addr, 0); - ASSERT_OK(r); - - /* Test valid TOS values */ - tos_in = 0; - r = uv_socket_set_tos((uv_handle_t*) &udp, tos_in); - ASSERT_OK(r); - - r = uv_socket_get_tos((uv_handle_t*) &udp, &tos_out); - ASSERT_OK(r); - ASSERT_EQ(tos_out, tos_in); - - tos_in = 96; - r = uv_socket_set_tos((uv_handle_t*) &udp, tos_in); - ASSERT_OK(r); - - r = uv_socket_get_tos((uv_handle_t*) &udp, &tos_out); - ASSERT_OK(r); - ASSERT_EQ(tos_out, tos_in); - - tos_in = 255; - r = uv_socket_set_tos((uv_handle_t*) &udp, tos_in); - ASSERT_OK(r); - - r = uv_socket_get_tos((uv_handle_t*) &udp, &tos_out); - ASSERT_OK(r); - ASSERT_EQ(tos_out, tos_in); - - uv_close((uv_handle_t*) &udp, NULL); - r = uv_run(loop, UV_RUN_DEFAULT); - ASSERT_OK(r); - - MAKE_VALGRIND_HAPPY(loop); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } - TEST_IMPL(socket_tos_invalid_handle) { - uv_loop_t* loop; uv_timer_t timer; - uv_pipe_t pipe; int r; int tos; - loop = uv_default_loop(); - /* Test with invalid handle types */ - r = uv_timer_init(loop, &timer); + r = uv_timer_init(uv_default_loop(), &timer); ASSERT_OK(r); - r = uv_socket_set_tos((uv_handle_t*) &timer, 64); + r = uv_socket_set_tos((uv_handle_t*)&timer, 64); ASSERT_EQ(r, UV_EINVAL); - r = uv_socket_get_tos((uv_handle_t*) &timer, &tos); + r = uv_socket_get_tos((uv_handle_t*)&timer, &tos); ASSERT_EQ(r, UV_EINVAL); - uv_close((uv_handle_t*) &timer, NULL); + uv_close((uv_handle_t*)&timer, NULL); - /* Test with pipe handle */ - r = uv_pipe_init(loop, &pipe, 0); + r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); ASSERT_OK(r); - r = uv_socket_set_tos((uv_handle_t*) &pipe, 64); - ASSERT_EQ(r, UV_EINVAL); - - r = uv_socket_get_tos((uv_handle_t*) &pipe, &tos); - ASSERT_EQ(r, UV_EINVAL); - - uv_close((uv_handle_t*) &pipe, NULL); - - r = uv_run(loop, UV_RUN_DEFAULT); - ASSERT_OK(r); - - MAKE_VALGRIND_HAPPY(loop); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } - TEST_IMPL(socket_tos_unbound_tcp) { - uv_loop_t* loop; uv_tcp_t tcp; int r; int tos; - loop = uv_default_loop(); - - /* Test with unbound TCP socket - should fail since no address family */ - r = uv_tcp_init(loop, &tcp); + r = uv_tcp_init(uv_default_loop(), &tcp); ASSERT_OK(r); - /* Getting/setting TOS on unbound socket should fail */ - r = uv_socket_set_tos((uv_handle_t*) &tcp, 64); + r = uv_socket_set_tos((uv_handle_t*)&tcp, 64); ASSERT_NE(r, 0); - r = uv_socket_get_tos((uv_handle_t*) &tcp, &tos); + r = uv_socket_get_tos((uv_handle_t*)&tcp, &tos); ASSERT_NE(r, 0); - uv_close((uv_handle_t*) &tcp, NULL); - r = uv_run(loop, UV_RUN_DEFAULT); + uv_close((uv_handle_t*)&tcp, NULL); + r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); ASSERT_OK(r); - MAKE_VALGRIND_HAPPY(loop); + MAKE_VALGRIND_HAPPY(uv_default_loop()); return 0; } From 4aba7880941c412578970fbb7079436d30b8ddd8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Jos=C3=A9=20Arboleda?= Date: Tue, 27 Jan 2026 23:24:27 -0500 Subject: [PATCH 3/4] win: WIN STILL WIP, IDK WHAT IS WRONG MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Juan José Arboleda --- CMakeLists.txt | 3 ++- src/uv-common.c | 37 +++++++++++++++++++++++++++++++++++++ test/test-socket-tos.c | 2 +- 3 files changed, 40 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e5e27ae15..a912fc2f9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -196,7 +196,8 @@ if(WIN32) ws2_32 dbghelp ole32 - shell32) + shell32 + qwave) list(APPEND uv_sources src/win/async.c src/win/core.c diff --git a/src/uv-common.c b/src/uv-common.c index 628dd1987..622cb67fe 100644 --- a/src/uv-common.c +++ b/src/uv-common.c @@ -32,6 +32,8 @@ #if defined(_WIN32) # include /* malloc */ +# include +# include #else # include /* if_nametoindex */ # include /* AF_UNIX, sockaddr_un */ @@ -1112,7 +1114,11 @@ int uv_socket_get_tos(const uv_handle_t* handle, int* tos) { return UV_EAFNOSUPPORT; } +#if defined(_WIN32) + r = getsockopt(fd, level, option, (char*)&tos_, &optlen); +#else r = getsockopt(fd, level, option, &tos_, &optlen); +#endif if (r) return r; @@ -1165,6 +1171,37 @@ int uv_socket_set_tos(const uv_handle_t* handle, int tos) { return UV_EAFNOSUPPORT; } +#ifndef _WIN32 r = setsockopt(fd, level, option, &tos, sizeof(tos)); return UV__ERR(r); +#else + HANDLE qosHandle = NULL; + QOS_VERSION version = {1, 0}; + QOS_FLOWID flowId = 0; + DWORD dscpValue = (DWORD)tos; + SOCKET socket = (SOCKET)fd; + + /* NOTE: I'm using setsockopt here to set the TOS value directly on the socket as UNIX. + * I'm not too worried about this one, let's use the QOS API as a backup plan. + */ + setsockopt(fd, level, option, (char*)&tos, sizeof(tos)); + + if (storage.ss_family == AF_UNSPEC) { + /* Can't set DSCP on an unspecified address */ + return UV_ENOTCONN; + } + + /* Do the same thing using QOS APIs just to be sure */ + if (QOSCreateHandle(&version, &qosHandle)) { + if(QOSAddSocketToFlow(qosHandle, socket, NULL, QOSTrafficTypeBestEffort, 0, &flowId)) { + QOSSetFlow(qosHandle, flowId, QOSSetOutgoingDSCPValue, sizeof(dscpValue), &dscpValue, 0, NULL); + } else { + int err = WSAGetLastError(); + printf("QOSAddSocketToFlow failed with error: %d\n", err); + } + QOSCloseHandle(qosHandle); + return 0; + } +#endif + return 0; } diff --git a/test/test-socket-tos.c b/test/test-socket-tos.c index ba31d59b3..2d5a5304a 100644 --- a/test/test-socket-tos.c +++ b/test/test-socket-tos.c @@ -1,4 +1,4 @@ -/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. +/* 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 From 7a6d93159b7bffef8be6b82112cf1616d00bd4c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Jos=C3=A9=20Arboleda?= Date: Fri, 30 Jan 2026 20:16:38 -0500 Subject: [PATCH 4/4] fixup: remove win, return ENOSYS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Juan José Arboleda --- CMakeLists.txt | 3 +-- src/uv-common.c | 45 ++++++++---------------------------------- test/test-socket-tos.c | 20 ++++++++++++++++++- 3 files changed, 28 insertions(+), 40 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a912fc2f9..e5e27ae15 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -196,8 +196,7 @@ if(WIN32) ws2_32 dbghelp ole32 - shell32 - qwave) + shell32) list(APPEND uv_sources src/win/async.c src/win/core.c diff --git a/src/uv-common.c b/src/uv-common.c index 622cb67fe..892423bc8 100644 --- a/src/uv-common.c +++ b/src/uv-common.c @@ -32,8 +32,6 @@ #if defined(_WIN32) # include /* malloc */ -# include -# include #else # include /* if_nametoindex */ # include /* AF_UNIX, sockaddr_un */ @@ -1075,6 +1073,10 @@ int uv_socket_get_tos(const uv_handle_t* handle, int* tos) { socklen_t optlen; struct sockaddr_storage storage; +#if defined(_WIN32) + return UV_ENOSYS; +#endif + addrlen = sizeof(storage); tos_ = 0; optlen = sizeof(tos_); @@ -1114,11 +1116,7 @@ int uv_socket_get_tos(const uv_handle_t* handle, int* tos) { return UV_EAFNOSUPPORT; } -#if defined(_WIN32) - r = getsockopt(fd, level, option, (char*)&tos_, &optlen); -#else r = getsockopt(fd, level, option, &tos_, &optlen); -#endif if (r) return r; @@ -1135,6 +1133,10 @@ int uv_socket_set_tos(const uv_handle_t* handle, int tos) { int level; int option; +#if defined(_WIN32) + return UV_ENOSYS; +#endif + addrlen = sizeof(storage); if (tos < 0 || tos > 255) @@ -1171,37 +1173,6 @@ int uv_socket_set_tos(const uv_handle_t* handle, int tos) { return UV_EAFNOSUPPORT; } -#ifndef _WIN32 r = setsockopt(fd, level, option, &tos, sizeof(tos)); return UV__ERR(r); -#else - HANDLE qosHandle = NULL; - QOS_VERSION version = {1, 0}; - QOS_FLOWID flowId = 0; - DWORD dscpValue = (DWORD)tos; - SOCKET socket = (SOCKET)fd; - - /* NOTE: I'm using setsockopt here to set the TOS value directly on the socket as UNIX. - * I'm not too worried about this one, let's use the QOS API as a backup plan. - */ - setsockopt(fd, level, option, (char*)&tos, sizeof(tos)); - - if (storage.ss_family == AF_UNSPEC) { - /* Can't set DSCP on an unspecified address */ - return UV_ENOTCONN; - } - - /* Do the same thing using QOS APIs just to be sure */ - if (QOSCreateHandle(&version, &qosHandle)) { - if(QOSAddSocketToFlow(qosHandle, socket, NULL, QOSTrafficTypeBestEffort, 0, &flowId)) { - QOSSetFlow(qosHandle, flowId, QOSSetOutgoingDSCPValue, sizeof(dscpValue), &dscpValue, 0, NULL); - } else { - int err = WSAGetLastError(); - printf("QOSAddSocketToFlow failed with error: %d\n", err); - } - QOSCloseHandle(qosHandle); - return 0; - } -#endif - return 0; } diff --git a/test/test-socket-tos.c b/test/test-socket-tos.c index 2d5a5304a..c3de8fdec 100644 --- a/test/test-socket-tos.c +++ b/test/test-socket-tos.c @@ -19,8 +19,8 @@ * IN THE SOFTWARE. */ -#include "task.h" #include "uv.h" +#include "task.h" static void setup_tcp(uv_loop_t* loop, uv_tcp_t* tcp, const char* ip, int is_ip6) { @@ -86,6 +86,9 @@ static void check_tos_fail(uv_handle_t* handle, int tos) { } TEST_IMPL(tcp_socket_set_get_tos) { +#if defined(_WIN32) + RETURN_SKIP("Windows does not support setting TOS"); +#endif uv_tcp_t tcp; setup_tcp(uv_default_loop(), &tcp, "0.0.0.0", 0); @@ -106,6 +109,9 @@ TEST_IMPL(tcp_socket_set_get_tos) { } TEST_IMPL(tcp6_socket_set_get_tos) { +#if defined(_WIN32) + RETURN_SKIP("Windows does not support setting TOS"); +#endif uv_tcp_t tcp; setup_tcp(uv_default_loop(), &tcp, "::1", 1); @@ -122,6 +128,9 @@ TEST_IMPL(tcp6_socket_set_get_tos) { } TEST_IMPL(udp_socket_set_get_tos) { +#if defined(_WIN32) + RETURN_SKIP("Windows does not support setting TOS"); +#endif uv_udp_t udp; setup_udp(uv_default_loop(), &udp, "0.0.0.0", 0); @@ -141,6 +150,9 @@ TEST_IMPL(udp_socket_set_get_tos) { } TEST_IMPL(udp6_socket_set_get_tos) { +#if defined(_WIN32) + RETURN_SKIP("Windows does not support setting TOS"); +#endif uv_udp_t udp; setup_udp(uv_default_loop(), &udp, "::1", 1); @@ -157,6 +169,9 @@ TEST_IMPL(udp6_socket_set_get_tos) { } TEST_IMPL(socket_tos_invalid_handle) { +#if defined(_WIN32) + RETURN_SKIP("Windows does not support setting TOS"); +#endif uv_timer_t timer; int r; int tos; @@ -181,6 +196,9 @@ TEST_IMPL(socket_tos_invalid_handle) { } TEST_IMPL(socket_tos_unbound_tcp) { +#if defined(_WIN32) + RETURN_SKIP("Windows does not support setting TOS on UDP sockets"); +#endif uv_tcp_t tcp; int r; int tos;