You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mesos.apache.org by an...@apache.org on 2018/05/23 21:36:52 UTC

[08/10] mesos git commit: Windows: Ported `sendfile_tests.cpp`.

Windows: Ported `sendfile_tests.cpp`.

The `os::sendfile` unit tests were using `socketpair`, but the rest of
the tests were cross-platform. By providing a Windows `socketpair`
implementation, the tests are now ported.

Review: https://reviews.apache.org/r/66961/


Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/387364cf
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/387364cf
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/387364cf

Branch: refs/heads/master
Commit: 387364cf3128b77e1c944427247222019f983edf
Parents: 20beb52
Author: Akash Gupta <ak...@hotmail.com>
Authored: Wed May 23 14:04:03 2018 -0700
Committer: Andrew Schwartzmeyer <an...@schwartzmeyer.com>
Committed: Wed May 23 14:07:47 2018 -0700

----------------------------------------------------------------------
 3rdparty/stout/tests/CMakeLists.txt        |   4 +-
 3rdparty/stout/tests/os/sendfile_tests.cpp | 143 +++++++++++++++++++++++-
 2 files changed, 143 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/387364cf/3rdparty/stout/tests/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/3rdparty/stout/tests/CMakeLists.txt b/3rdparty/stout/tests/CMakeLists.txt
index 43c5e87..86111a8 100644
--- a/3rdparty/stout/tests/CMakeLists.txt
+++ b/3rdparty/stout/tests/CMakeLists.txt
@@ -70,11 +70,11 @@ set(STOUT_OS_TESTS_SRC
   os/process_tests.cpp
   os/rmdir_tests.cpp
   os/socket_tests.cpp
-  os/strerror_tests.cpp)
+  os/strerror_tests.cpp
+  os/sendfile_tests.cpp)
 
 if (NOT WIN32)
   list(APPEND STOUT_OS_TESTS_SRC
-    os/sendfile_tests.cpp
     # NOTE: There is no intention to port the functions exercised in
     # the following tests to Windows.
     os/signals_tests.cpp

http://git-wip-us.apache.org/repos/asf/mesos/blob/387364cf/3rdparty/stout/tests/os/sendfile_tests.cpp
----------------------------------------------------------------------
diff --git a/3rdparty/stout/tests/os/sendfile_tests.cpp b/3rdparty/stout/tests/os/sendfile_tests.cpp
index 05966ae..021ac7f 100644
--- a/3rdparty/stout/tests/os/sendfile_tests.cpp
+++ b/3rdparty/stout/tests/os/sendfile_tests.cpp
@@ -20,6 +20,13 @@
 #include <stout/os.hpp>
 #include <stout/path.hpp>
 
+#ifdef __WINDOWS__
+#include <stout/windows.hpp>
+#endif // __WINDOWS__
+
+#include <stout/os/sendfile.hpp>
+#include <stout/os/write.hpp>
+
 #include <stout/tests/utils.hpp>
 
 using std::string;
@@ -52,14 +59,98 @@ protected:
 };
 
 
+#ifdef __WINDOWS__
+// TODO(akagup): If it's necessary, we can have a more general version of this
+// function in a stout header, but `socketpair` isn't currently used in the
+// cross-platform parts of Mesos.
+Try<std::array<int_fd, 2>> socketpair()
+{
+  struct AutoFD {
+    int_fd fd;
+    ~AutoFD() {
+      os::close(fd);
+    }
+  };
+
+  const Try<int_fd> server_ = net::socket(AF_INET, SOCK_STREAM, 0);
+  if (server_.isError()) {
+    return Error(server_.error());
+  }
+  const AutoFD server{server_.get()};
+
+  sockaddr_in addr;
+  addr.sin_family = AF_INET;
+  addr.sin_port = 0;
+  addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+  if (net::bind(
+          server.fd,
+          reinterpret_cast<const sockaddr*>(&addr),
+          sizeof(addr)) != 0) {
+    return SocketError();
+  }
+
+  if (::listen(server.fd, 1) != 0) {
+    return SocketError();
+  }
+
+  int addrlen = sizeof(addr);
+  if (::getsockname(
+          server.fd, reinterpret_cast<sockaddr*>(&addr), &addrlen) != 0) {
+    return SocketError();
+  }
+
+  const Try<int_fd> client_ = net::socket(AF_INET, SOCK_STREAM, 0);
+  if (client_.isError()) {
+    return Error(client_.error());
+  }
+
+  // Don't use the `AutoFD` here, since we want to return this and not call
+  // the destructor.
+  const int_fd client = client_.get();
+
+  // `connect` won't block due to the listening server backlog.
+  if (net::connect(
+          client,
+          reinterpret_cast<const sockaddr*>(&addr),
+          sizeof(addr)) != 0) {
+    SocketError error;
+    os::close(client);
+    return error;
+  }
+
+  // Don't use the `AutoFD` here, since we want to return this and not call
+  // the destructor.
+  addrlen = sizeof(addr);
+  const int_fd accepted_client =
+    net::accept(server.fd, reinterpret_cast<sockaddr*>(&addr), &addrlen);
+
+  if (!accepted_client.is_valid()) {
+    SocketError error;
+    os::close(client);
+    return error;
+  }
+
+  return std::array<int_fd, 2>{ accepted_client, client };
+}
+#endif // __WINDOWS__
+
+
 TEST_F(OsSendfileTest, Sendfile)
 {
   Try<int_fd> fd = os::open(filename, O_RDONLY | O_CLOEXEC);
   ASSERT_SOME(fd);
 
   // Construct a socket pair and use sendfile to transmit the text.
-  int s[2];
+  int_fd s[2];
+#ifdef __WINDOWS__
+  Try<std::array<int_fd, 2>> s_ = socketpair();
+  ASSERT_SOME(s_);
+  s[0] = s_.get()[0];
+  s[1] = s_.get()[1];
+#else
   ASSERT_NE(-1, socketpair(AF_UNIX, SOCK_STREAM, 0, s)) << os::strerror(errno);
+#endif // __WINDOWS__
+
   Try<ssize_t, SocketError> length =
     os::sendfile(s[0], fd.get(), 0, LOREM_IPSUM.size());
   ASSERT_TRUE(length.isSome());
@@ -67,7 +158,7 @@ TEST_F(OsSendfileTest, Sendfile)
 
   char* buffer = new char[LOREM_IPSUM.size()];
   ASSERT_EQ(static_cast<ssize_t>(LOREM_IPSUM.size()),
-            read(s[1], buffer, LOREM_IPSUM.size()));
+            os::read(s[1], buffer, LOREM_IPSUM.size()));
   ASSERT_EQ(LOREM_IPSUM, string(buffer, LOREM_IPSUM.size()));
   ASSERT_SOME(os::close(fd.get()));
   delete[] buffer;
@@ -86,8 +177,56 @@ TEST_F(OsSendfileTest, Sendfile)
   ASSERT_EQ(EPIPE, _errno) << result.error().message;
 #elif defined __APPLE__
   ASSERT_EQ(ENOTCONN, _errno) << result.error().message;
+#elif defined __WINDOWS__
+  ASSERT_EQ(WSAECONNRESET, _errno) << result.error().message;
 #endif
 
   ASSERT_SOME(os::close(fd.get()));
+
+#ifdef __WINDOWS__
+  // On Windows, closing this socket results in the `WSACONNRESET` error.
+  ASSERT_ERROR(os::close(s[0]));
+#else
   ASSERT_SOME(os::close(s[0]));
+#endif // __WINDOWS__
+}
+
+#ifdef __WINDOWS__
+TEST_F(OsSendfileTest, SendfileAsync)
+{
+  const string testfile =
+    path::join(sandbox.get(), id::UUID::random().toString());
+
+  // We create a 1MB file, which should be too big for the socket
+  // buffers to hold, forcing us to go through the asynchronous path.
+  const Try<int_fd> fd = os::open(testfile, O_CREAT | O_TRUNC | O_RDWR);
+  string data(1024 * 1024, 'A');
+  ASSERT_SOME(fd);
+  ASSERT_SOME(os::write(fd.get(), data));
+  ASSERT_SOME(os::lseek(fd.get(), 0, SEEK_SET));
+
+  const Try<std::array<int_fd, 2>> s = socketpair();
+
+  // We are sending data, but the other side isn't reading, so we should get
+  // that the operation is pending.
+  OVERLAPPED overlapped = {};
+  const Result<size_t> length =
+    os::sendfile_async(s.get()[0], fd.get(), data.size(), &overlapped);
+
+  // NOTE: A pending operation is represented by None()
+  ASSERT_NONE(length);
+
+  const Result<string> result = os::read(s.get()[1], data.size());
+  ASSERT_SOME(result);
+  ASSERT_EQ(data, result.get());
+
+  DWORD sent = 0;
+  DWORD flags = 0;
+  ASSERT_TRUE(
+      ::WSAGetOverlappedResult(s.get()[0], &overlapped, &sent, TRUE, &flags));
+
+  EXPECT_SOME(os::close(fd.get()));
+  EXPECT_SOME(os::close(s.get()[0]));
+  EXPECT_SOME(os::close(s.get()[1]));
 }
+#endif // __WINDOWS__
\ No newline at end of file