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 \*-------------------------------------------------------------------------*/
42 #define WAITFD_R        1
43 #define WAITFD_W        2
44 #define WAITFD_E        4
45 #define WAITFD_C        (WAITFD_E|WAITFD_W)
46 
socket_waitfd(p_socket ps,int sw,p_timeout tm)47 int socket_waitfd(p_socket ps, int sw, p_timeout tm) {
48     int ret;
49     fd_set rfds, wfds, efds, *rp = NULL, *wp = NULL, *ep = NULL;
50     struct timeval tv, *tp = NULL;
51     double t;
52     if (timeout_iszero(tm)) return IO_TIMEOUT;  /* optimize timeout == 0 case */
53     if (sw & WAITFD_R) {
54         FD_ZERO(&rfds);
55         FD_SET(*ps, &rfds);
56         rp = &rfds;
57     }
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) {
61         tv.tv_sec = (int) t;
62         tv.tv_usec = (int) ((t-tv.tv_sec)*1.0e6);
63         tp = &tv;
64     }
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;
69     return IO_DONE;
70 }
71 
72 /*-------------------------------------------------------------------------*\
73 * Select with int timeout in ms
74 \*-------------------------------------------------------------------------*/
socket_select(t_socket n,fd_set * rfds,fd_set * wfds,fd_set * efds,p_timeout tm)75 int socket_select(t_socket n, fd_set *rfds, fd_set *wfds, fd_set *efds,
76         p_timeout tm) {
77     struct timeval tv;
78     double t = timeout_get(tm);
79     tv.tv_sec = (int) t;
80     tv.tv_usec = (int) ((t - tv.tv_sec) * 1.0e6);
81     if (n <= 0) {
82         Sleep((DWORD) (1000*t));
83         return 0;
84     } else return select(0, rfds, wfds, efds, t >= 0.0? &tv: NULL);
85 }
86 
87 /*-------------------------------------------------------------------------*\
88 * Close and inutilize socket
89 \*-------------------------------------------------------------------------*/
socket_destroy(p_socket ps)90 void socket_destroy(p_socket ps) {
91     if (*ps != SOCKET_INVALID) {
92         socket_setblocking(ps); /* close can take a long time on WIN32 */
93         closesocket(*ps);
94         *ps = SOCKET_INVALID;
95     }
96 }
97 
98 /*-------------------------------------------------------------------------*\
99 *
100 \*-------------------------------------------------------------------------*/
socket_shutdown(p_socket ps,int how)101 void socket_shutdown(p_socket ps, int how) {
102     socket_setblocking(ps);
103     shutdown(*ps, how);
104     socket_setnonblocking(ps);
105 }
106 
107 /*-------------------------------------------------------------------------*\
108 * Creates and sets up a socket
109 \*-------------------------------------------------------------------------*/
socket_create(p_socket ps,int domain,int type,int protocol)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();
114 }
115 
116 /*-------------------------------------------------------------------------*\
117 * Connects or returns error message
118 \*-------------------------------------------------------------------------*/
socket_connect(p_socket ps,SA * addr,socklen_t len,p_timeout tm)119 int socket_connect(p_socket ps, SA *addr, socklen_t len, p_timeout tm) {
120     int err;
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) */
135         Sleep(10);
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;
141     } else return err;
142 
143 }
144 
145 /*-------------------------------------------------------------------------*\
146 * Binds or returns error message
147 \*-------------------------------------------------------------------------*/
socket_bind(p_socket ps,SA * addr,socklen_t len)148 int socket_bind(p_socket ps, SA *addr, socklen_t len) {
149     int err = IO_DONE;
150     socket_setblocking(ps);
151     if (bind(*ps, addr, len) < 0) err = WSAGetLastError();
152     socket_setnonblocking(ps);
153     return err;
154 }
155 
156 /*-------------------------------------------------------------------------*\
157 *
158 \*-------------------------------------------------------------------------*/
socket_listen(p_socket ps,int backlog)159 int socket_listen(p_socket ps, int backlog) {
160     int err = IO_DONE;
161     socket_setblocking(ps);
162     if (listen(*ps, backlog) < 0) err = WSAGetLastError();
163     socket_setnonblocking(ps);
164     return err;
165 }
166 
167 /*-------------------------------------------------------------------------*\
168 * Accept with timeout
169 \*-------------------------------------------------------------------------*/
socket_accept(p_socket ps,p_socket pa,SA * addr,socklen_t * len,p_timeout tm)170 int socket_accept(p_socket ps, p_socket pa, SA *addr, socklen_t *len,
171         p_timeout tm) {
172     if (*ps == SOCKET_INVALID) return IO_CLOSED;
173     for ( ;; ) {
174         int err;
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;
183     }
184 }
185 
186 /*-------------------------------------------------------------------------*\
187 * Send with timeout
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 \*-------------------------------------------------------------------------*/
socket_send(p_socket ps,const char * data,size_t count,size_t * sent,p_timeout tm)192 int socket_send(p_socket ps, const char *data, size_t count,
193         size_t *sent, p_timeout tm)
194 {
195     int err;
196     *sent = 0;
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 */
200     for ( ;; ) {
201         /* try to send something */
202         int put = send(*ps, data, (int) count, 0);
203         /* if we sent something, we are done */
204         if (put > 0) {
205             *sent = put;
206             return IO_DONE;
207         }
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;
214     }
215 }
216 
217 /*-------------------------------------------------------------------------*\
218 * Sendto with timeout
219 \*-------------------------------------------------------------------------*/
socket_sendto(p_socket ps,const char * data,size_t count,size_t * sent,SA * addr,socklen_t len,p_timeout tm)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)
222 {
223     int err;
224     *sent = 0;
225     if (*ps == SOCKET_INVALID) return IO_CLOSED;
226     for ( ;; ) {
227         int put = sendto(*ps, data, (int) count, 0, addr, len);
228         if (put > 0) {
229             *sent = put;
230             return IO_DONE;
231         }
232         err = WSAGetLastError();
233         if (err != WSAEWOULDBLOCK) return err;
234         if ((err = socket_waitfd(ps, WAITFD_W, tm)) != IO_DONE) return err;
235     }
236 }
237 
238 /*-------------------------------------------------------------------------*\
239 * Receive with timeout
240 \*-------------------------------------------------------------------------*/
socket_recv(p_socket ps,char * data,size_t count,size_t * got,p_timeout tm)241 int socket_recv(p_socket ps, char *data, size_t count, size_t *got, p_timeout tm) {
242     int err;
243     *got = 0;
244     if (*ps == SOCKET_INVALID) return IO_CLOSED;
245     for ( ;; ) {
246         int taken = recv(*ps, data, (int) count, 0);
247         if (taken > 0) {
248             *got = taken;
249             return IO_DONE;
250         }
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;
255     }
256 }
257 
258 /*-------------------------------------------------------------------------*\
259 * Recvfrom with timeout
260 \*-------------------------------------------------------------------------*/
socket_recvfrom(p_socket ps,char * data,size_t count,size_t * got,SA * addr,socklen_t * len,p_timeout tm)261 int socket_recvfrom(p_socket ps, char *data, size_t count, size_t *got,
262         SA *addr, socklen_t *len, p_timeout tm) {
263     int err;
264     *got = 0;
265     if (*ps == SOCKET_INVALID) return IO_CLOSED;
266     for ( ;; ) {
267         int taken = recvfrom(*ps, data, (int) count, 0, addr, len);
268         if (taken > 0) {
269             *got = taken;
270             return IO_DONE;
271         }
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;
276     }
277 }
278 
279 /*-------------------------------------------------------------------------*\
280 * Put socket into blocking mode
281 \*-------------------------------------------------------------------------*/
socket_setblocking(p_socket ps)282 void socket_setblocking(p_socket ps) {
283     u_long argp = 0;
284     ioctlsocket(*ps, FIONBIO, &argp);
285 }
286 
287 /*-------------------------------------------------------------------------*\
288 * Put socket into non-blocking mode
289 \*-------------------------------------------------------------------------*/
socket_setnonblocking(p_socket ps)290 void socket_setnonblocking(p_socket ps) {
291     u_long argp = 1;
292     ioctlsocket(*ps, FIONBIO, &argp);
293 }
294 
295 /*-------------------------------------------------------------------------*\
296 * DNS helpers
297 \*-------------------------------------------------------------------------*/
socket_gethostbyaddr(const char * addr,socklen_t len,struct hostent ** hp)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();
302 }
303 
socket_gethostbyname(const char * addr,struct hostent ** hp)304 int socket_gethostbyname(const char *addr, struct hostent **hp) {
305     *hp = gethostbyname(addr);
306     if (*hp) return IO_DONE;
307     else return  WSAGetLastError();
308 }
309 
310 /*-------------------------------------------------------------------------*\
311 * Error translation functions
312 \*-------------------------------------------------------------------------*/
socket_hoststrerror(int err)313 const char *socket_hoststrerror(int err) {
314     if (err <= 0) return io_strerror(err);
315     switch (err) {
316         case WSAHOST_NOT_FOUND: return "host not found";
317         default: return wstrerror(err);
318     }
319 }
320 
socket_strerror(int err)321 const char *socket_strerror(int err) {
322     if (err <= 0) return io_strerror(err);
323     switch (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);
332     }
333 }
334 
socket_ioerror(p_socket ps,int err)335 const char *socket_ioerror(p_socket ps, int err) {
336     (void) ps;
337     return socket_strerror(err);
338 }
339 
wstrerror(int err)340 static const char *wstrerror(int err) {
341     switch (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";
387     }
388 }
389 
socket_gaistrerror(int err)390 const char *socket_gaistrerror(int err) {
391     if (err == 0) return NULL;
392     switch (err) {
393         case EAI_AGAIN: return "temporary failure in name resolution";
394         case EAI_BADFLAGS: return "invalid value for ai_flags";
395 #ifdef EAI_BADHINTS
396         case EAI_BADHINTS: return "invalid value for hints";
397 #endif
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";
401         case EAI_NONAME:
402             return "host or service not provided, or not known";
403 //        case EAI_OVERFLOW: return "argument buffer overflow";
404 #ifdef EAI_PROTOCOL
405         case EAI_PROTOCOL: return "resolved protocol is unknown";
406 #endif
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);
411     }
412 }
413 
414