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 
8 /**
9  * @file os_abstraction.h Network stuff has many things that needs to be
10  *                        included and/or implemented by default.
11  *                        All those things are in this file.
12  */
13 
14 #ifndef NETWORK_CORE_OS_ABSTRACTION_H
15 #define NETWORK_CORE_OS_ABSTRACTION_H
16 
17 /**
18  * Abstraction of a network error where all implementation details of the
19  * error codes are encapsulated in this class and the abstraction layer.
20  */
21 class NetworkError {
22 private:
23 	int error;                   ///< The underlying error number from errno or WSAGetLastError.
24 	mutable std::string message; ///< The string representation of the error (set on first call to #AsString).
25 public:
26 	NetworkError(int error);
27 
28 	bool HasError() const;
29 	bool WouldBlock() const;
30 	bool IsConnectionReset() const;
31 	bool IsConnectInProgress() const;
32 	const std::string &AsString() const;
33 
34 	static NetworkError GetLast();
35 };
36 
37 /* Include standard stuff per OS */
38 
39 /* Windows stuff */
40 #if defined(_WIN32)
41 #include <errno.h>
42 #include <winsock2.h>
43 #include <ws2tcpip.h>
44 #include <windows.h>
45 
46 /* Windows has some different names for some types */
47 typedef unsigned long in_addr_t;
48 
49 /* Handle cross-compilation with --build=*-*-cygwin --host=*-*-mingw32 */
50 #if defined(__MINGW32__) && !defined(AI_ADDRCONFIG)
51 #	define AI_ADDRCONFIG               0x00000400
52 #endif
53 
54 #if !(defined(__MINGW32__) || defined(__CYGWIN__))
55 	/* Windows has some different names for some types */
56 	typedef SSIZE_T ssize_t;
57 	typedef int socklen_t;
58 #	define IPPROTO_IPV6 41
59 #endif /* !(__MINGW32__ && __CYGWIN__) */
60 #endif /* _WIN32 */
61 
62 /* UNIX stuff */
63 #if defined(UNIX) && !defined(__OS2__)
64 #	if defined(OPENBSD) || defined(__NetBSD__)
65 #		define AI_ADDRCONFIG 0
66 #	endif
67 #	define SOCKET int
68 #	define INVALID_SOCKET -1
69 #	define closesocket close
70 /* Need this for FIONREAD on solaris */
71 #	define BSD_COMP
72 
73 /* Includes needed for UNIX-like systems */
74 #	include <unistd.h>
75 #	include <sys/ioctl.h>
76 #	include <sys/socket.h>
77 #	include <netinet/in.h>
78 #	include <netinet/tcp.h>
79 #	include <arpa/inet.h>
80 #	include <net/if.h>
81 /* According to glibc/NEWS, <ifaddrs.h> appeared in glibc-2.3. */
82 #	if !defined(__sgi__) && !defined(SUNOS) && !defined(__INNOTEK_LIBC__) \
83 	   && !(defined(__GLIBC__) && (__GLIBC__ <= 2) && (__GLIBC_MINOR__ <= 2)) && !defined(__dietlibc__) && !defined(HPUX)
84 /* If for any reason ifaddrs.h does not exist on your system, comment out
85  *   the following two lines and an alternative way will be used to fetch
86  *   the list of IPs from the system. */
87 #		include <ifaddrs.h>
88 #		define HAVE_GETIFADDRS
89 #	endif
90 #	if !defined(INADDR_NONE)
91 #		define INADDR_NONE 0xffffffff
92 #	endif
93 
94 #	if defined(__GLIBC__) && (__GLIBC__ <= 2) && (__GLIBC_MINOR__ <= 1)
95 		typedef uint32_t in_addr_t;
96 #	endif
97 
98 #	include <errno.h>
99 #	include <sys/time.h>
100 #	include <netdb.h>
101 
102 #   if defined(__EMSCRIPTEN__)
103 /* Emscripten doesn't support AI_ADDRCONFIG and errors out on it. */
104 #		undef AI_ADDRCONFIG
105 #		define AI_ADDRCONFIG 0
106 /* Emscripten says it supports FD_SETSIZE fds, but it really only supports 64.
107  * https://github.com/emscripten-core/emscripten/issues/1711 */
108 #		undef FD_SETSIZE
109 #		define FD_SETSIZE 64
110 #   endif
111 
112 /* Haiku says it supports FD_SETSIZE fds, but it really only supports 512. */
113 #   if defined(__HAIKU__)
114 #		undef FD_SETSIZE
115 #		define FD_SETSIZE 512
116 #   endif
117 
118 #endif /* UNIX */
119 
120 /* OS/2 stuff */
121 #if defined(__OS2__)
122 #	define SOCKET int
123 #	define INVALID_SOCKET -1
124 #	define closesocket close
125 
126 /* Includes needed for OS/2 systems */
127 #	include <types.h>
128 #	include <unistd.h>
129 #	include <sys/ioctl.h>
130 #	include <sys/socket.h>
131 #	include <netinet/in.h>
132 #	include <netinet/tcp.h>
133 #	include <arpa/inet.h>
134 #	include <net/if.h>
135 #	include <errno.h>
136 #	include <sys/time.h>
137 #	include <netdb.h>
138 #	include <nerrno.h>
139 #	define INADDR_NONE 0xffffffff
140 #	include "../../3rdparty/os2/getaddrinfo.h"
141 #	include "../../3rdparty/os2/getnameinfo.h"
142 
143 #define IPV6_V6ONLY 27
144 
145 /*
146  * IPv6 address
147  */
148 struct in6_addr {
149 	union {
150 		uint8_t  __u6_addr8[16];
151 		uint16_t __u6_addr16[8];
152 		uint32_t __u6_addr32[4];
153 	} __u6_addr; /* 128-bit IP6 address */
154 };
155 
156 #define s6_addr   __u6_addr.__u6_addr8
157 
158 struct sockaddr_in6 {
159 	uint8_t         sin6_len;       /* length of this struct */
160 	sa_family_t     sin6_family;    /* AF_INET6 */
161 	in_port_t       sin6_port;      /* Transport layer port # */
162 	uint32_t        sin6_flowinfo;  /* IP6 flow information */
163 	struct in6_addr sin6_addr;      /* IP6 address */
164 	uint32_t        sin6_scope_id;  /* scope zone index */
165 };
166 
167 typedef int socklen_t;
168 #if !defined(__INNOTEK_LIBC__)
169 typedef unsigned long in_addr_t;
170 #endif /* __INNOTEK_LIBC__ */
171 
172 #endif /* OS/2 */
173 
174 #ifdef __EMSCRIPTEN__
175 /**
176  * Emscripten doesn't set 'addrlen' for accept(), getsockname(), getpeername()
177  * and recvfrom(), which confuses other functions and causes them to crash.
178  * This function needs to be called after these four functions to make sure
179  * 'addrlen' is patched up.
180  *
181  * https://github.com/emscripten-core/emscripten/issues/12996
182  *
183  * @param address The address returned by those four functions.
184  * @return The correct value for addrlen.
185  */
FixAddrLenForEmscripten(struct sockaddr_storage & address)186 static inline socklen_t FixAddrLenForEmscripten(struct sockaddr_storage &address)
187 {
188 	switch (address.ss_family) {
189 		case AF_INET6: return sizeof(struct sockaddr_in6);
190 		case AF_INET: return sizeof(struct sockaddr_in);
191 		default: NOT_REACHED();
192 	}
193 }
194 #endif
195 
196 
197 bool SetNonBlocking(SOCKET d);
198 bool SetNoDelay(SOCKET d);
199 bool SetReusePort(SOCKET d);
200 NetworkError GetSocketError(SOCKET d);
201 
202 /* Make sure these structures have the size we expect them to be */
203 static_assert(sizeof(in_addr)  ==  4); ///< IPv4 addresses should be 4 bytes.
204 static_assert(sizeof(in6_addr) == 16); ///< IPv6 addresses should be 16 bytes.
205 
206 #endif /* NETWORK_CORE_OS_ABSTRACTION_H */
207