Apache Mesos
error.hpp
Go to the documentation of this file.
1 // Licensed to the Apache Software Foundation (ASF) under one
2 // or more contributor license agreements. See the NOTICE file
3 // distributed with this work for additional information
4 // regarding copyright ownership. The ASF licenses this file
5 // to you under the Apache License, Version 2.0 (the
6 // "License"); you may not use this file except in compliance
7 // with the License. You may obtain a copy of the License at
8 //
9 // http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 
17 #ifndef __STOUT_WINDOWS_ERROR_HPP__
18 #define __STOUT_WINDOWS_ERROR_HPP__
19 
20 #include <stout/errorbase.hpp>
21 #include <stout/windows.hpp>
22 
23 // A useful type that can be used to represent a Try that has failed. This is a
24 // lot like `ErrnoError`, except instead of wrapping an error coming from the C
25 // standard libraries, it wraps an error coming from the Windows APIs.
26 class WindowsErrorBase : public Error
27 {
28 public:
29  const DWORD code;
30 
31 protected:
32  explicit WindowsErrorBase(DWORD _code)
33  : Error(get_last_error_as_string(_code)), code(_code) {}
34 
35  WindowsErrorBase(DWORD _code, const std::string& message)
36  : Error(message + ": " + get_last_error_as_string(_code)), code(_code) {}
37 
38 private:
39  static std::string get_last_error_as_string(const DWORD error_code)
40  {
41  // NOTE: While Windows does have a corresponding message string
42  // for an error code of zero, we want the default construction to
43  // have as low a cost as possible, so we short circuit here.
44  if (error_code == 0) {
45  return std::string();
46  }
47 
48  const DWORD flags = FORMAT_MESSAGE_ALLOCATE_BUFFER |
49  FORMAT_MESSAGE_FROM_SYSTEM |
50  FORMAT_MESSAGE_IGNORE_INSERTS;
51 
52  const DWORD default_language = MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT);
53 
54  // This following function `FormatMessage` is a lot like `strerror`, except
55  // it pretty-prints errors from the Windows API instead of from the C
56  // standard library. Basically, the semantics are: we pass in `error_code`,
57  // and it allocates room for a pretty-printed error message at
58  // `message_buffer`, and then dumps said pretty-printed error message at
59  // that address, in our `default_language`.
60  //
61  // The parameter `reinterpret_cast<char*>(&message_buffer)` may
62  // look strange to readers of this code. It is copied directly out
63  // of the documentation[1], and is unfortunately required to get
64  // the pretty-printed error message. The short story is:
65  //
66  // * The flag `FORMAT_MESSAGE_ALLOCATE_BUFFER` tells `FormatMessage` to
67  // point `message_buffer` (which is an `LPSTR` a.k.a. `char*`) at a
68  // string error message. But, `message_buffer` to point a `char*` at a
69  // different place, `FormatMessage` would need the address
70  // `&message_buffer` so that it could change where it is pointing.
71  // * So, to solve this problem, the API writers decided that when you
72  // pass that flag in, `FormatMessage` will treat the fifth parameter not
73  // as `LPSTR` (which is what the type is in the function signagure),
74  // but as `LPSTR*` a.k.a. `char**`, which (assuming you've casted the
75  // parameter correctly) allows it to allocate the message on your
76  // behalf, and change `message_buffer` to point at this new error
77  // string.
78  // * This is why we need this strange cast that you see below.
79  //
80  // Finally, and this is important: it is up to the user to free the memory
81  // with `LocalFree`! The line below where we do this comes directly from
82  // the documentation as well.
83  //
84  // [1] https://msdn.microsoft.com/en-us/library/windows/desktop/ms679351(v=vs.85).aspx
85  char* message_buffer = nullptr;
86  // NOTE: This explicitly uses the non-Unicode version of the API
87  // so we can avoid needing Unicode conversion logic in the
88  // `WindowsErrorBase` class.
89  size_t size = ::FormatMessageA(
90  flags,
91  nullptr, // Ignored.
92  error_code,
93  default_language,
94  reinterpret_cast<char*>(&message_buffer),
95  0, // Ignored.
96  nullptr); // Ignored.
97 
98  std::string message(message_buffer, size);
99 
100  // Required per documentation above.
101  ::LocalFree(message_buffer);
102 
103  return message;
104  }
105 };
106 
107 
109 {
110 public:
111  WindowsError() : WindowsErrorBase(::GetLastError()) {}
112 
113  explicit WindowsError(DWORD _code) : WindowsErrorBase(_code) {}
114 
115  WindowsError(const std::string& message)
116  : WindowsErrorBase(::GetLastError(), message) {}
117 
118  WindowsError(DWORD _code, const std::string& message)
119  : WindowsErrorBase(_code, message) {}
120 };
121 
122 
124 {
125 public:
126  WindowsSocketError() : WindowsErrorBase(::WSAGetLastError()) {}
127 
128  explicit WindowsSocketError(DWORD _code) : WindowsErrorBase(_code) {}
129 
130  WindowsSocketError(const std::string& message)
131  : WindowsErrorBase(::WSAGetLastError(), message) {}
132 
133  WindowsSocketError(DWORD _code, const std::string& message)
134  : WindowsErrorBase(_code, message) {}
135 };
136 
137 #endif // __STOUT_WINDOWS_ERROR_HPP__
Definition: errorbase.hpp:36
Try< Bytes > size(const std::string &path, const FollowSymlink follow=FollowSymlink::FOLLOW_SYMLINK)
Definition: stat.hpp:121
WindowsErrorBase(DWORD _code, const std::string &message)
Definition: error.hpp:35
WindowsError(DWORD _code, const std::string &message)
Definition: error.hpp:118
WindowsSocketError()
Definition: error.hpp:126
Definition: error.hpp:123
Definition: error.hpp:108
WindowsError(DWORD _code)
Definition: error.hpp:113
const DWORD code
Definition: error.hpp:29
WindowsSocketError(DWORD _code)
Definition: error.hpp:128
WindowsSocketError(DWORD _code, const std::string &message)
Definition: error.hpp:133
Definition: error.hpp:26
WindowsSocketError(const std::string &message)
Definition: error.hpp:130
WindowsError()
Definition: error.hpp:111
const std::string message
Definition: errorbase.hpp:46
WindowsError(const std::string &message)
Definition: error.hpp:115
WindowsErrorBase(DWORD _code)
Definition: error.hpp:32
Definition: parse.hpp:33