OpenTTD
os_abstraction.h
Go to the documentation of this file.
1 /* $Id: os_abstraction.h 27092 2014-12-24 17:17:18Z frosch $ */
2 
3 /*
4  * This file is part of OpenTTD.
5  * 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.
6  * 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.
7  * 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/>.
8  */
9 
16 #ifndef NETWORK_CORE_OS_ABSTRACTION_H
17 #define NETWORK_CORE_OS_ABSTRACTION_H
18 
19 /* Include standard stuff per OS */
20 
21 #ifdef ENABLE_NETWORK
22 
23 /* Windows stuff */
24 #if defined(WIN32) || defined(WIN64)
25 #include <errno.h>
26 #include <winsock2.h>
27 #include <ws2tcpip.h>
28 #include <windows.h>
29 
30 #define GET_LAST_ERROR() WSAGetLastError()
31 #undef EWOULDBLOCK
32 #define EWOULDBLOCK WSAEWOULDBLOCK
33 /* Windows has some different names for some types */
34 typedef unsigned long in_addr_t;
35 
36 #if !(defined(__MINGW32__) || defined(__CYGWIN__))
37  /* Windows has some different names for some types */
38  typedef SSIZE_T ssize_t;
39  typedef int socklen_t;
40 # define IPPROTO_IPV6 41
41 #else
42 #include "../../os/windows/win32.h"
43 #include "../../core/alloc_func.hpp"
44 
45 #define AI_ADDRCONFIG 0x00000400 /* Resolution only if global address configured */
46 #define IPV6_V6ONLY 27
47 
48 static inline int OTTDgetnameinfo(const struct sockaddr *sa, socklen_t salen, char *host, DWORD hostlen, char *serv, DWORD servlen, int flags)
49 {
50  static int (WINAPI *getnameinfo)(const struct sockaddr *, socklen_t, char *, DWORD, char *, DWORD, int) = NULL;
51  static bool first_time = true;
52 
53  if (first_time) {
54  LoadLibraryList((Function*)&getnameinfo, "ws2_32.dll\0getnameinfo\0\0");
55  first_time = false;
56  }
57 
58  if (getnameinfo != NULL) return getnameinfo(sa, salen, host, hostlen, serv, servlen, flags);
59 
60  strncpy(host, inet_ntoa(((const struct sockaddr_in *)sa)->sin_addr), hostlen);
61  return 0;
62 }
63 #define getnameinfo OTTDgetnameinfo
64 
65 static inline int OTTDgetaddrinfo(const char *nodename, const char *servname, const struct addrinfo *hints, struct addrinfo **res)
66 {
67  static int (WINAPI *getaddrinfo)(const char *, const char *, const struct addrinfo *, struct addrinfo **) = NULL;
68  static bool first_time = true;
69 
70  if (first_time) {
71  LoadLibraryList((Function*)&getaddrinfo, "ws2_32.dll\0getaddrinfo\0\0");
72  first_time = false;
73  }
74 
75  if (getaddrinfo != NULL) return getaddrinfo(nodename, servname, hints, res);
76 
77  *res = NULL;
78 
79  in_addr_t ip = inet_addr(nodename);
80  if (ip == INADDR_NONE) {
81  struct hostent *he = gethostbyname(nodename);
82  if (he == NULL) return EAI_NONAME;
83  ip = (*(struct in_addr *)he->h_addr).s_addr;
84  }
85 
86  struct sockaddr_in *sin = CallocT<struct sockaddr_in>(1);
87  sin->sin_family = AF_INET;
88  sin->sin_port = htons(strtoul(servname, NULL, 10));
89  sin->sin_addr.s_addr = ip;
90 
91  struct addrinfo *ai = CallocT<struct addrinfo>(1);
92  ai->ai_family = PF_INET;
93  ai->ai_addr = (struct sockaddr*)sin;
94  ai->ai_addrlen = sizeof(*sin);
95  ai->ai_socktype = hints->ai_socktype;
96 
97  *res = ai;
98  return 0;
99 }
100 #define getaddrinfo OTTDgetaddrinfo
101 
102 static inline void OTTDfreeaddrinfo(struct addrinfo *ai)
103 {
104  static int (WINAPI *freeaddrinfo)(struct addrinfo *) = NULL;
105  static bool first_time = true;
106 
107  if (ai == NULL) return;
108 
109  if (first_time) {
110  LoadLibraryList((Function*)&freeaddrinfo, "ws2_32.dll\0freeaddrinfo\0\0");
111  first_time = false;
112  }
113 
114  if (freeaddrinfo != NULL) {
115  freeaddrinfo(ai);
116  return;
117  }
118 
119  do {
120  struct addrinfo *next = ai->ai_next;
121  free(ai->ai_addr);
122  free(ai);
123  ai = next;
124  } while (ai != NULL);
125 }
126 #define freeaddrinfo OTTDfreeaddrinfo
127 #endif /* __MINGW32__ && __CYGWIN__ */
128 #endif /* WIN32 */
129 
130 /* UNIX stuff */
131 #if defined(UNIX) && !defined(__OS2__)
132 # if defined(OPENBSD) || defined(__NetBSD__)
133 # define AI_ADDRCONFIG 0
134 # endif
135 # define SOCKET int
136 # define INVALID_SOCKET -1
137 # if !defined(__MORPHOS__) && !defined(__AMIGA__)
138 # define ioctlsocket ioctl
139 # if !defined(BEOS_NET_SERVER)
140 # define closesocket close
141 # endif
142 # define GET_LAST_ERROR() (errno)
143 # endif
144 /* Need this for FIONREAD on solaris */
145 # define BSD_COMP
146 
147 /* Includes needed for UNIX-like systems */
148 # include <unistd.h>
149 # include <sys/ioctl.h>
150 # if defined(__BEOS__) && defined(BEOS_NET_SERVER)
151 # include <be/net/socket.h>
152 # include <be/kernel/OS.h> /* snooze() */
153 # include <be/net/netdb.h>
154  typedef unsigned long in_addr_t;
155 # define INADDR_NONE INADDR_BROADCAST
156 # else
157 # include <sys/socket.h>
158 # include <netinet/in.h>
159 # include <netinet/tcp.h>
160 # include <arpa/inet.h>
161 # include <net/if.h>
162 /* According to glibc/NEWS, <ifaddrs.h> appeared in glibc-2.3. */
163 # if !defined(__sgi__) && !defined(SUNOS) && !defined(__MORPHOS__) && !defined(__BEOS__) && !defined(__HAIKU__) && !defined(__INNOTEK_LIBC__) \
164  && !(defined(__GLIBC__) && (__GLIBC__ <= 2) && (__GLIBC_MINOR__ <= 2)) && !defined(__dietlibc__) && !defined(HPUX)
165 /* If for any reason ifaddrs.h does not exist on your system, comment out
166  * the following two lines and an alternative way will be used to fetch
167  * the list of IPs from the system. */
168 # include <ifaddrs.h>
169 # define HAVE_GETIFADDRS
170 # endif
171 # if !defined(INADDR_NONE)
172 # define INADDR_NONE 0xffffffff
173 # endif
174 # if defined(__BEOS__) && !defined(BEOS_NET_SERVER)
175  /* needed on Zeta */
176 # include <sys/sockio.h>
177 # endif
178 # endif /* BEOS_NET_SERVER */
179 
180 # if !defined(__BEOS__) && defined(__GLIBC__) && (__GLIBC__ <= 2) && (__GLIBC_MINOR__ <= 1)
181  typedef uint32_t in_addr_t;
182 # endif
183 
184 # include <errno.h>
185 # include <sys/time.h>
186 # include <netdb.h>
187 #endif /* UNIX */
188 
189 #ifdef __BEOS__
190  typedef int socklen_t;
191 #endif
192 
193 #ifdef __HAIKU__
194  #define IPV6_V6ONLY 27
195 #endif
196 
197 #if defined(PSP)
198 # include <sys/socket.h>
199 # include <netinet/in.h>
200 # include <arpa/inet.h>
201 # include <pspnet.h>
202 # include <pspnet_inet.h>
203 # include <pspnet_apctl.h>
204 # include <pspnet_resolver.h>
205 # include <errno.h>
206 # include <unistd.h>
207 # include <sys/select.h>
208 # include <sys/time.h>
209 # include <sys/fd_set.h>
210 
211 # define TCP_NODELAY 1
212 # define SO_NONBLOCK 0x1009
213 # define SOCKET int
214 # define INVALID_SOCKET -1
215 # define INADDR_NONE 0xffffffff
216 # define closesocket close
217 # define GET_LAST_ERROR() sceNetInetGetErrno()
218 #endif /* PSP */
219 
220 /* OS/2 stuff */
221 #if defined(__OS2__)
222 # define SOCKET int
223 # define INVALID_SOCKET -1
224 # define ioctlsocket ioctl
225 # define closesocket close
226 # define GET_LAST_ERROR() (sock_errno())
227 
228 /* Includes needed for OS/2 systems */
229 # include <types.h>
230 # include <unistd.h>
231 # include <sys/ioctl.h>
232 # include <sys/socket.h>
233 # include <netinet/in.h>
234 # include <netinet/tcp.h>
235 # include <arpa/inet.h>
236 # include <net/if.h>
237 # include <errno.h>
238 # include <sys/time.h>
239 # include <netdb.h>
240 # include <nerrno.h>
241 # define INADDR_NONE 0xffffffff
242 # include "../../3rdparty/os2/getaddrinfo.h"
243 # include "../../3rdparty/os2/getnameinfo.h"
244 
245 #define IPV6_V6ONLY 27
246 
247 /*
248  * IPv6 address
249  */
250 struct in6_addr {
251  union {
252  uint8_t __u6_addr8[16];
253  uint16_t __u6_addr16[8];
254  uint32_t __u6_addr32[4];
255  } __u6_addr; /* 128-bit IP6 address */
256 };
257 
258 #define s6_addr __u6_addr.__u6_addr8
259 
260 struct sockaddr_in6 {
261  uint8_t sin6_len; /* length of this struct */
262  sa_family_t sin6_family; /* AF_INET6 */
263  in_port_t sin6_port; /* Transport layer port # */
264  uint32_t sin6_flowinfo; /* IP6 flow information */
265  struct in6_addr sin6_addr; /* IP6 address */
266  uint32_t sin6_scope_id; /* scope zone index */
267 };
268 
269 typedef int socklen_t;
270 #if !defined(__INNOTEK_LIBC__)
271 typedef unsigned long in_addr_t;
272 #endif /* __INNOTEK_LIBC__ */
273 
274 #endif /* OS/2 */
275 
276 /* MorphOS and Amiga stuff */
277 #if defined(__MORPHOS__) || defined(__AMIGA__)
278 # include <exec/types.h>
279 # include <proto/exec.h> /* required for Open/CloseLibrary() */
280  /* MorphOS defines his network functions with UBYTE arrays while we
281  * use char arrays. This gives tons of unneeded warnings */
282 # define UBYTE char
283 # if defined(__MORPHOS__)
284 # include <sys/filio.h> /* FIO* defines */
285 # include <sys/sockio.h> /* SIO* defines */
286 # include <netinet/in.h>
287 # else /* __AMIGA__ */
288 # include <proto/socket.h>
289 # endif
290 
291 /* Make the names compatible */
292 # define closesocket(s) CloseSocket(s)
293 # define GET_LAST_ERROR() Errno()
294 # define ioctlsocket(s, request, status) IoctlSocket((LONG)s, (ULONG)request, (char*)status)
295 # define ioctl ioctlsocket
296 
297  typedef unsigned int in_addr_t;
298  typedef long socklen_t;
299  extern struct Library *SocketBase;
300 
301 # ifdef __AMIGA__
302  /* for usleep() implementation */
303  extern struct Device *TimerBase;
304  extern struct MsgPort *TimerPort;
305  extern struct timerequest *TimerRequest;
306 # endif
307 #endif /* __MORPHOS__ || __AMIGA__ */
308 
314 static inline bool SetNonBlocking(SOCKET d)
315 {
316 #ifdef WIN32
317  u_long nonblocking = 1;
318 #else
319  int nonblocking = 1;
320 #endif
321 #if (defined(__BEOS__) && defined(BEOS_NET_SERVER)) || defined(PSP)
322  return setsockopt(d, SOL_SOCKET, SO_NONBLOCK, &nonblocking, sizeof(nonblocking)) == 0;
323 #else
324  return ioctlsocket(d, FIONBIO, &nonblocking) == 0;
325 #endif
326 }
327 
333 static inline bool SetNoDelay(SOCKET d)
334 {
335  /* XXX should this be done at all? */
336 #if !defined(BEOS_NET_SERVER) /* not implemented on BeOS net_server */
337  int b = 1;
338  /* The (const char*) cast is needed for windows */
339  return setsockopt(d, IPPROTO_TCP, TCP_NODELAY, (const char*)&b, sizeof(b)) == 0;
340 #else
341  return true;
342 #endif
343 }
344 
345 /* Make sure these structures have the size we expect them to be */
346 assert_compile(sizeof(in_addr) == 4);
347 assert_compile(sizeof(in6_addr) == 16);
348 
349 #endif /* ENABLE_NETWORK */
350 
351 #endif /* NETWORK_CORE_OS_ABSTRACTION_H */