|
1 /*=========================================================================*\ |
|
2 * LuaSocket 2.0.2 |
|
3 * Copyright (C) 2004-2007 Diego Nehab |
|
4 * |
|
5 * Socket compatibilization module for Win32 |
|
6 * |
|
7 * The penalty of calling select to avoid busy-wait is only paid when |
|
8 * the I/O call fail in the first place. |
|
9 * |
|
10 * RCS ID: $Id: wsocket.c,v 1.36 2007/06/11 23:44:54 diego Exp $ |
|
11 \*=========================================================================*/ |
|
12 #include <string.h> |
|
13 |
|
14 #include "socket.h" |
|
15 |
|
16 /*-------------------------------------------------------------------------*\ |
|
17 * Initializes module |
|
18 \*-------------------------------------------------------------------------*/ |
|
19 int socket_open(void) { |
|
20 WSADATA wsaData; |
|
21 WORD wVersionRequested = MAKEWORD(2, 0); |
|
22 int err = WSAStartup(wVersionRequested, &wsaData ); |
|
23 if (err != 0) return 0; |
|
24 if ((LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 0) && |
|
25 (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1)) { |
|
26 WSACleanup(); |
|
27 return 0; |
|
28 } |
|
29 return 1; |
|
30 } |
|
31 |
|
32 /*-------------------------------------------------------------------------*\ |
|
33 * Close module |
|
34 \*-------------------------------------------------------------------------*/ |
|
35 int socket_close(void) { |
|
36 WSACleanup(); |
|
37 return 1; |
|
38 } |
|
39 |
|
40 /*-------------------------------------------------------------------------*\ |
|
41 * Wait for readable/writable/connected socket with timeout |
|
42 \*-------------------------------------------------------------------------*/ |
|
43 int socket_waitfd(p_socket ps, int sw, p_timeout tm) { |
|
44 int ret; |
|
45 fd_set rfds, wfds, efds, *rp = NULL, *wp = NULL, *ep = NULL; |
|
46 struct timeval tv, *tp = NULL; |
|
47 double t; |
|
48 if (timeout_iszero(tm)) return IO_TIMEOUT; /* optimize timeout == 0 case */ |
|
49 if (sw & WAITFD_R) { |
|
50 FD_ZERO(&rfds); |
|
51 FD_SET(*ps, &rfds); |
|
52 rp = &rfds; |
|
53 } |
|
54 if (sw & WAITFD_W) { FD_ZERO(&wfds); FD_SET(*ps, &wfds); wp = &wfds; } |
|
55 if (sw & WAITFD_C) { FD_ZERO(&efds); FD_SET(*ps, &efds); ep = &efds; } |
|
56 if ((t = timeout_get(tm)) >= 0.0) { |
|
57 tv.tv_sec = (int) t; |
|
58 tv.tv_usec = (int) ((t-tv.tv_sec)*1.0e6); |
|
59 tp = &tv; |
|
60 } |
|
61 ret = select(0, rp, wp, ep, tp); |
|
62 if (ret == -1) return WSAGetLastError(); |
|
63 if (ret == 0) return IO_TIMEOUT; |
|
64 if (sw == WAITFD_C && FD_ISSET(*ps, &efds)) return IO_CLOSED; |
|
65 return IO_DONE; |
|
66 } |
|
67 |
|
68 /*-------------------------------------------------------------------------*\ |
|
69 * Close and inutilize socket |
|
70 \*-------------------------------------------------------------------------*/ |
|
71 void socket_destroy(p_socket ps) { |
|
72 if (*ps != SOCKET_INVALID) { |
|
73 socket_setblocking(ps); /* close can take a long time on WIN32 */ |
|
74 closesocket(*ps); |
|
75 *ps = SOCKET_INVALID; |
|
76 } |
|
77 } |
|
78 |
|
79 /*-------------------------------------------------------------------------*\ |
|
80 * Put socket into blocking mode |
|
81 \*-------------------------------------------------------------------------*/ |
|
82 void socket_setblocking(p_socket ps) { |
|
83 u_long argp = 0; |
|
84 ioctlsocket(*ps, FIONBIO, &argp); |
|
85 } |
|
86 |
|
87 /*-------------------------------------------------------------------------*\ |
|
88 * Put socket into non-blocking mode |
|
89 \*-------------------------------------------------------------------------*/ |
|
90 void socket_setnonblocking(p_socket ps) { |
|
91 u_long argp = 1; |
|
92 ioctlsocket(*ps, FIONBIO, &argp); |
|
93 } |
|
94 |
|
95 /*-------------------------------------------------------------------------*\ |
|
96 * Error translation functions |
|
97 \*-------------------------------------------------------------------------*/ |
|
98 |
|
99 /* WinSock doesn't have a strerror... */ |
|
100 static const char *wstrerror(int err) { |
|
101 switch (err) { |
|
102 case WSAEINTR: return "Interrupted function call"; |
|
103 case WSAEACCES: return "Permission denied"; |
|
104 case WSAEFAULT: return "Bad address"; |
|
105 case WSAEINVAL: return "Invalid argument"; |
|
106 case WSAEMFILE: return "Too many open files"; |
|
107 case WSAEWOULDBLOCK: return "Resource temporarily unavailable"; |
|
108 case WSAEINPROGRESS: return "Operation now in progress"; |
|
109 case WSAEALREADY: return "Operation already in progress"; |
|
110 case WSAENOTSOCK: return "Socket operation on nonsocket"; |
|
111 case WSAEDESTADDRREQ: return "Destination address required"; |
|
112 case WSAEMSGSIZE: return "Message too long"; |
|
113 case WSAEPROTOTYPE: return "Protocol wrong type for socket"; |
|
114 case WSAENOPROTOOPT: return "Bad protocol option"; |
|
115 case WSAEPROTONOSUPPORT: return "Protocol not supported"; |
|
116 case WSAESOCKTNOSUPPORT: return "Socket type not supported"; |
|
117 case WSAEOPNOTSUPP: return "Operation not supported"; |
|
118 case WSAEPFNOSUPPORT: return "Protocol family not supported"; |
|
119 case WSAEAFNOSUPPORT: |
|
120 return "Address family not supported by protocol family"; |
|
121 case WSAEADDRINUSE: return "Address already in use"; |
|
122 case WSAEADDRNOTAVAIL: return "Cannot assign requested address"; |
|
123 case WSAENETDOWN: return "Network is down"; |
|
124 case WSAENETUNREACH: return "Network is unreachable"; |
|
125 case WSAENETRESET: return "Network dropped connection on reset"; |
|
126 case WSAECONNABORTED: return "Software caused connection abort"; |
|
127 case WSAECONNRESET: return "Connection reset by peer"; |
|
128 case WSAENOBUFS: return "No buffer space available"; |
|
129 case WSAEISCONN: return "Socket is already connected"; |
|
130 case WSAENOTCONN: return "Socket is not connected"; |
|
131 case WSAESHUTDOWN: return "Cannot send after socket shutdown"; |
|
132 case WSAETIMEDOUT: return "Connection timed out"; |
|
133 case WSAECONNREFUSED: return "Connection refused"; |
|
134 case WSAEHOSTDOWN: return "Host is down"; |
|
135 case WSAEHOSTUNREACH: return "No route to host"; |
|
136 case WSAEPROCLIM: return "Too many processes"; |
|
137 case WSASYSNOTREADY: return "Network subsystem is unavailable"; |
|
138 case WSAVERNOTSUPPORTED: return "Winsock.dll version out of range"; |
|
139 case WSANOTINITIALISED: |
|
140 return "Successful WSAStartup not yet performed"; |
|
141 case WSAEDISCON: return "Graceful shutdown in progress"; |
|
142 case WSAHOST_NOT_FOUND: return "Host not found"; |
|
143 case WSATRY_AGAIN: return "Nonauthoritative host not found"; |
|
144 case WSANO_RECOVERY: return "Nonrecoverable name lookup error"; |
|
145 case WSANO_DATA: return "Valid name, no data record of requested type"; |
|
146 default: return "Unknown error"; |
|
147 } |
|
148 } |
|
149 |
|
150 const char *socket_strerror(int err) { |
|
151 if (err <= 0) return io_strerror(err); |
|
152 switch (err) { |
|
153 case WSAEADDRINUSE: return "address already in use"; |
|
154 case WSAECONNREFUSED: return "connection refused"; |
|
155 case WSAEISCONN: return "already connected"; |
|
156 case WSAEACCES: return "permission denied"; |
|
157 case WSAECONNABORTED: return "closed"; |
|
158 case WSAECONNRESET: return "closed"; |
|
159 case WSAETIMEDOUT: return "timeout"; |
|
160 default: return wstrerror(err); |
|
161 } |
|
162 } |
|
163 |
|
164 /* Socket error code */ |
|
165 int socket_error() |
|
166 { |
|
167 return WSAGetLastError(); |
|
168 } |
|
169 |