OpenTTD Source 20241224-master-gf74b0cf984
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
31NetworkError::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
80const 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
133bool 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
151bool 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
167bool 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 SetNoDelay(SOCKET d)
Try to set the socket to not delay sending.
bool SetNonBlocking(SOCKET d)
Try to set the socket into non-blocking mode.
NetworkError GetSocketError(SOCKET d)
Get the error from a socket, if any.
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