summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSoichiro Ueda <the.latticeheart@gmail.com>2026-03-10 10:28:31 +0300
committerJakub Kicinski <kuba@kernel.org>2026-03-12 04:20:17 +0300
commit34c0378b156f02f5fd8149f24a7aa75b255e8cda (patch)
tree2d22c3f2725ad0e306dfdc59af379d1e17052922
parent482aac8b56ca21d06c588517970579474d56736e (diff)
downloadlinux-34c0378b156f02f5fd8149f24a7aa75b255e8cda.tar.xz
selftests: af_unix: validate SO_PEEK_OFF advancement and reset
Extend the so_peek_off selftest to ensure the socket peek offset is handled correctly after both MSG_PEEK and actual data consumption. Verify that the peek offset advances by the same amount as the number of bytes read when performing a read with MSG_PEEK. After exercising SO_PEEK_OFF via MSG_PEEK, drain the receive queue with a non-peek recv() and verify that it can receive all the content in the buffer and SO_PEEK_OFF returns back to 0. The verification after actual data consumption was suggested by Miao Wang when the original so_peek_off selftest was introduced. Link: https://lore.kernel.org/all/7B657CC7-B5CA-46D2-8A4B-8AB5FB83C6DA@gmail.com/ Suggested-by: Miao Wang <shankerwangmiao@gmail.com> Reviewed-by: Willem de Bruijn <willemb@google.com> Reviewed-by: Kuniyuki Iwashima <kuniyu@google.com> Signed-off-by: Soichiro Ueda <the.latticeheart@gmail.com> Link: https://patch.msgid.link/20260310072832.127848-1-the.latticeheart@gmail.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
-rw-r--r--tools/testing/selftests/net/af_unix/so_peek_off.c46
1 files changed, 46 insertions, 0 deletions
diff --git a/tools/testing/selftests/net/af_unix/so_peek_off.c b/tools/testing/selftests/net/af_unix/so_peek_off.c
index 86e7b0fb522d..f6466a717f49 100644
--- a/tools/testing/selftests/net/af_unix/so_peek_off.c
+++ b/tools/testing/selftests/net/af_unix/so_peek_off.c
@@ -76,6 +76,19 @@ FIXTURE_TEARDOWN(so_peek_off)
ASSERT_STREQ(str, buf); \
} while (0)
+#define peekoffeq(fd, expected) \
+ do { \
+ socklen_t optlen = sizeof(int); \
+ int off = -1; \
+ int ret; \
+ \
+ ret = getsockopt(fd, SOL_SOCKET, SO_PEEK_OFF, \
+ &off, &optlen); \
+ ASSERT_EQ(0, ret); \
+ ASSERT_EQ((socklen_t)sizeof(off), optlen); \
+ ASSERT_EQ(expected, off); \
+ } while (0)
+
#define async \
for (pid_t pid = (pid = fork(), \
pid < 0 ? \
@@ -91,7 +104,12 @@ TEST_F(so_peek_off, single_chunk)
sendeq(self->fd[0], "aaaabbbb", 0);
recveq(self->fd[1], "aaaa", 4, MSG_PEEK);
+ peekoffeq(self->fd[1], 4);
recveq(self->fd[1], "bbbb", 100, MSG_PEEK);
+ peekoffeq(self->fd[1], 8);
+
+ recveq(self->fd[1], "aaaabbbb", 8, 0);
+ peekoffeq(self->fd[1], 0);
}
TEST_F(so_peek_off, two_chunks)
@@ -100,7 +118,13 @@ TEST_F(so_peek_off, two_chunks)
sendeq(self->fd[0], "bbbb", 0);
recveq(self->fd[1], "aaaa", 4, MSG_PEEK);
+ peekoffeq(self->fd[1], 4);
recveq(self->fd[1], "bbbb", 100, MSG_PEEK);
+ peekoffeq(self->fd[1], 8);
+
+ recveq(self->fd[1], "aaaa", 4, 0);
+ recveq(self->fd[1], "bbbb", 4, 0);
+ peekoffeq(self->fd[1], 0);
}
TEST_F(so_peek_off, two_chunks_blocking)
@@ -111,6 +135,7 @@ TEST_F(so_peek_off, two_chunks_blocking)
}
recveq(self->fd[1], "aaaa", 4, MSG_PEEK);
+ peekoffeq(self->fd[1], 4);
async {
usleep(1000);
@@ -119,24 +144,38 @@ TEST_F(so_peek_off, two_chunks_blocking)
/* goto again; -> goto redo; in unix_stream_read_generic(). */
recveq(self->fd[1], "bbbb", 100, MSG_PEEK);
+ peekoffeq(self->fd[1], 8);
+
+ recveq(self->fd[1], "aaaa", 4, 0);
+ recveq(self->fd[1], "bbbb", 4, 0);
+ peekoffeq(self->fd[1], 0);
}
TEST_F(so_peek_off, two_chunks_overlap)
{
sendeq(self->fd[0], "aaaa", 0);
recveq(self->fd[1], "aa", 2, MSG_PEEK);
+ peekoffeq(self->fd[1], 2);
sendeq(self->fd[0], "bbbb", 0);
if (variant->type == SOCK_STREAM) {
/* SOCK_STREAM tries to fill the buffer. */
recveq(self->fd[1], "aabb", 4, MSG_PEEK);
+ peekoffeq(self->fd[1], 6);
recveq(self->fd[1], "bb", 100, MSG_PEEK);
+ peekoffeq(self->fd[1], 8);
} else {
/* SOCK_DGRAM and SOCK_SEQPACKET returns at the skb boundary. */
recveq(self->fd[1], "aa", 100, MSG_PEEK);
+ peekoffeq(self->fd[1], 4);
recveq(self->fd[1], "bbbb", 100, MSG_PEEK);
+ peekoffeq(self->fd[1], 8);
}
+
+ recveq(self->fd[1], "aaaa", 4, 0);
+ recveq(self->fd[1], "bbbb", 4, 0);
+ peekoffeq(self->fd[1], 0);
}
TEST_F(so_peek_off, two_chunks_overlap_blocking)
@@ -147,6 +186,7 @@ TEST_F(so_peek_off, two_chunks_overlap_blocking)
}
recveq(self->fd[1], "aa", 2, MSG_PEEK);
+ peekoffeq(self->fd[1], 2);
async {
usleep(1000);
@@ -155,8 +195,14 @@ TEST_F(so_peek_off, two_chunks_overlap_blocking)
/* Even SOCK_STREAM does not wait if at least one byte is read. */
recveq(self->fd[1], "aa", 100, MSG_PEEK);
+ peekoffeq(self->fd[1], 4);
recveq(self->fd[1], "bbbb", 100, MSG_PEEK);
+ peekoffeq(self->fd[1], 8);
+
+ recveq(self->fd[1], "aaaa", 4, 0);
+ recveq(self->fd[1], "bbbb", 4, 0);
+ peekoffeq(self->fd[1], 0);
}
TEST_HARNESS_MAIN