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 }