diff --git a/TODO b/TODO index bd8a950..5566d16 100644 --- a/TODO +++ b/TODO @@ -1,8 +1,13 @@ -change send/recv to avoid using select + + +check for interrupt compliance +add connect with timeout add gethostname and use it in HTTP, SMTP etc, and add manual entry. + add local connect, and manual entry -add shutdown, and manual entry + +add shutdown manual entry only allocate in case of success only call select if io fails... @@ -65,6 +70,8 @@ Ajeitar o protocolo da luaopen_socket()... sei l - testar os options! - adicionar exemplos de expansão: pipe, local, named pipe +* add shutdown +* change send/recv to avoid using select * O location do "redirect" pode ser relativo ao servidor atual (não pode, mas os servidores fazem merda...) * Ajeitar para Lua 5.0 diff --git a/luasocket.sln b/luasocket.sln new file mode 100644 index 0000000..25fe127 --- /dev/null +++ b/luasocket.sln @@ -0,0 +1,23 @@ +Microsoft Visual Studio Solution File, Format Version 8.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "luasocket", "luasocket.vcproj", "{4FAAB633-F0E7-4D12-B680-D150A0DD7268}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + Debug = Debug + Release = Release + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {4FAAB633-F0E7-4D12-B680-D150A0DD7268}.Debug.ActiveCfg = Debug|Win32 + {4FAAB633-F0E7-4D12-B680-D150A0DD7268}.Debug.Build.0 = Debug|Win32 + {4FAAB633-F0E7-4D12-B680-D150A0DD7268}.Release.ActiveCfg = Release|Win32 + {4FAAB633-F0E7-4D12-B680-D150A0DD7268}.Release.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionItems) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/luasocket.vcproj b/luasocket.vcproj new file mode 100644 index 0000000..b5c4d53 --- /dev/null +++ b/luasocket.vcproj @@ -0,0 +1,216 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/inet.h b/src/inet.h index 244a310..b69e82d 100644 --- a/src/inet.h +++ b/src/inet.h @@ -19,6 +19,10 @@ #include #include "socket.h" +#ifdef WIN32 +#define INET_ATON +#endif + void inet_open(lua_State *L); const char *inet_tryconnect(p_sock ps, const char *address, unsigned short port); diff --git a/src/luasocket.h b/src/luasocket.h index 7756605..ac26824 100644 --- a/src/luasocket.h +++ b/src/luasocket.h @@ -18,7 +18,9 @@ /*-------------------------------------------------------------------------*\ * Library's namespace \*-------------------------------------------------------------------------*/ +#ifndef LUASOCKET_LIBNAME #define LUASOCKET_LIBNAME "socket" +#endif /*-------------------------------------------------------------------------*\ * This macro prefixes all exported API functions diff --git a/src/tcp.c b/src/tcp.c index afa0477..a67b44a 100644 --- a/src/tcp.c +++ b/src/tcp.c @@ -36,6 +36,7 @@ static int meth_dirty(lua_State *L); static int opt_tcp_nodelay(lua_State *L); static int opt_keepalive(lua_State *L); static int opt_linger(lua_State *L); +static int opt_reuseaddr(lua_State *L); /* tcp object methods */ static luaL_reg tcp[] = { @@ -61,6 +62,7 @@ static luaL_reg tcp[] = { /* socket option handlers */ static luaL_reg opt[] = { {"keepalive", opt_keepalive}, + {"reuseaddr", opt_reuseaddr}, {"tcp-nodelay", opt_tcp_nodelay}, {"linger", opt_linger}, {NULL, NULL} @@ -123,7 +125,7 @@ static int meth_setoption(lua_State *L) static int opt_boolean(lua_State *L, int level, int name) { - p_tcp tcp = (p_tcp) aux_checkgroup(L, "tcp{client,server}", 1); + p_tcp tcp = (p_tcp) aux_checkgroup(L, "tcp{any}", 1); int val = aux_checkboolean(L, 2); if (setsockopt(tcp->sock, level, name, (char *) &val, sizeof(val)) < 0) { lua_pushnil(L); @@ -134,16 +136,16 @@ static int opt_boolean(lua_State *L, int level, int name) return 1; } +/* enables reuse of local address */ +static int opt_reuseaddr(lua_State *L) +{ + return opt_boolean(L, SOL_SOCKET, SO_REUSEADDR); +} + /* disables the Naggle algorithm */ static int opt_tcp_nodelay(lua_State *L) { - struct protoent *pe = getprotobyname("TCP"); - if (!pe) { - lua_pushnil(L); - lua_pushstring(L, "getprotobyname"); - return 2; - } - return opt_boolean(L, pe->p_proto, TCP_NODELAY); + return opt_boolean(L, IPPROTO_TCP, TCP_NODELAY); } static int opt_keepalive(lua_State *L) diff --git a/src/timeout.c b/src/timeout.c index 5d6de99..2d88ded 100644 --- a/src/timeout.c +++ b/src/timeout.c @@ -16,6 +16,7 @@ #ifdef WIN32 #include #else +#include #include #include #include diff --git a/src/udp.c b/src/udp.c index 58119cd..21730ab 100644 --- a/src/udp.c +++ b/src/udp.c @@ -35,6 +35,11 @@ static int meth_fd(lua_State *L); static int meth_dirty(lua_State *L); static int opt_dontroute(lua_State *L); static int opt_broadcast(lua_State *L); +static int opt_reuseaddr(lua_State *L); +static int opt_ip_multicast_ttl(lua_State *L); +static int opt_ip_multicast_loop(lua_State *L); +static int opt_ip_add_membership(lua_State *L); +static int opt_ip_drop_membersip(lua_State *L); /* udp object methods */ static luaL_reg udp[] = { @@ -57,8 +62,13 @@ static luaL_reg udp[] = { /* socket options */ static luaL_reg opt[] = { - {"dontroute", opt_dontroute}, - {"broadcast", opt_broadcast}, + {"dontroute", opt_dontroute}, + {"broadcast", opt_broadcast}, + {"reuseaddr", opt_reuseaddr}, + {"ip-multicast-ttl", opt_ip_multicast_ttl}, + {"ip-multicast-loop", opt_ip_multicast_loop}, + {"ip-add-membership", opt_ip_add_membership}, + {"ip-drop-membership", opt_ip_drop_membersip}, {NULL, NULL} }; @@ -244,11 +254,72 @@ static int opt_dontroute(lua_State *L) return opt_boolean(L, SOL_SOCKET, SO_DONTROUTE); } +static int opt_reuseaddr(lua_State *L) +{ + return opt_boolean(L, SOL_SOCKET, SO_REUSEADDR); +} + static int opt_broadcast(lua_State *L) { return opt_boolean(L, SOL_SOCKET, SO_BROADCAST); } +static int opt_ip_multicast_loop(lua_State *L) +{ + return opt_boolean(L, IPPROTO_IP, IP_MULTICAST_LOOP); +} + +static int opt_ip_multicast_ttl(lua_State *L) +{ + p_udp udp = (p_udp) aux_checkgroup(L, "udp{any}", 1); + int val = (int) luaL_checknumber(L, 2); + if (setsockopt(udp->sock, IPPROTO_IP, IP_MULTICAST_TTL, + (char *) &val, sizeof(val)) < 0) { + lua_pushnil(L); + lua_pushstring(L, "setsockopt failed"); + return 2; + } + lua_pushnumber(L, 1); + return 1; +} + +static int opt_membership(lua_State *L, int level, int name) +{ + p_udp udp = (p_udp) aux_checkgroup(L, "udp{any}", 1); + struct ip_mreq val; + if (!lua_istable(L, 2)) + luaL_typerror(L, 2, lua_typename(L, LUA_TTABLE)); + lua_pushstring(L, "multiaddr"); + lua_gettable(L, 2); + if (!lua_isstring(L, -1)) luaL_argerror(L, 2, "invalid 'group' field"); + if (!inet_aton(lua_tostring(L, -1), &val.imr_multiaddr)) + luaL_argerror(L, 3, "invalid 'multiaddr' ip address"); + lua_pushstring(L, "interface"); + lua_gettable(L, 2); + if (!lua_isstring(L, -1)) luaL_argerror(L, 2, "invalid 'interface' field"); + val.imr_interface.s_addr = htonl(INADDR_ANY); + if (strcmp(lua_tostring(L, -1), "*") && + !inet_aton(lua_tostring(L, -1), &val.imr_interface)) + luaL_argerror(L, 3, "invalid 'interface' ip address"); + if (setsockopt(udp->sock, level, name, (char *) &val, sizeof(val)) < 0) { + lua_pushnil(L); + lua_pushstring(L, "setsockopt failed"); + return 2; + } + lua_pushnumber(L, 1); + return 1; +} + +static int opt_ip_add_membership(lua_State *L) +{ + return opt_membership(L, IPPROTO_IP, IP_ADD_MEMBERSHIP); +} + +static int opt_ip_drop_membersip(lua_State *L) +{ + return opt_membership(L, IPPROTO_IP, IP_DROP_MEMBERSHIP); +} + /*-------------------------------------------------------------------------*\ * Just call tm methods \*-------------------------------------------------------------------------*/ diff --git a/src/usocket.c b/src/usocket.c index f2d9f01..89be85e 100644 --- a/src/usocket.c +++ b/src/usocket.c @@ -145,7 +145,7 @@ int sock_send(p_sock ps, const char *data, size_t count, size_t *sent, else return IO_TIMEOUT; /* here we know the connection has been closed */ } else return IO_CLOSED; - /* here we sent successfully sent something */ + /* here we successfully sent something */ } else { *sent = put; return IO_DONE; @@ -159,34 +159,36 @@ int sock_sendto(p_sock ps, const char *data, size_t count, size_t *sent, SA *addr, socklen_t addr_len, int timeout) { t_sock sock = *ps; - struct timeval tv; - fd_set fds; - ssize_t put = 0; - int err; + ssize_t put; int ret; + /* avoid making system calls on closed sockets */ 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); - ret = select(sock+1, NULL, &fds, NULL, timeout >= 0 ? &tv : NULL); - if (ret > 0) { - put = sendto(sock, data, count, 0, addr, addr_len); - if (put <= 0) { - err = IO_CLOSED; -#ifdef __CYGWIN__ - /* this is for CYGWIN, which is like Unix but has Win32 bugs */ - if (sent < 0 && errno == EWOULDBLOCK) err = IO_DONE; -#endif - *sent = 0; - } else { - *sent = put; - err = IO_DONE; - } - return err; - } else { + /* make sure we repeat in case the call was interrupted */ + do put = sendto(sock, data, count, 0, addr, addr_len); + while (put <= 0 && errno == EINTR); + /* deal with failure */ + if (put <= 0) { + /* in any case, nothing has been sent */ *sent = 0; - return IO_TIMEOUT; + /* run select to avoid busy wait */ + if (errno != EPIPE) { + struct timeval tv; + fd_set fds; + tv.tv_sec = timeout / 1000; + tv.tv_usec = (timeout % 1000) * 1000; + FD_ZERO(&fds); + FD_SET(sock, &fds); + ret = select(sock+1, NULL, &fds, NULL, timeout >= 0 ? &tv : NULL); + /* tell the caller to call us again because there is more data */ + if (ret > 0) return IO_DONE; + /* tell the caller there was no data before timeout */ + else return IO_TIMEOUT; + /* here we know the connection has been closed */ + } else return IO_CLOSED; + /* here we successfully sent something */ + } else { + *sent = put; + return IO_DONE; } } @@ -232,28 +234,26 @@ int sock_recvfrom(p_sock ps, char *data, size_t count, size_t *got, SA *addr, socklen_t *addr_len, int timeout) { t_sock sock = *ps; - struct timeval tv; - fd_set fds; - int ret; + ssize_t taken; if (sock == SOCK_INVALID) return IO_CLOSED; - ssize_t taken = 0; - tv.tv_sec = timeout / 1000; - tv.tv_usec = (timeout % 1000) * 1000; - FD_ZERO(&fds); - FD_SET(sock, &fds); - ret = select(sock+1, &fds, NULL, NULL, timeout >= 0 ? &tv : NULL); - if (ret > 0) { - taken = recvfrom(sock, data, count, 0, addr, addr_len); - if (taken <= 0) { - *got = 0; - return IO_CLOSED; - } else { - *got = taken; - return IO_DONE; - } - } else { + do taken = recvfrom(sock, data, count, 0, addr, addr_len); + while (taken <= 0 && errno == EINTR); + if (taken <= 0) { + struct timeval tv; + fd_set fds; + int ret; *got = 0; - return IO_TIMEOUT; + if (taken == 0) return IO_CLOSED; + tv.tv_sec = timeout / 1000; + tv.tv_usec = (timeout % 1000) * 1000; + FD_ZERO(&fds); + FD_SET(sock, &fds); + ret = select(sock+1, &fds, NULL, NULL, timeout >= 0 ? &tv : NULL); + if (ret > 0) return IO_DONE; + else return IO_TIMEOUT; + } else { + *got = taken; + return IO_DONE; } } diff --git a/src/wsocket.c b/src/wsocket.c index 59d88df..30208b9 100644 --- a/src/wsocket.c +++ b/src/wsocket.c @@ -100,7 +100,7 @@ int sock_accept(p_sock ps, p_sock pa, SA *addr, socklen_t *addr_len, FD_ZERO(&fds); FD_SET(sock, &fds); *pa = SOCK_INVALID; - if (select(sock+1, &fds, NULL, NULL, timeout >= 0 ? &tv : NULL) <= 0) + 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; @@ -116,34 +116,35 @@ int sock_send(p_sock ps, const char *data, size_t count, size_t *sent, int timeout) { t_sock sock = *ps; - struct timeval tv; - fd_set fds; - ssize_t put = 0; - if (sock == SOCK_INVALID) return IO_CLOSED; - int err; + ssize_t put; int ret; - tv.tv_sec = timeout / 1000; - tv.tv_usec = (timeout % 1000) * 1000; - FD_ZERO(&fds); - FD_SET(sock, &fds); - ret = select(sock+1, NULL, &fds, NULL, timeout >= 0 ? &tv : NULL); - if (ret > 0) { - put = send(sock, data, count, 0); - if (put <= 0) { - /* a bug in WinSock forces us to do a busy wait until we manage - ** to write, because select returns immediately even though it - ** should have blocked us until we could write... */ - if (WSAGetLastError() == WSAEWOULDBLOCK) err = IO_DONE; - else err = IO_CLOSED; - *sent = 0; - } else { - *sent = put; - err = IO_DONE; - } - return err; - } else { + /* avoid making system calls on closed sockets */ + if (sock == SOCK_INVALID) return IO_CLOSED; + /* try to send something */ + put = send(sock, data, (int) count, 0); + /* deal with failure */ + if (put <= 0) { + /* in any case, nothing has been sent */ *sent = 0; - return IO_TIMEOUT; + /* run select to avoid busy wait */ + if (WSAGetLastError() == WSAEWOULDBLOCK) { + struct timeval tv; + fd_set fds; + tv.tv_sec = timeout / 1000; + tv.tv_usec = (timeout % 1000) * 1000; + FD_ZERO(&fds); + FD_SET(sock, &fds); + ret = select(0, NULL, &fds, NULL, timeout >= 0 ? &tv : NULL); + /* tell the caller to call us again because there is more data */ + if (ret > 0) return IO_DONE; + /* tell the caller there was no data before timeout */ + else return IO_TIMEOUT; + /* here we know the connection has been closed */ + } else return IO_CLOSED; + /* here we successfully sent something */ + } else { + *sent = put; + return IO_DONE; } } @@ -154,34 +155,35 @@ int sock_sendto(p_sock ps, const char *data, size_t count, size_t *sent, SA *addr, socklen_t addr_len, int timeout) { t_sock sock = *ps; - struct timeval tv; - fd_set fds; - ssize_t put = 0; - int err; + ssize_t put; int ret; + /* avoid making system calls on closed sockets */ 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); - ret = select(sock+1, NULL, &fds, NULL, timeout >= 0 ? &tv : NULL); - if (ret > 0) { - put = sendto(sock, data, count, 0, addr, addr_len); - if (put <= 0) { - /* a bug in WinSock forces us to do a busy wait until we manage - ** to write, because select returns immediately even though it - ** should have blocked us until we could write... */ - if (WSAGetLastError() == WSAEWOULDBLOCK) err = IO_DONE; - else err = IO_CLOSED; - *sent = 0; - } else { - *sent = put; - err = IO_DONE; - } - return err; - } else { + /* try to send something */ + put = sendto(sock, data, (int) count, 0, addr, addr_len); + /* deal with failure */ + if (put <= 0) { + /* in any case, nothing has been sent */ *sent = 0; - return IO_TIMEOUT; + /* run select to avoid busy wait */ + if (WSAGetLastError() == WSAEWOULDBLOCK) { + struct timeval tv; + fd_set fds; + tv.tv_sec = timeout / 1000; + tv.tv_usec = (timeout % 1000) * 1000; + FD_ZERO(&fds); + FD_SET(sock, &fds); + ret = select(0, NULL, &fds, NULL, timeout >= 0 ? &tv : NULL); + /* tell the caller to call us again because there is more data */ + if (ret > 0) return IO_DONE; + /* tell the caller there was no data before timeout */ + else return IO_TIMEOUT; + /* here we know the connection has been closed */ + } else return IO_CLOSED; + /* here we successfully sent something */ + } else { + *sent = put; + return IO_DONE; } } @@ -191,28 +193,25 @@ int sock_sendto(p_sock ps, const char *data, size_t count, size_t *sent, int sock_recv(p_sock ps, char *data, size_t count, size_t *got, int timeout) { t_sock sock = *ps; - struct timeval tv; - fd_set fds; - int ret; - ssize_t taken = 0; + ssize_t taken; 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); - ret = select(sock+1, &fds, NULL, NULL, timeout >= 0 ? &tv : NULL); - if (ret > 0) { - taken = recv(sock, data, count, 0); - if (taken <= 0) { - *got = 0; - return IO_CLOSED; - } else { - *got = taken; - return IO_DONE; - } - } else { + taken = recv(sock, data, (int) count, 0); + if (taken <= 0) { + struct timeval tv; + fd_set fds; + int ret; *got = 0; - return IO_TIMEOUT; + if (taken == 0) return IO_CLOSED; + tv.tv_sec = timeout / 1000; + tv.tv_usec = (timeout % 1000) * 1000; + FD_ZERO(&fds); + FD_SET(sock, &fds); + ret = select(0, &fds, NULL, NULL, timeout >= 0 ? &tv : NULL); + if (ret > 0) return IO_DONE; + else return IO_TIMEOUT; + } else { + *got = taken; + return IO_DONE; } } @@ -223,28 +222,25 @@ int sock_recvfrom(p_sock ps, char *data, size_t count, size_t *got, SA *addr, socklen_t *addr_len, int timeout) { t_sock sock = *ps; - struct timeval tv; - fd_set fds; - int ret; - ssize_t taken = 0; + ssize_t taken; 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); - ret = select(sock+1, &fds, NULL, NULL, timeout >= 0 ? &tv : NULL); - if (ret > 0) { - taken = recvfrom(sock, data, count, 0, addr, addr_len); - if (taken <= 0) { - *got = 0; - return IO_CLOSED; - } else { - *got = taken; - return IO_DONE; - } - } else { + taken = recvfrom(sock, data, (int) count, 0, addr, addr_len); + if (taken <= 0) { + struct timeval tv; + fd_set fds; + int ret; *got = 0; - return IO_TIMEOUT; + if (taken == 0) return IO_CLOSED; + tv.tv_sec = timeout / 1000; + tv.tv_usec = (timeout % 1000) * 1000; + FD_ZERO(&fds); + FD_SET(sock, &fds); + ret = select(0, &fds, NULL, NULL, timeout >= 0 ? &tv : NULL); + if (ret > 0) return IO_DONE; + else return IO_TIMEOUT; + } else { + *got = taken; + return IO_DONE; } } diff --git a/test/testclnt.lua b/test/testclnt.lua index 2420711..6b07dca 100644 --- a/test/testclnt.lua +++ b/test/testclnt.lua @@ -99,8 +99,6 @@ else pass("connected!") end control:setoption("tcp-nodelay", true) ------------------------------------------------------------------------ -test("method registration") - function test_methods(sock, methods) for _, v in methods do if type(sock[v]) ~= "function" then @@ -110,38 +108,7 @@ function test_methods(sock, methods) pass(sock.class .. " methods are ok") end -test_methods(socket.tcp(), { - "connect", - "send", - "receive", - "bind", - "accept", - "setpeername", - "setsockname", - "getpeername", - "getsockname", - "setoption", - "settimeout", - "close", -}) - -test_methods(socket.udp(), { - "getpeername", - "getsockname", - "setsockname", - "setpeername", - "send", - "sendto", - "receive", - "receivefrom", - "setoption", - "settimeout", - "close", -}) - ------------------------------------------------------------------------ -test("mixed patterns") - function test_mixed(len) reconnect() local inter = math.ceil(len/4) @@ -163,21 +130,7 @@ remote "data:send(str); data:close()" else fail("patterns don't match") end end - -test_mixed(1) -test_mixed(17) -test_mixed(200) -test_mixed(4091) -test_mixed(80199) -test_mixed(4091) -test_mixed(200) -test_mixed(17) -test_mixed(1) - ------------------------------------------------------------------------ -test("character line") -reconnect() - function test_asciiline(len) local str, str10, back, err str = string.rep("x", math.mod(len, 10)) @@ -194,22 +147,7 @@ remote "data:send(str, '\\n')" else fail("lines don't match") end end -test_asciiline(1) -test_asciiline(17) -test_asciiline(200) -test_asciiline(4091) -test_asciiline(80199) -test_asciiline(800000) -test_asciiline(80199) -test_asciiline(4091) -test_asciiline(200) -test_asciiline(17) -test_asciiline(1) - ------------------------------------------------------------------------ -test("binary line") -reconnect() - function test_rawline(len) local str, str10, back, err str = string.rep(string.char(47), math.mod(len, 10)) @@ -227,22 +165,7 @@ remote "data:send(str, '\\n')" else fail("lines don't match") end end -test_rawline(1) -test_rawline(17) -test_rawline(200) -test_rawline(4091) -test_rawline(80199) -test_rawline(800000) -test_rawline(80199) -test_rawline(4091) -test_rawline(200) -test_rawline(17) -test_rawline(1) - ------------------------------------------------------------------------ -test("raw transfer") -reconnect() - function test_raw(len) local half = math.floor(len/2) local s1, s2, back, err @@ -261,38 +184,7 @@ remote "data:send(str)" else fail("blocks don't match") end end -test_raw(1) -test_raw(17) -test_raw(200) -test_raw(4091) -test_raw(80199) -test_raw(800000) -test_raw(80199) -test_raw(4091) -test_raw(200) -test_raw(17) -test_raw(1) ------------------------------------------------------------------------ -test("non-blocking transfer") -reconnect() - --- the value is not important, we only want --- to test non-blockin I/O anyways -data:settimeout(200) -test_raw(1) -test_raw(17) -test_raw(200) -test_raw(4091) -test_raw(80199) -test_raw(800000) -test_raw(80199) -test_raw(4091) -test_raw(200) -test_raw(17) -test_raw(1) - ------------------------------------------------------------------------- -test("total timeout on receive") function test_totaltimeoutreceive(len, tm, sl) local str, err, total reconnect() @@ -311,13 +203,8 @@ function test_totaltimeoutreceive(len, tm, sl) check_timeout(tm, sl, elapsed, err, "receive", "total", string.len(str) == 2*len) end -test_totaltimeoutreceive(800091, 1, 3) -test_totaltimeoutreceive(800091, 2, 3) -test_totaltimeoutreceive(800091, 3, 2) -test_totaltimeoutreceive(800091, 3, 1) ------------------------------------------------------------------------ -test("total timeout on send") function test_totaltimeoutsend(len, tm, sl) local str, err, total reconnect() @@ -336,13 +223,8 @@ function test_totaltimeoutsend(len, tm, sl) check_timeout(tm, sl, elapsed, err, "send", "total", total == 2*len) end -test_totaltimeoutsend(800091, 1, 3) -test_totaltimeoutsend(800091, 2, 3) -test_totaltimeoutsend(800091, 3, 2) -test_totaltimeoutsend(800091, 3, 1) ------------------------------------------------------------------------ -test("blocking timeout on receive") function test_blockingtimeoutreceive(len, tm, sl) local str, err, total reconnect() @@ -361,13 +243,8 @@ function test_blockingtimeoutreceive(len, tm, sl) check_timeout(tm, sl, elapsed, err, "receive", "blocking", string.len(str) == 2*len) end -test_blockingtimeoutreceive(800091, 1, 3) -test_blockingtimeoutreceive(800091, 2, 3) -test_blockingtimeoutreceive(800091, 3, 2) -test_blockingtimeoutreceive(800091, 3, 1) ------------------------------------------------------------------------ -test("blocking timeout on send") function test_blockingtimeoutsend(len, tm, sl) local str, err, total reconnect() @@ -386,15 +263,8 @@ function test_blockingtimeoutsend(len, tm, sl) check_timeout(tm, sl, elapsed, err, "send", "blocking", total == 2*len) end -test_blockingtimeoutsend(800091, 1, 3) -test_blockingtimeoutsend(800091, 2, 3) -test_blockingtimeoutsend(800091, 3, 2) -test_blockingtimeoutsend(800091, 3, 1) ------------------------------------------------------------------------ -test("bugs") - -io.write("empty host connect: ") function empty_connect() if data then data:close() data = nil end remote [[ @@ -408,27 +278,25 @@ function empty_connect() else fail("should not have connected!") end end -empty_connect() +------------------------------------------------------------------------ +function isclosed(c) + return c:fd() == -1 or c:fd() == (2^32-1) +end --- io.write("active close: ") function active_close() reconnect() - if socket._isclosed(data) then fail("should not be closed") end + if isclosed(data) then fail("should not be closed") end data:close() - if not socket._isclosed(data) then fail("should be closed") end + if not isclosed(data) then fail("should be closed") end data = nil local udp = socket.udp() - if socket._isclosed(udp) then fail("should not be closed") end + if isclosed(udp) then fail("should not be closed") end udp:close() - if not socket._isclosed(udp) then fail("should be closed") end + if not isclosed(udp) then fail("should be closed") end pass("ok") end --- active_close() - ------------------------------------------------------------------------ -test("closed connection detection") - function test_closed() local back, err local str = 'little string' @@ -453,18 +321,15 @@ function test_closed() ]] total, err = data:send(string.rep("ugauga", 100000)) if not err then -pass("failed: output buffer is at least %d bytes long!", total) + pass("failed: output buffer is at least %d bytes long!", total) elseif err ~= "closed" then -fail("got '"..err.."' instead of 'closed'.") + fail("got '"..err.."' instead of 'closed'.") else -pass("graceful 'closed' received after %d bytes were sent", total) + pass("graceful 'closed' received after %d bytes were sent", total) end end -test_closed() - ------------------------------------------------------------------------ -test("select function") function test_selectbugs() local r, s, e = socket.select(nil, nil, 0.1) assert(type(r) == "table" and type(s) == "table" and e == "timeout") @@ -481,7 +346,144 @@ function test_selectbugs() pass("invalid input: ok") end +test("method registration") +test_methods(socket.tcp(), { + "connect", + "send", + "receive", + "bind", + "accept", + "setpeername", + "setsockname", + "getpeername", + "getsockname", + "setoption", + "settimeout", + "close", +}) +test_methods(socket.udp(), { + "getpeername", + "getsockname", + "setsockname", + "setpeername", + "send", + "sendto", + "receive", + "receivefrom", + "setoption", + "settimeout", + "close", +}) + +test("mixed patterns") +reconnect() +test_mixed(1) +test_mixed(17) +test_mixed(200) +test_mixed(4091) +test_mixed(801990) +test_mixed(4091) +test_mixed(200) +test_mixed(17) +test_mixed(1) + +test("character line") +reconnect() +test_asciiline(1) +test_asciiline(17) +test_asciiline(200) +test_asciiline(4091) +test_asciiline(80199) +test_asciiline(8000000) +test_asciiline(80199) +test_asciiline(4091) +test_asciiline(200) +test_asciiline(17) +test_asciiline(1) + +test("binary line") +reconnect() +test_rawline(1) +test_rawline(17) +test_rawline(200) +test_rawline(4091) +test_rawline(80199) +test_rawline(8000000) +test_rawline(80199) +test_rawline(4091) +test_rawline(200) +test_rawline(17) +test_rawline(1) + +test("raw transfer") +reconnect() +test_raw(1) +test_raw(17) +test_raw(200) +test_raw(4091) +test_raw(80199) +test_raw(8000000) +test_raw(80199) +test_raw(4091) +test_raw(200) +test_raw(17) +test_raw(1) + +test("non-blocking transfer") +reconnect() +-- the value is not important, we only want +-- to test non-blockin I/O anyways +data:settimeout(200) +test_raw(1) +test_raw(17) +test_raw(200) +test_raw(4091) +test_raw(80199) +test_raw(8000000) +test_raw(80199) +test_raw(4091) +test_raw(200) +test_raw(17) +test_raw(1) + +test("select function") test_selectbugs() +test("empty host connect: ") +empty_connect() + +test("active close: ") +active_close() + +test("closed connection detection: ") +test_closed() + +a = [[ +test("total timeout on send") +test_totaltimeoutsend(800091, 1, 3) +test_totaltimeoutsend(800091, 2, 3) +test_totaltimeoutsend(800091, 3, 2) +test_totaltimeoutsend(800091, 3, 1) + +test("total timeout on receive") +test_totaltimeoutreceive(800091, 1, 3) +test_totaltimeoutreceive(800091, 2, 3) +test_totaltimeoutreceive(800091, 3, 2) +test_totaltimeoutreceive(800091, 3, 1) + +test("blocking timeout on send") +test_blockingtimeoutsend(800091, 1, 3) +test_blockingtimeoutsend(800091, 2, 3) +test_blockingtimeoutsend(800091, 3, 2) +test_blockingtimeoutsend(800091, 3, 1) + +test("blocking timeout on receive") +test_blockingtimeoutreceive(800091, 1, 3) +test_blockingtimeoutreceive(800091, 2, 3) +test_blockingtimeoutreceive(800091, 3, 2) +test_blockingtimeoutreceive(800091, 3, 1) +]] + +socket.done() test(string.format("done in %.2fs", socket.time() - start))