aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDiego Nehab <diego@tecgraf.puc-rio.br>2004-07-02 18:44:05 +0000
committerDiego Nehab <diego@tecgraf.puc-rio.br>2004-07-02 18:44:05 +0000
commitb1a4ad2b1996936744c679e6ae563986ff701a3a (patch)
treec446d3bf2fe5bb0452027ee93388e505c2dfa53d
parent63807d647624df155a81a2b323f370e2c36192f6 (diff)
downloadluasocket-b1a4ad2b1996936744c679e6ae563986ff701a3a.tar.gz
luasocket-b1a4ad2b1996936744c679e6ae563986ff701a3a.tar.bz2
luasocket-b1a4ad2b1996936744c679e6ae563986ff701a3a.zip
Compiles and runs on windows.
-rw-r--r--FIX4
-rw-r--r--src/buffer.h2
-rw-r--r--src/usocket.c38
-rw-r--r--src/wsocket.c469
-rw-r--r--test/mimetest.lua2
-rw-r--r--test/testclnt.lua22
6 files changed, 289 insertions, 248 deletions
diff --git a/FIX b/FIX
index d126226..b1e5851 100644
--- a/FIX
+++ b/FIX
@@ -1,3 +1,6 @@
1new sample unix domain support
2new sample LPD support
3comprehensive error messages in the default case.
1added getstats to help throttle. 4added getstats to help throttle.
2setup error messages in the default case. 5setup error messages in the default case.
3listen defaults to 32 backlog 6listen defaults to 32 backlog
@@ -7,5 +10,4 @@ accepted sockets are nonblocking
7new timming functions. higher resolution, no wrap around 10new timming functions. higher resolution, no wrap around
8bug fixes in the manual 11bug fixes in the manual
9getfd missing cast 12getfd missing cast
10added unix domain support example
11fixed local domain socket kludge of name size 13fixed local domain socket kludge of name size
diff --git a/src/buffer.h b/src/buffer.h
index 3ea2648..3cc885f 100644
--- a/src/buffer.h
+++ b/src/buffer.h
@@ -28,7 +28,7 @@
28/* buffer control structure */ 28/* buffer control structure */
29typedef struct t_buf_ { 29typedef struct t_buf_ {
30 double birthday; /* throttle support info: creation time, */ 30 double birthday; /* throttle support info: creation time, */
31 int sent, received; /* bytes sent, and bytes received */ 31 size_t sent, received; /* bytes sent, and bytes received */
32 p_io io; /* IO driver used for this buffer */ 32 p_io io; /* IO driver used for this buffer */
33 p_tm tm; /* timeout management for this buffer */ 33 p_tm tm; /* timeout management for this buffer */
34 size_t first, last; /* index of first and last bytes of stored data */ 34 size_t first, last; /* index of first and last bytes of stored data */
diff --git a/src/usocket.c b/src/usocket.c
index b99eaa8..0e3d30c 100644
--- a/src/usocket.c
+++ b/src/usocket.c
@@ -2,20 +2,13 @@
2* Socket compatibilization module for Unix 2* Socket compatibilization module for Unix
3* LuaSocket toolkit 3* LuaSocket toolkit
4* 4*
5* We are now treating EINTRs, but if an interrupt happens in the middle of 5* The code is now interrupt-safe.
6* a select function call, we don't guarantee values timeouts anymore. 6* The penalty of calling select to avoid busy-wait is only paid when
7* It's not a big deal, since we are not real-time anyways. 7* the I/O call fail in the first place.
8*
9* We also exchanged the order of the calls to send/recv and select.
10* The idea is that the outer loop (whoever is calling sock_send/recv)
11* will call the function again if we didn't time out, so we can
12* call write and then select only if it fails. This moves the penalty
13* to when data is not available, maximizing the bandwidth if data is
14* always available.
15* 8*
16* RCS ID: $Id$ 9* RCS ID: $Id$
17\*=========================================================================*/ 10\*=========================================================================*/
18#include <string.h> 11#include <string.h>
19#include <signal.h> 12#include <signal.h>
20 13
21#include "socket.h" 14#include "socket.h"
@@ -177,9 +170,9 @@ const char *sock_accept(p_sock ps, p_sock pa, SA *addr,
177 FD_SET(sock, &fds); 170 FD_SET(sock, &fds);
178 err = sock_select(sock+1, &fds, NULL, NULL, tm); 171 err = sock_select(sock+1, &fds, NULL, NULL, tm);
179 if (err == 0) return io_strerror(IO_TIMEOUT); 172 if (err == 0) return io_strerror(IO_TIMEOUT);
180 else if (err < 0) return sock_strerror(); 173 else if (err < 0) break;
181 } 174 }
182 return io_strerror(IO_TIMEOUT); /* can't get here */ 175 return sock_strerror();
183} 176}
184 177
185/*-------------------------------------------------------------------------*\ 178/*-------------------------------------------------------------------------*\
@@ -217,9 +210,10 @@ int sock_send(p_sock ps, const char *data, size_t count, size_t *sent, p_tm tm)
217 FD_SET(sock, &fds); 210 FD_SET(sock, &fds);
218 ret = sock_select(sock+1, NULL, &fds, NULL, tm); 211 ret = sock_select(sock+1, NULL, &fds, NULL, tm);
219 if (ret == 0) return IO_TIMEOUT; 212 if (ret == 0) return IO_TIMEOUT;
220 if (ret < 0) return IO_USER; 213 else if (ret < 0) break;
221 /* otherwise, try sending again */ 214 /* otherwise, try sending again */
222 } 215 }
216 return IO_USER;
223} 217}
224 218
225/*-------------------------------------------------------------------------*\ 219/*-------------------------------------------------------------------------*\
@@ -250,8 +244,9 @@ int sock_sendto(p_sock ps, const char *data, size_t count, size_t *sent,
250 FD_SET(sock, &fds); 244 FD_SET(sock, &fds);
251 ret = sock_select(sock+1, NULL, &fds, NULL, tm); 245 ret = sock_select(sock+1, NULL, &fds, NULL, tm);
252 if (ret == 0) return IO_TIMEOUT; 246 if (ret == 0) return IO_TIMEOUT;
253 if (ret < 0) return IO_USER; 247 else if (ret < 0) break;
254 } 248 }
249 return IO_USER;
255} 250}
256 251
257/*-------------------------------------------------------------------------*\ 252/*-------------------------------------------------------------------------*\
@@ -278,8 +273,9 @@ int sock_recv(p_sock ps, char *data, size_t count, size_t *got, p_tm tm) {
278 FD_SET(sock, &fds); 273 FD_SET(sock, &fds);
279 ret = sock_select(sock+1, &fds, NULL, NULL, tm); 274 ret = sock_select(sock+1, &fds, NULL, NULL, tm);
280 if (ret == 0) return IO_TIMEOUT; 275 if (ret == 0) return IO_TIMEOUT;
281 if (ret < 0) return IO_USER; 276 else if (ret < 0) break;
282 } 277 }
278 return IO_USER;
283} 279}
284 280
285/*-------------------------------------------------------------------------*\ 281/*-------------------------------------------------------------------------*\
@@ -307,8 +303,9 @@ int sock_recvfrom(p_sock ps, char *data, size_t count, size_t *got,
307 FD_SET(sock, &fds); 303 FD_SET(sock, &fds);
308 ret = sock_select(sock+1, &fds, NULL, NULL, tm); 304 ret = sock_select(sock+1, &fds, NULL, NULL, tm);
309 if (ret == 0) return IO_TIMEOUT; 305 if (ret == 0) return IO_TIMEOUT;
310 if (ret < 0) return IO_USER; 306 else if (ret < 0) break;
311 } 307 }
308 return IO_USER;
312} 309}
313 310
314/*-------------------------------------------------------------------------*\ 311/*-------------------------------------------------------------------------*\
@@ -333,7 +330,12 @@ void sock_setnonblocking(p_sock ps) {
333* Error translation functions 330* Error translation functions
334\*-------------------------------------------------------------------------*/ 331\*-------------------------------------------------------------------------*/
335const char *sock_hoststrerror(void) { 332const char *sock_hoststrerror(void) {
336 return hstrerror(h_errno); 333 switch (h_errno) {
334 case HOST_NOT_FOUND:
335 return "host not found";
336 default:
337 return hstrerror(h_errno);
338 }
337} 339}
338 340
339/* make sure important error messages are standard */ 341/* make sure important error messages are standard */
diff --git a/src/wsocket.c b/src/wsocket.c
index 7f3e066..a264452 100644
--- a/src/wsocket.c
+++ b/src/wsocket.c
@@ -2,12 +2,8 @@
2* Socket compatibilization module for Win32 2* Socket compatibilization module for Win32
3* LuaSocket toolkit 3* LuaSocket toolkit
4* 4*
5* We also exchanged the order of the calls to send/recv and select. 5* The penalty of calling select to avoid busy-wait is only paid when
6* The idea is that the outer loop (whoever is calling sock_send/recv) 6* the I/O call fail in the first place.
7* will call the function again if we didn't time out, so we can
8* call write and then select only if it fails. This moves the penalty
9* to when data is not available, maximizing the bandwidth if data is
10* always available.
11* 7*
12* RCS ID: $Id$ 8* RCS ID: $Id$
13\*=========================================================================*/ 9\*=========================================================================*/
@@ -15,17 +11,14 @@
15 11
16#include "socket.h" 12#include "socket.h"
17 13
18static const char *sock_createstrerror(int err); 14/* WinSock doesn't have a strerror... */
19static const char *sock_bindstrerror(int err); 15static const char *wstrerror(int err);
20static const char *sock_connectstrerror(int err); 16static int wisclosed(int err);
21static const char *sock_acceptstrerror(int err);
22static const char *sock_listenstrerror(int err);
23 17
24/*-------------------------------------------------------------------------*\ 18/*-------------------------------------------------------------------------*\
25* Initializes module 19* Initializes module
26\*-------------------------------------------------------------------------*/ 20\*-------------------------------------------------------------------------*/
27int sock_open(void) 21int sock_open(void) {
28{
29 WSADATA wsaData; 22 WSADATA wsaData;
30 WORD wVersionRequested = MAKEWORD(2, 0); 23 WORD wVersionRequested = MAKEWORD(2, 0);
31 int err = WSAStartup(wVersionRequested, &wsaData ); 24 int err = WSAStartup(wVersionRequested, &wsaData );
@@ -40,8 +33,7 @@ int sock_open(void)
40/*-------------------------------------------------------------------------*\ 33/*-------------------------------------------------------------------------*\
41* Close module 34* Close module
42\*-------------------------------------------------------------------------*/ 35\*-------------------------------------------------------------------------*/
43int sock_close(void) 36int sock_close(void) {
44{
45 WSACleanup(); 37 WSACleanup();
46 return 1; 38 return 1;
47} 39}
@@ -49,19 +41,18 @@ int sock_close(void)
49/*-------------------------------------------------------------------------*\ 41/*-------------------------------------------------------------------------*\
50* Select with int timeout in ms 42* Select with int timeout in ms
51\*-------------------------------------------------------------------------*/ 43\*-------------------------------------------------------------------------*/
52int sock_select(int n, fd_set *rfds, fd_set *wfds, fd_set *efds, int timeout) 44int sock_select(int n, fd_set *rfds, fd_set *wfds, fd_set *efds, p_tm tm) {
53{
54 struct timeval tv; 45 struct timeval tv;
55 tv.tv_sec = timeout / 1000; 46 double t = tm_get(tm);
56 tv.tv_usec = (timeout % 1000) * 1000; 47 tv.tv_sec = (int) t;
57 return select(n, rfds, wfds, efds, timeout >= 0? &tv: NULL); 48 tv.tv_usec = (int) ((t - tv.tv_sec) * 1.0e6);
49 return select(n, rfds, wfds, efds, t >= 0.0? &tv: NULL);
58} 50}
59 51
60/*-------------------------------------------------------------------------*\ 52/*-------------------------------------------------------------------------*\
61* Close and inutilize socket 53* Close and inutilize socket
62\*-------------------------------------------------------------------------*/ 54\*-------------------------------------------------------------------------*/
63void sock_destroy(p_sock ps) 55void sock_destroy(p_sock ps) {
64{
65 if (*ps != SOCK_INVALID) { 56 if (*ps != SOCK_INVALID) {
66 sock_setblocking(ps); /* close can take a long time on WIN32 */ 57 sock_setblocking(ps); /* close can take a long time on WIN32 */
67 closesocket(*ps); 58 closesocket(*ps);
@@ -72,8 +63,7 @@ void sock_destroy(p_sock ps)
72/*-------------------------------------------------------------------------*\ 63/*-------------------------------------------------------------------------*\
73* 64*
74\*-------------------------------------------------------------------------*/ 65\*-------------------------------------------------------------------------*/
75void sock_shutdown(p_sock ps, int how) 66void sock_shutdown(p_sock ps, int how) {
76{
77 sock_setblocking(ps); 67 sock_setblocking(ps);
78 shutdown(*ps, how); 68 shutdown(*ps, how);
79 sock_setnonblocking(ps); 69 sock_setnonblocking(ps);
@@ -82,11 +72,9 @@ void sock_shutdown(p_sock ps, int how)
82/*-------------------------------------------------------------------------*\ 72/*-------------------------------------------------------------------------*\
83* Creates and sets up a socket 73* Creates and sets up a socket
84\*-------------------------------------------------------------------------*/ 74\*-------------------------------------------------------------------------*/
85const char *sock_create(p_sock ps, int domain, int type, int protocol) 75const char *sock_create(p_sock ps, int domain, int type, int protocol) {
86{
87 t_sock sock = socket(domain, type, protocol); 76 t_sock sock = socket(domain, type, protocol);
88 if (sock == SOCK_INVALID) 77 if (sock == SOCK_INVALID) return sock_strerror();
89 return sock_createstrerror(WSAGetLastError());
90 *ps = sock; 78 *ps = sock;
91 return NULL; 79 return NULL;
92} 80}
@@ -94,10 +82,9 @@ const char *sock_create(p_sock ps, int domain, int type, int protocol)
94/*-------------------------------------------------------------------------*\ 82/*-------------------------------------------------------------------------*\
95* Connects or returns error message 83* Connects or returns error message
96\*-------------------------------------------------------------------------*/ 84\*-------------------------------------------------------------------------*/
97const char *sock_connect(p_sock ps, SA *addr, socklen_t addr_len, p_tm tm) 85const char *sock_connect(p_sock ps, SA *addr, socklen_t addr_len, p_tm tm) {
98{
99 t_sock sock = *ps; 86 t_sock sock = *ps;
100 int err, timeout = tm_getretry(tm); 87 int err;
101 fd_set efds, wfds; 88 fd_set efds, wfds;
102 /* don't call on closed socket */ 89 /* don't call on closed socket */
103 if (sock == SOCK_INVALID) return io_strerror(IO_CLOSED); 90 if (sock == SOCK_INVALID) return io_strerror(IO_CLOSED);
@@ -106,15 +93,17 @@ const char *sock_connect(p_sock ps, SA *addr, socklen_t addr_len, p_tm tm)
106 /* if no error, we're done */ 93 /* if no error, we're done */
107 if (err == 0) return NULL; 94 if (err == 0) return NULL;
108 /* make sure the system is trying to connect */ 95 /* make sure the system is trying to connect */
109 err = WSAGetLastError(); 96 err = WSAGetLastError();
110 if (err != WSAEWOULDBLOCK) return sock_connectstrerror(err); 97 if (err != WSAEWOULDBLOCK) return wstrerror(err);
98 /* optimize for timeout=0 */
99 if (tm_get(tm) == 0.0) return io_strerror(IO_TIMEOUT);
111 /* wait for a timeout or for the system's answer */ 100 /* wait for a timeout or for the system's answer */
112 FD_ZERO(&wfds); FD_SET(sock, &wfds); 101 FD_ZERO(&wfds); FD_SET(sock, &wfds);
113 FD_ZERO(&efds); FD_SET(sock, &efds); 102 FD_ZERO(&efds); FD_SET(sock, &efds);
114 /* we run select to wait */ 103 /* we run select to wait */
115 err = sock_select(0, NULL, &wfds, &efds, timeout); 104 err = sock_select(0, NULL, &wfds, &efds, tm);
116 /* if select returned due to an event */ 105 /* if select returned due to an event */
117 if (err > 0 ) { 106 if (err > 0) {
118 /* if was in efds, we failed */ 107 /* if was in efds, we failed */
119 if (FD_ISSET(sock, &efds)) { 108 if (FD_ISSET(sock, &efds)) {
120 int why, len = sizeof(why); 109 int why, len = sizeof(why);
@@ -124,22 +113,21 @@ const char *sock_connect(p_sock ps, SA *addr, socklen_t addr_len, p_tm tm)
124 getsockopt(sock, SOL_SOCKET, SO_ERROR, (char *)&why, &len); 113 getsockopt(sock, SOL_SOCKET, SO_ERROR, (char *)&why, &len);
125 /* we KNOW there was an error. if why is 0, we will return 114 /* we KNOW there was an error. if why is 0, we will return
126 * "unknown error", but it's not really our fault */ 115 * "unknown error", but it's not really our fault */
127 return sock_connectstrerror(why); 116 return wstrerror(why);
128 /* otherwise it must be in wfds, so we succeeded */ 117 /* otherwise it must be in wfds, so we succeeded */
129 } else return NULL; 118 } else return NULL;
130 /* if no event happened, we timed out */ 119 /* if no event happened, we timed out */
131 } else return io_strerror(IO_TIMEOUT); 120 } else if (err == 0) return io_strerror(IO_TIMEOUT);
121 return sock_strerror();
132} 122}
133 123
134/*-------------------------------------------------------------------------*\ 124/*-------------------------------------------------------------------------*\
135* Binds or returns error message 125* Binds or returns error message
136\*-------------------------------------------------------------------------*/ 126\*-------------------------------------------------------------------------*/
137const char *sock_bind(p_sock ps, SA *addr, socklen_t addr_len) 127const char *sock_bind(p_sock ps, SA *addr, socklen_t addr_len) {
138{
139 const char *err = NULL; 128 const char *err = NULL;
140 sock_setblocking(ps); 129 sock_setblocking(ps);
141 if (bind(*ps, addr, addr_len) < 0) 130 if (bind(*ps, addr, addr_len) < 0) err = sock_strerror();
142 err = sock_bindstrerror(WSAGetLastError());
143 sock_setnonblocking(ps); 131 sock_setnonblocking(ps);
144 return err; 132 return err;
145} 133}
@@ -147,12 +135,10 @@ const char *sock_bind(p_sock ps, SA *addr, socklen_t addr_len)
147/*-------------------------------------------------------------------------*\ 135/*-------------------------------------------------------------------------*\
148* 136*
149\*-------------------------------------------------------------------------*/ 137\*-------------------------------------------------------------------------*/
150const char *sock_listen(p_sock ps, int backlog) 138const char *sock_listen(p_sock ps, int backlog) {
151{
152 const char *err = NULL; 139 const char *err = NULL;
153 sock_setblocking(ps); 140 sock_setblocking(ps);
154 if (listen(*ps, backlog) < 0) 141 if (listen(*ps, backlog) < 0) err = sock_strerror();
155 err = sock_listenstrerror(WSAGetLastError());
156 sock_setnonblocking(ps); 142 sock_setnonblocking(ps);
157 return err; 143 return err;
158} 144}
@@ -161,8 +147,7 @@ const char *sock_listen(p_sock ps, int backlog)
161* Accept with timeout 147* Accept with timeout
162\*-------------------------------------------------------------------------*/ 148\*-------------------------------------------------------------------------*/
163const char *sock_accept(p_sock ps, p_sock pa, SA *addr, 149const char *sock_accept(p_sock ps, p_sock pa, SA *addr,
164 socklen_t *addr_len, p_tm tm) 150 socklen_t *addr_len, p_tm tm) {
165{
166 t_sock sock = *ps; 151 t_sock sock = *ps;
167 SA dummy_addr; 152 SA dummy_addr;
168 socklen_t dummy_len = sizeof(dummy_addr); 153 socklen_t dummy_len = sizeof(dummy_addr);
@@ -171,151 +156,163 @@ const char *sock_accept(p_sock ps, p_sock pa, SA *addr,
171 if (!addr_len) addr_len = &dummy_len; 156 if (!addr_len) addr_len = &dummy_len;
172 for (;;) { 157 for (;;) {
173 fd_set rfds; 158 fd_set rfds;
174 int timeout = tm_getretry(tm);
175 int err; 159 int err;
176 /* try to get client socket */ 160 /* try to get client socket */
177 *pa = accept(sock, addr, addr_len); 161 *pa = accept(sock, addr, addr_len);
178 /* if return is valid, we are done */ 162 /* if return is valid, we are done */
179 if (*pa != SOCK_INVALID) return NULL; 163 if (*pa != SOCK_INVALID) return NULL;
180 /* optimization */
181 if (timeout == 0) return io_strerror(IO_TIMEOUT);
182 /* otherwise find out why we failed */ 164 /* otherwise find out why we failed */
183 err = WSAGetLastError(); 165 err = WSAGetLastError();
184 /* if we failed because there was no connectoin, keep trying*/ 166 /* if we failed because there was no connectoin, keep trying */
185 if (err != WSAEWOULDBLOCK) return sock_acceptstrerror(err); 167 if (err != WSAEWOULDBLOCK) return wstrerror(err);
168 /* optimize for the timeout=0 case */
169 if (tm_get(tm) == 0.0) return io_strerror(IO_TIMEOUT);
186 /* call select to avoid busy wait */ 170 /* call select to avoid busy wait */
187 FD_ZERO(&rfds); 171 FD_ZERO(&rfds);
188 FD_SET(sock, &rfds); 172 FD_SET(sock, &rfds);
189 err = sock_select(0, &rfds, NULL, NULL, timeout); 173 err = sock_select(0, &rfds, NULL, NULL, tm);
190 if (err <= 0) return io_strerror(IO_TIMEOUT); 174 if (err == 0) return io_strerror(IO_TIMEOUT);
175 else if (err < 0) break;
191 } 176 }
192 return io_strerror(IO_TIMEOUT); /* can't get here */ 177 return sock_strerror();
193} 178}
194 179
195/*-------------------------------------------------------------------------*\ 180/*-------------------------------------------------------------------------*\
196* Send with timeout 181* Send with timeout
197\*-------------------------------------------------------------------------*/ 182\*-------------------------------------------------------------------------*/
198int sock_send(p_sock ps, const char *data, size_t count, size_t *sent, 183int sock_send(p_sock ps, const char *data, size_t count, size_t *sent, p_tm tm)
199 int timeout)
200{ 184{
201 t_sock sock = *ps; 185 t_sock sock = *ps;
202 int put;
203 /* avoid making system calls on closed sockets */ 186 /* avoid making system calls on closed sockets */
204 if (sock == SOCK_INVALID) return IO_CLOSED; 187 if (sock == SOCK_INVALID) return IO_CLOSED;
205 /* try to send something */ 188 for ( ;; ) {
206 put = send(sock, data, (int) count, 0); 189 fd_set fds;
207 /* deal with failure */ 190 int ret, put;
208 if (put <= 0) { 191 /* try to send something */
209 /* in any case, nothing has been sent */ 192 put = send(sock, data, (int) count, 0);
193 /* if we sent something, we are done */
194 if (put > 0) {
195 *sent = put;
196 return IO_DONE;
197 }
198 /* deal with failure */
210 *sent = 0; 199 *sent = 0;
200 ret = WSAGetLastError();
201 /* check for connection closed */
202 if (wisclosed(ret)) return IO_CLOSED;
203 /* we can only proceed if there was no serious error */
204 if (ret != WSAEWOULDBLOCK) return IO_USER;
205 /* optimize for the timeout = 0 case */
206 if (tm_get(tm) == 0.0) return IO_TIMEOUT;
211 /* run select to avoid busy wait */ 207 /* run select to avoid busy wait */
212 if (WSAGetLastError() == WSAEWOULDBLOCK) { 208 FD_ZERO(&fds);
213 fd_set fds; 209 FD_SET(sock, &fds);
214 int ret; 210 ret = sock_select(0, NULL, &fds, NULL, tm);
215 /* optimize for the timeout = 0 case */ 211 if (ret == 0) return IO_TIMEOUT;
216 if (timeout == 0) return IO_TIMEOUT; 212 else if (ret < 0) break;
217 FD_ZERO(&fds); 213 }
218 FD_SET(sock, &fds); 214 return IO_USER;
219 ret = sock_select(0, NULL, &fds, NULL, timeout);
220 /* tell the caller to call us again because now we can send */
221 if (ret > 0) return IO_RETRY;
222 /* tell the caller we can't send anything before timint out */
223 else return IO_TIMEOUT;
224 /* here we know the connection has been closed */
225 } else return IO_CLOSED;
226 /* here we successfully sent something */
227 } else {
228 *sent = put;
229 return IO_DONE;
230 }
231} 215}
232 216
233/*-------------------------------------------------------------------------*\ 217/*-------------------------------------------------------------------------*\
234* Sendto with timeout 218* Sendto with timeout
235\*-------------------------------------------------------------------------*/ 219\*-------------------------------------------------------------------------*/
236int sock_sendto(p_sock ps, const char *data, size_t count, size_t *sent, 220int sock_sendto(p_sock ps, const char *data, size_t count, size_t *sent,
237 SA *addr, socklen_t addr_len, int timeout) 221 SA *addr, socklen_t addr_len, p_tm tm)
238{ 222{
239 t_sock sock = *ps; 223 t_sock sock = *ps;
240 int put; 224 /* avoid making system calls on closed sockets */
241 if (sock == SOCK_INVALID) return IO_CLOSED; 225 if (sock == SOCK_INVALID) return IO_CLOSED;
242 put = sendto(sock, data, (int) count, 0, addr, addr_len); 226 for ( ;; ) {
243 if (put <= 0) { 227 fd_set fds;
228 int ret, put;
229 /* try to send something */
230 put = sendto(sock, data, (int) count, 0, addr, addr_len);
231 /* if we sent something, we are done */
232 if (put > 0) {
233 *sent = put;
234 return IO_DONE;
235 }
236 /* deal with failure */
244 *sent = 0; 237 *sent = 0;
245 if (WSAGetLastError() == WSAEWOULDBLOCK) { 238 ret = WSAGetLastError();
246 fd_set fds; 239 /* check for connection closed */
247 int ret; 240 if (wisclosed(ret)) return IO_CLOSED;
248 if (timeout == 0) return IO_TIMEOUT; 241 /* we can only proceed if there was no serious error */
249 FD_ZERO(&fds); 242 if (ret != WSAEWOULDBLOCK) return IO_USER;
250 FD_SET(sock, &fds); 243 /* optimize for the timeout = 0 case */
251 ret = sock_select(0, NULL, &fds, NULL, timeout); 244 if (tm_get(tm) == 0.0) return IO_TIMEOUT;
252 if (ret > 0) return IO_RETRY; 245 /* run select to avoid busy wait */
253 else return IO_TIMEOUT; 246 FD_ZERO(&fds);
254 } else return IO_CLOSED; 247 FD_SET(sock, &fds);
255 } else { 248 ret = sock_select(0, NULL, &fds, NULL, tm);
256 *sent = put; 249 if (ret == 0) return IO_TIMEOUT;
257 return IO_DONE; 250 else if (ret < 0) break;
258 } 251 }
252 return IO_USER;
259} 253}
260 254
261/*-------------------------------------------------------------------------*\ 255/*-------------------------------------------------------------------------*\
262* Receive with timeout 256* Receive with timeout
263\*-------------------------------------------------------------------------*/ 257\*-------------------------------------------------------------------------*/
264int sock_recv(p_sock ps, char *data, size_t count, size_t *got, int timeout) 258int sock_recv(p_sock ps, char *data, size_t count, size_t *got, p_tm tm)
265{ 259{
266 t_sock sock = *ps; 260 t_sock sock = *ps;
267 int taken;
268 if (sock == SOCK_INVALID) return IO_CLOSED; 261 if (sock == SOCK_INVALID) return IO_CLOSED;
269 taken = recv(sock, data, (int) count, 0); 262 for ( ;; ) {
270 if (taken <= 0) {
271 fd_set fds; 263 fd_set fds;
272 int ret; 264 int ret, taken;
265 taken = recv(sock, data, (int) count, 0);
266 if (taken > 0) {
267 *got = taken;
268 return IO_DONE;
269 }
273 *got = 0; 270 *got = 0;
274 if (taken == 0 || WSAGetLastError() != WSAEWOULDBLOCK) return IO_CLOSED; 271 if (taken == 0 || wisclosed(ret = WSAGetLastError())) return IO_CLOSED;
275 if (timeout == 0) return IO_TIMEOUT; 272 if (ret != WSAEWOULDBLOCK) return IO_USER;
273 if (tm_get(tm) == 0.0) return IO_TIMEOUT;
276 FD_ZERO(&fds); 274 FD_ZERO(&fds);
277 FD_SET(sock, &fds); 275 FD_SET(sock, &fds);
278 ret = sock_select(0, &fds, NULL, NULL, timeout); 276 ret = sock_select(0, &fds, NULL, NULL, tm);
279 if (ret > 0) return IO_RETRY; 277 if (ret == 0) return IO_TIMEOUT;
280 else return IO_TIMEOUT; 278 else if (ret < 0) break;
281 } else {
282 *got = taken;
283 return IO_DONE;
284 } 279 }
280 return IO_TIMEOUT;
285} 281}
286 282
287/*-------------------------------------------------------------------------*\ 283/*-------------------------------------------------------------------------*\
288* Recvfrom with timeout 284* Recvfrom with timeout
289\*-------------------------------------------------------------------------*/ 285\*-------------------------------------------------------------------------*/
290int sock_recvfrom(p_sock ps, char *data, size_t count, size_t *got, 286int sock_recvfrom(p_sock ps, char *data, size_t count, size_t *got,
291 SA *addr, socklen_t *addr_len, int timeout) 287 SA *addr, socklen_t *addr_len, p_tm tm)
292{ 288{
293 t_sock sock = *ps; 289 t_sock sock = *ps;
294 int taken;
295 if (sock == SOCK_INVALID) return IO_CLOSED; 290 if (sock == SOCK_INVALID) return IO_CLOSED;
296 taken = recvfrom(sock, data, (int) count, 0, addr, addr_len); 291 for ( ;; ) {
297 if (taken <= 0) {
298 fd_set fds; 292 fd_set fds;
299 int ret; 293 int ret, taken;
294 taken = recvfrom(sock, data, (int) count, 0, addr, addr_len);
295 if (taken > 0) {
296 *got = taken;
297 return IO_DONE;
298 }
300 *got = 0; 299 *got = 0;
301 if (taken == 0 || WSAGetLastError() != WSAEWOULDBLOCK) return IO_CLOSED; 300 if (taken == 0 || wisclosed(ret = WSAGetLastError())) return IO_CLOSED;
302 if (timeout == 0) return IO_TIMEOUT; 301 if (ret != WSAEWOULDBLOCK) return IO_USER;
302 if (tm_get(tm) == 0.0) return IO_TIMEOUT;
303 FD_ZERO(&fds); 303 FD_ZERO(&fds);
304 FD_SET(sock, &fds); 304 FD_SET(sock, &fds);
305 ret = sock_select(0, &fds, NULL, NULL, timeout); 305 ret = sock_select(0, &fds, NULL, NULL, tm);
306 if (ret > 0) return IO_RETRY; 306 if (ret == 0) return IO_TIMEOUT;
307 else return IO_TIMEOUT; 307 else if (ret < 0) break;
308 } else {
309 *got = taken;
310 return IO_DONE;
311 } 308 }
309 return IO_TIMEOUT;
312} 310}
313 311
314/*-------------------------------------------------------------------------*\ 312/*-------------------------------------------------------------------------*\
315* Put socket into blocking mode 313* Put socket into blocking mode
316\*-------------------------------------------------------------------------*/ 314\*-------------------------------------------------------------------------*/
317void sock_setblocking(p_sock ps) 315void sock_setblocking(p_sock ps) {
318{
319 u_long argp = 0; 316 u_long argp = 0;
320 ioctlsocket(*ps, FIONBIO, &argp); 317 ioctlsocket(*ps, FIONBIO, &argp);
321} 318}
@@ -323,8 +320,7 @@ void sock_setblocking(p_sock ps)
323/*-------------------------------------------------------------------------*\ 320/*-------------------------------------------------------------------------*\
324* Put socket into non-blocking mode 321* Put socket into non-blocking mode
325\*-------------------------------------------------------------------------*/ 322\*-------------------------------------------------------------------------*/
326void sock_setnonblocking(p_sock ps) 323void sock_setnonblocking(p_sock ps) {
327{
328 u_long argp = 1; 324 u_long argp = 1;
329 ioctlsocket(*ps, FIONBIO, &argp); 325 ioctlsocket(*ps, FIONBIO, &argp);
330} 326}
@@ -332,117 +328,136 @@ void sock_setnonblocking(p_sock ps)
332/*-------------------------------------------------------------------------*\ 328/*-------------------------------------------------------------------------*\
333* Error translation functions 329* Error translation functions
334\*-------------------------------------------------------------------------*/ 330\*-------------------------------------------------------------------------*/
335/* return error messages for the known errors reported by gethostbyname */ 331const char *sock_hoststrerror(void) {
336const char *sock_hoststrerror(void) 332 int err = WSAGetLastError();
337{
338 switch (WSAGetLastError()) {
339 case WSANOTINITIALISED: return "not initialized";
340 case WSAENETDOWN: return "network is down";
341 case WSAHOST_NOT_FOUND: return "host not found";
342 case WSATRY_AGAIN: return "name server unavailable, try again later";
343 case WSANO_RECOVERY: return "name server error";
344 case WSANO_DATA: return "host not found";
345 case WSAEINPROGRESS: return "another call in progress";
346 case WSAEFAULT: return "invalid memory address";
347 case WSAEINTR: return "call interrupted";
348 default: return "unknown error";
349 }
350}
351
352/* return error messages for the known errors reported by socket */
353static const char *sock_createstrerror(int err)
354{
355 switch (err) { 333 switch (err) {
356 case WSANOTINITIALISED: return "not initialized"; 334 case WSAHOST_NOT_FOUND:
357 case WSAENETDOWN: return "network is down"; 335 return "host not found";
358 case WSAEAFNOSUPPORT: return "address family not supported"; 336 default:
359 case WSAEINPROGRESS: return "another call in progress"; 337 return wstrerror(err);
360 case WSAEMFILE: return "descriptor table is full";
361 case WSAENOBUFS: return "insufficient buffer space";
362 case WSAEPROTONOSUPPORT: return "protocol not supported";
363 case WSAEPROTOTYPE: return "wrong protocol type";
364 case WSAESOCKTNOSUPPORT: return "socket type not supported by family";
365 default: return "unknown error";
366 } 338 }
367} 339}
368 340
369/* return error messages for the known errors reported by accept */ 341const char *sock_strerror(void) {
370static const char *sock_acceptstrerror(int err) 342 int err = WSAGetLastError();
371{
372 switch (err) { 343 switch (err) {
373 case WSANOTINITIALISED: return "not initialized"; 344 case WSAEADDRINUSE:
374 case WSAENETDOWN: return "network is down"; 345 return "address already in use";
375 case WSAEFAULT: return "invalid memory address"; 346 default:
376 case WSAEINTR: return "call interrupted"; 347 return wstrerror(err);
377 case WSAEINPROGRESS: return "another call in progress";
378 case WSAEINVAL: return "not listening";
379 case WSAEMFILE: return "descriptor table is full";
380 case WSAENOBUFS: return "insufficient buffer space";
381 case WSAENOTSOCK: return "descriptor not a socket";
382 case WSAEOPNOTSUPP: return "not supported";
383 case WSAEWOULDBLOCK: return "call would block";
384 default: return "unknown error";
385 } 348 }
386} 349}
387 350
388/* return error messages for the known errors reported by bind */ 351const char *sock_geterr(p_sock ps, int code) {
389static const char *sock_bindstrerror(int err) 352 (void) ps;
390{ 353 (void) code;
391 switch (err) { 354 return sock_strerror();
392 case WSANOTINITIALISED: return "not initialized";
393 case WSAENETDOWN: return "network is down";
394 case WSAEACCES: return "broadcast not enabled for socket";
395 case WSAEADDRINUSE: return "address already in use";
396 case WSAEADDRNOTAVAIL: return "address not available in local host";
397 case WSAEFAULT: return "invalid memory address";
398 case WSAEINPROGRESS: return "another call in progress";
399 case WSAEINVAL: return "already bound";
400 case WSAENOBUFS: return "insuficient buffer space";
401 case WSAENOTSOCK: return "descriptor not a socket";
402 default: return "unknown error";
403 }
404
405} 355}
406 356
407/* return error messages for the known errors reported by listen */ 357int wisclosed(int err) {
408static const char *sock_listenstrerror(int err)
409{
410 switch (err) { 358 switch (err) {
411 case WSANOTINITIALISED: return "not initialized"; 359 case WSAECONNRESET:
412 case WSAENETDOWN: return "network is down"; 360 case WSAECONNABORTED:
413 case WSAEADDRINUSE: return "local address already in use"; 361 case WSAESHUTDOWN:
414 case WSAEINPROGRESS: return "another call in progress"; 362 case WSAENOTCONN:
415 case WSAEINVAL: return "not bound"; 363 return 1;
416 case WSAEISCONN: return "already connected"; 364 default:
417 case WSAEMFILE: return "descriptor table is full"; 365 return 0;
418 case WSAENOBUFS: return "insuficient buffer space";
419 case WSAENOTSOCK: return "descriptor not a socket";
420 case WSAEOPNOTSUPP: return "not supported";
421 default: return "unknown error";
422 } 366 }
423} 367}
424 368
425/* return error messages for the known errors reported by connect */ 369static const char *wstrerror(int err) {
426static const char *sock_connectstrerror(int err)
427{
428 switch (err) { 370 switch (err) {
429 case WSANOTINITIALISED: return "not initialized"; 371 case WSAEINTR:
430 case WSAENETDOWN: return "network is down"; 372 return "WSAEINTR: Interrupted function call";
431 case WSAEADDRINUSE: return "local address already in use"; 373 case WSAEACCES:
432 case WSAEINTR: return "call interrupted"; 374 return "WSAEACCES: Permission denied";
433 case WSAEINPROGRESS: return "another call in progress"; 375 case WSAEFAULT:
434 case WSAEALREADY: return "connect already in progress"; 376 return "WSAEFAULT: Bad address";
435 case WSAEADDRNOTAVAIL: return "invalid remote address"; 377 case WSAEINVAL:
436 case WSAEAFNOSUPPORT: return "address family not supported"; 378 return "WSAEINVAL: Invalid argument";
437 case WSAECONNREFUSED: return "connection refused"; 379 case WSAEMFILE:
438 case WSAEFAULT: return "invalid memory address"; 380 return "WSAEMFILE: Too many open files";
439 case WSAEINVAL: return "socket is listening"; 381 case WSAEWOULDBLOCK:
440 case WSAEISCONN: return "socket already connected"; 382 return "WSAEWOULDBLOCK: Resource temporarily unavailable";
441 case WSAENETUNREACH: return "network is unreachable"; 383 case WSAEINPROGRESS:
442 case WSAENOTSOCK: return "descriptor not a socket"; 384 return "WSAEINPROGRESS: Operation now in progress";
443 case WSAETIMEDOUT: return io_strerror(IO_TIMEOUT); 385 case WSAEALREADY:
444 case WSAEWOULDBLOCK: return "would block"; 386 return "WSAEALREADY: Operation already in progress";
445 case WSAEACCES: return "broadcast not enabled"; 387 case WSAENOTSOCK:
446 default: return "unknown error"; 388 return "WSAENOTSOCK: Socket operation on nonsocket";
389 case WSAEDESTADDRREQ:
390 return "WSAEDESTADDRREQ: Destination address required";
391 case WSAEMSGSIZE:
392 return "WSAEMSGSIZE: Message too long";
393 case WSAEPROTOTYPE:
394 return "WSAEPROTOTYPE: Protocol wrong type for socket";
395 case WSAENOPROTOOPT:
396 return "WSAENOPROTOOPT: Bad protocol option";
397 case WSAEPROTONOSUPPORT:
398 return "WSAEPROTONOSUPPORT: Protocol not supported";
399 case WSAESOCKTNOSUPPORT:
400 return "WSAESOCKTNOSUPPORT: Socket type not supported";
401 case WSAEOPNOTSUPP:
402 return "WSAEOPNOTSUPP: Operation not supported";
403 case WSAEPFNOSUPPORT:
404 return "WSAEPFNOSUPPORT: Protocol family not supported";
405 case WSAEAFNOSUPPORT:
406 return "WSAEAFNOSUPPORT: Address family not supported by "
407 "protocol family";
408 case WSAEADDRINUSE:
409 return "WSAEADDRINUSE: Address already in use";
410 case WSAEADDRNOTAVAIL:
411 return "WSAEADDRNOTAVAIL: Cannot assign requested address";
412 case WSAENETDOWN:
413 return "WSAENETDOWN: Network is down";
414 case WSAENETUNREACH:
415 return "WSAENETUNREACH: Network is unreachable";
416 case WSAENETRESET:
417 return "WSAENETRESET: Network dropped connection on reset";
418 case WSAECONNABORTED:
419 return "WSAECONNABORTED: Software caused connection abort";
420 case WSAECONNRESET:
421 return "WSAECONNRESET: Connection reset by peer";
422 case WSAENOBUFS:
423 return "WSAENOBUFS: No buffer space available";
424 case WSAEISCONN:
425 return "WSAEISCONN: Socket is already connected";
426 case WSAENOTCONN:
427 return "WSAENOTCONN: Socket is not connected";
428 case WSAESHUTDOWN:
429 return "WSAESHUTDOWN: Cannot send after socket shutdown";
430 case WSAETIMEDOUT:
431 return "WSAETIMEDOUT: Connection timed out";
432 case WSAECONNREFUSED:
433 return "WSAECONNREFUSED: Connection refused";
434 case WSAEHOSTDOWN:
435 return "WSAEHOSTDOWN: Host is down";
436 case WSAEHOSTUNREACH:
437 return "WSAEHOSTUNREACH: No route to host";
438 case WSAEPROCLIM:
439 return "WSAEPROCLIM: Too many processes";
440 case WSASYSNOTREADY:
441 return "WSASYSNOTREADY: Network subsystem is unavailable";
442 case WSAVERNOTSUPPORTED:
443 return "WSAVERNOTSUPPORTED: Winsock.dll version out of range";
444 case WSANOTINITIALISED:
445 return "WSANOTINITIALISED: Successful WSAStartup not yet performed";
446 case WSAEDISCON:
447 return "WSAEDISCON: Graceful shutdown in progress";
448 case WSATYPE_NOT_FOUND:
449 return "WSATYPE_NOT_FOUND: Class type not found";
450 case WSAHOST_NOT_FOUND:
451 return "WSAHOST_NOT_FOUND: Host not found";
452 case WSATRY_AGAIN:
453 return "WSATRY_AGAIN: Nonauthoritative host not found";
454 case WSANO_RECOVERY:
455 return "WSANO_RECOVERY: Nonrecoverable name lookup error";
456 case WSANO_DATA:
457 return "WSANO_DATA: Valid name, no data record of requested type";
458 case WSASYSCALLFAILURE:
459 return "WSASYSCALLFAILURE: System call failure";
460 default:
461 return "Unknown error";
447 } 462 }
448} 463}
diff --git a/test/mimetest.lua b/test/mimetest.lua
index 0b3db33..413a83b 100644
--- a/test/mimetest.lua
+++ b/test/mimetest.lua
@@ -8,7 +8,7 @@ local qptest = "qptest.bin"
8local eqptest = "qptest.bin2" 8local eqptest = "qptest.bin2"
9local dqptest = "qptest.bin3" 9local dqptest = "qptest.bin3"
10 10
11local b64test = "luasocket.dylib" 11local b64test = "luasocket.dll"
12local eb64test = "b64test.bin" 12local eb64test = "b64test.bin"
13local db64test = "b64test.bin2" 13local db64test = "b64test.bin2"
14 14
diff --git a/test/testclnt.lua b/test/testclnt.lua
index 38dc19a..cdd2c08 100644
--- a/test/testclnt.lua
+++ b/test/testclnt.lua
@@ -438,6 +438,25 @@ function rebind_test()
438end 438end
439 439
440------------------------------------------------------------------------ 440------------------------------------------------------------------------
441function getstats_test()
442 reconnect()
443 local t = 0
444 for i = 1, 25 do
445 local c = math.random(1, 100)
446 remote (string.format ([[
447 str = data:receive(%d)
448 data:send(str)
449 ]], c))
450 c:send(string.rep("a", c))
451 c:receive(c)
452 local r, s, a = c:getstats()
453 assert(r == t, "received count failed")
454 assert(s == t, "sent count failed")
455 end
456 print("ok")
457end
458
459------------------------------------------------------------------------
441test("method registration") 460test("method registration")
442test_methods(socket.tcp(), { 461test_methods(socket.tcp(), {
443 "accept", 462 "accept",
@@ -499,6 +518,9 @@ test("accept function: ")
499accept_timeout() 518accept_timeout()
500accept_errors() 519accept_errors()
501 520
521test("getstats test")
522getstats_test()
523
502test("character line") 524test("character line")
503test_asciiline(1) 525test_asciiline(1)
504test_asciiline(17) 526test_asciiline(17)