OpenTTD Source  12.0-beta2
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 <mutex>
23 
24 #include "../../safeguards.h"
25 
31 {
32 }
33 
39 {
40 #if defined(_WIN32)
41  return this->error == WSAEWOULDBLOCK;
42 #else
43  /* Usually EWOULDBLOCK and EAGAIN are the same, but sometimes they are not
44  * and the POSIX.1 specification states that either should be checked. */
45  return this->error == EWOULDBLOCK || this->error == EAGAIN;
46 #endif
47 }
48 
54 {
55 #if defined(_WIN32)
56  return this->error == WSAECONNRESET;
57 #else
58  return this->error == ECONNRESET;
59 #endif
60 }
61 
67 {
68 #if defined(_WIN32)
69  return this->error == WSAEWOULDBLOCK;
70 #else
71  return this->error == EINPROGRESS;
72 #endif
73 }
74 
79 const std::string &NetworkError::AsString() const
80 {
81  if (this->message.empty()) {
82 #if defined(_WIN32)
83  char buffer[512];
84  if (FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, this->error,
85  MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buffer, sizeof(buffer), NULL) == 0) {
86  seprintf(buffer, lastof(buffer), "Unknown error %d", this->error);
87  }
88  this->message.assign(buffer);
89 #else
90  /* Make strerror thread safe by locking access to it. There is a thread safe strerror_r, however
91  * the non-POSIX variant is available due to defining _GNU_SOURCE meaning it is not portable.
92  * The problem with the non-POSIX variant is that it does not necessarily fill the buffer with
93  * the error message but can also return a pointer to a static bit of memory, whereas the POSIX
94  * variant always fills the buffer. This makes the behaviour too erratic to work with. */
95  static std::mutex mutex;
96  std::lock_guard<std::mutex> guard(mutex);
97  this->message.assign(strerror(this->error));
98 #endif
99  }
100  return this->message;
101 }
102 
108 {
109  return this->error != 0;
110 }
111 
117 {
118 #if defined(_WIN32)
119  return NetworkError(WSAGetLastError());
120 #elif defined(__OS2__)
121  return NetworkError(sock_errno());
122 #else
123  return NetworkError(errno);
124 #endif
125 }
126 
127 
133 bool SetNonBlocking(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(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 }
SetReusePort
bool SetReusePort(SOCKET d)
Try to set the socket to reuse ports.
Definition: os_abstraction.cpp:167
NetworkError::HasError
bool HasError() const
Check whether an error was actually set.
Definition: os_abstraction.cpp:107
NetworkError::message
std::string message
The string representation of the error (set on first call to AsString).
Definition: os_abstraction.h:24
NetworkError::WouldBlock
bool WouldBlock() const
Check whether this error describes that the operation would block.
Definition: os_abstraction.cpp:38
NetworkError::GetLast
static NetworkError GetLast()
Get the last network error.
Definition: os_abstraction.cpp:116
stdafx.h
GetSocketError
NetworkError GetSocketError(SOCKET d)
Get the error from a socket, if any.
Definition: os_abstraction.cpp:184
NetworkError::error
int error
The underlying error number from errno or WSAGetLastError.
Definition: os_abstraction.h:23
NetworkError::IsConnectInProgress
bool IsConnectInProgress() const
Check whether this error describes a connect is in progress.
Definition: os_abstraction.cpp:66
NetworkError::IsConnectionReset
bool IsConnectionReset() const
Check whether this error describes a connection reset.
Definition: os_abstraction.cpp:53
NetworkError::AsString
const std::string & AsString() const
Get the string representation of the error message.
Definition: os_abstraction.cpp:79
seprintf
int CDECL seprintf(char *str, const char *last, const char *format,...)
Safer implementation of snprintf; same as snprintf except:
Definition: string.cpp:535
NetworkError
Abstraction of a network error where all implementation details of the error codes are encapsulated i...
Definition: os_abstraction.h:21
error
void CDECL error(const char *s,...)
Error handling for fatal non-user errors.
Definition: openttd.cpp:132
SetNonBlocking
bool SetNonBlocking(SOCKET d)
Try to set the socket into non-blocking mode.
Definition: os_abstraction.cpp:133
os_abstraction.h
NetworkError::NetworkError
NetworkError(int error)
Construct the network error with the given error code.
Definition: os_abstraction.cpp:30
lastof
#define lastof(x)
Get the last element of an fixed size array.
Definition: stdafx.h:394
SetNoDelay
bool SetNoDelay(SOCKET d)
Try to set the socket to not delay sending.
Definition: os_abstraction.cpp:151