gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/test/syscalls/linux/readv_common.cc (about) 1 // Copyright 2018 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #include <errno.h> 16 #include <fcntl.h> 17 #include <sys/socket.h> 18 #include <sys/types.h> 19 #include <unistd.h> 20 21 #include "gtest/gtest.h" 22 #include "test/util/test_util.h" 23 24 namespace gvisor { 25 namespace testing { 26 27 // MatchesStringLength checks that a tuple argument of (struct iovec *, int) 28 // corresponding to an iovec array and its length, contains data that matches 29 // the string length strlen. 30 MATCHER_P(MatchesStringLength, strlen, "") { 31 struct iovec* iovs = arg.first; 32 int niov = arg.second; 33 int offset = 0; 34 for (int i = 0; i < niov; i++) { 35 offset += iovs[i].iov_len; 36 } 37 if (offset != static_cast<int>(strlen)) { 38 *result_listener << offset; 39 return false; 40 } 41 return true; 42 } 43 44 // MatchesStringValue checks that a tuple argument of (struct iovec *, int) 45 // corresponding to an iovec array and its length, contains data that matches 46 // the string value str. 47 MATCHER_P(MatchesStringValue, str, "") { 48 struct iovec* iovs = arg.first; 49 int len = strlen(str); 50 int niov = arg.second; 51 int offset = 0; 52 for (int i = 0; i < niov; i++) { 53 struct iovec iov = iovs[i]; 54 if (len < offset) { 55 *result_listener << "strlen " << len << " < offset " << offset; 56 return false; 57 } 58 if (strncmp(static_cast<char*>(iov.iov_base), &str[offset], iov.iov_len)) { 59 absl::string_view iovec_string(static_cast<char*>(iov.iov_base), 60 iov.iov_len); 61 *result_listener << iovec_string << " @offset " << offset; 62 return false; 63 } 64 offset += iov.iov_len; 65 } 66 return true; 67 } 68 69 extern const char kReadvTestData[] = 70 "127.0.0.1 localhost" 71 "" 72 "# The following lines are desirable for IPv6 capable hosts" 73 "::1 ip6-localhost ip6-loopback" 74 "fe00::0 ip6-localnet" 75 "ff00::0 ip6-mcastprefix" 76 "ff02::1 ip6-allnodes" 77 "ff02::2 ip6-allrouters" 78 "ff02::3 ip6-allhosts" 79 "192.168.1.100 a" 80 "93.184.216.34 foo.bar.example.com xcpu"; 81 extern const size_t kReadvTestDataSize = sizeof(kReadvTestData); 82 83 static void ReadAllOneProvidedBuffer(int fd, std::vector<char>* buffer) { 84 struct iovec iovs[1]; 85 iovs[0].iov_base = buffer->data(); 86 iovs[0].iov_len = kReadvTestDataSize; 87 88 ASSERT_THAT(readv(fd, iovs, 1), SyscallSucceedsWithValue(kReadvTestDataSize)); 89 90 std::pair<struct iovec*, int> iovec_desc(iovs, 1); 91 EXPECT_THAT(iovec_desc, MatchesStringLength(kReadvTestDataSize)); 92 EXPECT_THAT(iovec_desc, MatchesStringValue(kReadvTestData)); 93 } 94 95 void ReadAllOneBuffer(int fd) { 96 std::vector<char> buffer(kReadvTestDataSize); 97 ReadAllOneProvidedBuffer(fd, &buffer); 98 } 99 100 void ReadAllOneLargeBuffer(int fd) { 101 std::vector<char> buffer(10 * kReadvTestDataSize); 102 ReadAllOneProvidedBuffer(fd, &buffer); 103 } 104 105 void ReadOneHalfAtATime(int fd) { 106 int len0 = kReadvTestDataSize / 2; 107 int len1 = kReadvTestDataSize - len0; 108 std::vector<char> buffer0(len0); 109 std::vector<char> buffer1(len1); 110 111 struct iovec iovs[2]; 112 iovs[0].iov_base = buffer0.data(); 113 iovs[0].iov_len = len0; 114 iovs[1].iov_base = buffer1.data(); 115 iovs[1].iov_len = len1; 116 117 ASSERT_THAT(readv(fd, iovs, 2), SyscallSucceedsWithValue(kReadvTestDataSize)); 118 119 std::pair<struct iovec*, int> iovec_desc(iovs, 2); 120 EXPECT_THAT(iovec_desc, MatchesStringLength(kReadvTestDataSize)); 121 EXPECT_THAT(iovec_desc, MatchesStringValue(kReadvTestData)); 122 } 123 124 void ReadOneBufferPerByte(int fd) { 125 std::vector<char> buffer(kReadvTestDataSize); 126 std::vector<struct iovec> iovs(kReadvTestDataSize); 127 char* buffer_ptr = buffer.data(); 128 struct iovec* iovs_ptr = iovs.data(); 129 130 for (int i = 0; i < static_cast<int>(kReadvTestDataSize); i++) { 131 struct iovec iov = { 132 .iov_base = &buffer_ptr[i], 133 .iov_len = 1, 134 }; 135 iovs_ptr[i] = iov; 136 } 137 138 ASSERT_THAT(readv(fd, iovs_ptr, kReadvTestDataSize), 139 SyscallSucceedsWithValue(kReadvTestDataSize)); 140 141 std::pair<struct iovec*, int> iovec_desc(iovs.data(), kReadvTestDataSize); 142 EXPECT_THAT(iovec_desc, MatchesStringLength(kReadvTestDataSize)); 143 EXPECT_THAT(iovec_desc, MatchesStringValue(kReadvTestData)); 144 } 145 146 void ReadBuffersOverlapping(int fd) { 147 // overlap the first overlap_bytes. 148 int overlap_bytes = 8; 149 std::vector<char> buffer(kReadvTestDataSize); 150 151 // overlapping causes us to get more data. 152 int expected_size = kReadvTestDataSize + overlap_bytes; 153 std::vector<char> expected(expected_size); 154 char* expected_ptr = expected.data(); 155 memcpy(expected_ptr, &kReadvTestData[overlap_bytes], overlap_bytes); 156 memcpy(&expected_ptr[overlap_bytes], &kReadvTestData[overlap_bytes], 157 kReadvTestDataSize - overlap_bytes); 158 159 struct iovec iovs[2]; 160 iovs[0].iov_base = buffer.data(); 161 iovs[0].iov_len = overlap_bytes; 162 iovs[1].iov_base = buffer.data(); 163 iovs[1].iov_len = kReadvTestDataSize; 164 165 ASSERT_THAT(readv(fd, iovs, 2), SyscallSucceedsWithValue(kReadvTestDataSize)); 166 167 std::pair<struct iovec*, int> iovec_desc(iovs, 2); 168 EXPECT_THAT(iovec_desc, MatchesStringLength(expected_size)); 169 EXPECT_THAT(iovec_desc, MatchesStringValue(expected_ptr)); 170 } 171 172 void ReadBuffersDiscontinuous(int fd) { 173 // Each iov is 1 byte separated by 1 byte. 174 std::vector<char> buffer(kReadvTestDataSize * 2); 175 std::vector<struct iovec> iovs(kReadvTestDataSize); 176 177 char* buffer_ptr = buffer.data(); 178 struct iovec* iovs_ptr = iovs.data(); 179 180 for (int i = 0; i < static_cast<int>(kReadvTestDataSize); i++) { 181 struct iovec iov = { 182 .iov_base = &buffer_ptr[i * 2], 183 .iov_len = 1, 184 }; 185 iovs_ptr[i] = iov; 186 } 187 188 ASSERT_THAT(readv(fd, iovs_ptr, kReadvTestDataSize), 189 SyscallSucceedsWithValue(kReadvTestDataSize)); 190 191 std::pair<struct iovec*, int> iovec_desc(iovs.data(), kReadvTestDataSize); 192 EXPECT_THAT(iovec_desc, MatchesStringLength(kReadvTestDataSize)); 193 EXPECT_THAT(iovec_desc, MatchesStringValue(kReadvTestData)); 194 } 195 196 void ReadIovecsCompletelyFilled(int fd) { 197 int half = kReadvTestDataSize / 2; 198 std::vector<char> buffer(kReadvTestDataSize); 199 char* buffer_ptr = buffer.data(); 200 memset(buffer.data(), '\0', kReadvTestDataSize); 201 202 struct iovec iovs[2]; 203 iovs[0].iov_base = buffer.data(); 204 iovs[0].iov_len = half; 205 iovs[1].iov_base = &buffer_ptr[half]; 206 iovs[1].iov_len = half; 207 208 ASSERT_THAT(readv(fd, iovs, 2), SyscallSucceedsWithValue(half * 2)); 209 210 std::pair<struct iovec*, int> iovec_desc(iovs, 2); 211 EXPECT_THAT(iovec_desc, MatchesStringLength(half * 2)); 212 EXPECT_THAT(iovec_desc, MatchesStringValue(kReadvTestData)); 213 214 char* str = static_cast<char*>(iovs[0].iov_base); 215 str[iovs[0].iov_len - 1] = '\0'; 216 ASSERT_EQ(half - 1, strlen(str)); 217 } 218 219 } // namespace testing 220 } // namespace gvisor