Mercurial > luasocket
comparison src/wsocket.c @ 0:4b915342e2a8
LuaSocket 2.0.2 + CMake build description.
author | Eric Wing <ewing . public |-at-| gmail . com> |
---|---|
date | Tue, 26 Aug 2008 18:40:01 -0700 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:4b915342e2a8 |
---|---|
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 \*-------------------------------------------------------------------------*/ | |
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 \*-------------------------------------------------------------------------*/ | |
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 | |
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 \*-------------------------------------------------------------------------*/ | |
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 \*-------------------------------------------------------------------------*/ | |
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 \*-------------------------------------------------------------------------*/ | |
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 \*-------------------------------------------------------------------------*/ | |
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 \*-------------------------------------------------------------------------*/ | |
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 \*-------------------------------------------------------------------------*/ | |
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 \*-------------------------------------------------------------------------*/ | |
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 \*-------------------------------------------------------------------------*/ | |
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 \*-------------------------------------------------------------------------*/ | |
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 \*-------------------------------------------------------------------------*/ | |
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 \*-------------------------------------------------------------------------*/ | |
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 \*-------------------------------------------------------------------------*/ | |
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 \*-------------------------------------------------------------------------*/ | |
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 \*-------------------------------------------------------------------------*/ | |
303 void socket_setnonblocking(p_socket ps) { | |
304 u_long argp = 1; | |
305 ioctlsocket(*ps, FIONBIO, &argp); | |
306 } | |
307 | |
308 /*-------------------------------------------------------------------------*\ | |
309 * DNS helpers | |
310 \*-------------------------------------------------------------------------*/ | |
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 | |
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 \*-------------------------------------------------------------------------*/ | |
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 | |
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 | |
348 const char *socket_ioerror(p_socket ps, int err) { | |
349 (void) ps; | |
350 return socket_strerror(err); | |
351 } | |
352 | |
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 } |