aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/buffer.h2
-rw-r--r--src/usocket.c38
-rw-r--r--src/wsocket.c469
3 files changed, 263 insertions, 246 deletions
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}