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