OpenTTD Source: src/network/core/os_abstraction.cpp Source File

OpenTTD Source 15.3

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 <https://www.gnu.org/licenses/old-licenses/gpl-2.0>.
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
40 bool NetworkError::WouldBlock() const
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
55 bool NetworkError::IsConnectionReset() const
56{
57#if defined(_WIN32)
58 return this->error == WSAECONNRESET;
59#else
60 return this->error == ECONNRESET;
61#endif
62}
63
68 bool NetworkError::IsConnectInProgress() const
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
110 bool NetworkError::HasError() const
111{
112 return this->error != 0;
113}
114
119/* static */ NetworkError NetworkError::GetLast()
120{
121#if defined(_WIN32)
122 return NetworkError(WSAGetLastError());
123#else
124 return NetworkError(errno);
125#endif
126}
127
128
134 bool 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
152 bool 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
168 bool 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
185 NetworkError GetSocketError(SOCKET d)
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}
NetworkError
Abstraction of a network error where all implementation details of the error codes are encapsulated i...
Definition os_abstraction.h:21
NetworkError::AsString
std::string_view AsString() const
Get the string representation of the error message.
Definition os_abstraction.cpp:81
NetworkError::WouldBlock
bool WouldBlock() const
Check whether this error describes that the operation would block.
Definition os_abstraction.cpp:40
NetworkError::IsConnectInProgress
bool IsConnectInProgress() const
Check whether this error describes a connect is in progress.
Definition os_abstraction.cpp:68
NetworkError::error
int error
The underlying error number from errno or WSAGetLastError.
Definition os_abstraction.h:23
NetworkError::HasError
bool HasError() const
Check whether an error was actually set.
Definition os_abstraction.cpp:110
NetworkError::IsConnectionReset
bool IsConnectionReset() const
Check whether this error describes a connection reset.
Definition os_abstraction.cpp:55
NetworkError::message
std::string message
The string representation of the error (set on first call to AsString).
Definition os_abstraction.h:24
NetworkError::NetworkError
NetworkError(int error, std::string_view message={})
Construct the network error with the given error code.
Definition os_abstraction.cpp:32
NetworkError::GetLast
static NetworkError GetLast()
Get the last network error.
Definition os_abstraction.cpp:119
SetReusePort
bool SetReusePort(SOCKET d)
Try to set the socket to reuse ports.
Definition os_abstraction.cpp:168
SetNoDelay
bool SetNoDelay(SOCKET d)
Try to set the socket to not delay sending.
Definition os_abstraction.cpp:152
SetNonBlocking
bool SetNonBlocking(SOCKET d)
Try to set the socket into non-blocking mode.
Definition os_abstraction.cpp:134
GetSocketError
NetworkError GetSocketError(SOCKET d)
Get the error from a socket, if any.
Definition os_abstraction.cpp:185
os_abstraction.h
Network stuff has many things that needs to be included and/or implemented by default.
FS2OTTD
std::string FS2OTTD(std::wstring_view name)
Convert to OpenTTD's encoding from a wide string.
Definition win32.cpp:340