From fc29bfef9d56d6bd1bd00ae6e9d7dde67d01fcac Mon Sep 17 00:00:00 2001 From: Rocker Zhang Date: Fri, 5 Jun 2026 00:51:31 +0800 Subject: [PATCH] zdtm: add test for SO_SNDTIMEO and SO_RCVTIMEO CRIU dumps and restores the SO_SNDTIMEO and SO_RCVTIMEO socket send/receive timeout options in dump_socket_opts()/restore_socket_opts() (criu/sockets.c), but the ZDTM suite has no dedicated coverage for them: SO_SNDTIMEO is not exercised by any test, and SO_RCVTIMEO is only used incidentally as a receive timeout in socket_icmp, never asserted across checkpoint/restore. Add socket-timeo, which sets distinct send and receive timeouts on a socket, performs checkpoint/restore, and verifies both values survive. Whole-second timeouts are used because the kernel stores these options with jiffy granularity: setsockopt() may round a sub-second value to the nearest tick depending on HZ, so a literal sub-second expectation could fail to match the stored value regardless of checkpoint/restore. The send and receive values differ so a mix-up between the two options is caught. Assisted-by: Claude:claude-opus-4-8 Signed-off-by: Rocker Zhang --- test/zdtm/static/Makefile | 1 + test/zdtm/static/socket-timeo.c | 75 +++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+) create mode 100644 test/zdtm/static/socket-timeo.c diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile index 947cafd37..0e2580ed6 100644 --- a/test/zdtm/static/Makefile +++ b/test/zdtm/static/Makefile @@ -137,6 +137,7 @@ TST_NOFILE := \ socket-tcp-skip-in-flight \ socket-tcp-keepalive \ socket-linger \ + socket-timeo \ sock_opts00 \ sock_opts01 \ sock_opts02 \ diff --git a/test/zdtm/static/socket-timeo.c b/test/zdtm/static/socket-timeo.c new file mode 100644 index 000000000..8fcaf2f6e --- /dev/null +++ b/test/zdtm/static/socket-timeo.c @@ -0,0 +1,75 @@ +#include +#include +#include +#include +#include + +#include "zdtmtst.h" + +const char *test_doc = "Check SO_SNDTIMEO and SO_RCVTIMEO socket options"; +const char *test_author = "Rocker Zhang "; + +/* + * Whole-second timeouts are used on purpose. The kernel stores + * SO_SNDTIMEO/SO_RCVTIMEO with jiffy granularity, so setsockopt() may + * round a sub-second tv_usec to the nearest tick depending on HZ. Such a + * value would still survive checkpoint/restore (CRIU saves and restores + * whatever the kernel reports), but a literal sub-second expectation in + * this test could fail to match the rounded value. Whole seconds avoid + * that ambiguity. Distinct send/receive values catch a possible mix-up + * between the two options. + */ +static int check_timeo(int sk, int opt, const char *name, const struct timeval *want) +{ + struct timeval got = { 0, 0 }; + socklen_t optlen = sizeof(got); + + if (getsockopt(sk, SOL_SOCKET, opt, &got, &optlen) < 0) { + pr_perror("getsockopt %s", name); + return -1; + } + + if (got.tv_sec != want->tv_sec || got.tv_usec != want->tv_usec) { + fail("%s has incorrect value (%ld.%06ld != %ld.%06ld)", name, (long)got.tv_sec, (long)got.tv_usec, + (long)want->tv_sec, (long)want->tv_usec); + return -1; + } + + return 0; +} + +int main(int argc, char **argv) +{ + int sk; + struct timeval sndtimeo = { 7, 0 }, rcvtimeo = { 11, 0 }; + + test_init(argc, argv); + + sk = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); + if (sk < 0) { + pr_perror("Can't create socket"); + return 1; + } + + if (setsockopt(sk, SOL_SOCKET, SO_SNDTIMEO, &sndtimeo, sizeof(sndtimeo)) < 0) { + pr_perror("setsockopt SO_SNDTIMEO"); + return 1; + } + + if (setsockopt(sk, SOL_SOCKET, SO_RCVTIMEO, &rcvtimeo, sizeof(rcvtimeo)) < 0) { + pr_perror("setsockopt SO_RCVTIMEO"); + return 1; + } + + test_daemon(); + test_waitsig(); + + if (check_timeo(sk, SO_SNDTIMEO, "SO_SNDTIMEO", &sndtimeo)) + return 1; + + if (check_timeo(sk, SO_RCVTIMEO, "SO_RCVTIMEO", &rcvtimeo)) + return 1; + + pass(); + return 0; +}