1 /*=========================================================================*\
2 * Socket compatibilization module for Win32
3 * LuaSocket toolkit
4 *
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 \*=========================================================================*/
8 #include <string.h>
9
10 #include "socket.h"
11
12 /* WinSock doesn't have a strerror... */
13 static const char *wstrerror(int err);
14
15 /*-------------------------------------------------------------------------*\
16 * Initializes module
17 \*-------------------------------------------------------------------------*/
socket_open(void)18 int socket_open(void) {
19 WSADATA wsaData;
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)) {
25 WSACleanup();
26 return 0;
27 }
28 return 1;
29 }
30
31 /*-------------------------------------------------------------------------*\
32 * Close module
33 \*-------------------------------------------------------------------------*/
socket_close(void)34 int socket_close(void) {
35 WSACleanup();
36 return 1;
37 }
38
39 /*-------------------------------------------------------------------------*\
40 * Wait for readable/writable/connected socket with timeout
41 \*-------------------------------------------------------------------------*/
socket_waitfd(p_socket ps,int sw,p_timeout tm)42 int socket_waitfd(p_socket ps, int sw, p_timeout tm) {
43 int ret;
44 fd_set rfds, wfds, efds, *rp = NULL, *wp = NULL, *ep = NULL;
45 struct timeval tv, *tp = NULL;
46 double t;
47 if (timeout_iszero(tm)) return IO_TIMEOUT; /* optimize timeout == 0 case */
48 if (sw & WAITFD_R) {
49 FD_ZERO(&rfds);
50 FD_SET(*ps, &rfds);
51 rp = &rfds;
52 }
53 if (sw & WAITFD_W) { FD_ZERO(&wfds); FD_SET(*ps, &wfds); wp = &wfds; }
54 if (sw & WAITFD_C) { FD_ZERO(&efds); FD_SET(*ps, &efds); ep = &efds; }
55 if ((t = timeout_get(tm)) >= 0.0) {
56 tv.tv_sec = (int) t;
57 tv.tv_usec = (int) ((t-tv.tv_sec)*1.0e6);
58 tp = &tv;
59 }
60 ret = select(0, rp, wp, ep, tp);
61 if (ret == -1) return WSAGetLastError();
62 if (ret == 0) return IO_TIMEOUT;
63 if (sw == WAITFD_C && FD_ISSET(*ps, &efds)) return IO_CLOSED;
64 return IO_DONE;
65 }
66
67 /*-------------------------------------------------------------------------*\
68 * Select with int timeout in ms
69 \*-------------------------------------------------------------------------*/
socket_select(t_socket n,fd_set * rfds,fd_set * wfds,fd_set * efds,p_timeout tm)70 int socket_select(t_socket n, fd_set *rfds, fd_set *wfds, fd_set *efds,
71 p_timeout tm) {
72 struct timeval tv;
73 double t = timeout_get(tm);
74 tv.tv_sec = (int) t;
75 tv.tv_usec = (int) ((t - tv.tv_sec) * 1.0e6);
76 if (n <= 0) {
77 Sleep((DWORD) (1000*t));
78 return 0;
79 } else return select(0, rfds, wfds, efds, t >= 0.0? &tv: NULL);
80 }
81
82 /*-------------------------------------------------------------------------*\
83 * Close and inutilize socket
84 \*-------------------------------------------------------------------------*/
socket_destroy(p_socket ps)85 void socket_destroy(p_socket ps) {
86 if (*ps != SOCKET_INVALID) {
87 socket_setblocking(ps); /* close can take a long time on WIN32 */
88 closesocket(*ps);
89 *ps = SOCKET_INVALID;
90 }
91 }
92
93 /*-------------------------------------------------------------------------*\
94 *
95 \*-------------------------------------------------------------------------*/
socket_shutdown(p_socket ps,int how)96 void socket_shutdown(p_socket ps, int how) {
97 socket_setblocking(ps);
98 shutdown(*ps, how);
99 socket_setnonblocking(ps);
100 }
101
102 /*-------------------------------------------------------------------------*\
103 * Creates and sets up a socket
104 \*-------------------------------------------------------------------------*/
socket_create(p_socket ps,int domain,int type,int protocol)105 int socket_create(p_socket ps, int domain, int type, int protocol) {
106 *ps = socket(domain, type, protocol);
107 if (*ps != SOCKET_INVALID) return IO_DONE;
108 else return WSAGetLastError();
109 }
110
111 /*-------------------------------------------------------------------------*\
112 * Connects or returns error message
113 \*-------------------------------------------------------------------------*/
socket_connect(p_socket ps,SA * addr,socklen_t len,p_timeout tm)114 int socket_connect(p_socket ps, SA *addr, socklen_t len, p_timeout tm) {
115 int err;
116 /* don't call on closed socket */
117 if (*ps == SOCKET_INVALID) return IO_CLOSED;
118 /* ask system to connect */
119 if (connect(*ps, addr, len) == 0) return IO_DONE;
120 /* make sure the system is trying to connect */
121 err = WSAGetLastError();
122 if (err != WSAEWOULDBLOCK && err != WSAEINPROGRESS) return err;
123 /* zero timeout case optimization */
124 if (timeout_iszero(tm)) return IO_TIMEOUT;
125 /* we wait until something happens */
126 err = socket_waitfd(ps, WAITFD_C, tm);
127 if (err == IO_CLOSED) {
128 int len = sizeof(err);
129 /* give windows time to set the error (yes, disgusting) */
130 Sleep(10);
131 /* find out why we failed */
132 getsockopt(*ps, SOL_SOCKET, SO_ERROR, (char *)&err, &len);
133 /* we KNOW there was an error. if 'why' is 0, we will return
134 * "unknown error", but it's not really our fault */
135 return err > 0? err: IO_UNKNOWN;
136 } else return err;
137
138 }
139
140 /*-------------------------------------------------------------------------*\
141 * Binds or returns error message
142 \*-------------------------------------------------------------------------*/
socket_bind(p_socket ps,SA * addr,socklen_t len)143 int socket_bind(p_socket ps, SA *addr, socklen_t len) {
144 int err = IO_DONE;
145 socket_setblocking(ps);
146 if (bind(*ps, addr, len) < 0) err = WSAGetLastError();
147 socket_setnonblocking(ps);
148 return err;
149 }
150
151 /*-------------------------------------------------------------------------*\
152 *
153 \*-------------------------------------------------------------------------*/
socket_listen(p_socket ps,int backlog)154 int socket_listen(p_socket ps, int backlog) {
155 int err = IO_DONE;
156 socket_setblocking(ps);
157 if (listen(*ps, backlog) < 0) err = WSAGetLastError();
158 socket_setnonblocking(ps);
159 return err;
160 }
161
162 /*-------------------------------------------------------------------------*\
163 * Accept with timeout
164 \*-------------------------------------------------------------------------*/
socket_accept(p_socket ps,p_socket pa,SA * addr,socklen_t * len,p_timeout tm)165 int socket_accept(p_socket ps, p_socket pa, SA *addr, socklen_t *len,
166 p_timeout tm) {
167 if (*ps == SOCKET_INVALID) return IO_CLOSED;
168 for ( ;; ) {
169 int err;
170 /* try to get client socket */
171 if ((*pa = accept(*ps, addr, len)) != SOCKET_INVALID) return IO_DONE;
172 /* find out why we failed */
173 err = WSAGetLastError();
174 /* if we failed because there was no connectoin, keep trying */
175 if (err != WSAEWOULDBLOCK && err != WSAECONNABORTED) return err;
176 /* call select to avoid busy wait */
177 if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err;
178 }
179 }
180
181 /*-------------------------------------------------------------------------*\
182 * Send with timeout
183 * On windows, if you try to send 10MB, the OS will buffer EVERYTHING
184 * this can take an awful lot of time and we will end up blocked.
185 * Therefore, whoever calls this function should not pass a huge buffer.
186 \*-------------------------------------------------------------------------*/
socket_send(p_socket ps,const char * data,size_t count,size_t * sent,p_timeout tm)187 int socket_send(p_socket ps, const char *data, size_t count,
188 size_t *sent, p_timeout tm)
189 {
190 int err;
191 *sent = 0;
192 /* avoid making system calls on closed sockets */
193 if (*ps == SOCKET_INVALID) return IO_CLOSED;
194 /* loop until we send something or we give up on error */
195 for ( ;; ) {
196 /* try to send something */
197 int put = send(*ps, data, (int) count, 0);
198 /* if we sent something, we are done */
199 if (put > 0) {
200 *sent = put;
201 return IO_DONE;
202 }
203 /* deal with failure */
204 err = WSAGetLastError();
205 /* we can only proceed if there was no serious error */
206 if (err != WSAEWOULDBLOCK) return err;
207 /* avoid busy wait */
208 if ((err = socket_waitfd(ps, WAITFD_W, tm)) != IO_DONE) return err;
209 }
210 }
211
212 /*-------------------------------------------------------------------------*\
213 * Sendto with timeout
214 \*-------------------------------------------------------------------------*/
socket_sendto(p_socket ps,const char * data,size_t count,size_t * sent,SA * addr,socklen_t len,p_timeout tm)215 int socket_sendto(p_socket ps, const char *data, size_t count, size_t *sent,
216 SA *addr, socklen_t len, p_timeout tm)
217 {
218 int err;
219 *sent = 0;
220 if (*ps == SOCKET_INVALID) return IO_CLOSED;
221 for ( ;; ) {
222 int put = sendto(*ps, data, (int) count, 0, addr, len);
223 if (put > 0) {
224 *sent = put;
225 return IO_DONE;
226 }
227 err = WSAGetLastError();
228 if (err != WSAEWOULDBLOCK) return err;
229 if ((err = socket_waitfd(ps, WAITFD_W, tm)) != IO_DONE) return err;
230 }
231 }
232
233 /*-------------------------------------------------------------------------*\
234 * Receive with timeout
235 \*-------------------------------------------------------------------------*/
socket_recv(p_socket ps,char * data,size_t count,size_t * got,p_timeout tm)236 int socket_recv(p_socket ps, char *data, size_t count, size_t *got,
237 p_timeout tm)
238 {
239 int err, prev = IO_DONE;
240 *got = 0;
241 if (*ps == SOCKET_INVALID) return IO_CLOSED;
242 for ( ;; ) {
243 int taken = recv(*ps, data, (int) count, 0);
244 if (taken > 0) {
245 *got = taken;
246 return IO_DONE;
247 }
248 if (taken == 0) return IO_CLOSED;
249 err = WSAGetLastError();
250 /* On UDP, a connreset simply means the previous send failed.
251 * So we try again.
252 * On TCP, it means our socket is now useless, so the error passes.
253 * (We will loop again, exiting because the same error will happen) */
254 if (err != WSAEWOULDBLOCK) {
255 if (err != WSAECONNRESET || prev == WSAECONNRESET) return err;
256 prev = err;
257 }
258 if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err;
259 }
260 }
261
262 /*-------------------------------------------------------------------------*\
263 * Recvfrom with timeout
264 \*-------------------------------------------------------------------------*/
socket_recvfrom(p_socket ps,char * data,size_t count,size_t * got,SA * addr,socklen_t * len,p_timeout tm)265 int socket_recvfrom(p_socket ps, char *data, size_t count, size_t *got,
266 SA *addr, socklen_t *len, p_timeout tm)
267 {
268 int err, prev = IO_DONE;
269 *got = 0;
270 if (*ps == SOCKET_INVALID) return IO_CLOSED;
271 for ( ;; ) {
272 int taken = recvfrom(*ps, data, (int) count, 0, addr, len);
273 if (taken > 0) {
274 *got = taken;
275 return IO_DONE;
276 }
277 if (taken == 0) return IO_CLOSED;
278 err = WSAGetLastError();
279 /* On UDP, a connreset simply means the previous send failed.
280 * So we try again.
281 * On TCP, it means our socket is now useless, so the error passes.
282 * (We will loop again, exiting because the same error will happen) */
283 if (err != WSAEWOULDBLOCK) {
284 if (err != WSAECONNRESET || prev == WSAECONNRESET) return err;
285 prev = err;
286 }
287 if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err;
288 }
289 }
290
291 /*-------------------------------------------------------------------------*\
292 * Put socket into blocking mode
293 \*-------------------------------------------------------------------------*/
socket_setblocking(p_socket ps)294 void socket_setblocking(p_socket ps) {
295 u_long argp = 0;
296 ioctlsocket(*ps, FIONBIO, &argp);
297 }
298
299 /*-------------------------------------------------------------------------*\
300 * Put socket into non-blocking mode
301 \*-------------------------------------------------------------------------*/
socket_setnonblocking(p_socket ps)302 void socket_setnonblocking(p_socket ps) {
303 u_long argp = 1;
304 ioctlsocket(*ps, FIONBIO, &argp);
305 }
306
307 /*-------------------------------------------------------------------------*\
308 * DNS helpers
309 \*-------------------------------------------------------------------------*/
socket_gethostbyaddr(const char * addr,socklen_t len,struct hostent ** hp)310 int socket_gethostbyaddr(const char *addr, socklen_t len, struct hostent **hp) {
311 *hp = gethostbyaddr(addr, len, AF_INET);
312 if (*hp) return IO_DONE;
313 else return WSAGetLastError();
314 }
315
socket_gethostbyname(const char * addr,struct hostent ** hp)316 int socket_gethostbyname(const char *addr, struct hostent **hp) {
317 *hp = gethostbyname(addr);
318 if (*hp) return IO_DONE;
319 else return WSAGetLastError();
320 }
321
322 /*-------------------------------------------------------------------------*\
323 * Error translation functions
324 \*-------------------------------------------------------------------------*/
socket_hoststrerror(int err)325 const char *socket_hoststrerror(int err) {
326 if (err <= 0) return io_strerror(err);
327 switch (err) {
328 case WSAHOST_NOT_FOUND: return "host not found";
329 default: return wstrerror(err);
330 }
331 }
332
socket_strerror(int err)333 const char *socket_strerror(int err) {
334 if (err <= 0) return io_strerror(err);
335 switch (err) {
336 case WSAEADDRINUSE: return "address already in use";
337 case WSAECONNREFUSED: return "connection refused";
338 case WSAEISCONN: return "already connected";
339 case WSAEACCES: return "permission denied";
340 case WSAECONNABORTED: return "closed";
341 case WSAECONNRESET: return "closed";
342 case WSAETIMEDOUT: return "timeout";
343 default: return wstrerror(err);
344 }
345 }
346
socket_ioerror(p_socket ps,int err)347 const char *socket_ioerror(p_socket ps, int err) {
348 (void) ps;
349 return socket_strerror(err);
350 }
351
wstrerror(int err)352 static const char *wstrerror(int err) {
353 switch (err) {
354 case WSAEINTR: return "Interrupted function call";
355 case WSAEACCES: return "Permission denied";
356 case WSAEFAULT: return "Bad address";
357 case WSAEINVAL: return "Invalid argument";
358 case WSAEMFILE: return "Too many open files";
359 case WSAEWOULDBLOCK: return "Resource temporarily unavailable";
360 case WSAEINPROGRESS: return "Operation now in progress";
361 case WSAEALREADY: return "Operation already in progress";
362 case WSAENOTSOCK: return "Socket operation on nonsocket";
363 case WSAEDESTADDRREQ: return "Destination address required";
364 case WSAEMSGSIZE: return "Message too long";
365 case WSAEPROTOTYPE: return "Protocol wrong type for socket";
366 case WSAENOPROTOOPT: return "Bad protocol option";
367 case WSAEPROTONOSUPPORT: return "Protocol not supported";
368 case WSAESOCKTNOSUPPORT: return "Socket type not supported";
369 case WSAEOPNOTSUPP: return "Operation not supported";
370 case WSAEPFNOSUPPORT: return "Protocol family not supported";
371 case WSAEAFNOSUPPORT:
372 return "Address family not supported by protocol family";
373 case WSAEADDRINUSE: return "Address already in use";
374 case WSAEADDRNOTAVAIL: return "Cannot assign requested address";
375 case WSAENETDOWN: return "Network is down";
376 case WSAENETUNREACH: return "Network is unreachable";
377 case WSAENETRESET: return "Network dropped connection on reset";
378 case WSAECONNABORTED: return "Software caused connection abort";
379 case WSAECONNRESET: return "Connection reset by peer";
380 case WSAENOBUFS: return "No buffer space available";
381 case WSAEISCONN: return "Socket is already connected";
382 case WSAENOTCONN: return "Socket is not connected";
383 case WSAESHUTDOWN: return "Cannot send after socket shutdown";
384 case WSAETIMEDOUT: return "Connection timed out";
385 case WSAECONNREFUSED: return "Connection refused";
386 case WSAEHOSTDOWN: return "Host is down";
387 case WSAEHOSTUNREACH: return "No route to host";
388 case WSAEPROCLIM: return "Too many processes";
389 case WSASYSNOTREADY: return "Network subsystem is unavailable";
390 case WSAVERNOTSUPPORTED: return "Winsock.dll version out of range";
391 case WSANOTINITIALISED:
392 return "Successful WSAStartup not yet performed";
393 case WSAEDISCON: return "Graceful shutdown in progress";
394 case WSAHOST_NOT_FOUND: return "Host not found";
395 case WSATRY_AGAIN: return "Nonauthoritative host not found";
396 case WSANO_RECOVERY: return "Nonrecoverable name lookup error";
397 case WSANO_DATA: return "Valid name, no data record of requested type";
398 default: return "Unknown error";
399 }
400 }
401
socket_gaistrerror(int err)402 const char *socket_gaistrerror(int err) {
403 if (err == 0) return NULL;
404 switch (err) {
405 case EAI_AGAIN: return "temporary failure in name resolution";
406 case EAI_BADFLAGS: return "invalid value for ai_flags";
407 #ifdef EAI_BADHINTS
408 case EAI_BADHINTS: return "invalid value for hints";
409 #endif
410 case EAI_FAIL: return "non-recoverable failure in name resolution";
411 case EAI_FAMILY: return "ai_family not supported";
412 case EAI_MEMORY: return "memory allocation failure";
413 case EAI_NONAME:
414 return "host or service not provided, or not known";
415 #ifdef EAI_OVERFLOW
416 case EAI_OVERFLOW: return "argument buffer overflow";
417 #endif
418 #ifdef EAI_PROTOCOL
419 case EAI_PROTOCOL: return "resolved protocol is unknown";
420 #endif
421 case EAI_SERVICE: return "service not supported for socket type";
422 case EAI_SOCKTYPE: return "ai_socktype not supported";
423 #ifdef EAI_SYSTEM
424 case EAI_SYSTEM: return strerror(errno);
425 #endif
426 default: return gai_strerror(err);
427 }
428 }
429
430