Apache Mesos
read.hpp
Go to the documentation of this file.
1 // Licensed under the Apache License, Version 2.0 (the "License");
2 // you may not use this file except in compliance with the License.
3 // You may obtain a copy of the License at
4 //
5 // http://www.apache.org/licenses/LICENSE-2.0
6 //
7 // Unless required by applicable law or agreed to in writing, software
8 // distributed under the License is distributed on an "AS IS" BASIS,
9 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 // See the License for the specific language governing permissions and
11 // limitations under the License.
12 
13 #ifndef __STOUT_OS_WINDOWS_READ_HPP__
14 #define __STOUT_OS_WINDOWS_READ_HPP__
15 
16 #include <stout/result.hpp>
17 #include <stout/unreachable.hpp>
18 #include <stout/windows.hpp>
19 
21 
22 #include <stout/os/int_fd.hpp>
23 #include <stout/os/socket.hpp>
24 
25 namespace os {
26 
27 // Asynchronous read on a overlapped int_fd. Returns `Error` on fatal errors,
28 // `None()` on a successful pending IO operation or number of bytes read on a
29 // successful IO operation that finished immediately.
31  const int_fd& fd,
32  void* data,
33  size_t size,
34  OVERLAPPED* overlapped)
35 {
36  CHECK_LE(size, UINT_MAX);
37 
38  switch (fd.type()) {
40  DWORD bytes;
41  const bool success =
42  ::ReadFile(fd, data, static_cast<DWORD>(size), &bytes, overlapped);
43 
44  // On failure, there are two EOF cases for reads:
45  // 1) ERROR_BROKEN_PIPE: The write end is closed and there is no data.
46  // 2) ERROR_HANDLE_EOF: We hit the EOF for an asynchronous file handle.
47  const DWORD errorCode = ::GetLastError();
48  if (success == FALSE &&
49  (errorCode == ERROR_BROKEN_PIPE || errorCode == ERROR_HANDLE_EOF)) {
50  return 0;
51  }
52 
54  }
56  static_assert(
57  std::is_same<OVERLAPPED, WSAOVERLAPPED>::value,
58  "Expected `WSAOVERLAPPED` to be of type `OVERLAPPED`.");
59 
60  // Note that it's okay to allocate this on the stack, since the WinSock
61  // providers must copy the WSABUF to their internal buffers. See
62  // https://msdn.microsoft.com/en-us/library/windows/desktop/ms741688(v=vs.85).aspx // NOLINT(whitespace/line_length)
63  WSABUF buf = {
64  static_cast<u_long>(size),
65  static_cast<char*>(data)
66  };
67 
68  DWORD bytes;
69  DWORD flags = 0;
70  const int result =
71  ::WSARecv(fd, &buf, 1, &bytes, &flags, overlapped, nullptr);
72 
74  }
75  }
76 
77  UNREACHABLE();
78 }
79 
80 
81 // Synchronous reads on any int_fd. Returns -1 on error and
82 // number of bytes read on success.
83 inline ssize_t read(const int_fd& fd, void* data, size_t size)
84 {
85  CHECK_LE(size, UINT_MAX);
86 
87  switch (fd.type()) {
89  // Handle non-overlapped case. We just use the regular `ReadFile` since
90  // seekable overlapped files require an offset, which we don't track.
91  if (!fd.is_overlapped()) {
92  DWORD bytes;
93  const BOOL result =
94  ::ReadFile(fd, data, static_cast<DWORD>(size), &bytes, nullptr);
95 
96  if (result == FALSE) {
97  // The pipe "breaks" when the other process closes its handle, but we
98  // still have the data and therefore do not want to return an error.
99  if (::GetLastError() != ERROR_BROKEN_PIPE) {
100  // Indicates an error, but we can't return a `WindowsError`.
101  return -1;
102  }
103  }
104 
105  return static_cast<ssize_t>(bytes);
106  }
107 
108  // Asynchronous handle, we can use the `read_async` function
109  // and then wait on the overlapped object for a synchronous read.
110  Try<OVERLAPPED> overlapped_ =
112 
113  if (overlapped_.isError()) {
114  return -1;
115  }
116 
117  OVERLAPPED overlapped = overlapped_.get();
118  Result<size_t> result = read_async(fd, data, size, &overlapped);
119 
120  if (result.isError()) {
121  return -1;
122  }
123 
124  if (result.isSome()) {
125  return result.get();
126  }
127 
128  // IO is pending, so wait for the overlapped object.
129  DWORD bytes;
130  const BOOL wait_success =
131  ::GetOverlappedResult(fd, &overlapped, &bytes, TRUE);
132 
133  if (wait_success == TRUE) {
134  return bytes;
135  }
136 
137  // On failure, there are two EOF cases for reads:
138  // 1) ERROR_BROKEN_PIPE: The write end is closed and there is no data.
139  // 2) ERROR_HANDLE_EOF: We hit the EOF for an asynchronous file handle.
140  const DWORD error = ::GetLastError();
141  if (error == ERROR_BROKEN_PIPE || error == ERROR_HANDLE_EOF) {
142  return 0;
143  }
144 
145  return -1;
146  }
148  return ::recv(fd, (char*)data, static_cast<unsigned int>(size), 0);
149  }
150  }
151 
152  UNREACHABLE();
153 }
154 
155 } // namespace os {
156 
157 #endif // __STOUT_OS_WINDOWS_READ_HPP__
SSIZE_T ssize_t
Definition: windows.hpp:186
Try< Bytes > size(const std::string &path, const FollowSymlink follow=FollowSymlink::FOLLOW_SYMLINK)
Definition: stat.hpp:130
T & get()&
Definition: try.hpp:80
Definition: check.hpp:33
Try< OVERLAPPED > init_overlapped_for_sync_io()
Definition: overlapped.hpp:30
Result< size_t > process_async_io_result(bool successful_return_code, size_t bytes_transfered)
Definition: overlapped.hpp:71
Definition: posix_signalhandler.hpp:23
Future< size_t > recv(const int_fd &fd, void *buf, size_t size)
Definition: check.hpp:30
#define UNREACHABLE()
Definition: unreachable.hpp:22
Result< size_t > read_async(const int_fd &fd, void *data, size_t size, OVERLAPPED *overlapped)
Definition: read.hpp:30
Result< std::string > read(int_fd fd, size_t size)
Definition: read.hpp:55
bool isError() const
Definition: try.hpp:78
std::string error(const std::string &msg, uint32_t code)
T & get()&
Definition: result.hpp:116
bool isSome() const
Definition: result.hpp:112
bool isError() const
Definition: result.hpp:114
int int_fd
Definition: int_fd.hpp:35
Definition: parse.hpp:33