File Index
Files and directories
Sign in
FILE

so_peek_off.c

File preview with syntax highlighting.

linux-6.19.14/tools/testing/selftests/net/af_unix/so_peek_off.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/* Copyright 2025 Google LLC */
  3
  4#include <stdlib.h>
  5#include <unistd.h>
  6
  7#include <sys/socket.h>
  8
  9#include "../../kselftest_harness.h"
 10
 11FIXTURE(so_peek_off)
 12{
 13	int fd[2];	/* 0: sender, 1: receiver */
 14};
 15
 16FIXTURE_VARIANT(so_peek_off)
 17{
 18	int type;
 19};
 20
 21FIXTURE_VARIANT_ADD(so_peek_off, stream)
 22{
 23	.type = SOCK_STREAM,
 24};
 25
 26FIXTURE_VARIANT_ADD(so_peek_off, dgram)
 27{
 28	.type = SOCK_DGRAM,
 29};
 30
 31FIXTURE_VARIANT_ADD(so_peek_off, seqpacket)
 32{
 33	.type = SOCK_SEQPACKET,
 34};
 35
 36FIXTURE_SETUP(so_peek_off)
 37{
 38	struct timeval timeout = {
 39		.tv_sec = 5,
 40		.tv_usec = 0,
 41	};
 42	int ret;
 43
 44	ret = socketpair(AF_UNIX, variant->type, 0, self->fd);
 45	ASSERT_EQ(0, ret);
 46
 47	ret = setsockopt(self->fd[1], SOL_SOCKET, SO_RCVTIMEO_NEW,
 48			 &timeout, sizeof(timeout));
 49	ASSERT_EQ(0, ret);
 50
 51	ret = setsockopt(self->fd[1], SOL_SOCKET, SO_PEEK_OFF,
 52			 &(int){0}, sizeof(int));
 53	ASSERT_EQ(0, ret);
 54}
 55
 56FIXTURE_TEARDOWN(so_peek_off)
 57{
 58	close_range(self->fd[0], self->fd[1], 0);
 59}
 60
 61#define sendeq(fd, str, flags)					\
 62	do {							\
 63		int bytes, len = strlen(str);			\
 64								\
 65		bytes = send(fd, str, len, flags);		\
 66		ASSERT_EQ(len, bytes);				\
 67	} while (0)
 68
 69#define recveq(fd, str, buflen, flags)				\
 70	do {							\
 71		char buf[(buflen) + 1] = {};			\
 72		int bytes;					\
 73								\
 74		bytes = recv(fd, buf, buflen, flags);		\
 75		ASSERT_NE(-1, bytes);				\
 76		ASSERT_STREQ(str, buf);				\
 77	} while (0)
 78
 79#define async							\
 80	for (pid_t pid = (pid = fork(),				\
 81			  pid < 0 ?				\
 82			  __TH_LOG("Failed to start async {}"),	\
 83			  _metadata->exit_code = KSFT_FAIL,	\
 84			  __bail(1, _metadata),			\
 85			  0xdead :				\
 86			  pid);					\
 87	     !pid; exit(0))
 88
 89TEST_F(so_peek_off, single_chunk)
 90{
 91	sendeq(self->fd[0], "aaaabbbb", 0);
 92
 93	recveq(self->fd[1], "aaaa", 4, MSG_PEEK);
 94	recveq(self->fd[1], "bbbb", 100, MSG_PEEK);
 95}
 96
 97TEST_F(so_peek_off, two_chunks)
 98{
 99	sendeq(self->fd[0], "aaaa", 0);
100	sendeq(self->fd[0], "bbbb", 0);
101
102	recveq(self->fd[1], "aaaa", 4, MSG_PEEK);
103	recveq(self->fd[1], "bbbb", 100, MSG_PEEK);
104}
105
106TEST_F(so_peek_off, two_chunks_blocking)
107{
108	async {
109		usleep(1000);
110		sendeq(self->fd[0], "aaaa", 0);
111	}
112
113	recveq(self->fd[1], "aaaa", 4, MSG_PEEK);
114
115	async {
116		usleep(1000);
117		sendeq(self->fd[0], "bbbb", 0);
118	}
119
120	/* goto again; -> goto redo; in unix_stream_read_generic(). */
121	recveq(self->fd[1], "bbbb", 100, MSG_PEEK);
122}
123
124TEST_F(so_peek_off, two_chunks_overlap)
125{
126	sendeq(self->fd[0], "aaaa", 0);
127	recveq(self->fd[1], "aa", 2, MSG_PEEK);
128
129	sendeq(self->fd[0], "bbbb", 0);
130
131	if (variant->type == SOCK_STREAM) {
132		/* SOCK_STREAM tries to fill the buffer. */
133		recveq(self->fd[1], "aabb", 4, MSG_PEEK);
134		recveq(self->fd[1], "bb", 100, MSG_PEEK);
135	} else {
136		/* SOCK_DGRAM and SOCK_SEQPACKET returns at the skb boundary. */
137		recveq(self->fd[1], "aa", 100, MSG_PEEK);
138		recveq(self->fd[1], "bbbb", 100, MSG_PEEK);
139	}
140}
141
142TEST_F(so_peek_off, two_chunks_overlap_blocking)
143{
144	async {
145		usleep(1000);
146		sendeq(self->fd[0], "aaaa", 0);
147	}
148
149	recveq(self->fd[1], "aa", 2, MSG_PEEK);
150
151	async {
152		usleep(1000);
153		sendeq(self->fd[0], "bbbb", 0);
154	}
155
156	/* Even SOCK_STREAM does not wait if at least one byte is read. */
157	recveq(self->fd[1], "aa", 100, MSG_PEEK);
158
159	recveq(self->fd[1], "bbbb", 100, MSG_PEEK);
160}
161
162TEST_HARNESS_MAIN
~/ Read-only file preview.