Xemu [doxygen]  hyppo 0a42be3a057156924bc1b626a687bd6e27349c45 @ Sat 19 Mar 02:15:11 CET 2022
emutools_socketapi.c
Go to the documentation of this file.
1 /* Part of the Xemu project, please visit: https://github.com/lgblgblgb/xemu
2  Copyright (C)2016-2021 LGB (Gábor Lénárt) <lgblgblgb@gmail.com>
3 
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8 
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13 
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
17 
18 #ifdef XEMU_HAS_SOCKET_API
19 
20 #include <stdio.h>
21 #include <strings.h>
22 #include <sys/types.h>
23 #include <unistd.h>
24 #include <stdlib.h>
25 #include <fcntl.h>
26 #include <errno.h>
27 #include <string.h>
28 #include <sys/time.h>
31 
32 #ifndef WINSOCK_VERSION_MAJOR
33 #define WINSOCK_VERSION_MAJOR 2
34 #endif
35 #ifndef WINSOCK_VERSION_MINOR
36 #define WINSOCK_VERSION_MINOR 2
37 #endif
38 
39 #ifdef XEMU_ARCH_WIN
40 # define SOCK_ERR() WSAGetLastError()
41 #else
42 # define SOCK_ERR() (errno+0)
43 #endif
44 
45 #ifdef XEMU_ARCH_WIN
46 // FIXME: maybe migrate this to Windows' FormatMessage() at some point?
47 const char *xemusock_strerror ( int err )
48 {
49  switch (err) {
50  case 0: return "Success (0)";
51  case WSA_INVALID_HANDLE: return "Invalid handle (INVALID_HANDLE)";
52  case WSA_NOT_ENOUGH_MEMORY: return "Not enough memory (NOT_ENOUGH_MEMORY)";
53  case WSA_INVALID_PARAMETER: return "Invalid parameter (INVALID_PARAMETER)";
54  case WSA_OPERATION_ABORTED: return "Operation aborted (OPERATION_ABORTED)";
55  case WSA_IO_INCOMPLETE: return "IO incomplete (IO_INCOMPLETE)";
56  case WSA_IO_PENDING: return "IO pending (IO_PENDING)";
57  case WSAEINTR: return "Interrupted (EINTR)";
58  case WSAEBADF: return "Invalid handle (EBADF)";
59  case WSAEACCES: return "Permission denied (EACCES)";
60  case WSAEFAULT: return "Bad address (EFAULT)";
61  case WSAEINVAL: return "Invaild argument (EINVAL)";
62  case WSAEMFILE: return "Too many files (EMFILE)";
63  case WSAEWOULDBLOCK: return "Resource temporarily unavailable (EWOULDBLOCK)";
64  case WSAEINPROGRESS: return "Operation now in progress (EINPROGRESS)";
65  case WSAEALREADY: return "Operation already in progress (EALREADY)";
66  case WSAENOTSOCK: return "Socket operation on nonsocket (ENOTSOCK)";
67  case WSAEDESTADDRREQ: return "Destination address required (EDESTADDRREQ)";
68  case WSAEMSGSIZE: return "Message too long (EMSGSIZE)";
69  case WSAEPROTOTYPE: return "Protocol wrong type for socket (EPROTOTYPE)";
70  case WSAENOPROTOOPT: return "Bad protocol option (ENOPROTOOPT)";
71  case WSAEPROTONOSUPPORT: return "Protocol not supported (EPROTONOSUPPORT)";
72  case WSAESOCKTNOSUPPORT: return "Socket type not supported (ESOCKTNOSUPPORT)";
73  case WSAEOPNOTSUPP: return "Operation not supported (EOPNOTSUPP)";
74  case WSAEPFNOSUPPORT: return "Protocol family not supported (EPFNOSUPPORT)";
75  case WSAEAFNOSUPPORT: return "Address family not supported by protocol family (EAFNOSUPPORT)";
76  case WSAEADDRINUSE: return "Address already in use (EADDRINUSE)";
77  case WSAEADDRNOTAVAIL: return "Cannot assign requested address (EADDRNOTAVAIL)";
78  case WSAENETDOWN: return "Network is down (ENETDOWN)";
79  case WSAENETUNREACH: return "Network is unreachable (ENETUNREACH)";
80  case WSAENETRESET: return "Network dropped connection on reset (ENETRESET)";
81  case WSAECONNABORTED: return "Software caused connection abort (ECONNABORTED)";
82  case WSAECONNRESET: return "Connection reset by peer (ECONNRESET)";
83  case WSAENOBUFS: return "No buffer space available (ENOBUFS)";
84  case WSAEISCONN: return "Socket is already connected (EISCONN)";
85  case WSAENOTCONN: return "Socket is not connected (ENOTCONN)";
86  case WSAESHUTDOWN: return "Cannot send after socket shutdown (ESHUTDOWN)";
87  case WSAETOOMANYREFS: return "Too many references (ETOOMANYREFS)";
88  case WSAETIMEDOUT: return "Connection timed out (ETIMEDOUT)";
89  case WSAECONNREFUSED: return "Connection refused (ECONNREFUSED)";
90  case WSAELOOP: return "Cannot translate name (ELOOP)";
91  case WSAENAMETOOLONG: return "Name too long (ENAMETOOLONG)";
92  case WSAEHOSTDOWN: return "Host is down (EHOSTDOWN)";
93  case WSAEHOSTUNREACH: return "No route to host (EHOSTUNREACH)";
94  case WSAENOTEMPTY: return "Directory not empty (ENOTEMPTY)";
95  case WSAEPROCLIM: return "Too many processes (EPROCLIM)";
96  case WSAEUSERS: return "User quota exceeded (EUSERS)";
97  case WSAEDQUOT: return "Disk quota exceeded (EDQUOT)";
98  case WSAESTALE: return "Stale file handle reference (ESTALE)";
99  case WSAEREMOTE: return "Item is remote (EREMOTE)";
100  case WSASYSNOTREADY: return "Network subsystem is unavailable (SYSNOTREADY)";
101  case WSAVERNOTSUPPORTED: return "Winsock.dll version out of range (VERNOTSUPPORTED)";
102  case WSANOTINITIALISED: return "Successful WSAStartup not yet performed (NOTINITIALISED)";
103  case WSAEDISCON: return "Graceful shutdown in progress (EDISCON)";
104  case WSAENOMORE: return "No more results (ENOMORE)";
105  case WSAECANCELLED: return "Call has been canceled (WSAECANCELLED)";
106  case WSAEINVALIDPROCTABLE: return "Procedure call table is invalid (EINVALIDPROCTABLE)";
107  case WSAEINVALIDPROVIDER: return "Service provider is invalid (EINVALIDPROVIDER)";
108  case WSAEPROVIDERFAILEDINIT: return "Service provider failed to initialize (EPROVIDERFAILEDINIT)";
109  case WSASYSCALLFAILURE: return "System call failure (SYSCALLFAILURE)";
110  case WSASERVICE_NOT_FOUND: return "Service not found (SERVICE_NOT_FOUND)";
111  case WSATYPE_NOT_FOUND: return "Class type not found (TYPE_NOT_FOUND)";
112  case WSA_E_NO_MORE: return "No more results (E_NO_MORE)";
113  case WSA_E_CANCELLED: return "Call was canceled (E_CANCELLED)";
114  case WSAEREFUSED: return "Database query was refused (EREFUSED)";
115  case WSAHOST_NOT_FOUND: return "Host not found (HOST_NOT_FOUND)";
116  case WSATRY_AGAIN: return "Nonauthoritative host not found (TRY_AGAIN)";
117  case WSANO_RECOVERY: return "This is a nonrecoverable error (NO_RECOVERY)";
118  case WSANO_DATA: return "Valid name, no data record of requested type (NO_DATA)";
119  default: return "Unknown Winsock error";
120  }
121 }
122 #endif
123 
124 
125 static int _winsock_init_status = 1; // 1 = todo, 0 = was OK, -1 = error!
126 static char _winsock_errmsg[512];
127 
128 
129 const char *xemusock_init ( void )
130 {
131  if (_winsock_init_status == 0)
132  return NULL;
133  if (_winsock_init_status < 0)
134  return _winsock_errmsg;
135 #ifdef XEMU_ARCH_WIN
136  WSADATA wsa;
137  if (WSAStartup(MAKEWORD(WINSOCK_VERSION_MAJOR, WINSOCK_VERSION_MINOR), &wsa)) {
138  int err = SOCK_ERR();
139  snprintf(_winsock_errmsg, sizeof _winsock_errmsg, "WINSOCK: ERROR: Failed to initialize winsock2, [%d]: %s", err, xemusock_strerror(err));
140  _winsock_init_status = -1;
141  DEBUGPRINT("%s" NL, _winsock_errmsg);
142  return _winsock_errmsg;
143  }
144  if (LOBYTE(wsa.wVersion) != WINSOCK_VERSION_MAJOR || HIBYTE(wsa.wVersion) != WINSOCK_VERSION_MINOR) {
145  WSACleanup();
146  snprintf(_winsock_errmsg, sizeof _winsock_errmsg,
147  "WINSOCK: ERROR: No suitable winsock API in the implemantion DLL (we need v%d.%d, we got: v%d.%d), windows system error ...",
148  WINSOCK_VERSION_MAJOR, WINSOCK_VERSION_MINOR,
149  HIBYTE(wsa.wVersion), LOBYTE(wsa.wVersion)
150  );
151  _winsock_init_status = -1;
152  DEBUGPRINT("%s" NL, _winsock_errmsg);
153  return _winsock_errmsg;
154  }
155  DEBUGPRINT("WINSOCK: OK: initialized, version %d.%d" NL, HIBYTE(wsa.wVersion), LOBYTE(wsa.wVersion));
156 #endif
157  _winsock_init_status = 0;
158  return NULL;
159 }
160 
161 
162 void xemusock_uninit ( void )
163 {
164 #ifdef XEMU_ARCH_WIN
165  if (_winsock_init_status == 0) {
166  WSACleanup();
167  _winsock_init_status = 1;
168  DEBUGPRINT("WINSOCK: uninitialized." NL);
169  }
170 #endif
171 }
172 
173 
174 void xemusock_fill_servaddr_for_inet_ip_netlong ( struct sockaddr_in *servaddr, unsigned int ip_netlong, int port )
175 {
176  memset(servaddr, 0, sizeof(struct sockaddr_in));
177  if (ip_netlong == 0)
178  ip_netlong = INADDR_ANY;
179  servaddr->sin_addr.s_addr = ip_netlong;
180  servaddr->sin_port = htons(port);
181  servaddr->sin_family = AF_INET;
182 }
183 
184 
185 void xemusock_fill_servaddr_for_inet_ip_native ( struct sockaddr_in *servaddr, unsigned int ip_native, int port )
186 {
187  xemusock_fill_servaddr_for_inet_ip_netlong(servaddr, htonl(ip_native), port);
188 }
189 
190 
191 int xemusock_set_nonblocking ( xemusock_socket_t sock, int is_nonblock, int *xerrno )
192 {
193 #ifdef XEMU_ARCH_WIN
194  u_long mode = !!is_nonblock; // 1 = use non-blocking sockets
195  if (ioctlsocket(sock, FIONBIO, &mode)) {
196  if (xerrno)
197  *xerrno = SOCK_ERR();
198  return -1;
199  }
200  return 0;
201 #else
202  int flags = fcntl(sock, F_GETFL);
203  if (flags == -1) {
204  if (xerrno)
205  *xerrno = SOCK_ERR();
206  return -1;
207  }
208  flags = (is_nonblock ? (flags | O_NONBLOCK) : (flags & ~O_NONBLOCK));
209  if (fcntl(sock, F_SETFL, flags) == -1) {
210  if (xerrno)
211  *xerrno = SOCK_ERR();
212  return -1;
213  }
214  return 0;
215 #endif
216 }
217 
218 
219 xemusock_socket_t xemusock_create_for_inet ( int is_tcp, int is_nonblock, int *xerrno )
220 {
221  xemusock_socket_t sock = socket(AF_INET, is_tcp ? SOCK_STREAM : SOCK_DGRAM, 0);
222  if (sock == XS_INVALID_SOCKET) {
223  if (xerrno)
224  *xerrno = SOCK_ERR();
225  return XS_INVALID_SOCKET;
226  }
227  if (is_nonblock == 1) {
228  int ret = xemusock_set_nonblocking(sock, 1, xerrno);
229  if (ret) {
230  xemusock_close(sock, NULL);
231  return XS_INVALID_SOCKET;
232  } else
233  return sock;
234  }
235  return sock;
236 }
237 
238 
239 int xemusock_close ( xemusock_socket_t sock, int *xerrno )
240 {
241 #ifdef XEMU_ARCH_WIN
242  int ret = closesocket(sock);
243 #else
244  int ret = close(sock);
245 #endif
246  if (ret) {
247  if (xerrno)
248  *xerrno = SOCK_ERR();
249  return XS_SOCKET_ERROR;
250  } else
251  return 0;
252 }
253 
254 
255 int xemusock_connect ( xemusock_socket_t sock, struct sockaddr_in *servaddr, int *xerrno )
256 {
257  if (connect(sock, (struct sockaddr *)servaddr, sizeof(struct sockaddr_in)) == XS_SOCKET_ERROR) {
258  if (xerrno)
259  *xerrno = SOCK_ERR();
260  return -1;
261  } else
262  return 0;
263 }
264 
265 
266 int xemusock_shutdown ( xemusock_socket_t sock, int *xerrno )
267 {
268  if (shutdown(sock, SHUT_RDWR) == XS_SOCKET_ERROR) {
269  if (xerrno)
270  *xerrno = SOCK_ERR();
271  return -1;
272  } else
273  return 0;
274 }
275 
276 
277 int xemusock_sendto ( xemusock_socket_t sock, const void *buffer, int length, struct sockaddr_in *servaddr, int *xerrno )
278 {
279  int ret = sendto(sock, buffer, length, 0, (struct sockaddr*)servaddr, sizeof(struct sockaddr_in));
280  if (ret == XS_SOCKET_ERROR) {
281  if (xerrno)
282  *xerrno = SOCK_ERR();
283  return -1;
284  } else
285  return ret;
286 }
287 
288 
289 int xemusock_send ( xemusock_socket_t sock, const void *buffer, int length, int *xerrno )
290 {
291  int ret = send(sock, buffer, length, 0);
292  if (ret == XS_SOCKET_ERROR) {
293  if (xerrno)
294  *xerrno = SOCK_ERR();
295  return -1;
296  } else
297  return ret;
298 }
299 
300 
301 int xemusock_recvfrom ( xemusock_socket_t sock, void *buffer, int length, struct sockaddr_in *servaddr, int *xerrno )
302 {
303  xemusock_socklen_t addrlen = sizeof(struct sockaddr_in);
304  int ret = recvfrom(sock, buffer, length, 0, (struct sockaddr*)servaddr, &addrlen);
305  if (ret == XS_SOCKET_ERROR) {
306  if (xerrno)
307  *xerrno = SOCK_ERR();
308  return -1;
309  } else
310  return ret;
311 }
312 
313 
314 int xemusock_recv ( xemusock_socket_t sock, void *buffer, int length, int *xerrno )
315 {
316  int ret = recv(sock, buffer, length, 0);
317  if (ret == XS_SOCKET_ERROR) {
318  if (xerrno)
319  *xerrno = SOCK_ERR();
320  return -1;
321  } else
322  return ret;
323 }
324 
325 
326 int xemusock_bind ( xemusock_socket_t sock, struct sockaddr *addr, xemusock_socklen_t addrlen, int *xerrno )
327 {
328  int ret = bind(sock, addr, addrlen);
329  if (ret) {
330  if (xerrno)
331  *xerrno = SOCK_ERR();
332  return -1;
333  } else
334  return 0;
335 }
336 
337 
338 int xemusock_listen ( xemusock_socket_t sock, int backlog, int *xerrno )
339 {
340  int ret = listen(sock, backlog);
341  if (ret) {
342  if (xerrno)
343  *xerrno = SOCK_ERR();
344  return -1;
345  } else
346  return 0;
347 }
348 
349 
350 xemusock_socket_t xemusock_accept ( xemusock_socket_t sock, struct sockaddr *addr, xemusock_socklen_t *addrlen, int *xerrno )
351 {
352  xemusock_socket_t ret = accept(sock, addr, addrlen);
353  if (ret == XS_INVALID_SOCKET) {
354  if (xerrno)
355  *xerrno = SOCK_ERR();
356  }
357  return ret;
358 }
359 
360 
361 int xemusock_setsockopt ( xemusock_socket_t sock, int level, int option, const void *value, int len, int *xerrno )
362 {
363  if (setsockopt(sock, level, option, (const char*)value, len)) {
364  if (xerrno)
365  *xerrno = SOCK_ERR();
366  return -1;
367  } else
368  return 0;
369 }
370 
371 
372 int xemusock_setsockopt_reuseaddr ( xemusock_socket_t sock, int *xerrno )
373 {
374 #ifdef XEMU_ARCH_WIN
375  static const BOOL on = 1;
376 #else
377  static const int on = 1;
378 #endif
379  return xemusock_setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof on, xerrno);
380 }
381 
382 
383 int xemusock_select_1 ( xemusock_socket_t sock, int usec, int what, int *xerrno )
384 {
385  for (;;) {
386  int ret;
387  struct timeval timeout;
388  fd_set fds_r, fds_w, fds_e;
389  FD_ZERO(&fds_r);
390  FD_ZERO(&fds_w);
391  FD_ZERO(&fds_e);
392  if (what & XEMUSOCK_SELECT_R)
393  FD_SET(sock, &fds_r);
394  if (what & XEMUSOCK_SELECT_W)
395  FD_SET(sock, &fds_w);
396  if (what & XEMUSOCK_SELECT_E)
397  FD_SET(sock, &fds_e);
398  timeout.tv_sec = 0;
399  timeout.tv_usec = usec;
400  ret = select(sock + 1, &fds_r, &fds_w, &fds_e, usec >= 0 ? &timeout : NULL);
401  if (ret == XS_SOCKET_ERROR) {
402  int err = SOCK_ERR();
403  if (err == XSEINTR)
404  continue;
405  if (xerrno)
406  *xerrno = SOCK_ERR();
407  return -1;
408  }
409  if (ret == 0)
410  return 0;
411  return (FD_ISSET(sock, &fds_r) ? XEMUSOCK_SELECT_R : 0) | (FD_ISSET(sock, &fds_w) ? XEMUSOCK_SELECT_W : 0) | (FD_ISSET(sock, &fds_e) ? XEMUSOCK_SELECT_E : 0);
412  }
413 }
414 
415 #endif
flags
Uint8 flags
Definition: z8k1.c:126
addr
int addr
Definition: dma65.c:81
emutools_basicdefs.h
DEBUGPRINT
#define DEBUGPRINT(...)
Definition: emutools_basicdefs.h:171
emutools_socketapi.h
mode
int mode
Definition: vera.c:61
NL
#define NL
Definition: fat32.c:37
value
int value
Definition: dma65.c:90