OpenTTD Source  20241121-master-g67a0fccfad
os_abstraction.cpp
Go to the documentation of this file.
1 /*
2  * This file is part of OpenTTD.
3  * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4  * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
6  */
7 
19 #include "stdafx.h"
20 #include "os_abstraction.h"
21 #include "../../string_func.h"
22 #include "../../3rdparty/fmt/format.h"
23 #include <mutex>
24 
25 #include "../../safeguards.h"
26 
31 NetworkError::NetworkError(int error) : error(error)
32 {
33 }
34 
40 {
41 #if defined(_WIN32)
42  return this->error == WSAEWOULDBLOCK;
43 #else
44  /* Usually EWOULDBLOCK and EAGAIN are the same, but sometimes they are not
45  * and the POSIX.1 specification states that either should be checked. */
46  return this->error == EWOULDBLOCK || this->error == EAGAIN;
47 #endif
48 }
49 
55 {
56 #if defined(_WIN32)
57  return this->error == WSAECONNRESET;
58 #else
59  return this->error == ECONNRESET;
60 #endif
61 }
62 
68 {
69 #if defined(_WIN32)
70  return this->error == WSAEWOULDBLOCK;
71 #else
72  return this->error == EINPROGRESS;
73 #endif
74 }
75 
80 const std::string &NetworkError::AsString() const
81 {
82  if (this->message.empty()) {
83 #if defined(_WIN32)
84  wchar_t buffer[512];
85  if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr, this->error,
86  MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buffer, static_cast<DWORD>(std::size(buffer)), nullptr) == 0) {
87  this->message.assign(fmt::format("Unknown error {}", this->error));
88  } else {
89  this->message.assign(FS2OTTD(buffer));
90  }
91 #else
92  /* Make strerror thread safe by locking access to it. There is a thread safe strerror_r, however
93  * the non-POSIX variant is available due to defining _GNU_SOURCE meaning it is not portable.
94  * The problem with the non-POSIX variant is that it does not necessarily fill the buffer with
95  * the error message but can also return a pointer to a static bit of memory, whereas the POSIX
96  * variant always fills the buffer. This makes the behaviour too erratic to work with. */
97  static std::mutex mutex;
98  std::lock_guard<std::mutex> guard(mutex);
99  this->message.assign(strerror(this->error));
100 #endif
101  }
102  return this->message;
103 }
104 
110 {
111  return this->error != 0;
112 }
113 
119 {
120 #if defined(_WIN32)
121  return NetworkError(WSAGetLastError());
122 #else
123  return NetworkError(errno);
124 #endif
125 }
126 
127 
133 bool SetNonBlocking([[maybe_unused]] SOCKET d)
134 {
135 #if defined(_WIN32)
136  u_long nonblocking = 1;
137  return ioctlsocket(d, FIONBIO, &nonblocking) == 0;
138 #elif defined __EMSCRIPTEN__
139  return true;
140 #else
141  int nonblocking = 1;
142  return ioctl(d, FIONBIO, &nonblocking) == 0;
143 #endif
144 }
145 
151 bool SetNoDelay([[maybe_unused]] SOCKET d)
152 {
153 #ifdef __EMSCRIPTEN__
154  return true;
155 #else
156  int flags = 1;
157  /* The (const char*) cast is needed for windows */
158  return setsockopt(d, IPPROTO_TCP, TCP_NODELAY, (const char *)&flags, sizeof(flags)) == 0;
159 #endif
160 }
161 
167 bool SetReusePort(SOCKET d)
168 {
169 #ifdef _WIN32
170  /* Windows has no SO_REUSEPORT, but for our usecases SO_REUSEADDR does the same job. */
171  int reuse_port = 1;
172  return setsockopt(d, SOL_SOCKET, SO_REUSEADDR, (const char *)&reuse_port, sizeof(reuse_port)) == 0;
173 #else
174  int reuse_port = 1;
175  return setsockopt(d, SOL_SOCKET, SO_REUSEPORT, &reuse_port, sizeof(reuse_port)) == 0;
176 #endif
177 }
178 
185 {
186  int err;
187  socklen_t len = sizeof(err);
188  getsockopt(d, SOL_SOCKET, SO_ERROR, (char *)&err, &len);
189 
190  return NetworkError(err);
191 }
Abstraction of a network error where all implementation details of the error codes are encapsulated i...
bool WouldBlock() const
Check whether this error describes that the operation would block.
bool IsConnectInProgress() const
Check whether this error describes a connect is in progress.
int error
The underlying error number from errno or WSAGetLastError.
bool HasError() const
Check whether an error was actually set.
bool IsConnectionReset() const
Check whether this error describes a connection reset.
std::string message
The string representation of the error (set on first call to AsString).
const std::string & AsString() const
Get the string representation of the error message.
NetworkError(int error)
Construct the network error with the given error code.
static NetworkError GetLast()
Get the last network error.
bool SetReusePort(SOCKET d)
Try to set the socket to reuse ports.
bool SetNonBlocking([[maybe_unused]] SOCKET d)
Try to set the socket into non-blocking mode.
NetworkError GetSocketError(SOCKET d)
Get the error from a socket, if any.
bool SetNoDelay([[maybe_unused]] SOCKET d)
Try to set the socket to not delay sending.
Network stuff has many things that needs to be included and/or implemented by default.
Definition of base types and functions in a cross-platform compatible way.
std::string FS2OTTD(const std::wstring &name)
Convert to OpenTTD's encoding from a wide string.
Definition: win32.cpp:337