Apache Mesos
pipe.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_PIPE_HPP__
14 #define __STOUT_OS_WINDOWS_PIPE_HPP__
15 
16 #include <array>
17 #include <string>
18 
19 #include <stout/check.hpp>
20 #include <stout/error.hpp>
21 #include <stout/try.hpp>
22 #include <stout/uuid.hpp>
23 #include <stout/windows.hpp> // For `windows.h`.
24 
25 #include <stout/os/int_fd.hpp>
26 
27 namespace os {
28 
29 // Returns an "anonymous" pipe that can be used for interprocess communication.
30 // Since anonymous pipes do not support overlapped IO, we emulate it with an
31 // uniquely named pipe.
32 //
33 // NOTE: Overlapped pipes passed to child processes behave weirdly, so we have
34 // the ability to create non overlapped pipe handles.
36  bool read_overlapped = true, bool write_overlapped = true)
37 {
38  const DWORD read_flags = read_overlapped ? FILE_FLAG_OVERLAPPED : 0;
39  const DWORD write_flags = write_overlapped ? FILE_FLAG_OVERLAPPED : 0;
40  std::wstring name =
41  wide_stringify("\\\\.\\pipe\\mesos-pipe-" + id::UUID::random().toString());
42 
43  // The named pipe name must be at most 256 characters [1]. It doesn't say if
44  // it includes the null terminator, so we limit to 255 to be safe. Since the
45  // UUID name is fixed length, this is just a sanity check.
46  //
47  // [1] https://msdn.microsoft.com/en-us/library/windows/desktop/aa365150(v=vs.85).aspx // NOLINT(whitespace/line_length)
48  CHECK_LE(name.size(), 255);
49 
50  // Create the named pipe. To avoid the time-of-check vs time-of-use attack,
51  // we have the `FILE_FLAG_FIRST_PIPE_INSTANCE` flag to fail if the pipe
52  // already exists.
53  //
54  // TODO(akagup): The buffer size is currently required, since we don't have
55  // IOCP yet. When testing IOCP, it should be 0, but after that, we can try
56  // restoring the buffer for an optimization.
57  const HANDLE read_handle = ::CreateNamedPipeW(
58  name.data(),
59  PIPE_ACCESS_INBOUND | FILE_FLAG_FIRST_PIPE_INSTANCE | read_flags,
60  PIPE_TYPE_BYTE | PIPE_WAIT | PIPE_REJECT_REMOTE_CLIENTS,
61  1, // Max pipe instances.
62  4096, // Inbound buffer size.
63  4096, // Outbound buffer size.
64  0, // Pipe timeout for connections.
65  nullptr); // Security attributes (not inheritable).
66 
67  if (read_handle == INVALID_HANDLE_VALUE) {
68  return WindowsError();
69  }
70 
71  // To create a client named pipe, we use the generic `CreateFile` API. We
72  // don't use the other named pipe APIs, since they are used for different
73  // purposes. For example, `ConnectNamedPipe` is similar to a server calling
74  // `accept` for sockets and `CallNamedPipe` is used for message type pipes,
75  // but we want a byte stream pipe.
76  //
77  // See https://msdn.microsoft.com/en-us/library/windows/desktop/aa365598%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396 // NOLINT(whitespace/line_length)
78  const HANDLE write_handle = ::CreateFileW(
79  name.data(),
80  GENERIC_WRITE,
81  0,
82  nullptr,
83  OPEN_EXISTING,
84  FILE_ATTRIBUTE_NORMAL | write_flags,
85  nullptr);
86 
87  const WindowsError error;
88  if (write_handle == INVALID_HANDLE_VALUE) {
89  ::CloseHandle(read_handle);
90  return error;
91  }
92 
93  return std::array<int_fd, 2>{int_fd(read_handle, read_overlapped),
94  int_fd(write_handle, write_overlapped)};
95 }
96 
97 } // namespace os {
98 
99 #endif // __STOUT_OS_WINDOWS_PIPE_HPP__
Try< std::array< int, 2 > > pipe()
Definition: pipe.hpp:33
Definition: check.hpp:33
Definition: error.hpp:108
Definition: posix_signalhandler.hpp:23
static UUID random()
Definition: uuid.hpp:38
constexpr Handle HANDLE
Definition: ingress.hpp:37
std::string error(const std::string &msg, uint32_t code)
int int_fd
Definition: int_fd.hpp:35
constexpr const char * name
Definition: shell.hpp:43