From 3febb302ad28fd25de51cbc686739469b92d8921 Mon Sep 17 00:00:00 2001 From: Diego Nehab Date: Thu, 27 Nov 2003 00:30:54 +0000 Subject: [PATCH] Killed a few bugs found by Tomas. --- TODO | 12 ++++++++ src/buffer.c | 6 ++-- src/http.lua | 5 ++-- src/tcp.c | 22 +++++++------- src/timeout.c | 80 ++++++++++++++++++++++++++++++++------------------- src/timeout.h | 7 ++--- src/udp.c | 8 +++--- src/usocket.c | 6 ++++ src/usocket.h | 5 ---- src/wsocket.c | 6 ++++ 10 files changed, 99 insertions(+), 58 deletions(-) diff --git a/TODO b/TODO index ce3ee38..9fdb1e8 100644 --- a/TODO +++ b/TODO @@ -1,3 +1,15 @@ +replace times by getrusage + +make sure modules know if their dependencies are there. + +one thing i noticed in usocket.c is that it doesn't check for EINTR +after write(), sendto(), read(), recvfrom() etc. ? the usual trick is +to loop while you get EINTR: + + do + ret = write(...); + while(ret < 0 && errno == EINTR) + Read about diff --git a/src/buffer.c b/src/buffer.c index c860f35..04419e7 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -138,7 +138,8 @@ int sendraw(p_buf buf, const char *data, size_t count, size_t *sent) int err = IO_DONE; while (total < count && err == IO_DONE) { size_t done; - err = io->send(io->ctx, data+total, count-total, &done, tm_get(tm)); + err = io->send(io->ctx, data+total, count-total, &done, + tm_getsuccess(tm)); total += done; } *sent = total; @@ -239,7 +240,8 @@ int buf_get(p_buf buf, const char **data, size_t *count) p_tm tm = buf->tm; if (buf_isempty(buf)) { size_t got; - err = io->recv(io->ctx, buf->data, BUF_SIZE, &got, tm_get(tm)); + err = io->recv(io->ctx, buf->data, BUF_SIZE, &got, + tm_getsuccess(tm)); buf->first = 0; buf->last = got; } diff --git a/src/http.lua b/src/http.lua index 252285a..18a44b6 100644 --- a/src/http.lua +++ b/src/http.lua @@ -18,7 +18,7 @@ Public.TIMEOUT = 60 -- default port for document retrieval Public.PORT = 80 -- user agent field sent in request -Public.USERAGENT = "LuaSocket 1.5" +Public.USERAGENT = "LuaSocket 2.0" -- block size used in transfers Public.BLOCKSIZE = 8192 @@ -193,7 +193,8 @@ function Private.receivebody_bylength(sock, length, receive_cb) while length > 0 do local size = math.min(Public.BLOCKSIZE, length) local chunk, err = sock:receive(size) - if err then + -- if there was an error before we got all the data + if err and string.len(chunk) ~= length then go, uerr = receive_cb(nil, err) return uerr or err end diff --git a/src/tcp.c b/src/tcp.c index 098e29d..d68db08 100644 --- a/src/tcp.c +++ b/src/tcp.c @@ -198,21 +198,21 @@ static int meth_accept(lua_State *L) { struct sockaddr_in addr; socklen_t addr_len = sizeof(addr); + int err = IO_ERROR; p_tcp server = (p_tcp) aux_checkclass(L, "tcp{server}", 1); p_tm tm = &server->tm; p_tcp client = lua_newuserdata(L, sizeof(t_tcp)); - tm_markstart(tm); aux_setclass(L, "tcp{client}", -1); - for ( ;; ) { - sock_accept(&server->sock, &client->sock, - (SA *) &addr, &addr_len, tm_get(tm)); - if (client->sock == SOCK_INVALID) { - if (tm_get(tm) == 0) { - lua_pushnil(L); - io_pusherror(L, IO_TIMEOUT); - return 2; - } - } else break; + tm_markstart(tm); + /* loop until connection accepted or timeout happens */ + while (err != IO_DONE) { + err = sock_accept(&server->sock, &client->sock, + (SA *) &addr, &addr_len, tm_getfailure(tm)); + if (err == IO_CLOSED || (err == IO_TIMEOUT && !tm_getfailure(tm))) { + lua_pushnil(L); + io_pusherror(L, err); + return 2; + } } /* initialize remaining structure fields */ io_init(&client->io, (p_send) sock_send, (p_recv) sock_recv, &client->sock); diff --git a/src/timeout.c b/src/timeout.c index 38d1135..5d6de99 100644 --- a/src/timeout.c +++ b/src/timeout.c @@ -16,8 +16,8 @@ #ifdef WIN32 #include #else +#include #include -#include #include #endif @@ -46,40 +46,62 @@ void tm_init(p_tm tm, int block, int total) } /*-------------------------------------------------------------------------*\ -* Set and get timeout limits -\*-------------------------------------------------------------------------*/ -void tm_setblock(p_tm tm, int block) -{ tm->block = block; } -void tm_settotal(p_tm tm, int total) -{ tm->total = total; } -int tm_getblock(p_tm tm) -{ return tm->block; } -int tm_gettotal(p_tm tm) -{ return tm->total; } -int tm_getstart(p_tm tm) -{ return tm->start; } - -/*-------------------------------------------------------------------------*\ -* Determines how much time we have left for the current operation +* Determines how much time we have left for the next system call, +* if the previous call was successful * Input * tm: timeout control structure * Returns * the number of ms left or -1 if there is no time limit \*-------------------------------------------------------------------------*/ -int tm_get(p_tm tm) +int tm_getsuccess(p_tm tm) { - /* no timeout */ - if (tm->block < 0 && tm->total < 0) + if (tm->block < 0 && tm->total < 0) { return -1; - /* there is no block timeout, we use the return timeout */ - else if (tm->block < 0) - return MAX(tm->total - tm_gettime() + tm->start, 0); - /* there is no return timeout, we use the block timeout */ - else if (tm->total < 0) + } else if (tm->block < 0) { + int t = tm->total - tm_gettime() + tm->start; + return MAX(t, 0); + } else if (tm->total < 0) { return tm->block; - /* both timeouts are specified */ - else return MIN(tm->block, - MAX(tm->total - tm_gettime() + tm->start, 0)); + } else { + int t = tm->total - tm_gettime() + tm->start; + return MIN(tm->block, MAX(t, 0)); + } +} + +/*-------------------------------------------------------------------------*\ +* Returns time since start of operation +* Input +* tm: timeout control structure +* Returns +* start field of structure +\*-------------------------------------------------------------------------*/ +int tm_getstart(p_tm tm) +{ + return tm->start; +} + +/*-------------------------------------------------------------------------*\ +* Determines how much time we have left for the next system call, +* if the previous call was a failure +* Input +* tm: timeout control structure +* Returns +* the number of ms left or -1 if there is no time limit +\*-------------------------------------------------------------------------*/ +int tm_getfailure(p_tm tm) +{ + if (tm->block < 0 && tm->total < 0) { + return -1; + } else if (tm->block < 0) { + int t = tm->total - tm_gettime() + tm->start; + return MAX(t, 0); + } else if (tm->total < 0) { + int t = tm->block - tm_gettime() + tm->start; + return MAX(t, 0); + } else { + int t = tm->total - tm_gettime() + tm->start; + return MIN(tm->block, MAX(t, 0)); + } } /*-------------------------------------------------------------------------*\ @@ -131,10 +153,10 @@ int tm_meth_settimeout(lua_State *L, p_tm tm) const char *mode = luaL_optstring(L, 3, "b"); switch (*mode) { case 'b': - tm_setblock(tm, ms); + tm->block = ms; break; case 'r': case 't': - tm_settotal(tm, ms); + tm->total = ms; break; default: luaL_argcheck(L, 0, 3, "invalid timeout mode"); diff --git a/src/timeout.h b/src/timeout.h index ef2f533..17f44ea 100644 --- a/src/timeout.h +++ b/src/timeout.h @@ -18,13 +18,10 @@ typedef t_tm *p_tm; void tm_open(lua_State *L); void tm_init(p_tm tm, int block, int total); -void tm_setblock(p_tm tm, int block); -void tm_settotal(p_tm tm, int total); -int tm_getblock(p_tm tm); -int tm_gettotal(p_tm tm); +int tm_getsuccess(p_tm tm); +int tm_getfailure(p_tm tm); void tm_markstart(p_tm tm); int tm_getstart(p_tm tm); -int tm_get(p_tm tm); int tm_gettime(void); int tm_meth_settimeout(lua_State *L, p_tm tm); diff --git a/src/udp.c b/src/udp.c index 6647711..58119cd 100644 --- a/src/udp.c +++ b/src/udp.c @@ -100,7 +100,7 @@ static int meth_send(lua_State *L) int err; const char *data = luaL_checklstring(L, 2, &count); tm_markstart(tm); - err = sock_send(&udp->sock, data, count, &sent, tm_get(tm)); + err = sock_send(&udp->sock, data, count, &sent, tm_getsuccess(tm)); if (err == IO_DONE) lua_pushnumber(L, sent); else lua_pushnil(L); /* a 'closed' error on an unconnected means the target address was not @@ -129,7 +129,7 @@ static int meth_sendto(lua_State *L) addr.sin_port = htons(port); tm_markstart(tm); err = sock_sendto(&udp->sock, data, count, &sent, - (SA *) &addr, sizeof(addr), tm_get(tm)); + (SA *) &addr, sizeof(addr), tm_getsuccess(tm)); if (err == IO_DONE) lua_pushnumber(L, sent); else lua_pushnil(L); /* a 'closed' error on an unconnected means the target address was not @@ -150,7 +150,7 @@ static int meth_receive(lua_State *L) p_tm tm = &udp->tm; count = MIN(count, sizeof(buffer)); tm_markstart(tm); - err = sock_recv(&udp->sock, buffer, count, &got, tm_get(tm)); + err = sock_recv(&udp->sock, buffer, count, &got, tm_getsuccess(tm)); if (err == IO_DONE) lua_pushlstring(L, buffer, got); else lua_pushnil(L); io_pusherror(L, err); @@ -172,7 +172,7 @@ static int meth_receivefrom(lua_State *L) tm_markstart(tm); count = MIN(count, sizeof(buffer)); err = sock_recvfrom(&udp->sock, buffer, count, &got, - (SA *) &addr, &addr_len, tm_get(tm)); + (SA *) &addr, &addr_len, tm_getsuccess(tm)); if (err == IO_DONE) { lua_pushlstring(L, buffer, got); lua_pushstring(L, inet_ntoa(addr.sin_addr)); diff --git a/src/usocket.c b/src/usocket.c index 202238b..b120d7b 100644 --- a/src/usocket.c +++ b/src/usocket.c @@ -83,10 +83,12 @@ int sock_accept(p_sock ps, p_sock pa, SA *addr, socklen_t *addr_len, SA dummy_addr; socklen_t dummy_len; fd_set fds; + if (sock == SOCK_INVALID) return IO_CLOSED; tv.tv_sec = timeout / 1000; tv.tv_usec = (timeout % 1000) * 1000; FD_ZERO(&fds); FD_SET(sock, &fds); + *pa = SOCK_INVALID; if (select(sock+1, &fds, NULL, NULL, timeout >= 0 ? &tv : NULL) <= 0) return IO_TIMEOUT; if (!addr) addr = &dummy_addr; @@ -108,6 +110,7 @@ int sock_send(p_sock ps, const char *data, size_t count, size_t *sent, ssize_t put = 0; int err; int ret; + if (sock == SOCK_INVALID) return IO_CLOSED; tv.tv_sec = timeout / 1000; tv.tv_usec = (timeout % 1000) * 1000; FD_ZERO(&fds); @@ -145,6 +148,7 @@ int sock_sendto(p_sock ps, const char *data, size_t count, size_t *sent, ssize_t put = 0; int err; int ret; + if (sock == SOCK_INVALID) return IO_CLOSED; tv.tv_sec = timeout / 1000; tv.tv_usec = (timeout % 1000) * 1000; FD_ZERO(&fds); @@ -180,6 +184,7 @@ int sock_recv(p_sock ps, char *data, size_t count, size_t *got, int timeout) fd_set fds; int ret; ssize_t taken = 0; + if (sock == SOCK_INVALID) return IO_CLOSED; tv.tv_sec = timeout / 1000; tv.tv_usec = (timeout % 1000) * 1000; FD_ZERO(&fds); @@ -210,6 +215,7 @@ int sock_recvfrom(p_sock ps, char *data, size_t count, size_t *got, struct timeval tv; fd_set fds; int ret; + if (sock == SOCK_INVALID) return IO_CLOSED; ssize_t taken = 0; tv.tv_sec = timeout / 1000; tv.tv_usec = (timeout % 1000) * 1000; diff --git a/src/usocket.h b/src/usocket.h index 85b7caa..b9255cb 100644 --- a/src/usocket.h +++ b/src/usocket.h @@ -34,11 +34,6 @@ /* TCP options (nagle algorithm disable) */ #include -#ifdef __APPLE__ -/* for some reason socklen_t is not defined in Mac Os X */ -typedef int socklen_t; -#endif - typedef int t_sock; typedef t_sock *p_sock; diff --git a/src/wsocket.c b/src/wsocket.c index f9e1084..1ba28b6 100644 --- a/src/wsocket.c +++ b/src/wsocket.c @@ -86,10 +86,12 @@ int sock_accept(p_sock ps, p_sock pa, SA *addr, socklen_t *addr_len, SA dummy_addr; socklen_t dummy_len; fd_set fds; + if (sock == SOCK_INVALID) return IO_CLOSED; tv.tv_sec = timeout / 1000; tv.tv_usec = (timeout % 1000) * 1000; FD_ZERO(&fds); FD_SET(sock, &fds); + *pa = SOCK_INVALID; if (select(sock+1, &fds, NULL, NULL, timeout >= 0 ? &tv : NULL) <= 0) return IO_TIMEOUT; if (!addr) addr = &dummy_addr; @@ -109,6 +111,7 @@ int sock_send(p_sock ps, const char *data, size_t count, size_t *sent, struct timeval tv; fd_set fds; ssize_t put = 0; + if (sock == SOCK_INVALID) return IO_CLOSED; int err; int ret; tv.tv_sec = timeout / 1000; @@ -148,6 +151,7 @@ int sock_sendto(p_sock ps, const char *data, size_t count, size_t *sent, ssize_t put = 0; int err; int ret; + if (sock == SOCK_INVALID) return IO_CLOSED; tv.tv_sec = timeout / 1000; tv.tv_usec = (timeout % 1000) * 1000; FD_ZERO(&fds); @@ -183,6 +187,7 @@ int sock_recv(p_sock ps, char *data, size_t count, size_t *got, int timeout) fd_set fds; int ret; ssize_t taken = 0; + if (sock == SOCK_INVALID) return IO_CLOSED; tv.tv_sec = timeout / 1000; tv.tv_usec = (timeout % 1000) * 1000; FD_ZERO(&fds); @@ -214,6 +219,7 @@ int sock_recvfrom(p_sock ps, char *data, size_t count, size_t *got, fd_set fds; int ret; ssize_t taken = 0; + if (sock == SOCK_INVALID) return IO_CLOSED; tv.tv_sec = timeout / 1000; tv.tv_usec = (timeout % 1000) * 1000; FD_ZERO(&fds);