Apache Mesos
windows.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_WINDOWS_HPP__
14 #define __STOUT_WINDOWS_HPP__
15 
16 // We include `WinSock2.h` before `Windows.h` explicitly to avoid symbol
17 // re-definitions. This is a documented pattern, because `Windows.h` will
18 // otherwise include `winsock.h` for "historical reasons". Note that
19 // `winsock.h` is for Windows Sockets 1.1, last used in Windows 2000.
20 //
21 // NOTE: The capitalization of these headers is based on the files
22 // included in the SDK, rather than MSDN documentation.
23 //
24 // https://msdn.microsoft.com/en-us/library/windows/desktop/ms738562(v=vs.85).aspx
25 // NOLINT(whitespace/line_length)
26 #include <WinSock2.h> // For Windows Sockets 2.
27 #include <WS2tcpip.h> // For `getaddrinfo` etc.
28 #include <iphlpapi.h> // For `GetAdaptersInfo`.
29 #include <MSWSock.h> // For `TransmitFile`.
30 #include <winioctl.h> // For `DeviceIoControl`
31 #include <Windows.h> // For everything else.
32 
33 #include <sys/stat.h> // For permissions flags.
34 
35 #include <basetsd.h> // For `SSIZE_T`.
36 
37 #include <memory>
38 #include <type_traits>
39 
40 #include <glog/logging.h>
41 
42 
43 #if !defined(_UNICODE) || !defined(UNICODE)
44 // Much of the Windows API is available both in `string` and `wstring`
45 // varieties. To avoid polluting the namespace with two versions of every
46 // function, a common pattern in the Windows headers is to offer a single macro
47 // that expands to the `string` or `wstring` version, depending on whether the
48 // `_UNICODE` and `UNICODE` preprocessor symbols are set. For example,
49 // `GetMessage` will expand to either `GetMessageA` (the `string` version) or
50 // `GetMessageW` (the `wstring` version) depending on whether these symbols are
51 // defined.
52 //
53 // Unfortunately the `string` version is not UTF-8, like a developer would
54 // expect on Linux, but is instead the current Windows code page, and thus may
55 // take a different value at runtime. This makes it potentially difficult to
56 // decode, whereas the `wstring` version is always encoded as UTF-16, and thus
57 // can be programatically converted to UTF-8 using the `stringify()` function
58 // (converting UTF-8 to UTF-16 is done with `wide_stringify()`).
59 //
60 // Furthermore, support for NTFS long paths requires the use of the `wstring`
61 // APIs, coupled with the `\\?\` long path prefix marker for paths longer than
62 // the max path limit. This is accomplished by wrapping paths sent to Windows
63 // APIs with the `internal::windows::longpath()` helper. In order to prevent
64 // future regressions, we enforce the definitions of `_UNICODE` and `UNICODE`.
65 //
66 // NOTE: The Mesos code should always use the explicit `W` suffixed APIs in
67 // order to avoid type ambiguity.
68 #error "Mesos must be built with `_UNICODE` and `UNICODE` defined."
69 #endif // !defined(_UNICODE) || !defined(UNICODE)
70 
71 // An RAII `HANDLE`.
72 class SharedHandle : public std::shared_ptr<void>
73 {
74  static_assert(std::is_same<HANDLE, void*>::value,
75  "Expected `HANDLE` to be of type `void*`.");
76 
77 public:
78  // We delete the default constructor so that the callsite is forced to make
79  // an explicit decision about what the empty `HANDLE` value should be, as it
80  // is not the same for all `HANDLE` types. For example, `OpenProcess`
81  // returns a `nullptr` for an invalid handle, but `CreateFile` returns an
82  // `INVALID_HANDLE_VALUE` instead. This inconsistency is inherent in the
83  // Windows API.
84  SharedHandle() = delete;
85 
86  template <typename Deleter>
87  SharedHandle(HANDLE handle, Deleter deleter)
88  : std::shared_ptr<void>(handle, deleter) {}
89 
90  HANDLE get_handle() const { return this->get(); }
91 };
92 
93 
94 // Definitions and constants used for Windows compat.
95 //
96 // Gathers most of the Windows-compatibility definitions. This makes it
97 // possible for files throughout the codebase to remain relatively free of all
98 // the #if's we'd need to make them work.
99 //
100 // Roughly, the things that should go in this file are definitions and
101 // declarations that one would not mind being:
102 // * in global scope.
103 // * globally available throughout both the Stout codebase, and any code
104 // that uses it (such as Mesos).
105 
106 
107 // This code un-defines the global `GetMessage` macro defined by the Windows
108 // headers, and replaces it with an inline function that is equivalent.
109 //
110 // There are two reasons for doing this. The first is because this macro
111 // interferes with `google::protobufs::Reflection::GetMessage`. Replacing the
112 // `GetMessage` macro with an inline function allows people calling the
113 // `GetMessage` macro to carry on doing so with no code changes, but it will
114 // also allow us to use `google::protobufs::Reflection::GetMessage` without
115 // interference from the macro.
116 //
117 // The second is because we don't want to obliterate the `GetMessage` macro for
118 // people who include this header, either on purpose, or incidentally as part
119 // of some other Mesos header. The effect is that our need to call protobuf's
120 // `GetMessage` function has no deleterious effect on customers of this API.
121 //
122 // NOTE: the Windows headers also don't use define-once semantics for the
123 // `GetMessage` macro. In particular, this means that every time you include
124 // `Winuser.h` and a `GetMessage` macro isn't defined, the Windows headers will
125 // redefine it for you. The impact of this is that you should re-un-define the
126 // macro every time you include `Windows.h`; since we should be including
127 // `Windows.h` only from this file, we un-define it just after we include
128 // `Windows.h`.
129 #ifdef GetMessage
130 inline BOOL GetMessageWindows(
131  LPMSG lpMsg,
132  HWND hWnd,
133  UINT wMsgFilterMin,
134  UINT wMsgFilterMax)
135 {
136  return GetMessage(lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax);
137 }
138 #undef GetMessage
139 inline BOOL GetMessage(
140  LPMSG lpMsg,
141  HWND hWnd,
142  UINT wMsgFilterMin,
143  UINT wMsgFilterMax)
144 {
145  return GetMessageWindows(lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax);
146 }
147 #endif // GetMessage
148 
149 
150 // Define constants used for Windows compat. Allows a lot of code on
151 // Windows and POSIX systems to be the same, because we can pass the
152 // same constants to functions we call to do things like file I/O.
153 #define STDIN_FILENO 0
154 #define STDOUT_FILENO 1
155 #define STDERR_FILENO 2
156 
157 #define R_OK 0x4
158 #define W_OK 0x2
159 #define X_OK 0x0 // No such permission on Windows.
160 #define F_OK 0x0
161 
162 #define MAXHOSTNAMELEN NI_MAXHOST
163 
164 #define PATH_MAX _MAX_PATH
165 
166 // NOTE: for details on what this value should be, consult [1], [2], and [3].
167 //
168 // [1] http://www.opensource.apple.com/source/gnumake/gnumake-119/make/w32/include/dirent.h
169 // [2] https://en.wikipedia.org/wiki/Comparison_of_file_systems#Limits
170 // [3] https://msdn.microsoft.com/en-us/library/930f87yf.aspx
171 const int NAME_MAX = PATH_MAX;
172 
173 // Corresponds to `mode_t` defined in sys/types.h of the POSIX spec.
174 // See large "permissions API" comment below for an explanation of
175 // why this is an int instead of unsigned short (as is common on
176 // POSIX).
177 typedef int mode_t;
178 
179 // `DWORD` is expected to be the type holding PIDs throughout the Windows API,
180 // including functions like `OpenProcess`.
181 typedef DWORD pid_t;
182 
183 typedef UINT uid_t;
184 typedef UINT gid_t;
185 
186 typedef SSIZE_T ssize_t;
187 
188 // Socket flags. Define behavior of a socket when it (e.g.) shuts down. We map
189 // the Windows versions of these flags to their POSIX equivalents so we don't
190 // have to change any socket code.
191 constexpr int SHUT_RD = SD_RECEIVE;
192 constexpr int SHUT_WR = SD_SEND;
193 constexpr int SHUT_RDWR = SD_BOTH;
194 constexpr int MSG_NOSIGNAL = 0; // `SIGPIPE` signal does not exist on Windows.
195 
196 // The following functions are usually macros on POSIX; we provide them here as
197 // functions to avoid having global macros lying around. Note that these
198 // operate on the `_stat` struct (a Windows version of the standard POSIX
199 // `stat` struct), of which the `st_mode` field is known to be an `int`.
200 inline bool S_ISDIR(const int mode)
201 {
202  return (mode & S_IFMT) == S_IFDIR; // Directory.
203 }
204 
205 
206 inline bool S_ISREG(const int mode)
207 {
208  return (mode & S_IFMT) == S_IFREG; // File.
209 }
210 
211 
212 inline bool S_ISCHR(const int mode)
213 {
214  return (mode & S_IFMT) == S_IFCHR; // Character device.
215 }
216 
217 
218 inline bool S_ISFIFO(const int mode)
219 {
220  return (mode & S_IFMT) == _S_IFIFO; // Pipe.
221 }
222 
223 
224 inline bool S_ISBLK(const int mode)
225 {
226  return false; // Block special device.
227 }
228 
229 
230 inline bool S_ISSOCK(const int mode)
231 {
232  return false; // Socket.
233 }
234 
235 
236 inline bool S_ISLNK(const int mode)
237 {
238  return false; // Symbolic link.
239 }
240 
241 // Permissions API. (cf. MESOS-3176 to track ongoing permissions work.)
242 //
243 // We are currently able to emulate a subset of the POSIX permissions model
244 // with the Windows model:
245 // [x] User write permissions.
246 // [x] User read permissions.
247 // [ ] User execute permissions.
248 // [ ] Group permissions of any sort.
249 // [ ] Other permissions of any sort.
250 // [x] Flags to control "fallback" behavior (e.g., we might choose
251 // to fall back to user readability when the user passes the
252 // group readability flag in, since we currently do not support
253 // group readability).
254 //
255 //
256 // Rationale:
257 // Windows currently implements two permissions models: (1) an extremely
258 // primitive permission model it largely inherited from DOS, and (2) the Access
259 // Control List (ACL) API. Because there is no trivial way to map the classic
260 // POSIX model into the ACL model, we have implemented POSIX-style permissions
261 // in terms of the DOS model. The result is the permissions limitations above.
262 //
263 //
264 // Flag implementation:
265 // Flags fall into the following two categories.
266 // (1) Flags which exist in both permission models, but which have
267 // different names (e.g., `S_IRUSR` in POSIX is called `_S_IREAD` on
268 // Windows). In this case, we define the POSIX name to be the Windows
269 // value (e.g., we define `S_IRUSR` to have the same value as `_S_IREAD`),
270 // so that we can pass the POSIX name into Windows functions like
271 // `_open`.
272 // (2) Flags which exist only on POSIX (e.g., `S_IXUSR`). Here we
273 // define the POSIX name to be the value given in the glibc
274 // documentation[1], shifted left by 16 bits (since `mode_t`
275 // is unsigned short on POSIX and `int` on Windows). We give these
276 // flags glibc values to stay consistent, and so that existing
277 // calls to functions like `open` do not break when they try to
278 // use a flag that doesn't exist on Windows. But, of course,
279 // these flags do not affect the execution of these functions.
280 //
281 //
282 // Flag strictness:
283 // Because the current implementation does not directly support setting or
284 // getting group or other permission bits on the Windows platform, there is a
285 // question of what we should fall back to when these flags are passed in to
286 // Stout methods.
287 //
288 // TODO(hausdorff): Investigate permissions mappings.
289 // We force "strictness" of the permission flag semantics:
290 // * The group permissions flags will not fall back to anything, and will be
291 // completely ignored.
292 // * Other permissions: Same as above, but with other permissions.
293 //
294 //
295 // Execute permissions:
296 // Because DOS has no notion of "execute permissions", we define execute
297 // permissions to be read permissions. This is not ideal, but it is closest to
298 // being accurate.
299 //
300 //
301 // [1] http://www.delorie.com/gnu/docs/glibc/libc_288.html
302 
303 
304 // User permission flags.
305 const mode_t S_IRUSR = mode_t(_S_IREAD); // Readable by user.
306 const mode_t S_IWUSR = mode_t(_S_IWRITE); // Writeable by user.
307 const mode_t S_IXUSR = S_IRUSR; // Fallback to user read.
309 
310 
311 // Group permission flags. Lossy mapping to Windows permissions. See
312 // note above about flag strictness for explanation.
313 const mode_t S_IRGRP = 0x00200000; // No-op.
314 const mode_t S_IWGRP = 0x00100000; // No-op.
315 const mode_t S_IXGRP = 0x00080000; // No-op.
317 
318 
319 // Other permission flags. Lossy mapping to Windows permissions. See
320 // note above about flag stictness for explanation.
321 const mode_t S_IROTH = 0x00040000; // No-op.
322 const mode_t S_IWOTH = 0x00020000; // No-op.
323 const mode_t S_IXOTH = 0x00010000; // No-op.
325 
326 
327 // Flags for set-ID-on-exec.
328 const mode_t S_ISUID = 0x08000000; // No-op.
329 const mode_t S_ISGID = 0x04000000; // No-op.
330 const mode_t S_ISVTX = 0x02000000; // No-op.
331 
332 // Even though SIGKILL doesn't exist on Windows, we define
333 // it here, because Docker defines it. So, the docker
334 // executor needs this signal value to properly kill containers.
335 const mode_t SIGKILL = 0x00000009; // Signal Kill.
336 
337 inline auto strerror_r(int errnum, char* buffer, size_t length) ->
338 decltype(strerror_s(buffer, length, errnum))
339 {
340  return strerror_s(buffer, length, errnum);
341 }
342 
343 
344 // NOTE: Signals do not exist on Windows, so all signals are unknown.
345 // If the signal number is unknown, the Posix specification leaves the
346 // return value of `strsignal` unspecified.
347 inline const char* strsignal(int signum)
348 {
349  static const char UNKNOWN_STRSIGNAL[] = "Unknown signal";
350  return UNKNOWN_STRSIGNAL;
351 }
352 
353 
354 #define SIGPIPE 100
355 
356 // On Windows, the exit code, unlike Linux, is simply a 32 bit unsigned integer
357 // with no special encoding. Since the `status` value from `waitpid` returns a
358 // 32 bit integer, we can't use it to determine if the process exited normally,
359 // because all the possibilities could be valid exit codes. So, we assume that
360 // if we get an exit code, the process exited normally.
361 #ifndef WIFEXITED
362 #define WIFEXITED(x) true
363 #endif // WIFEXITED
364 
365 // Returns the exit status of the child.
366 // On Windows, they are a 32 bit unsigned integer.
367 #ifndef WEXITSTATUS
368 #define WEXITSTATUS(x) static_cast<DWORD>(x)
369 #endif // WEXITSTATUS
370 
371 // A signaled Windows process always exits with status code 3, but it's
372 // impossible to distinguish that from a process that exits normally with
373 // status code 3. Since signals aren't really used on Windows, we will
374 // assume that the process is not signaled.
375 #ifndef WIFSIGNALED
376 #define WIFSIGNALED(x) false
377 #endif // WIFSIGNALED
378 
379 // Specifies that `::waitpid` should return immediately rather than
380 // blocking and waiting for child to notify of state change.
381 #ifndef WNOHANG
382 #define WNOHANG 1
383 #endif // WNOHANG
384 
385 #endif // __STOUT_WINDOWS_HPP__
SharedHandle(HANDLE handle, Deleter deleter)
Definition: windows.hpp:87
SSIZE_T ssize_t
Definition: windows.hpp:186
const mode_t S_IXOTH
Definition: windows.hpp:323
const mode_t S_IRGRP
Definition: windows.hpp:313
UINT uid_t
Definition: windows.hpp:183
bool S_ISDIR(const int mode)
Definition: windows.hpp:200
HANDLE get_handle() const
Definition: windows.hpp:90
Definition: windows.hpp:72
const mode_t SIGKILL
Definition: windows.hpp:335
const mode_t S_IWUSR
Definition: windows.hpp:306
const char * strsignal(int signum)
Definition: windows.hpp:347
bool S_ISSOCK(const int mode)
Definition: windows.hpp:230
Definition: type_utils.hpp:619
bool S_ISREG(const int mode)
Definition: windows.hpp:206
constexpr int SHUT_RDWR
Definition: windows.hpp:193
const mode_t S_IRUSR
Definition: windows.hpp:305
bool S_ISFIFO(const int mode)
Definition: windows.hpp:218
const int NAME_MAX
Definition: windows.hpp:171
const mode_t S_IRWXO
Definition: windows.hpp:324
const mode_t S_ISVTX
Definition: windows.hpp:330
DWORD pid_t
Definition: windows.hpp:181
int mode_t
Definition: windows.hpp:177
const mode_t S_IXGRP
Definition: windows.hpp:315
SharedHandle()=delete
constexpr Handle HANDLE
Definition: ingress.hpp:37
auto strerror_r(int errnum, char *buffer, size_t length) -> decltype(strerror_s(buffer, length, errnum))
Definition: windows.hpp:337
const mode_t S_IXUSR
Definition: windows.hpp:307
#define PATH_MAX
Definition: windows.hpp:164
bool S_ISBLK(const int mode)
Definition: windows.hpp:224
const mode_t S_IRWXU
Definition: windows.hpp:308
const mode_t S_IWGRP
Definition: windows.hpp:314
const mode_t S_ISUID
Definition: windows.hpp:328
const mode_t S_IRWXG
Definition: windows.hpp:316
constexpr int MSG_NOSIGNAL
Definition: windows.hpp:194
bool S_ISLNK(const int mode)
Definition: windows.hpp:236
Try< mode_t > mode(const std::string &path, const FollowSymlink follow=FollowSymlink::FOLLOW_SYMLINK)
Definition: stat.hpp:168
const mode_t S_IWOTH
Definition: windows.hpp:322
constexpr int SHUT_RD
Definition: windows.hpp:191
const mode_t S_ISGID
Definition: windows.hpp:329
bool S_ISCHR(const int mode)
Definition: windows.hpp:212
const mode_t S_IROTH
Definition: windows.hpp:321
constexpr int SHUT_WR
Definition: windows.hpp:192
UINT gid_t
Definition: windows.hpp:184