diff options
-rw-r--r-- | src/buffer.c | 12 | ||||
-rw-r--r-- | src/http.lua | 8 | ||||
-rw-r--r-- | src/inet.c | 41 | ||||
-rw-r--r-- | src/inet.h | 8 | ||||
-rw-r--r-- | src/io.c | 35 | ||||
-rw-r--r-- | src/io.h | 6 | ||||
-rw-r--r-- | src/socket.h | 7 | ||||
-rw-r--r-- | src/tcp.c | 69 | ||||
-rw-r--r-- | src/timeout.c | 4 | ||||
-rw-r--r-- | src/timeout.h | 4 | ||||
-rw-r--r-- | src/udp.c | 64 | ||||
-rw-r--r-- | src/usocket.c | 163 | ||||
-rw-r--r-- | test/httptest.lua | 3 | ||||
-rw-r--r-- | test/testclnt.lua | 4 |
14 files changed, 231 insertions, 197 deletions
diff --git a/src/buffer.c b/src/buffer.c index 04419e7..e6d4ce8 100644 --- a/src/buffer.c +++ b/src/buffer.c | |||
@@ -138,8 +138,7 @@ int sendraw(p_buf buf, const char *data, size_t count, size_t *sent) | |||
138 | int err = IO_DONE; | 138 | int err = IO_DONE; |
139 | while (total < count && err == IO_DONE) { | 139 | while (total < count && err == IO_DONE) { |
140 | size_t done; | 140 | size_t done; |
141 | err = io->send(io->ctx, data+total, count-total, &done, | 141 | err = io->send(io->ctx, data+total, count-total, &done, tm_get(tm)); |
142 | tm_getsuccess(tm)); | ||
143 | total += done; | 142 | total += done; |
144 | } | 143 | } |
145 | *sent = total; | 144 | *sent = total; |
@@ -156,7 +155,7 @@ int recvraw(lua_State *L, p_buf buf, size_t wanted) | |||
156 | size_t total = 0; | 155 | size_t total = 0; |
157 | luaL_Buffer b; | 156 | luaL_Buffer b; |
158 | luaL_buffinit(L, &b); | 157 | luaL_buffinit(L, &b); |
159 | while (total < wanted && err == IO_DONE) { | 158 | while (total < wanted && (err == IO_DONE || err == IO_RETRY)) { |
160 | size_t count; const char *data; | 159 | size_t count; const char *data; |
161 | err = buf_get(buf, &data, &count); | 160 | err = buf_get(buf, &data, &count); |
162 | count = MIN(count, wanted - total); | 161 | count = MIN(count, wanted - total); |
@@ -177,7 +176,7 @@ int recvall(lua_State *L, p_buf buf) | |||
177 | int err = IO_DONE; | 176 | int err = IO_DONE; |
178 | luaL_Buffer b; | 177 | luaL_Buffer b; |
179 | luaL_buffinit(L, &b); | 178 | luaL_buffinit(L, &b); |
180 | while (err == IO_DONE) { | 179 | while (err == IO_DONE || err == IO_RETRY) { |
181 | const char *data; size_t count; | 180 | const char *data; size_t count; |
182 | err = buf_get(buf, &data, &count); | 181 | err = buf_get(buf, &data, &count); |
183 | luaL_addlstring(&b, data, count); | 182 | luaL_addlstring(&b, data, count); |
@@ -197,7 +196,7 @@ int recvline(lua_State *L, p_buf buf) | |||
197 | int err = IO_DONE; | 196 | int err = IO_DONE; |
198 | luaL_Buffer b; | 197 | luaL_Buffer b; |
199 | luaL_buffinit(L, &b); | 198 | luaL_buffinit(L, &b); |
200 | while (err == IO_DONE) { | 199 | while (err == IO_DONE || err == IO_RETRY) { |
201 | size_t count, pos; const char *data; | 200 | size_t count, pos; const char *data; |
202 | err = buf_get(buf, &data, &count); | 201 | err = buf_get(buf, &data, &count); |
203 | pos = 0; | 202 | pos = 0; |
@@ -240,8 +239,7 @@ int buf_get(p_buf buf, const char **data, size_t *count) | |||
240 | p_tm tm = buf->tm; | 239 | p_tm tm = buf->tm; |
241 | if (buf_isempty(buf)) { | 240 | if (buf_isempty(buf)) { |
242 | size_t got; | 241 | size_t got; |
243 | err = io->recv(io->ctx, buf->data, BUF_SIZE, &got, | 242 | err = io->recv(io->ctx, buf->data, BUF_SIZE, &got, tm_get(tm)); |
244 | tm_getsuccess(tm)); | ||
245 | buf->first = 0; | 243 | buf->first = 0; |
246 | buf->last = got; | 244 | buf->last = got; |
247 | } | 245 | } |
diff --git a/src/http.lua b/src/http.lua index 1925c68..2fc9e87 100644 --- a/src/http.lua +++ b/src/http.lua | |||
@@ -549,10 +549,16 @@ function request_cb(reqt, respt) | |||
549 | reqt.headers = fill_headers(reqt.headers, parsed) | 549 | reqt.headers = fill_headers(reqt.headers, parsed) |
550 | -- try to connect to server | 550 | -- try to connect to server |
551 | local sock | 551 | local sock |
552 | sock, respt.error = socket.connect(parsed.host, parsed.port) | 552 | sock, respt.error = socket.tcp() |
553 | if not sock then return respt end | 553 | if not sock then return respt end |
554 | -- set connection timeout so that we do not hang forever | 554 | -- set connection timeout so that we do not hang forever |
555 | sock:settimeout(TIMEOUT) | 555 | sock:settimeout(TIMEOUT) |
556 | local ret | ||
557 | ret, respt.error = sock:connect(parsed.host, parsed.port) | ||
558 | if not ret then | ||
559 | sock:close() | ||
560 | return respt | ||
561 | end | ||
556 | -- send request message | 562 | -- send request message |
557 | respt.error = send_request(sock, reqt.method, | 563 | respt.error = send_request(sock, reqt.method, |
558 | request_uri(parsed), reqt.headers, reqt.body_cb) | 564 | request_uri(parsed), reqt.headers, reqt.body_cb) |
@@ -180,11 +180,11 @@ static void inet_pushresolved(lua_State *L, struct hostent *hp) | |||
180 | /*-------------------------------------------------------------------------*\ | 180 | /*-------------------------------------------------------------------------*\ |
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, p_tm tm, const char *address, |
184 | unsigned short port, int timeout) | 184 | unsigned short port) |
185 | { | 185 | { |
186 | struct sockaddr_in remote; | 186 | struct sockaddr_in remote; |
187 | const char *err; | 187 | int err; |
188 | memset(&remote, 0, sizeof(remote)); | 188 | memset(&remote, 0, sizeof(remote)); |
189 | remote.sin_family = AF_INET; | 189 | remote.sin_family = AF_INET; |
190 | remote.sin_port = htons(port); | 190 | remote.sin_port = htons(port); |
@@ -197,14 +197,14 @@ 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 | err = sock_connect(ps, (SA *) &remote, sizeof(remote), timeout); | 200 | do err = sock_connect(ps, (SA *) &remote, sizeof(remote), tm_getretry(tm)); |
201 | if (err) { | 201 | while (err == IO_RETRY && tm_getretry(tm)); |
202 | if (err != IO_DONE) { | ||
202 | sock_destroy(ps); | 203 | sock_destroy(ps); |
203 | *ps = SOCK_INVALID; | 204 | *ps = SOCK_INVALID; |
204 | return err; | 205 | if (err == IO_ERROR) return sock_connectstrerror(); |
205 | } else { | 206 | else return io_strerror(err); |
206 | return NULL; | 207 | } else return NULL; |
207 | } | ||
208 | } | 208 | } |
209 | 209 | ||
210 | /*-------------------------------------------------------------------------*\ | 210 | /*-------------------------------------------------------------------------*\ |
@@ -214,7 +214,6 @@ const char *inet_trybind(p_sock ps, const char *address, unsigned short port, | |||
214 | int backlog) | 214 | int backlog) |
215 | { | 215 | { |
216 | struct sockaddr_in local; | 216 | struct sockaddr_in local; |
217 | const char *err; | ||
218 | memset(&local, 0, sizeof(local)); | 217 | memset(&local, 0, sizeof(local)); |
219 | /* address is either wildcard or a valid ip address */ | 218 | /* address is either wildcard or a valid ip address */ |
220 | local.sin_addr.s_addr = htonl(INADDR_ANY); | 219 | local.sin_addr.s_addr = htonl(INADDR_ANY); |
@@ -229,11 +228,10 @@ const char *inet_trybind(p_sock ps, const char *address, unsigned short port, | |||
229 | memcpy(&local.sin_addr, *addr, sizeof(struct in_addr)); | 228 | memcpy(&local.sin_addr, *addr, sizeof(struct in_addr)); |
230 | } | 229 | } |
231 | sock_setblocking(ps); | 230 | sock_setblocking(ps); |
232 | err = sock_bind(ps, (SA *) &local, sizeof(local)); | 231 | if (sock_bind(ps, (SA *) &local, sizeof(local)) != IO_DONE) { |
233 | if (err) { | ||
234 | sock_destroy(ps); | 232 | sock_destroy(ps); |
235 | *ps = SOCK_INVALID; | 233 | *ps = SOCK_INVALID; |
236 | return err; | 234 | return sock_bindstrerror(); |
237 | } else { | 235 | } else { |
238 | sock_setnonblocking(ps); | 236 | sock_setnonblocking(ps); |
239 | if (backlog > 0) sock_listen(ps, backlog); | 237 | if (backlog > 0) sock_listen(ps, backlog); |
@@ -246,7 +244,22 @@ const char *inet_trybind(p_sock ps, const char *address, unsigned short port, | |||
246 | \*-------------------------------------------------------------------------*/ | 244 | \*-------------------------------------------------------------------------*/ |
247 | const char *inet_trycreate(p_sock ps, int type) | 245 | const char *inet_trycreate(p_sock ps, int type) |
248 | { | 246 | { |
249 | return sock_create(ps, AF_INET, type, 0); | 247 | if (sock_create(ps, AF_INET, type, 0) == IO_DONE) return NULL; |
248 | else return sock_createstrerror(); | ||
249 | } | ||
250 | |||
251 | /*-------------------------------------------------------------------------*\ | ||
252 | * Tries to accept an inet socket | ||
253 | \*-------------------------------------------------------------------------*/ | ||
254 | const char *inet_tryaccept(p_sock ps, p_tm tm, p_sock pc) | ||
255 | { | ||
256 | struct sockaddr_in addr; | ||
257 | socklen_t addr_len = sizeof(addr); | ||
258 | int err; | ||
259 | /* loop until connection accepted or timeout happens */ | ||
260 | do err = sock_accept(ps, pc, (SA *) &addr, &addr_len, tm_getretry(tm)); | ||
261 | while (err == IO_RETRY && tm_getretry(tm) != 0); | ||
262 | return io_strerror(err); | ||
250 | } | 263 | } |
251 | 264 | ||
252 | /*-------------------------------------------------------------------------*\ | 265 | /*-------------------------------------------------------------------------*\ |
@@ -18,17 +18,21 @@ | |||
18 | \*=========================================================================*/ | 18 | \*=========================================================================*/ |
19 | #include <lua.h> | 19 | #include <lua.h> |
20 | #include "socket.h" | 20 | #include "socket.h" |
21 | #include "timeout.h" | ||
21 | 22 | ||
22 | #ifdef WIN32 | 23 | #ifdef WIN32 |
23 | #define INET_ATON | 24 | #define INET_ATON |
24 | #endif | 25 | #endif |
25 | 26 | ||
26 | void inet_open(lua_State *L); | 27 | void inet_open(lua_State *L); |
27 | const char *inet_tryconnect(p_sock ps, const char *address, | 28 | |
28 | unsigned short port, int timeout); | 29 | const char *inet_tryconnect(p_sock ps, p_tm tm, const char *address, |
30 | unsigned short port); | ||
29 | const char *inet_trybind(p_sock ps, const char *address, | 31 | const char *inet_trybind(p_sock ps, const char *address, |
30 | unsigned short port, int backlog); | 32 | unsigned short port, int backlog); |
31 | const char *inet_trycreate(p_sock ps, int type); | 33 | const char *inet_trycreate(p_sock ps, int type); |
34 | const char *inet_tryaccept(p_sock ps, p_tm tm, p_sock pc); | ||
35 | |||
32 | int inet_meth_getpeername(lua_State *L, p_sock ps); | 36 | int inet_meth_getpeername(lua_State *L, p_sock ps); |
33 | int inet_meth_getsockname(lua_State *L, p_sock ps); | 37 | int inet_meth_getsockname(lua_State *L, p_sock ps); |
34 | 38 | ||
@@ -22,27 +22,24 @@ void io_init(p_io io, p_send send, p_recv recv, void *ctx) | |||
22 | /*-------------------------------------------------------------------------*\ | 22 | /*-------------------------------------------------------------------------*\ |
23 | * Translate error codes to Lua | 23 | * Translate error codes to Lua |
24 | \*-------------------------------------------------------------------------*/ | 24 | \*-------------------------------------------------------------------------*/ |
25 | void io_pusherror(lua_State *L, int code) | 25 | const char *io_strerror(int code) |
26 | { | 26 | { |
27 | switch (code) { | 27 | switch (code) { |
28 | case IO_DONE: | 28 | case IO_DONE: return NULL; |
29 | lua_pushnil(L); | 29 | case IO_TIMEOUT: return "timeout"; |
30 | break; | 30 | case IO_RETRY: return "retry"; |
31 | case IO_TIMEOUT: | 31 | case IO_CLOSED: return "closed"; |
32 | lua_pushstring(L, "timeout"); | 32 | case IO_REFUSED: return "refused"; |
33 | break; | 33 | default: return "unknown error"; |
34 | case IO_LIMITED: | ||
35 | lua_pushstring(L, "limited"); | ||
36 | break; | ||
37 | case IO_CLOSED: | ||
38 | lua_pushstring(L, "closed"); | ||
39 | break; | ||
40 | case IO_REFUSED: | ||
41 | lua_pushstring(L, "refused"); | ||
42 | break; | ||
43 | default: | ||
44 | lua_pushstring(L, "unknown error"); | ||
45 | break; | ||
46 | } | 34 | } |
47 | } | 35 | } |
48 | 36 | ||
37 | /*-------------------------------------------------------------------------*\ | ||
38 | * Translate error codes to Lua | ||
39 | \*-------------------------------------------------------------------------*/ | ||
40 | void io_pusherror(lua_State *L, int code) | ||
41 | { | ||
42 | const char *err = io_strerror(code); | ||
43 | if (err) lua_pushstring(L, err); | ||
44 | else lua_pushnil(L); | ||
45 | } | ||
@@ -20,12 +20,11 @@ | |||
20 | /* IO error codes */ | 20 | /* IO error codes */ |
21 | enum { | 21 | enum { |
22 | IO_DONE, /* operation completed successfully */ | 22 | IO_DONE, /* operation completed successfully */ |
23 | IO_RETRY, /* please try again */ | ||
23 | IO_TIMEOUT, /* operation timed out */ | 24 | IO_TIMEOUT, /* operation timed out */ |
24 | IO_CLOSED, /* the connection has been closed */ | 25 | IO_CLOSED, /* the connection has been closed */ |
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_ERROR /* something else wrong... */ |
28 | IO_LIMITED /* maximum number of bytes reached */ | ||
29 | }; | 28 | }; |
30 | 29 | ||
31 | /* interface to send function */ | 30 | /* interface to send function */ |
@@ -54,6 +53,7 @@ typedef struct t_io_ { | |||
54 | } t_io; | 53 | } t_io; |
55 | typedef t_io *p_io; | 54 | typedef t_io *p_io; |
56 | 55 | ||
56 | const char *io_strerror(int code); | ||
57 | void io_pusherror(lua_State *L, int code); | 57 | void io_pusherror(lua_State *L, int code); |
58 | void io_init(p_io io, p_send send, p_recv recv, void *ctx); | 58 | void io_init(p_io io, p_send send, p_recv recv, void *ctx); |
59 | 59 | ||
diff --git a/src/socket.h b/src/socket.h index aeadff0..739dedd 100644 --- a/src/socket.h +++ b/src/socket.h | |||
@@ -30,12 +30,12 @@ typedef struct sockaddr SA; | |||
30 | * interface to sockets | 30 | * interface to sockets |
31 | \*=========================================================================*/ | 31 | \*=========================================================================*/ |
32 | int sock_open(void); | 32 | int sock_open(void); |
33 | const char *sock_create(p_sock ps, int domain, int type, int protocol); | 33 | int 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, int timeout); | 37 | int 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 | int 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); |
41 | int sock_send(p_sock ps, const char *data, size_t count, | 41 | int sock_send(p_sock ps, const char *data, size_t count, |
@@ -48,6 +48,7 @@ int sock_recvfrom(p_sock ps, char *data, size_t count, | |||
48 | size_t *got, SA *addr, socklen_t *addr_len, int timeout); | 48 | size_t *got, SA *addr, socklen_t *addr_len, int timeout); |
49 | void sock_setnonblocking(p_sock ps); | 49 | void sock_setnonblocking(p_sock ps); |
50 | void sock_setblocking(p_sock ps); | 50 | void sock_setblocking(p_sock ps); |
51 | |||
51 | const char *sock_hoststrerror(void); | 52 | const char *sock_hoststrerror(void); |
52 | const char *sock_createstrerror(void); | 53 | const char *sock_createstrerror(void); |
53 | const char *sock_bindstrerror(void); | 54 | const char *sock_bindstrerror(void); |
@@ -63,7 +63,7 @@ static luaL_reg tcp[] = { | |||
63 | static luaL_reg opt[] = { | 63 | static luaL_reg opt[] = { |
64 | {"keepalive", opt_keepalive}, | 64 | {"keepalive", opt_keepalive}, |
65 | {"reuseaddr", opt_reuseaddr}, | 65 | {"reuseaddr", opt_reuseaddr}, |
66 | {"tcp-nodelay", opt_tcp_nodelay}, | 66 | {"tcp-nodelay", opt_tcp_nodelay}, |
67 | {"linger", opt_linger}, | 67 | {"linger", opt_linger}, |
68 | {NULL, NULL} | 68 | {NULL, NULL} |
69 | }; | 69 | }; |
@@ -200,32 +200,26 @@ static int meth_dirty(lua_State *L) | |||
200 | \*-------------------------------------------------------------------------*/ | 200 | \*-------------------------------------------------------------------------*/ |
201 | static int meth_accept(lua_State *L) | 201 | static int meth_accept(lua_State *L) |
202 | { | 202 | { |
203 | struct sockaddr_in addr; | ||
204 | socklen_t addr_len = sizeof(addr); | ||
205 | int err = IO_ERROR; | ||
206 | p_tcp server = (p_tcp) aux_checkclass(L, "tcp{server}", 1); | 203 | p_tcp server = (p_tcp) aux_checkclass(L, "tcp{server}", 1); |
207 | p_tm tm = &server->tm; | 204 | p_tm tm = &server->tm; |
208 | p_tcp client; | ||
209 | t_sock sock; | 205 | t_sock sock; |
210 | tm_markstart(tm); | 206 | tm_markstart(tm); |
211 | /* loop until connection accepted or timeout happens */ | 207 | const char *err = inet_tryaccept(&server->sock, tm, &sock); |
212 | while (err != IO_DONE) { | 208 | /* if successful, push client socket */ |
213 | err = sock_accept(&server->sock, &sock, | 209 | if (!err) { |
214 | (SA *) &addr, &addr_len, tm_getfailure(tm)); | 210 | p_tcp clnt = lua_newuserdata(L, sizeof(t_tcp)); |
215 | if (err == IO_CLOSED || (err == IO_TIMEOUT && !tm_getfailure(tm))) { | 211 | aux_setclass(L, "tcp{client}", -1); |
216 | lua_pushnil(L); | 212 | /* initialize structure fields */ |
217 | io_pusherror(L, err); | 213 | clnt->sock = sock; |
218 | return 2; | 214 | io_init(&clnt->io, (p_send)sock_send, (p_recv)sock_recv, &clnt->sock); |
219 | } | 215 | tm_init(&clnt->tm, -1, -1); |
216 | buf_init(&clnt->buf, &clnt->io, &clnt->tm); | ||
217 | return 1; | ||
218 | } else { | ||
219 | lua_pushnil(L); | ||
220 | lua_pushstring(L, err); | ||
221 | return 2; | ||
220 | } | 222 | } |
221 | client = lua_newuserdata(L, sizeof(t_tcp)); | ||
222 | aux_setclass(L, "tcp{client}", -1); | ||
223 | client->sock = sock; | ||
224 | /* initialize remaining structure fields */ | ||
225 | io_init(&client->io, (p_send) sock_send, (p_recv) sock_recv, &client->sock); | ||
226 | tm_init(&client->tm, -1, -1); | ||
227 | buf_init(&client->buf, &client->io, &client->tm); | ||
228 | return 1; | ||
229 | } | 223 | } |
230 | 224 | ||
231 | /*-------------------------------------------------------------------------*\ | 225 | /*-------------------------------------------------------------------------*\ |
@@ -260,7 +254,7 @@ static int meth_connect(lua_State *L) | |||
260 | p_tm tm = &tcp->tm; | 254 | p_tm tm = &tcp->tm; |
261 | const char *err; | 255 | const char *err; |
262 | tm_markstart(tm); | 256 | tm_markstart(tm); |
263 | err = inet_tryconnect(&tcp->sock, address, port, tm_getfailure(tm)); | 257 | err = inet_tryconnect(&tcp->sock, tm, address, port); |
264 | if (err) { | 258 | if (err) { |
265 | lua_pushnil(L); | 259 | lua_pushnil(L); |
266 | lua_pushstring(L, err); | 260 | lua_pushstring(L, err); |
@@ -283,7 +277,7 @@ static int meth_close(lua_State *L) | |||
283 | } | 277 | } |
284 | 278 | ||
285 | /*-------------------------------------------------------------------------*\ | 279 | /*-------------------------------------------------------------------------*\ |
286 | * Shuts the connection down | 280 | * Shuts the connection down partially |
287 | \*-------------------------------------------------------------------------*/ | 281 | \*-------------------------------------------------------------------------*/ |
288 | static int meth_shutdown(lua_State *L) | 282 | static int meth_shutdown(lua_State *L) |
289 | { | 283 | { |
@@ -341,22 +335,23 @@ static int meth_settimeout(lua_State *L) | |||
341 | \*-------------------------------------------------------------------------*/ | 335 | \*-------------------------------------------------------------------------*/ |
342 | int global_create(lua_State *L) | 336 | int global_create(lua_State *L) |
343 | { | 337 | { |
344 | const char *err; | 338 | t_sock sock; |
345 | /* allocate tcp object */ | 339 | const char *err = inet_trycreate(&sock, SOCK_STREAM); |
346 | p_tcp tcp = (p_tcp) lua_newuserdata(L, sizeof(t_tcp)); | ||
347 | /* set its type as master object */ | ||
348 | aux_setclass(L, "tcp{master}", -1); | ||
349 | /* try to allocate a system socket */ | 340 | /* try to allocate a system socket */ |
350 | err = inet_trycreate(&tcp->sock, SOCK_STREAM); | 341 | if (!err) { |
351 | if (err) { /* get rid of object on stack and push error */ | 342 | /* allocate tcp object */ |
352 | lua_pop(L, 1); | 343 | p_tcp tcp = (p_tcp) lua_newuserdata(L, sizeof(t_tcp)); |
344 | tcp->sock = sock; | ||
345 | /* set its type as master object */ | ||
346 | aux_setclass(L, "tcp{master}", -1); | ||
347 | /* initialize remaining structure fields */ | ||
348 | io_init(&tcp->io, (p_send) sock_send, (p_recv) sock_recv, &tcp->sock); | ||
349 | tm_init(&tcp->tm, -1, -1); | ||
350 | buf_init(&tcp->buf, &tcp->io, &tcp->tm); | ||
351 | return 1; | ||
352 | } else { | ||
353 | lua_pushnil(L); | 353 | lua_pushnil(L); |
354 | lua_pushstring(L, err); | 354 | lua_pushstring(L, err); |
355 | return 2; | 355 | return 2; |
356 | } | 356 | } |
357 | /* initialize remaining structure fields */ | ||
358 | io_init(&tcp->io, (p_send) sock_send, (p_recv) sock_recv, &tcp->sock); | ||
359 | tm_init(&tcp->tm, -1, -1); | ||
360 | buf_init(&tcp->buf, &tcp->io, &tcp->tm); | ||
361 | return 1; | ||
362 | } | 357 | } |
diff --git a/src/timeout.c b/src/timeout.c index 2d88ded..0063378 100644 --- a/src/timeout.c +++ b/src/timeout.c | |||
@@ -54,7 +54,7 @@ void tm_init(p_tm tm, int block, int total) | |||
54 | * Returns | 54 | * Returns |
55 | * the number of ms left or -1 if there is no time limit | 55 | * the number of ms left or -1 if there is no time limit |
56 | \*-------------------------------------------------------------------------*/ | 56 | \*-------------------------------------------------------------------------*/ |
57 | int tm_getsuccess(p_tm tm) | 57 | int tm_get(p_tm tm) |
58 | { | 58 | { |
59 | if (tm->block < 0 && tm->total < 0) { | 59 | if (tm->block < 0 && tm->total < 0) { |
60 | return -1; | 60 | return -1; |
@@ -89,7 +89,7 @@ int tm_getstart(p_tm tm) | |||
89 | * Returns | 89 | * Returns |
90 | * the number of ms left or -1 if there is no time limit | 90 | * the number of ms left or -1 if there is no time limit |
91 | \*-------------------------------------------------------------------------*/ | 91 | \*-------------------------------------------------------------------------*/ |
92 | int tm_getfailure(p_tm tm) | 92 | int tm_getretry(p_tm tm) |
93 | { | 93 | { |
94 | if (tm->block < 0 && tm->total < 0) { | 94 | if (tm->block < 0 && tm->total < 0) { |
95 | return -1; | 95 | return -1; |
diff --git a/src/timeout.h b/src/timeout.h index 17f44ea..0a036f4 100644 --- a/src/timeout.h +++ b/src/timeout.h | |||
@@ -18,8 +18,8 @@ typedef t_tm *p_tm; | |||
18 | 18 | ||
19 | void tm_open(lua_State *L); | 19 | void tm_open(lua_State *L); |
20 | void tm_init(p_tm tm, int block, int total); | 20 | void tm_init(p_tm tm, int block, int total); |
21 | int tm_getsuccess(p_tm tm); | 21 | int tm_get(p_tm tm); |
22 | int tm_getfailure(p_tm tm); | 22 | int tm_getretry(p_tm tm); |
23 | void tm_markstart(p_tm tm); | 23 | void tm_markstart(p_tm tm); |
24 | int tm_getstart(p_tm tm); | 24 | int tm_getstart(p_tm tm); |
25 | int tm_gettime(void); | 25 | int tm_gettime(void); |
@@ -29,6 +29,7 @@ static int meth_getpeername(lua_State *L); | |||
29 | static int meth_setsockname(lua_State *L); | 29 | static int meth_setsockname(lua_State *L); |
30 | static int meth_setpeername(lua_State *L); | 30 | static int meth_setpeername(lua_State *L); |
31 | static int meth_close(lua_State *L); | 31 | static int meth_close(lua_State *L); |
32 | static int meth_shutdown(lua_State *L); | ||
32 | static int meth_setoption(lua_State *L); | 33 | static int meth_setoption(lua_State *L); |
33 | static int meth_settimeout(lua_State *L); | 34 | static int meth_settimeout(lua_State *L); |
34 | static int meth_fd(lua_State *L); | 35 | static int meth_fd(lua_State *L); |
@@ -53,6 +54,7 @@ static luaL_reg udp[] = { | |||
53 | {"receivefrom", meth_receivefrom}, | 54 | {"receivefrom", meth_receivefrom}, |
54 | {"settimeout", meth_settimeout}, | 55 | {"settimeout", meth_settimeout}, |
55 | {"close", meth_close}, | 56 | {"close", meth_close}, |
57 | {"shutdown", meth_shutdown}, | ||
56 | {"setoption", meth_setoption}, | 58 | {"setoption", meth_setoption}, |
57 | {"__gc", meth_close}, | 59 | {"__gc", meth_close}, |
58 | {"fd", meth_fd}, | 60 | {"fd", meth_fd}, |
@@ -110,7 +112,7 @@ static int meth_send(lua_State *L) | |||
110 | int err; | 112 | int err; |
111 | const char *data = luaL_checklstring(L, 2, &count); | 113 | const char *data = luaL_checklstring(L, 2, &count); |
112 | tm_markstart(tm); | 114 | tm_markstart(tm); |
113 | err = sock_send(&udp->sock, data, count, &sent, tm_getsuccess(tm)); | 115 | err = sock_send(&udp->sock, data, count, &sent, tm_get(tm)); |
114 | if (err == IO_DONE) lua_pushnumber(L, sent); | 116 | if (err == IO_DONE) lua_pushnumber(L, sent); |
115 | else lua_pushnil(L); | 117 | else lua_pushnil(L); |
116 | /* a 'closed' error on an unconnected means the target address was not | 118 | /* a 'closed' error on an unconnected means the target address was not |
@@ -139,7 +141,7 @@ static int meth_sendto(lua_State *L) | |||
139 | addr.sin_port = htons(port); | 141 | addr.sin_port = htons(port); |
140 | tm_markstart(tm); | 142 | tm_markstart(tm); |
141 | err = sock_sendto(&udp->sock, data, count, &sent, | 143 | err = sock_sendto(&udp->sock, data, count, &sent, |
142 | (SA *) &addr, sizeof(addr), tm_getsuccess(tm)); | 144 | (SA *) &addr, sizeof(addr), tm_get(tm)); |
143 | if (err == IO_DONE) lua_pushnumber(L, sent); | 145 | if (err == IO_DONE) lua_pushnumber(L, sent); |
144 | else lua_pushnil(L); | 146 | else lua_pushnil(L); |
145 | /* a 'closed' error on an unconnected means the target address was not | 147 | /* a 'closed' error on an unconnected means the target address was not |
@@ -160,7 +162,7 @@ static int meth_receive(lua_State *L) | |||
160 | p_tm tm = &udp->tm; | 162 | p_tm tm = &udp->tm; |
161 | count = MIN(count, sizeof(buffer)); | 163 | count = MIN(count, sizeof(buffer)); |
162 | tm_markstart(tm); | 164 | tm_markstart(tm); |
163 | err = sock_recv(&udp->sock, buffer, count, &got, tm_getsuccess(tm)); | 165 | err = sock_recv(&udp->sock, buffer, count, &got, tm_get(tm)); |
164 | if (err == IO_DONE) lua_pushlstring(L, buffer, got); | 166 | if (err == IO_DONE) lua_pushlstring(L, buffer, got); |
165 | else lua_pushnil(L); | 167 | else lua_pushnil(L); |
166 | io_pusherror(L, err); | 168 | io_pusherror(L, err); |
@@ -182,7 +184,7 @@ static int meth_receivefrom(lua_State *L) | |||
182 | tm_markstart(tm); | 184 | tm_markstart(tm); |
183 | count = MIN(count, sizeof(buffer)); | 185 | count = MIN(count, sizeof(buffer)); |
184 | err = sock_recvfrom(&udp->sock, buffer, count, &got, | 186 | err = sock_recvfrom(&udp->sock, buffer, count, &got, |
185 | (SA *) &addr, &addr_len, tm_getsuccess(tm)); | 187 | (SA *) &addr, &addr_len, tm_get(tm)); |
186 | if (err == IO_DONE) { | 188 | if (err == IO_DONE) { |
187 | lua_pushlstring(L, buffer, got); | 189 | lua_pushlstring(L, buffer, got); |
188 | lua_pushstring(L, inet_ntoa(addr.sin_addr)); | 190 | lua_pushstring(L, inet_ntoa(addr.sin_addr)); |
@@ -341,8 +343,7 @@ static int meth_setpeername(lua_State *L) | |||
341 | unsigned short port = connecting ? | 343 | unsigned short port = connecting ? |
342 | (unsigned short) luaL_checknumber(L, 3) : | 344 | (unsigned short) luaL_checknumber(L, 3) : |
343 | (unsigned short) luaL_optnumber(L, 3, 0); | 345 | (unsigned short) luaL_optnumber(L, 3, 0); |
344 | const char *err; | 346 | const char *err = inet_tryconnect(&udp->sock, tm, address, port); |
345 | err = inet_tryconnect(&udp->sock, address, port, tm_getfailure(tm)); | ||
346 | if (err) { | 347 | if (err) { |
347 | lua_pushnil(L); | 348 | lua_pushnil(L); |
348 | lua_pushstring(L, err); | 349 | lua_pushstring(L, err); |
@@ -366,6 +367,33 @@ static int meth_close(lua_State *L) | |||
366 | } | 367 | } |
367 | 368 | ||
368 | /*-------------------------------------------------------------------------*\ | 369 | /*-------------------------------------------------------------------------*\ |
370 | * Shuts the connection down partially | ||
371 | \*-------------------------------------------------------------------------*/ | ||
372 | static int meth_shutdown(lua_State *L) | ||
373 | { | ||
374 | p_udp udp = (p_udp) aux_checkgroup(L, "udp{any}", 1); | ||
375 | const char *how = luaL_optstring(L, 2, "both"); | ||
376 | switch (how[0]) { | ||
377 | case 'b': | ||
378 | if (strcmp(how, "both")) goto error; | ||
379 | sock_shutdown(&udp->sock, 2); | ||
380 | break; | ||
381 | case 's': | ||
382 | if (strcmp(how, "send")) goto error; | ||
383 | sock_shutdown(&udp->sock, 1); | ||
384 | break; | ||
385 | case 'r': | ||
386 | if (strcmp(how, "receive")) goto error; | ||
387 | sock_shutdown(&udp->sock, 0); | ||
388 | break; | ||
389 | } | ||
390 | return 0; | ||
391 | error: | ||
392 | luaL_argerror(L, 2, "invalid shutdown method"); | ||
393 | return 0; | ||
394 | } | ||
395 | |||
396 | /*-------------------------------------------------------------------------*\ | ||
369 | * Turns a master object into a server object | 397 | * Turns a master object into a server object |
370 | \*-------------------------------------------------------------------------*/ | 398 | \*-------------------------------------------------------------------------*/ |
371 | static int meth_setsockname(lua_State *L) | 399 | static int meth_setsockname(lua_State *L) |
@@ -391,21 +419,21 @@ static int meth_setsockname(lua_State *L) | |||
391 | \*-------------------------------------------------------------------------*/ | 419 | \*-------------------------------------------------------------------------*/ |
392 | int global_create(lua_State *L) | 420 | int global_create(lua_State *L) |
393 | { | 421 | { |
394 | const char *err; | 422 | t_sock sock; |
395 | /* allocate udp object */ | 423 | const char *err = inet_trycreate(&sock, SOCK_DGRAM); |
396 | p_udp udp = (p_udp) lua_newuserdata(L, sizeof(t_udp)); | ||
397 | /* set its type as master object */ | ||
398 | aux_setclass(L, "udp{unconnected}", -1); | ||
399 | /* try to allocate a system socket */ | 424 | /* try to allocate a system socket */ |
400 | err = inet_trycreate(&udp->sock, SOCK_DGRAM); | 425 | if (!err) { |
401 | if (err) { | 426 | /* allocate tcp object */ |
402 | /* get rid of object on stack and push error */ | 427 | p_udp udp = (p_udp) lua_newuserdata(L, sizeof(t_udp)); |
403 | lua_pop(L, 1); | 428 | udp->sock = sock; |
429 | /* set its type as master object */ | ||
430 | aux_setclass(L, "udp{unconnected}", -1); | ||
431 | /* initialize remaining structure fields */ | ||
432 | tm_init(&udp->tm, -1, -1); | ||
433 | return 1; | ||
434 | } else { | ||
404 | lua_pushnil(L); | 435 | lua_pushnil(L); |
405 | lua_pushstring(L, err); | 436 | lua_pushstring(L, err); |
406 | return 2; | 437 | return 2; |
407 | } | 438 | } |
408 | /* initialize timeout management */ | ||
409 | tm_init(&udp->tm, -1, -1); | ||
410 | return 1; | ||
411 | } | 439 | } |
diff --git a/src/usocket.c b/src/usocket.c index 9fcf4e8..acac852 100644 --- a/src/usocket.c +++ b/src/usocket.c | |||
@@ -46,50 +46,59 @@ void sock_destroy(p_sock ps) | |||
46 | /*-------------------------------------------------------------------------*\ | 46 | /*-------------------------------------------------------------------------*\ |
47 | * Creates and sets up a socket | 47 | * Creates and sets up a socket |
48 | \*-------------------------------------------------------------------------*/ | 48 | \*-------------------------------------------------------------------------*/ |
49 | const char *sock_create(p_sock ps, int domain, int type, int protocol) | 49 | int sock_create(p_sock ps, int domain, int type, int protocol) |
50 | { | 50 | { |
51 | int val = 1; | 51 | int val = 1; |
52 | t_sock sock = socket(domain, type, protocol); | 52 | t_sock sock = socket(domain, type, protocol); |
53 | if (sock == SOCK_INVALID) return sock_createstrerror(); | 53 | if (sock == SOCK_INVALID) return IO_ERROR; |
54 | *ps = sock; | 54 | *ps = sock; |
55 | sock_setnonblocking(ps); | 55 | sock_setnonblocking(ps); |
56 | setsockopt(*ps, SOL_SOCKET, SO_REUSEADDR, (char *) &val, sizeof(val)); | 56 | setsockopt(*ps, SOL_SOCKET, SO_REUSEADDR, (char *) &val, sizeof(val)); |
57 | return NULL; | 57 | return IO_DONE; |
58 | } | 58 | } |
59 | 59 | ||
60 | /*-------------------------------------------------------------------------*\ | 60 | /*-------------------------------------------------------------------------*\ |
61 | * Connects or returns error message | 61 | * Connects or returns error message |
62 | \*-------------------------------------------------------------------------*/ | 62 | \*-------------------------------------------------------------------------*/ |
63 | const char *sock_connect(p_sock ps, SA *addr, socklen_t addr_len, int timeout) | 63 | int sock_connect(p_sock ps, SA *addr, socklen_t addr_len, int timeout) |
64 | { | 64 | { |
65 | t_sock sock = *ps; | 65 | t_sock sock = *ps; |
66 | if (sock == SOCK_INVALID) return "closed"; | 66 | if (sock == SOCK_INVALID) return IO_CLOSED; |
67 | /* if connect fails, we have to find out why */ | ||
67 | if (connect(sock, addr, addr_len) < 0) { | 68 | if (connect(sock, addr, addr_len) < 0) { |
68 | struct timeval tv; | 69 | struct timeval tv; |
69 | fd_set wfds, efds; | 70 | fd_set rfds, efds, wfds; |
70 | int err; | 71 | int err; |
72 | /* make sure the system is trying to connect */ | ||
73 | if (errno != EINPROGRESS) return IO_ERROR; | ||
71 | tv.tv_sec = timeout / 1000; | 74 | tv.tv_sec = timeout / 1000; |
72 | tv.tv_usec = (timeout % 1000) * 1000; | 75 | tv.tv_usec = (timeout % 1000) * 1000; |
73 | FD_ZERO(&wfds); FD_ZERO(&efds); | 76 | FD_ZERO(&rfds); FD_SET(sock, &rfds); |
74 | FD_SET(sock, &wfds); FD_SET(sock, &efds); | 77 | FD_ZERO(&wfds); FD_SET(sock, &wfds); |
75 | do err = select(sock+1, NULL, &wfds, &efds, timeout >= 0 ? &tv : NULL); | 78 | FD_ZERO(&efds); FD_SET(sock, &efds); |
76 | while (err < 0 && errno == EINTR); | 79 | /* we run select to avoid busy waiting */ |
77 | if (err <= 0) return "timeout"; | 80 | err = select(sock+1, &rfds, &wfds, &efds, timeout >= 0? &tv: NULL); |
78 | if (FD_ISSET(sock, &efds)) { | 81 | /* if select was interrupted, ask the user to retry */ |
82 | if (err < 0 && errno == EINTR) return IO_RETRY; | ||
83 | /* if selects readable, try reading */ | ||
84 | if (err > 0) { | ||
79 | char dummy; | 85 | char dummy; |
80 | recv(sock, &dummy, 0, 0); | 86 | /* try reading so that errno is set */ |
81 | return sock_connectstrerror(); | 87 | if (recv(sock, &dummy, 0, 0) < 0) return IO_ERROR; |
82 | } else return NULL; | 88 | return IO_DONE; |
83 | } else return NULL; | 89 | /* if no event happened, there was a timeout */ |
90 | } else return IO_TIMEOUT; | ||
91 | /* otherwise connection succeeded */ | ||
92 | } else return IO_DONE; | ||
84 | } | 93 | } |
85 | 94 | ||
86 | /*-------------------------------------------------------------------------*\ | 95 | /*-------------------------------------------------------------------------*\ |
87 | * Binds or returns error message | 96 | * Binds or returns error message |
88 | \*-------------------------------------------------------------------------*/ | 97 | \*-------------------------------------------------------------------------*/ |
89 | const char *sock_bind(p_sock ps, SA *addr, socklen_t addr_len) | 98 | int sock_bind(p_sock ps, SA *addr, socklen_t addr_len) |
90 | { | 99 | { |
91 | if (bind(*ps, addr, addr_len) < 0) return sock_bindstrerror(); | 100 | if (bind(*ps, addr, addr_len) < 0) return IO_ERROR; |
92 | else return NULL; | 101 | else return IO_DONE; |
93 | } | 102 | } |
94 | 103 | ||
95 | /*-------------------------------------------------------------------------*\ | 104 | /*-------------------------------------------------------------------------*\ |
@@ -115,25 +124,24 @@ int sock_accept(p_sock ps, p_sock pa, SA *addr, socklen_t *addr_len, | |||
115 | int timeout) | 124 | int timeout) |
116 | { | 125 | { |
117 | t_sock sock = *ps; | 126 | t_sock sock = *ps; |
118 | struct timeval tv; | ||
119 | SA dummy_addr; | 127 | SA dummy_addr; |
120 | socklen_t dummy_len; | 128 | socklen_t dummy_len; |
121 | fd_set fds; | ||
122 | int err; | ||
123 | if (sock == SOCK_INVALID) return IO_CLOSED; | 129 | if (sock == SOCK_INVALID) return IO_CLOSED; |
124 | tv.tv_sec = timeout / 1000; | ||
125 | tv.tv_usec = (timeout % 1000) * 1000; | ||
126 | FD_ZERO(&fds); | ||
127 | FD_SET(sock, &fds); | ||
128 | *pa = SOCK_INVALID; | ||
129 | do err = select(sock+1, &fds, NULL, NULL, timeout >= 0 ? &tv : NULL); | ||
130 | while (err < 0 && errno == EINTR); | ||
131 | if (err <= 0) return IO_TIMEOUT; | ||
132 | if (!addr) addr = &dummy_addr; | 130 | if (!addr) addr = &dummy_addr; |
133 | if (!addr_len) addr_len = &dummy_len; | 131 | if (!addr_len) addr_len = &dummy_len; |
134 | *pa = accept(sock, addr, addr_len); | 132 | *pa = accept(sock, addr, addr_len); |
135 | if (*pa == SOCK_INVALID) return IO_ERROR; | 133 | if (*pa == SOCK_INVALID) { |
136 | else return IO_DONE; | 134 | struct timeval tv; |
135 | fd_set fds; | ||
136 | tv.tv_sec = timeout / 1000; | ||
137 | tv.tv_usec = (timeout % 1000) * 1000; | ||
138 | FD_ZERO(&fds); | ||
139 | FD_SET(sock, &fds); | ||
140 | /* just call select to avoid busy-wait. doesn't really matter | ||
141 | * what happens. the caller will choose to retry or not */ | ||
142 | select(sock+1, &fds, NULL, NULL, timeout >= 0? &tv: NULL); | ||
143 | return IO_RETRY; | ||
144 | } else return IO_DONE; | ||
137 | } | 145 | } |
138 | 146 | ||
139 | /*-------------------------------------------------------------------------*\ | 147 | /*-------------------------------------------------------------------------*\ |
@@ -144,32 +152,31 @@ int sock_send(p_sock ps, const char *data, size_t count, size_t *sent, | |||
144 | { | 152 | { |
145 | t_sock sock = *ps; | 153 | t_sock sock = *ps; |
146 | ssize_t put; | 154 | ssize_t put; |
147 | int ret; | ||
148 | /* avoid making system calls on closed sockets */ | 155 | /* avoid making system calls on closed sockets */ |
149 | if (sock == SOCK_INVALID) return IO_CLOSED; | 156 | if (sock == SOCK_INVALID) return IO_CLOSED; |
150 | /* make sure we repeat in case the call was interrupted */ | 157 | /* make sure we repeat in case the call was interrupted */ |
151 | do put = write(sock, data, count); | 158 | do put = send(sock, data, count, 0); |
152 | while (put <= 0 && errno == EINTR); | 159 | while (put < 0 && errno == EINTR); |
153 | /* deal with failure */ | 160 | /* deal with failure */ |
154 | if (put <= 0) { | 161 | if (put <= 0) { |
162 | struct timeval tv; | ||
163 | fd_set fds; | ||
155 | /* in any case, nothing has been sent */ | 164 | /* in any case, nothing has been sent */ |
156 | *sent = 0; | 165 | *sent = 0; |
166 | /* here we know the connection has been closed */ | ||
167 | if (errno == EPIPE) return IO_CLOSED; | ||
157 | /* run select to avoid busy wait */ | 168 | /* run select to avoid busy wait */ |
158 | if (errno != EPIPE) { | 169 | tv.tv_sec = timeout / 1000; |
159 | struct timeval tv; | 170 | tv.tv_usec = (timeout % 1000) * 1000; |
160 | fd_set fds; | 171 | FD_ZERO(&fds); |
161 | tv.tv_sec = timeout / 1000; | 172 | FD_SET(sock, &fds); |
162 | tv.tv_usec = (timeout % 1000) * 1000; | 173 | if (select(sock+1, NULL, &fds, NULL, timeout >= 0? &tv: NULL) <= 0) { |
163 | FD_ZERO(&fds); | 174 | /* here the call was interrupted. calling again might work */ |
164 | FD_SET(sock, &fds); | 175 | if (errno == EINTR) return IO_RETRY; |
165 | do ret = select(sock+1, NULL, &fds, NULL, timeout >= 0 ?&tv : NULL); | 176 | /* here there was no data before timeout */ |
166 | while (ret < 0 && errno == EINTR); | ||
167 | /* tell the caller to call us again because there is more data */ | ||
168 | if (ret > 0) return IO_DONE; | ||
169 | /* tell the caller there was no data before timeout */ | ||
170 | else return IO_TIMEOUT; | 177 | else return IO_TIMEOUT; |
171 | /* here we know the connection has been closed */ | 178 | /* here we didn't send anything, but now we can */ |
172 | } else return IO_CLOSED; | 179 | } else return IO_DONE; |
173 | /* here we successfully sent something */ | 180 | /* here we successfully sent something */ |
174 | } else { | 181 | } else { |
175 | *sent = put; | 182 | *sent = put; |
@@ -185,33 +192,22 @@ int sock_sendto(p_sock ps, const char *data, size_t count, size_t *sent, | |||
185 | { | 192 | { |
186 | t_sock sock = *ps; | 193 | t_sock sock = *ps; |
187 | ssize_t put; | 194 | ssize_t put; |
188 | int ret; | ||
189 | /* avoid making system calls on closed sockets */ | ||
190 | if (sock == SOCK_INVALID) return IO_CLOSED; | 195 | if (sock == SOCK_INVALID) return IO_CLOSED; |
191 | /* make sure we repeat in case the call was interrupted */ | ||
192 | do put = sendto(sock, data, count, 0, addr, addr_len); | 196 | do put = sendto(sock, data, count, 0, addr, addr_len); |
193 | while (put <= 0 && errno == EINTR); | 197 | while (put < 0 && errno == EINTR); |
194 | /* deal with failure */ | ||
195 | if (put <= 0) { | 198 | if (put <= 0) { |
196 | /* in any case, nothing has been sent */ | 199 | struct timeval tv; |
200 | fd_set fds; | ||
197 | *sent = 0; | 201 | *sent = 0; |
198 | /* run select to avoid busy wait */ | 202 | if (errno == EPIPE) return IO_CLOSED; |
199 | if (errno != EPIPE) { | 203 | tv.tv_sec = timeout / 1000; |
200 | struct timeval tv; | 204 | tv.tv_usec = (timeout % 1000) * 1000; |
201 | fd_set fds; | 205 | FD_ZERO(&fds); |
202 | tv.tv_sec = timeout / 1000; | 206 | FD_SET(sock, &fds); |
203 | tv.tv_usec = (timeout % 1000) * 1000; | 207 | if (select(sock+1, NULL, &fds, NULL, timeout >= 0? &tv: NULL) <= 0) { |
204 | FD_ZERO(&fds); | 208 | if (errno == EINTR) return IO_RETRY; |
205 | FD_SET(sock, &fds); | ||
206 | do ret = select(sock+1, NULL, &fds, NULL, timeout >= 0? &tv: NULL); | ||
207 | while (ret < 0 && errno == EINTR); | ||
208 | /* tell the caller to call us again because there is more data */ | ||
209 | if (ret > 0) return IO_DONE; | ||
210 | /* tell the caller there was no data before timeout */ | ||
211 | else return IO_TIMEOUT; | 209 | else return IO_TIMEOUT; |
212 | /* here we know the connection has been closed */ | 210 | } else return IO_DONE; |
213 | } else return IO_CLOSED; | ||
214 | /* here we successfully sent something */ | ||
215 | } else { | 211 | } else { |
216 | *sent = put; | 212 | *sent = put; |
217 | return IO_DONE; | 213 | return IO_DONE; |
@@ -220,11 +216,6 @@ int sock_sendto(p_sock ps, const char *data, size_t count, size_t *sent, | |||
220 | 216 | ||
221 | /*-------------------------------------------------------------------------*\ | 217 | /*-------------------------------------------------------------------------*\ |
222 | * Receive with timeout | 218 | * Receive with timeout |
223 | * Here we exchanged the order of the calls to write and select | ||
224 | * The idea is that the outer loop (whoever is calling sock_send) | ||
225 | * will call the function again if we didn't time out, so we can | ||
226 | * call write and then select only if it fails. | ||
227 | * Should speed things up! | ||
228 | \*-------------------------------------------------------------------------*/ | 219 | \*-------------------------------------------------------------------------*/ |
229 | int sock_recv(p_sock ps, char *data, size_t count, size_t *got, int timeout) | 220 | int sock_recv(p_sock ps, char *data, size_t count, size_t *got, int timeout) |
230 | { | 221 | { |
@@ -232,7 +223,7 @@ int sock_recv(p_sock ps, char *data, size_t count, size_t *got, int timeout) | |||
232 | ssize_t taken; | 223 | ssize_t taken; |
233 | if (sock == SOCK_INVALID) return IO_CLOSED; | 224 | if (sock == SOCK_INVALID) return IO_CLOSED; |
234 | do taken = read(sock, data, count); | 225 | do taken = read(sock, data, count); |
235 | while (taken <= 0 && errno == EINTR); | 226 | while (taken < 0 && errno == EINTR); |
236 | if (taken <= 0) { | 227 | if (taken <= 0) { |
237 | struct timeval tv; | 228 | struct timeval tv; |
238 | fd_set fds; | 229 | fd_set fds; |
@@ -243,10 +234,10 @@ int sock_recv(p_sock ps, char *data, size_t count, size_t *got, int timeout) | |||
243 | tv.tv_usec = (timeout % 1000) * 1000; | 234 | tv.tv_usec = (timeout % 1000) * 1000; |
244 | FD_ZERO(&fds); | 235 | FD_ZERO(&fds); |
245 | FD_SET(sock, &fds); | 236 | FD_SET(sock, &fds); |
246 | do ret = select(sock+1, &fds, NULL, NULL, timeout >= 0 ? &tv : NULL); | 237 | ret = select(sock+1, &fds, NULL, NULL, timeout >= 0 ? &tv : NULL); |
247 | while (ret < 0 && errno == EINTR); | 238 | if (ret < 0 && errno == EINTR) return IO_RETRY; |
248 | if (ret > 0) return IO_DONE; | 239 | if (ret == 0) return IO_TIMEOUT; |
249 | else return IO_TIMEOUT; | 240 | else return IO_DONE; |
250 | } else { | 241 | } else { |
251 | *got = taken; | 242 | *got = taken; |
252 | return IO_DONE; | 243 | return IO_DONE; |
@@ -263,7 +254,7 @@ int sock_recvfrom(p_sock ps, char *data, size_t count, size_t *got, | |||
263 | ssize_t taken; | 254 | ssize_t taken; |
264 | if (sock == SOCK_INVALID) return IO_CLOSED; | 255 | if (sock == SOCK_INVALID) return IO_CLOSED; |
265 | do taken = recvfrom(sock, data, count, 0, addr, addr_len); | 256 | do taken = recvfrom(sock, data, count, 0, addr, addr_len); |
266 | while (taken <= 0 && errno == EINTR); | 257 | while (taken < 0 && errno == EINTR); |
267 | if (taken <= 0) { | 258 | if (taken <= 0) { |
268 | struct timeval tv; | 259 | struct timeval tv; |
269 | fd_set fds; | 260 | fd_set fds; |
@@ -274,10 +265,10 @@ int sock_recvfrom(p_sock ps, char *data, size_t count, size_t *got, | |||
274 | tv.tv_usec = (timeout % 1000) * 1000; | 265 | tv.tv_usec = (timeout % 1000) * 1000; |
275 | FD_ZERO(&fds); | 266 | FD_ZERO(&fds); |
276 | FD_SET(sock, &fds); | 267 | FD_SET(sock, &fds); |
277 | do ret = select(sock+1, &fds, NULL, NULL, timeout >= 0 ? &tv : NULL); | 268 | ret = select(sock+1, &fds, NULL, NULL, timeout >= 0 ? &tv : NULL); |
278 | while (ret < 0 && errno == EINTR); | 269 | if (ret < 0 && errno == EINTR) return IO_RETRY; |
279 | if (ret > 0) return IO_DONE; | 270 | if (ret == 0) return IO_TIMEOUT; |
280 | else return IO_TIMEOUT; | 271 | else return IO_DONE; |
281 | } else { | 272 | } else { |
282 | *got = taken; | 273 | *got = taken; |
283 | return IO_DONE; | 274 | return IO_DONE; |
diff --git a/test/httptest.lua b/test/httptest.lua index 9d9fa25..d3a4dc0 100644 --- a/test/httptest.lua +++ b/test/httptest.lua | |||
@@ -314,9 +314,10 @@ body = socket.http.get { | |||
314 | check(body == index) | 314 | check(body == index) |
315 | 315 | ||
316 | io.write("testing HEAD method: ") | 316 | io.write("testing HEAD method: ") |
317 | socket.http.TIMEOUT = 1 | ||
317 | response = socket.http.request { | 318 | response = socket.http.request { |
318 | method = "HEAD", | 319 | method = "HEAD", |
319 | url = "http://www.tecgraf.puc-rio.br/~diego/" | 320 | url = "http://www.cs.princeton.edu/~diego/" |
320 | } | 321 | } |
321 | check(response and response.headers) | 322 | check(response and response.headers) |
322 | 323 | ||
diff --git a/test/testclnt.lua b/test/testclnt.lua index 6b07dca..3dea831 100644 --- a/test/testclnt.lua +++ b/test/testclnt.lua | |||
@@ -359,6 +359,7 @@ test_methods(socket.tcp(), { | |||
359 | "getsockname", | 359 | "getsockname", |
360 | "setoption", | 360 | "setoption", |
361 | "settimeout", | 361 | "settimeout", |
362 | "shutdown", | ||
362 | "close", | 363 | "close", |
363 | }) | 364 | }) |
364 | test_methods(socket.udp(), { | 365 | test_methods(socket.udp(), { |
@@ -372,6 +373,7 @@ test_methods(socket.udp(), { | |||
372 | "receivefrom", | 373 | "receivefrom", |
373 | "setoption", | 374 | "setoption", |
374 | "settimeout", | 375 | "settimeout", |
376 | "shutdown", | ||
375 | "close", | 377 | "close", |
376 | }) | 378 | }) |
377 | 379 | ||
@@ -484,6 +486,4 @@ test_blockingtimeoutreceive(800091, 3, 2) | |||
484 | test_blockingtimeoutreceive(800091, 3, 1) | 486 | test_blockingtimeoutreceive(800091, 3, 1) |
485 | ]] | 487 | ]] |
486 | 488 | ||
487 | socket.done() | ||
488 | |||
489 | test(string.format("done in %.2fs", socket.time() - start)) | 489 | test(string.format("done in %.2fs", socket.time() - start)) |