From f1d34a1fd6f318cd686cb7bb39eacb10e3415ba7 Mon Sep 17 00:00:00 2001 From: Maximilian Fridrich Date: Tue, 26 Nov 2024 07:45:40 +0100 Subject: [PATCH 1/2] tcp,udp: set TOS (TCLASS) for IPv6 sockets --- src/tcp/tcp.c | 32 ++++++++++++++++++++++++++++++-- src/udp/udp.c | 16 +++++++++++++++- 2 files changed, 45 insertions(+), 3 deletions(-) diff --git a/src/tcp/tcp.c b/src/tcp/tcp.c index 889713e51..9c2f4ac10 100644 --- a/src/tcp/tcp.c +++ b/src/tcp/tcp.c @@ -1450,12 +1450,25 @@ int tcp_settos(struct tcp_sock *ts, uint32_t tos) { int err = 0; int v = tos; + struct sa sa; if (!ts) return EINVAL; ts->tos = tos; - err = tcp_sock_setopt(ts, IPPROTO_IP, IP_TOS, &v, sizeof(v)); + err = tcp_local_get(ts, &sa); + if (err) + return err; + + if (sa_af(&sa) == AF_INET) { + err = tcp_sock_setopt(ts, IPPROTO_IP, IP_TOS, &v, sizeof(v)); + } +#if defined(IPV6_TCLASS) && !defined(WIN32) + else if (sa_af(&sa) == AF_INET6) { + err = tcp_sock_setopt(ts, IPPROTO_IPV6, IPV6_TCLASS, &v, + sizeof(v)); + } +#endif return err; } @@ -1465,16 +1478,31 @@ int tcp_conn_settos(struct tcp_conn *tc, uint32_t tos) { int err = 0; int v = tos; + struct sa sa; if (!tc) return EINVAL; tc->tos = tos; - if (tc->fdc != RE_BAD_SOCK) { + if (tc->fdc == RE_BAD_SOCK) + return err; + + err = tcp_conn_local_get(tc, &sa); + if (err) + return err; + + if (sa_af(&sa) == AF_INET) { if (0 != setsockopt(tc->fdc, IPPROTO_IP, IP_TOS, BUF_CAST &v, sizeof(v))) err = RE_ERRNO_SOCK; } +#if defined(IPV6_TCLASS) && !defined(WIN32) + else if (sa_af(&sa) == AF_INET6) { + if (0 != setsockopt(tc->fdc, IPPROTO_IPV6, IPV6_TCLASS, + BUF_CAST &v, sizeof(v))) + err = RE_ERRNO_SOCK; + } +#endif return err; } diff --git a/src/udp/udp.c b/src/udp/udp.c index 7a7f9cb52..8bfbca67d 100644 --- a/src/udp/udp.c +++ b/src/udp/udp.c @@ -628,6 +628,7 @@ int udp_settos(struct udp_sock *us, uint8_t tos) { int err = 0; int v = tos; + struct sa sa; #ifdef WIN32 QOS_VERSION qos_version = { 1 , 0 }; QOS_TRAFFIC_TYPE qos_type = QOSTrafficTypeBestEffort; @@ -660,7 +661,20 @@ int udp_settos(struct udp_sock *us, uint8_t tos) return WSAGetLastError(); } #endif - err = udp_setsockopt(us, IPPROTO_IP, IP_TOS, &v, sizeof(v)); + err = udp_local_get(us, &sa); + if (err) + return err; + + if (sa_af(&sa) == AF_INET) { + err = udp_setsockopt(us, IPPROTO_IP, IP_TOS, &v, sizeof(v)); + } +#if defined(IPV6_TCLASS) && !defined(WIN32) + else if (sa_af(&sa) == AF_INET6) { + err = udp_setsockopt(us, IPPROTO_IPV6, IPV6_TCLASS, &v, + sizeof(v)); + } +#endif + return err; } From 9bfbc91a256da39f5a42bba431c8785b56839d51 Mon Sep 17 00:00:00 2001 From: Maximilian Fridrich Date: Thu, 12 Dec 2024 16:17:44 +0100 Subject: [PATCH 2/2] test/tcp,udp: Add TOS/TCLASS tests --- test/tcp.c | 64 +++++++++++++++++++++++++++++++++++++++++++++ test/test.c | 2 ++ test/test.h | 2 ++ test/udp.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 143 insertions(+) diff --git a/test/tcp.c b/test/tcp.c index 2619da449..0e6d5254e 100644 --- a/test/tcp.c +++ b/test/tcp.c @@ -227,3 +227,67 @@ int test_tcp(void) return err; } + + +#if !defined(WIN32) +static int tcp_tos(const char *addr) +{ + struct tcp_test *tt; + struct sa srv; + int err; + + tt = mem_zalloc(sizeof(*tt), destructor); + if (!tt) + return ENOMEM; + + err = sa_set_str(&srv, addr, 0); + TEST_ERR(err); + + err = tcp_listen(&tt->ts, &srv, tcp_server_conn_handler, tt); + TEST_ERR(err); + + err = tcp_settos(tt->ts, 184); + TEST_ERR(err); + + err = tcp_local_get(tt->ts, &srv); + TEST_ERR(err); + + err = tcp_connect(&tt->tc, &srv, tcp_client_estab_handler, + tcp_client_recv_handler, tcp_client_close_handler, + tt); + TEST_ERR(err); + + err = re_main_timeout(500); + TEST_ERR(err); + + if (tt->err) + err = tt->err; + + out: + mem_deref(tt); + + return err; +} + + +int test_tcp_tos(void) +{ + int err; + + err = tcp_tos("127.0.0.1"); + TEST_ERR(err); + + err = tcp_tos("::1"); + TEST_ERR(err); + + out: + return err; +} +#else +/* Outcome of the TOS test on Windows would be dependent on the + * DisableUserTOSSetting Windows registry setting. */ +int test_tcp_tos(void) +{ + return 0; +} +#endif diff --git a/test/test.c b/test/test.c index 1ec985d46..9494e77cf 100644 --- a/test/test.c +++ b/test/test.c @@ -216,6 +216,7 @@ static const struct test tests[] = { TEST(test_sys_fs_fopen), TEST(test_sys_getenv), TEST(test_tcp), + TEST(test_tcp_tos), TEST(test_telev), TEST(test_text2pcap), #ifdef USE_TLS @@ -236,6 +237,7 @@ static const struct test tests[] = { TEST(test_turn), TEST(test_turn_tcp), TEST(test_udp), + TEST(test_udp_tos), TEST(test_unixsock), TEST(test_uri), TEST(test_uri_encode), diff --git a/test/test.h b/test/test.h index 303b84166..6af831927 100644 --- a/test/test.h +++ b/test/test.h @@ -332,6 +332,7 @@ int test_sys_fs_isfile(void); int test_sys_fs_fopen(void); int test_sys_getenv(void); int test_tcp(void); +int test_tcp_tos(void); int test_telev(void); int test_text2pcap(void); int test_thread(void); @@ -343,6 +344,7 @@ int test_turn(void); int test_turn_tcp(void); int test_turn_thread(void); int test_udp(void); +int test_udp_tos(void); int test_unixsock(void); int test_uri(void); int test_uri_encode(void); diff --git a/test/udp.c b/test/udp.c index 22a8d3243..4887692a0 100644 --- a/test/udp.c +++ b/test/udp.c @@ -213,3 +213,78 @@ int test_udp(void) return err; } + + +#if !defined(WIN32) +static int udp_tos(const char *addr) +{ + struct udp_test *ut; + int layer = 0; + int err; + + ut = mem_zalloc(sizeof(*ut), destructor); + if (!ut) + return ENOMEM; + + err = sa_set_str(&ut->cli, addr, 0); + err |= sa_set_str(&ut->srv, addr, 0); + TEST_ERR(err); + + err = udp_listen(&ut->usc, &ut->cli, udp_recv_client, ut); + err |= udp_listen(&ut->uss, &ut->srv, udp_recv_server, ut); + TEST_ERR(err); + + err = udp_settos(ut->usc, 184); + err |= udp_settos(ut->uss, 120); + TEST_ERR(err); + + err = udp_local_get(ut->usc, &ut->cli); + err |= udp_local_get(ut->uss, &ut->srv); + TEST_ERR(err); + + err = udp_register_helper(&ut->uh, ut->usc, layer, + udp_helper_send, udp_helper_recv, ut); + TEST_ERR(err); + + /* Send from connected client UDP socket */ + err = udp_connect(ut->usc, &ut->srv); + TEST_ERR(err); + + /* Start test */ + err = send_data(ut->usc, &ut->srv, data0); + TEST_ERR(err); + + err = re_main_timeout(100); + TEST_ERR(err); + + if (ut->err) + err = ut->err; + + out: + mem_deref(ut); + + return err; +} + + +int test_udp_tos(void) +{ + int err; + + err = udp_tos("127.0.0.1"); + TEST_ERR(err); + + err = udp_tos("::1"); + TEST_ERR(err); + + out: + return err; +} +#else +/* Outcome of the TOS test on Windows would be dependent on the + * DisableUserTOSSetting Windows registry setting. */ +int test_udp_tos(void) +{ + return 0; +} +#endif