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 11 FIXTURE(so_peek_off) 12 { 13 int fd[2]; /* 0: sender, 1: receiver */ 14 }; 15 16 FIXTURE_VARIANT(so_peek_off) 17 { 18 int type; 19 }; 20 21 FIXTURE_VARIANT_ADD(so_peek_off, stream) 22 { 23 .type = SOCK_STREAM, 24 }; 25 26 FIXTURE_VARIANT_ADD(so_peek_off, dgram) 27 { 28 .type = SOCK_DGRAM, 29 }; 30 31 FIXTURE_VARIANT_ADD(so_peek_off, seqpacket) 32 { 33 .type = SOCK_SEQPACKET, 34 }; 35 36 FIXTURE_SETUP(so_peek_off) 37 { 38 struct timeval timeout = { 39 .tv_sec = 0, 40 .tv_usec = 3000, 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 56 FIXTURE_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 89 TEST_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 97 TEST_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 106 TEST_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 124 TEST_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 142 TEST_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 162 TEST_HARNESS_MAIN 163