OpenTTD Source 20250523-master-g321f7e8683
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
32NetworkError::NetworkError(int error, std::string_view message) : error(error), message(message)
33{
34}
35
41{
42#if defined(_WIN32)
43 return this->error == WSAEWOULDBLOCK;
44#else
45 /* Usually EWOULDBLOCK and EAGAIN are the same, but sometimes they are not
46 * and the POSIX.1 specification states that either should be checked. */
47 return this->error == EWOULDBLOCK || this->error == EAGAIN;
48#endif
49}
50
56{
57#if defined(_WIN32)
58 return this->error == WSAECONNRESET;
59#else
60 return this->error == ECONNRESET;
61#endif
62}
63
69{
70#if defined(_WIN32)
71 return this->error == WSAEWOULDBLOCK;
72#else
73 return this->error == EINPROGRESS;
74#endif
75}
76
81std::string_view NetworkError::AsString() const
82{
83 if (this->message.empty()) {
84#if defined(_WIN32)
85 wchar_t buffer[512];
86 if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr, this->error,
87 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buffer, static_cast<DWORD>(std::size(buffer)), nullptr) == 0) {
88 this->message.assign(fmt::format("Unknown error {}", this->error));
89 } else {
90 this->message.assign(FS2OTTD(buffer));
91 }
92#else
93 /* Make strerror thread safe by locking access to it. There is a thread safe strerror_r, however
94 * the non-POSIX variant is available due to defining _GNU_SOURCE meaning it is not portable.
95 * The problem with the non-POSIX variant is that it does not necessarily fill the buffer with
96 * the error message but can also return a pointer to a static bit of memory, whereas the POSIX
97 * variant always fills the buffer. This makes the behaviour too erratic to work with. */
98 static std::mutex mutex;
99 std::lock_guard<std::mutex> guard(mutex);
100 this->message.assign(strerror(this->error));
101#endif
102 }
103 return this->message;
104}
105
111{
112 return this->error != 0;
113}
114
120{
121#if defined(_WIN32)
122 return NetworkError(WSAGetLastError());
123#else
124 return NetworkError(errno);
125#endif
126}
127
128
134bool SetNonBlocking([[maybe_unused]] SOCKET d)
135{
136#if defined(_WIN32)
137 u_long nonblocking = 1;
138 return ioctlsocket(d, FIONBIO, &nonblocking) == 0;
139#elif defined __EMSCRIPTEN__
140 return true;
141#else
142 int nonblocking = 1;
143 return ioctl(d, FIONBIO, &nonblocking) == 0;
144#endif
145}
146
152bool SetNoDelay([[maybe_unused]] SOCKET d)
153{
154#ifdef __EMSCRIPTEN__
155 return true;
156#else
157 int flags = 1;
158 /* The (const char *) cast is needed for windows */
159 return setsockopt(d, IPPROTO_TCP, TCP_NODELAY, reinterpret_cast<const char *>(&flags), sizeof(flags)) == 0;
160#endif
161}
162
168bool SetReusePort(SOCKET d)
169{
170#ifdef _WIN32
171 /* Windows has no SO_REUSEPORT, but for our usecases SO_REUSEADDR does the same job. */
172 int reuse_port = 1;
173 return setsockopt(d, SOL_SOCKET, SO_REUSEADDR, (const char *)&reuse_port, sizeof(reuse_port)) == 0;
174#else
175 int reuse_port = 1;
176 return setsockopt(d, SOL_SOCKET, SO_REUSEPORT, &reuse_port, sizeof(reuse_port)) == 0;
177#endif
178}
179
186{
187 int err;
188 socklen_t len = sizeof(err);
189 if (getsockopt(d, SOL_SOCKET, SO_ERROR, (char *)&err, &len) != 0) return NetworkError(-1, "Could not get error for socket");
190
191 return NetworkError(err);
192}
Abstraction of a network error where all implementation details of the error codes are encapsulated i...
std::string_view AsString() const
Get the string representation of the error message.
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).
NetworkError(int error, std::string_view message={})
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.
std::string FS2OTTD(std::wstring_view name)
Convert to OpenTTD's encoding from a wide string.
Definition win32.cpp:337