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