// Copyright 2018 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include #include #include #include #include #include "gtest/gtest.h" #include "gtest/gtest.h" #include "test/syscalls/linux/file_base.h" #include "test/util/test_util.h" namespace gvisor { namespace testing { extern const char kReadvTestData[] = "127.0.0.1 localhost" "" "# The following lines are desirable for IPv6 capable hosts" "::1 ip6-localhost ip6-loopback" "fe00::0 ip6-localnet" "ff00::0 ip6-mcastprefix" "ff02::1 ip6-allnodes" "ff02::2 ip6-allrouters" "ff02::3 ip6-allhosts" "192.168.1.100 a" "93.184.216.34 foo.bar.example.com xcpu"; extern const size_t kReadvTestDataSize = sizeof(kReadvTestData); static void ReadAllOneProvidedBuffer(int fd, std::vector* buffer) { struct iovec iovs[1]; iovs[0].iov_base = buffer->data(); iovs[0].iov_len = kReadvTestDataSize; ASSERT_THAT(readv(fd, iovs, 1), SyscallSucceedsWithValue(kReadvTestDataSize)); std::pair iovec_desc(iovs, 1); EXPECT_THAT(iovec_desc, MatchesStringLength(kReadvTestDataSize)); EXPECT_THAT(iovec_desc, MatchesStringValue(kReadvTestData)); } void ReadAllOneBuffer(int fd) { std::vector buffer(kReadvTestDataSize); ReadAllOneProvidedBuffer(fd, &buffer); } void ReadAllOneLargeBuffer(int fd) { std::vector buffer(10 * kReadvTestDataSize); ReadAllOneProvidedBuffer(fd, &buffer); } void ReadOneHalfAtATime(int fd) { int len0 = kReadvTestDataSize / 2; int len1 = kReadvTestDataSize - len0; std::vector buffer0(len0); std::vector buffer1(len1); struct iovec iovs[2]; iovs[0].iov_base = buffer0.data(); iovs[0].iov_len = len0; iovs[1].iov_base = buffer1.data(); iovs[1].iov_len = len1; ASSERT_THAT(readv(fd, iovs, 2), SyscallSucceedsWithValue(kReadvTestDataSize)); std::pair iovec_desc(iovs, 2); EXPECT_THAT(iovec_desc, MatchesStringLength(kReadvTestDataSize)); EXPECT_THAT(iovec_desc, MatchesStringValue(kReadvTestData)); } void ReadOneBufferPerByte(int fd) { std::vector buffer(kReadvTestDataSize); std::vector iovs(kReadvTestDataSize); char* buffer_ptr = buffer.data(); struct iovec* iovs_ptr = iovs.data(); for (int i = 0; i < static_cast(kReadvTestDataSize); i++) { struct iovec iov = { .iov_base = &buffer_ptr[i], .iov_len = 1, }; iovs_ptr[i] = iov; } ASSERT_THAT(readv(fd, iovs_ptr, kReadvTestDataSize), SyscallSucceedsWithValue(kReadvTestDataSize)); std::pair iovec_desc(iovs.data(), kReadvTestDataSize); EXPECT_THAT(iovec_desc, MatchesStringLength(kReadvTestDataSize)); EXPECT_THAT(iovec_desc, MatchesStringValue(kReadvTestData)); } void ReadBuffersOverlapping(int fd) { // overlap the first overlap_bytes. int overlap_bytes = 8; std::vector buffer(kReadvTestDataSize); // overlapping causes us to get more data. int expected_size = kReadvTestDataSize + overlap_bytes; std::vector expected(expected_size); char* expected_ptr = expected.data(); memcpy(expected_ptr, &kReadvTestData[overlap_bytes], overlap_bytes); memcpy(&expected_ptr[overlap_bytes], &kReadvTestData[overlap_bytes], kReadvTestDataSize); struct iovec iovs[2]; iovs[0].iov_base = buffer.data(); iovs[0].iov_len = overlap_bytes; iovs[1].iov_base = buffer.data(); iovs[1].iov_len = kReadvTestDataSize; ASSERT_THAT(readv(fd, iovs, 2), SyscallSucceedsWithValue(kReadvTestDataSize)); std::pair iovec_desc(iovs, 2); EXPECT_THAT(iovec_desc, MatchesStringLength(expected_size)); EXPECT_THAT(iovec_desc, MatchesStringValue(expected_ptr)); } void ReadBuffersDiscontinuous(int fd) { // Each iov is 1 byte separated by 1 byte. std::vector buffer(kReadvTestDataSize * 2); std::vector iovs(kReadvTestDataSize); char* buffer_ptr = buffer.data(); struct iovec* iovs_ptr = iovs.data(); for (int i = 0; i < static_cast(kReadvTestDataSize); i++) { struct iovec iov = { .iov_base = &buffer_ptr[i * 2], .iov_len = 1, }; iovs_ptr[i] = iov; } ASSERT_THAT(readv(fd, iovs_ptr, kReadvTestDataSize), SyscallSucceedsWithValue(kReadvTestDataSize)); std::pair iovec_desc(iovs.data(), kReadvTestDataSize); EXPECT_THAT(iovec_desc, MatchesStringLength(kReadvTestDataSize)); EXPECT_THAT(iovec_desc, MatchesStringValue(kReadvTestData)); } void ReadIovecsCompletelyFilled(int fd) { int half = kReadvTestDataSize / 2; std::vector buffer(kReadvTestDataSize); char* buffer_ptr = buffer.data(); memset(buffer.data(), '\0', kReadvTestDataSize); struct iovec iovs[2]; iovs[0].iov_base = buffer.data(); iovs[0].iov_len = half; iovs[1].iov_base = &buffer_ptr[half]; iovs[1].iov_len = half; ASSERT_THAT(readv(fd, iovs, 2), SyscallSucceedsWithValue(half * 2)); std::pair iovec_desc(iovs, 2); EXPECT_THAT(iovec_desc, MatchesStringLength(half * 2)); EXPECT_THAT(iovec_desc, MatchesStringValue(kReadvTestData)); char* str = static_cast(iovs[0].iov_base); str[iovs[0].iov_len - 1] = '\0'; ASSERT_EQ(half - 1, strlen(str)); } } // namespace testing } // namespace gvisor