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