aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEW25
-rw-r--r--etc/tftp.lua131
-rw-r--r--samples/daytimeclnt.lua3
-rw-r--r--samples/talker.lua12
-rw-r--r--src/auxiliar.c113
-rw-r--r--src/auxiliar.h26
-rw-r--r--src/buffer.c275
-rw-r--r--src/buffer.h26
-rw-r--r--src/ftp.lua57
-rw-r--r--src/http.lua35
-rw-r--r--src/inet.c170
-rw-r--r--src/inet.h36
-rw-r--r--src/io.c8
-rw-r--r--src/io.h34
-rw-r--r--src/luasocket.c64
-rw-r--r--src/luasocket.h8
-rw-r--r--src/mbox.lua20
-rw-r--r--src/smtp.lua39
-rw-r--r--src/tcp.c222
-rw-r--r--src/tcp.h20
-rw-r--r--src/timeout.c116
-rw-r--r--src/timeout.h32
-rw-r--r--src/udp.c404
-rw-r--r--src/udp.h27
-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.lua6
-rw-r--r--test/httptest.lua15
-rw-r--r--test/smtptest.lua10
-rw-r--r--test/testclnt.lua372
-rw-r--r--test/testsrvr.lua3
-rw-r--r--test/tftptest.lua7
32 files changed, 1487 insertions, 1076 deletions
diff --git a/NEW b/NEW
index 749641a..879f12c 100644
--- a/NEW
+++ b/NEW
@@ -1,5 +1,20 @@
1Socket structures are independent 1All functions provided by the library are in the namespace "socket".
2UDPBUFFERSIZE is now internal 2Functions such as send/receive/timeout/close etc do not exist in the
3Better treatment of closed connections: test!!! 3namespace. They are now only available as methods of the appropriate
4HTTP post now deals with 1xx codes 4objects.
5connect, bind etc only try first address returned by resolver 5
6Object has been changed to become more uniform. First create an object for
7a given domain/family and protocol. Then connect or bind if needed. Then
8use IO functions.
9
10All functions return a non-nil value as first return value if successful.
11All functions return nil followed by error message in case of error.
12WARNING: The send function was affected.
13
14Better error messages and parameter checking.
15
16UDP connected udp sockets can break association with peer by calling
17setpeername with address "*".
18
19socket.sleep and socket.time are now part of the library and are
20supported.
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
9local Public, Private = {}, {}
10local socket = _G[LUASOCKET_LIBNAME] -- get LuaSocket namespace
11socket.tftp = Public -- create tftp sub namespace
12
13-----------------------------------------------------------------------------
14-- Program constants
15-----------------------------------------------------------------------------
16local char = string.char
17local byte = string.byte
18
19Public.PORT = 69
20Private.OP_RRQ = 1
21Private.OP_WRQ = 2
22Private.OP_DATA = 3
23Private.OP_ACK = 4
24Private.OP_ERROR = 5
25Private.OP_INV = {"RRQ", "WRQ", "DATA", "ACK", "ERROR"}
26
27-----------------------------------------------------------------------------
28-- Packet creation functions
29-----------------------------------------------------------------------------
30function Private.RRQ(source, mode)
31 return char(0, Private.OP_RRQ) .. source .. char(0) .. mode .. char(0)
32end
33
34function Private.WRQ(source, mode)
35 return char(0, Private.OP_RRQ) .. source .. char(0) .. mode .. char(0)
36end
37
38function 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)
43end
44
45function Private.get_OP(dgram)
46 local op = byte(dgram, 1)*256 + byte(dgram, 2)
47 return op
48end
49
50-----------------------------------------------------------------------------
51-- Packet analysis functions
52-----------------------------------------------------------------------------
53function 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
57end
58
59function 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)
64end
65
66-----------------------------------------------------------------------------
67-- Downloads and returns a file pointed to by url
68-----------------------------------------------------------------------------
69function 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
131end
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
7host = socket.toip(host) 7host = socket.toip(host)
8udp = socket.udp() 8udp = socket.udp()
9print("Using host '" ..host.. "' and port " ..port.. "...") 9print("Using host '" ..host.. "' and port " ..port.. "...")
10err = udp:sendto("anything", host, port) 10udp:setpeername(host, port)
11sent, err = udp:send("anything")
11if err then print(err) exit() end 12if err then print(err) exit() end
12dgram, err = udp:receive() 13dgram, err = udp:receive()
13if not dgram then print(err) exit() end 14if 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
6end 6end
7print("Attempting connection to host '" ..host.. "' and port " ..port.. "...") 7print("Attempting connection to host '" ..host.. "' and port " ..port.. "...")
8c, e = connect(host, port) 8c, e = socket.connect(host, port)
9if not c then 9if not c then
10 print(e) 10 print(e)
11 exit() 11 os.exit()
12end 12end
13print("Connected! Please type stuff (empty line to stop):") 13print("Connected! Please type stuff (empty line to stop):")
14l = read() 14l = io.read()
15while l and l ~= "" and not e do 15while 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()
22end 22end
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\*=========================================================================*/
11static 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\*-------------------------------------------------------------------------*/
21void 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\*-------------------------------------------------------------------------*/
40void 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\*-------------------------------------------------------------------------*/
54void *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\*-------------------------------------------------------------------------*/
68void *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\*-------------------------------------------------------------------------*/
82void 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\*-------------------------------------------------------------------------*/
95static 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
12void aux_newclass(lua_State *L, const char *name, luaL_reg *func);
13void aux_add2group(lua_State *L, const char *name, const char *group);
14void *aux_checkclass(lua_State *L, const char *name, int objidx);
15void *aux_checkgroup(lua_State *L, const char *group, int objidx);
16void 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\*=========================================================================*/
17static int sendraw(lua_State *L, p_buf buf, cchar *data, size_t len,
18 size_t *done);
19static int recvraw(lua_State *L, p_buf buf, size_t wanted); 16static int recvraw(lua_State *L, p_buf buf, size_t wanted);
20static int recvdosline(lua_State *L, p_buf buf); 17static int recvline(lua_State *L, p_buf buf);
21static int recvunixline(lua_State *L, p_buf buf);
22static int recvall(lua_State *L, p_buf buf); 18static int recvall(lua_State *L, p_buf buf);
23 19static int buf_get(p_buf buf, const char **data, size_t *count);
24static int buf_contents(lua_State *L, p_buf buf, cchar **data, size_t *len); 20static void buf_skip(p_buf buf, size_t count);
25static void buf_skip(lua_State *L, p_buf buf, size_t len); 21static 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\*-------------------------------------------------------------------------*/
44void buf_init(lua_State *L, p_buf buf, p_base base) 37void 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\*-------------------------------------------------------------------------*/
62int buf_send(lua_State *L, p_buf buf) 47int 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\*-------------------------------------------------------------------------*/
104int buf_receive(lua_State *L, p_buf buf) 73int 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\*-------------------------------------------------------------------------*/
158int buf_isempty(lua_State *L, p_buf buf) 121int 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\*-------------------------------------------------------------------------*/
178static int sendraw(lua_State *L, p_buf buf, cchar *data, size_t len, 132static 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\*-------------------------------------------------------------------------*/
201static int recvraw(lua_State *L, p_buf buf, size_t wanted) 150static
151int 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\*-------------------------------------------------------------------------*/
226static int recvall(lua_State *L, p_buf buf) 172static
173int 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\*-------------------------------------------------------------------------*/
249static int recvdosline(lua_State *L, p_buf buf) 192static
193int 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\*-------------------------------------------------------------------------*/
281static 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\*-------------------------------------------------------------------------*/
310static void buf_skip(lua_State *L, p_buf buf, size_t len) 220static
221void 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\*-------------------------------------------------------------------------*/
327static int buf_contents(lua_State *L, p_buf buf, cchar **data, size_t *len) 232static
233int 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\*-------------------------------------------------------------------------*/
18typedef struct t_buf_tag { 19typedef 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;
23typedef t_buf *p_buf; 25typedef t_buf *p_buf;
24 26
@@ -26,9 +28,9 @@ typedef t_buf *p_buf;
26* Exported functions 28* Exported functions
27\*-------------------------------------------------------------------------*/ 29\*-------------------------------------------------------------------------*/
28void buf_open(lua_State *L); 30void buf_open(lua_State *L);
29void buf_init(lua_State *L, p_buf buf, p_base base); 31void buf_init(p_buf buf, p_io io, p_tm tm);
30int buf_send(lua_State *L, p_buf buf); 32int buf_meth_send(lua_State *L, p_buf buf);
31int buf_receive(lua_State *L, p_buf buf); 33int buf_meth_receive(lua_State *L, p_buf buf);
32int buf_isempty(lua_State *L, p_buf buf); 34int 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
9local Public, Private = {}, {} 9local Public, Private = {}, {}
10socket.ftp = Public 10local socket = _G[LUASOCKET_LIBNAME] -- get LuaSocket namespace
11socket.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"
23Public.BLOCKSIZE = 8192 24Public.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-----------------------------------------------------------------------------
33function Private.try_sendline(sock, line) 34function 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
37end 38end
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-----------------------------------------------------------------------------
47function Private.try_receive(...) 47function 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 51end
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-----------------------------------------------------------------------------
61function Private.try_sendline(sock, line)
62 return Private.try_send(sock, line .. "\r\n")
52end 63end
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-----------------------------------------------------------------------------
309function Private.send_indirect(data, send_cb, chunk, size) 320function 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
9local Public, Private = {}, {} 9local Public, Private = {}, {}
10socket.http = Public 10local socket = _G[LUASOCKET_LIBNAME] -- get LuaSocket namespace
11socket.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-----------------------------------------------------------------------------
32function Private.try_receive(...) 33function 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
40end 37end
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-----------------------------------------------------------------------------
49function Private.try_send(sock, data) 46function 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
53end 50end
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-----------------------------------------------------------------------------
287function Private.send_indirect(data, send_cb, chunk, size) 284function 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
305end 302end
diff --git a/src/inet.c b/src/inet.c
index 341c60e..f20762f 100644
--- a/src/inet.c
+++ b/src/inet.c
@@ -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\*=========================================================================*/
25static int inet_lua_toip(lua_State *L); 17static int inet_global_toip(lua_State *L);
26static int inet_lua_tohostname(lua_State *L); 18static int inet_global_tohostname(lua_State *L);
27static int inet_lua_getpeername(lua_State *L); 19
28static int inet_lua_getsockname(lua_State *L);
29static void inet_pushresolved(lua_State *L, struct hostent *hp); 20static void inet_pushresolved(lua_State *L, struct hostent *hp);
30 21
31#ifdef COMPAT_INETATON 22#ifdef INET_ATON
32static int inet_aton(cchar *cp, struct in_addr *inp); 23static int inet_aton(const char *cp, struct in_addr *inp);
33#endif 24#endif
34 25
26static 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\*-------------------------------------------------------------------------*/
41void inet_open(lua_State *L) 38void 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\*-------------------------------------------------------------------------*/
56void 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\*-------------------------------------------------------------------------*/
73void 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\*-------------------------------------------------------------------------*/
90static int inet_lua_toip(lua_State *L) 55static 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\*-------------------------------------------------------------------------*/
118static int inet_lua_tohostname(lua_State *L) 84static 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\*-------------------------------------------------------------------------*/
147static int inet_lua_getpeername(lua_State *L) 114int 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\*-------------------------------------------------------------------------*/
169static int inet_lua_getsockname(lua_State *L) 135int 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\*-------------------------------------------------------------------------*/
233cchar *inet_tryconnect(p_inet inet, cchar *address, ushort port) 198const 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\*-------------------------------------------------------------------------*/
265cchar *inet_trybind(p_inet inet, cchar *address, ushort port) 235const 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\*-------------------------------------------------------------------------*/
299cchar *inet_trysocket(p_inet inet, int type) 272const 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/*-------------------------------------------------------------------------*\
diff --git a/src/inet.h b/src/inet.h
index 93fcedf..bcefc5b 100644
--- a/src/inet.h
+++ b/src/inet.h
@@ -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\*-------------------------------------------------------------------------*/
24typedef t_sock t_inet;
25typedef t_inet *p_inet;
26 11
27/*-------------------------------------------------------------------------*\ 12/*-------------------------------------------------------------------------*\
28* Exported functions 13* Exported functions
29\*-------------------------------------------------------------------------*/ 14\*-------------------------------------------------------------------------*/
30void inet_open(lua_State *L); 15void inet_open(lua_State *L);
31void inet_construct(lua_State *L, p_inet inet);
32void inet_inherit(lua_State *L, cchar *lsclass);
33 16
34cchar *inet_tryconnect(p_sock sock, cchar *address, ushort); 17const char *inet_tryconnect(p_sock ps, const char *address,
35cchar *inet_trybind(p_sock sock, cchar *address, ushort); 18 unsigned short port);
36cchar *inet_trysocket(p_inet inet, int type); 19const char *inet_trybind(p_sock ps, const char *address,
20 unsigned short port, int backlog);
21const char *inet_trycreate(p_sock ps, int type);
22
23int inet_meth_getpeername(lua_State *L, p_sock ps);
24int 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
3void 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 */
7typedef 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 */
16typedef 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 */
25typedef 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;
30typedef t_io *p_io;
31
32void 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\*-------------------------------------------------------------------------*/
45LUASOCKET_API int lua_socketlibopen(lua_State *L) 40LUASOCKET_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\*-------------------------------------------------------------------------*/
31LUASOCKET_API int lua_socketlibopen(lua_State *L); 31LUASOCKET_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
5function Public.split_message(message_s) 5function 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
25end 25end
26 26
@@ -32,10 +32,10 @@ function Public.parse_header(header_s)
32end 32end
33 33
34function Public.parse_headers(headers_s) 34function 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)
73end 73end
74 74
75function Public.parse(mbox_s) 75function 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
81end 81end
82 82
83function Public.parse_message(message_s) 83function 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
88end 88end
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
9local Public, Private = {}, {} 9local Public, Private = {}, {}
10socket.smtp = Public 10local socket = _G[LUASOCKET_LIBNAME] -- get LuaSocket namespace
11socket.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"
23Public.SERVER = "localhost" 24Public.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-----------------------------------------------------------------------------
33function Private.try_send(sock, data) 34function 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
37end 38end
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-----------------------------------------------------------------------------
47function Private.try_receive(...) 47function 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
52end 51end
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\*=========================================================================*/
20static int tcp_global_create(lua_State *L);
21static int tcp_meth_connect(lua_State *L);
22static int tcp_meth_bind(lua_State *L);
23static int tcp_meth_send(lua_State *L);
24static int tcp_meth_getsockname(lua_State *L);
25static int tcp_meth_getpeername(lua_State *L);
26static int tcp_meth_receive(lua_State *L);
27static int tcp_meth_accept(lua_State *L);
28static int tcp_meth_close(lua_State *L);
29static int tcp_meth_timeout(lua_State *L);
30
31/* tcp object methods */
32static 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 */
48static luaL_reg func[] = {
49 {"tcp", tcp_global_create},
50 {NULL, NULL}
51};
52
53/*-------------------------------------------------------------------------*\
54* Initializes module
55\*-------------------------------------------------------------------------*/
56void 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\*-------------------------------------------------------------------------*/
79static 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
85static 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\*-------------------------------------------------------------------------*/
94static 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
100static 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\*-------------------------------------------------------------------------*/
109static 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\*-------------------------------------------------------------------------*/
118static 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\*-------------------------------------------------------------------------*/
128static 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\*-------------------------------------------------------------------------*/
148static 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\*-------------------------------------------------------------------------*/
170static 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\*-------------------------------------------------------------------------*/
203int 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
10typedef struct t_tcp_ {
11 t_sock sock;
12 t_io io;
13 t_buf buf;
14 t_tm tm;
15} t_tcp;
16typedef t_tcp *p_tcp;
17
18void 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 @@
28static int tm_lua_time(lua_State *L); 29static int tm_lua_time(lua_State *L);
29static int tm_lua_sleep(lua_State *L); 30static int tm_lua_sleep(lua_State *L);
30 31
32static 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\*-------------------------------------------------------------------------*/
41void tm_set(p_tm tm, int tm_block, int tm_return) 44void 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\*-------------------------------------------------------------------------*/
54void tm_get(p_tm tm, int *tm_block, int *tm_return) 53void tm_setblock(p_tm tm, int block)
55{ 54{ tm->block = block; }
56 if (tm_block) *tm_block = tm->tm_block; 55void tm_settotal(p_tm tm, int total)
57 if (tm_return) *tm_return = tm->tm_return; 56{ tm->total = total; }
58} 57int tm_getblock(p_tm tm)
58{ return tm->block; }
59int tm_gettotal(p_tm tm)
60{ return tm->total; }
61int 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\*-------------------------------------------------------------------------*/
68int tm_getremaining(p_tm tm) 71int 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\*-------------------------------------------------------------------------*/
89void tm_markstart(p_tm tm) 92void 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\*-------------------------------------------------------------------------*/
100int 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\*-------------------------------------------------------------------------*/
126void tm_open(lua_State *L) 118void 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\*-------------------------------------------------------------------------*/
129int 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
9typedef 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; 12typedef 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;
15typedef t_tm *p_tm; 17typedef t_tm *p_tm;
16 18
17void tm_set(p_tm tm, int tm_block, int tm_return);
18int tm_getremaining(p_tm tm);
19int tm_getelapsed(p_tm tm);
20int tm_gettime(void);
21void tm_get(p_tm tm, int *tm_block, int *tm_return);
22void tm_markstart(p_tm tm);
23void tm_open(lua_State *L); 19void tm_open(lua_State *L);
20void tm_init(p_tm tm, int block, int total);
21void tm_setblock(p_tm tm, int block);
22void tm_settotal(p_tm tm, int total);
23int tm_getblock(p_tm tm);
24int tm_gettotal(p_tm tm);
25void tm_markstart(p_tm tm);
26int tm_getstart(p_tm tm);
27int tm_get(p_tm tm);
28int tm_gettime(void);
29int tm_meth_timeout(lua_State *L, p_tm tm);
24 30
25#endif 31#endif
diff --git a/src/udp.c b/src/udp.c
index 361816c..1701d1b 100644
--- a/src/udp.c
+++ b/src/udp.c
@@ -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\*=========================================================================*/
29static int udp_lua_send(lua_State *L); 20static int udp_global_create(lua_State *L);
30static int udp_lua_sendto(lua_State *L); 21static int udp_meth_send(lua_State *L);
31static int udp_lua_receive(lua_State *L); 22static int udp_meth_sendto(lua_State *L);
32static int udp_lua_receivefrom(lua_State *L); 23static int udp_meth_receive(lua_State *L);
33static int udp_lua_setpeername(lua_State *L); 24static int udp_meth_receivefrom(lua_State *L);
34static int udp_lua_setsockname(lua_State *L); 25static int udp_meth_getsockname(lua_State *L);
26static int udp_meth_getpeername(lua_State *L);
27static int udp_meth_setsockname(lua_State *L);
28static int udp_meth_setpeername(lua_State *L);
29static int udp_meth_close(lua_State *L);
30static int udp_meth_timeout(lua_State *L);
35 31
36static int udp_global_udp(lua_State *L); 32/* udp object methods */
33static 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
38static struct luaL_reg funcs[] = { 47/* functions in library namespace */
39 {"send", udp_lua_send}, 48static 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\*-------------------------------------------------------------------------*/
53void udp_open(lua_State *L) 56void 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\*-------------------------------------------------------------------------*/
70void 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\*-------------------------------------------------------------------------*/
83void udp_construct(lua_State *L, p_udp udp) 75static 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\*-------------------------------------------------------------------------*/
95p_udp udp_push(lua_State *L) 93static 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\*-------------------------------------------------------------------------*/
114static 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\*-------------------------------------------------------------------------*/
146static int udp_lua_receive(lua_State *L) 120static 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\*-------------------------------------------------------------------------*/
172static int udp_lua_receivefrom(lua_State *L) 139static 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\*-------------------------------------------------------------------------*/
209static int udp_lua_send(lua_State *L) 167static 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); 173static 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\*-------------------------------------------------------------------------*/
235static int udp_lua_sendto(lua_State *L) 182static 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\*-------------------------------------------------------------------------*/
267static int udp_lua_setsockname(lua_State * L) 191static 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 214static 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\*-------------------------------------------------------------------------*/
287static int udp_lua_setpeername(lua_State *L) 224static 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\*-------------------------------------------------------------------------*/
245int 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}
diff --git a/src/udp.h b/src/udp.h
index 928a99f..4ba53e6 100644
--- a/src/udp.h
+++ b/src/udp.h
@@ -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 \ 11typedef struct t_udp_ {
17 INET_FIELDS; \ 12 t_sock sock;
18 int udp_connected 13 t_tm tm;
19
20typedef struct t_udp_tag {
21 UDP_FIELDS;
22} t_udp; 14} t_udp;
23typedef t_udp *p_udp; 15typedef t_udp *p_udp;
24 16
25void udp_inherit(lua_State *L, cchar *lsclass);
26void udp_construct(lua_State *L, p_udp udp);
27void udp_open(lua_State *L); 17void udp_open(lua_State *L);
28p_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\*=========================================================================*/
15static cchar *try_setoption(lua_State *L, COMPAT_FD sock); 15static const char *try_setoption(lua_State *L, p_sock ps);
16static cchar *try_setbooloption(lua_State *L, COMPAT_FD sock, int name); 16static const char *try_setbooloption(lua_State *L, p_sock ps, int name);
17 17
18/*=========================================================================*\ 18/*=========================================================================*\
19* Exported functions. 19* Exported functions.
20\*=========================================================================*/ 20\*=========================================================================*/
21int compat_open(lua_State *L) 21int 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
31COMPAT_FD compat_accept(COMPAT_FD s, struct sockaddr *addr, 31void sock_destroy(p_sock ps)
32 size_t *len, int deadline)
33{ 32{
33 close(*ps);
34}
35
36const 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
46const 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
52const 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
58void sock_listen(p_sock ps, int backlog)
59{
60 listen(*ps, backlog);
61}
62
63void 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
44int compat_send(COMPAT_FD c, cchar *data, size_t count, size_t *sent, 76int 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
77int compat_sendto(COMPAT_FD c, cchar *data, size_t count, size_t *sent, 110int 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
110int compat_recv(COMPAT_FD c, char *data, size_t count, size_t *got, 144int 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
137int compat_recvfrom(COMPAT_FD c, char *data, size_t count, size_t *got, 171int 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\*-------------------------------------------------------------------------*/
167const char *compat_hoststrerror(void) 202const 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\*-------------------------------------------------------------------------*/
181const char *compat_socketstrerror(void) 216const 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\*-------------------------------------------------------------------------*/
195const char *compat_bindstrerror(void) 230const 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\*-------------------------------------------------------------------------*/
212const char *compat_connectstrerror(void) 247const 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\*-------------------------------------------------------------------------*/
232void compat_setreuseaddr(COMPAT_FD sock) 267void 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
238COMPAT_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\*-------------------------------------------------------------------------*/
251void compat_setblocking(COMPAT_FD sock) 276void 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\*-------------------------------------------------------------------------*/
261void compat_setnonblocking(COMPAT_FD sock) 286void 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\*-------------------------------------------------------------------------*/
276cchar *compat_trysetoptions(lua_State *L, COMPAT_FD sock) 301const 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\*=========================================================================*/
291static 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\*-------------------------------------------------------------------------*/
311static cchar *try_setoption(lua_State *L, COMPAT_FD sock) 321static 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\*=========================================================================*/
339static 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 34typedef int t_sock;
35#define COMPAT_INVALIDFD (-1) 35typedef 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 @@
1dofile("noglobals.lua")
2
3local similar = function(s1, s2) 1local 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
35local index, err, saved, back, expected 33local index, err, saved, back, expected
36 34
37local t = socket._time() 35local t = socket.time()
38 36
39index = readfile("test/index.html") 37index = readfile("test/index.html")
40 38
@@ -112,4 +110,4 @@ back, err = socket.ftp.get("ftp://localhost/index.wrong.html;type=a")
112check(err, err) 110check(err, err)
113 111
114print("passed all tests") 112print("passed all tests")
115print(string.format("done in %.2fs", socket._time() - t)) 113print(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
7dofile("noglobals.lua")
8
9local similar = function(s1, s2) 6local 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
28local check = function (v, e) 25local 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
31end 28end
32 29
33local check_request = function(request, expect, ignore) 30local 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")
46end 43end
47 44
48local request, response, ignore, expect, index, prefix, cgiprefix 45local host, request, response, ignore, expect, index, prefix, cgiprefix
49 46
50local t = socket._time() 47local t = socket.time()
51 48
52host = host or "localhost" 49host = host or "localhost"
53prefix = prefix or "/luasocket" 50prefix = prefix or "/luasocket"
@@ -310,4 +307,4 @@ check(response and response.headers)
310 307
311print("passed all tests") 308print("passed all tests")
312 309
313print(string.format("done in %.2fs", socket._time() - t)) 310print(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
14local t = socket._time() 14local t = socket.time()
15local err 15local err
16 16
17dofile("mbox.lua") 17dofile("mbox.lua")
@@ -106,7 +106,7 @@ local insert = function(sent, message)
106end 106end
107 107
108local mark = function() 108local mark = function()
109 local time = socket._time() 109 local time = socket.time()
110 return { time = time } 110 return { time = time }
111end 111end
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
256end 256end
257 257
258print("passed all tests") 258print("passed all tests")
259print(string.format("done in %.2fs", socket._time() - t)) 259print(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
67end 67end
68 68
69if not socket.debug then
70 fail("Please define LUASOCKET_DEBUG and recompile LuaSocket")
71end
72
69io.write("----------------------------------------------\n", 73io.write("----------------------------------------------\n",
70"LuaSocket Test Procedures\n", 74"LuaSocket Test Procedures\n",
71"----------------------------------------------\n") 75"----------------------------------------------\n")
72 76
73if not socket._time or not socket._sleep then 77start = socket.time()
74 fail("not compiled with _DEBUG")
75end
76
77start = socket._time()
78 78
79function tcpreconnect() 79function 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
89end 89end
90reconnect = tcpreconnect
91 90
92pass("attempting control connection...") 91pass("attempting control connection...")
93control, err = socket.connect(host, port) 92control, err = socket.connect(host, port)
@@ -95,101 +94,78 @@ if err then fail(err)
95else pass("connected!") end 94else pass("connected!") end
96 95
97------------------------------------------------------------------------ 96------------------------------------------------------------------------
98test("bugs")
99
100io.write("empty host connect: ")
101function 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
112end
113
114empty_connect()
115
116io.write("active close: ")
117function 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")
128end
129
130active_close()
131
132------------------------------------------------------------------------
133test("method registration") 97test("method registration")
134 98
135function test_methods(sock, methods) 99function 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")
142end 106end
143 107
144test_methods(control, { 108test_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
153if udpsocket then 122test_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 })
166end
167
168test_methods(socket.bind("*", 0), {
169 "close",
170 "timeout", 131 "timeout",
171 "accept" 132 "close",
172}) 133})
173 134
174------------------------------------------------------------------------ 135------------------------------------------------------------------------
175test("select function") 136test("mixed patterns")
176function test_selectbugs() 137
177 local r, s, e = socket.select(nil, nil, 0.1) 138function 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) 147remote (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
151remote "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
190end 157end
191 158
192test_selectbugs() 159
160test_mixed(1)
161test_mixed(17)
162test_mixed(200)
163test_mixed(4091)
164test_mixed(80199)
165test_mixed(4091)
166test_mixed(200)
167test_mixed(17)
168test_mixed(1)
193 169
194------------------------------------------------------------------------ 170------------------------------------------------------------------------
195test("character line") 171test("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")
204remote "str = data:receive()" 180remote "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
207remote "data:send(str, '\\n')" 183remote "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")
232remote "str = data:receive()" 208remote "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
235remote "data:send(str, '\\n')" 211remote "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")
264remote (string.format("str = data:receive(%d)", len)) 240remote (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
269remote "data:send(str)" 245remote "data:send(str)"
270 back, err = data:receive(len) 246 back, err = data:receive(len)
@@ -304,127 +280,54 @@ test_raw(17)
304test_raw(1) 280test_raw(1)
305 281
306------------------------------------------------------------------------ 282------------------------------------------------------------------------
307test("mixed patterns") 283test("total timeout on receive")
308reconnect() 284function test_totaltimeoutreceive(len, tm, sl)
309
310function 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")
317remote (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
321remote "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
327end
328
329test_mixed(1)
330test_mixed(17)
331test_mixed(200)
332test_mixed(4091)
333test_mixed(80199)
334test_mixed(800000)
335test_mixed(80199)
336test_mixed(4091)
337test_mixed(200)
338test_mixed(17)
339test_mixed(1)
340
341------------------------------------------------------------------------
342test("closed connection detection")
343
344function 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
368pass("failed: output buffer is at least %d bytes long!", total)
369 elseif err ~= "closed" then
370fail("got '"..err.."' instead of 'closed'.")
371 else
372pass("graceful 'closed' received after %d bytes were sent", total)
373 end
374end
375
376test_closed()
377
378------------------------------------------------------------------------
379test("return timeout on receive")
380function 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)
397end 301end
398test_blockingtimeoutreceive(800091, 1, 3) 302test_totaltimeoutreceive(800091, 1, 3)
399test_blockingtimeoutreceive(800091, 2, 3) 303test_totaltimeoutreceive(800091, 2, 3)
400test_blockingtimeoutreceive(800091, 3, 2) 304test_totaltimeoutreceive(800091, 3, 2)
401test_blockingtimeoutreceive(800091, 3, 1) 305test_totaltimeoutreceive(800091, 3, 1)
402 306
403------------------------------------------------------------------------ 307------------------------------------------------------------------------
404test("return timeout on send") 308test("total timeout on send")
405function test_returntimeoutsend(len, tm, sl) 309function 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)
422end 326end
423test_returntimeoutsend(800091, 1, 3) 327test_totaltimeoutsend(800091, 1, 3)
424test_returntimeoutsend(800091, 2, 3) 328test_totaltimeoutsend(800091, 2, 3)
425test_returntimeoutsend(800091, 3, 2) 329test_totaltimeoutsend(800091, 3, 2)
426test_returntimeoutsend(800091, 3, 1) 330test_totaltimeoutsend(800091, 3, 1)
427
428 331
429------------------------------------------------------------------------ 332------------------------------------------------------------------------
430test("blocking timeout on receive") 333test("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)
451test_blockingtimeoutreceive(800091, 3, 2) 354test_blockingtimeoutreceive(800091, 3, 2)
452test_blockingtimeoutreceive(800091, 3, 1) 355test_blockingtimeoutreceive(800091, 3, 1)
453 356
454
455------------------------------------------------------------------------ 357------------------------------------------------------------------------
456test("blocking timeout on send") 358test("blocking timeout on send")
457function test_blockingtimeoutsend(len, tm, sl) 359function 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)
474end 376end
@@ -478,4 +380,98 @@ test_blockingtimeoutsend(800091, 3, 2)
478test_blockingtimeoutsend(800091, 3, 1) 380test_blockingtimeoutsend(800091, 3, 1)
479 381
480------------------------------------------------------------------------ 382------------------------------------------------------------------------
481test(string.format("done in %.2fs", socket._time() - start)) 383test("bugs")
384
385io.write("empty host connect: ")
386function 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
397end
398
399empty_connect()
400
401-- io.write("active close: ")
402function 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")
413end
414
415-- active_close()
416
417------------------------------------------------------------------------
418test("closed connection detection")
419
420function 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
444pass("failed: output buffer is at least %d bytes long!", total)
445 elseif err ~= "closed" then
446fail("got '"..err.."' instead of 'closed'.")
447 else
448pass("graceful 'closed' received after %d bytes were sent", total)
449 end
450end
451
452test_closed()
453
454------------------------------------------------------------------------
455test("select function")
456function 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")
470end
471
472-- test_selectbugs()
473
474
475
476
477test(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
24end 25end
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
2dofile("tftpclnt.lua") 2dofile("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)
13end 13end
14 14
15host = host or "localhost" 15host = host or "localhost"
16print("downloading") 16retrieved, err = socket.tftp.get("tftp://" .. host .."/index.html")
17err = tftp_get(host, 69, "index.html", "index.got")
18assert(not err, err) 17assert(not err, err)
19original = readfile("test/index.html") 18original = readfile("test/index.html")
20retrieved = readfile("index.got")
21os.remove("index.got")
22assert(original == retrieved, "files differ!") 19assert(original == retrieved, "files differ!")
23print("passed") 20print("passed")