diff options
author | Diego Nehab <diego@tecgraf.puc-rio.br> | 2004-01-17 08:02:04 +0000 |
---|---|---|
committer | Diego Nehab <diego@tecgraf.puc-rio.br> | 2004-01-17 08:02:04 +0000 |
commit | 02ef4e7daae6bef629dcb568052755fb85ed2efc (patch) | |
tree | 3001b5d4429626e086b457ade7a899428fbfeb34 | |
parent | 076451c75336b30e6152bd5c02f355db39107f7d (diff) | |
download | luasocket-02ef4e7daae6bef629dcb568052755fb85ed2efc.tar.gz luasocket-02ef4e7daae6bef629dcb568052755fb85ed2efc.tar.bz2 luasocket-02ef4e7daae6bef629dcb568052755fb85ed2efc.zip |
Trying to get rid of EINTR problems...
-rw-r--r-- | src/inet.c | 6 | ||||
-rw-r--r-- | src/inet.h | 2 | ||||
-rw-r--r-- | src/io.h | 1 | ||||
-rw-r--r-- | src/socket.h | 2 | ||||
-rw-r--r-- | src/tcp.c | 7 | ||||
-rw-r--r-- | src/udp.c | 4 | ||||
-rw-r--r-- | src/usocket.c | 59 | ||||
-rw-r--r-- | src/wsocket.c | 7 |
8 files changed, 63 insertions, 25 deletions
@@ -181,7 +181,7 @@ static void inet_pushresolved(lua_State *L, struct hostent *hp) | |||
181 | * Tries to connect to remote address (address, port) | 181 | * Tries to connect to remote address (address, port) |
182 | \*-------------------------------------------------------------------------*/ | 182 | \*-------------------------------------------------------------------------*/ |
183 | const char *inet_tryconnect(p_sock ps, const char *address, | 183 | const char *inet_tryconnect(p_sock ps, const char *address, |
184 | unsigned short port) | 184 | unsigned short port, int timeout) |
185 | { | 185 | { |
186 | struct sockaddr_in remote; | 186 | struct sockaddr_in remote; |
187 | const char *err; | 187 | const char *err; |
@@ -197,14 +197,12 @@ const char *inet_tryconnect(p_sock ps, const char *address, | |||
197 | memcpy(&remote.sin_addr, *addr, sizeof(struct in_addr)); | 197 | memcpy(&remote.sin_addr, *addr, sizeof(struct in_addr)); |
198 | } | 198 | } |
199 | } else remote.sin_family = AF_UNSPEC; | 199 | } else remote.sin_family = AF_UNSPEC; |
200 | sock_setblocking(ps); | 200 | err = sock_connect(ps, (SA *) &remote, sizeof(remote), timeout); |
201 | err = sock_connect(ps, (SA *) &remote, sizeof(remote)); | ||
202 | if (err) { | 201 | if (err) { |
203 | sock_destroy(ps); | 202 | sock_destroy(ps); |
204 | *ps = SOCK_INVALID; | 203 | *ps = SOCK_INVALID; |
205 | return err; | 204 | return err; |
206 | } else { | 205 | } else { |
207 | sock_setnonblocking(ps); | ||
208 | return NULL; | 206 | return NULL; |
209 | } | 207 | } |
210 | } | 208 | } |
@@ -25,7 +25,7 @@ | |||
25 | 25 | ||
26 | void inet_open(lua_State *L); | 26 | void inet_open(lua_State *L); |
27 | const char *inet_tryconnect(p_sock ps, const char *address, | 27 | const char *inet_tryconnect(p_sock ps, const char *address, |
28 | unsigned short port); | 28 | unsigned short port, int timeout); |
29 | const char *inet_trybind(p_sock ps, const char *address, | 29 | const char *inet_trybind(p_sock ps, const char *address, |
30 | unsigned short port, int backlog); | 30 | unsigned short port, int backlog); |
31 | const char *inet_trycreate(p_sock ps, int type); | 31 | const char *inet_trycreate(p_sock ps, int type); |
@@ -24,6 +24,7 @@ enum { | |||
24 | IO_CLOSED, /* the connection has been closed */ | 24 | IO_CLOSED, /* the connection has been closed */ |
25 | IO_ERROR, /* something wrong... */ | 25 | IO_ERROR, /* something wrong... */ |
26 | IO_REFUSED, /* transfer has been refused */ | 26 | IO_REFUSED, /* transfer has been refused */ |
27 | IO_RETRY, /* please try again */ | ||
27 | IO_LIMITED /* maximum number of bytes reached */ | 28 | IO_LIMITED /* maximum number of bytes reached */ |
28 | }; | 29 | }; |
29 | 30 | ||
diff --git a/src/socket.h b/src/socket.h index cea9e0d..aeadff0 100644 --- a/src/socket.h +++ b/src/socket.h | |||
@@ -34,7 +34,7 @@ const char *sock_create(p_sock ps, int domain, int type, int protocol); | |||
34 | void sock_destroy(p_sock ps); | 34 | void sock_destroy(p_sock ps); |
35 | int sock_accept(p_sock ps, p_sock pa, SA *addr, socklen_t *addr_len, | 35 | int sock_accept(p_sock ps, p_sock pa, SA *addr, socklen_t *addr_len, |
36 | int timeout); | 36 | int timeout); |
37 | const char *sock_connect(p_sock ps, SA *addr, socklen_t addr_len); | 37 | const char *sock_connect(p_sock ps, SA *addr, socklen_t addr_len, int timeout); |
38 | const char *sock_bind(p_sock ps, SA *addr, socklen_t addr_len); | 38 | const char *sock_bind(p_sock ps, SA *addr, socklen_t addr_len); |
39 | void sock_listen(p_sock ps, int backlog); | 39 | void sock_listen(p_sock ps, int backlog); |
40 | void sock_shutdown(p_sock ps, int how); | 40 | void sock_shutdown(p_sock ps, int how); |
@@ -257,7 +257,10 @@ static int meth_connect(lua_State *L) | |||
257 | p_tcp tcp = (p_tcp) aux_checkclass(L, "tcp{master}", 1); | 257 | p_tcp tcp = (p_tcp) aux_checkclass(L, "tcp{master}", 1); |
258 | const char *address = luaL_checkstring(L, 2); | 258 | const char *address = luaL_checkstring(L, 2); |
259 | unsigned short port = (unsigned short) luaL_checknumber(L, 3); | 259 | unsigned short port = (unsigned short) luaL_checknumber(L, 3); |
260 | const char *err = inet_tryconnect(&tcp->sock, address, port); | 260 | p_tm tm = &tcp->tm; |
261 | const char *err; | ||
262 | tm_markstart(tm); | ||
263 | err = inet_tryconnect(&tcp->sock, address, port, tm_getfailure(tm)); | ||
261 | if (err) { | 264 | if (err) { |
262 | lua_pushnil(L); | 265 | lua_pushnil(L); |
263 | lua_pushstring(L, err); | 266 | lua_pushstring(L, err); |
@@ -326,7 +329,7 @@ static int meth_getsockname(lua_State *L) | |||
326 | \*-------------------------------------------------------------------------*/ | 329 | \*-------------------------------------------------------------------------*/ |
327 | static int meth_settimeout(lua_State *L) | 330 | static int meth_settimeout(lua_State *L) |
328 | { | 331 | { |
329 | p_tcp tcp = (p_tcp) aux_checkgroup(L, "tcp{client,server}", 1); | 332 | p_tcp tcp = (p_tcp) aux_checkgroup(L, "tcp{any}", 1); |
330 | return tm_meth_settimeout(L, &tcp->tm); | 333 | return tm_meth_settimeout(L, &tcp->tm); |
331 | } | 334 | } |
332 | 335 | ||
@@ -335,12 +335,14 @@ static int meth_settimeout(lua_State *L) | |||
335 | static int meth_setpeername(lua_State *L) | 335 | static int meth_setpeername(lua_State *L) |
336 | { | 336 | { |
337 | p_udp udp = (p_udp) aux_checkclass(L, "udp{unconnected}", 1); | 337 | p_udp udp = (p_udp) aux_checkclass(L, "udp{unconnected}", 1); |
338 | p_tm tm = &udp->tm; | ||
338 | const char *address = luaL_checkstring(L, 2); | 339 | const char *address = luaL_checkstring(L, 2); |
339 | int connecting = strcmp(address, "*"); | 340 | int connecting = strcmp(address, "*"); |
340 | unsigned short port = connecting ? | 341 | unsigned short port = connecting ? |
341 | (unsigned short) luaL_checknumber(L, 3) : | 342 | (unsigned short) luaL_checknumber(L, 3) : |
342 | (unsigned short) luaL_optnumber(L, 3, 0); | 343 | (unsigned short) luaL_optnumber(L, 3, 0); |
343 | const char *err = inet_tryconnect(&udp->sock, address, port); | 344 | const char *err; |
345 | err = inet_tryconnect(&udp->sock, address, port, tm_getfailure(tm)); | ||
344 | if (err) { | 346 | if (err) { |
345 | lua_pushnil(L); | 347 | lua_pushnil(L); |
346 | lua_pushstring(L, err); | 348 | lua_pushstring(L, err); |
diff --git a/src/usocket.c b/src/usocket.c index 89be85e..9fcf4e8 100644 --- a/src/usocket.c +++ b/src/usocket.c | |||
@@ -2,6 +2,17 @@ | |||
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 | ||
6 | * a select function call, we don't guarantee values timeouts anymore. | ||
7 | * It's not a big deal, since we are not real-time anyways. | ||
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 | * | ||
5 | * RCS ID: $Id$ | 16 | * RCS ID: $Id$ |
6 | \*=========================================================================*/ | 17 | \*=========================================================================*/ |
7 | #include <string.h> | 18 | #include <string.h> |
@@ -49,10 +60,27 @@ const char *sock_create(p_sock ps, int domain, int type, int protocol) | |||
49 | /*-------------------------------------------------------------------------*\ | 60 | /*-------------------------------------------------------------------------*\ |
50 | * Connects or returns error message | 61 | * Connects or returns error message |
51 | \*-------------------------------------------------------------------------*/ | 62 | \*-------------------------------------------------------------------------*/ |
52 | const char *sock_connect(p_sock ps, SA *addr, socklen_t addr_len) | 63 | const char *sock_connect(p_sock ps, SA *addr, socklen_t addr_len, int timeout) |
53 | { | 64 | { |
54 | if (connect(*ps, addr, addr_len) < 0) return sock_connectstrerror(); | 65 | t_sock sock = *ps; |
55 | else return NULL; | 66 | if (sock == SOCK_INVALID) return "closed"; |
67 | if (connect(sock, addr, addr_len) < 0) { | ||
68 | struct timeval tv; | ||
69 | fd_set wfds, efds; | ||
70 | int err; | ||
71 | tv.tv_sec = timeout / 1000; | ||
72 | tv.tv_usec = (timeout % 1000) * 1000; | ||
73 | FD_ZERO(&wfds); FD_ZERO(&efds); | ||
74 | FD_SET(sock, &wfds); FD_SET(sock, &efds); | ||
75 | do err = select(sock+1, NULL, &wfds, &efds, timeout >= 0 ? &tv : NULL); | ||
76 | while (err < 0 && errno == EINTR); | ||
77 | if (err <= 0) return "timeout"; | ||
78 | if (FD_ISSET(sock, &efds)) { | ||
79 | char dummy; | ||
80 | recv(sock, &dummy, 0, 0); | ||
81 | return sock_connectstrerror(); | ||
82 | } else return NULL; | ||
83 | } else return NULL; | ||
56 | } | 84 | } |
57 | 85 | ||
58 | /*-------------------------------------------------------------------------*\ | 86 | /*-------------------------------------------------------------------------*\ |
@@ -91,14 +119,16 @@ int sock_accept(p_sock ps, p_sock pa, SA *addr, socklen_t *addr_len, | |||
91 | SA dummy_addr; | 119 | SA dummy_addr; |
92 | socklen_t dummy_len; | 120 | socklen_t dummy_len; |
93 | fd_set fds; | 121 | fd_set fds; |
122 | int err; | ||
94 | if (sock == SOCK_INVALID) return IO_CLOSED; | 123 | if (sock == SOCK_INVALID) return IO_CLOSED; |
95 | tv.tv_sec = timeout / 1000; | 124 | tv.tv_sec = timeout / 1000; |
96 | tv.tv_usec = (timeout % 1000) * 1000; | 125 | tv.tv_usec = (timeout % 1000) * 1000; |
97 | FD_ZERO(&fds); | 126 | FD_ZERO(&fds); |
98 | FD_SET(sock, &fds); | 127 | FD_SET(sock, &fds); |
99 | *pa = SOCK_INVALID; | 128 | *pa = SOCK_INVALID; |
100 | if (select(sock+1, &fds, NULL, NULL, timeout >= 0 ? &tv : NULL) <= 0) | 129 | do err = select(sock+1, &fds, NULL, NULL, timeout >= 0 ? &tv : NULL); |
101 | return IO_TIMEOUT; | 130 | while (err < 0 && errno == EINTR); |
131 | if (err <= 0) return IO_TIMEOUT; | ||
102 | if (!addr) addr = &dummy_addr; | 132 | if (!addr) addr = &dummy_addr; |
103 | if (!addr_len) addr_len = &dummy_len; | 133 | if (!addr_len) addr_len = &dummy_len; |
104 | *pa = accept(sock, addr, addr_len); | 134 | *pa = accept(sock, addr, addr_len); |
@@ -108,12 +138,6 @@ int sock_accept(p_sock ps, p_sock pa, SA *addr, socklen_t *addr_len, | |||
108 | 138 | ||
109 | /*-------------------------------------------------------------------------*\ | 139 | /*-------------------------------------------------------------------------*\ |
110 | * Send with timeout | 140 | * Send with timeout |
111 | * Here we exchanged the order of the calls to write and select | ||
112 | * The idea is that the outer loop (whoever is calling sock_send) | ||
113 | * will call the function again if we didn't time out, so we can | ||
114 | * call write and then select only if it fails. | ||
115 | * Should speed things up! | ||
116 | * We are also treating EINTR and EPIPE errors. | ||
117 | \*-------------------------------------------------------------------------*/ | 141 | \*-------------------------------------------------------------------------*/ |
118 | int sock_send(p_sock ps, const char *data, size_t count, size_t *sent, | 142 | int sock_send(p_sock ps, const char *data, size_t count, size_t *sent, |
119 | int timeout) | 143 | int timeout) |
@@ -138,7 +162,8 @@ int sock_send(p_sock ps, const char *data, size_t count, size_t *sent, | |||
138 | tv.tv_usec = (timeout % 1000) * 1000; | 162 | tv.tv_usec = (timeout % 1000) * 1000; |
139 | FD_ZERO(&fds); | 163 | FD_ZERO(&fds); |
140 | FD_SET(sock, &fds); | 164 | FD_SET(sock, &fds); |
141 | ret = select(sock+1, NULL, &fds, NULL, timeout >= 0 ? &tv : NULL); | 165 | do ret = select(sock+1, NULL, &fds, NULL, timeout >= 0 ?&tv : NULL); |
166 | while (ret < 0 && errno == EINTR); | ||
142 | /* tell the caller to call us again because there is more data */ | 167 | /* tell the caller to call us again because there is more data */ |
143 | if (ret > 0) return IO_DONE; | 168 | if (ret > 0) return IO_DONE; |
144 | /* tell the caller there was no data before timeout */ | 169 | /* tell the caller there was no data before timeout */ |
@@ -178,7 +203,8 @@ int sock_sendto(p_sock ps, const char *data, size_t count, size_t *sent, | |||
178 | tv.tv_usec = (timeout % 1000) * 1000; | 203 | tv.tv_usec = (timeout % 1000) * 1000; |
179 | FD_ZERO(&fds); | 204 | FD_ZERO(&fds); |
180 | FD_SET(sock, &fds); | 205 | FD_SET(sock, &fds); |
181 | ret = select(sock+1, NULL, &fds, NULL, timeout >= 0 ? &tv : NULL); | 206 | do ret = select(sock+1, NULL, &fds, NULL, timeout >= 0? &tv: NULL); |
207 | while (ret < 0 && errno == EINTR); | ||
182 | /* tell the caller to call us again because there is more data */ | 208 | /* tell the caller to call us again because there is more data */ |
183 | if (ret > 0) return IO_DONE; | 209 | if (ret > 0) return IO_DONE; |
184 | /* tell the caller there was no data before timeout */ | 210 | /* tell the caller there was no data before timeout */ |
@@ -199,7 +225,6 @@ int sock_sendto(p_sock ps, const char *data, size_t count, size_t *sent, | |||
199 | * will call the function again if we didn't time out, so we can | 225 | * will call the function again if we didn't time out, so we can |
200 | * call write and then select only if it fails. | 226 | * call write and then select only if it fails. |
201 | * Should speed things up! | 227 | * Should speed things up! |
202 | * We are also treating EINTR errors. | ||
203 | \*-------------------------------------------------------------------------*/ | 228 | \*-------------------------------------------------------------------------*/ |
204 | int sock_recv(p_sock ps, char *data, size_t count, size_t *got, int timeout) | 229 | int sock_recv(p_sock ps, char *data, size_t count, size_t *got, int timeout) |
205 | { | 230 | { |
@@ -218,7 +243,8 @@ int sock_recv(p_sock ps, char *data, size_t count, size_t *got, int timeout) | |||
218 | tv.tv_usec = (timeout % 1000) * 1000; | 243 | tv.tv_usec = (timeout % 1000) * 1000; |
219 | FD_ZERO(&fds); | 244 | FD_ZERO(&fds); |
220 | FD_SET(sock, &fds); | 245 | FD_SET(sock, &fds); |
221 | ret = select(sock+1, &fds, NULL, NULL, timeout >= 0 ? &tv : NULL); | 246 | do ret = select(sock+1, &fds, NULL, NULL, timeout >= 0 ? &tv : NULL); |
247 | while (ret < 0 && errno == EINTR); | ||
222 | if (ret > 0) return IO_DONE; | 248 | if (ret > 0) return IO_DONE; |
223 | else return IO_TIMEOUT; | 249 | else return IO_TIMEOUT; |
224 | } else { | 250 | } else { |
@@ -248,7 +274,8 @@ int sock_recvfrom(p_sock ps, char *data, size_t count, size_t *got, | |||
248 | tv.tv_usec = (timeout % 1000) * 1000; | 274 | tv.tv_usec = (timeout % 1000) * 1000; |
249 | FD_ZERO(&fds); | 275 | FD_ZERO(&fds); |
250 | FD_SET(sock, &fds); | 276 | FD_SET(sock, &fds); |
251 | ret = select(sock+1, &fds, NULL, NULL, timeout >= 0 ? &tv : NULL); | 277 | do ret = select(sock+1, &fds, NULL, NULL, timeout >= 0 ? &tv : NULL); |
278 | while (ret < 0 && errno == EINTR); | ||
252 | if (ret > 0) return IO_DONE; | 279 | if (ret > 0) return IO_DONE; |
253 | else return IO_TIMEOUT; | 280 | else return IO_TIMEOUT; |
254 | } else { | 281 | } else { |
diff --git a/src/wsocket.c b/src/wsocket.c index 30208b9..bf92a90 100644 --- a/src/wsocket.c +++ b/src/wsocket.c | |||
@@ -2,6 +2,13 @@ | |||
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. | ||
6 | * The idea is that the outer loop (whoever is calling sock_send/recv) | ||
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 | * | ||
5 | * RCS ID: $Id$ | 12 | * RCS ID: $Id$ |
6 | \*=========================================================================*/ | 13 | \*=========================================================================*/ |
7 | #include <string.h> | 14 | #include <string.h> |