diff --git a/luasocket.vcproj b/luasocket.vcproj index f6ae497..9424810 100644 --- a/luasocket.vcproj +++ b/luasocket.vcproj @@ -139,6 +139,9 @@ + + diff --git a/src/options.c b/src/options.c index 32a98d6..972844f 100644 --- a/src/options.c +++ b/src/options.c @@ -3,6 +3,7 @@ #include "auxiliar.h" #include "options.h" +#include "inet.h" static int opt_setmembership(lua_State *L, p_sock ps, int level, int name); static int opt_setboolean(lua_State *L, p_sock ps, int level, int name); diff --git a/src/usocket.c b/src/usocket.c index 54f203b..5afa1bf 100644 --- a/src/usocket.c +++ b/src/usocket.c @@ -140,7 +140,7 @@ int sock_accept(p_sock ps, p_sock pa, SA *addr, socklen_t *addr_len, p_tm tm) { t_sock sock = *ps; SA dummy_addr; - socklen_t dummy_len; + socklen_t dummy_len = sizeof(dummy_addr); if (sock == SOCK_INVALID) return IO_CLOSED; if (!addr) addr = &dummy_addr; if (!addr_len) addr_len = &dummy_len; diff --git a/src/wsocket.c b/src/wsocket.c index 5ea2e56..f834503 100644 --- a/src/wsocket.c +++ b/src/wsocket.c @@ -15,6 +15,10 @@ #include "socket.h" +static const char *sock_createstrerror(void); +static const char *sock_bindstrerror(void); +static const char *sock_connectstrerror(void); + /*-------------------------------------------------------------------------*\ * Initializes module \*-------------------------------------------------------------------------*/ @@ -53,63 +57,64 @@ void sock_shutdown(p_sock ps, int how) /*-------------------------------------------------------------------------*\ * Creates and sets up a socket \*-------------------------------------------------------------------------*/ -int sock_create(p_sock ps, int domain, int type, int protocol) +const char *sock_create(p_sock ps, int domain, int type, int protocol) { int val = 1; t_sock sock = socket(domain, type, protocol); - if (sock == SOCK_INVALID) return IO_ERROR; + if (sock == SOCK_INVALID) return sock_createstrerror(); *ps = sock; sock_setnonblocking(ps); setsockopt(*ps, SOL_SOCKET, SO_REUSEADDR, (char *) &val, sizeof(val)); - return IO_DONE; + return NULL; } /*-------------------------------------------------------------------------*\ * Connects or returns error message \*-------------------------------------------------------------------------*/ -int sock_connect(p_sock ps, SA *addr, socklen_t addr_len, int timeout) +const char *sock_connect(p_sock ps, SA *addr, socklen_t addr_len, p_tm tm) { t_sock sock = *ps; - if (sock == SOCK_INVALID) return IO_CLOSED; - /* if connect fails, we have to find out why */ - if (connect(sock, addr, addr_len) < 0) { - int err; - struct timeval tv; - fd_set efds, wfds; - /* make sure the system is trying to connect */ - if (WSAGetLastError() != WSAEWOULDBLOCK) return IO_ERROR; - tv.tv_sec = timeout / 1000; - tv.tv_usec = (timeout % 1000) * 1000; - FD_ZERO(&wfds); FD_SET(sock, &wfds); - FD_ZERO(&efds); FD_SET(sock, &efds); - /* we run select to avoid busy waiting */ - err = select(0, NULL, &wfds, &efds, timeout >= 0? &tv: NULL); - /* if select returned due to an event */ - if (err > 0 ) { - /* the sets tell whether it was a sucess or failure */ - if (FD_ISSET(sock,&efds) || !FD_ISSET(sock,&wfds)) { - int why; - int len = sizeof(why); - /* find out why it failed */ - getsockopt(sock, SOL_SOCKET, SO_ERROR, (char *)&why, &len); - WSASetLastError(why); - return IO_ERROR; - } else return IO_DONE; + int err, timeout = tm_getretry(tm); + struct timeval tv; + fd_set efds, wfds; + /* don't call on closed socket */ + if (sock == SOCK_INVALID) return io_strerror(IO_CLOSED); + /* ask system to connect */ + err = connect(sock, addr, addr_len); + /* if no error, we're done */ + if (err == 0) return NULL; + /* make sure the system is trying to connect */ + if (WSAGetLastError() != WSAEWOULDBLOCK) return sock_connectstrerror(); + /* wait for a timeout or for the system's answer */ + tv.tv_sec = timeout / 1000; + tv.tv_usec = (timeout % 1000) * 1000; + FD_ZERO(&wfds); FD_SET(sock, &wfds); + FD_ZERO(&efds); FD_SET(sock, &efds); + /* we run select to wait */ + err = select(0, NULL, &wfds, &efds, timeout >= 0? &tv: NULL); + /* if select returned due to an event */ + if (err > 0 ) { + /* if was in efds, we failed */ + if (FD_ISSET(sock,&efds) || !FD_ISSET(sock,&wfds)) { + int why; + int len = sizeof(why); + /* find out why we failed */ + getsockopt(sock, SOL_SOCKET, SO_ERROR, (char *)&why, &len); + WSASetLastError(why); + return sock_connectstrerror(); + /* if was in wfds, we succeeded */ + } else return NULL; /* if nothing happened, we timed out */ - } else if (err == 0) return IO_TIMEOUT; - /* otherwise, I don't know what happened */ - else return IO_ERROR; - /* otherwise, it worked */ - } else return IO_DONE; + } else return io_strerror(IO_TIMEOUT); } /*-------------------------------------------------------------------------*\ * Binds or returns error message \*-------------------------------------------------------------------------*/ -int sock_bind(p_sock ps, SA *addr, socklen_t addr_len) +const char *sock_bind(p_sock ps, SA *addr, socklen_t addr_len) { - if (bind(*ps, addr, addr_len) < 0) return IO_ERROR; - else return IO_DONE; + if (bind(*ps, addr, addr_len) < 0) return sock_bindstrerror(); + else return NULL; } /*-------------------------------------------------------------------------*\ @@ -123,27 +128,29 @@ void sock_listen(p_sock ps, int backlog) /*-------------------------------------------------------------------------*\ * Accept with timeout \*-------------------------------------------------------------------------*/ -int sock_accept(p_sock ps, p_sock pa, SA *addr, socklen_t *addr_len, - int timeout) +int sock_accept(p_sock ps, p_sock pa, SA *addr, socklen_t *addr_len, p_tm tm) { t_sock sock = *ps; - struct timeval tv; SA dummy_addr; - socklen_t dummy_len; - fd_set fds; + socklen_t dummy_len = sizeof(dummy_addr); 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(0, &fds, NULL, NULL, timeout >= 0 ? &tv : NULL) <= 0) - return IO_TIMEOUT; if (!addr) addr = &dummy_addr; if (!addr_len) addr_len = &dummy_len; - *pa = accept(sock, addr, addr_len); - if (*pa == SOCK_INVALID) return IO_ERROR; - else return IO_DONE; + for (;;) { + int timeout = tm_getretry(tm); + struct timeval tv; + fd_set fds; + *pa = accept(sock, addr, addr_len); + if (*pa != SOCK_INVALID) return IO_DONE; + if (timeout == 0) return IO_TIMEOUT; + tv.tv_sec = timeout / 1000; + tv.tv_usec = (timeout % 1000) * 1000; + FD_ZERO(&fds); + FD_SET(sock, &fds); + /* call select just to avoid busy-wait. */ + select(0, &fds, NULL, NULL, timeout >= 0? &tv: NULL); + } + return IO_TIMEOUT; /* can't get here */ } /*-------------------------------------------------------------------------*\ @@ -313,7 +320,7 @@ const char *sock_hoststrerror(void) } } -const char *sock_createstrerror(void) +static const char *sock_createstrerror(void) { switch (WSAGetLastError()) { case WSANOTINITIALISED: return "not initialized"; @@ -324,7 +331,7 @@ const char *sock_createstrerror(void) } } -const char *sock_bindstrerror(void) +static const char *sock_bindstrerror(void) { switch (WSAGetLastError()) { case WSANOTINITIALISED: return "not initialized"; @@ -338,7 +345,7 @@ const char *sock_bindstrerror(void) } } -const char *sock_connectstrerror(void) +static const char *sock_connectstrerror(void) { switch (WSAGetLastError()) { case WSANOTINITIALISED: return "not initialized"; diff --git a/test/testclnt.lua b/test/testclnt.lua index a0d9fda..6dccd0c 100644 --- a/test/testclnt.lua +++ b/test/testclnt.lua @@ -132,6 +132,7 @@ end ------------------------------------------------------------------------ function test_asciiline(len) + reconnect() local str, str10, back, err str = string.rep("x", math.mod(len, 10)) str10 = string.rep("aZb.c#dAe?", math.floor(len/10)) @@ -149,6 +150,7 @@ end ------------------------------------------------------------------------ function test_rawline(len) + reconnect() local str, str10, back, err str = string.rep(string.char(47), math.mod(len, 10)) str10 = string.rep(string.char(120,21,77,4,5,0,7,36,44,100), @@ -167,6 +169,7 @@ end ------------------------------------------------------------------------ function test_raw(len) + reconnect() local half = math.floor(len/2) local s1, s2, back, err s1 = string.rep("x", half) @@ -186,8 +189,8 @@ end ------------------------------------------------------------------------ function test_totaltimeoutreceive(len, tm, sl) - local str, err, total reconnect() + local str, err, total pass("%d bytes, %ds total timeout, %ds pause", len, tm, sl) remote (string.format ([[ data:settimeout(%d) @@ -206,8 +209,8 @@ end ------------------------------------------------------------------------ function test_totaltimeoutsend(len, tm, sl) - local str, err, total reconnect() + local str, err, total pass("%d bytes, %ds total timeout, %ds pause", len, tm, sl) remote (string.format ([[ data:settimeout(%d) @@ -226,8 +229,8 @@ end ------------------------------------------------------------------------ function test_blockingtimeoutreceive(len, tm, sl) - local str, err, total reconnect() + local str, err, total pass("%d bytes, %ds blocking timeout, %ds pause", len, tm, sl) remote (string.format ([[ data:settimeout(%d) @@ -246,8 +249,8 @@ end ------------------------------------------------------------------------ function test_blockingtimeoutsend(len, tm, sl) - local str, err, total reconnect() + local str, err, total pass("%d bytes, %ds blocking timeout, %ds pause", len, tm, sl) remote (string.format ([[ data:settimeout(%d) @@ -266,11 +269,14 @@ end ------------------------------------------------------------------------ function empty_connect() + reconnect() if data then data:close() data = nil end +print("before remote") remote [[ if data then data:close() data = nil end data = server:accept() ]] +print("after remote") data, err = socket.connect("", port) if not data then pass("ok") @@ -445,7 +451,6 @@ test("connect with timeout (if it hangs, it failed:)") connect_timeout() test("mixed patterns") -reconnect() test_mixed(1) test_mixed(17) test_mixed(200) @@ -457,7 +462,6 @@ test_mixed(17) test_mixed(1) test("character line") -reconnect() test_asciiline(1) test_asciiline(17) test_asciiline(200) diff --git a/test/testsrvr.lua b/test/testsrvr.lua index 6010789..99b54e5 100644 --- a/test/testsrvr.lua +++ b/test/testsrvr.lua @@ -6,7 +6,8 @@ if not server then print("server: " .. tostring(error)) os.exit() end ack = "\n" while 1 do print("server: waiting for client connection..."); - control = server:accept() + control, error = server:accept() + assert(control, error) -- control:setoption("nodelay", true) while 1 do command, error = control:receive()