diff options
-rw-r--r-- | NEW | 25 | ||||
-rw-r--r-- | etc/tftp.lua | 131 | ||||
-rw-r--r-- | samples/daytimeclnt.lua | 3 | ||||
-rw-r--r-- | samples/talker.lua | 12 | ||||
-rw-r--r-- | src/auxiliar.c | 113 | ||||
-rw-r--r-- | src/auxiliar.h | 26 | ||||
-rw-r--r-- | src/buffer.c | 275 | ||||
-rw-r--r-- | src/buffer.h | 26 | ||||
-rw-r--r-- | src/ftp.lua | 57 | ||||
-rw-r--r-- | src/http.lua | 35 | ||||
-rw-r--r-- | src/inet.c | 170 | ||||
-rw-r--r-- | src/inet.h | 36 | ||||
-rw-r--r-- | src/io.c | 8 | ||||
-rw-r--r-- | src/io.h | 34 | ||||
-rw-r--r-- | src/luasocket.c | 64 | ||||
-rw-r--r-- | src/luasocket.h | 8 | ||||
-rw-r--r-- | src/mbox.lua | 20 | ||||
-rw-r--r-- | src/smtp.lua | 39 | ||||
-rw-r--r-- | src/tcp.c | 222 | ||||
-rw-r--r-- | src/tcp.h | 20 | ||||
-rw-r--r-- | src/timeout.c | 116 | ||||
-rw-r--r-- | src/timeout.h | 32 | ||||
-rw-r--r-- | src/udp.c | 404 | ||||
-rw-r--r-- | src/udp.h | 27 | ||||
-rw-r--r-- | src/usocket.c (renamed from src/unix.c) | 229 | ||||
-rw-r--r-- | src/usocket.h (renamed from src/unix.h) | 18 | ||||
-rw-r--r-- | test/ftptest.lua | 6 | ||||
-rw-r--r-- | test/httptest.lua | 15 | ||||
-rw-r--r-- | test/smtptest.lua | 10 | ||||
-rw-r--r-- | test/testclnt.lua | 372 | ||||
-rw-r--r-- | test/testsrvr.lua | 3 | ||||
-rw-r--r-- | test/tftptest.lua | 7 |
32 files changed, 1487 insertions, 1076 deletions
@@ -1,5 +1,20 @@ | |||
1 | Socket structures are independent | 1 | All functions provided by the library are in the namespace "socket". |
2 | UDPBUFFERSIZE is now internal | 2 | Functions such as send/receive/timeout/close etc do not exist in the |
3 | Better treatment of closed connections: test!!! | 3 | namespace. They are now only available as methods of the appropriate |
4 | HTTP post now deals with 1xx codes | 4 | objects. |
5 | connect, bind etc only try first address returned by resolver | 5 | |
6 | Object has been changed to become more uniform. First create an object for | ||
7 | a given domain/family and protocol. Then connect or bind if needed. Then | ||
8 | use IO functions. | ||
9 | |||
10 | All functions return a non-nil value as first return value if successful. | ||
11 | All functions return nil followed by error message in case of error. | ||
12 | WARNING: The send function was affected. | ||
13 | |||
14 | Better error messages and parameter checking. | ||
15 | |||
16 | UDP connected udp sockets can break association with peer by calling | ||
17 | setpeername with address "*". | ||
18 | |||
19 | socket.sleep and socket.time are now part of the library and are | ||
20 | supported. | ||
diff --git a/etc/tftp.lua b/etc/tftp.lua new file mode 100644 index 0000000..a0db68e --- /dev/null +++ b/etc/tftp.lua | |||
@@ -0,0 +1,131 @@ | |||
1 | ----------------------------------------------------------------------------- | ||
2 | -- TFTP support for the Lua language | ||
3 | -- LuaSocket 1.5 toolkit. | ||
4 | -- Author: Diego Nehab | ||
5 | -- Conforming to: RFC 783, LTN7 | ||
6 | -- RCS ID: $Id$ | ||
7 | ----------------------------------------------------------------------------- | ||
8 | |||
9 | local Public, Private = {}, {} | ||
10 | local socket = _G[LUASOCKET_LIBNAME] -- get LuaSocket namespace | ||
11 | socket.tftp = Public -- create tftp sub namespace | ||
12 | |||
13 | ----------------------------------------------------------------------------- | ||
14 | -- Program constants | ||
15 | ----------------------------------------------------------------------------- | ||
16 | local char = string.char | ||
17 | local byte = string.byte | ||
18 | |||
19 | Public.PORT = 69 | ||
20 | Private.OP_RRQ = 1 | ||
21 | Private.OP_WRQ = 2 | ||
22 | Private.OP_DATA = 3 | ||
23 | Private.OP_ACK = 4 | ||
24 | Private.OP_ERROR = 5 | ||
25 | Private.OP_INV = {"RRQ", "WRQ", "DATA", "ACK", "ERROR"} | ||
26 | |||
27 | ----------------------------------------------------------------------------- | ||
28 | -- Packet creation functions | ||
29 | ----------------------------------------------------------------------------- | ||
30 | function Private.RRQ(source, mode) | ||
31 | return char(0, Private.OP_RRQ) .. source .. char(0) .. mode .. char(0) | ||
32 | end | ||
33 | |||
34 | function Private.WRQ(source, mode) | ||
35 | return char(0, Private.OP_RRQ) .. source .. char(0) .. mode .. char(0) | ||
36 | end | ||
37 | |||
38 | function Private.ACK(block) | ||
39 | local low, high | ||
40 | low = math.mod(block, 256) | ||
41 | high = (block - low)/256 | ||
42 | return char(0, Private.OP_ACK, high, low) | ||
43 | end | ||
44 | |||
45 | function Private.get_OP(dgram) | ||
46 | local op = byte(dgram, 1)*256 + byte(dgram, 2) | ||
47 | return op | ||
48 | end | ||
49 | |||
50 | ----------------------------------------------------------------------------- | ||
51 | -- Packet analysis functions | ||
52 | ----------------------------------------------------------------------------- | ||
53 | function Private.split_DATA(dgram) | ||
54 | local block = byte(dgram, 3)*256 + byte(dgram, 4) | ||
55 | local data = string.sub(dgram, 5) | ||
56 | return block, data | ||
57 | end | ||
58 | |||
59 | function Private.get_ERROR(dgram) | ||
60 | local code = byte(dgram, 3)*256 + byte(dgram, 4) | ||
61 | local msg | ||
62 | _,_, msg = string.find(dgram, "(.*)\000", 5) | ||
63 | return string.format("error code %d: %s", code, msg) | ||
64 | end | ||
65 | |||
66 | ----------------------------------------------------------------------------- | ||
67 | -- Downloads and returns a file pointed to by url | ||
68 | ----------------------------------------------------------------------------- | ||
69 | function Public.get(url) | ||
70 | local parsed = socket.url.parse(url, { | ||
71 | host = "", | ||
72 | port = Public.PORT, | ||
73 | path ="/", | ||
74 | scheme = "tftp" | ||
75 | }) | ||
76 | if parsed.scheme ~= "tftp" then | ||
77 | return nil, string.format("unknown scheme '%s'", parsed.scheme) | ||
78 | end | ||
79 | local retries, dgram, sent, datahost, dataport, code | ||
80 | local cat = socket.concat.create() | ||
81 | local last = 0 | ||
82 | local udp, err = socket.udp() | ||
83 | if not udp then return nil, err end | ||
84 | -- convert from name to ip if needed | ||
85 | parsed.host = socket.toip(parsed.host) | ||
86 | udp:timeout(1) | ||
87 | -- first packet gives data host/port to be used for data transfers | ||
88 | retries = 0 | ||
89 | repeat | ||
90 | sent, err = udp:sendto(Private.RRQ(parsed.path, "octet"), | ||
91 | parsed.host, parsed.port) | ||
92 | if err then return nil, err end | ||
93 | dgram, datahost, dataport = udp:receivefrom() | ||
94 | retries = retries + 1 | ||
95 | until dgram or datahost ~= "timeout" or retries > 5 | ||
96 | if not dgram then return nil, datahost end | ||
97 | -- associate socket with data host/port | ||
98 | udp:setpeername(datahost, dataport) | ||
99 | -- process all data packets | ||
100 | while 1 do | ||
101 | -- decode packet | ||
102 | code = Private.get_OP(dgram) | ||
103 | if code == Private.OP_ERROR then | ||
104 | return nil, Private.get_ERROR(dgram) | ||
105 | end | ||
106 | if code ~= Private.OP_DATA then | ||
107 | return nil, "unhandled opcode " .. code | ||
108 | end | ||
109 | -- get data packet parts | ||
110 | local block, data = Private.split_DATA(dgram) | ||
111 | -- if not repeated, write | ||
112 | if block == last+1 then | ||
113 | cat:addstring(data) | ||
114 | last = block | ||
115 | end | ||
116 | -- last packet brings less than 512 bytes of data | ||
117 | if string.len(data) < 512 then | ||
118 | sent, err = udp:send(Private.ACK(block)) | ||
119 | return cat:getresult() | ||
120 | end | ||
121 | -- get the next packet | ||
122 | retries = 0 | ||
123 | repeat | ||
124 | sent, err = udp:send(Private.ACK(last)) | ||
125 | if err then return err end | ||
126 | dgram, err = udp:receive() | ||
127 | retries = retries + 1 | ||
128 | until dgram or err ~= "timeout" or retries > 5 | ||
129 | if not dgram then return err end | ||
130 | end | ||
131 | end | ||
diff --git a/samples/daytimeclnt.lua b/samples/daytimeclnt.lua index 000dfd5..4debc81 100644 --- a/samples/daytimeclnt.lua +++ b/samples/daytimeclnt.lua | |||
@@ -7,7 +7,8 @@ end | |||
7 | host = socket.toip(host) | 7 | host = socket.toip(host) |
8 | udp = socket.udp() | 8 | udp = socket.udp() |
9 | print("Using host '" ..host.. "' and port " ..port.. "...") | 9 | print("Using host '" ..host.. "' and port " ..port.. "...") |
10 | err = udp:sendto("anything", host, port) | 10 | udp:setpeername(host, port) |
11 | sent, err = udp:send("anything") | ||
11 | if err then print(err) exit() end | 12 | if err then print(err) exit() end |
12 | dgram, err = udp:receive() | 13 | dgram, err = udp:receive() |
13 | if not dgram then print(err) exit() end | 14 | if not dgram then print(err) exit() end |
diff --git a/samples/talker.lua b/samples/talker.lua index d66cf66..688824f 100644 --- a/samples/talker.lua +++ b/samples/talker.lua | |||
@@ -5,18 +5,18 @@ if arg then | |||
5 | port = arg[2] or port | 5 | port = arg[2] or port |
6 | end | 6 | end |
7 | print("Attempting connection to host '" ..host.. "' and port " ..port.. "...") | 7 | print("Attempting connection to host '" ..host.. "' and port " ..port.. "...") |
8 | c, e = connect(host, port) | 8 | c, e = socket.connect(host, port) |
9 | if not c then | 9 | if not c then |
10 | print(e) | 10 | print(e) |
11 | exit() | 11 | os.exit() |
12 | end | 12 | end |
13 | print("Connected! Please type stuff (empty line to stop):") | 13 | print("Connected! Please type stuff (empty line to stop):") |
14 | l = read() | 14 | l = io.read() |
15 | while l and l ~= "" and not e do | 15 | while l and l ~= "" and not e do |
16 | e = c:send(l, "\n") | 16 | t, e = c:send(l, "\n") |
17 | if e then | 17 | if e then |
18 | print(e) | 18 | print(e) |
19 | exit() | 19 | os.exit() |
20 | end | 20 | end |
21 | l = read() | 21 | l = io.read() |
22 | end | 22 | end |
diff --git a/src/auxiliar.c b/src/auxiliar.c new file mode 100644 index 0000000..5e5ba1a --- /dev/null +++ b/src/auxiliar.c | |||
@@ -0,0 +1,113 @@ | |||
1 | /*=========================================================================*\ | ||
2 | * Auxiliar routines for class hierarchy manipulation | ||
3 | * | ||
4 | * RCS ID: $Id$ | ||
5 | \*=========================================================================*/ | ||
6 | #include "aux.h" | ||
7 | |||
8 | /*=========================================================================*\ | ||
9 | * Internal function prototypes | ||
10 | \*=========================================================================*/ | ||
11 | static void *aux_getgroupudata(lua_State *L, const char *group, int objidx); | ||
12 | |||
13 | /*=========================================================================*\ | ||
14 | * Exported functions | ||
15 | \*=========================================================================*/ | ||
16 | /*-------------------------------------------------------------------------*\ | ||
17 | * Creates a new class. A class has methods given by the func array and the | ||
18 | * field 'class' tells the object class. The table 'group' list the class | ||
19 | * groups the object belongs to. | ||
20 | \*-------------------------------------------------------------------------*/ | ||
21 | void aux_newclass(lua_State *L, const char *name, luaL_reg *func) | ||
22 | { | ||
23 | luaL_newmetatable(L, name); | ||
24 | lua_pushstring(L, "__index"); | ||
25 | lua_newtable(L); | ||
26 | luaL_openlib(L, NULL, func, 0); | ||
27 | lua_pushstring(L, "class"); | ||
28 | lua_pushstring(L, name); | ||
29 | lua_settable(L, -3); | ||
30 | lua_settable(L, -3); | ||
31 | lua_pushstring(L, "group"); | ||
32 | lua_newtable(L); | ||
33 | lua_settable(L, -3); | ||
34 | lua_pop(L, 1); | ||
35 | } | ||
36 | |||
37 | /*-------------------------------------------------------------------------*\ | ||
38 | * Add group to object list of groups. | ||
39 | \*-------------------------------------------------------------------------*/ | ||
40 | void aux_add2group(lua_State *L, const char *name, const char *group) | ||
41 | { | ||
42 | luaL_getmetatable(L, name); | ||
43 | lua_pushstring(L, "group"); | ||
44 | lua_gettable(L, -2); | ||
45 | lua_pushstring(L, group); | ||
46 | lua_pushnumber(L, 1); | ||
47 | lua_settable(L, -3); | ||
48 | lua_pop(L, 2); | ||
49 | } | ||
50 | |||
51 | /*-------------------------------------------------------------------------*\ | ||
52 | * Get a userdata making sure the object belongs to a given class. | ||
53 | \*-------------------------------------------------------------------------*/ | ||
54 | void *aux_checkclass(lua_State *L, const char *name, int objidx) | ||
55 | { | ||
56 | void *data = luaL_checkudata(L, objidx, name); | ||
57 | if (!data) { | ||
58 | char msg[45]; | ||
59 | sprintf(msg, "%.35s expected", name); | ||
60 | luaL_argerror(L, objidx, msg); | ||
61 | } | ||
62 | return data; | ||
63 | } | ||
64 | |||
65 | /*-------------------------------------------------------------------------*\ | ||
66 | * Get a userdata making sure the object belongs to a given group. | ||
67 | \*-------------------------------------------------------------------------*/ | ||
68 | void *aux_checkgroup(lua_State *L, const char *group, int objidx) | ||
69 | { | ||
70 | void *data = aux_getgroupudata(L, group, objidx); | ||
71 | if (!data) { | ||
72 | char msg[45]; | ||
73 | sprintf(msg, "%.35s expected", group); | ||
74 | luaL_argerror(L, objidx, msg); | ||
75 | } | ||
76 | return data; | ||
77 | } | ||
78 | |||
79 | /*-------------------------------------------------------------------------*\ | ||
80 | * Set object class. | ||
81 | \*-------------------------------------------------------------------------*/ | ||
82 | void aux_setclass(lua_State *L, const char *name, int objidx) | ||
83 | { | ||
84 | luaL_getmetatable(L, name); | ||
85 | if (objidx < 0) objidx--; | ||
86 | lua_setmetatable(L, objidx); | ||
87 | } | ||
88 | |||
89 | /*=========================================================================*\ | ||
90 | * Internal functions | ||
91 | \*=========================================================================*/ | ||
92 | /*-------------------------------------------------------------------------*\ | ||
93 | * Get a userdata if object belongs to a given group. | ||
94 | \*-------------------------------------------------------------------------*/ | ||
95 | static void *aux_getgroupudata(lua_State *L, const char *group, int objidx) | ||
96 | { | ||
97 | if (!lua_getmetatable(L, objidx)) return NULL; | ||
98 | lua_pushstring(L, "group"); | ||
99 | lua_gettable(L, -2); | ||
100 | if (lua_isnil(L, -1)) { | ||
101 | lua_pop(L, 2); | ||
102 | return NULL; | ||
103 | } | ||
104 | lua_pushstring(L, group); | ||
105 | lua_gettable(L, -2); | ||
106 | if (lua_isnil(L, -1)) { | ||
107 | lua_pop(L, 3); | ||
108 | return NULL; | ||
109 | } | ||
110 | lua_pop(L, 3); | ||
111 | return lua_touserdata(L, objidx); | ||
112 | } | ||
113 | |||
diff --git a/src/auxiliar.h b/src/auxiliar.h new file mode 100644 index 0000000..2681a84 --- /dev/null +++ b/src/auxiliar.h | |||
@@ -0,0 +1,26 @@ | |||
1 | /*=========================================================================*\ | ||
2 | * Auxiliar routines for class hierarchy manipulation | ||
3 | * | ||
4 | * RCS ID: $Id$ | ||
5 | \*=========================================================================*/ | ||
6 | #ifndef AUX_H | ||
7 | #define AUX_H | ||
8 | |||
9 | #include <lua.h> | ||
10 | #include <lauxlib.h> | ||
11 | |||
12 | void aux_newclass(lua_State *L, const char *name, luaL_reg *func); | ||
13 | void aux_add2group(lua_State *L, const char *name, const char *group); | ||
14 | void *aux_checkclass(lua_State *L, const char *name, int objidx); | ||
15 | void *aux_checkgroup(lua_State *L, const char *group, int objidx); | ||
16 | void aux_setclass(lua_State *L, const char *name, int objidx); | ||
17 | |||
18 | /* min and max macros */ | ||
19 | #ifndef MIN | ||
20 | #define MIN(x, y) ((x) < (y) ? x : y) | ||
21 | #endif | ||
22 | #ifndef MAX | ||
23 | #define MAX(x, y) ((x) > (y) ? x : y) | ||
24 | #endif | ||
25 | |||
26 | #endif | ||
diff --git a/src/buffer.c b/src/buffer.c index 73df8b3..c5ef66c 100644 --- a/src/buffer.c +++ b/src/buffer.c | |||
@@ -1,28 +1,24 @@ | |||
1 | /*=========================================================================*\ | 1 | /*=========================================================================*\ |
2 | * Buffered input/output routines | 2 | * Buffered input/output routines |
3 | * Lua methods: | ||
4 | * send: unbuffered send using C base_send | ||
5 | * receive: buffered read using C base_receive | ||
6 | * | 3 | * |
7 | * RCS ID: $Id$ | 4 | * RCS ID: $Id$ |
8 | \*=========================================================================*/ | 5 | \*=========================================================================*/ |
9 | #include <lua.h> | 6 | #include <lua.h> |
10 | #include <lauxlib.h> | 7 | #include <lauxlib.h> |
11 | 8 | ||
12 | #include "lsbuf.h" | 9 | #include "error.h" |
10 | #include "aux.h" | ||
11 | #include "buf.h" | ||
13 | 12 | ||
14 | /*=========================================================================*\ | 13 | /*=========================================================================*\ |
15 | * Internal function prototypes. | 14 | * Internal function prototypes |
16 | \*=========================================================================*/ | 15 | \*=========================================================================*/ |
17 | static int sendraw(lua_State *L, p_buf buf, cchar *data, size_t len, | ||
18 | size_t *done); | ||
19 | static int recvraw(lua_State *L, p_buf buf, size_t wanted); | 16 | static int recvraw(lua_State *L, p_buf buf, size_t wanted); |
20 | static int recvdosline(lua_State *L, p_buf buf); | 17 | static int recvline(lua_State *L, p_buf buf); |
21 | static int recvunixline(lua_State *L, p_buf buf); | ||
22 | static int recvall(lua_State *L, p_buf buf); | 18 | static int recvall(lua_State *L, p_buf buf); |
23 | 19 | static int buf_get(p_buf buf, const char **data, size_t *count); | |
24 | static int buf_contents(lua_State *L, p_buf buf, cchar **data, size_t *len); | 20 | static void buf_skip(p_buf buf, size_t count); |
25 | static void buf_skip(lua_State *L, p_buf buf, size_t len); | 21 | static int sendraw(p_buf buf, const char *data, size_t count, size_t *sent); |
26 | 22 | ||
27 | /*=========================================================================*\ | 23 | /*=========================================================================*\ |
28 | * Exported functions | 24 | * Exported functions |
@@ -37,98 +33,69 @@ void buf_open(lua_State *L) | |||
37 | 33 | ||
38 | /*-------------------------------------------------------------------------*\ | 34 | /*-------------------------------------------------------------------------*\ |
39 | * Initializes C structure | 35 | * Initializes C structure |
40 | * Input | ||
41 | * buf: buffer structure to initialize | ||
42 | * base: socket object to associate with buffer structure | ||
43 | \*-------------------------------------------------------------------------*/ | 36 | \*-------------------------------------------------------------------------*/ |
44 | void buf_init(lua_State *L, p_buf buf, p_base base) | 37 | void buf_init(p_buf buf, p_io io, p_tm tm) |
45 | { | 38 | { |
46 | (void) L; | 39 | buf->first = buf->last = 0; |
47 | buf->buf_first = buf->buf_last = 0; | 40 | buf->io = io; |
48 | buf->buf_base = base; | 41 | buf->tm = tm; |
49 | } | 42 | } |
50 | 43 | ||
51 | /*-------------------------------------------------------------------------*\ | 44 | /*-------------------------------------------------------------------------*\ |
52 | * Send data through buffered object | 45 | * Send data through buffered object |
53 | * Input | ||
54 | * buf: buffer structure to be used | ||
55 | * Lua Input: self, a_1 [, a_2, a_3 ... a_n] | ||
56 | * self: socket object | ||
57 | * a_i: strings to be sent. | ||
58 | * Lua Returns | ||
59 | * On success: nil, followed by the total number of bytes sent | ||
60 | * On error: error message | ||
61 | \*-------------------------------------------------------------------------*/ | 46 | \*-------------------------------------------------------------------------*/ |
62 | int buf_send(lua_State *L, p_buf buf) | 47 | int buf_meth_send(lua_State *L, p_buf buf) |
63 | { | 48 | { |
64 | int top = lua_gettop(L); | 49 | int top = lua_gettop(L); |
65 | size_t total = 0; | 50 | size_t total = 0; |
66 | int err = PRIV_DONE; | 51 | int arg, err = IO_DONE; |
67 | int arg; | 52 | p_tm tm = buf->tm; |
68 | p_base base = buf->buf_base; | 53 | tm_markstart(tm); |
69 | tm_markstart(&base->base_tm); | ||
70 | for (arg = 2; arg <= top; arg++) { /* first arg is socket object */ | 54 | for (arg = 2; arg <= top; arg++) { /* first arg is socket object */ |
71 | size_t done, len; | 55 | size_t sent, count; |
72 | cchar *data = luaL_optlstring(L, arg, NULL, &len); | 56 | const char *data = luaL_optlstring(L, arg, NULL, &count); |
73 | if (!data || err != PRIV_DONE) break; | 57 | if (!data || err != IO_DONE) break; |
74 | err = sendraw(L, buf, data, len, &done); | 58 | err = sendraw(buf, data, count, &sent); |
75 | total += done; | 59 | total += sent; |
76 | } | 60 | } |
77 | priv_pusherror(L, err); | ||
78 | lua_pushnumber(L, total); | 61 | lua_pushnumber(L, total); |
62 | error_push(L, err); | ||
79 | #ifdef LUASOCKET_DEBUG | 63 | #ifdef LUASOCKET_DEBUG |
80 | /* push time elapsed during operation as the last return value */ | 64 | /* push time elapsed during operation as the last return value */ |
81 | lua_pushnumber(L, tm_getelapsed(&base->base_tm)/1000.0); | 65 | lua_pushnumber(L, (tm_gettime() - tm_getstart(tm))/1000.0); |
82 | #endif | 66 | #endif |
83 | return lua_gettop(L) - top; | 67 | return lua_gettop(L) - top; |
84 | } | 68 | } |
85 | 69 | ||
86 | /*-------------------------------------------------------------------------*\ | 70 | /*-------------------------------------------------------------------------*\ |
87 | * Receive data from a buffered object | 71 | * Receive data from a buffered object |
88 | * Input | ||
89 | * buf: buffer structure to be used | ||
90 | * Lua Input: self [pat_1, pat_2 ... pat_n] | ||
91 | * self: socket object | ||
92 | * pat_i: may be one of the following | ||
93 | * "*l": reads a text line, defined as a string of caracters terminates | ||
94 | * by a LF character, preceded or not by a CR character. This is | ||
95 | * the default pattern | ||
96 | * "*lu": reads a text line, terminanted by a CR character only. (Unix mode) | ||
97 | * "*a": reads until connection closed | ||
98 | * number: reads 'number' characters from the socket object | ||
99 | * Lua Returns | ||
100 | * On success: one string for each pattern | ||
101 | * On error: all strings for which there was no error, followed by one | ||
102 | * nil value for the remaining strings, followed by an error code | ||
103 | \*-------------------------------------------------------------------------*/ | 72 | \*-------------------------------------------------------------------------*/ |
104 | int buf_receive(lua_State *L, p_buf buf) | 73 | int buf_meth_receive(lua_State *L, p_buf buf) |
105 | { | 74 | { |
106 | int top = lua_gettop(L); | 75 | int top = lua_gettop(L); |
107 | int arg, err = PRIV_DONE; | 76 | int arg, err = IO_DONE; |
108 | p_base base = buf->buf_base; | 77 | p_tm tm = buf->tm; |
109 | tm_markstart(&base->base_tm); | 78 | tm_markstart(tm); |
110 | /* push default pattern if need be */ | 79 | /* push default pattern if need be */ |
111 | if (top < 2) { | 80 | if (top < 2) { |
112 | lua_pushstring(L, "*l"); | 81 | lua_pushstring(L, "*l"); |
113 | top++; | 82 | top++; |
114 | } | 83 | } |
115 | /* make sure we have enough stack space */ | 84 | /* make sure we have enough stack space for all returns */ |
116 | luaL_checkstack(L, top+LUA_MINSTACK, "too many arguments"); | 85 | luaL_checkstack(L, top+LUA_MINSTACK, "too many arguments"); |
117 | /* receive all patterns */ | 86 | /* receive all patterns */ |
118 | for (arg = 2; arg <= top && err == PRIV_DONE; arg++) { | 87 | for (arg = 2; arg <= top && err == IO_DONE; arg++) { |
119 | if (!lua_isnumber(L, arg)) { | 88 | if (!lua_isnumber(L, arg)) { |
120 | static cchar *patternnames[] = {"*l", "*lu", "*a", "*w", NULL}; | 89 | static const char *patternnames[] = {"*l", "*a", NULL}; |
121 | cchar *pattern = luaL_optstring(L, arg, NULL); | 90 | const char *pattern = lua_isnil(L, arg) ? |
91 | "*l" : luaL_checkstring(L, arg); | ||
122 | /* get next pattern */ | 92 | /* get next pattern */ |
123 | switch (luaL_findstring(pattern, patternnames)) { | 93 | switch (luaL_findstring(pattern, patternnames)) { |
124 | case 0: /* DOS line pattern */ | 94 | case 0: /* line pattern */ |
125 | err = recvdosline(L, buf); break; | 95 | err = recvline(L, buf); break; |
126 | case 1: /* Unix line pattern */ | 96 | case 1: /* until closed pattern */ |
127 | err = recvunixline(L, buf); break; | 97 | err = recvall(L, buf); |
128 | case 2: /* Until closed pattern */ | 98 | if (err == IO_CLOSED) err = IO_DONE; |
129 | err = recvall(L, buf); break; | ||
130 | case 3: /* Word pattern */ | ||
131 | luaL_argcheck(L, 0, arg, "word patterns are deprecated"); | ||
132 | break; | 99 | break; |
133 | default: /* else it is an error */ | 100 | default: /* else it is an error */ |
134 | luaL_argcheck(L, 0, arg, "invalid receive pattern"); | 101 | luaL_argcheck(L, 0, arg, "invalid receive pattern"); |
@@ -140,25 +107,20 @@ int buf_receive(lua_State *L, p_buf buf) | |||
140 | /* push nil for each pattern after an error */ | 107 | /* push nil for each pattern after an error */ |
141 | for ( ; arg <= top; arg++) lua_pushnil(L); | 108 | for ( ; arg <= top; arg++) lua_pushnil(L); |
142 | /* last return is an error code */ | 109 | /* last return is an error code */ |
143 | priv_pusherror(L, err); | 110 | error_push(L, err); |
144 | #ifdef LUASOCKET_DEBUG | 111 | #ifdef LUASOCKET_DEBUG |
145 | /* push time elapsed during operation as the last return value */ | 112 | /* push time elapsed during operation as the last return value */ |
146 | lua_pushnumber(L, tm_getelapsed(&base->base_tm)/1000.0); | 113 | lua_pushnumber(L, (tm_gettime() - tm_getstart(tm))/1000.0); |
147 | #endif | 114 | #endif |
148 | return lua_gettop(L) - top; | 115 | return lua_gettop(L) - top; |
149 | } | 116 | } |
150 | 117 | ||
151 | /*-------------------------------------------------------------------------*\ | 118 | /*-------------------------------------------------------------------------*\ |
152 | * Determines if there is any data in the read buffer | 119 | * Determines if there is any data in the read buffer |
153 | * Input | ||
154 | * buf: buffer structure to be used | ||
155 | * Returns | ||
156 | * 1 if empty, 0 if there is data | ||
157 | \*-------------------------------------------------------------------------*/ | 120 | \*-------------------------------------------------------------------------*/ |
158 | int buf_isempty(lua_State *L, p_buf buf) | 121 | int buf_isempty(p_buf buf) |
159 | { | 122 | { |
160 | (void) L; | 123 | return buf->first >= buf->last; |
161 | return buf->buf_first >= buf->buf_last; | ||
162 | } | 124 | } |
163 | 125 | ||
164 | /*=========================================================================*\ | 126 | /*=========================================================================*\ |
@@ -166,24 +128,16 @@ int buf_isempty(lua_State *L, p_buf buf) | |||
166 | \*=========================================================================*/ | 128 | \*=========================================================================*/ |
167 | /*-------------------------------------------------------------------------*\ | 129 | /*-------------------------------------------------------------------------*\ |
168 | * Sends a raw block of data through a buffered object. | 130 | * Sends a raw block of data through a buffered object. |
169 | * Input | ||
170 | * buf: buffer structure to be used | ||
171 | * data: data to be sent | ||
172 | * len: number of bytes to send | ||
173 | * Output | ||
174 | * sent: number of bytes sent | ||
175 | * Returns | ||
176 | * operation error code. | ||
177 | \*-------------------------------------------------------------------------*/ | 131 | \*-------------------------------------------------------------------------*/ |
178 | static int sendraw(lua_State *L, p_buf buf, cchar *data, size_t len, | 132 | static int sendraw(p_buf buf, const char *data, size_t count, size_t *sent) |
179 | size_t *sent) | ||
180 | { | 133 | { |
181 | p_base base = buf->buf_base; | 134 | p_io io = buf->io; |
135 | p_tm tm = buf->tm; | ||
182 | size_t total = 0; | 136 | size_t total = 0; |
183 | int err = PRIV_DONE; | 137 | int err = IO_DONE; |
184 | while (total < len && err == PRIV_DONE) { | 138 | while (total < count && err == IO_DONE) { |
185 | size_t done; | 139 | size_t done; |
186 | err = base->base_send(L, base, data + total, len - total, &done); | 140 | err = io->send(io->ctx, data+total, count-total, &done, tm_get(tm)); |
187 | total += done; | 141 | total += done; |
188 | } | 142 | } |
189 | *sent = total; | 143 | *sent = total; |
@@ -192,25 +146,21 @@ static int sendraw(lua_State *L, p_buf buf, cchar *data, size_t len, | |||
192 | 146 | ||
193 | /*-------------------------------------------------------------------------*\ | 147 | /*-------------------------------------------------------------------------*\ |
194 | * Reads a raw block of data from a buffered object. | 148 | * Reads a raw block of data from a buffered object. |
195 | * Input | ||
196 | * buf: buffer structure | ||
197 | * wanted: number of bytes to be read | ||
198 | * Returns | ||
199 | * operation error code. | ||
200 | \*-------------------------------------------------------------------------*/ | 149 | \*-------------------------------------------------------------------------*/ |
201 | static int recvraw(lua_State *L, p_buf buf, size_t wanted) | 150 | static |
151 | int recvraw(lua_State *L, p_buf buf, size_t wanted) | ||
202 | { | 152 | { |
203 | int err = PRIV_DONE; | 153 | int err = IO_DONE; |
204 | size_t total = 0; | 154 | size_t total = 0; |
205 | luaL_Buffer b; | 155 | luaL_Buffer b; |
206 | luaL_buffinit(L, &b); | 156 | luaL_buffinit(L, &b); |
207 | while (total < wanted && err == PRIV_DONE) { | 157 | while (total < wanted && err == IO_DONE) { |
208 | size_t len; cchar *data; | 158 | size_t count; const char *data; |
209 | err = buf_contents(L, buf, &data, &len); | 159 | err = buf_get(buf, &data, &count); |
210 | len = MIN(len, wanted - total); | 160 | count = MIN(count, wanted - total); |
211 | luaL_addlstring(&b, data, len); | 161 | luaL_addlstring(&b, data, count); |
212 | buf_skip(L, buf, len); | 162 | buf_skip(buf, count); |
213 | total += len; | 163 | total += count; |
214 | } | 164 | } |
215 | luaL_pushresult(&b); | 165 | luaL_pushresult(&b); |
216 | return err; | 166 | return err; |
@@ -218,21 +168,18 @@ static int recvraw(lua_State *L, p_buf buf, size_t wanted) | |||
218 | 168 | ||
219 | /*-------------------------------------------------------------------------*\ | 169 | /*-------------------------------------------------------------------------*\ |
220 | * Reads everything until the connection is closed | 170 | * Reads everything until the connection is closed |
221 | * Input | ||
222 | * buf: buffer structure | ||
223 | * Result | ||
224 | * operation error code. | ||
225 | \*-------------------------------------------------------------------------*/ | 171 | \*-------------------------------------------------------------------------*/ |
226 | static int recvall(lua_State *L, p_buf buf) | 172 | static |
173 | int recvall(lua_State *L, p_buf buf) | ||
227 | { | 174 | { |
228 | int err = PRIV_DONE; | 175 | int err = IO_DONE; |
229 | luaL_Buffer b; | 176 | luaL_Buffer b; |
230 | luaL_buffinit(L, &b); | 177 | luaL_buffinit(L, &b); |
231 | while (err == PRIV_DONE) { | 178 | while (err == IO_DONE) { |
232 | cchar *data; size_t len; | 179 | const char *data; size_t count; |
233 | err = buf_contents(L, buf, &data, &len); | 180 | err = buf_get(buf, &data, &count); |
234 | luaL_addlstring(&b, data, len); | 181 | luaL_addlstring(&b, data, count); |
235 | buf_skip(L, buf, len); | 182 | buf_skip(buf, count); |
236 | } | 183 | } |
237 | luaL_pushresult(&b); | 184 | luaL_pushresult(&b); |
238 | return err; | 185 | return err; |
@@ -241,61 +188,27 @@ static int recvall(lua_State *L, p_buf buf) | |||
241 | /*-------------------------------------------------------------------------*\ | 188 | /*-------------------------------------------------------------------------*\ |
242 | * Reads a line terminated by a CR LF pair or just by a LF. The CR and LF | 189 | * Reads a line terminated by a CR LF pair or just by a LF. The CR and LF |
243 | * are not returned by the function and are discarded from the buffer. | 190 | * are not returned by the function and are discarded from the buffer. |
244 | * Input | ||
245 | * buf: buffer structure | ||
246 | * Result | ||
247 | * operation error code. PRIV_DONE, PRIV_TIMEOUT or PRIV_CLOSED | ||
248 | \*-------------------------------------------------------------------------*/ | 191 | \*-------------------------------------------------------------------------*/ |
249 | static int recvdosline(lua_State *L, p_buf buf) | 192 | static |
193 | int recvline(lua_State *L, p_buf buf) | ||
250 | { | 194 | { |
251 | int err = 0; | 195 | int err = 0; |
252 | luaL_Buffer b; | 196 | luaL_Buffer b; |
253 | luaL_buffinit(L, &b); | 197 | luaL_buffinit(L, &b); |
254 | while (err == PRIV_DONE) { | 198 | while (err == IO_DONE) { |
255 | size_t len, pos; cchar *data; | 199 | size_t count, pos; const char *data; |
256 | err = buf_contents(L, buf, &data, &len); | 200 | err = buf_get(buf, &data, &count); |
257 | pos = 0; | 201 | pos = 0; |
258 | while (pos < len && data[pos] != '\n') { | 202 | while (pos < count && data[pos] != '\n') { |
259 | /* we ignore all \r's */ | 203 | /* we ignore all \r's */ |
260 | if (data[pos] != '\r') luaL_putchar(&b, data[pos]); | 204 | if (data[pos] != '\r') luaL_putchar(&b, data[pos]); |
261 | pos++; | 205 | pos++; |
262 | } | 206 | } |
263 | if (pos < len) { /* found '\n' */ | 207 | if (pos < count) { /* found '\n' */ |
264 | buf_skip(L, buf, pos+1); /* skip '\n' too */ | 208 | buf_skip(buf, pos+1); /* skip '\n' too */ |
265 | break; /* we are done */ | ||
266 | } else /* reached the end of the buffer */ | ||
267 | buf_skip(L, buf, pos); | ||
268 | } | ||
269 | luaL_pushresult(&b); | ||
270 | return err; | ||
271 | } | ||
272 | |||
273 | /*-------------------------------------------------------------------------*\ | ||
274 | * Reads a line terminated by a LF character, which is not returned by | ||
275 | * the function, and is skipped in the buffer. | ||
276 | * Input | ||
277 | * buf: buffer structure | ||
278 | * Returns | ||
279 | * operation error code. PRIV_DONE, PRIV_TIMEOUT or PRIV_CLOSED | ||
280 | \*-------------------------------------------------------------------------*/ | ||
281 | static int recvunixline(lua_State *L, p_buf buf) | ||
282 | { | ||
283 | int err = PRIV_DONE; | ||
284 | luaL_Buffer b; | ||
285 | luaL_buffinit(L, &b); | ||
286 | while (err == 0) { | ||
287 | size_t pos, len; cchar *data; | ||
288 | err = buf_contents(L, buf, &data, &len); | ||
289 | pos = 0; | ||
290 | while (pos < len && data[pos] != '\n') { | ||
291 | luaL_putchar(&b, data[pos]); | ||
292 | pos++; | ||
293 | } | ||
294 | if (pos < len) { /* found '\n' */ | ||
295 | buf_skip(L, buf, pos+1); /* skip '\n' too */ | ||
296 | break; /* we are done */ | 209 | break; /* we are done */ |
297 | } else /* reached the end of the buffer */ | 210 | } else /* reached the end of the buffer */ |
298 | buf_skip(L, buf, pos); | 211 | buf_skip(buf, pos); |
299 | } | 212 | } |
300 | luaL_pushresult(&b); | 213 | luaL_pushresult(&b); |
301 | return err; | 214 | return err; |
@@ -303,38 +216,32 @@ static int recvunixline(lua_State *L, p_buf buf) | |||
303 | 216 | ||
304 | /*-------------------------------------------------------------------------*\ | 217 | /*-------------------------------------------------------------------------*\ |
305 | * Skips a given number of bytes in read buffer | 218 | * Skips a given number of bytes in read buffer |
306 | * Input | ||
307 | * buf: buffer structure | ||
308 | * len: number of bytes to skip | ||
309 | \*-------------------------------------------------------------------------*/ | 219 | \*-------------------------------------------------------------------------*/ |
310 | static void buf_skip(lua_State *L, p_buf buf, size_t len) | 220 | static |
221 | void buf_skip(p_buf buf, size_t count) | ||
311 | { | 222 | { |
312 | buf->buf_first += len; | 223 | buf->first += count; |
313 | if (buf_isempty(L, buf)) buf->buf_first = buf->buf_last = 0; | 224 | if (buf_isempty(buf)) |
225 | buf->first = buf->last = 0; | ||
314 | } | 226 | } |
315 | 227 | ||
316 | /*-------------------------------------------------------------------------*\ | 228 | /*-------------------------------------------------------------------------*\ |
317 | * Return any data available in buffer, or get more data from transport layer | 229 | * Return any data available in buffer, or get more data from transport layer |
318 | * if buffer is empty. | 230 | * if buffer is empty. |
319 | * Input | ||
320 | * buf: buffer structure | ||
321 | * Output | ||
322 | * data: pointer to buffer start | ||
323 | * len: buffer buffer length | ||
324 | * Returns | ||
325 | * PRIV_DONE, PRIV_CLOSED, PRIV_TIMEOUT ... | ||
326 | \*-------------------------------------------------------------------------*/ | 231 | \*-------------------------------------------------------------------------*/ |
327 | static int buf_contents(lua_State *L, p_buf buf, cchar **data, size_t *len) | 232 | static |
233 | int buf_get(p_buf buf, const char **data, size_t *count) | ||
328 | { | 234 | { |
329 | int err = PRIV_DONE; | 235 | int err = IO_DONE; |
330 | p_base base = buf->buf_base; | 236 | p_io io = buf->io; |
331 | if (buf_isempty(L, buf)) { | 237 | p_tm tm = buf->tm; |
332 | size_t done; | 238 | if (buf_isempty(buf)) { |
333 | err = base->base_receive(L, base, buf->buf_data, BUF_SIZE, &done); | 239 | size_t got; |
334 | buf->buf_first = 0; | 240 | err = io->recv(io->ctx, buf->data, BUF_SIZE, &got, tm_get(tm)); |
335 | buf->buf_last = done; | 241 | buf->first = 0; |
242 | buf->last = got; | ||
336 | } | 243 | } |
337 | *len = buf->buf_last - buf->buf_first; | 244 | *count = buf->last - buf->first; |
338 | *data = buf->buf_data + buf->buf_first; | 245 | *data = buf->data + buf->first; |
339 | return err; | 246 | return err; |
340 | } | 247 | } |
diff --git a/src/buffer.h b/src/buffer.h index 4943e3b..3ffc145 100644 --- a/src/buffer.h +++ b/src/buffer.h | |||
@@ -3,11 +3,12 @@ | |||
3 | * | 3 | * |
4 | * RCS ID: $Id$ | 4 | * RCS ID: $Id$ |
5 | \*=========================================================================*/ | 5 | \*=========================================================================*/ |
6 | #ifndef BUF_H_ | 6 | #ifndef BUF_H |
7 | #define BUF_H_ | 7 | #define BUF_H |
8 | 8 | ||
9 | #include <lua.h> | 9 | #include <lua.h> |
10 | #include "lsbase.h" | 10 | #include "io.h" |
11 | #include "tm.h" | ||
11 | 12 | ||
12 | /* buffer size in bytes */ | 13 | /* buffer size in bytes */ |
13 | #define BUF_SIZE 8192 | 14 | #define BUF_SIZE 8192 |
@@ -15,10 +16,11 @@ | |||
15 | /*-------------------------------------------------------------------------*\ | 16 | /*-------------------------------------------------------------------------*\ |
16 | * Buffer control structure | 17 | * Buffer control structure |
17 | \*-------------------------------------------------------------------------*/ | 18 | \*-------------------------------------------------------------------------*/ |
18 | typedef struct t_buf_tag { | 19 | typedef struct t_buf_ { |
19 | size_t buf_first, buf_last; | 20 | p_io io; /* IO driver used for this buffer */ |
20 | char buf_data[BUF_SIZE]; | 21 | p_tm tm; /* timeout management for this buffer */ |
21 | p_base buf_base; | 22 | size_t first, last; /* index of first and last bytes of stored data */ |
23 | char data[BUF_SIZE]; /* storage space for buffer data */ | ||
22 | } t_buf; | 24 | } t_buf; |
23 | typedef t_buf *p_buf; | 25 | typedef t_buf *p_buf; |
24 | 26 | ||
@@ -26,9 +28,9 @@ typedef t_buf *p_buf; | |||
26 | * Exported functions | 28 | * Exported functions |
27 | \*-------------------------------------------------------------------------*/ | 29 | \*-------------------------------------------------------------------------*/ |
28 | void buf_open(lua_State *L); | 30 | void buf_open(lua_State *L); |
29 | void buf_init(lua_State *L, p_buf buf, p_base base); | 31 | void buf_init(p_buf buf, p_io io, p_tm tm); |
30 | int buf_send(lua_State *L, p_buf buf); | 32 | int buf_meth_send(lua_State *L, p_buf buf); |
31 | int buf_receive(lua_State *L, p_buf buf); | 33 | int buf_meth_receive(lua_State *L, p_buf buf); |
32 | int buf_isempty(lua_State *L, p_buf buf); | 34 | int buf_isempty(p_buf buf); |
33 | 35 | ||
34 | #endif /* BUF_H_ */ | 36 | #endif /* BUF_H */ |
diff --git a/src/ftp.lua b/src/ftp.lua index 4017eb5..c48f2c7 100644 --- a/src/ftp.lua +++ b/src/ftp.lua | |||
@@ -7,7 +7,8 @@ | |||
7 | ----------------------------------------------------------------------------- | 7 | ----------------------------------------------------------------------------- |
8 | 8 | ||
9 | local Public, Private = {}, {} | 9 | local Public, Private = {}, {} |
10 | socket.ftp = Public | 10 | local socket = _G[LUASOCKET_LIBNAME] -- get LuaSocket namespace |
11 | socket.ftp = Public -- create ftp sub namespace | ||
11 | 12 | ||
12 | ----------------------------------------------------------------------------- | 13 | ----------------------------------------------------------------------------- |
13 | -- Program constants | 14 | -- Program constants |
@@ -23,32 +24,42 @@ Public.EMAIL = "anonymous@anonymous.org" | |||
23 | Public.BLOCKSIZE = 8192 | 24 | Public.BLOCKSIZE = 8192 |
24 | 25 | ||
25 | ----------------------------------------------------------------------------- | 26 | ----------------------------------------------------------------------------- |
26 | -- Tries to send DOS mode lines. Closes socket on error. | 27 | -- Tries to get a pattern from the server and closes socket on error |
27 | -- Input | 28 | -- sock: socket connected to the server |
28 | -- sock: server socket | 29 | -- pattern: pattern to receive |
29 | -- line: string to be sent | ||
30 | -- Returns | 30 | -- Returns |
31 | -- err: message in case of error, nil if successfull | 31 | -- received pattern on success |
32 | -- nil followed by error message on error | ||
32 | ----------------------------------------------------------------------------- | 33 | ----------------------------------------------------------------------------- |
33 | function Private.try_sendline(sock, line) | 34 | function Private.try_receive(sock, pattern) |
34 | local err = sock:send(line .. "\r\n") | 35 | local data, err = sock:receive(pattern) |
35 | if err then sock:close() end | 36 | if not data then sock:close() end |
36 | return err | 37 | return data, err |
37 | end | 38 | end |
38 | 39 | ||
39 | ----------------------------------------------------------------------------- | 40 | ----------------------------------------------------------------------------- |
40 | -- Tries to get a pattern from the server and closes socket on error | 41 | -- Tries to send data to the server and closes socket on error |
41 | -- sock: socket connected to the server | 42 | -- sock: socket connected to the server |
42 | -- ...: pattern to receive | 43 | -- data: data to send |
43 | -- Returns | 44 | -- Returns |
44 | -- ...: received pattern | 45 | -- err: error message if any, nil if successfull |
45 | -- err: error message if any | ||
46 | ----------------------------------------------------------------------------- | 46 | ----------------------------------------------------------------------------- |
47 | function Private.try_receive(...) | 47 | function Private.try_send(sock, data) |
48 | local sock = arg[1] | 48 | local sent, err = sock:send(data) |
49 | local data, err = sock.receive(unpack(arg)) | 49 | if not sent then sock:close() end |
50 | if err then sock:close() end | 50 | return err |
51 | return data, err | 51 | end |
52 | |||
53 | ----------------------------------------------------------------------------- | ||
54 | -- Tries to send DOS mode lines. Closes socket on error. | ||
55 | -- Input | ||
56 | -- sock: server socket | ||
57 | -- line: string to be sent | ||
58 | -- Returns | ||
59 | -- err: message in case of error, nil if successfull | ||
60 | ----------------------------------------------------------------------------- | ||
61 | function Private.try_sendline(sock, line) | ||
62 | return Private.try_send(sock, line .. "\r\n") | ||
52 | end | 63 | end |
53 | 64 | ||
54 | ----------------------------------------------------------------------------- | 65 | ----------------------------------------------------------------------------- |
@@ -307,20 +318,20 @@ end | |||
307 | -- nil if successfull, or an error message in case of error | 318 | -- nil if successfull, or an error message in case of error |
308 | ----------------------------------------------------------------------------- | 319 | ----------------------------------------------------------------------------- |
309 | function Private.send_indirect(data, send_cb, chunk, size) | 320 | function Private.send_indirect(data, send_cb, chunk, size) |
310 | local sent, err | 321 | local total, sent, err |
311 | sent = 0 | 322 | total = 0 |
312 | while 1 do | 323 | while 1 do |
313 | if type(chunk) ~= "string" or type(size) ~= "number" then | 324 | if type(chunk) ~= "string" or type(size) ~= "number" then |
314 | data:close() | 325 | data:close() |
315 | if not chunk and type(size) == "string" then return size | 326 | if not chunk and type(size) == "string" then return size |
316 | else return "invalid callback return" end | 327 | else return "invalid callback return" end |
317 | end | 328 | end |
318 | err = data:send(chunk) | 329 | sent, err = data:send(chunk) |
319 | if err then | 330 | if err then |
320 | data:close() | 331 | data:close() |
321 | return err | 332 | return err |
322 | end | 333 | end |
323 | sent = sent + string.len(chunk) | 334 | total = total + sent |
324 | if sent >= size then break end | 335 | if sent >= size then break end |
325 | chunk, size = send_cb() | 336 | chunk, size = send_cb() |
326 | end | 337 | end |
diff --git a/src/http.lua b/src/http.lua index 59645ee..d531a2f 100644 --- a/src/http.lua +++ b/src/http.lua | |||
@@ -7,7 +7,8 @@ | |||
7 | ----------------------------------------------------------------------------- | 7 | ----------------------------------------------------------------------------- |
8 | 8 | ||
9 | local Public, Private = {}, {} | 9 | local Public, Private = {}, {} |
10 | socket.http = Public | 10 | local socket = _G[LUASOCKET_LIBNAME] -- get LuaSocket namespace |
11 | socket.http = Public -- create http sub namespace | ||
11 | 12 | ||
12 | ----------------------------------------------------------------------------- | 13 | ----------------------------------------------------------------------------- |
13 | -- Program constants | 14 | -- Program constants |
@@ -24,19 +25,15 @@ Public.BLOCKSIZE = 8192 | |||
24 | ----------------------------------------------------------------------------- | 25 | ----------------------------------------------------------------------------- |
25 | -- Tries to get a pattern from the server and closes socket on error | 26 | -- Tries to get a pattern from the server and closes socket on error |
26 | -- sock: socket connected to the server | 27 | -- sock: socket connected to the server |
27 | -- ...: pattern to receive | 28 | -- pattern: pattern to receive |
28 | -- Returns | 29 | -- Returns |
29 | -- ...: received pattern | 30 | -- received pattern on success |
30 | -- err: error message if any | 31 | -- nil followed by error message on error |
31 | ----------------------------------------------------------------------------- | 32 | ----------------------------------------------------------------------------- |
32 | function Private.try_receive(...) | 33 | function Private.try_receive(sock, pattern) |
33 | local sock = arg[1] | 34 | local data, err = sock:receive(pattern) |
34 | local data, err = sock.receive(unpack(arg)) | 35 | if not data then sock:close() end |
35 | if err then | 36 | return data, err |
36 | sock:close() | ||
37 | return nil, err | ||
38 | end | ||
39 | return data | ||
40 | end | 37 | end |
41 | 38 | ||
42 | ----------------------------------------------------------------------------- | 39 | ----------------------------------------------------------------------------- |
@@ -47,8 +44,8 @@ end | |||
47 | -- err: error message if any, nil if successfull | 44 | -- err: error message if any, nil if successfull |
48 | ----------------------------------------------------------------------------- | 45 | ----------------------------------------------------------------------------- |
49 | function Private.try_send(sock, data) | 46 | function Private.try_send(sock, data) |
50 | local err = sock:send(data) | 47 | local sent, err = sock:send(data) |
51 | if err then sock:close() end | 48 | if not sent then sock:close() end |
52 | return err | 49 | return err |
53 | end | 50 | end |
54 | 51 | ||
@@ -285,21 +282,21 @@ end | |||
285 | -- nil if successfull, or an error message in case of error | 282 | -- nil if successfull, or an error message in case of error |
286 | ----------------------------------------------------------------------------- | 283 | ----------------------------------------------------------------------------- |
287 | function Private.send_indirect(data, send_cb, chunk, size) | 284 | function Private.send_indirect(data, send_cb, chunk, size) |
288 | local sent, err | 285 | local total, sent, err |
289 | sent = 0 | 286 | total = 0 |
290 | while 1 do | 287 | while 1 do |
291 | if type(chunk) ~= "string" or type(size) ~= "number" then | 288 | if type(chunk) ~= "string" or type(size) ~= "number" then |
292 | data:close() | 289 | data:close() |
293 | if not chunk and type(size) == "string" then return size | 290 | if not chunk and type(size) == "string" then return size |
294 | else return "invalid callback return" end | 291 | else return "invalid callback return" end |
295 | end | 292 | end |
296 | err = data:send(chunk) | 293 | sent, err = data:send(chunk) |
297 | if err then | 294 | if err then |
298 | data:close() | 295 | data:close() |
299 | return err | 296 | return err |
300 | end | 297 | end |
301 | sent = sent + string.len(chunk) | 298 | total = total + sent |
302 | if sent >= size then break end | 299 | if total >= size then break end |
303 | chunk, size = send_cb() | 300 | chunk, size = send_cb() |
304 | end | 301 | end |
305 | end | 302 | end |
@@ -1,12 +1,5 @@ | |||
1 | /*=========================================================================*\ | 1 | /*=========================================================================*\ |
2 | * Internet domain class: inherits from the Socket class, and implement | 2 | * Internet domain functions |
3 | * a few methods shared by all internet related objects | ||
4 | * Lua methods: | ||
5 | * getpeername: gets socket peer ip address and port | ||
6 | * getsockname: gets local socket ip address and port | ||
7 | * Global Lua fuctions: | ||
8 | * toip: gets resolver info on host name | ||
9 | * tohostname: gets resolver info on dotted-quad | ||
10 | * | 3 | * |
11 | * RCS ID: $Id$ | 4 | * RCS ID: $Id$ |
12 | \*=========================================================================*/ | 5 | \*=========================================================================*/ |
@@ -15,23 +8,27 @@ | |||
15 | #include <lua.h> | 8 | #include <lua.h> |
16 | #include <lauxlib.h> | 9 | #include <lauxlib.h> |
17 | 10 | ||
18 | #include "lsinet.h" | 11 | #include "luasocket.h" |
19 | #include "lssock.h" | 12 | #include "inet.h" |
20 | #include "lscompat.h" | ||
21 | 13 | ||
22 | /*=========================================================================*\ | 14 | /*=========================================================================*\ |
23 | * Internal function prototypes. | 15 | * Internal function prototypes. |
24 | \*=========================================================================*/ | 16 | \*=========================================================================*/ |
25 | static int inet_lua_toip(lua_State *L); | 17 | static int inet_global_toip(lua_State *L); |
26 | static int inet_lua_tohostname(lua_State *L); | 18 | static int inet_global_tohostname(lua_State *L); |
27 | static int inet_lua_getpeername(lua_State *L); | 19 | |
28 | static int inet_lua_getsockname(lua_State *L); | ||
29 | static void inet_pushresolved(lua_State *L, struct hostent *hp); | 20 | static void inet_pushresolved(lua_State *L, struct hostent *hp); |
30 | 21 | ||
31 | #ifdef COMPAT_INETATON | 22 | #ifdef INET_ATON |
32 | static int inet_aton(cchar *cp, struct in_addr *inp); | 23 | static int inet_aton(const char *cp, struct in_addr *inp); |
33 | #endif | 24 | #endif |
34 | 25 | ||
26 | static luaL_reg func[] = { | ||
27 | { "toip", inet_global_toip }, | ||
28 | { "tohostname", inet_global_tohostname }, | ||
29 | { NULL, NULL} | ||
30 | }; | ||
31 | |||
35 | /*=========================================================================*\ | 32 | /*=========================================================================*\ |
36 | * Exported functions | 33 | * Exported functions |
37 | \*=========================================================================*/ | 34 | \*=========================================================================*/ |
@@ -40,39 +37,7 @@ static int inet_aton(cchar *cp, struct in_addr *inp); | |||
40 | \*-------------------------------------------------------------------------*/ | 37 | \*-------------------------------------------------------------------------*/ |
41 | void inet_open(lua_State *L) | 38 | void inet_open(lua_State *L) |
42 | { | 39 | { |
43 | lua_pushcfunction(L, inet_lua_toip); | 40 | luaL_openlib(L, LUASOCKET_LIBNAME, func, 0); |
44 | priv_newglobal(L, "toip"); | ||
45 | lua_pushcfunction(L, inet_lua_tohostname); | ||
46 | priv_newglobal(L, "tohostname"); | ||
47 | priv_newglobalmethod(L, "getsockname"); | ||
48 | priv_newglobalmethod(L, "getpeername"); | ||
49 | } | ||
50 | |||
51 | /*-------------------------------------------------------------------------*\ | ||
52 | * Hook lua methods to methods table. | ||
53 | * Input | ||
54 | * lsclass: class name | ||
55 | \*-------------------------------------------------------------------------*/ | ||
56 | void inet_inherit(lua_State *L, cchar *lsclass) | ||
57 | { | ||
58 | unsigned int i; | ||
59 | static struct luaL_reg funcs[] = { | ||
60 | {"getsockname", inet_lua_getsockname}, | ||
61 | {"getpeername", inet_lua_getpeername}, | ||
62 | }; | ||
63 | sock_inherit(L, lsclass); | ||
64 | for (i = 0; i < sizeof(funcs)/sizeof(funcs[0]); i++) { | ||
65 | lua_pushcfunction(L, funcs[i].func); | ||
66 | priv_setmethod(L, lsclass, funcs[i].name); | ||
67 | } | ||
68 | } | ||
69 | |||
70 | /*-------------------------------------------------------------------------*\ | ||
71 | * Constructs the object | ||
72 | \*-------------------------------------------------------------------------*/ | ||
73 | void inet_construct(lua_State *L, p_inet inet) | ||
74 | { | ||
75 | sock_construct(L, (p_sock) inet); | ||
76 | } | 41 | } |
77 | 42 | ||
78 | /*=========================================================================*\ | 43 | /*=========================================================================*\ |
@@ -87,17 +52,18 @@ void inet_construct(lua_State *L, p_inet inet) | |||
87 | * On success: first IP address followed by a resolved table | 52 | * On success: first IP address followed by a resolved table |
88 | * On error: nil, followed by an error message | 53 | * On error: nil, followed by an error message |
89 | \*-------------------------------------------------------------------------*/ | 54 | \*-------------------------------------------------------------------------*/ |
90 | static int inet_lua_toip(lua_State *L) | 55 | static int inet_global_toip(lua_State *L) |
91 | { | 56 | { |
92 | cchar *address = luaL_checkstring(L, 1); | 57 | const char *address = luaL_checkstring(L, 1); |
93 | struct in_addr addr; | 58 | struct in_addr addr; |
94 | struct hostent *hp; | 59 | struct hostent *hp; |
95 | if (inet_aton(address, &addr)) | 60 | if (inet_aton(address, &addr)) |
96 | hp = gethostbyaddr((char *) &addr, sizeof(addr), AF_INET); | 61 | hp = gethostbyaddr((char *) &addr, sizeof(addr), AF_INET); |
97 | else hp = gethostbyname(address); | 62 | else |
63 | hp = gethostbyname(address); | ||
98 | if (!hp) { | 64 | if (!hp) { |
99 | lua_pushnil(L); | 65 | lua_pushnil(L); |
100 | lua_pushstring(L, compat_hoststrerror()); | 66 | lua_pushstring(L, sock_hoststrerror()); |
101 | return 2; | 67 | return 2; |
102 | } | 68 | } |
103 | addr = *((struct in_addr *) hp->h_addr); | 69 | addr = *((struct in_addr *) hp->h_addr); |
@@ -115,17 +81,18 @@ static int inet_lua_toip(lua_State *L) | |||
115 | * On success: canonic name followed by a resolved table | 81 | * On success: canonic name followed by a resolved table |
116 | * On error: nil, followed by an error message | 82 | * On error: nil, followed by an error message |
117 | \*-------------------------------------------------------------------------*/ | 83 | \*-------------------------------------------------------------------------*/ |
118 | static int inet_lua_tohostname(lua_State *L) | 84 | static int inet_global_tohostname(lua_State *L) |
119 | { | 85 | { |
120 | cchar *address = luaL_checkstring(L, 1); | 86 | const char *address = luaL_checkstring(L, 1); |
121 | struct in_addr addr; | 87 | struct in_addr addr; |
122 | struct hostent *hp; | 88 | struct hostent *hp; |
123 | if (inet_aton(address, &addr)) | 89 | if (inet_aton(address, &addr)) |
124 | hp = gethostbyaddr((char *) &addr, sizeof(addr), AF_INET); | 90 | hp = gethostbyaddr((char *) &addr, sizeof(addr), AF_INET); |
125 | else hp = gethostbyname(address); | 91 | else |
92 | hp = gethostbyname(address); | ||
126 | if (!hp) { | 93 | if (!hp) { |
127 | lua_pushnil(L); | 94 | lua_pushnil(L); |
128 | lua_pushstring(L, compat_hoststrerror()); | 95 | lua_pushstring(L, sock_hoststrerror()); |
129 | return 2; | 96 | return 2; |
130 | } | 97 | } |
131 | lua_pushstring(L, hp->h_name); | 98 | lua_pushstring(L, hp->h_name); |
@@ -138,18 +105,17 @@ static int inet_lua_tohostname(lua_State *L) | |||
138 | \*=========================================================================*/ | 105 | \*=========================================================================*/ |
139 | /*-------------------------------------------------------------------------*\ | 106 | /*-------------------------------------------------------------------------*\ |
140 | * Retrieves socket peer name | 107 | * Retrieves socket peer name |
141 | * Lua Input: sock | 108 | * Input: |
142 | * sock: socket | 109 | * sock: socket |
143 | * Lua Returns | 110 | * Lua Returns |
144 | * On success: ip address and port of peer | 111 | * On success: ip address and port of peer |
145 | * On error: nil | 112 | * On error: nil |
146 | \*-------------------------------------------------------------------------*/ | 113 | \*-------------------------------------------------------------------------*/ |
147 | static int inet_lua_getpeername(lua_State *L) | 114 | int inet_meth_getpeername(lua_State *L, p_sock ps) |
148 | { | 115 | { |
149 | p_sock sock = (p_sock) lua_touserdata(L, 1); | ||
150 | struct sockaddr_in peer; | 116 | struct sockaddr_in peer; |
151 | size_t peer_len = sizeof(peer); | 117 | size_t peer_len = sizeof(peer); |
152 | if (getpeername(sock->fd, (SA *) &peer, &peer_len) < 0) { | 118 | if (getpeername(*ps, (SA *) &peer, &peer_len) < 0) { |
153 | lua_pushnil(L); | 119 | lua_pushnil(L); |
154 | return 1; | 120 | return 1; |
155 | } | 121 | } |
@@ -160,18 +126,17 @@ static int inet_lua_getpeername(lua_State *L) | |||
160 | 126 | ||
161 | /*-------------------------------------------------------------------------*\ | 127 | /*-------------------------------------------------------------------------*\ |
162 | * Retrieves socket local name | 128 | * Retrieves socket local name |
163 | * Lua Input: sock | 129 | * Input: |
164 | * sock: socket | 130 | * sock: socket |
165 | * Lua Returns | 131 | * Lua Returns |
166 | * On success: local ip address and port | 132 | * On success: local ip address and port |
167 | * On error: nil | 133 | * On error: nil |
168 | \*-------------------------------------------------------------------------*/ | 134 | \*-------------------------------------------------------------------------*/ |
169 | static int inet_lua_getsockname(lua_State *L) | 135 | int inet_meth_getsockname(lua_State *L, p_sock ps) |
170 | { | 136 | { |
171 | p_sock sock = (p_sock) lua_touserdata(L, 1); | ||
172 | struct sockaddr_in local; | 137 | struct sockaddr_in local; |
173 | size_t local_len = sizeof(local); | 138 | size_t local_len = sizeof(local); |
174 | if (getsockname(sock->fd, (SA *) &local, &local_len) < 0) { | 139 | if (getsockname(*ps, (SA *) &local, &local_len) < 0) { |
175 | lua_pushnil(L); | 140 | lua_pushnil(L); |
176 | return 1; | 141 | return 1; |
177 | } | 142 | } |
@@ -222,47 +187,53 @@ static void inet_pushresolved(lua_State *L, struct hostent *hp) | |||
222 | } | 187 | } |
223 | 188 | ||
224 | /*-------------------------------------------------------------------------*\ | 189 | /*-------------------------------------------------------------------------*\ |
225 | * Tries to create a TCP socket and connect to remote address (address, port) | 190 | * Tries to connect to remote address (address, port) |
226 | * Input | 191 | * Input |
227 | * client: socket structure to be used | 192 | * ps: pointer to socket |
228 | * address: host name or ip address | 193 | * address: host name or ip address |
229 | * port: port number to bind to | 194 | * port: port number to bind to |
230 | * Returns | 195 | * Returns |
231 | * NULL in case of success, error message otherwise | 196 | * NULL in case of success, error message otherwise |
232 | \*-------------------------------------------------------------------------*/ | 197 | \*-------------------------------------------------------------------------*/ |
233 | cchar *inet_tryconnect(p_inet inet, cchar *address, ushort port) | 198 | const char *inet_tryconnect(p_sock ps, const char *address, ushort port) |
234 | { | 199 | { |
235 | struct sockaddr_in remote; | 200 | struct sockaddr_in remote; |
236 | memset(&remote, 0, sizeof(remote)); | 201 | memset(&remote, 0, sizeof(remote)); |
237 | remote.sin_family = AF_INET; | 202 | remote.sin_family = AF_INET; |
238 | remote.sin_port = htons(port); | 203 | remote.sin_port = htons(port); |
239 | if (!strlen(address) || !inet_aton(address, &remote.sin_addr)) { | 204 | if (strcmp(address, "*")) { |
240 | struct hostent *hp = gethostbyname(address); | 205 | if (!strlen(address) || !inet_aton(address, &remote.sin_addr)) { |
241 | struct in_addr **addr; | 206 | struct hostent *hp = gethostbyname(address); |
242 | if (!hp) return compat_hoststrerror(); | 207 | struct in_addr **addr; |
243 | addr = (struct in_addr **) hp->h_addr_list; | 208 | remote.sin_family = AF_INET; |
244 | memcpy(&remote.sin_addr, *addr, sizeof(struct in_addr)); | 209 | if (!hp) return sock_hoststrerror(); |
245 | } | 210 | addr = (struct in_addr **) hp->h_addr_list; |
246 | compat_setblocking(inet->fd); | 211 | memcpy(&remote.sin_addr, *addr, sizeof(struct in_addr)); |
247 | if (compat_connect(inet->fd, (SA *) &remote, sizeof(remote)) < 0) { | 212 | } |
248 | const char *err = compat_connectstrerror(); | 213 | } else remote.sin_family = AF_UNSPEC; |
249 | compat_close(inet->fd); | 214 | sock_setblocking(ps); |
250 | inet->fd = COMPAT_INVALIDFD; | 215 | const char *err = sock_connect(ps, (SA *) &remote, sizeof(remote)); |
216 | if (err) { | ||
217 | sock_destroy(ps); | ||
218 | *ps = SOCK_INVALID; | ||
251 | return err; | 219 | return err; |
252 | } | 220 | } else { |
253 | compat_setnonblocking(inet->fd); | 221 | sock_setnonblocking(ps); |
254 | return NULL; | 222 | return NULL; |
223 | } | ||
255 | } | 224 | } |
256 | 225 | ||
257 | /*-------------------------------------------------------------------------*\ | 226 | /*-------------------------------------------------------------------------*\ |
258 | * Tries to create a TCP socket and bind it to (address, port) | 227 | * Tries to bind socket to (address, port) |
259 | * Input | 228 | * Input |
229 | * sock: pointer to socket | ||
260 | * address: host name or ip address | 230 | * address: host name or ip address |
261 | * port: port number to bind to | 231 | * port: port number to bind to |
262 | * Returns | 232 | * Returns |
263 | * NULL in case of success, error message otherwise | 233 | * NULL in case of success, error message otherwise |
264 | \*-------------------------------------------------------------------------*/ | 234 | \*-------------------------------------------------------------------------*/ |
265 | cchar *inet_trybind(p_inet inet, cchar *address, ushort port) | 235 | const char *inet_trybind(p_sock ps, const char *address, ushort port, |
236 | int backlog) | ||
266 | { | 237 | { |
267 | struct sockaddr_in local; | 238 | struct sockaddr_in local; |
268 | memset(&local, 0, sizeof(local)); | 239 | memset(&local, 0, sizeof(local)); |
@@ -274,34 +245,33 @@ cchar *inet_trybind(p_inet inet, cchar *address, ushort port) | |||
274 | (!strlen(address) || !inet_aton(address, &local.sin_addr))) { | 245 | (!strlen(address) || !inet_aton(address, &local.sin_addr))) { |
275 | struct hostent *hp = gethostbyname(address); | 246 | struct hostent *hp = gethostbyname(address); |
276 | struct in_addr **addr; | 247 | struct in_addr **addr; |
277 | if (!hp) return compat_hoststrerror(); | 248 | if (!hp) return sock_hoststrerror(); |
278 | addr = (struct in_addr **) hp->h_addr_list; | 249 | addr = (struct in_addr **) hp->h_addr_list; |
279 | memcpy(&local.sin_addr, *addr, sizeof(struct in_addr)); | 250 | memcpy(&local.sin_addr, *addr, sizeof(struct in_addr)); |
280 | } | 251 | } |
281 | compat_setblocking(inet->fd); | 252 | sock_setblocking(ps); |
282 | if (compat_bind(inet->fd, (SA *) &local, sizeof(local)) < 0) { | 253 | const char *err = sock_bind(ps, (SA *) &local, sizeof(local)); |
283 | const char *err = compat_bindstrerror(); | 254 | if (err) { |
284 | compat_close(inet->fd); | 255 | sock_destroy(ps); |
285 | inet->fd = COMPAT_INVALIDFD; | 256 | *ps = SOCK_INVALID; |
286 | return err; | 257 | return err; |
258 | } else { | ||
259 | sock_setnonblocking(ps); | ||
260 | if (backlog > 0) sock_listen(ps, backlog); | ||
261 | return NULL; | ||
287 | } | 262 | } |
288 | compat_setnonblocking(inet->fd); | ||
289 | return NULL; | ||
290 | } | 263 | } |
291 | 264 | ||
292 | /*-------------------------------------------------------------------------*\ | 265 | /*-------------------------------------------------------------------------*\ |
293 | * Tries to create a new inet socket | 266 | * Tries to create a new inet socket |
294 | * Input | 267 | * Input |
295 | * udp: udp structure | 268 | * sock: pointer to socket |
296 | * Returns | 269 | * Returns |
297 | * NULL if successfull, error message on error | 270 | * NULL if successfull, error message on error |
298 | \*-------------------------------------------------------------------------*/ | 271 | \*-------------------------------------------------------------------------*/ |
299 | cchar *inet_trysocket(p_inet inet, int type) | 272 | const char *inet_trycreate(p_sock ps, int type) |
300 | { | 273 | { |
301 | if (inet->fd != COMPAT_INVALIDFD) compat_close(inet->fd); | 274 | return sock_create(ps, AF_INET, type, 0); |
302 | inet->fd = compat_socket(AF_INET, type, 0); | ||
303 | if (inet->fd == COMPAT_INVALIDFD) return compat_socketstrerror(); | ||
304 | else return NULL; | ||
305 | } | 275 | } |
306 | 276 | ||
307 | /*-------------------------------------------------------------------------*\ | 277 | /*-------------------------------------------------------------------------*\ |
@@ -1,38 +1,26 @@ | |||
1 | /*=========================================================================*\ | 1 | /*=========================================================================*\ |
2 | * Internet domain class: inherits from the Socket class, and implement | 2 | * Internet domain functions |
3 | * a few methods shared by all internet related objects | ||
4 | * | 3 | * |
5 | * RCS ID: $Id$ | 4 | * RCS ID: $Id$ |
6 | \*=========================================================================*/ | 5 | \*=========================================================================*/ |
7 | #ifndef INET_H_ | 6 | #ifndef INET_H |
8 | #define INET_H_ | 7 | #define INET_H |
9 | 8 | ||
10 | #include <lua.h> | 9 | #include <lua.h> |
11 | #include "lssock.h" | 10 | #include "sock.h" |
12 | |||
13 | /* class name */ | ||
14 | #define INET_CLASS "luasocket(inet)" | ||
15 | |||
16 | /*-------------------------------------------------------------------------*\ | ||
17 | * Socket fields | ||
18 | \*-------------------------------------------------------------------------*/ | ||
19 | #define INET_FIELDS SOCK_FIELDS | ||
20 | |||
21 | /*-------------------------------------------------------------------------*\ | ||
22 | * Socket structure | ||
23 | \*-------------------------------------------------------------------------*/ | ||
24 | typedef t_sock t_inet; | ||
25 | typedef t_inet *p_inet; | ||
26 | 11 | ||
27 | /*-------------------------------------------------------------------------*\ | 12 | /*-------------------------------------------------------------------------*\ |
28 | * Exported functions | 13 | * Exported functions |
29 | \*-------------------------------------------------------------------------*/ | 14 | \*-------------------------------------------------------------------------*/ |
30 | void inet_open(lua_State *L); | 15 | void inet_open(lua_State *L); |
31 | void inet_construct(lua_State *L, p_inet inet); | ||
32 | void inet_inherit(lua_State *L, cchar *lsclass); | ||
33 | 16 | ||
34 | cchar *inet_tryconnect(p_sock sock, cchar *address, ushort); | 17 | const char *inet_tryconnect(p_sock ps, const char *address, |
35 | cchar *inet_trybind(p_sock sock, cchar *address, ushort); | 18 | unsigned short port); |
36 | cchar *inet_trysocket(p_inet inet, int type); | 19 | const char *inet_trybind(p_sock ps, const char *address, |
20 | unsigned short port, int backlog); | ||
21 | const char *inet_trycreate(p_sock ps, int type); | ||
22 | |||
23 | int inet_meth_getpeername(lua_State *L, p_sock ps); | ||
24 | int inet_meth_getsockname(lua_State *L, p_sock ps); | ||
37 | 25 | ||
38 | #endif /* INET_H_ */ | 26 | #endif /* INET_H_ */ |
diff --git a/src/io.c b/src/io.c new file mode 100644 index 0000000..902124a --- /dev/null +++ b/src/io.c | |||
@@ -0,0 +1,8 @@ | |||
1 | #include "io.h" | ||
2 | |||
3 | void io_init(p_io io, p_send send, p_recv recv, void *ctx) | ||
4 | { | ||
5 | io->send = send; | ||
6 | io->recv = recv; | ||
7 | io->ctx = ctx; | ||
8 | } | ||
diff --git a/src/io.h b/src/io.h new file mode 100644 index 0000000..b5b7f1d --- /dev/null +++ b/src/io.h | |||
@@ -0,0 +1,34 @@ | |||
1 | #ifndef IO_H | ||
2 | #define IO_H | ||
3 | |||
4 | #include "error.h" | ||
5 | |||
6 | /* interface to send function */ | ||
7 | typedef int (*p_send) ( | ||
8 | void *ctx, /* context needed by send */ | ||
9 | const char *data, /* pointer to buffer with data to send */ | ||
10 | size_t count, /* number of bytes to send from buffer */ | ||
11 | size_t *sent, /* number of bytes sent uppon return */ | ||
12 | int timeout /* number of miliseconds left for transmission */ | ||
13 | ); | ||
14 | |||
15 | /* interface to recv function */ | ||
16 | typedef int (*p_recv) ( | ||
17 | void *ctx, /* context needed by recv */ | ||
18 | char *data, /* pointer to buffer where data will be writen */ | ||
19 | size_t count, /* number of bytes to receive into buffer */ | ||
20 | size_t *got, /* number of bytes received uppon return */ | ||
21 | int timeout /* number of miliseconds left for transmission */ | ||
22 | ); | ||
23 | |||
24 | /* IO driver definition */ | ||
25 | typedef struct t_io_ { | ||
26 | void *ctx; /* context needed by send/recv */ | ||
27 | p_send send; /* send function pointer */ | ||
28 | p_recv recv; /* receive function pointer */ | ||
29 | } t_io; | ||
30 | typedef t_io *p_io; | ||
31 | |||
32 | void io_init(p_io io, p_send send, p_recv recv, void *ctx); | ||
33 | |||
34 | #endif /* IO_H */ | ||
diff --git a/src/luasocket.c b/src/luasocket.c index bcc705f..53f8c21 100644 --- a/src/luasocket.c +++ b/src/luasocket.c | |||
@@ -23,18 +23,13 @@ | |||
23 | * LuaSocket includes | 23 | * LuaSocket includes |
24 | \*=========================================================================*/ | 24 | \*=========================================================================*/ |
25 | #include "luasocket.h" | 25 | #include "luasocket.h" |
26 | #include "lspriv.h" | 26 | |
27 | #include "lsselect.h" | 27 | #include "tm.h" |
28 | #include "lscompat.h" | 28 | #include "buf.h" |
29 | #include "lsbase.h" | 29 | #include "sock.h" |
30 | #include "lstm.h" | 30 | #include "inet.h" |
31 | #include "lsbuf.h" | 31 | #include "tcp.h" |
32 | #include "lssock.h" | 32 | #include "udp.h" |
33 | #include "lsinet.h" | ||
34 | #include "lstcpc.h" | ||
35 | #include "lstcps.h" | ||
36 | #include "lstcps.h" | ||
37 | #include "lsudp.h" | ||
38 | 33 | ||
39 | /*=========================================================================*\ | 34 | /*=========================================================================*\ |
40 | * Exported functions | 35 | * Exported functions |
@@ -42,34 +37,29 @@ | |||
42 | /*-------------------------------------------------------------------------*\ | 37 | /*-------------------------------------------------------------------------*\ |
43 | * Initializes all library modules. | 38 | * Initializes all library modules. |
44 | \*-------------------------------------------------------------------------*/ | 39 | \*-------------------------------------------------------------------------*/ |
45 | LUASOCKET_API int lua_socketlibopen(lua_State *L) | 40 | LUASOCKET_API int luaopen_socketlib(lua_State *L) |
46 | { | 41 | { |
47 | compat_open(L); | 42 | /* create namespace table */ |
48 | priv_open(L); | 43 | lua_pushstring(L, LUASOCKET_LIBNAME); |
49 | select_open(L); | 44 | lua_newtable(L); |
50 | base_open(L); | 45 | #ifdef LUASOCKET_DEBUG |
51 | tm_open(L); | 46 | lua_pushstring(L, "debug"); |
52 | fd_open(L); | 47 | lua_pushnumber(L, 1); |
48 | lua_settable(L, -3); | ||
49 | #endif | ||
50 | lua_settable(L, LUA_GLOBALSINDEX); | ||
51 | /* make sure modules know what is our namespace */ | ||
52 | lua_pushstring(L, "LUASOCKET_LIBNAME"); | ||
53 | lua_pushstring(L, LUASOCKET_LIBNAME); | ||
54 | lua_settable(L, LUA_GLOBALSINDEX); | ||
55 | /* initialize all modules */ | ||
53 | sock_open(L); | 56 | sock_open(L); |
54 | inet_open(L); | 57 | tm_open(L); |
55 | tcpc_open(L); | ||
56 | buf_open(L); | 58 | buf_open(L); |
57 | tcps_open(L); | 59 | inet_open(L); |
60 | tcp_open(L); | ||
58 | udp_open(L); | 61 | udp_open(L); |
59 | #ifdef LUASOCKET_DOFILE | 62 | /* load all Lua code */ |
60 | lua_dofile(L, "concat.lua"); | 63 | lua_dofile(L, "luasocket.lua"); |
61 | lua_dofile(L, "code.lua"); | ||
62 | lua_dofile(L, "url.lua"); | ||
63 | lua_dofile(L, "http.lua"); | ||
64 | lua_dofile(L, "smtp.lua"); | ||
65 | lua_dofile(L, "ftp.lua"); | ||
66 | #else | ||
67 | #include "concat.loh" | ||
68 | #include "code.loh" | ||
69 | #include "url.loh" | ||
70 | #include "http.loh" | ||
71 | #include "smtp.loh" | ||
72 | #include "ftp.loh" | ||
73 | #endif | ||
74 | return 0; | 64 | return 0; |
75 | } | 65 | } |
diff --git a/src/luasocket.h b/src/luasocket.h index fd22606..6c25af2 100644 --- a/src/luasocket.h +++ b/src/luasocket.h | |||
@@ -5,8 +5,8 @@ | |||
5 | * | 5 | * |
6 | * RCS ID: $Id$ | 6 | * RCS ID: $Id$ |
7 | \*=========================================================================*/ | 7 | \*=========================================================================*/ |
8 | #ifndef _LUASOCKET_H_ | 8 | #ifndef LUASOCKET_H |
9 | #define _LUASOCKET_H_ | 9 | #define LUASOCKET_H |
10 | 10 | ||
11 | /*-------------------------------------------------------------------------*\ | 11 | /*-------------------------------------------------------------------------*\ |
12 | * Current luasocket version | 12 | * Current luasocket version |
@@ -28,6 +28,6 @@ | |||
28 | /*-------------------------------------------------------------------------*\ | 28 | /*-------------------------------------------------------------------------*\ |
29 | * Initializes the library. | 29 | * Initializes the library. |
30 | \*-------------------------------------------------------------------------*/ | 30 | \*-------------------------------------------------------------------------*/ |
31 | LUASOCKET_API int lua_socketlibopen(lua_State *L); | 31 | LUASOCKET_API int luaopen_socketlib(lua_State *L); |
32 | 32 | ||
33 | #endif /* _LUASOCKET_H_ */ | 33 | #endif /* LUASOCKET_H */ |
diff --git a/src/mbox.lua b/src/mbox.lua index 4a72331..f52719b 100644 --- a/src/mbox.lua +++ b/src/mbox.lua | |||
@@ -5,10 +5,10 @@ mbox = Public | |||
5 | function Public.split_message(message_s) | 5 | function Public.split_message(message_s) |
6 | local message = {} | 6 | local message = {} |
7 | message_s = string.gsub(message_s, "\r\n", "\n") | 7 | message_s = string.gsub(message_s, "\r\n", "\n") |
8 | string.gsub(message_s, "^(.-\n)\n", function (h) %message.headers = h end) | 8 | string.gsub(message_s, "^(.-\n)\n", function (h) message.headers = h end) |
9 | string.gsub(message_s, "^.-\n\n(.*)", function (b) %message.body = b end) | 9 | string.gsub(message_s, "^.-\n\n(.*)", function (b) message.body = b end) |
10 | if not message.body then | 10 | if not message.body then |
11 | string.gsub(message_s, "^\n(.*)", function (b) %message.body = b end) | 11 | string.gsub(message_s, "^\n(.*)", function (b) message.body = b end) |
12 | end | 12 | end |
13 | if not message.headers and not message.body then | 13 | if not message.headers and not message.body then |
14 | message.headers = message_s | 14 | message.headers = message_s |
@@ -20,7 +20,7 @@ function Public.split_headers(headers_s) | |||
20 | local headers = {} | 20 | local headers = {} |
21 | headers_s = string.gsub(headers_s, "\r\n", "\n") | 21 | headers_s = string.gsub(headers_s, "\r\n", "\n") |
22 | headers_s = string.gsub(headers_s, "\n[ ]+", " ") | 22 | headers_s = string.gsub(headers_s, "\n[ ]+", " ") |
23 | string.gsub("\n" .. headers_s, "\n([^\n]+)", function (h) table.insert(%headers, h) end) | 23 | string.gsub("\n" .. headers_s, "\n([^\n]+)", function (h) table.insert(headers, h) end) |
24 | return headers | 24 | return headers |
25 | end | 25 | end |
26 | 26 | ||
@@ -32,10 +32,10 @@ function Public.parse_header(header_s) | |||
32 | end | 32 | end |
33 | 33 | ||
34 | function Public.parse_headers(headers_s) | 34 | function Public.parse_headers(headers_s) |
35 | local headers_t = %Public.split_headers(headers_s) | 35 | local headers_t = Public.split_headers(headers_s) |
36 | local headers = {} | 36 | local headers = {} |
37 | for i = 1, table.getn(headers_t) do | 37 | for i = 1, table.getn(headers_t) do |
38 | local name, value = %Public.parse_header(headers_t[i]) | 38 | local name, value = Public.parse_header(headers_t[i]) |
39 | if name then | 39 | if name then |
40 | name = string.lower(name) | 40 | name = string.lower(name) |
41 | if headers[name] then | 41 | if headers[name] then |
@@ -73,16 +73,16 @@ function Public.split_mbox(mbox_s) | |||
73 | end | 73 | end |
74 | 74 | ||
75 | function Public.parse(mbox_s) | 75 | function Public.parse(mbox_s) |
76 | local mbox = %Public.split_mbox(mbox_s) | 76 | local mbox = Public.split_mbox(mbox_s) |
77 | for i = 1, table.getn(mbox) do | 77 | for i = 1, table.getn(mbox) do |
78 | mbox[i] = %Public.parse_message(mbox[i]) | 78 | mbox[i] = Public.parse_message(mbox[i]) |
79 | end | 79 | end |
80 | return mbox | 80 | return mbox |
81 | end | 81 | end |
82 | 82 | ||
83 | function Public.parse_message(message_s) | 83 | function Public.parse_message(message_s) |
84 | local message = {} | 84 | local message = {} |
85 | message.headers, message.body = %Public.split_message(message_s) | 85 | message.headers, message.body = Public.split_message(message_s) |
86 | message.headers = %Public.parse_headers(message.headers) | 86 | message.headers = Public.parse_headers(message.headers) |
87 | return message | 87 | return message |
88 | end | 88 | end |
diff --git a/src/smtp.lua b/src/smtp.lua index 0ba2b0f..604f79b 100644 --- a/src/smtp.lua +++ b/src/smtp.lua | |||
@@ -7,7 +7,8 @@ | |||
7 | ----------------------------------------------------------------------------- | 7 | ----------------------------------------------------------------------------- |
8 | 8 | ||
9 | local Public, Private = {}, {} | 9 | local Public, Private = {}, {} |
10 | socket.smtp = Public | 10 | local socket = _G[LUASOCKET_LIBNAME] -- get LuaSocket namespace |
11 | socket.smtp = Public -- create smtp sub namespace | ||
11 | 12 | ||
12 | ----------------------------------------------------------------------------- | 13 | ----------------------------------------------------------------------------- |
13 | -- Program constants | 14 | -- Program constants |
@@ -23,32 +24,30 @@ Public.DOMAIN = os.getenv("SERVER_NAME") or "localhost" | |||
23 | Public.SERVER = "localhost" | 24 | Public.SERVER = "localhost" |
24 | 25 | ||
25 | ----------------------------------------------------------------------------- | 26 | ----------------------------------------------------------------------------- |
26 | -- Tries to send data through socket. Closes socket on error. | 27 | -- Tries to get a pattern from the server and closes socket on error |
27 | -- Input | 28 | -- sock: socket connected to the server |
28 | -- sock: server socket | 29 | -- pattern: pattern to receive |
29 | -- data: string to be sent | ||
30 | -- Returns | 30 | -- Returns |
31 | -- err: message in case of error, nil if successfull | 31 | -- received pattern on success |
32 | -- nil followed by error message on error | ||
32 | ----------------------------------------------------------------------------- | 33 | ----------------------------------------------------------------------------- |
33 | function Private.try_send(sock, data) | 34 | function Private.try_receive(sock, pattern) |
34 | local err = sock:send(data) | 35 | local data, err = sock:receive(pattern) |
35 | if err then sock:close() end | 36 | if not data then sock:close() end |
36 | return err | 37 | return data, err |
37 | end | 38 | end |
38 | 39 | ||
39 | ----------------------------------------------------------------------------- | 40 | ----------------------------------------------------------------------------- |
40 | -- Tries to get a pattern from the server and closes socket on error | 41 | -- Tries to send data to the server and closes socket on error |
41 | -- sock: socket opened to the server | 42 | -- sock: socket connected to the server |
42 | -- ...: pattern to receive | 43 | -- data: data to send |
43 | -- Returns | 44 | -- Returns |
44 | -- ...: received pattern | 45 | -- err: error message if any, nil if successfull |
45 | -- err: error message if any | ||
46 | ----------------------------------------------------------------------------- | 46 | ----------------------------------------------------------------------------- |
47 | function Private.try_receive(...) | 47 | function Private.try_send(sock, data) |
48 | local sock = arg[1] | 48 | local sent, err = sock:send(data) |
49 | local data, err = sock.receive(unpack(arg)) | 49 | if not sent then sock:close() end |
50 | if err then sock:close() end | 50 | return err |
51 | return data, err | ||
52 | end | 51 | end |
53 | 52 | ||
54 | ----------------------------------------------------------------------------- | 53 | ----------------------------------------------------------------------------- |
diff --git a/src/tcp.c b/src/tcp.c new file mode 100644 index 0000000..db6a38e --- /dev/null +++ b/src/tcp.c | |||
@@ -0,0 +1,222 @@ | |||
1 | /*=========================================================================*\ | ||
2 | * TCP object | ||
3 | * | ||
4 | * RCS ID: $Id$ | ||
5 | \*=========================================================================*/ | ||
6 | #include <string.h> | ||
7 | |||
8 | #include <lua.h> | ||
9 | #include <lauxlib.h> | ||
10 | |||
11 | #include "luasocket.h" | ||
12 | |||
13 | #include "aux.h" | ||
14 | #include "inet.h" | ||
15 | #include "tcp.h" | ||
16 | |||
17 | /*=========================================================================*\ | ||
18 | * Internal function prototypes | ||
19 | \*=========================================================================*/ | ||
20 | static int tcp_global_create(lua_State *L); | ||
21 | static int tcp_meth_connect(lua_State *L); | ||
22 | static int tcp_meth_bind(lua_State *L); | ||
23 | static int tcp_meth_send(lua_State *L); | ||
24 | static int tcp_meth_getsockname(lua_State *L); | ||
25 | static int tcp_meth_getpeername(lua_State *L); | ||
26 | static int tcp_meth_receive(lua_State *L); | ||
27 | static int tcp_meth_accept(lua_State *L); | ||
28 | static int tcp_meth_close(lua_State *L); | ||
29 | static int tcp_meth_timeout(lua_State *L); | ||
30 | |||
31 | /* tcp object methods */ | ||
32 | static luaL_reg tcp[] = { | ||
33 | {"connect", tcp_meth_connect}, | ||
34 | {"send", tcp_meth_send}, | ||
35 | {"receive", tcp_meth_receive}, | ||
36 | {"bind", tcp_meth_bind}, | ||
37 | {"accept", tcp_meth_accept}, | ||
38 | {"setpeername", tcp_meth_connect}, | ||
39 | {"setsockname", tcp_meth_bind}, | ||
40 | {"getpeername", tcp_meth_getpeername}, | ||
41 | {"getsockname", tcp_meth_getsockname}, | ||
42 | {"timeout", tcp_meth_timeout}, | ||
43 | {"close", tcp_meth_close}, | ||
44 | {NULL, NULL} | ||
45 | }; | ||
46 | |||
47 | /* functions in library namespace */ | ||
48 | static luaL_reg func[] = { | ||
49 | {"tcp", tcp_global_create}, | ||
50 | {NULL, NULL} | ||
51 | }; | ||
52 | |||
53 | /*-------------------------------------------------------------------------*\ | ||
54 | * Initializes module | ||
55 | \*-------------------------------------------------------------------------*/ | ||
56 | void tcp_open(lua_State *L) | ||
57 | { | ||
58 | /* create classes */ | ||
59 | aux_newclass(L, "tcp{master}", tcp); | ||
60 | aux_newclass(L, "tcp{client}", tcp); | ||
61 | aux_newclass(L, "tcp{server}", tcp); | ||
62 | /* create class groups */ | ||
63 | aux_add2group(L, "tcp{client}", "tcp{client, server}"); | ||
64 | aux_add2group(L, "tcp{server}", "tcp{client, server}"); | ||
65 | aux_add2group(L, "tcp{master}", "tcp{any}"); | ||
66 | aux_add2group(L, "tcp{client}", "tcp{any}"); | ||
67 | aux_add2group(L, "tcp{server}", "tcp{any}"); | ||
68 | /* define library functions */ | ||
69 | luaL_openlib(L, LUASOCKET_LIBNAME, func, 0); | ||
70 | lua_pop(L, 1); | ||
71 | } | ||
72 | |||
73 | /*=========================================================================*\ | ||
74 | * Lua methods | ||
75 | \*=========================================================================*/ | ||
76 | /*-------------------------------------------------------------------------*\ | ||
77 | * Just call buffered IO methods | ||
78 | \*-------------------------------------------------------------------------*/ | ||
79 | static int tcp_meth_send(lua_State *L) | ||
80 | { | ||
81 | p_tcp tcp = (p_tcp) aux_checkclass(L, "tcp{client}", 1); | ||
82 | return buf_meth_send(L, &tcp->buf); | ||
83 | } | ||
84 | |||
85 | static int tcp_meth_receive(lua_State *L) | ||
86 | { | ||
87 | p_tcp tcp = (p_tcp) aux_checkclass(L, "tcp{client}", 1); | ||
88 | return buf_meth_receive(L, &tcp->buf); | ||
89 | } | ||
90 | |||
91 | /*-------------------------------------------------------------------------*\ | ||
92 | * Just call inet methods | ||
93 | \*-------------------------------------------------------------------------*/ | ||
94 | static int tcp_meth_getpeername(lua_State *L) | ||
95 | { | ||
96 | p_tcp tcp = (p_tcp) aux_checkclass(L, "tcp{client}", 1); | ||
97 | return inet_meth_getpeername(L, &tcp->sock); | ||
98 | } | ||
99 | |||
100 | static int tcp_meth_getsockname(lua_State *L) | ||
101 | { | ||
102 | p_tcp tcp = (p_tcp) aux_checkgroup(L, "tcp{client, server}", 1); | ||
103 | return inet_meth_getsockname(L, &tcp->sock); | ||
104 | } | ||
105 | |||
106 | /*-------------------------------------------------------------------------*\ | ||
107 | * Just call tm methods | ||
108 | \*-------------------------------------------------------------------------*/ | ||
109 | static int tcp_meth_timeout(lua_State *L) | ||
110 | { | ||
111 | p_tcp tcp = (p_tcp) aux_checkgroup(L, "tcp{any}", 1); | ||
112 | return tm_meth_timeout(L, &tcp->tm); | ||
113 | } | ||
114 | |||
115 | /*-------------------------------------------------------------------------*\ | ||
116 | * Closes socket used by object | ||
117 | \*-------------------------------------------------------------------------*/ | ||
118 | static int tcp_meth_close(lua_State *L) | ||
119 | { | ||
120 | p_tcp tcp = (p_tcp) aux_checkgroup(L, "tcp{any}", 1); | ||
121 | sock_destroy(&tcp->sock); | ||
122 | return 0; | ||
123 | } | ||
124 | |||
125 | /*-------------------------------------------------------------------------*\ | ||
126 | * Turns a master tcp object into a client object. | ||
127 | \*-------------------------------------------------------------------------*/ | ||
128 | static int tcp_meth_connect(lua_State *L) | ||
129 | { | ||
130 | p_tcp tcp = (p_tcp) aux_checkclass(L, "tcp{master}", 1); | ||
131 | const char *address = luaL_checkstring(L, 2); | ||
132 | unsigned short port = (ushort) luaL_checknumber(L, 3); | ||
133 | const char *err = inet_tryconnect(&tcp->sock, address, port); | ||
134 | if (err) { | ||
135 | lua_pushnil(L); | ||
136 | lua_pushstring(L, err); | ||
137 | return 2; | ||
138 | } | ||
139 | /* turn master object into a client object */ | ||
140 | aux_setclass(L, "tcp{client}", 1); | ||
141 | lua_pushnumber(L, 1); | ||
142 | return 1; | ||
143 | } | ||
144 | |||
145 | /*-------------------------------------------------------------------------*\ | ||
146 | * Turns a master object into a server object | ||
147 | \*-------------------------------------------------------------------------*/ | ||
148 | static int tcp_meth_bind(lua_State *L) | ||
149 | { | ||
150 | p_tcp tcp = (p_tcp) aux_checkclass(L, "tcp{master}", 1); | ||
151 | const char *address = luaL_checkstring(L, 2); | ||
152 | unsigned short port = (ushort) luaL_checknumber(L, 3); | ||
153 | int backlog = (int) luaL_optnumber(L, 4, 1); | ||
154 | const char *err = inet_trybind(&tcp->sock, address, port, backlog); | ||
155 | if (err) { | ||
156 | lua_pushnil(L); | ||
157 | lua_pushstring(L, err); | ||
158 | return 2; | ||
159 | } | ||
160 | /* turn master object into a server object */ | ||
161 | aux_setclass(L, "tcp{server}", 1); | ||
162 | lua_pushnumber(L, 1); | ||
163 | return 1; | ||
164 | } | ||
165 | |||
166 | /*-------------------------------------------------------------------------*\ | ||
167 | * Waits for and returns a client object attempting connection to the | ||
168 | * server object | ||
169 | \*-------------------------------------------------------------------------*/ | ||
170 | static int tcp_meth_accept(lua_State *L) | ||
171 | { | ||
172 | struct sockaddr_in addr; | ||
173 | size_t addr_len = sizeof(addr); | ||
174 | p_tcp server = (p_tcp) aux_checkclass(L, "tcp{server}", 1); | ||
175 | p_tm tm = &server->tm; | ||
176 | p_tcp client = lua_newuserdata(L, sizeof(t_tcp)); | ||
177 | tm_markstart(tm); | ||
178 | aux_setclass(L, "tcp{client}", -1); | ||
179 | for ( ;; ) { | ||
180 | sock_accept(&server->sock, &client->sock, | ||
181 | (SA *) &addr, &addr_len, tm_get(tm)); | ||
182 | if (client->sock == SOCK_INVALID) { | ||
183 | if (tm_get(tm) == 0) { | ||
184 | lua_pushnil(L); | ||
185 | error_push(L, IO_TIMEOUT); | ||
186 | return 2; | ||
187 | } | ||
188 | } else break; | ||
189 | } | ||
190 | /* initialize remaining structure fields */ | ||
191 | io_init(&client->io, (p_send) sock_send, (p_recv) sock_recv, &client->sock); | ||
192 | tm_init(&client->tm, -1, -1); | ||
193 | buf_init(&client->buf, &client->io, &client->tm); | ||
194 | return 1; | ||
195 | } | ||
196 | |||
197 | /*=========================================================================*\ | ||
198 | * Library functions | ||
199 | \*=========================================================================*/ | ||
200 | /*-------------------------------------------------------------------------*\ | ||
201 | * Creates a master tcp object | ||
202 | \*-------------------------------------------------------------------------*/ | ||
203 | int tcp_global_create(lua_State *L) | ||
204 | { | ||
205 | /* allocate tcp object */ | ||
206 | p_tcp tcp = (p_tcp) lua_newuserdata(L, sizeof(t_tcp)); | ||
207 | /* set its type as master object */ | ||
208 | aux_setclass(L, "tcp{master}", -1); | ||
209 | /* try to allocate a system socket */ | ||
210 | const char *err = inet_trycreate(&tcp->sock, SOCK_STREAM); | ||
211 | if (err) { /* get rid of object on stack and push error */ | ||
212 | lua_pop(L, 1); | ||
213 | lua_pushnil(L); | ||
214 | lua_pushstring(L, err); | ||
215 | return 2; | ||
216 | } | ||
217 | /* initialize remaining structure fields */ | ||
218 | io_init(&tcp->io, (p_send) sock_send, (p_recv) sock_recv, &tcp->sock); | ||
219 | tm_init(&tcp->tm, -1, -1); | ||
220 | buf_init(&tcp->buf, &tcp->io, &tcp->tm); | ||
221 | return 1; | ||
222 | } | ||
diff --git a/src/tcp.h b/src/tcp.h new file mode 100644 index 0000000..d4cc65c --- /dev/null +++ b/src/tcp.h | |||
@@ -0,0 +1,20 @@ | |||
1 | #ifndef TCP_H | ||
2 | #define TCP_H | ||
3 | |||
4 | #include <lua.h> | ||
5 | |||
6 | #include "buf.h" | ||
7 | #include "tm.h" | ||
8 | #include "sock.h" | ||
9 | |||
10 | typedef struct t_tcp_ { | ||
11 | t_sock sock; | ||
12 | t_io io; | ||
13 | t_buf buf; | ||
14 | t_tm tm; | ||
15 | } t_tcp; | ||
16 | typedef t_tcp *p_tcp; | ||
17 | |||
18 | void tcp_open(lua_State *L); | ||
19 | |||
20 | #endif | ||
diff --git a/src/timeout.c b/src/timeout.c index 5549c89..17878aa 100644 --- a/src/timeout.c +++ b/src/timeout.c | |||
@@ -1,18 +1,19 @@ | |||
1 | /*=========================================================================*\ | 1 | /*=========================================================================*\ |
2 | * Timeout management functions | 2 | * Timeout management functions |
3 | * Global Lua functions: | 3 | * Global Lua functions: |
4 | * _sleep: (debug mode only) | 4 | * _sleep |
5 | * _time: (debug mode only) | 5 | * _time |
6 | * | 6 | * |
7 | * RCS ID: $Id$ | 7 | * RCS ID: $Id$ |
8 | \*=========================================================================*/ | 8 | \*=========================================================================*/ |
9 | #include <stdio.h> | ||
10 | |||
9 | #include <lua.h> | 11 | #include <lua.h> |
10 | #include <lauxlib.h> | 12 | #include <lauxlib.h> |
11 | 13 | ||
12 | #include "lspriv.h" | 14 | #include "luasocket.h" |
13 | #include "lstm.h" | 15 | #include "aux.h" |
14 | 16 | #include "tm.h" | |
15 | #include <stdio.h> | ||
16 | 17 | ||
17 | #ifdef WIN32 | 18 | #ifdef WIN32 |
18 | #include <windows.h> | 19 | #include <windows.h> |
@@ -28,78 +29,69 @@ | |||
28 | static int tm_lua_time(lua_State *L); | 29 | static int tm_lua_time(lua_State *L); |
29 | static int tm_lua_sleep(lua_State *L); | 30 | static int tm_lua_sleep(lua_State *L); |
30 | 31 | ||
32 | static luaL_reg func[] = { | ||
33 | { "time", tm_lua_time }, | ||
34 | { "sleep", tm_lua_sleep }, | ||
35 | { NULL, NULL } | ||
36 | }; | ||
37 | |||
31 | /*=========================================================================*\ | 38 | /*=========================================================================*\ |
32 | * Exported functions. | 39 | * Exported functions. |
33 | \*=========================================================================*/ | 40 | \*=========================================================================*/ |
34 | /*-------------------------------------------------------------------------*\ | 41 | /*-------------------------------------------------------------------------*\ |
35 | * Sets timeout limits | 42 | * Initialize structure |
36 | * Input | ||
37 | * tm: timeout control structure | ||
38 | * mode: block or return timeout | ||
39 | * value: timeout value in miliseconds | ||
40 | \*-------------------------------------------------------------------------*/ | 43 | \*-------------------------------------------------------------------------*/ |
41 | void tm_set(p_tm tm, int tm_block, int tm_return) | 44 | void tm_init(p_tm tm, int block, int total) |
42 | { | 45 | { |
43 | tm->tm_block = tm_block; | 46 | tm->block = block; |
44 | tm->tm_return = tm_return; | 47 | tm->total = total; |
45 | } | 48 | } |
46 | 49 | ||
47 | /*-------------------------------------------------------------------------*\ | 50 | /*-------------------------------------------------------------------------*\ |
48 | * Returns timeout limits | 51 | * Set and get timeout limits |
49 | * Input | ||
50 | * tm: timeout control structure | ||
51 | * mode: block or return timeout | ||
52 | * value: timeout value in miliseconds | ||
53 | \*-------------------------------------------------------------------------*/ | 52 | \*-------------------------------------------------------------------------*/ |
54 | void tm_get(p_tm tm, int *tm_block, int *tm_return) | 53 | void tm_setblock(p_tm tm, int block) |
55 | { | 54 | { tm->block = block; } |
56 | if (tm_block) *tm_block = tm->tm_block; | 55 | void tm_settotal(p_tm tm, int total) |
57 | if (tm_return) *tm_return = tm->tm_return; | 56 | { tm->total = total; } |
58 | } | 57 | int tm_getblock(p_tm tm) |
58 | { return tm->block; } | ||
59 | int tm_gettotal(p_tm tm) | ||
60 | { return tm->total; } | ||
61 | int tm_getstart(p_tm tm) | ||
62 | { return tm->start; } | ||
59 | 63 | ||
60 | /*-------------------------------------------------------------------------*\ | 64 | /*-------------------------------------------------------------------------*\ |
61 | * Determines how much time we have left for the current io operation | 65 | * Determines how much time we have left for the current operation |
62 | * an IO write operation. | ||
63 | * Input | 66 | * Input |
64 | * tm: timeout control structure | 67 | * tm: timeout control structure |
65 | * Returns | 68 | * Returns |
66 | * the number of ms left or -1 if there is no time limit | 69 | * the number of ms left or -1 if there is no time limit |
67 | \*-------------------------------------------------------------------------*/ | 70 | \*-------------------------------------------------------------------------*/ |
68 | int tm_getremaining(p_tm tm) | 71 | int tm_get(p_tm tm) |
69 | { | 72 | { |
70 | /* no timeout */ | 73 | /* no timeout */ |
71 | if (tm->tm_block < 0 && tm->tm_return < 0) | 74 | if (tm->block < 0 && tm->total < 0) |
72 | return -1; | 75 | return -1; |
73 | /* there is no block timeout, we use the return timeout */ | 76 | /* there is no block timeout, we use the return timeout */ |
74 | else if (tm->tm_block < 0) | 77 | else if (tm->block < 0) |
75 | return MAX(tm->tm_return - tm_gettime() + tm->tm_start, 0); | 78 | return MAX(tm->total - tm_gettime() + tm->start, 0); |
76 | /* there is no return timeout, we use the block timeout */ | 79 | /* there is no return timeout, we use the block timeout */ |
77 | else if (tm->tm_return < 0) | 80 | else if (tm->total < 0) |
78 | return tm->tm_block; | 81 | return tm->block; |
79 | /* both timeouts are specified */ | 82 | /* both timeouts are specified */ |
80 | else return MIN(tm->tm_block, | 83 | else return MIN(tm->block, |
81 | MAX(tm->tm_return - tm_gettime() + tm->tm_start, 0)); | 84 | MAX(tm->total - tm_gettime() + tm->start, 0)); |
82 | } | 85 | } |
83 | 86 | ||
84 | /*-------------------------------------------------------------------------*\ | 87 | /*-------------------------------------------------------------------------*\ |
85 | * Marks the operation start time in sock structure | 88 | * Marks the operation start time in structure |
86 | * Input | 89 | * Input |
87 | * tm: timeout control structure | 90 | * tm: timeout control structure |
88 | \*-------------------------------------------------------------------------*/ | 91 | \*-------------------------------------------------------------------------*/ |
89 | void tm_markstart(p_tm tm) | 92 | void tm_markstart(p_tm tm) |
90 | { | 93 | { |
91 | tm->tm_start = tm_gettime(); | 94 | tm->start = tm_gettime(); |
92 | tm->tm_end = tm->tm_start; | ||
93 | } | ||
94 | |||
95 | /*-------------------------------------------------------------------------*\ | ||
96 | * Returns the length of the operation in ms | ||
97 | * Input | ||
98 | * tm: timeout control structure | ||
99 | \*-------------------------------------------------------------------------*/ | ||
100 | int tm_getelapsed(p_tm tm) | ||
101 | { | ||
102 | return tm->tm_end - tm->tm_start; | ||
103 | } | 95 | } |
104 | 96 | ||
105 | /*-------------------------------------------------------------------------*\ | 97 | /*-------------------------------------------------------------------------*\ |
@@ -125,11 +117,31 @@ int tm_gettime(void) | |||
125 | \*-------------------------------------------------------------------------*/ | 117 | \*-------------------------------------------------------------------------*/ |
126 | void tm_open(lua_State *L) | 118 | void tm_open(lua_State *L) |
127 | { | 119 | { |
128 | (void) L; | 120 | luaL_openlib(L, LUASOCKET_LIBNAME, func, 0); |
129 | lua_pushcfunction(L, tm_lua_time); | 121 | } |
130 | priv_newglobal(L, "_time"); | 122 | |
131 | lua_pushcfunction(L, tm_lua_sleep); | 123 | /*-------------------------------------------------------------------------*\ |
132 | priv_newglobal(L, "_sleep"); | 124 | * Sets timeout values for IO operations |
125 | * Lua Input: base, time [, mode] | ||
126 | * time: time out value in seconds | ||
127 | * mode: "b" for block timeout, "t" for total timeout. (default: b) | ||
128 | \*-------------------------------------------------------------------------*/ | ||
129 | int tm_meth_timeout(lua_State *L, p_tm tm) | ||
130 | { | ||
131 | int ms = lua_isnil(L, 2) ? -1 : (int) (luaL_checknumber(L, 2)*1000.0); | ||
132 | const char *mode = luaL_optstring(L, 3, "b"); | ||
133 | switch (*mode) { | ||
134 | case 'b': | ||
135 | tm_setblock(tm, ms); | ||
136 | break; | ||
137 | case 'r': case 't': | ||
138 | tm_settotal(tm, ms); | ||
139 | break; | ||
140 | default: | ||
141 | luaL_argcheck(L, 0, 3, "invalid timeout mode"); | ||
142 | break; | ||
143 | } | ||
144 | return 0; | ||
133 | } | 145 | } |
134 | 146 | ||
135 | /*=========================================================================*\ | 147 | /*=========================================================================*\ |
diff --git a/src/timeout.h b/src/timeout.h index 1dc0a5a..43476cb 100644 --- a/src/timeout.h +++ b/src/timeout.h | |||
@@ -3,23 +3,29 @@ | |||
3 | * | 3 | * |
4 | * RCS ID: $Id$ | 4 | * RCS ID: $Id$ |
5 | \*=========================================================================*/ | 5 | \*=========================================================================*/ |
6 | #ifndef _TM_H | 6 | #ifndef TM_H |
7 | #define _TM_H | 7 | #define TM_H |
8 | 8 | ||
9 | typedef struct t_tm_tag { | 9 | #include <lua.h> |
10 | int tm_return; | 10 | |
11 | int tm_block; | 11 | /* timeout control structure */ |
12 | int tm_start; | 12 | typedef struct t_tm_ { |
13 | int tm_end; | 13 | int total; /* total number of miliseconds for operation */ |
14 | int block; /* maximum time for blocking calls */ | ||
15 | int start; /* time of start of operation */ | ||
14 | } t_tm; | 16 | } t_tm; |
15 | typedef t_tm *p_tm; | 17 | typedef t_tm *p_tm; |
16 | 18 | ||
17 | void tm_set(p_tm tm, int tm_block, int tm_return); | ||
18 | int tm_getremaining(p_tm tm); | ||
19 | int tm_getelapsed(p_tm tm); | ||
20 | int tm_gettime(void); | ||
21 | void tm_get(p_tm tm, int *tm_block, int *tm_return); | ||
22 | void tm_markstart(p_tm tm); | ||
23 | void tm_open(lua_State *L); | 19 | void tm_open(lua_State *L); |
20 | void tm_init(p_tm tm, int block, int total); | ||
21 | void tm_setblock(p_tm tm, int block); | ||
22 | void tm_settotal(p_tm tm, int total); | ||
23 | int tm_getblock(p_tm tm); | ||
24 | int tm_gettotal(p_tm tm); | ||
25 | void tm_markstart(p_tm tm); | ||
26 | int tm_getstart(p_tm tm); | ||
27 | int tm_get(p_tm tm); | ||
28 | int tm_gettime(void); | ||
29 | int tm_meth_timeout(lua_State *L, p_tm tm); | ||
24 | 30 | ||
25 | #endif | 31 | #endif |
@@ -1,299 +1,263 @@ | |||
1 | /*=========================================================================*\ | 1 | /*=========================================================================*\ |
2 | * UDP class: inherits from Socked and Internet domain classes and provides | 2 | * UDP object |
3 | * all the functionality for UDP objects. | ||
4 | * Lua methods: | ||
5 | * send: using compat module | ||
6 | * sendto: using compat module | ||
7 | * receive: using compat module | ||
8 | * receivefrom: using compat module | ||
9 | * setpeername: using internet module | ||
10 | * setsockname: using internet module | ||
11 | * Global Lua functions: | ||
12 | * udp: creates the udp object | ||
13 | * | 3 | * |
14 | * RCS ID: $Id$ | 4 | * RCS ID: $Id$ |
15 | \*=========================================================================*/ | 5 | \*=========================================================================*/ |
16 | #include <string.h> | 6 | #include <string.h> |
17 | 7 | ||
18 | #include <lua.h> | 8 | #include <lua.h> |
19 | #include <lauxlib.h> | 9 | #include <lauxlib.h> |
20 | 10 | ||
21 | #include "lsinet.h" | 11 | #include "luasocket.h" |
22 | #include "lsudp.h" | 12 | |
23 | #include "lscompat.h" | 13 | #include "aux.h" |
24 | #include "lsselect.h" | 14 | #include "inet.h" |
15 | #include "udp.h" | ||
25 | 16 | ||
26 | /*=========================================================================*\ | 17 | /*=========================================================================*\ |
27 | * Internal function prototypes. | 18 | * Internal function prototypes |
28 | \*=========================================================================*/ | 19 | \*=========================================================================*/ |
29 | static int udp_lua_send(lua_State *L); | 20 | static int udp_global_create(lua_State *L); |
30 | static int udp_lua_sendto(lua_State *L); | 21 | static int udp_meth_send(lua_State *L); |
31 | static int udp_lua_receive(lua_State *L); | 22 | static int udp_meth_sendto(lua_State *L); |
32 | static int udp_lua_receivefrom(lua_State *L); | 23 | static int udp_meth_receive(lua_State *L); |
33 | static int udp_lua_setpeername(lua_State *L); | 24 | static int udp_meth_receivefrom(lua_State *L); |
34 | static int udp_lua_setsockname(lua_State *L); | 25 | static int udp_meth_getsockname(lua_State *L); |
26 | static int udp_meth_getpeername(lua_State *L); | ||
27 | static int udp_meth_setsockname(lua_State *L); | ||
28 | static int udp_meth_setpeername(lua_State *L); | ||
29 | static int udp_meth_close(lua_State *L); | ||
30 | static int udp_meth_timeout(lua_State *L); | ||
35 | 31 | ||
36 | static int udp_global_udp(lua_State *L); | 32 | /* udp object methods */ |
33 | static luaL_reg udp[] = { | ||
34 | {"setpeername", udp_meth_setpeername}, | ||
35 | {"setsockname", udp_meth_setsockname}, | ||
36 | {"getsockname", udp_meth_getsockname}, | ||
37 | {"getpeername", udp_meth_getpeername}, | ||
38 | {"send", udp_meth_send}, | ||
39 | {"sendto", udp_meth_sendto}, | ||
40 | {"receive", udp_meth_receive}, | ||
41 | {"receivefrom", udp_meth_receivefrom}, | ||
42 | {"timeout", udp_meth_timeout}, | ||
43 | {"close", udp_meth_close}, | ||
44 | {NULL, NULL} | ||
45 | }; | ||
37 | 46 | ||
38 | static struct luaL_reg funcs[] = { | 47 | /* functions in library namespace */ |
39 | {"send", udp_lua_send}, | 48 | static luaL_reg func[] = { |
40 | {"sendto", udp_lua_sendto}, | 49 | {"udp", udp_global_create}, |
41 | {"receive", udp_lua_receive}, | 50 | {NULL, NULL} |
42 | {"receivefrom", udp_lua_receivefrom}, | ||
43 | {"setpeername", udp_lua_setpeername}, | ||
44 | {"setsockname", udp_lua_setsockname}, | ||
45 | }; | 51 | }; |
46 | 52 | ||
47 | /*=========================================================================*\ | ||
48 | * Exported functions | ||
49 | \*=========================================================================*/ | ||
50 | /*-------------------------------------------------------------------------*\ | 53 | /*-------------------------------------------------------------------------*\ |
51 | * Initializes module | 54 | * Initializes module |
52 | \*-------------------------------------------------------------------------*/ | 55 | \*-------------------------------------------------------------------------*/ |
53 | void udp_open(lua_State *L) | 56 | void udp_open(lua_State *L) |
54 | { | 57 | { |
55 | unsigned int i; | 58 | /* create classes */ |
56 | priv_newclass(L, UDP_CLASS); | 59 | aux_newclass(L, "udp{connected}", udp); |
57 | udp_inherit(L, UDP_CLASS); | 60 | aux_newclass(L, "udp{unconnected}", udp); |
58 | /* declare global functions */ | 61 | /* create class groups */ |
59 | lua_pushcfunction(L, udp_global_udp); | 62 | aux_add2group(L, "udp{connected}", "udp{any}"); |
60 | priv_newglobal(L, "udp"); | 63 | aux_add2group(L, "udp{unconnected}", "udp{any}"); |
61 | for (i = 0; i < sizeof(funcs)/sizeof(funcs[0]); i++) | 64 | /* define library functions */ |
62 | priv_newglobalmethod(L, funcs[i].name); | 65 | luaL_openlib(L, LUASOCKET_LIBNAME, func, 0); |
63 | /* make class selectable */ | 66 | lua_pop(L, 1); |
64 | select_addclass(L, UDP_CLASS); | ||
65 | } | ||
66 | |||
67 | /*-------------------------------------------------------------------------*\ | ||
68 | * Hook object methods to methods table. | ||
69 | \*-------------------------------------------------------------------------*/ | ||
70 | void udp_inherit(lua_State *L, cchar *lsclass) | ||
71 | { | ||
72 | unsigned int i; | ||
73 | inet_inherit(L, lsclass); | ||
74 | for (i = 0; i < sizeof(funcs)/sizeof(funcs[0]); i++) { | ||
75 | lua_pushcfunction(L, funcs[i].func); | ||
76 | priv_setmethod(L, lsclass, funcs[i].name); | ||
77 | } | ||
78 | } | 67 | } |
79 | 68 | ||
69 | /*=========================================================================*\ | ||
70 | * Lua methods | ||
71 | \*=========================================================================*/ | ||
80 | /*-------------------------------------------------------------------------*\ | 72 | /*-------------------------------------------------------------------------*\ |
81 | * Initializes socket structure | 73 | * Send data through connected udp socket |
82 | \*-------------------------------------------------------------------------*/ | 74 | \*-------------------------------------------------------------------------*/ |
83 | void udp_construct(lua_State *L, p_udp udp) | 75 | static int udp_meth_send(lua_State *L) |
84 | { | 76 | { |
85 | inet_construct(L, (p_inet) udp); | 77 | p_udp udp = (p_udp) aux_checkclass(L, "udp{connected}", 1); |
86 | udp->udp_connected = 0; | 78 | p_tm tm = &udp->tm; |
79 | size_t count, sent = 0; | ||
80 | int err; | ||
81 | const char *data = luaL_checklstring(L, 2, &count); | ||
82 | tm_markstart(tm); | ||
83 | err = sock_send(&udp->sock, data, count, &sent, tm_get(tm)); | ||
84 | if (err == IO_DONE) lua_pushnumber(L, sent); | ||
85 | else lua_pushnil(L); | ||
86 | error_push(L, err); | ||
87 | return 2; | ||
87 | } | 88 | } |
88 | 89 | ||
89 | /*-------------------------------------------------------------------------*\ | 90 | /*-------------------------------------------------------------------------*\ |
90 | * Creates a socket structure and initializes it. A socket object is | 91 | * Send data through unconnected udp socket |
91 | * left in the Lua stack. | ||
92 | * Returns | ||
93 | * pointer to allocated structure | ||
94 | \*-------------------------------------------------------------------------*/ | 92 | \*-------------------------------------------------------------------------*/ |
95 | p_udp udp_push(lua_State *L) | 93 | static int udp_meth_sendto(lua_State *L) |
96 | { | 94 | { |
97 | p_udp udp = (p_udp) lua_newuserdata(L, sizeof(t_udp)); | 95 | p_udp udp = (p_udp) aux_checkclass(L, "udp{unconnected}", 1); |
98 | priv_setclass(L, UDP_CLASS); | 96 | size_t count, sent = 0; |
99 | udp_construct(L, udp); | 97 | const char *data = luaL_checklstring(L, 2, &count); |
100 | return udp; | 98 | const char *ip = luaL_checkstring(L, 3); |
99 | ushort port = (ushort) luaL_checknumber(L, 4); | ||
100 | p_tm tm = &udp->tm; | ||
101 | struct sockaddr_in addr; | ||
102 | int err; | ||
103 | memset(&addr, 0, sizeof(addr)); | ||
104 | if (!inet_aton(ip, &addr.sin_addr)) | ||
105 | luaL_argerror(L, 3, "invalid ip address"); | ||
106 | addr.sin_family = AF_INET; | ||
107 | addr.sin_port = htons(port); | ||
108 | tm_markstart(tm); | ||
109 | err = sock_sendto(&udp->sock, data, count, &sent, | ||
110 | (SA *) &addr, sizeof(addr), tm_get(tm)); | ||
111 | if (err == IO_DONE) lua_pushnumber(L, sent); | ||
112 | else lua_pushnil(L); | ||
113 | error_push(L, err == IO_CLOSED ? IO_REFUSED : err); | ||
114 | return 2; | ||
101 | } | 115 | } |
102 | 116 | ||
103 | /*=========================================================================*\ | ||
104 | * Socket table constructors | ||
105 | \*=========================================================================*/ | ||
106 | /*-------------------------------------------------------------------------*\ | ||
107 | * Creates a udp socket object and returns it to the Lua script. | ||
108 | * Lua Input: [options] | ||
109 | * options: socket options table | ||
110 | * Lua Returns | ||
111 | * On success: udp socket | ||
112 | * On error: nil, followed by an error message | ||
113 | \*-------------------------------------------------------------------------*/ | ||
114 | static int udp_global_udp(lua_State *L) | ||
115 | { | ||
116 | int oldtop = lua_gettop(L); | ||
117 | p_udp udp = udp_push(L); | ||
118 | cchar *err = inet_trysocket((p_inet) udp, SOCK_DGRAM); | ||
119 | if (err) { | ||
120 | lua_pushnil(L); | ||
121 | lua_pushstring(L, err); | ||
122 | return 2; | ||
123 | } | ||
124 | if (oldtop < 1) return 1; | ||
125 | err = compat_trysetoptions(L, udp->fd); | ||
126 | if (err) { | ||
127 | lua_pushnil(L); | ||
128 | lua_pushstring(L, err); | ||
129 | return 2; | ||
130 | } | ||
131 | return 1; | ||
132 | } | ||
133 | |||
134 | /*=========================================================================*\ | ||
135 | * Socket table methods | ||
136 | \*=========================================================================*/ | ||
137 | /*-------------------------------------------------------------------------*\ | 117 | /*-------------------------------------------------------------------------*\ |
138 | * Receives data from a UDP socket | 118 | * Receives data from a UDP socket |
139 | * Lua Input: sock [, wanted] | ||
140 | * sock: client socket created by the connect function | ||
141 | * wanted: the number of bytes expected (default: LUASOCKET_UDPBUFFERSIZE) | ||
142 | * Lua Returns | ||
143 | * On success: datagram received | ||
144 | * On error: nil, followed by an error message | ||
145 | \*-------------------------------------------------------------------------*/ | 119 | \*-------------------------------------------------------------------------*/ |
146 | static int udp_lua_receive(lua_State *L) | 120 | static int udp_meth_receive(lua_State *L) |
147 | { | 121 | { |
148 | p_udp udp = (p_udp) lua_touserdata(L, 1); | 122 | p_udp udp = (p_udp) aux_checkgroup(L, "udp{any}", 1); |
149 | char buffer[UDP_DATAGRAMSIZE]; | 123 | char buffer[UDP_DATAGRAMSIZE]; |
150 | size_t got, wanted = (size_t) luaL_optnumber(L, 2, sizeof(buffer)); | 124 | size_t got, count = (size_t) luaL_optnumber(L, 2, sizeof(buffer)); |
151 | int err; | 125 | int err; |
152 | p_tm tm = &udp->base_tm; | 126 | p_tm tm = &udp->tm; |
153 | wanted = MIN(wanted, sizeof(buffer)); | 127 | count = MIN(count, sizeof(buffer)); |
154 | tm_markstart(tm); | 128 | tm_markstart(tm); |
155 | err = compat_recv(udp->fd, buffer, wanted, &got, tm_getremaining(tm)); | 129 | err = sock_recv(&udp->sock, buffer, count, &got, tm_get(tm)); |
156 | if (err == PRIV_CLOSED) err = PRIV_REFUSED; | 130 | if (err == IO_DONE) lua_pushlstring(L, buffer, got); |
157 | if (err != PRIV_DONE) lua_pushnil(L); | 131 | else lua_pushnil(L); |
158 | else lua_pushlstring(L, buffer, got); | 132 | error_push(L, err); |
159 | priv_pusherror(L, err); | ||
160 | return 2; | 133 | return 2; |
161 | } | 134 | } |
162 | 135 | ||
163 | /*-------------------------------------------------------------------------*\ | 136 | /*-------------------------------------------------------------------------*\ |
164 | * Receives a datagram from a UDP socket | 137 | * Receives data and sender from a UDP socket |
165 | * Lua Input: sock [, wanted] | ||
166 | * sock: client socket created by the connect function | ||
167 | * wanted: the number of bytes expected (default: LUASOCKET_UDPBUFFERSIZE) | ||
168 | * Lua Returns | ||
169 | * On success: datagram received, ip and port of sender | ||
170 | * On error: nil, followed by an error message | ||
171 | \*-------------------------------------------------------------------------*/ | 138 | \*-------------------------------------------------------------------------*/ |
172 | static int udp_lua_receivefrom(lua_State *L) | 139 | static int udp_meth_receivefrom(lua_State *L) |
173 | { | 140 | { |
174 | p_udp udp = (p_udp) lua_touserdata(L, 1); | 141 | p_udp udp = (p_udp) aux_checkclass(L, "udp{unconnected}", 1); |
175 | p_tm tm = &udp->base_tm; | 142 | struct sockaddr_in addr; |
176 | struct sockaddr_in peer; | 143 | size_t addr_len = sizeof(addr); |
177 | size_t peer_len = sizeof(peer); | ||
178 | char buffer[UDP_DATAGRAMSIZE]; | 144 | char buffer[UDP_DATAGRAMSIZE]; |
179 | size_t wanted = (size_t) luaL_optnumber(L, 2, sizeof(buffer)); | 145 | size_t got, count = (size_t) luaL_optnumber(L, 2, sizeof(buffer)); |
180 | size_t got; | ||
181 | int err; | 146 | int err; |
182 | if (udp->udp_connected) luaL_error(L, "receivefrom on connected socket"); | 147 | p_tm tm = &udp->tm; |
183 | tm_markstart(tm); | 148 | tm_markstart(tm); |
184 | wanted = MIN(wanted, sizeof(buffer)); | 149 | count = MIN(count, sizeof(buffer)); |
185 | err = compat_recvfrom(udp->fd, buffer, wanted, &got, tm_getremaining(tm), | 150 | err = sock_recvfrom(&udp->sock, buffer, count, &got, |
186 | (SA *) &peer, &peer_len); | 151 | (SA *) &addr, &addr_len, tm_get(tm)); |
187 | if (err == PRIV_CLOSED) err = PRIV_REFUSED; | 152 | if (err == IO_DONE) { |
188 | if (err == PRIV_DONE) { | ||
189 | lua_pushlstring(L, buffer, got); | 153 | lua_pushlstring(L, buffer, got); |
190 | lua_pushstring(L, inet_ntoa(peer.sin_addr)); | 154 | lua_pushstring(L, inet_ntoa(addr.sin_addr)); |
191 | lua_pushnumber(L, ntohs(peer.sin_port)); | 155 | lua_pushnumber(L, ntohs(addr.sin_port)); |
192 | return 3; | 156 | return 3; |
193 | } else { | 157 | } else { |
194 | lua_pushnil(L); | 158 | lua_pushnil(L); |
195 | priv_pusherror(L, err); | 159 | error_push(L, err); |
196 | return 2; | 160 | return 2; |
197 | } | 161 | } |
198 | } | 162 | } |
199 | 163 | ||
200 | /*-------------------------------------------------------------------------*\ | 164 | /*-------------------------------------------------------------------------*\ |
201 | * Send data through a connected UDP socket | 165 | * Just call inet methods |
202 | * Lua Input: sock, data | ||
203 | * sock: udp socket | ||
204 | * data: data to be sent | ||
205 | * Lua Returns | ||
206 | * On success: nil, followed by the total number of bytes sent | ||
207 | * On error: error message | ||
208 | \*-------------------------------------------------------------------------*/ | 166 | \*-------------------------------------------------------------------------*/ |
209 | static int udp_lua_send(lua_State *L) | 167 | static int udp_meth_getpeername(lua_State *L) |
210 | { | 168 | { |
211 | p_udp udp = (p_udp) lua_touserdata(L, 1); | 169 | p_udp udp = (p_udp) aux_checkclass(L, "udp{connected}", 1); |
212 | p_tm tm = &udp->base_tm; | 170 | return inet_meth_getpeername(L, &udp->sock); |
213 | size_t wanted, sent = 0; | 171 | } |
214 | int err; | 172 | |
215 | cchar *data = luaL_checklstring(L, 2, &wanted); | 173 | static int udp_meth_getsockname(lua_State *L) |
216 | if (!udp->udp_connected) luaL_error(L, "send on unconnected socket"); | 174 | { |
217 | tm_markstart(tm); | 175 | p_udp udp = (p_udp) aux_checkgroup(L, "udp{any}", 1); |
218 | err = compat_send(udp->fd, data, wanted, &sent, tm_getremaining(tm)); | 176 | return inet_meth_getsockname(L, &udp->sock); |
219 | priv_pusherror(L, err == PRIV_CLOSED ? PRIV_REFUSED : err); | ||
220 | lua_pushnumber(L, sent); | ||
221 | return 2; | ||
222 | } | 177 | } |
223 | 178 | ||
224 | /*-------------------------------------------------------------------------*\ | 179 | /*-------------------------------------------------------------------------*\ |
225 | * Send data through a unconnected UDP socket | 180 | * Just call tm methods |
226 | * Lua Input: sock, data, ip, port | ||
227 | * sock: udp socket | ||
228 | * data: data to be sent | ||
229 | * ip: ip address of target | ||
230 | * port: port in target | ||
231 | * Lua Returns | ||
232 | * On success: nil, followed by the total number of bytes sent | ||
233 | * On error: error message | ||
234 | \*-------------------------------------------------------------------------*/ | 181 | \*-------------------------------------------------------------------------*/ |
235 | static int udp_lua_sendto(lua_State *L) | 182 | static int udp_meth_timeout(lua_State *L) |
236 | { | 183 | { |
237 | p_udp udp = (p_udp) lua_touserdata(L, 1); | 184 | p_udp udp = (p_udp) aux_checkgroup(L, "udp{any}", 1); |
238 | size_t wanted, sent = 0; | 185 | return tm_meth_timeout(L, &udp->tm); |
239 | cchar *data = luaL_checklstring(L, 2, &wanted); | ||
240 | cchar *ip = luaL_checkstring(L, 3); | ||
241 | ushort port = (ushort) luaL_checknumber(L, 4); | ||
242 | p_tm tm = &udp->base_tm; | ||
243 | struct sockaddr_in peer; | ||
244 | int err; | ||
245 | if (udp->udp_connected) luaL_error(L, "sendto on connected socket"); | ||
246 | memset(&peer, 0, sizeof(peer)); | ||
247 | if (!inet_aton(ip, &peer.sin_addr)) luaL_error(L, "invalid ip address"); | ||
248 | peer.sin_family = AF_INET; | ||
249 | peer.sin_port = htons(port); | ||
250 | tm_markstart(tm); | ||
251 | err = compat_sendto(udp->fd, data, wanted, &sent, tm_getremaining(tm), | ||
252 | (SA *) &peer, sizeof(peer)); | ||
253 | priv_pusherror(L, err == PRIV_CLOSED ? PRIV_REFUSED : err); | ||
254 | lua_pushnumber(L, sent); | ||
255 | return 2; | ||
256 | } | 186 | } |
257 | 187 | ||
258 | /*-------------------------------------------------------------------------*\ | 188 | /*-------------------------------------------------------------------------*\ |
259 | * Associates a local address to an UDP socket | 189 | * Turns a master udp object into a client object. |
260 | * Lua Input: address, port | ||
261 | * address: host name or ip address to bind to | ||
262 | * port: port to bind to | ||
263 | * Lua Returns | ||
264 | * On success: nil | ||
265 | * On error: error message | ||
266 | \*-------------------------------------------------------------------------*/ | 190 | \*-------------------------------------------------------------------------*/ |
267 | static int udp_lua_setsockname(lua_State * L) | 191 | static int udp_meth_setpeername(lua_State *L) |
268 | { | 192 | { |
269 | p_udp udp = (p_udp) lua_touserdata(L, 1); | 193 | p_udp udp = (p_udp) aux_checkclass(L, "udp{unconnected}", 1); |
270 | cchar *address = luaL_checkstring(L, 2); | 194 | const char *address = luaL_checkstring(L, 2); |
271 | ushort port = (ushort) luaL_checknumber(L, 3); | 195 | int connecting = strcmp(address, "*"); |
272 | cchar *err = inet_trybind((p_inet) udp, address, port); | 196 | unsigned short port = connecting ? |
273 | if (err) lua_pushstring(L, err); | 197 | (ushort) luaL_checknumber(L, 3) : (ushort) luaL_optnumber(L, 3, 0); |
274 | else lua_pushnil(L); | 198 | const char *err = inet_tryconnect(&udp->sock, address, port); |
199 | if (err) { | ||
200 | lua_pushnil(L); | ||
201 | lua_pushstring(L, err); | ||
202 | return 2; | ||
203 | } | ||
204 | /* change class to connected or unconnected depending on address */ | ||
205 | if (connecting) aux_setclass(L, "udp{connected}", 1); | ||
206 | else aux_setclass(L, "udp{unconnected}", 1); | ||
207 | lua_pushnumber(L, 1); | ||
275 | return 1; | 208 | return 1; |
276 | } | 209 | } |
277 | 210 | ||
278 | /*-------------------------------------------------------------------------*\ | 211 | /*-------------------------------------------------------------------------*\ |
279 | * Sets a peer for a UDP socket | 212 | * Closes socket used by object |
280 | * Lua Input: address, port | 213 | \*-------------------------------------------------------------------------*/ |
281 | * address: remote host name | 214 | static int udp_meth_close(lua_State *L) |
282 | * port: remote host port | 215 | { |
283 | * Lua Returns | 216 | p_udp udp = (p_udp) aux_checkgroup(L, "udp{any}", 1); |
284 | * On success: nil | 217 | sock_destroy(&udp->sock); |
285 | * On error: error message | 218 | return 0; |
219 | } | ||
220 | |||
221 | /*-------------------------------------------------------------------------*\ | ||
222 | * Turns a master object into a server object | ||
286 | \*-------------------------------------------------------------------------*/ | 223 | \*-------------------------------------------------------------------------*/ |
287 | static int udp_lua_setpeername(lua_State *L) | 224 | static int udp_meth_setsockname(lua_State *L) |
288 | { | 225 | { |
289 | p_udp udp = (p_udp) lua_touserdata(L, 1); | 226 | p_udp udp = (p_udp) aux_checkclass(L, "udp{master}", 1); |
290 | cchar *address = luaL_checkstring(L, 2); | 227 | const char *address = luaL_checkstring(L, 2); |
291 | ushort port = (ushort) luaL_checknumber(L, 3); | 228 | unsigned short port = (ushort) luaL_checknumber(L, 3); |
292 | cchar *err = inet_tryconnect((p_inet) udp, address, port); | 229 | const char *err = inet_trybind(&udp->sock, address, port, -1); |
293 | if (!err) { | 230 | if (err) { |
294 | udp->udp_connected = 1; | ||
295 | lua_pushnil(L); | 231 | lua_pushnil(L); |
296 | } else lua_pushstring(L, err); | 232 | lua_pushstring(L, err); |
233 | return 2; | ||
234 | } | ||
235 | lua_pushnumber(L, 1); | ||
297 | return 1; | 236 | return 1; |
298 | } | 237 | } |
299 | 238 | ||
239 | /*=========================================================================*\ | ||
240 | * Library functions | ||
241 | \*=========================================================================*/ | ||
242 | /*-------------------------------------------------------------------------*\ | ||
243 | * Creates a master udp object | ||
244 | \*-------------------------------------------------------------------------*/ | ||
245 | int udp_global_create(lua_State *L) | ||
246 | { | ||
247 | /* allocate udp object */ | ||
248 | p_udp udp = (p_udp) lua_newuserdata(L, sizeof(t_udp)); | ||
249 | /* set its type as master object */ | ||
250 | aux_setclass(L, "udp{unconnected}", -1); | ||
251 | /* try to allocate a system socket */ | ||
252 | const char *err = inet_trycreate(&udp->sock, SOCK_DGRAM); | ||
253 | if (err) { | ||
254 | /* get rid of object on stack and push error */ | ||
255 | lua_pop(L, 1); | ||
256 | lua_pushnil(L); | ||
257 | lua_pushstring(L, err); | ||
258 | return 2; | ||
259 | } | ||
260 | /* initialize timeout management */ | ||
261 | tm_init(&udp->tm, -1, -1); | ||
262 | return 1; | ||
263 | } | ||
@@ -1,30 +1,19 @@ | |||
1 | /*=========================================================================*\ | 1 | #ifndef UDP_H |
2 | * UDP class: inherits from Socked and Internet domain classes and provides | 2 | #define UDP_H |
3 | * all the functionality for UDP objects. | ||
4 | * | ||
5 | * RCS ID: $Id$ | ||
6 | \*=========================================================================*/ | ||
7 | #ifndef UDP_H_ | ||
8 | #define UDP_H_ | ||
9 | 3 | ||
10 | #include "lsinet.h" | 4 | #include <lua.h> |
11 | 5 | ||
12 | #define UDP_CLASS "luasocket(UDP socket)" | 6 | #include "tm.h" |
7 | #include "sock.h" | ||
13 | 8 | ||
14 | #define UDP_DATAGRAMSIZE 576 | 9 | #define UDP_DATAGRAMSIZE 576 |
15 | 10 | ||
16 | #define UDP_FIELDS \ | 11 | typedef struct t_udp_ { |
17 | INET_FIELDS; \ | 12 | t_sock sock; |
18 | int udp_connected | 13 | t_tm tm; |
19 | |||
20 | typedef struct t_udp_tag { | ||
21 | UDP_FIELDS; | ||
22 | } t_udp; | 14 | } t_udp; |
23 | typedef t_udp *p_udp; | 15 | typedef t_udp *p_udp; |
24 | 16 | ||
25 | void udp_inherit(lua_State *L, cchar *lsclass); | ||
26 | void udp_construct(lua_State *L, p_udp udp); | ||
27 | void udp_open(lua_State *L); | 17 | void udp_open(lua_State *L); |
28 | p_udp udp_push(lua_State *L); | ||
29 | 18 | ||
30 | #endif | 19 | #endif |
diff --git a/src/unix.c b/src/usocket.c index 23984b0..b4b8d5a 100644 --- a/src/unix.c +++ b/src/usocket.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /*=========================================================================*\ | 1 | /*=========================================================================*\ |
2 | * Network compatibilization module: Unix version | 2 | * Socket compatibilization module for Unix |
3 | * | 3 | * |
4 | * RCS ID: $Id$ | 4 | * RCS ID: $Id$ |
5 | \*=========================================================================*/ | 5 | \*=========================================================================*/ |
@@ -7,20 +7,20 @@ | |||
7 | #include <lauxlib.h> | 7 | #include <lauxlib.h> |
8 | #include <string.h> | 8 | #include <string.h> |
9 | 9 | ||
10 | #include "lscompat.h" | 10 | #include "sock.h" |
11 | 11 | ||
12 | /*=========================================================================*\ | 12 | /*=========================================================================*\ |
13 | * Internal function prototypes | 13 | * Internal function prototypes |
14 | \*=========================================================================*/ | 14 | \*=========================================================================*/ |
15 | static cchar *try_setoption(lua_State *L, COMPAT_FD sock); | 15 | static const char *try_setoption(lua_State *L, p_sock ps); |
16 | static cchar *try_setbooloption(lua_State *L, COMPAT_FD sock, int name); | 16 | static const char *try_setbooloption(lua_State *L, p_sock ps, int name); |
17 | 17 | ||
18 | /*=========================================================================*\ | 18 | /*=========================================================================*\ |
19 | * Exported functions. | 19 | * Exported functions. |
20 | \*=========================================================================*/ | 20 | \*=========================================================================*/ |
21 | int compat_open(lua_State *L) | 21 | int sock_open(lua_State *L) |
22 | { | 22 | { |
23 | /* Instals a handler to ignore sigpipe. */ | 23 | /* instals a handler to ignore sigpipe. */ |
24 | struct sigaction new; | 24 | struct sigaction new; |
25 | memset(&new, 0, sizeof(new)); | 25 | memset(&new, 0, sizeof(new)); |
26 | new.sa_handler = SIG_IGN; | 26 | new.sa_handler = SIG_IGN; |
@@ -28,143 +28,178 @@ int compat_open(lua_State *L) | |||
28 | return 1; | 28 | return 1; |
29 | } | 29 | } |
30 | 30 | ||
31 | COMPAT_FD compat_accept(COMPAT_FD s, struct sockaddr *addr, | 31 | void sock_destroy(p_sock ps) |
32 | size_t *len, int deadline) | ||
33 | { | 32 | { |
33 | close(*ps); | ||
34 | } | ||
35 | |||
36 | const char *sock_create(p_sock ps, int domain, int type, int protocol) | ||
37 | { | ||
38 | t_sock sock = socket(domain, type, protocol); | ||
39 | if (sock == SOCK_INVALID) return sock_createstrerror(); | ||
40 | *ps = sock; | ||
41 | sock_setnonblocking(ps); | ||
42 | sock_setreuseaddr(ps); | ||
43 | return NULL; | ||
44 | } | ||
45 | |||
46 | const char *sock_connect(p_sock ps, SA *addr, size_t addr_len) | ||
47 | { | ||
48 | if (connect(*ps, addr, addr_len) < 0) return sock_connectstrerror(); | ||
49 | else return NULL; | ||
50 | } | ||
51 | |||
52 | const char *sock_bind(p_sock ps, SA *addr, size_t addr_len) | ||
53 | { | ||
54 | if (bind(*ps, addr, addr_len) < 0) return sock_bindstrerror(); | ||
55 | else return NULL; | ||
56 | } | ||
57 | |||
58 | void sock_listen(p_sock ps, int backlog) | ||
59 | { | ||
60 | listen(*ps, backlog); | ||
61 | } | ||
62 | |||
63 | void sock_accept(p_sock ps, p_sock pa, SA *addr, size_t *addr_len, int timeout) | ||
64 | { | ||
65 | t_sock sock = *ps; | ||
34 | struct timeval tv; | 66 | struct timeval tv; |
35 | fd_set fds; | 67 | fd_set fds; |
36 | tv.tv_sec = deadline / 1000; | 68 | tv.tv_sec = timeout / 1000; |
37 | tv.tv_usec = (deadline % 1000) * 1000; | 69 | tv.tv_usec = (timeout % 1000) * 1000; |
38 | FD_ZERO(&fds); | 70 | FD_ZERO(&fds); |
39 | FD_SET(s, &fds); | 71 | FD_SET(sock, &fds); |
40 | select(s+1, &fds, NULL, NULL, deadline >= 0 ? &tv : NULL); | 72 | select(sock+1, &fds, NULL, NULL, timeout >= 0 ? &tv : NULL); |
41 | return accept(s, addr, len); | 73 | *pa = accept(sock, addr, addr_len); |
42 | } | 74 | } |
43 | 75 | ||
44 | int compat_send(COMPAT_FD c, cchar *data, size_t count, size_t *sent, | 76 | int sock_send(p_sock ps, const char *data, size_t count, size_t *sent, |
45 | int deadline) | 77 | int timeout) |
46 | { | 78 | { |
79 | t_sock sock = *ps; | ||
47 | struct timeval tv; | 80 | struct timeval tv; |
48 | fd_set fds; | 81 | fd_set fds; |
49 | ssize_t put = 0; | 82 | ssize_t put = 0; |
50 | int err; | 83 | int err; |
51 | int ret; | 84 | int ret; |
52 | tv.tv_sec = deadline / 1000; | 85 | tv.tv_sec = timeout / 1000; |
53 | tv.tv_usec = (deadline % 1000) * 1000; | 86 | tv.tv_usec = (timeout % 1000) * 1000; |
54 | FD_ZERO(&fds); | 87 | FD_ZERO(&fds); |
55 | FD_SET(c, &fds); | 88 | FD_SET(sock, &fds); |
56 | ret = select(c+1, NULL, &fds, NULL, deadline >= 0 ? &tv : NULL); | 89 | ret = select(sock+1, NULL, &fds, NULL, timeout >= 0 ? &tv : NULL); |
57 | if (ret > 0) { | 90 | if (ret > 0) { |
58 | put = write(c, data, count); | 91 | put = write(sock, data, count); |
59 | if (put <= 0) { | 92 | if (put <= 0) { |
60 | err = PRIV_CLOSED; | 93 | err = IO_CLOSED; |
61 | #ifdef __CYGWIN__ | 94 | #ifdef __CYGWIN__ |
62 | /* this is for CYGWIN, which is like Unix but has Win32 bugs */ | 95 | /* this is for CYGWIN, which is like Unix but has Win32 bugs */ |
63 | if (errno == EWOULDBLOCK) err = PRIV_DONE; | 96 | if (errno == EWOULDBLOCK) err = IO_DONE; |
64 | #endif | 97 | #endif |
65 | *sent = 0; | 98 | *sent = 0; |
66 | } else { | 99 | } else { |
67 | *sent = put; | 100 | *sent = put; |
68 | err = PRIV_DONE; | 101 | err = IO_DONE; |
69 | } | 102 | } |
70 | return err; | 103 | return err; |
71 | } else { | 104 | } else { |
72 | *sent = 0; | 105 | *sent = 0; |
73 | return PRIV_TIMEOUT; | 106 | return IO_TIMEOUT; |
74 | } | 107 | } |
75 | } | 108 | } |
76 | 109 | ||
77 | int compat_sendto(COMPAT_FD c, cchar *data, size_t count, size_t *sent, | 110 | int sock_sendto(p_sock ps, const char *data, size_t count, size_t *sent, |
78 | int deadline, SA *addr, size_t len) | 111 | SA *addr, size_t addr_len, int timeout) |
79 | { | 112 | { |
113 | t_sock sock = *ps; | ||
80 | struct timeval tv; | 114 | struct timeval tv; |
81 | fd_set fds; | 115 | fd_set fds; |
82 | ssize_t put = 0; | 116 | ssize_t put = 0; |
83 | int err; | 117 | int err; |
84 | int ret; | 118 | int ret; |
85 | tv.tv_sec = deadline / 1000; | 119 | tv.tv_sec = timeout / 1000; |
86 | tv.tv_usec = (deadline % 1000) * 1000; | 120 | tv.tv_usec = (timeout % 1000) * 1000; |
87 | FD_ZERO(&fds); | 121 | FD_ZERO(&fds); |
88 | FD_SET(c, &fds); | 122 | FD_SET(sock, &fds); |
89 | ret = select(c+1, NULL, &fds, NULL, deadline >= 0 ? &tv : NULL); | 123 | ret = select(sock+1, NULL, &fds, NULL, timeout >= 0 ? &tv : NULL); |
90 | if (ret > 0) { | 124 | if (ret > 0) { |
91 | put = sendto(c, data, count, 0, addr, len); | 125 | put = sendto(sock, data, count, 0, addr, addr_len); |
92 | if (put <= 0) { | 126 | if (put <= 0) { |
93 | err = PRIV_CLOSED; | 127 | err = IO_CLOSED; |
94 | #ifdef __CYGWIN__ | 128 | #ifdef __CYGWIN__ |
95 | /* this is for CYGWIN, which is like Unix but has Win32 bugs */ | 129 | /* this is for CYGWIN, which is like Unix but has Win32 bugs */ |
96 | if (sent < 0 && errno == EWOULDBLOCK) err = PRIV_DONE; | 130 | if (sent < 0 && errno == EWOULDBLOCK) err = IO_DONE; |
97 | #endif | 131 | #endif |
98 | *sent = 0; | 132 | *sent = 0; |
99 | } else { | 133 | } else { |
100 | *sent = put; | 134 | *sent = put; |
101 | err = PRIV_DONE; | 135 | err = IO_DONE; |
102 | } | 136 | } |
103 | return err; | 137 | return err; |
104 | } else { | 138 | } else { |
105 | *sent = 0; | 139 | *sent = 0; |
106 | return PRIV_TIMEOUT; | 140 | return IO_TIMEOUT; |
107 | } | 141 | } |
108 | } | 142 | } |
109 | 143 | ||
110 | int compat_recv(COMPAT_FD c, char *data, size_t count, size_t *got, | 144 | int sock_recv(p_sock ps, char *data, size_t count, size_t *got, int timeout) |
111 | int deadline) | ||
112 | { | 145 | { |
146 | t_sock sock = *ps; | ||
113 | struct timeval tv; | 147 | struct timeval tv; |
114 | fd_set fds; | 148 | fd_set fds; |
115 | int ret; | 149 | int ret; |
116 | ssize_t taken = 0; | 150 | ssize_t taken = 0; |
117 | tv.tv_sec = deadline / 1000; | 151 | tv.tv_sec = timeout / 1000; |
118 | tv.tv_usec = (deadline % 1000) * 1000; | 152 | tv.tv_usec = (timeout % 1000) * 1000; |
119 | FD_ZERO(&fds); | 153 | FD_ZERO(&fds); |
120 | FD_SET(c, &fds); | 154 | FD_SET(sock, &fds); |
121 | ret = select(c+1, &fds, NULL, NULL, deadline >= 0 ? &tv : NULL); | 155 | ret = select(sock+1, &fds, NULL, NULL, timeout >= 0 ? &tv : NULL); |
122 | if (ret > 0) { | 156 | if (ret > 0) { |
123 | taken = read(c, data, count); | 157 | taken = read(sock, data, count); |
124 | if (taken <= 0) { | 158 | if (taken <= 0) { |
125 | *got = 0; | 159 | *got = 0; |
126 | return PRIV_CLOSED; | 160 | return IO_CLOSED; |
127 | } else { | 161 | } else { |
128 | *got = taken; | 162 | *got = taken; |
129 | return PRIV_DONE; | 163 | return IO_DONE; |
130 | } | 164 | } |
131 | } else { | 165 | } else { |
132 | *got = 0; | 166 | *got = 0; |
133 | return PRIV_TIMEOUT; | 167 | return IO_TIMEOUT; |
134 | } | 168 | } |
135 | } | 169 | } |
136 | 170 | ||
137 | int compat_recvfrom(COMPAT_FD c, char *data, size_t count, size_t *got, | 171 | int sock_recvfrom(p_sock ps, char *data, size_t count, size_t *got, |
138 | int deadline, SA *addr, size_t *len) | 172 | SA *addr, size_t *addr_len, int timeout) |
139 | { | 173 | { |
174 | t_sock sock = *ps; | ||
140 | struct timeval tv; | 175 | struct timeval tv; |
141 | fd_set fds; | 176 | fd_set fds; |
142 | int ret; | 177 | int ret; |
143 | ssize_t taken = 0; | 178 | ssize_t taken = 0; |
144 | tv.tv_sec = deadline / 1000; | 179 | tv.tv_sec = timeout / 1000; |
145 | tv.tv_usec = (deadline % 1000) * 1000; | 180 | tv.tv_usec = (timeout % 1000) * 1000; |
146 | FD_ZERO(&fds); | 181 | FD_ZERO(&fds); |
147 | FD_SET(c, &fds); | 182 | FD_SET(sock, &fds); |
148 | ret = select(c+1, &fds, NULL, NULL, deadline >= 0 ? &tv : NULL); | 183 | ret = select(sock+1, &fds, NULL, NULL, timeout >= 0 ? &tv : NULL); |
149 | if (ret > 0) { | 184 | if (ret > 0) { |
150 | taken = recvfrom(c, data, count, 0, addr, len); | 185 | taken = recvfrom(sock, data, count, 0, addr, addr_len); |
151 | if (taken <= 0) { | 186 | if (taken <= 0) { |
152 | *got = 0; | 187 | *got = 0; |
153 | return PRIV_CLOSED; | 188 | return IO_CLOSED; |
154 | } else { | 189 | } else { |
155 | *got = taken; | 190 | *got = taken; |
156 | return PRIV_DONE; | 191 | return IO_DONE; |
157 | } | 192 | } |
158 | } else { | 193 | } else { |
159 | *got = 0; | 194 | *got = 0; |
160 | return PRIV_TIMEOUT; | 195 | return IO_TIMEOUT; |
161 | } | 196 | } |
162 | } | 197 | } |
163 | 198 | ||
164 | /*-------------------------------------------------------------------------*\ | 199 | /*-------------------------------------------------------------------------*\ |
165 | * Returns a string describing the last host manipulation error. | 200 | * Returns a string describing the last host manipulation error. |
166 | \*-------------------------------------------------------------------------*/ | 201 | \*-------------------------------------------------------------------------*/ |
167 | const char *compat_hoststrerror(void) | 202 | const char *sock_hoststrerror(void) |
168 | { | 203 | { |
169 | switch (h_errno) { | 204 | switch (h_errno) { |
170 | case HOST_NOT_FOUND: return "host not found"; | 205 | case HOST_NOT_FOUND: return "host not found"; |
@@ -178,7 +213,7 @@ const char *compat_hoststrerror(void) | |||
178 | /*-------------------------------------------------------------------------*\ | 213 | /*-------------------------------------------------------------------------*\ |
179 | * Returns a string describing the last socket manipulation error. | 214 | * Returns a string describing the last socket manipulation error. |
180 | \*-------------------------------------------------------------------------*/ | 215 | \*-------------------------------------------------------------------------*/ |
181 | const char *compat_socketstrerror(void) | 216 | const char *sock_createstrerror(void) |
182 | { | 217 | { |
183 | switch (errno) { | 218 | switch (errno) { |
184 | case EACCES: return "access denied"; | 219 | case EACCES: return "access denied"; |
@@ -192,7 +227,7 @@ const char *compat_socketstrerror(void) | |||
192 | /*-------------------------------------------------------------------------*\ | 227 | /*-------------------------------------------------------------------------*\ |
193 | * Returns a string describing the last bind command error. | 228 | * Returns a string describing the last bind command error. |
194 | \*-------------------------------------------------------------------------*/ | 229 | \*-------------------------------------------------------------------------*/ |
195 | const char *compat_bindstrerror(void) | 230 | const char *sock_bindstrerror(void) |
196 | { | 231 | { |
197 | switch (errno) { | 232 | switch (errno) { |
198 | case EBADF: return "invalid descriptor"; | 233 | case EBADF: return "invalid descriptor"; |
@@ -209,7 +244,7 @@ const char *compat_bindstrerror(void) | |||
209 | /*-------------------------------------------------------------------------*\ | 244 | /*-------------------------------------------------------------------------*\ |
210 | * Returns a string describing the last connect error. | 245 | * Returns a string describing the last connect error. |
211 | \*-------------------------------------------------------------------------*/ | 246 | \*-------------------------------------------------------------------------*/ |
212 | const char *compat_connectstrerror(void) | 247 | const char *sock_connectstrerror(void) |
213 | { | 248 | { |
214 | switch (errno) { | 249 | switch (errno) { |
215 | case EBADF: return "invalid descriptor"; | 250 | case EBADF: return "invalid descriptor"; |
@@ -229,40 +264,30 @@ const char *compat_connectstrerror(void) | |||
229 | * Input | 264 | * Input |
230 | * sock: socket descriptor | 265 | * sock: socket descriptor |
231 | \*-------------------------------------------------------------------------*/ | 266 | \*-------------------------------------------------------------------------*/ |
232 | void compat_setreuseaddr(COMPAT_FD sock) | 267 | void sock_setreuseaddr(p_sock ps) |
233 | { | 268 | { |
234 | int val = 1; | 269 | int val = 1; |
235 | setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&val, sizeof(val)); | 270 | setsockopt(*ps, SOL_SOCKET, SO_REUSEADDR, (char *)&val, sizeof(val)); |
236 | } | ||
237 | |||
238 | COMPAT_FD compat_socket(int domain, int type, int protocol) | ||
239 | { | ||
240 | COMPAT_FD sock = socket(domain, type, protocol); | ||
241 | if (sock != COMPAT_INVALIDFD) { | ||
242 | compat_setnonblocking(sock); | ||
243 | compat_setreuseaddr(sock); | ||
244 | } | ||
245 | return sock; | ||
246 | } | 271 | } |
247 | 272 | ||
248 | /*-------------------------------------------------------------------------*\ | 273 | /*-------------------------------------------------------------------------*\ |
249 | * Put socket into blocking mode. | 274 | * Put socket into blocking mode. |
250 | \*-------------------------------------------------------------------------*/ | 275 | \*-------------------------------------------------------------------------*/ |
251 | void compat_setblocking(COMPAT_FD sock) | 276 | void sock_setblocking(p_sock ps) |
252 | { | 277 | { |
253 | int flags = fcntl(sock, F_GETFL, 0); | 278 | int flags = fcntl(*ps, F_GETFL, 0); |
254 | flags &= (~(O_NONBLOCK)); | 279 | flags &= (~(O_NONBLOCK)); |
255 | fcntl(sock, F_SETFL, flags); | 280 | fcntl(*ps, F_SETFL, flags); |
256 | } | 281 | } |
257 | 282 | ||
258 | /*-------------------------------------------------------------------------*\ | 283 | /*-------------------------------------------------------------------------*\ |
259 | * Put socket into non-blocking mode. | 284 | * Put socket into non-blocking mode. |
260 | \*-------------------------------------------------------------------------*/ | 285 | \*-------------------------------------------------------------------------*/ |
261 | void compat_setnonblocking(COMPAT_FD sock) | 286 | void sock_setnonblocking(p_sock ps) |
262 | { | 287 | { |
263 | int flags = fcntl(sock, F_GETFL, 0); | 288 | int flags = fcntl(*ps, F_GETFL, 0); |
264 | flags |= O_NONBLOCK; | 289 | flags |= O_NONBLOCK; |
265 | fcntl(sock, F_SETFL, flags); | 290 | fcntl(*ps, F_SETFL, flags); |
266 | } | 291 | } |
267 | 292 | ||
268 | /*-------------------------------------------------------------------------*\ | 293 | /*-------------------------------------------------------------------------*\ |
@@ -273,54 +298,50 @@ void compat_setnonblocking(COMPAT_FD sock) | |||
273 | * Returns | 298 | * Returns |
274 | * NULL if successfull, error message on error | 299 | * NULL if successfull, error message on error |
275 | \*-------------------------------------------------------------------------*/ | 300 | \*-------------------------------------------------------------------------*/ |
276 | cchar *compat_trysetoptions(lua_State *L, COMPAT_FD sock) | 301 | const char *sock_trysetoptions(lua_State *L, p_sock ps) |
277 | { | 302 | { |
278 | if (!lua_istable(L, 1)) luaL_argerror(L, 1, "invalid options table"); | 303 | if (!lua_istable(L, 1)) luaL_argerror(L, 1, "invalid options table"); |
279 | lua_pushnil(L); | 304 | lua_pushnil(L); |
280 | while (lua_next(L, 1)) { | 305 | while (lua_next(L, 1)) { |
281 | cchar *err = try_setoption(L, sock); | 306 | const char *err = try_setoption(L, ps); |
282 | lua_pop(L, 1); | 307 | lua_pop(L, 1); |
283 | if (err) return err; | 308 | if (err) return err; |
284 | } | 309 | } |
285 | return NULL; | 310 | return NULL; |
286 | } | 311 | } |
287 | 312 | ||
288 | /*=========================================================================*\ | ||
289 | * Internal functions. | ||
290 | \*=========================================================================*/ | ||
291 | static cchar *try_setbooloption(lua_State *L, COMPAT_FD sock, int name) | ||
292 | { | ||
293 | int bool, res; | ||
294 | if (!lua_isnumber(L, -1)) luaL_error(L, "invalid option value"); | ||
295 | bool = (int) lua_tonumber(L, -1); | ||
296 | res = setsockopt(sock, SOL_SOCKET, name, (char *) &bool, sizeof(bool)); | ||
297 | if (res < 0) return "error setting option"; | ||
298 | else return NULL; | ||
299 | } | ||
300 | |||
301 | |||
302 | /*-------------------------------------------------------------------------*\ | 313 | /*-------------------------------------------------------------------------*\ |
303 | * Set socket options from a table on top of Lua stack. | 314 | * Set socket options from a table on top of Lua stack. |
304 | * Supports SO_KEEPALIVE, SO_DONTROUTE, SO_BROADCAST, and SO_LINGER options. | 315 | * Supports SO_KEEPALIVE, SO_DONTROUTE, and SO_BROADCAST options. |
305 | * Input | 316 | * Input |
306 | * L: Lua state to use | 317 | * sock: socket |
307 | * sock: socket descriptor | ||
308 | * Returns | 318 | * Returns |
309 | * 1 if successful, 0 otherwise | 319 | * 1 if successful, 0 otherwise |
310 | \*-------------------------------------------------------------------------*/ | 320 | \*-------------------------------------------------------------------------*/ |
311 | static cchar *try_setoption(lua_State *L, COMPAT_FD sock) | 321 | static const char *try_setoption(lua_State *L, p_sock ps) |
312 | { | 322 | { |
313 | static cchar *options[] = { | 323 | static const char *options[] = { |
314 | "SO_KEEPALIVE", "SO_DONTROUTE", "SO_BROADCAST", "SO_LINGER", NULL | 324 | "SO_KEEPALIVE", "SO_DONTROUTE", "SO_BROADCAST", NULL |
315 | }; | 325 | }; |
316 | cchar *option = lua_tostring(L, -2); | 326 | const char *option = lua_tostring(L, -2); |
317 | if (!lua_isstring(L, -2)) return "invalid option"; | 327 | if (!lua_isstring(L, -2)) return "invalid option"; |
318 | switch (luaL_findstring(option, options)) { | 328 | switch (luaL_findstring(option, options)) { |
319 | case 0: return try_setbooloption(L, sock, SO_KEEPALIVE); | 329 | case 0: return try_setbooloption(L, ps, SO_KEEPALIVE); |
320 | case 1: return try_setbooloption(L, sock, SO_DONTROUTE); | 330 | case 1: return try_setbooloption(L, ps, SO_DONTROUTE); |
321 | case 2: return try_setbooloption(L, sock, SO_BROADCAST); | 331 | case 2: return try_setbooloption(L, ps, SO_BROADCAST); |
322 | case 3: return "SO_LINGER is deprecated"; | ||
323 | default: return "unsupported option"; | 332 | default: return "unsupported option"; |
324 | } | 333 | } |
325 | } | 334 | } |
326 | 335 | ||
336 | /*=========================================================================*\ | ||
337 | * Internal functions. | ||
338 | \*=========================================================================*/ | ||
339 | static const char *try_setbooloption(lua_State *L, p_sock ps, int name) | ||
340 | { | ||
341 | int bool, res; | ||
342 | if (!lua_isnumber(L, -1)) luaL_error(L, "invalid option value"); | ||
343 | bool = (int) lua_tonumber(L, -1); | ||
344 | res = setsockopt(*ps, SOL_SOCKET, name, (char *) &bool, sizeof(bool)); | ||
345 | if (res < 0) return "error setting option"; | ||
346 | else return NULL; | ||
347 | } | ||
diff --git a/src/unix.h b/src/usocket.h index 863e478..f124bce 100644 --- a/src/unix.h +++ b/src/usocket.h | |||
@@ -1,10 +1,10 @@ | |||
1 | /*=========================================================================*\ | 1 | /*=========================================================================*\ |
2 | * Network compatibilization module: Unix version | 2 | * Socket compatibilization module for Unix |
3 | * | 3 | * |
4 | * RCS ID: $Id$ | 4 | * RCS ID: $Id$ |
5 | \*=========================================================================*/ | 5 | \*=========================================================================*/ |
6 | #ifndef UNIX_H_ | 6 | #ifndef UNIX_H |
7 | #define UNIX_H_ | 7 | #define UNIX_H |
8 | 8 | ||
9 | /*=========================================================================*\ | 9 | /*=========================================================================*\ |
10 | * BSD include files | 10 | * BSD include files |
@@ -31,13 +31,9 @@ | |||
31 | #include <netinet/in.h> | 31 | #include <netinet/in.h> |
32 | #include <arpa/inet.h> | 32 | #include <arpa/inet.h> |
33 | 33 | ||
34 | #define COMPAT_FD int | 34 | typedef int t_sock; |
35 | #define COMPAT_INVALIDFD (-1) | 35 | typedef t_sock *p_sock; |
36 | 36 | ||
37 | #define compat_bind bind | 37 | #define SOCK_INVALID (-1) |
38 | #define compat_connect connect | ||
39 | #define compat_listen listen | ||
40 | #define compat_close close | ||
41 | #define compat_select select | ||
42 | 38 | ||
43 | #endif /* UNIX_H_ */ | 39 | #endif /* UNIX_H */ |
diff --git a/test/ftptest.lua b/test/ftptest.lua index ee3af91..6ba61a4 100644 --- a/test/ftptest.lua +++ b/test/ftptest.lua | |||
@@ -1,5 +1,3 @@ | |||
1 | dofile("noglobals.lua") | ||
2 | |||
3 | local similar = function(s1, s2) | 1 | local similar = function(s1, s2) |
4 | return | 2 | return |
5 | string.lower(string.gsub(s1, "%s", "")) == | 3 | string.lower(string.gsub(s1, "%s", "")) == |
@@ -34,7 +32,7 @@ end | |||
34 | 32 | ||
35 | local index, err, saved, back, expected | 33 | local index, err, saved, back, expected |
36 | 34 | ||
37 | local t = socket._time() | 35 | local t = socket.time() |
38 | 36 | ||
39 | index = readfile("test/index.html") | 37 | index = readfile("test/index.html") |
40 | 38 | ||
@@ -112,4 +110,4 @@ back, err = socket.ftp.get("ftp://localhost/index.wrong.html;type=a") | |||
112 | check(err, err) | 110 | check(err, err) |
113 | 111 | ||
114 | print("passed all tests") | 112 | print("passed all tests") |
115 | print(string.format("done in %.2fs", socket._time() - t)) | 113 | print(string.format("done in %.2fs", socket.time() - t)) |
diff --git a/test/httptest.lua b/test/httptest.lua index 1eb4b6a..030974c 100644 --- a/test/httptest.lua +++ b/test/httptest.lua | |||
@@ -3,9 +3,6 @@ | |||
3 | -- needs ScriptAlias from /home/c/diego/tec/luasocket/test/cgi | 3 | -- needs ScriptAlias from /home/c/diego/tec/luasocket/test/cgi |
4 | -- to /luasocket-test-cgi | 4 | -- to /luasocket-test-cgi |
5 | -- needs AllowOverride AuthConfig on /home/c/diego/tec/luasocket/test/auth | 5 | -- needs AllowOverride AuthConfig on /home/c/diego/tec/luasocket/test/auth |
6 | |||
7 | dofile("noglobals.lua") | ||
8 | |||
9 | local similar = function(s1, s2) | 6 | local similar = function(s1, s2) |
10 | return string.lower(string.gsub(s1 or "", "%s", "")) == | 7 | return string.lower(string.gsub(s1 or "", "%s", "")) == |
11 | string.lower(string.gsub(s2 or "", "%s", "")) | 8 | string.lower(string.gsub(s2 or "", "%s", "")) |
@@ -27,27 +24,27 @@ end | |||
27 | 24 | ||
28 | local check = function (v, e) | 25 | local check = function (v, e) |
29 | if v then print("ok") | 26 | if v then print("ok") |
30 | else %fail(e) end | 27 | else fail(e) end |
31 | end | 28 | end |
32 | 29 | ||
33 | local check_request = function(request, expect, ignore) | 30 | local check_request = function(request, expect, ignore) |
34 | local response = socket.http.request(request) | 31 | local response = socket.http.request(request) |
35 | for i,v in response do | 32 | for i,v in response do |
36 | if not ignore[i] then | 33 | if not ignore[i] then |
37 | if v ~= expect[i] then %fail(i .. " differs!") end | 34 | if v ~= expect[i] then fail(i .. " differs!") end |
38 | end | 35 | end |
39 | end | 36 | end |
40 | for i,v in expect do | 37 | for i,v in expect do |
41 | if not ignore[i] then | 38 | if not ignore[i] then |
42 | if v ~= response[i] then %fail(i .. " differs!") end | 39 | if v ~= response[i] then fail(i .. " differs!") end |
43 | end | 40 | end |
44 | end | 41 | end |
45 | print("ok") | 42 | print("ok") |
46 | end | 43 | end |
47 | 44 | ||
48 | local request, response, ignore, expect, index, prefix, cgiprefix | 45 | local host, request, response, ignore, expect, index, prefix, cgiprefix |
49 | 46 | ||
50 | local t = socket._time() | 47 | local t = socket.time() |
51 | 48 | ||
52 | host = host or "localhost" | 49 | host = host or "localhost" |
53 | prefix = prefix or "/luasocket" | 50 | prefix = prefix or "/luasocket" |
@@ -310,4 +307,4 @@ check(response and response.headers) | |||
310 | 307 | ||
311 | print("passed all tests") | 308 | print("passed all tests") |
312 | 309 | ||
313 | print(string.format("done in %.2fs", socket._time() - t)) | 310 | print(string.format("done in %.2fs", socket.time() - t)) |
diff --git a/test/smtptest.lua b/test/smtptest.lua index 27ba400..09bf634 100644 --- a/test/smtptest.lua +++ b/test/smtptest.lua | |||
@@ -11,7 +11,7 @@ local files = { | |||
11 | "/var/spool/mail/luasock3", | 11 | "/var/spool/mail/luasock3", |
12 | } | 12 | } |
13 | 13 | ||
14 | local t = socket._time() | 14 | local t = socket.time() |
15 | local err | 15 | local err |
16 | 16 | ||
17 | dofile("mbox.lua") | 17 | dofile("mbox.lua") |
@@ -106,7 +106,7 @@ local insert = function(sent, message) | |||
106 | end | 106 | end |
107 | 107 | ||
108 | local mark = function() | 108 | local mark = function() |
109 | local time = socket._time() | 109 | local time = socket.time() |
110 | return { time = time } | 110 | return { time = time } |
111 | end | 111 | end |
112 | 112 | ||
@@ -116,11 +116,11 @@ local wait = function(sentinel, n) | |||
116 | while 1 do | 116 | while 1 do |
117 | local mbox = parse(get()) | 117 | local mbox = parse(get()) |
118 | if n == table.getn(mbox) then break end | 118 | if n == table.getn(mbox) then break end |
119 | if socket._time() - sentinel.time > 50 then | 119 | if socket.time() - sentinel.time > 50 then |
120 | to = 1 | 120 | to = 1 |
121 | break | 121 | break |
122 | end | 122 | end |
123 | socket._sleep(1) | 123 | socket.sleep(1) |
124 | io.write(".") | 124 | io.write(".") |
125 | io.stdout:flush() | 125 | io.stdout:flush() |
126 | end | 126 | end |
@@ -256,4 +256,4 @@ for i = 1, table.getn(mbox) do | |||
256 | end | 256 | end |
257 | 257 | ||
258 | print("passed all tests") | 258 | print("passed all tests") |
259 | print(string.format("done in %.2fs", socket._time() - t)) | 259 | print(string.format("done in %.2fs", socket.time() - t)) |
diff --git a/test/testclnt.lua b/test/testclnt.lua index 3e80a36..b2b4b18 100644 --- a/test/testclnt.lua +++ b/test/testclnt.lua | |||
@@ -43,7 +43,7 @@ function check_timeout(tm, sl, elapsed, err, opp, mode, alldone) | |||
43 | else pass("proper timeout") end | 43 | else pass("proper timeout") end |
44 | end | 44 | end |
45 | else | 45 | else |
46 | if mode == "return" then | 46 | if mode == "total" then |
47 | if elapsed > tm then | 47 | if elapsed > tm then |
48 | if err ~= "timeout" then fail("should have timed out") | 48 | if err ~= "timeout" then fail("should have timed out") |
49 | else pass("proper timeout") end | 49 | else pass("proper timeout") end |
@@ -66,17 +66,17 @@ function check_timeout(tm, sl, elapsed, err, opp, mode, alldone) | |||
66 | end | 66 | end |
67 | end | 67 | end |
68 | 68 | ||
69 | if not socket.debug then | ||
70 | fail("Please define LUASOCKET_DEBUG and recompile LuaSocket") | ||
71 | end | ||
72 | |||
69 | io.write("----------------------------------------------\n", | 73 | io.write("----------------------------------------------\n", |
70 | "LuaSocket Test Procedures\n", | 74 | "LuaSocket Test Procedures\n", |
71 | "----------------------------------------------\n") | 75 | "----------------------------------------------\n") |
72 | 76 | ||
73 | if not socket._time or not socket._sleep then | 77 | start = socket.time() |
74 | fail("not compiled with _DEBUG") | ||
75 | end | ||
76 | |||
77 | start = socket._time() | ||
78 | 78 | ||
79 | function tcpreconnect() | 79 | function reconnect() |
80 | io.write("attempting data connection... ") | 80 | io.write("attempting data connection... ") |
81 | if data then data:close() end | 81 | if data then data:close() end |
82 | remote [[ | 82 | remote [[ |
@@ -87,7 +87,6 @@ function tcpreconnect() | |||
87 | if not data then fail(err) | 87 | if not data then fail(err) |
88 | else pass("connected!") end | 88 | else pass("connected!") end |
89 | end | 89 | end |
90 | reconnect = tcpreconnect | ||
91 | 90 | ||
92 | pass("attempting control connection...") | 91 | pass("attempting control connection...") |
93 | control, err = socket.connect(host, port) | 92 | control, err = socket.connect(host, port) |
@@ -95,101 +94,78 @@ if err then fail(err) | |||
95 | else pass("connected!") end | 94 | else pass("connected!") end |
96 | 95 | ||
97 | ------------------------------------------------------------------------ | 96 | ------------------------------------------------------------------------ |
98 | test("bugs") | ||
99 | |||
100 | io.write("empty host connect: ") | ||
101 | function empty_connect() | ||
102 | if data then data:close() data = nil end | ||
103 | remote [[ | ||
104 | if data then data:close() data = nil end | ||
105 | data = server:accept() | ||
106 | ]] | ||
107 | data, err = socket.connect("", port) | ||
108 | if not data then | ||
109 | pass("ok") | ||
110 | data = socket.connect(host, port) | ||
111 | else fail("should not have connected!") end | ||
112 | end | ||
113 | |||
114 | empty_connect() | ||
115 | |||
116 | io.write("active close: ") | ||
117 | function active_close() | ||
118 | reconnect() | ||
119 | if socket._isclosed(data) then fail("should not be closed") end | ||
120 | data:close() | ||
121 | if not socket._isclosed(data) then fail("should be closed") end | ||
122 | data = nil | ||
123 | local udp = socket.udp() | ||
124 | if socket._isclosed(udp) then fail("should not be closed") end | ||
125 | udp:close() | ||
126 | if not socket._isclosed(udp) then fail("should be closed") end | ||
127 | pass("ok") | ||
128 | end | ||
129 | |||
130 | active_close() | ||
131 | |||
132 | ------------------------------------------------------------------------ | ||
133 | test("method registration") | 97 | test("method registration") |
134 | 98 | ||
135 | function test_methods(sock, methods) | 99 | function test_methods(sock, methods) |
136 | for _, v in methods do | 100 | for _, v in methods do |
137 | if type(sock[v]) ~= "function" then | 101 | if type(sock[v]) ~= "function" then |
138 | fail(type(sock) .. " method " .. v .. "not registered") | 102 | fail(sock.class .. " method '" .. v .. "' not registered") |
139 | end | 103 | end |
140 | end | 104 | end |
141 | pass(type(sock) .. " methods are ok") | 105 | pass(sock.class .. " methods are ok") |
142 | end | 106 | end |
143 | 107 | ||
144 | test_methods(control, { | 108 | test_methods(socket.tcp(), { |
145 | "close", | 109 | "connect", |
146 | "timeout", | 110 | "send", |
147 | "send", | 111 | "receive", |
148 | "receive", | 112 | "bind", |
113 | "accept", | ||
114 | "setpeername", | ||
115 | "setsockname", | ||
149 | "getpeername", | 116 | "getpeername", |
150 | "getsockname" | 117 | "getsockname", |
118 | "timeout", | ||
119 | "close", | ||
151 | }) | 120 | }) |
152 | 121 | ||
153 | if udpsocket then | 122 | test_methods(socket.udp(), { |
154 | test_methods(socket.udp(), { | 123 | "getpeername", |
155 | "close", | 124 | "getsockname", |
156 | "timeout", | 125 | "setsockname", |
157 | "send", | 126 | "setpeername", |
158 | "sendto", | 127 | "send", |
159 | "receive", | 128 | "sendto", |
160 | "receivefrom", | 129 | "receive", |
161 | "getpeername", | 130 | "receivefrom", |
162 | "getsockname", | ||
163 | "setsockname", | ||
164 | "setpeername" | ||
165 | }) | ||
166 | end | ||
167 | |||
168 | test_methods(socket.bind("*", 0), { | ||
169 | "close", | ||
170 | "timeout", | 131 | "timeout", |
171 | "accept" | 132 | "close", |
172 | }) | 133 | }) |
173 | 134 | ||
174 | ------------------------------------------------------------------------ | 135 | ------------------------------------------------------------------------ |
175 | test("select function") | 136 | test("mixed patterns") |
176 | function test_selectbugs() | 137 | |
177 | local r, s, e = socket.select(nil, nil, 0.1) | 138 | function test_mixed(len) |
178 | assert(type(r) == "table" and type(s) == "table" and e == "timeout") | 139 | reconnect() |
179 | pass("both nil: ok") | 140 | local inter = math.ceil(len/4) |
180 | local udp = socket.udp() | 141 | local p1 = "unix " .. string.rep("x", inter) .. "line\n" |
181 | udp:close() | 142 | local p2 = "dos " .. string.rep("y", inter) .. "line\r\n" |
182 | r, s, e = socket.select({ udp }, { udp }, 0.1) | 143 | local p3 = "raw " .. string.rep("z", inter) .. "bytes" |
183 | assert(type(r) == "table" and type(s) == "table" and e == "timeout") | 144 | local p4 = "end" .. string.rep("w", inter) .. "bytes" |
184 | pass("closed sockets: ok") | 145 | local bp1, bp2, bp3, bp4 |
185 | e = pcall(socket.select, "wrong", 1, 0.1) | 146 | pass(len .. " byte(s) patterns") |
186 | assert(e == false) | 147 | remote (string.format("str = data:receive(%d)", |
187 | e = pcall(socket.select, {}, 1, 0.1) | 148 | string.len(p1)+string.len(p2)+string.len(p3)+string.len(p4))) |
188 | assert(e == false) | 149 | sent, err = data:send(p1, p2, p3, p4) |
189 | pass("invalid input: ok") | 150 | if err then fail(err) end |
151 | remote "data:send(str); data:close()" | ||
152 | bp1, bp2, bp3, bp4, err = data:receive("*l", "*l", string.len(p3), "*a") | ||
153 | if err then fail(err) end | ||
154 | if bp1.."\n" == p1 and bp2.."\r\n" == p2 and bp3 == p3 and bp4 == p4 then | ||
155 | pass("patterns match") | ||
156 | else fail("patterns don't match") end | ||
190 | end | 157 | end |
191 | 158 | ||
192 | test_selectbugs() | 159 | |
160 | test_mixed(1) | ||
161 | test_mixed(17) | ||
162 | test_mixed(200) | ||
163 | test_mixed(4091) | ||
164 | test_mixed(80199) | ||
165 | test_mixed(4091) | ||
166 | test_mixed(200) | ||
167 | test_mixed(17) | ||
168 | test_mixed(1) | ||
193 | 169 | ||
194 | ------------------------------------------------------------------------ | 170 | ------------------------------------------------------------------------ |
195 | test("character line") | 171 | test("character line") |
@@ -202,7 +178,7 @@ function test_asciiline(len) | |||
202 | str = str .. str10 | 178 | str = str .. str10 |
203 | pass(len .. " byte(s) line") | 179 | pass(len .. " byte(s) line") |
204 | remote "str = data:receive()" | 180 | remote "str = data:receive()" |
205 | err = data:send(str, "\n") | 181 | sent, err = data:send(str, "\n") |
206 | if err then fail(err) end | 182 | if err then fail(err) end |
207 | remote "data:send(str, '\\n')" | 183 | remote "data:send(str, '\\n')" |
208 | back, err = data:receive() | 184 | back, err = data:receive() |
@@ -230,7 +206,7 @@ function test_rawline(len) | |||
230 | str = str .. str10 | 206 | str = str .. str10 |
231 | pass(len .. " byte(s) line") | 207 | pass(len .. " byte(s) line") |
232 | remote "str = data:receive()" | 208 | remote "str = data:receive()" |
233 | err = data:send(str, "\n") | 209 | sent, err = data:send(str, "\n") |
234 | if err then fail(err) end | 210 | if err then fail(err) end |
235 | remote "data:send(str, '\\n')" | 211 | remote "data:send(str, '\\n')" |
236 | back, err = data:receive() | 212 | back, err = data:receive() |
@@ -262,9 +238,9 @@ function test_raw(len) | |||
262 | s2 = string.rep("y", len-half) | 238 | s2 = string.rep("y", len-half) |
263 | pass(len .. " byte(s) block") | 239 | pass(len .. " byte(s) block") |
264 | remote (string.format("str = data:receive(%d)", len)) | 240 | remote (string.format("str = data:receive(%d)", len)) |
265 | err = data:send(s1) | 241 | sent, err = data:send(s1) |
266 | if err then fail(err) end | 242 | if err then fail(err) end |
267 | err = data:send(s2) | 243 | sent, err = data:send(s2) |
268 | if err then fail(err) end | 244 | if err then fail(err) end |
269 | remote "data:send(str)" | 245 | remote "data:send(str)" |
270 | back, err = data:receive(len) | 246 | back, err = data:receive(len) |
@@ -304,127 +280,54 @@ test_raw(17) | |||
304 | test_raw(1) | 280 | test_raw(1) |
305 | 281 | ||
306 | ------------------------------------------------------------------------ | 282 | ------------------------------------------------------------------------ |
307 | test("mixed patterns") | 283 | test("total timeout on receive") |
308 | reconnect() | 284 | function test_totaltimeoutreceive(len, tm, sl) |
309 | |||
310 | function test_mixed(len) | ||
311 | local inter = math.floor(len/3) | ||
312 | local p1 = "unix " .. string.rep("x", inter) .. "line\n" | ||
313 | local p2 = "dos " .. string.rep("y", inter) .. "line\r\n" | ||
314 | local p3 = "raw " .. string.rep("z", inter) .. "bytes" | ||
315 | local bp1, bp2, bp3 | ||
316 | pass(len .. " byte(s) patterns") | ||
317 | remote (string.format("str = data:receive(%d)", | ||
318 | string.len(p1)+string.len(p2)+string.len(p3))) | ||
319 | err = data:send(p1, p2, p3) | ||
320 | if err then fail(err) end | ||
321 | remote "data:send(str)" | ||
322 | bp1, bp2, bp3, err = data:receive("*lu", "*l", string.len(p3)) | ||
323 | if err then fail(err) end | ||
324 | if bp1.."\n" == p1 and bp2.."\r\n" == p2 and bp3 == p3 then | ||
325 | pass("patterns match") | ||
326 | else fail("patterns don't match") end | ||
327 | end | ||
328 | |||
329 | test_mixed(1) | ||
330 | test_mixed(17) | ||
331 | test_mixed(200) | ||
332 | test_mixed(4091) | ||
333 | test_mixed(80199) | ||
334 | test_mixed(800000) | ||
335 | test_mixed(80199) | ||
336 | test_mixed(4091) | ||
337 | test_mixed(200) | ||
338 | test_mixed(17) | ||
339 | test_mixed(1) | ||
340 | |||
341 | ------------------------------------------------------------------------ | ||
342 | test("closed connection detection") | ||
343 | |||
344 | function test_closed() | ||
345 | local back, err | ||
346 | local str = 'little string' | ||
347 | reconnect() | ||
348 | pass("trying read detection") | ||
349 | remote (string.format ([[ | ||
350 | data:send('%s') | ||
351 | data:close() | ||
352 | data = nil | ||
353 | ]], str)) | ||
354 | -- try to get a line | ||
355 | back, err = data:receive() | ||
356 | if not err then fail("shold have gotten 'closed'.") | ||
357 | elseif err ~= "closed" then fail("got '"..err.."' instead of 'closed'.") | ||
358 | elseif str ~= back then fail("didn't receive partial result.") | ||
359 | else pass("graceful 'closed' received") end | ||
360 | reconnect() | ||
361 | pass("trying write detection") | ||
362 | remote [[ | ||
363 | data:close() | ||
364 | data = nil | ||
365 | ]] | ||
366 | err, total = data:send(string.rep("ugauga", 100000)) | ||
367 | if not err then | ||
368 | pass("failed: output buffer is at least %d bytes long!", total) | ||
369 | elseif err ~= "closed" then | ||
370 | fail("got '"..err.."' instead of 'closed'.") | ||
371 | else | ||
372 | pass("graceful 'closed' received after %d bytes were sent", total) | ||
373 | end | ||
374 | end | ||
375 | |||
376 | test_closed() | ||
377 | |||
378 | ------------------------------------------------------------------------ | ||
379 | test("return timeout on receive") | ||
380 | function test_blockingtimeoutreceive(len, tm, sl) | ||
381 | local str, err, total | 285 | local str, err, total |
382 | reconnect() | 286 | reconnect() |
383 | pass("%d bytes, %ds return timeout, %ds pause", len, tm, sl) | 287 | pass("%d bytes, %ds total timeout, %ds pause", len, tm, sl) |
384 | remote (string.format ([[ | 288 | remote (string.format ([[ |
385 | data:timeout(%d) | 289 | data:timeout(%d) |
386 | str = string.rep('a', %d) | 290 | str = string.rep('a', %d) |
387 | data:send(str) | 291 | data:send(str) |
388 | print('server: sleeping for %ds') | 292 | print('server: sleeping for %ds') |
389 | socket._sleep(%d) | 293 | socket.sleep(%d) |
390 | print('server: woke up') | 294 | print('server: woke up') |
391 | data:send(str) | 295 | data:send(str) |
392 | ]], 2*tm, len, sl, sl)) | 296 | ]], 2*tm, len, sl, sl)) |
393 | data:timeout(tm, "return") | 297 | data:timeout(tm, "total") |
394 | str, err, elapsed = data:receive(2*len) | 298 | str, err, elapsed = data:receive(2*len) |
395 | check_timeout(tm, sl, elapsed, err, "receive", "return", | 299 | check_timeout(tm, sl, elapsed, err, "receive", "total", |
396 | string.len(str) == 2*len) | 300 | string.len(str) == 2*len) |
397 | end | 301 | end |
398 | test_blockingtimeoutreceive(800091, 1, 3) | 302 | test_totaltimeoutreceive(800091, 1, 3) |
399 | test_blockingtimeoutreceive(800091, 2, 3) | 303 | test_totaltimeoutreceive(800091, 2, 3) |
400 | test_blockingtimeoutreceive(800091, 3, 2) | 304 | test_totaltimeoutreceive(800091, 3, 2) |
401 | test_blockingtimeoutreceive(800091, 3, 1) | 305 | test_totaltimeoutreceive(800091, 3, 1) |
402 | 306 | ||
403 | ------------------------------------------------------------------------ | 307 | ------------------------------------------------------------------------ |
404 | test("return timeout on send") | 308 | test("total timeout on send") |
405 | function test_returntimeoutsend(len, tm, sl) | 309 | function test_totaltimeoutsend(len, tm, sl) |
406 | local str, err, total | 310 | local str, err, total |
407 | reconnect() | 311 | reconnect() |
408 | pass("%d bytes, %ds return timeout, %ds pause", len, tm, sl) | 312 | pass("%d bytes, %ds total timeout, %ds pause", len, tm, sl) |
409 | remote (string.format ([[ | 313 | remote (string.format ([[ |
410 | data:timeout(%d) | 314 | data:timeout(%d) |
411 | str = data:receive(%d) | 315 | str = data:receive(%d) |
412 | print('server: sleeping for %ds') | 316 | print('server: sleeping for %ds') |
413 | socket._sleep(%d) | 317 | socket.sleep(%d) |
414 | print('server: woke up') | 318 | print('server: woke up') |
415 | str = data:receive(%d) | 319 | str = data:receive(%d) |
416 | ]], 2*tm, len, sl, sl, len)) | 320 | ]], 2*tm, len, sl, sl, len)) |
417 | data:timeout(tm, "return") | 321 | data:timeout(tm, "total") |
418 | str = string.rep("a", 2*len) | 322 | str = string.rep("a", 2*len) |
419 | err, total, elapsed = data:send(str) | 323 | total, err, elapsed = data:send(str) |
420 | check_timeout(tm, sl, elapsed, err, "send", "return", | 324 | check_timeout(tm, sl, elapsed, err, "send", "total", |
421 | total == 2*len) | 325 | total == 2*len) |
422 | end | 326 | end |
423 | test_returntimeoutsend(800091, 1, 3) | 327 | test_totaltimeoutsend(800091, 1, 3) |
424 | test_returntimeoutsend(800091, 2, 3) | 328 | test_totaltimeoutsend(800091, 2, 3) |
425 | test_returntimeoutsend(800091, 3, 2) | 329 | test_totaltimeoutsend(800091, 3, 2) |
426 | test_returntimeoutsend(800091, 3, 1) | 330 | test_totaltimeoutsend(800091, 3, 1) |
427 | |||
428 | 331 | ||
429 | ------------------------------------------------------------------------ | 332 | ------------------------------------------------------------------------ |
430 | test("blocking timeout on receive") | 333 | test("blocking timeout on receive") |
@@ -437,7 +340,7 @@ function test_blockingtimeoutreceive(len, tm, sl) | |||
437 | str = string.rep('a', %d) | 340 | str = string.rep('a', %d) |
438 | data:send(str) | 341 | data:send(str) |
439 | print('server: sleeping for %ds') | 342 | print('server: sleeping for %ds') |
440 | socket._sleep(%d) | 343 | socket.sleep(%d) |
441 | print('server: woke up') | 344 | print('server: woke up') |
442 | data:send(str) | 345 | data:send(str) |
443 | ]], 2*tm, len, sl, sl)) | 346 | ]], 2*tm, len, sl, sl)) |
@@ -451,7 +354,6 @@ test_blockingtimeoutreceive(800091, 2, 3) | |||
451 | test_blockingtimeoutreceive(800091, 3, 2) | 354 | test_blockingtimeoutreceive(800091, 3, 2) |
452 | test_blockingtimeoutreceive(800091, 3, 1) | 355 | test_blockingtimeoutreceive(800091, 3, 1) |
453 | 356 | ||
454 | |||
455 | ------------------------------------------------------------------------ | 357 | ------------------------------------------------------------------------ |
456 | test("blocking timeout on send") | 358 | test("blocking timeout on send") |
457 | function test_blockingtimeoutsend(len, tm, sl) | 359 | function test_blockingtimeoutsend(len, tm, sl) |
@@ -462,13 +364,13 @@ function test_blockingtimeoutsend(len, tm, sl) | |||
462 | data:timeout(%d) | 364 | data:timeout(%d) |
463 | str = data:receive(%d) | 365 | str = data:receive(%d) |
464 | print('server: sleeping for %ds') | 366 | print('server: sleeping for %ds') |
465 | socket._sleep(%d) | 367 | socket.sleep(%d) |
466 | print('server: woke up') | 368 | print('server: woke up') |
467 | str = data:receive(%d) | 369 | str = data:receive(%d) |
468 | ]], 2*tm, len, sl, sl, len)) | 370 | ]], 2*tm, len, sl, sl, len)) |
469 | data:timeout(tm) | 371 | data:timeout(tm) |
470 | str = string.rep("a", 2*len) | 372 | str = string.rep("a", 2*len) |
471 | err, total, elapsed = data:send(str) | 373 | total, err, elapsed = data:send(str) |
472 | check_timeout(tm, sl, elapsed, err, "send", "blocking", | 374 | check_timeout(tm, sl, elapsed, err, "send", "blocking", |
473 | total == 2*len) | 375 | total == 2*len) |
474 | end | 376 | end |
@@ -478,4 +380,98 @@ test_blockingtimeoutsend(800091, 3, 2) | |||
478 | test_blockingtimeoutsend(800091, 3, 1) | 380 | test_blockingtimeoutsend(800091, 3, 1) |
479 | 381 | ||
480 | ------------------------------------------------------------------------ | 382 | ------------------------------------------------------------------------ |
481 | test(string.format("done in %.2fs", socket._time() - start)) | 383 | test("bugs") |
384 | |||
385 | io.write("empty host connect: ") | ||
386 | function empty_connect() | ||
387 | if data then data:close() data = nil end | ||
388 | remote [[ | ||
389 | if data then data:close() data = nil end | ||
390 | data = server:accept() | ||
391 | ]] | ||
392 | data, err = socket.connect("", port) | ||
393 | if not data then | ||
394 | pass("ok") | ||
395 | data = socket.connect(host, port) | ||
396 | else fail("should not have connected!") end | ||
397 | end | ||
398 | |||
399 | empty_connect() | ||
400 | |||
401 | -- io.write("active close: ") | ||
402 | function active_close() | ||
403 | reconnect() | ||
404 | if socket._isclosed(data) then fail("should not be closed") end | ||
405 | data:close() | ||
406 | if not socket._isclosed(data) then fail("should be closed") end | ||
407 | data = nil | ||
408 | local udp = socket.udp() | ||
409 | if socket._isclosed(udp) then fail("should not be closed") end | ||
410 | udp:close() | ||
411 | if not socket._isclosed(udp) then fail("should be closed") end | ||
412 | pass("ok") | ||
413 | end | ||
414 | |||
415 | -- active_close() | ||
416 | |||
417 | ------------------------------------------------------------------------ | ||
418 | test("closed connection detection") | ||
419 | |||
420 | function test_closed() | ||
421 | local back, err | ||
422 | local str = 'little string' | ||
423 | reconnect() | ||
424 | pass("trying read detection") | ||
425 | remote (string.format ([[ | ||
426 | data:send('%s') | ||
427 | data:close() | ||
428 | data = nil | ||
429 | ]], str)) | ||
430 | -- try to get a line | ||
431 | back, err = data:receive() | ||
432 | if not err then fail("shold have gotten 'closed'.") | ||
433 | elseif err ~= "closed" then fail("got '"..err.."' instead of 'closed'.") | ||
434 | elseif str ~= back then fail("didn't receive partial result.") | ||
435 | else pass("graceful 'closed' received") end | ||
436 | reconnect() | ||
437 | pass("trying write detection") | ||
438 | remote [[ | ||
439 | data:close() | ||
440 | data = nil | ||
441 | ]] | ||
442 | total, err = data:send(string.rep("ugauga", 100000)) | ||
443 | if not err then | ||
444 | pass("failed: output buffer is at least %d bytes long!", total) | ||
445 | elseif err ~= "closed" then | ||
446 | fail("got '"..err.."' instead of 'closed'.") | ||
447 | else | ||
448 | pass("graceful 'closed' received after %d bytes were sent", total) | ||
449 | end | ||
450 | end | ||
451 | |||
452 | test_closed() | ||
453 | |||
454 | ------------------------------------------------------------------------ | ||
455 | test("select function") | ||
456 | function test_selectbugs() | ||
457 | local r, s, e = socket.select(nil, nil, 0.1) | ||
458 | assert(type(r) == "table" and type(s) == "table" and e == "timeout") | ||
459 | pass("both nil: ok") | ||
460 | local udp = socket.udp() | ||
461 | udp:close() | ||
462 | r, s, e = socket.select({ udp }, { udp }, 0.1) | ||
463 | assert(type(r) == "table" and type(s) == "table" and e == "timeout") | ||
464 | pass("closed sockets: ok") | ||
465 | e = pcall(socket.select, "wrong", 1, 0.1) | ||
466 | assert(e == false) | ||
467 | e = pcall(socket.select, {}, 1, 0.1) | ||
468 | assert(e == false) | ||
469 | pass("invalid input: ok") | ||
470 | end | ||
471 | |||
472 | -- test_selectbugs() | ||
473 | |||
474 | |||
475 | |||
476 | |||
477 | test(string.format("done in %.2fs", socket.time() - start)) | ||
diff --git a/test/testsrvr.lua b/test/testsrvr.lua index fb77ea5..3c40840 100644 --- a/test/testsrvr.lua +++ b/test/testsrvr.lua | |||
@@ -13,12 +13,13 @@ while 1 do | |||
13 | print("server: closing connection...") | 13 | print("server: closing connection...") |
14 | break | 14 | break |
15 | end | 15 | end |
16 | error = control:send("\n") | 16 | sent, error = control:send("\n") |
17 | if error then | 17 | if error then |
18 | control:close() | 18 | control:close() |
19 | print("server: closing connection...") | 19 | print("server: closing connection...") |
20 | break | 20 | break |
21 | end | 21 | end |
22 | print(command); | ||
22 | (loadstring(command))() | 23 | (loadstring(command))() |
23 | end | 24 | end |
24 | end | 25 | end |
diff --git a/test/tftptest.lua b/test/tftptest.lua index a435ad4..a478ed8 100644 --- a/test/tftptest.lua +++ b/test/tftptest.lua | |||
@@ -1,5 +1,5 @@ | |||
1 | -- load tftpclnt.lua | 1 | -- load tftpclnt.lua |
2 | dofile("tftpclnt.lua") | 2 | dofile("tftp.lua") |
3 | 3 | ||
4 | -- needs tftp server running on localhost, with root pointing to | 4 | -- needs tftp server running on localhost, with root pointing to |
5 | -- a directory with index.html in it | 5 | -- a directory with index.html in it |
@@ -13,11 +13,8 @@ function readfile(file) | |||
13 | end | 13 | end |
14 | 14 | ||
15 | host = host or "localhost" | 15 | host = host or "localhost" |
16 | print("downloading") | 16 | retrieved, err = socket.tftp.get("tftp://" .. host .."/index.html") |
17 | err = tftp_get(host, 69, "index.html", "index.got") | ||
18 | assert(not err, err) | 17 | assert(not err, err) |
19 | original = readfile("test/index.html") | 18 | original = readfile("test/index.html") |
20 | retrieved = readfile("index.got") | ||
21 | os.remove("index.got") | ||
22 | assert(original == retrieved, "files differ!") | 19 | assert(original == retrieved, "files differ!") |
23 | print("passed") | 20 | print("passed") |