diff --git a/FIX b/FIX index 10a96b0..9d50a66 100644 --- a/FIX +++ b/FIX @@ -1,2 +1,9 @@ tcp{client}:shutdown() was checking for group instead of class. tcp{client}:send() now returns i+sent-1... +get rid of a = socket.try() in the manual, except for protected cases. + replace it with assert. +get rid of "base." kludge +check all "require("http")" etc in the manual. +make sure sock_gethostname.* only return success if the hp is not null! +change 'l' prefix in C libraries to 'l-something'... + don't forget the declarations in luasocket.h and mime.h!!! diff --git a/TODO b/TODO index 7b74fe2..19c9319 100644 --- a/TODO +++ b/TODO @@ -1,6 +1,7 @@ -get rid of a = socket.try() in the manual, except for protected cases. - replace it with assert. +BUG NO SET DO TINYIRC!!! SINISTRO. +talk about the non-blocking connect in the manual +test it on Windows!!! think about a dispatcher. - it creates a server and receives a function that will do the work on @@ -13,17 +14,9 @@ functions for non-blocking so they can be used in the context of the dispatcher! adjust manual for new sock:send returns. -check all "require("http")" etc in the manual. _VERSION, _DEBUG, etc. -get rid of "base." kludge -make sure sock_gethostname.* only return success if the hp is not -null! -change 'l' prefix in C libraries to 'l-something'... - don't forget the declarations in luasocket.h and mime.h!!! -leave code for losers that don't have nanosleep -"foo.bar.baz" previously had to provide luaopen_foobarbaz() and now -should use luaopen_foo_bar_baz(). Change compat-5.1 and LuaSocket? +leave code for losers that don't have nanosleep ftp.send/recv return bytes transfered? new scheme to choose family/protocol of object to create @@ -47,27 +40,4 @@ testar os options! - proteger ou atomizar o conjunto (timedout, receive), (timedout, send) - inet_ntoa também é uma merda. -*eliminate globals from namespaces created by module(). -*make sure standard libraries are "required" by modules before use. -*use wim's filter.chain or something better -*close wasn't returning 1 -*make sure errors not thrown by try() are not caught by protect() -*move wsocket.c:sock_send kludge to buffer.c:sendraw? -*bug on UDP sendto. -*fix PROXY in http.lua -*use new distribution scheme -*create the getstats method. -*fix local domain socket kludge of name size -*use TLS -*sort out the wrap around of gettime... - *use doubles all over - *sock_send, sock_recv & sock_select use p_tm instead of timeout - *make select interrupt safe (will be with tm stuff) - *use GetSystemTimeAsFileTime in windows (WinCE will suffer document) -*add getstats to the manual -*Fazer compilar com g++ -*test associativity of socket.select -* fix manual for send and receive -* add thanks to mike -* change sock:send to use indices just like string.sub? -* change sendraw to send by chunks +eliminate globals from namespaces created by module(). diff --git a/doc/ftp.html b/doc/ftp.html index 454d417..7860c27 100644 --- a/doc/ftp.html +++ b/doc/ftp.html @@ -65,7 +65,7 @@ To obtain the ftp namespace, run:
-- loads the FTP module and any libraries it requires -local ftp = require("ftp") +local ftp = require("socket.ftp")
@@ -150,7 +150,7 @@ error.
-- load the ftp support -local ftp = require("ftp") +local ftp = require("socket.ftp") -- Log as user "anonymous" on server "ftp.tecgraf.puc-rio.br", -- and get file "lua.tar.gz" from directory "pub/lua" as binary. @@ -159,9 +159,9 @@ f, e = ftp.get("ftp://ftp.tecgraf.puc-rio.br/pub/lua/lua.tar.gz;type=i")-- load needed modules -local ftp = require("ftp") +local ftp = require("socket.ftp") local ltn12 = require("ltn12") -local url = require("url") +local url = require("socket.url") -- a function that returns a directory listing function nlst(u) @@ -230,7 +230,7 @@ message describing the reason for failure.-- load the ftp support -local ftp = require("ftp") +local ftp = require("socket.ftp") -- Log as user "fulano" on server "ftp.example.com", -- using password "silva", and store a file "README" with contents @@ -241,7 +241,7 @@ f, e = ftp.put("ftp://fulano:silva@ftp.example.com/README",-- load the ftp support -local ftp = require("ftp") +local ftp = require("socket.ftp") local ltn12 = require("ltn12") -- Log as user "fulano" on server "ftp.example.com", diff --git a/doc/http.html b/doc/http.html index 4cbbe95..af58571 100644 --- a/doc/http.html +++ b/doc/http.html @@ -62,7 +62,7 @@ To obtain the http namespace, run:-- loads the HTTP module and any libraries it requires -local http = require("http") +local http = require("socket.http")@@ -206,7 +206,7 @@ Here are a few examples with the simple interface:
-- load the http module -http = require("http") +http = require("socket.http") -- connect to server "www.tecgraf.puc-rio.br" and retrieves this manual -- file from "/luasocket/http.html" @@ -231,7 +231,7 @@ And here is an example using the generic interface:-- load the http module -http = require("http") +http = require("socket.http") -- Requests information about a document, without downloading it. -- Useful, for example, if you want to display a download gauge and need @@ -276,7 +276,7 @@ authentication is required.-- load required modules -http = require("http") +http = require("socket.http") mime = require("mime") -- Connect to server "www.example.com" and tries to retrieve diff --git a/doc/introduction.html b/doc/introduction.html index f8fe078..c88fa40 100644 --- a/doc/introduction.html +++ b/doc/introduction.html @@ -182,7 +182,7 @@ program. -- load namespace local socket = require("socket") -- create a TCP socket and bind it to the local host, at any port -local server = socket.try(socket.bind("*", 0)) +local server = assert(socket.bind("*", 0)) -- find out which port the OS chose for us local ip, port = server:getsockname() -- print a message informing what's up @@ -287,13 +287,13 @@ local host, port = "localhost", 13 -- load namespace local socket = require("socket") -- convert host name to ip address -local ip = socket.try(socket.dns.toip(host)) +local ip = assert(socket.dns.toip(host)) -- create a new UDP object -local udp = socket.try(socket.udp()) +local udp = assert(socket.udp()) -- contact daytime host -socket.try(udp:sendto("anything", ip, port)) +assert(udp:sendto("anything", ip, port)) -- retrieve the answer and print results -io.write(socket.try((udp:receive()))) +io.write(assert(udp:receive()))diff --git a/doc/ltn12.html b/doc/ltn12.html index 44fcbe4..c5a0f59 100644 --- a/doc/ltn12.html +++ b/doc/ltn12.html @@ -271,7 +271,7 @@ The function returns the sink and the table used to store the chunks.-- load needed modules -local http = require("http") +local http = require("socket.http") local ltn12 = require("ltn12") -- a simplified http.get function diff --git a/doc/smtp.html b/doc/smtp.html index 8feae3e..bd18bfa 100644 --- a/doc/smtp.html +++ b/doc/smtp.html @@ -69,7 +69,7 @@ To obtain the smtp namespace, run:-- loads the SMTP module and everything it requires -local smtp = require("smtp") +local smtp = require("socket.smtp")@@ -239,7 +239,7 @@ and
-- load the smtp support -local smtp = require("smtp") +local smtp = require("socket.smtp") -- Connects to server "localhost" and sends a message to users -- "fulano@example.com", "beltrano@example.com", @@ -329,7 +329,7 @@ as listed in the introduction.-- load the smtp support and its friends -local smtp = require("smtp") +local smtp = require("socket.smtp") local mime = require("mime") local ltn12 = require("ltn12") diff --git a/doc/socket.html b/doc/socket.html index f638fd9..18c71d1 100644 --- a/doc/socket.html +++ b/doc/socket.html @@ -145,7 +145,10 @@ socket.protect(func)-Converts a function that throws exceptions into a safe function. +Converts a function that throws exceptions into a safe function. This +function only catches exceptions thrown by the try +and newtry functions. It does not catch normal +Lua errors.
@@ -346,7 +349,9 @@ socket.try(ret1 [, ret2 ... retN])
-Throws an exception in case of error. +Throws an exception in case of error. The exception can only be caught +by the protect function. It does not explode +into an error message.
diff --git a/doc/url.html b/doc/url.html index 56e1ef5..ac84d24 100644 --- a/doc/url.html +++ b/doc/url.html @@ -52,7 +52,7 @@ To obtain the url namespace, run:
-- loads the URL module -local url = require("url") +local url = require("socket.url")@@ -193,7 +193,7 @@ The function returns the encoded string.
-- load url module -url = require("url") +url = require("socket.url") code = url.escape("/#?;") -- code = "%2f%23%3f%3b" @@ -239,7 +239,7 @@ parsed_url = {
-- load url module -url = require("url") +url = require("socket.url") parsed_url = url.parse("http://www.example.com/cgilua/index.lua?a=2#there") -- parsed_url = { diff --git a/src/buffer.c b/src/buffer.c index 0ec7b4d..45cd0f2 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -123,7 +123,7 @@ int buf_meth_receive(lua_State *L, p_buf buf) { else if (p[0] == '*' && p[1] == 'a') err = recvall(buf, &b); else luaL_argcheck(L, 0, 2, "invalid receive pattern"); /* get a fixed number of bytes */ - } else err = recvraw(buf, (size_t) lua_tonumber(L, 2), &b); + } else err = recvraw(buf, (size_t) lua_tonumber(L, 2)-size, &b); /* check if there was an error */ if (err != IO_DONE) { /* we can't push anyting in the stack before pushing the diff --git a/src/inet.c b/src/inet.c index e2afcdf..d713643 100644 --- a/src/inet.c +++ b/src/inet.c @@ -220,7 +220,6 @@ const char *inet_tryconnect(p_sock ps, const char *address, } } else remote.sin_family = AF_UNSPEC; err = sock_connect(ps, (SA *) &remote, sizeof(remote), tm); - if (err != IO_DONE) sock_destroy(ps); return sock_strerror(err); } diff --git a/src/luasocket.c b/src/luasocket.c index 4b829f8..8f13dbc 100644 --- a/src/luasocket.c +++ b/src/luasocket.c @@ -87,7 +87,7 @@ static int global_unload(lua_State *L) { static int base_open(lua_State *L) { if (sock_open()) { /* export functions (and leave namespace table on top of stack) */ - luaL_module(L, "socket", func, 0); + luaL_openlib(L, "socket", func, 0); #ifdef LUASOCKET_DEBUG lua_pushstring(L, "DEBUG"); lua_pushboolean(L, 1); @@ -108,7 +108,7 @@ static int base_open(lua_State *L) { /*-------------------------------------------------------------------------*\ * Initializes all library modules. \*-------------------------------------------------------------------------*/ -LUASOCKET_API int luaopen_lsocket(lua_State *L) { +LUASOCKET_API int luaopen_csocket(lua_State *L) { int i; base_open(L); for (i = 0; mod[i].name; i++) mod[i].func(L); diff --git a/src/luasocket.h b/src/luasocket.h index db54a18..768e335 100644 --- a/src/luasocket.h +++ b/src/luasocket.h @@ -13,7 +13,7 @@ /*-------------------------------------------------------------------------*\ * Current luasocket version \*-------------------------------------------------------------------------*/ -#define LUASOCKET_VERSION "LuaSocket 2.0 (beta3)" +#define LUASOCKET_VERSION "LuaSocket 2.0" #define LUASOCKET_COPYRIGHT "Copyright (C) 2004-2005 Diego Nehab" #define LUASOCKET_AUTHORS "Diego Nehab" @@ -27,6 +27,6 @@ /*-------------------------------------------------------------------------*\ * Initializes the library. \*-------------------------------------------------------------------------*/ -LUASOCKET_API int luaopen_socket(lua_State *L); +LUASOCKET_API int luaopen_csocket(lua_State *L); #endif /* LUASOCKET_H */ diff --git a/src/mime.c b/src/mime.c index dcc4af3..67f9f5b 100644 --- a/src/mime.c +++ b/src/mime.c @@ -78,9 +78,9 @@ static UC b64unbase[256]; /*-------------------------------------------------------------------------*\ * Initializes module \*-------------------------------------------------------------------------*/ -MIME_API int luaopen_lmime(lua_State *L) +MIME_API int luaopen_cmime(lua_State *L) { - luaL_module(L, "mime", func, 0); + luaL_openlib(L, "mime", func, 0); /* initialize lookup tables */ qpsetup(qpclass, qpunbase); b64setup(b64unbase); diff --git a/src/mime.h b/src/mime.h index 688d043..d596861 100644 --- a/src/mime.h +++ b/src/mime.h @@ -19,6 +19,6 @@ #define MIME_API extern #endif -MIME_API int luaopen_mime(lua_State *L); +MIME_API int luaopen_cmime(lua_State *L); #endif /* MIME_H */ diff --git a/src/mime.lua b/src/mime.lua index 4d5bdba..6492a96 100644 --- a/src/mime.lua +++ b/src/mime.lua @@ -8,9 +8,10 @@ ----------------------------------------------------------------------------- -- Declare module and import dependencies ----------------------------------------------------------------------------- +package.loaded.base = _G local base = require("base") local ltn12 = require("ltn12") -local mime = require("lmime") +local mime = require("cmime") module("mime") -- encode, decode and wrap algorithm tables diff --git a/src/socket.h b/src/socket.h index 368c2b6..639229d 100644 --- a/src/socket.h +++ b/src/socket.h @@ -45,11 +45,15 @@ int sock_sendto(p_sock ps, const char *data, size_t count, size_t *sent, SA *addr, socklen_t addr_len, p_tm tm); int sock_recvfrom(p_sock ps, char *data, size_t count, size_t *got, SA *addr, socklen_t *addr_len, p_tm tm); + void sock_setnonblocking(p_sock ps); void sock_setblocking(p_sock ps); + +int sock_waitfd(int fd, int sw, p_tm tm); int sock_select(int n, fd_set *rfds, fd_set *wfds, fd_set *efds, p_tm tm); int sock_connect(p_sock ps, SA *addr, socklen_t addr_len, p_tm tm); +int sock_connected(p_sock ps, p_tm tm); int sock_create(p_sock ps, int domain, int type, int protocol); int sock_bind(p_sock ps, SA *addr, socklen_t addr_len); int sock_listen(p_sock ps, int backlog); diff --git a/src/socket.lua b/src/socket.lua index 1c82750..f3563e7 100644 --- a/src/socket.lua +++ b/src/socket.lua @@ -7,10 +7,11 @@ ----------------------------------------------------------------------------- -- Declare module and import dependencies ----------------------------------------------------------------------------- +package.loaded.base = _G local base = require("base") local string = require("string") local math = require("math") -local socket = require("lsocket") +local socket = require("csocket") module("socket") ----------------------------------------------------------------------------- diff --git a/src/tcp.c b/src/tcp.c index 0b3706b..3a84191 100644 --- a/src/tcp.c +++ b/src/tcp.c @@ -20,6 +20,7 @@ \*=========================================================================*/ static int global_create(lua_State *L); static int meth_connect(lua_State *L); +static int meth_connected(lua_State *L); static int meth_listen(lua_State *L); static int meth_bind(lua_State *L); static int meth_send(lua_State *L); @@ -45,6 +46,7 @@ static luaL_reg tcp[] = { {"bind", meth_bind}, {"close", meth_close}, {"connect", meth_connect}, + {"connected", meth_connected}, {"dirty", meth_dirty}, {"getfd", meth_getfd}, {"getpeername", meth_getpeername}, @@ -113,12 +115,12 @@ static int meth_receive(lua_State *L) { } static int meth_getstats(lua_State *L) { - p_tcp tcp = (p_tcp) aux_checkgroup(L, "tcp{any}", 1); + p_tcp tcp = (p_tcp) aux_checkclass(L, "tcp{client}", 1); return buf_meth_getstats(L, &tcp->buf); } static int meth_setstats(lua_State *L) { - p_tcp tcp = (p_tcp) aux_checkgroup(L, "tcp{any}", 1); + p_tcp tcp = (p_tcp) aux_checkclass(L, "tcp{client}", 1); return buf_meth_setstats(L, &tcp->buf); } @@ -224,6 +226,22 @@ static int meth_connect(lua_State *L) return 1; } +static int meth_connected(lua_State *L) +{ + static t_tm tm = {-1, -1}; + p_tcp tcp = (p_tcp) aux_checkclass(L, "tcp{master}", 1); + int err = sock_connected(&tcp->sock, &tm); + if (err != IO_DONE) { + lua_pushnil(L); + lua_pushstring(L, sock_strerror(err)); + return 2; + } + /* turn master object into a client object */ + aux_setclass(L, "tcp{client}", 1); + lua_pushnumber(L, 1); + return 1; +} + /*-------------------------------------------------------------------------*\ * Closes socket used by object \*-------------------------------------------------------------------------*/ diff --git a/src/unix.c b/src/unix.c index 1e0e252..c169268 100644 --- a/src/unix.c +++ b/src/unix.c @@ -32,6 +32,8 @@ static int meth_settimeout(lua_State *L); static int meth_getfd(lua_State *L); static int meth_setfd(lua_State *L); static int meth_dirty(lua_State *L); +static int meth_getstats(lua_State *L); +static int meth_setstats(lua_State *L); static const char *unix_tryconnect(p_unix un, const char *path); static const char *unix_trybind(p_unix un, const char *path); @@ -46,6 +48,8 @@ static luaL_reg un[] = { {"connect", meth_connect}, {"dirty", meth_dirty}, {"getfd", meth_getfd}, + {"getstats", meth_getstats}, + {"setstats", meth_setstats}, {"listen", meth_listen}, {"receive", meth_receive}, {"send", meth_send}, @@ -75,7 +79,7 @@ static luaL_reg func[] = { /*-------------------------------------------------------------------------*\ * Initializes module \*-------------------------------------------------------------------------*/ -int unix_open(lua_State *L) { +int luaopen_socketunix(lua_State *L) { /* create classes */ aux_newclass(L, "unix{master}", un); aux_newclass(L, "unix{client}", un); @@ -84,11 +88,9 @@ int unix_open(lua_State *L) { aux_add2group(L, "unix{master}", "unix{any}"); aux_add2group(L, "unix{client}", "unix{any}"); aux_add2group(L, "unix{server}", "unix{any}"); - aux_add2group(L, "unix{client}", "unix{client,server}"); - aux_add2group(L, "unix{server}", "unix{client,server}"); /* define library functions */ - luaL_openlib(L, NULL, func, 0); - return 0; + luaL_openlib(L, "socket", func, 0); + return 1; } /*=========================================================================*\ @@ -107,6 +109,16 @@ static int meth_receive(lua_State *L) { return buf_meth_receive(L, &un->buf); } +static int meth_getstats(lua_State *L) { + p_unix un = (p_unix) aux_checkclass(L, "unix{client}", 1); + return buf_meth_getstats(L, &un->buf); +} + +static int meth_setstats(lua_State *L) { + p_unix un = (p_unix) aux_checkclass(L, "unix{client}", 1); + return buf_meth_setstats(L, &un->buf); +} + /*-------------------------------------------------------------------------*\ * Just call option handler \*-------------------------------------------------------------------------*/ @@ -250,7 +262,8 @@ static int meth_close(lua_State *L) { p_unix un = (p_unix) aux_checkgroup(L, "unix{any}", 1); sock_destroy(&un->sock); - return 0; + lua_pushnumber(L, 1); + return 1; } /*-------------------------------------------------------------------------*\ @@ -277,7 +290,7 @@ static int meth_listen(lua_State *L) \*-------------------------------------------------------------------------*/ static int meth_shutdown(lua_State *L) { - p_unix un = (p_unix) aux_checkgroup(L, "unix{client}", 1); + p_unix un = (p_unix) aux_checkclass(L, "unix{client}", 1); const char *how = luaL_optstring(L, 2, "both"); switch (how[0]) { case 'b': diff --git a/src/unix.h b/src/unix.h index 7b2a5c5..aaaef3d 100644 --- a/src/unix.h +++ b/src/unix.h @@ -23,6 +23,6 @@ typedef struct t_unix_ { } t_unix; typedef t_unix *p_unix; -int unix_open(lua_State *L); +int luaopen_socketunix(lua_State *L); #endif /* UNIX_H */ diff --git a/src/usocket.c b/src/usocket.c index c1ab725..3428a0c 100644 --- a/src/usocket.c +++ b/src/usocket.c @@ -22,7 +22,7 @@ #define WAITFD_R POLLIN #define WAITFD_W POLLOUT #define WAITFD_C (POLLIN|POLLOUT) -static int sock_waitfd(int fd, int sw, p_tm tm) { +int sock_waitfd(int fd, int sw, p_tm tm) { int ret; struct pollfd pfd; pfd.fd = fd; @@ -44,7 +44,7 @@ static int sock_waitfd(int fd, int sw, p_tm tm) { #define WAITFD_W 2 #define WAITFD_C (WAITFD_R|WAITFD_W) -static int sock_waitfd(int fd, int sw, p_tm tm) { +int sock_waitfd(int fd, int sw, p_tm tm) { int ret; fd_set rfds, wfds, *rp, *wp; struct timeval tv, *tp; @@ -166,12 +166,20 @@ int sock_connect(p_sock ps, SA *addr, socklen_t len, p_tm tm) { while ((err = errno) == EINTR); /* if connection failed immediately, return error code */ if (err != EINPROGRESS && err != EAGAIN) return err; + /* zero timeout case optimization */ + if (tm_iszero(tm)) return IO_TIMEOUT; /* wait until we have the result of the connection attempt or timeout */ - if ((err = sock_waitfd(*ps, WAITFD_C, tm)) == IO_CLOSED) { - /* finaly find out if we succeeded connecting */ + return sock_connected(ps, tm); +} + +/*-------------------------------------------------------------------------*\ +* Checks if socket is connected, or return reason for failure +\*-------------------------------------------------------------------------*/ +int sock_connected(p_sock ps, p_tm tm) { + int err; + if ((err = sock_waitfd(*ps, WAITFD_C, tm) == IO_CLOSED)) { if (recv(*ps, (char *) &err, 0, 0) == 0) return IO_DONE; else return errno; - /* timed out or some weirder error */ } else return err; } @@ -321,13 +329,17 @@ void sock_setnonblocking(p_sock ps) { int sock_gethostbyaddr(const char *addr, socklen_t len, struct hostent **hp) { *hp = gethostbyaddr(addr, len, AF_INET); if (*hp) return IO_DONE; - else return h_errno; + else if (h_errno) return h_errno; + else if (errno) return errno; + else return IO_UNKNOWN; } int sock_gethostbyname(const char *addr, struct hostent **hp) { *hp = gethostbyname(addr); if (*hp) return IO_DONE; - else return h_errno; + else if (h_errno) return h_errno; + else if (errno) return errno; + else return IO_UNKNOWN; } /*-------------------------------------------------------------------------*\ diff --git a/src/wsocket.c b/src/wsocket.c index 69fac4d..c0686cd 100644 --- a/src/wsocket.c +++ b/src/wsocket.c @@ -45,7 +45,7 @@ int sock_close(void) { #define WAITFD_E 4 #define WAITFD_C (WAITFD_E|WAITFD_W) -static int sock_waitfd(t_sock fd, int sw, p_tm tm) { +int sock_waitfd(t_sock fd, int sw, p_tm tm) { int ret; fd_set rfds, wfds, efds, *rp = NULL, *wp = NULL, *ep = NULL; struct timeval tv, *tp = NULL; @@ -118,7 +118,17 @@ int sock_connect(p_sock ps, SA *addr, socklen_t len, p_tm tm) { /* make sure the system is trying to connect */ err = WSAGetLastError(); if (err != WSAEWOULDBLOCK && err != WSAEINPROGRESS) return err; + /* zero timeout case optimization */ + if (tm_iszero(tm)) return IO_TIMEOUT; /* we wait until something happens */ + return sock_connected(ps, tm); +} + +/*-------------------------------------------------------------------------*\ +* Check if socket is connected +\*-------------------------------------------------------------------------*/ +int sock_connected(p_sock ps) { + int err; if ((err = sock_waitfd(*ps, WAITFD_C, tm)) == IO_CLOSED) { int len = sizeof(err); /* give windows time to set the error (yes, disgusting) */ @@ -126,9 +136,8 @@ int sock_connect(p_sock ps, SA *addr, socklen_t len, p_tm tm) { /* find out why we failed */ getsockopt(*ps, SOL_SOCKET, SO_ERROR, (char *)&err, &len); /* we KNOW there was an error. if why is 0, we will return - * "unknown error", but it's not really our fault */ + * "unknown error", but it's not really our fault */ return err > 0? err: IO_UNKNOWN; - /* here we deal with the case in which it worked, timedout or weird errors */ } else return err; } diff --git a/test/dicttest.lua b/test/dicttest.lua index a37ec8d..7ac7811 100644 --- a/test/dicttest.lua +++ b/test/dicttest.lua @@ -1,3 +1,3 @@ local dict = require"socket.dict" -for i,v in dict.get("dict://dell-diego/d:banana") do print(v) end +for i,v in dict.get("dict://localhost/d:teste") do print(v) end diff --git a/test/httptest.lua b/test/httptest.lua index 8862ceb..2335fcb 100644 --- a/test/httptest.lua +++ b/test/httptest.lua @@ -23,7 +23,7 @@ http.TIMEOUT = 10 local t = socket.gettime() host = host or "diego.student.princeton.edu" -proxy = proxy or "http://dell-diego:3128" +proxy = proxy or "http://localhost:3128" prefix = prefix or "/luasocket-test" cgiprefix = cgiprefix or "/luasocket-test-cgi" index_file = "test/index.html" diff --git a/test/testclnt.lua b/test/testclnt.lua index c2c782c..e3f2b94 100644 --- a/test/testclnt.lua +++ b/test/testclnt.lua @@ -465,16 +465,14 @@ print("Testing " .. 2*size .. " bytes") remote(string.format([[ data:send(string.rep("a", %d)) socket.sleep(0.5) - data:send(string.rep("b", %d)) + data:send(string.rep("b", %d) .. "\n") ]], size, size)) local err = "timeout" local part = "" local str data:settimeout(0) while 1 do - local needed = 2*size - string.len(part) - assert(needed > 0, "weird") - str, err, part = data:receive(needed, part) + str, err, part = data:receive("*l", part) if err ~= "timeout" then break end end assert(str == (string.rep("a", size) .. string.rep("b", size))) @@ -482,15 +480,14 @@ remote(string.format([[ remote(string.format([[ str = data:receive(%d) socket.sleep(0.5) - str = data:receive(%d, str) + str = data:receive(2*%d, str) data:send(str) ]], size, size)) data:settimeout(0) - local sofar = 1 + local start = 0 while 1 do - _, err, part = data:send(str, sofar) + ret, err, start = data:send(str, start+1) if err ~= "timeout" then break end - sofar = sofar + part end data:send("\n") data:settimeout(-1) @@ -501,6 +498,7 @@ end ------------------------------------------------------------------------ + test("method registration") test_methods(socket.tcp(), { "accept", @@ -622,7 +620,7 @@ test_nonblocking(17) test_nonblocking(200) test_nonblocking(4091) test_nonblocking(80199) -test_nonblocking(8000000) +test_nonblocking(800000) test_nonblocking(80199) test_nonblocking(4091) test_nonblocking(200) diff --git a/test/testsrvr.lua b/test/testsrvr.lua index 2408e83..f1972c2 100644 --- a/test/testsrvr.lua +++ b/test/testsrvr.lua @@ -9,6 +9,7 @@ while 1 do while 1 do command = assert(control:receive()); assert(control:send(ack)); + print(command); (loadstring(command))(); end end diff --git a/test/utestclnt.lua b/test/utestclnt.lua new file mode 100644 index 0000000..f002c6e --- /dev/null +++ b/test/utestclnt.lua @@ -0,0 +1,644 @@ +require"socket" +local socket = require"socket.unix" + +host = "luasocket" + +function pass(...) + local s = string.format(unpack(arg)) + io.stderr:write(s, "\n") +end + +function fail(...) + local s = string.format(unpack(arg)) + io.stderr:write("ERROR: ", s, "!\n") +socket.sleep(3) + os.exit() +end + +function warn(...) + local s = string.format(unpack(arg)) + io.stderr:write("WARNING: ", s, "\n") +end + +function remote(...) + local s = string.format(unpack(arg)) + s = string.gsub(s, "\n", ";") + s = string.gsub(s, "%s+", " ") + s = string.gsub(s, "^%s*", "") + control:send(s .. "\n") + control:receive() +end + +function test(test) + io.stderr:write("----------------------------------------------\n", + "testing: ", test, "\n", + "----------------------------------------------\n") +end + +function uconnect(path) + local u = assert(socket.unix()) + assert(u:connect(path)) + return u +end + +function ubind(path) + local u = assert(socket.unix()) + assert(u:bind(path)) + assert(u:listen(5)) + return u +end + +function check_timeout(tm, sl, elapsed, err, opp, mode, alldone) + if tm < sl then + if opp == "send" then + if not err then warn("must be buffered") + elseif err == "timeout" then pass("proper timeout") + else fail("unexpected error '%s'", err) end + else + if err ~= "timeout" then fail("should have timed out") + else pass("proper timeout") end + end + else + if mode == "total" then + if elapsed > tm then + if err ~= "timeout" then fail("should have timed out") + else pass("proper timeout") end + elseif elapsed < tm then + if err then fail(err) + else pass("ok") end + else + if alldone then + if err then fail("unexpected error '%s'", err) + else pass("ok") end + else + if err ~= "timeout" then fail(err) + else pass("proper timeoutk") end + end + end + else + if err then fail(err) + else pass("ok") end + end + end +end + +if not socket.DEBUG then + fail("Please define LUASOCKET_DEBUG and recompile LuaSocket") +end + +io.stderr:write("----------------------------------------------\n", +"LuaSocket Test Procedures\n", +"----------------------------------------------\n") + +start = socket.gettime() + +function reconnect() + io.stderr:write("attempting data connection... ") + if data then data:close() end + remote [[ + i = i or 1 + if data then data:close() data = nil end + print("accepting") + data = server:accept() + i = i + 1 + print("done " .. i) + ]] + data, err = uconnect(host, port) + if not data then fail(err) + else pass("connected!") end +end + +pass("attempting control connection...") +control, err = uconnect(host, port) +if err then fail(err) +else pass("connected!") end + +------------------------------------------------------------------------ +function test_methods(sock, methods) + for _, v in methods do + if type(sock[v]) ~= "function" then + fail(sock.class .. " method '" .. v .. "' not registered") + end + end + pass(sock.class .. " methods are ok") +end + +------------------------------------------------------------------------ +function test_mixed(len) + reconnect() + local inter = math.ceil(len/4) + local p1 = "unix " .. string.rep("x", inter) .. "line\n" + local p2 = "dos " .. string.rep("y", inter) .. "line\r\n" + local p3 = "raw " .. string.rep("z", inter) .. "bytes" + local p4 = "end" .. string.rep("w", inter) .. "bytes" + local bp1, bp2, bp3, bp4 +remote (string.format("str = data:receive(%d)", + string.len(p1)+string.len(p2)+string.len(p3)+string.len(p4))) + sent, err = data:send(p1..p2..p3..p4) + if err then fail(err) end +remote "data:send(str); data:close()" + bp1, err = data:receive() + if err then fail(err) end + bp2, err = data:receive() + if err then fail(err) end + bp3, err = data:receive(string.len(p3)) + if err then fail(err) end + bp4, err = data:receive("*a") + if err then fail(err) end + if bp1.."\n" == p1 and bp2.."\r\n" == p2 and bp3 == p3 and bp4 == p4 then + pass("patterns match") + else fail("patterns don't match") end +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)) + str = str .. str10 +remote "str = data:receive()" + sent, err = data:send(str.."\n") + if err then fail(err) end +remote "data:send(str ..'\\n')" + back, err = data:receive() + if err then fail(err) end + if back == str then pass("lines match") + else fail("lines don't match") end +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), + math.floor(len/10)) + str = str .. str10 +remote "str = data:receive()" + sent, err = data:send(str.."\n") + if err then fail(err) end +remote "data:send(str..'\\n')" + back, err = data:receive() + if err then fail(err) end + if back == str then pass("lines match") + else fail("lines don't match") end +end + +------------------------------------------------------------------------ +function test_raw(len) + reconnect() + local half = math.floor(len/2) + local s1, s2, back, err + s1 = string.rep("x", half) + s2 = string.rep("y", len-half) +remote (string.format("str = data:receive(%d)", len)) + sent, err = data:send(s1) + if err then fail(err) end + sent, err = data:send(s2) + if err then fail(err) end +remote "data:send(str)" + back, err = data:receive(len) + if err then fail(err) end + if back == s1..s2 then pass("blocks match") + else fail("blocks don't match") end +end + +------------------------------------------------------------------------ +function test_totaltimeoutreceive(len, tm, sl) + reconnect() + local str, err, partial + pass("%d bytes, %ds total timeout, %ds pause", len, tm, sl) + remote (string.format ([[ + data:settimeout(%d) + str = string.rep('a', %d) + data:send(str) + print('server: sleeping for %ds') + socket.sleep(%d) + print('server: woke up') + data:send(str) + ]], 2*tm, len, sl, sl)) + data:settimeout(tm, "total") +local t = socket.gettime() + str, err, partial, elapsed = data:receive(2*len) + check_timeout(tm, sl, elapsed, err, "receive", "total", + string.len(str or partial) == 2*len) +end + +------------------------------------------------------------------------ +function test_totaltimeoutsend(len, tm, sl) + reconnect() + local str, err, total + pass("%d bytes, %ds total timeout, %ds pause", len, tm, sl) + remote (string.format ([[ + data:settimeout(%d) + str = data:receive(%d) + print('server: sleeping for %ds') + socket.sleep(%d) + print('server: woke up') + str = data:receive(%d) + ]], 2*tm, len, sl, sl, len)) + data:settimeout(tm, "total") + str = string.rep("a", 2*len) + total, err, partial, elapsed = data:send(str) + check_timeout(tm, sl, elapsed, err, "send", "total", + total == 2*len) +end + +------------------------------------------------------------------------ +function test_blockingtimeoutreceive(len, tm, sl) + reconnect() + local str, err, partial + pass("%d bytes, %ds blocking timeout, %ds pause", len, tm, sl) + remote (string.format ([[ + data:settimeout(%d) + str = string.rep('a', %d) + data:send(str) + print('server: sleeping for %ds') + socket.sleep(%d) + print('server: woke up') + data:send(str) + ]], 2*tm, len, sl, sl)) + data:settimeout(tm) + str, err, partial, elapsed = data:receive(2*len) + check_timeout(tm, sl, elapsed, err, "receive", "blocking", + string.len(str or partial) == 2*len) +end + +------------------------------------------------------------------------ +function test_blockingtimeoutsend(len, tm, sl) + reconnect() + local str, err, total + pass("%d bytes, %ds blocking timeout, %ds pause", len, tm, sl) + remote (string.format ([[ + data:settimeout(%d) + str = data:receive(%d) + print('server: sleeping for %ds') + socket.sleep(%d) + print('server: woke up') + str = data:receive(%d) + ]], 2*tm, len, sl, sl, len)) + data:settimeout(tm) + str = string.rep("a", 2*len) + total, err, partial, elapsed = data:send(str) + check_timeout(tm, sl, elapsed, err, "send", "blocking", + total == 2*len) +end + +------------------------------------------------------------------------ +function empty_connect() + reconnect() + if data then data:close() data = nil end + remote [[ + if data then data:close() data = nil end + data = server:accept() + ]] + data, err = socket.connect("", port) + if not data then + pass("ok") + data = socket.connect(host, port) + else + pass("gethostbyname returns localhost on empty string...") + end +end + +------------------------------------------------------------------------ +function isclosed(c) + return c:getfd() == -1 or c:getfd() == (2^32-1) +end + +function active_close() + reconnect() + if isclosed(data) then fail("should not be closed") end + data:close() + if not isclosed(data) then fail("should be closed") end + data = nil + local udp = socket.udp() + if isclosed(udp) then fail("should not be closed") end + udp:close() + if not isclosed(udp) then fail("should be closed") end + pass("ok") +end + +------------------------------------------------------------------------ +function test_closed() + local back, partial, err + local str = 'little string' + reconnect() + pass("trying read detection") + remote (string.format ([[ + data:send('%s') + data:close() + data = nil + ]], str)) + -- try to get a line + back, err, partial = data:receive() + if not err then fail("should have gotten 'closed'.") + elseif err ~= "closed" then fail("got '"..err.."' instead of 'closed'.") + elseif str ~= partial then fail("didn't receive partial result.") + else pass("graceful 'closed' received") end + reconnect() + pass("trying write detection") + remote [[ + data:close() + data = nil + ]] + total, err, partial = data:send(string.rep("ugauga", 100000)) + if not err then + pass("failed: output buffer is at least %d bytes long!", total) + elseif err ~= "closed" then + fail("got '"..err.."' instead of 'closed'.") + else + pass("graceful 'closed' received after %d bytes were sent", partial) + end +end + +------------------------------------------------------------------------ +function test_selectbugs() + local r, s, e = socket.select(nil, nil, 0.1) + assert(type(r) == "table" and type(s) == "table" and + (e == "timeout" or e == "error")) + pass("both nil: ok") + local udp = socket.udp() + udp:close() + r, s, e = socket.select({ udp }, { udp }, 0.1) + assert(type(r) == "table" and type(s) == "table" and + (e == "timeout" or e == "error")) + pass("closed sockets: ok") + e = pcall(socket.select, "wrong", 1, 0.1) + assert(e == false) + e = pcall(socket.select, {}, 1, 0.1) + assert(e == false) + pass("invalid input: ok") +end + +------------------------------------------------------------------------ +function accept_timeout() + io.stderr:write("accept with timeout (if it hangs, it failed): ") + local s, e = socket.bind("*", 0, 0) + assert(s, e) + local t = socket.gettime() + s:settimeout(1) + local c, e = s:accept() + assert(not c, "should not accept") + assert(e == "timeout", string.format("wrong error message (%s)", e)) + t = socket.gettime() - t + assert(t < 2, string.format("took to long to give up (%gs)", t)) + s:close() + pass("good") +end + +------------------------------------------------------------------------ +function connect_timeout() + io.stderr:write("connect with timeout (if it hangs, it failed!): ") + local t = socket.gettime() + local c, e = socket.tcp() + assert(c, e) + c:settimeout(0.1) + local t = socket.gettime() + local r, e = c:connect("127.0.0.2", 80) + assert(not r, "should not connect") + assert(socket.gettime() - t < 2, "took too long to give up.") + c:close() + print("ok") +end + +------------------------------------------------------------------------ +function accept_errors() + io.stderr:write("not listening: ") + local d, e = socket.bind("*", 0) + assert(d, e); + local c, e = socket.tcp(); + assert(c, e); + d:setfd(c:getfd()) + d:settimeout(2) + local r, e = d:accept() + assert(not r and e) + print("ok: ", e) + io.stderr:write("not supported: ") + local c, e = socket.udp() + assert(c, e); + d:setfd(c:getfd()) + local r, e = d:accept() + assert(not r and e) + print("ok: ", e) +end + +------------------------------------------------------------------------ +function connect_errors() + io.stderr:write("connection refused: ") + local c, e = socket.connect("localhost", 1); + assert(not c and e) + print("ok: ", e) + io.stderr:write("host not found: ") + local c, e = socket.connect("host.is.invalid", 1); + assert(not c and e, e) + print("ok: ", e) +end + +------------------------------------------------------------------------ +function rebind_test() + local c = socket.bind("localhost", 0) + local i, p = c:getsockname() + local s, e = socket.tcp() + assert(s, e) + s:setoption("reuseaddr", false) + r, e = s:bind("localhost", p) + assert(not r, "managed to rebind!") + assert(e) + print("ok: ", e) +end + +------------------------------------------------------------------------ +function getstats_test() + reconnect() + local t = 0 + for i = 1, 25 do + local c = math.random(1, 100) + remote (string.format ([[ + str = data:receive(%d) + data:send(str) + ]], c)) + data:send(string.rep("a", c)) + data:receive(c) + t = t + c + local r, s, a = data:getstats() + assert(r == t, "received count failed" .. tostring(r) + .. "/" .. tostring(t)) + assert(s == t, "sent count failed" .. tostring(s) + .. "/" .. tostring(t)) + end + print("ok") +end + + +------------------------------------------------------------------------ +function test_nonblocking(size) + reconnect() +print("Testing " .. 2*size .. " bytes") +remote(string.format([[ + data:send(string.rep("a", %d)) + socket.sleep(0.5) + data:send(string.rep("b", %d) .. "\n") +]], size, size)) + local err = "timeout" + local part = "" + local str + data:settimeout(0) + while 1 do + str, err, part = data:receive("*l", part) + if err ~= "timeout" then break end + end + assert(str == (string.rep("a", size) .. string.rep("b", size))) + reconnect() +remote(string.format([[ + str = data:receive(%d) + socket.sleep(0.5) + str = data:receive(%d, str) + data:send(str) +]], size, size)) + data:settimeout(0) + local start = 0 + while 1 do + ret, err, start = data:send(str, start+1) + if err ~= "timeout" then break end + end + data:send("\n") + data:settimeout(-1) + local back = data:receive(2*size) + assert(back == str, "'" .. back .. "' vs '" .. str .. "'") + print("ok") +end + +------------------------------------------------------------------------ + +test("method registration") +test_methods(socket.unix(), { + "accept", + "bind", + "close", + "connect", + "dirty", + "getfd", + "getstats", + "setstats", + "listen", + "receive", + "send", + "setfd", + "setoption", + "setpeername", + "setsockname", + "settimeout", + "shutdown", +}) + +test("connect function") +--connect_timeout() +--empty_connect() +--connect_errors() + +--test("rebinding: ") +--rebind_test() + +test("active close: ") +active_close() + +test("closed connection detection: ") +test_closed() + +test("accept function: ") +accept_timeout() +accept_errors() + +test("getstats test") +getstats_test() + +test("character line") +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("mixed patterns") +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("binary line") +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") +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") +test_nonblocking(1) +test_nonblocking(17) +test_nonblocking(200) +test_nonblocking(4091) +test_nonblocking(80199) +test_nonblocking(8000000) +test_nonblocking(80199) +test_nonblocking(4091) +test_nonblocking(200) +test_nonblocking(17) +test_nonblocking(1) + +test("total timeout on send") +test_totaltimeoutsend(800091, 1, 3) +test_totaltimeoutsend(800091, 2, 3) +test_totaltimeoutsend(800091, 5, 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) + +test(string.format("done in %.2fs", socket.gettime() - start)) diff --git a/test/utestsrvr.lua b/test/utestsrvr.lua new file mode 100644 index 0000000..f7be196 --- /dev/null +++ b/test/utestsrvr.lua @@ -0,0 +1,17 @@ +require("socket"); +os.remove("/tmp/luasocket") +socket = require("socket.unix"); +host = "luasocket"; +server = socket.unix() +print(server:bind(host)) +print(server:listen(5)) +ack = "\n"; +while 1 do + print("server: waiting for client connection..."); + control = assert(server:accept()); + while 1 do + command = assert(control:receive()); + assert(control:send(ack)); + (loadstring(command))(); + end +end