1 /*=========================================================================*\
2 * Socket compatibilization module for Win32
5 * The penalty of calling select to avoid busy-wait is only paid when
6 * the I/O call fail in the first place.
7 \*=========================================================================*/
12 /* WinSock doesn't have a strerror... */
13 static const char *wstrerror(int err
);
15 /*-------------------------------------------------------------------------*\
17 \*-------------------------------------------------------------------------*/
18 int socket_open(void) {
20 WORD wVersionRequested
= MAKEWORD(2, 0);
21 int err
= WSAStartup(wVersionRequested
, &wsaData
);
22 if (err
!= 0) return 0;
23 if ((LOBYTE(wsaData
.wVersion
) != 2 || HIBYTE(wsaData
.wVersion
) != 0) &&
24 (LOBYTE(wsaData
.wVersion
) != 1 || HIBYTE(wsaData
.wVersion
) != 1)) {
31 /*-------------------------------------------------------------------------*\
33 \*-------------------------------------------------------------------------*/
34 int socket_close(void) {
39 /*-------------------------------------------------------------------------*\
40 * Wait for readable/writable/connected socket with timeout
41 \*-------------------------------------------------------------------------*/
45 #define WAITFD_C (WAITFD_E|WAITFD_W)
47 int socket_waitfd(p_socket ps
, int sw
, p_timeout tm
) {
49 fd_set rfds
, wfds
, efds
, *rp
= NULL
, *wp
= NULL
, *ep
= NULL
;
50 struct timeval tv
, *tp
= NULL
;
52 if (timeout_iszero(tm
)) return IO_TIMEOUT
; /* optimize timeout == 0 case */
58 if (sw
& WAITFD_W
) { FD_ZERO(&wfds
); FD_SET(*ps
, &wfds
); wp
= &wfds
; }
59 if (sw
& WAITFD_C
) { FD_ZERO(&efds
); FD_SET(*ps
, &efds
); ep
= &efds
; }
60 if ((t
= timeout_get(tm
)) >= 0.0) {
62 tv
.tv_usec
= (int) ((t
-tv
.tv_sec
)*1.0e6
);
65 ret
= select(0, rp
, wp
, ep
, tp
);
66 if (ret
== -1) return WSAGetLastError();
67 if (ret
== 0) return IO_TIMEOUT
;
68 if (sw
== WAITFD_C
&& FD_ISSET(*ps
, &efds
)) return IO_CLOSED
;
72 /*-------------------------------------------------------------------------*\
73 * Select with int timeout in ms
74 \*-------------------------------------------------------------------------*/
75 int socket_select(t_socket n
, fd_set
*rfds
, fd_set
*wfds
, fd_set
*efds
,
78 double t
= timeout_get(tm
);
80 tv
.tv_usec
= (int) ((t
- tv
.tv_sec
) * 1.0e6
);
82 Sleep((DWORD
) (1000*t
));
84 } else return select(0, rfds
, wfds
, efds
, t
>= 0.0? &tv
: NULL
);
87 /*-------------------------------------------------------------------------*\
88 * Close and inutilize socket
89 \*-------------------------------------------------------------------------*/
90 void socket_destroy(p_socket ps
) {
91 if (*ps
!= SOCKET_INVALID
) {
92 socket_setblocking(ps
); /* close can take a long time on WIN32 */
98 /*-------------------------------------------------------------------------*\
100 \*-------------------------------------------------------------------------*/
101 void socket_shutdown(p_socket ps
, int how
) {
102 socket_setblocking(ps
);
104 socket_setnonblocking(ps
);
107 /*-------------------------------------------------------------------------*\
108 * Creates and sets up a socket
109 \*-------------------------------------------------------------------------*/
110 int socket_create(p_socket ps
, int domain
, int type
, int protocol
) {
111 *ps
= socket(domain
, type
, protocol
);
112 if (*ps
!= SOCKET_INVALID
) return IO_DONE
;
113 else return WSAGetLastError();
116 /*-------------------------------------------------------------------------*\
117 * Connects or returns error message
118 \*-------------------------------------------------------------------------*/
119 int socket_connect(p_socket ps
, SA
*addr
, socklen_t len
, p_timeout tm
) {
121 /* don't call on closed socket */
122 if (*ps
== SOCKET_INVALID
) return IO_CLOSED
;
123 /* ask system to connect */
124 if (connect(*ps
, addr
, len
) == 0) return IO_DONE
;
125 /* make sure the system is trying to connect */
126 err
= WSAGetLastError();
127 if (err
!= WSAEWOULDBLOCK
&& err
!= WSAEINPROGRESS
) return err
;
128 /* zero timeout case optimization */
129 if (timeout_iszero(tm
)) return IO_TIMEOUT
;
130 /* we wait until something happens */
131 err
= socket_waitfd(ps
, WAITFD_C
, tm
);
132 if (err
== IO_CLOSED
) {
133 int len
= sizeof(err
);
134 /* give windows time to set the error (yes, disgusting) */
136 /* find out why we failed */
137 getsockopt(*ps
, SOL_SOCKET
, SO_ERROR
, (char *)&err
, &len
);
138 /* we KNOW there was an error. if 'why' is 0, we will return
139 * "unknown error", but it's not really our fault */
140 return err
> 0? err
: IO_UNKNOWN
;
145 /*-------------------------------------------------------------------------*\
146 * Binds or returns error message
147 \*-------------------------------------------------------------------------*/
148 int socket_bind(p_socket ps
, SA
*addr
, socklen_t len
) {
150 socket_setblocking(ps
);
151 if (bind(*ps
, addr
, len
) < 0) err
= WSAGetLastError();
152 socket_setnonblocking(ps
);
156 /*-------------------------------------------------------------------------*\
158 \*-------------------------------------------------------------------------*/
159 int socket_listen(p_socket ps
, int backlog
) {
161 socket_setblocking(ps
);
162 if (listen(*ps
, backlog
) < 0) err
= WSAGetLastError();
163 socket_setnonblocking(ps
);
167 /*-------------------------------------------------------------------------*\
168 * Accept with timeout
169 \*-------------------------------------------------------------------------*/
170 int socket_accept(p_socket ps
, p_socket pa
, SA
*addr
, socklen_t
*len
,
172 if (*ps
== SOCKET_INVALID
) return IO_CLOSED
;
175 /* try to get client socket */
176 if ((*pa
= accept(*ps
, addr
, len
)) != SOCKET_INVALID
) return IO_DONE
;
177 /* find out why we failed */
178 err
= WSAGetLastError();
179 /* if we failed because there was no connectoin, keep trying */
180 if (err
!= WSAEWOULDBLOCK
&& err
!= WSAECONNABORTED
) return err
;
181 /* call select to avoid busy wait */
182 if ((err
= socket_waitfd(ps
, WAITFD_R
, tm
)) != IO_DONE
) return err
;
186 /*-------------------------------------------------------------------------*\
188 * On windows, if you try to send 10MB, the OS will buffer EVERYTHING
189 * this can take an awful lot of time and we will end up blocked.
190 * Therefore, whoever calls this function should not pass a huge buffer.
191 \*-------------------------------------------------------------------------*/
192 int socket_send(p_socket ps
, const char *data
, size_t count
,
193 size_t *sent
, p_timeout tm
)
197 /* avoid making system calls on closed sockets */
198 if (*ps
== SOCKET_INVALID
) return IO_CLOSED
;
199 /* loop until we send something or we give up on error */
201 /* try to send something */
202 int put
= send(*ps
, data
, (int) count
, 0);
203 /* if we sent something, we are done */
208 /* deal with failure */
209 err
= WSAGetLastError();
210 /* we can only proceed if there was no serious error */
211 if (err
!= WSAEWOULDBLOCK
) return err
;
212 /* avoid busy wait */
213 if ((err
= socket_waitfd(ps
, WAITFD_W
, tm
)) != IO_DONE
) return err
;
217 /*-------------------------------------------------------------------------*\
218 * Sendto with timeout
219 \*-------------------------------------------------------------------------*/
220 int socket_sendto(p_socket ps
, const char *data
, size_t count
, size_t *sent
,
221 SA
*addr
, socklen_t len
, p_timeout tm
)
225 if (*ps
== SOCKET_INVALID
) return IO_CLOSED
;
227 int put
= sendto(*ps
, data
, (int) count
, 0, addr
, len
);
232 err
= WSAGetLastError();
233 if (err
!= WSAEWOULDBLOCK
) return err
;
234 if ((err
= socket_waitfd(ps
, WAITFD_W
, tm
)) != IO_DONE
) return err
;
238 /*-------------------------------------------------------------------------*\
239 * Receive with timeout
240 \*-------------------------------------------------------------------------*/
241 int socket_recv(p_socket ps
, char *data
, size_t count
, size_t *got
, p_timeout tm
) {
244 if (*ps
== SOCKET_INVALID
) return IO_CLOSED
;
246 int taken
= recv(*ps
, data
, (int) count
, 0);
251 if (taken
== 0) return IO_CLOSED
;
252 err
= WSAGetLastError();
253 if (err
!= WSAEWOULDBLOCK
) return err
;
254 if ((err
= socket_waitfd(ps
, WAITFD_R
, tm
)) != IO_DONE
) return err
;
258 /*-------------------------------------------------------------------------*\
259 * Recvfrom with timeout
260 \*-------------------------------------------------------------------------*/
261 int socket_recvfrom(p_socket ps
, char *data
, size_t count
, size_t *got
,
262 SA
*addr
, socklen_t
*len
, p_timeout tm
) {
265 if (*ps
== SOCKET_INVALID
) return IO_CLOSED
;
267 int taken
= recvfrom(*ps
, data
, (int) count
, 0, addr
, len
);
272 if (taken
== 0) return IO_CLOSED
;
273 err
= WSAGetLastError();
274 if (err
!= WSAEWOULDBLOCK
) return err
;
275 if ((err
= socket_waitfd(ps
, WAITFD_R
, tm
)) != IO_DONE
) return err
;
279 /*-------------------------------------------------------------------------*\
280 * Put socket into blocking mode
281 \*-------------------------------------------------------------------------*/
282 void socket_setblocking(p_socket ps
) {
284 ioctlsocket(*ps
, FIONBIO
, &argp
);
287 /*-------------------------------------------------------------------------*\
288 * Put socket into non-blocking mode
289 \*-------------------------------------------------------------------------*/
290 void socket_setnonblocking(p_socket ps
) {
292 ioctlsocket(*ps
, FIONBIO
, &argp
);
295 /*-------------------------------------------------------------------------*\
297 \*-------------------------------------------------------------------------*/
298 int socket_gethostbyaddr(const char *addr
, socklen_t len
, struct hostent
**hp
) {
299 *hp
= gethostbyaddr(addr
, len
, AF_INET
);
300 if (*hp
) return IO_DONE
;
301 else return WSAGetLastError();
304 int socket_gethostbyname(const char *addr
, struct hostent
**hp
) {
305 *hp
= gethostbyname(addr
);
306 if (*hp
) return IO_DONE
;
307 else return WSAGetLastError();
310 /*-------------------------------------------------------------------------*\
311 * Error translation functions
312 \*-------------------------------------------------------------------------*/
313 const char *socket_hoststrerror(int err
) {
314 if (err
<= 0) return io_strerror(err
);
316 case WSAHOST_NOT_FOUND
: return "host not found";
317 default: return wstrerror(err
);
321 const char *socket_strerror(int err
) {
322 if (err
<= 0) return io_strerror(err
);
324 case WSAEADDRINUSE
: return "address already in use";
325 case WSAECONNREFUSED
: return "connection refused";
326 case WSAEISCONN
: return "already connected";
327 case WSAEACCES
: return "permission denied";
328 case WSAECONNABORTED
: return "closed";
329 case WSAECONNRESET
: return "closed";
330 case WSAETIMEDOUT
: return "timeout";
331 default: return wstrerror(err
);
335 const char *socket_ioerror(p_socket ps
, int err
) {
337 return socket_strerror(err
);
340 static const char *wstrerror(int err
) {
342 case WSAEINTR
: return "Interrupted function call";
343 case WSAEACCES
: return "Permission denied";
344 case WSAEFAULT
: return "Bad address";
345 case WSAEINVAL
: return "Invalid argument";
346 case WSAEMFILE
: return "Too many open files";
347 case WSAEWOULDBLOCK
: return "Resource temporarily unavailable";
348 case WSAEINPROGRESS
: return "Operation now in progress";
349 case WSAEALREADY
: return "Operation already in progress";
350 case WSAENOTSOCK
: return "Socket operation on nonsocket";
351 case WSAEDESTADDRREQ
: return "Destination address required";
352 case WSAEMSGSIZE
: return "Message too long";
353 case WSAEPROTOTYPE
: return "Protocol wrong type for socket";
354 case WSAENOPROTOOPT
: return "Bad protocol option";
355 case WSAEPROTONOSUPPORT
: return "Protocol not supported";
356 case WSAESOCKTNOSUPPORT
: return "Socket type not supported";
357 case WSAEOPNOTSUPP
: return "Operation not supported";
358 case WSAEPFNOSUPPORT
: return "Protocol family not supported";
359 case WSAEAFNOSUPPORT
:
360 return "Address family not supported by protocol family";
361 case WSAEADDRINUSE
: return "Address already in use";
362 case WSAEADDRNOTAVAIL
: return "Cannot assign requested address";
363 case WSAENETDOWN
: return "Network is down";
364 case WSAENETUNREACH
: return "Network is unreachable";
365 case WSAENETRESET
: return "Network dropped connection on reset";
366 case WSAECONNABORTED
: return "Software caused connection abort";
367 case WSAECONNRESET
: return "Connection reset by peer";
368 case WSAENOBUFS
: return "No buffer space available";
369 case WSAEISCONN
: return "Socket is already connected";
370 case WSAENOTCONN
: return "Socket is not connected";
371 case WSAESHUTDOWN
: return "Cannot send after socket shutdown";
372 case WSAETIMEDOUT
: return "Connection timed out";
373 case WSAECONNREFUSED
: return "Connection refused";
374 case WSAEHOSTDOWN
: return "Host is down";
375 case WSAEHOSTUNREACH
: return "No route to host";
376 case WSAEPROCLIM
: return "Too many processes";
377 case WSASYSNOTREADY
: return "Network subsystem is unavailable";
378 case WSAVERNOTSUPPORTED
: return "Winsock.dll version out of range";
379 case WSANOTINITIALISED
:
380 return "Successful WSAStartup not yet performed";
381 case WSAEDISCON
: return "Graceful shutdown in progress";
382 case WSAHOST_NOT_FOUND
: return "Host not found";
383 case WSATRY_AGAIN
: return "Nonauthoritative host not found";
384 case WSANO_RECOVERY
: return "Nonrecoverable name lookup error";
385 case WSANO_DATA
: return "Valid name, no data record of requested type";
386 default: return "Unknown error";
390 const char *socket_gaistrerror(int err
) {
391 if (err
== 0) return NULL
;
393 case EAI_AGAIN
: return "temporary failure in name resolution";
394 case EAI_BADFLAGS
: return "invalid value for ai_flags";
396 case EAI_BADHINTS
: return "invalid value for hints";
398 case EAI_FAIL
: return "non-recoverable failure in name resolution";
399 case EAI_FAMILY
: return "ai_family not supported";
400 case EAI_MEMORY
: return "memory allocation failure";
402 return "host or service not provided, or not known";
403 // case EAI_OVERFLOW: return "argument buffer overflow";
405 case EAI_PROTOCOL
: return "resolved protocol is unknown";
407 case EAI_SERVICE
: return "service not supported for socket type";
408 case EAI_SOCKTYPE
: return "ai_socktype not supported";
409 // case EAI_SYSTEM: return strerror(errno);
410 default: return gai_strerror(err
);