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 /src/usocket.c | |
parent | 076451c75336b30e6152bd5c02f355db39107f7d (diff) | |
download | luasocket-02ef4e7daae6bef629dcb568052755fb85ed2efc.tar.gz luasocket-02ef4e7daae6bef629dcb568052755fb85ed2efc.tar.bz2 luasocket-02ef4e7daae6bef629dcb568052755fb85ed2efc.zip |
Trying to get rid of EINTR problems...
Diffstat (limited to 'src/usocket.c')
-rw-r--r-- | src/usocket.c | 59 |
1 files changed, 43 insertions, 16 deletions
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 { |