FILE
so_peek_off.c
File preview with syntax highlighting.
linux-6.19.14/tools/testing/selftests/net/af_unix/so_peek_off.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.