aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDiego Nehab <diego@tecgraf.puc-rio.br>2004-07-01 03:32:09 +0000
committerDiego Nehab <diego@tecgraf.puc-rio.br>2004-07-01 03:32:09 +0000
commit7115c12fbc9aae1cd46fdf049697a27fb996181a (patch)
tree2e918f54f729766701aabdef488a6461bc623da1
parent7aaba59909e8527190694285f56ca68772c97f6a (diff)
downloadluasocket-7115c12fbc9aae1cd46fdf049697a27fb996181a.tar.gz
luasocket-7115c12fbc9aae1cd46fdf049697a27fb996181a.tar.bz2
luasocket-7115c12fbc9aae1cd46fdf049697a27fb996181a.zip
Moving on to beta2.
-rw-r--r--FIX7
-rw-r--r--TODO8
-rw-r--r--etc/tftp.lua25
-rw-r--r--samples/lpr.lua51
-rw-r--r--src/buffer.c68
-rw-r--r--src/io.c20
-rw-r--r--src/io.h22
-rw-r--r--src/select.c11
-rw-r--r--src/socket.h14
-rw-r--r--src/tcp.c6
-rw-r--r--src/timeout.c73
-rw-r--r--src/timeout.h16
-rw-r--r--src/udp.c105
-rw-r--r--src/usocket.c334
-rw-r--r--src/usocket.h6
-rw-r--r--test/testclnt.lua62
16 files changed, 388 insertions, 440 deletions
diff --git a/FIX b/FIX
index 720c72b..0972403 100644
--- a/FIX
+++ b/FIX
@@ -1,8 +1,9 @@
1setup error messages in the default case.
1listen defaults to 32 backlog 2listen defaults to 32 backlog
2smtp sends quit on exceptions 3smtp/ftp/http fail gracefully
3accept/connect interrupt safe 4accept/connect/select interrupt safe
4accepted sockets are nonblocking 5accepted sockets are nonblocking
5new timming functions. better sleep/gettime 6new timming functions. higher resolution, no wrap around
6bug fixes in the manual 7bug fixes in the manual
7getfd missing cast 8getfd missing cast
8added unix domain support example 9added unix domain support example
diff --git a/TODO b/TODO
index 437e1e5..c74e525 100644
--- a/TODO
+++ b/TODO
@@ -1,8 +1,8 @@
1setup error messages in the default case. 1create the getstats method.
2 2
3ajeitar o connect com a dica do mike 3 sent, received, age = sock:getstats()
4 if ((err > 1 || !FD_ISSET(sock, &wfds)) && 4
5 recv(sock, &dummy, 0, 0) < 0 && errno != EWOULDBLOCK) ... 5take a look at DB's smtp patch
6 6
7sort out the wrap around of gettime... 7sort out the wrap around of gettime...
8 use doubles all over 8 use doubles all over
diff --git a/etc/tftp.lua b/etc/tftp.lua
index 2fc914e..70db050 100644
--- a/etc/tftp.lua
+++ b/etc/tftp.lua
@@ -72,50 +72,51 @@ local function tget(gett)
72 local retries, dgram, sent, datahost, dataport, code 72 local retries, dgram, sent, datahost, dataport, code
73 local last = 0 73 local last = 0
74 local con = socket.try(socket.udp()) 74 local con = socket.try(socket.udp())
75 local try = socket.newtry(function() con:close() end)
75 -- convert from name to ip if needed 76 -- convert from name to ip if needed
76 gett.host = socket.try(socket.dns.toip(gett.host)) 77 gett.host = try(socket.dns.toip(gett.host))
77 con:settimeout(1) 78 con:settimeout(1)
78 -- first packet gives data host/port to be used for data transfers 79 -- first packet gives data host/port to be used for data transfers
79 retries = 0 80 retries = 0
80 repeat 81 repeat
81 sent = socket.try(con:sendto(RRQ(gett.path, "octet"), 82 sent = try(con:sendto(RRQ(gett.path, "octet"),
82 gett.host, gett.port)) 83 gett.host, gett.port))
83 dgram, datahost, dataport = con:receivefrom() 84 dgram, datahost, dataport = con:receivefrom()
84 retries = retries + 1 85 retries = retries + 1
85 until dgram or datahost ~= "timeout" or retries > 5 86 until dgram or datahost ~= "timeout" or retries > 5
86 socket.try(dgram, datahost) 87 try(dgram, datahost)
87 -- associate socket with data host/port 88 -- associate socket with data host/port
88 socket.try(con:setpeername(datahost, dataport)) 89 try(con:setpeername(datahost, dataport))
89 -- default sink 90 -- default sink
90 local sink = gett.sink or ltn12.sink.null() 91 local sink = gett.sink or ltn12.sink.null()
91 -- process all data packets 92 -- process all data packets
92 while 1 do 93 while 1 do
93 -- decode packet 94 -- decode packet
94 code = get_OP(dgram) 95 code = get_OP(dgram)
95 socket.try(code ~= OP_ERROR, get_ERROR(dgram)) 96 try(code ~= OP_ERROR, get_ERROR(dgram))
96 socket.try(code == OP_DATA, "unhandled opcode " .. code) 97 try(code == OP_DATA, "unhandled opcode " .. code)
97 -- get data packet parts 98 -- get data packet parts
98 local block, data = split_DATA(dgram) 99 local block, data = split_DATA(dgram)
99 -- if not repeated, write 100 -- if not repeated, write
100 if block == last+1 then 101 if block == last+1 then
101 socket.try(sink(data)) 102 try(sink(data))
102 last = block 103 last = block
103 end 104 end
104 -- last packet brings less than 512 bytes of data 105 -- last packet brings less than 512 bytes of data
105 if string.len(data) < 512 then 106 if string.len(data) < 512 then
106 socket.try(con:send(ACK(block))) 107 try(con:send(ACK(block)))
107 socket.try(con:close()) 108 try(con:close())
108 socket.try(sink(nil)) 109 try(sink(nil))
109 return 1 110 return 1
110 end 111 end
111 -- get the next packet 112 -- get the next packet
112 retries = 0 113 retries = 0
113 repeat 114 repeat
114 sent = socket.try(con:send(ACK(last))) 115 sent = try(con:send(ACK(last)))
115 dgram, err = con:receive() 116 dgram, err = con:receive()
116 retries = retries + 1 117 retries = retries + 1
117 until dgram or err ~= "timeout" or retries > 5 118 until dgram or err ~= "timeout" or retries > 5
118 socket.try(dgram, err) 119 try(dgram, err)
119 end 120 end
120end 121end
121 122
diff --git a/samples/lpr.lua b/samples/lpr.lua
new file mode 100644
index 0000000..77c354f
--- /dev/null
+++ b/samples/lpr.lua
@@ -0,0 +1,51 @@
1local lp = require("lp")
2
3local function usage()
4 print('\nUsage: lp filename [keyword=val...]\n')
5 print('Valid keywords are :')
6 print(
7 ' host=remote host or IP address (default "localhost")\n' ..
8 ' queue=remote queue or printer name (default "printer")\n' ..
9 ' port=remote port number (default 515)\n' ..
10 ' user=sending user name\n' ..
11 ' format=["binary" | "text" | "ps" | "pr" | "fortran"] (default "binary")\n' ..
12 ' banner=true|false\n' ..
13 ' indent=number of columns to indent\n' ..
14 ' mail=email of address to notify when print is complete\n' ..
15 ' title=title to use for "pr" format\n' ..
16 ' width=width for "text" or "pr" formats\n' ..
17 ' class=\n' ..
18 ' job=\n' ..
19 ' name=\n' ..
20 ' localbind=true|false\n'
21 )
22 return nil
23end
24
25if not arg or not arg[1] then
26 return usage()
27end
28
29do
30 local s="opt = {"
31 for i = 2 , table.getn(arg), 1 do
32 s = s .. string.gsub(arg[i],"[%s%c%p]*([%w]*)=([\"]?[%w%s_!@#$%%^&*()<>:;]+[\"]\?\.?)","%1%=\"%2\",\n")
33 end
34 s = s .. "};\n"
35 assert(loadstring(s))();
36 if not arg[2] then
37 return usage()
38 end
39 if arg[1] ~= "query" then
40 r,e=lp.send(arg[1],opt)
41 io.stderr:write(tostring(r or e),'\n')
42 else
43 r,e=lp.query(opt)
44 io.stderr:write(tostring(r or e), '\n')
45 end
46end
47
48-- trivial tests
49--lua lp.lua lp.lua queue=default host=localhost
50--lua lp.lua lp.lua queue=default host=localhost format=binary localbind=1
51--lua lp.lua query queue=default host=localhost
diff --git a/src/buffer.c b/src/buffer.c
index 60e42ae..aa50db0 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -33,8 +33,7 @@ static int sendraw(p_buf buf, const char *data, size_t count, size_t *sent);
33/*-------------------------------------------------------------------------*\ 33/*-------------------------------------------------------------------------*\
34* Initializes module 34* Initializes module
35\*-------------------------------------------------------------------------*/ 35\*-------------------------------------------------------------------------*/
36int buf_open(lua_State *L) 36int buf_open(lua_State *L) {
37{
38 (void) L; 37 (void) L;
39 return 0; 38 return 0;
40} 39}
@@ -42,8 +41,7 @@ int buf_open(lua_State *L)
42/*-------------------------------------------------------------------------*\ 41/*-------------------------------------------------------------------------*\
43* Initializes C structure 42* Initializes C structure
44\*-------------------------------------------------------------------------*/ 43\*-------------------------------------------------------------------------*/
45void buf_init(p_buf buf, p_io io, p_tm tm) 44void buf_init(p_buf buf, p_io io, p_tm tm) {
46{
47 buf->first = buf->last = 0; 45 buf->first = buf->last = 0;
48 buf->io = io; 46 buf->io = io;
49 buf->tm = tm; 47 buf->tm = tm;
@@ -52,13 +50,11 @@ void buf_init(p_buf buf, p_io io, p_tm tm)
52/*-------------------------------------------------------------------------*\ 50/*-------------------------------------------------------------------------*\
53* object:send() interface 51* object:send() interface
54\*-------------------------------------------------------------------------*/ 52\*-------------------------------------------------------------------------*/
55int buf_meth_send(lua_State *L, p_buf buf) 53int buf_meth_send(lua_State *L, p_buf buf) {
56{
57 int top = lua_gettop(L); 54 int top = lua_gettop(L);
58 size_t total = 0; 55 size_t total = 0;
59 int arg, err = IO_DONE; 56 int arg, err = IO_DONE;
60 p_tm tm = buf->tm; 57 p_tm tm = tm_markstart(buf->tm);
61 tm_markstart(tm);
62 for (arg = 2; arg <= top; arg++) { /* first arg is socket object */ 58 for (arg = 2; arg <= top; arg++) { /* first arg is socket object */
63 size_t sent, count; 59 size_t sent, count;
64 const char *data = luaL_optlstring(L, arg, NULL, &count); 60 const char *data = luaL_optlstring(L, arg, NULL, &count);
@@ -69,7 +65,7 @@ int buf_meth_send(lua_State *L, p_buf buf)
69 /* check if there was an error */ 65 /* check if there was an error */
70 if (err != IO_DONE) { 66 if (err != IO_DONE) {
71 lua_pushnil(L); 67 lua_pushnil(L);
72 io_pusherror(L, err); 68 io_pusherror(L, buf->io, err);
73 lua_pushnumber(L, total); 69 lua_pushnumber(L, total);
74 } else { 70 } else {
75 lua_pushnumber(L, total); 71 lua_pushnumber(L, total);
@@ -78,7 +74,7 @@ int buf_meth_send(lua_State *L, p_buf buf)
78 } 74 }
79#ifdef LUASOCKET_DEBUG 75#ifdef LUASOCKET_DEBUG
80 /* push time elapsed during operation as the last return value */ 76 /* push time elapsed during operation as the last return value */
81 lua_pushnumber(L, (tm_gettime() - tm_getstart(tm))/1000.0); 77 lua_pushnumber(L, tm_gettime() - tm_getstart(tm));
82#endif 78#endif
83 return lua_gettop(L) - top; 79 return lua_gettop(L) - top;
84} 80}
@@ -86,13 +82,11 @@ int buf_meth_send(lua_State *L, p_buf buf)
86/*-------------------------------------------------------------------------*\ 82/*-------------------------------------------------------------------------*\
87* object:receive() interface 83* object:receive() interface
88\*-------------------------------------------------------------------------*/ 84\*-------------------------------------------------------------------------*/
89int buf_meth_receive(lua_State *L, p_buf buf) 85int buf_meth_receive(lua_State *L, p_buf buf) {
90{
91 int err = IO_DONE, top = lua_gettop(L); 86 int err = IO_DONE, top = lua_gettop(L);
92 p_tm tm = buf->tm; 87 p_tm tm = tm_markstart(buf->tm);
93 luaL_Buffer b; 88 luaL_Buffer b;
94 luaL_buffinit(L, &b); 89 luaL_buffinit(L, &b);
95 tm_markstart(tm);
96 /* receive all patterns */ 90 /* receive all patterns */
97 if (!lua_isnumber(L, 2)) { 91 if (!lua_isnumber(L, 2)) {
98 static const char *patternnames[] = {"*l", "*a", NULL}; 92 static const char *patternnames[] = {"*l", "*a", NULL};
@@ -107,7 +101,7 @@ int buf_meth_receive(lua_State *L, p_buf buf)
107 /* check if there was an error */ 101 /* check if there was an error */
108 if (err != IO_DONE) { 102 if (err != IO_DONE) {
109 luaL_pushresult(&b); 103 luaL_pushresult(&b);
110 io_pusherror(L, err); 104 io_pusherror(L, buf->io, err);
111 lua_pushvalue(L, -2); 105 lua_pushvalue(L, -2);
112 lua_pushnil(L); 106 lua_pushnil(L);
113 lua_replace(L, -4); 107 lua_replace(L, -4);
@@ -118,7 +112,7 @@ int buf_meth_receive(lua_State *L, p_buf buf)
118 } 112 }
119#ifdef LUASOCKET_DEBUG 113#ifdef LUASOCKET_DEBUG
120 /* push time elapsed during operation as the last return value */ 114 /* push time elapsed during operation as the last return value */
121 lua_pushnumber(L, (tm_gettime() - tm_getstart(tm))/1000.0); 115 lua_pushnumber(L, tm_gettime() - tm_getstart(tm));
122#endif 116#endif
123 return lua_gettop(L) - top; 117 return lua_gettop(L) - top;
124} 118}
@@ -126,8 +120,7 @@ int buf_meth_receive(lua_State *L, p_buf buf)
126/*-------------------------------------------------------------------------*\ 120/*-------------------------------------------------------------------------*\
127* Determines if there is any data in the read buffer 121* Determines if there is any data in the read buffer
128\*-------------------------------------------------------------------------*/ 122\*-------------------------------------------------------------------------*/
129int buf_isempty(p_buf buf) 123int buf_isempty(p_buf buf) {
130{
131 return buf->first >= buf->last; 124 return buf->first >= buf->last;
132} 125}
133 126
@@ -137,16 +130,14 @@ int buf_isempty(p_buf buf)
137/*-------------------------------------------------------------------------*\ 130/*-------------------------------------------------------------------------*\
138* Sends a block of data (unbuffered) 131* Sends a block of data (unbuffered)
139\*-------------------------------------------------------------------------*/ 132\*-------------------------------------------------------------------------*/
140static 133static int sendraw(p_buf buf, const char *data, size_t count, size_t *sent) {
141int sendraw(p_buf buf, const char *data, size_t count, size_t *sent)
142{
143 p_io io = buf->io; 134 p_io io = buf->io;
144 p_tm tm = buf->tm; 135 p_tm tm = buf->tm;
145 size_t total = 0; 136 size_t total = 0;
146 int err = IO_DONE; 137 int err = IO_DONE;
147 while (total < count && (err == IO_DONE || err == IO_RETRY)) { 138 while (total < count && err == IO_DONE) {
148 size_t done; 139 size_t done;
149 err = io->send(io->ctx, data+total, count-total, &done, tm_get(tm)); 140 err = io->send(io->ctx, data+total, count-total, &done, tm);
150 total += done; 141 total += done;
151 } 142 }
152 *sent = total; 143 *sent = total;
@@ -156,12 +147,10 @@ int sendraw(p_buf buf, const char *data, size_t count, size_t *sent)
156/*-------------------------------------------------------------------------*\ 147/*-------------------------------------------------------------------------*\
157* Reads a fixed number of bytes (buffered) 148* Reads a fixed number of bytes (buffered)
158\*-------------------------------------------------------------------------*/ 149\*-------------------------------------------------------------------------*/
159static 150static int recvraw(p_buf buf, size_t wanted, luaL_Buffer *b) {
160int recvraw(p_buf buf, size_t wanted, luaL_Buffer *b) 151 int err = IO_DONE;
161{
162 int err = IO_DONE;
163 size_t total = 0; 152 size_t total = 0;
164 while (total < wanted && (err == IO_DONE || err == IO_RETRY)) { 153 while (total < wanted && err == IO_DONE) {
165 size_t count; const char *data; 154 size_t count; const char *data;
166 err = buf_get(buf, &data, &count); 155 err = buf_get(buf, &data, &count);
167 count = MIN(count, wanted - total); 156 count = MIN(count, wanted - total);
@@ -175,11 +164,9 @@ int recvraw(p_buf buf, size_t wanted, luaL_Buffer *b)
175/*-------------------------------------------------------------------------*\ 164/*-------------------------------------------------------------------------*\
176* Reads everything until the connection is closed (buffered) 165* Reads everything until the connection is closed (buffered)
177\*-------------------------------------------------------------------------*/ 166\*-------------------------------------------------------------------------*/
178static 167static int recvall(p_buf buf, luaL_Buffer *b) {
179int recvall(p_buf buf, luaL_Buffer *b)
180{
181 int err = IO_DONE; 168 int err = IO_DONE;
182 while (err == IO_DONE || err == IO_RETRY) { 169 while (err == IO_DONE) {
183 const char *data; size_t count; 170 const char *data; size_t count;
184 err = buf_get(buf, &data, &count); 171 err = buf_get(buf, &data, &count);
185 luaL_addlstring(b, data, count); 172 luaL_addlstring(b, data, count);
@@ -193,11 +180,9 @@ int recvall(p_buf buf, luaL_Buffer *b)
193* Reads a line terminated by a CR LF pair or just by a LF. The CR and LF 180* Reads a line terminated by a CR LF pair or just by a LF. The CR and LF
194* are not returned by the function and are discarded from the buffer 181* are not returned by the function and are discarded from the buffer
195\*-------------------------------------------------------------------------*/ 182\*-------------------------------------------------------------------------*/
196static 183static int recvline(p_buf buf, luaL_Buffer *b) {
197int recvline(p_buf buf, luaL_Buffer *b)
198{
199 int err = IO_DONE; 184 int err = IO_DONE;
200 while (err == IO_DONE || err == IO_RETRY) { 185 while (err == IO_DONE) {
201 size_t count, pos; const char *data; 186 size_t count, pos; const char *data;
202 err = buf_get(buf, &data, &count); 187 err = buf_get(buf, &data, &count);
203 pos = 0; 188 pos = 0;
@@ -219,9 +204,7 @@ int recvline(p_buf buf, luaL_Buffer *b)
219* Skips a given number of bytes from read buffer. No data is read from the 204* Skips a given number of bytes from read buffer. No data is read from the
220* transport layer 205* transport layer
221\*-------------------------------------------------------------------------*/ 206\*-------------------------------------------------------------------------*/
222static 207static void buf_skip(p_buf buf, size_t count) {
223void buf_skip(p_buf buf, size_t count)
224{
225 buf->first += count; 208 buf->first += count;
226 if (buf_isempty(buf)) 209 if (buf_isempty(buf))
227 buf->first = buf->last = 0; 210 buf->first = buf->last = 0;
@@ -231,15 +214,13 @@ void buf_skip(p_buf buf, size_t count)
231* Return any data available in buffer, or get more data from transport layer 214* Return any data available in buffer, or get more data from transport layer
232* if buffer is empty 215* if buffer is empty
233\*-------------------------------------------------------------------------*/ 216\*-------------------------------------------------------------------------*/
234static 217static int buf_get(p_buf buf, const char **data, size_t *count) {
235int buf_get(p_buf buf, const char **data, size_t *count)
236{
237 int err = IO_DONE; 218 int err = IO_DONE;
238 p_io io = buf->io; 219 p_io io = buf->io;
239 p_tm tm = buf->tm; 220 p_tm tm = buf->tm;
240 if (buf_isempty(buf)) { 221 if (buf_isempty(buf)) {
241 size_t got; 222 size_t got;
242 err = io->recv(io->ctx, buf->data, BUF_SIZE, &got, tm_get(tm)); 223 err = io->recv(io->ctx, buf->data, BUF_SIZE, &got, tm);
243 buf->first = 0; 224 buf->first = 0;
244 buf->last = got; 225 buf->last = got;
245 } 226 }
@@ -247,4 +228,3 @@ int buf_get(p_buf buf, const char **data, size_t *count)
247 *data = buf->data + buf->first; 228 *data = buf->data + buf->first;
248 return err; 229 return err;
249} 230}
250
diff --git a/src/io.c b/src/io.c
index 612454b..30595c7 100644
--- a/src/io.c
+++ b/src/io.c
@@ -12,34 +12,34 @@
12/*-------------------------------------------------------------------------*\ 12/*-------------------------------------------------------------------------*\
13* Initializes C structure 13* Initializes C structure
14\*-------------------------------------------------------------------------*/ 14\*-------------------------------------------------------------------------*/
15void io_init(p_io io, p_send send, p_recv recv, void *ctx) 15void io_init(p_io io, p_send send, p_recv recv, p_geterr geterr, void *ctx) {
16{
17 io->send = send; 16 io->send = send;
18 io->recv = recv; 17 io->recv = recv;
18 io->geterr = geterr;
19 io->ctx = ctx; 19 io->ctx = ctx;
20} 20}
21 21
22/*-------------------------------------------------------------------------*\ 22/*-------------------------------------------------------------------------*\
23* Translate error codes to Lua 23* Translate error codes to Lua
24\*-------------------------------------------------------------------------*/ 24\*-------------------------------------------------------------------------*/
25const char *io_strerror(int code) 25const char *io_strerror(int code) {
26{
27 switch (code) { 26 switch (code) {
28 case IO_DONE: return NULL; 27 case IO_DONE: return NULL;
29 case IO_TIMEOUT: return "timeout";
30 case IO_RETRY: return "retry";
31 case IO_CLOSED: return "closed"; 28 case IO_CLOSED: return "closed";
32 case IO_REFUSED: return "refused"; 29 case IO_TIMEOUT: return "timeout";
30 case IO_CLIPPED: return "clipped";
33 default: return "unknown error"; 31 default: return "unknown error";
34 } 32 }
35} 33}
36 34
37/*-------------------------------------------------------------------------*\ 35/*-------------------------------------------------------------------------*\
38* Translate error codes to Lua 36* Push error message from code or from driver
39\*-------------------------------------------------------------------------*/ 37\*-------------------------------------------------------------------------*/
40void io_pusherror(lua_State *L, int code) 38void io_pusherror(lua_State *L, p_io io, int code)
41{ 39{
42 const char *err = io_strerror(code); 40 const char *err = NULL;
41 if (code < IO_USER) err = io_strerror(code);
42 else err = io->geterr(io->ctx, code);
43 if (err) lua_pushstring(L, err); 43 if (err) lua_pushstring(L, err);
44 else lua_pushnil(L); 44 else lua_pushnil(L);
45} 45}
diff --git a/src/io.h b/src/io.h
index 495bdc6..72602dd 100644
--- a/src/io.h
+++ b/src/io.h
@@ -17,14 +17,15 @@
17#include <stdio.h> 17#include <stdio.h>
18#include <lua.h> 18#include <lua.h>
19 19
20#include "timeout.h"
21
20/* IO error codes */ 22/* IO error codes */
21enum { 23enum {
22 IO_DONE, /* operation completed successfully */ 24 IO_DONE, /* operation completed successfully */
23 IO_RETRY, /* please try again */
24 IO_TIMEOUT, /* operation timed out */ 25 IO_TIMEOUT, /* operation timed out */
25 IO_CLOSED, /* the connection has been closed */ 26 IO_CLOSED, /* the connection has been closed */
26 IO_REFUSED, /* transfer has been refused */ 27 IO_CLIPPED, /* maxium bytes count reached */
27 IO_ERROR /* something else wrong... */ 28 IO_USER /* last element in enum is user custom error */
28}; 29};
29 30
30/* interface to send function */ 31/* interface to send function */
@@ -33,7 +34,13 @@ typedef int (*p_send) (
33 const char *data, /* pointer to buffer with data to send */ 34 const char *data, /* pointer to buffer with data to send */
34 size_t count, /* number of bytes to send from buffer */ 35 size_t count, /* number of bytes to send from buffer */
35 size_t *sent, /* number of bytes sent uppon return */ 36 size_t *sent, /* number of bytes sent uppon return */
36 int timeout /* number of miliseconds left for transmission */ 37 p_tm tm /* timeout control */
38);
39
40/* returns an error string */
41typedef const char *(*p_geterr) (
42 void *ctx, /* context needed by geterror */
43 int code /* error code */
37); 44);
38 45
39/* interface to recv function */ 46/* interface to recv function */
@@ -42,7 +49,7 @@ typedef int (*p_recv) (
42 char *data, /* pointer to buffer where data will be writen */ 49 char *data, /* pointer to buffer where data will be writen */
43 size_t count, /* number of bytes to receive into buffer */ 50 size_t count, /* number of bytes to receive into buffer */
44 size_t *got, /* number of bytes received uppon return */ 51 size_t *got, /* number of bytes received uppon return */
45 int timeout /* number of miliseconds left for transmission */ 52 p_tm tm /* timeout control */
46); 53);
47 54
48/* IO driver definition */ 55/* IO driver definition */
@@ -50,11 +57,12 @@ typedef struct t_io_ {
50 void *ctx; /* context needed by send/recv */ 57 void *ctx; /* context needed by send/recv */
51 p_send send; /* send function pointer */ 58 p_send send; /* send function pointer */
52 p_recv recv; /* receive function pointer */ 59 p_recv recv; /* receive function pointer */
60 p_geterr geterr; /* receive function pointer */
53} t_io; 61} t_io;
54typedef t_io *p_io; 62typedef t_io *p_io;
55 63
56const char *io_strerror(int code); 64const char *io_strerror(int code);
57void io_pusherror(lua_State *L, int code); 65void io_pusherror(lua_State *L, p_io io, int code);
58void io_init(p_io io, p_send send, p_recv recv, void *ctx); 66void io_init(p_io io, p_send send, p_recv recv, p_geterr geterr, void *ctx);
59 67
60#endif /* IO_H */ 68#endif /* IO_H */
diff --git a/src/select.c b/src/select.c
index 49730d1..3c01b06 100644
--- a/src/select.c
+++ b/src/select.c
@@ -10,6 +10,7 @@
10#include <lauxlib.h> 10#include <lauxlib.h>
11 11
12#include "socket.h" 12#include "socket.h"
13#include "timeout.h"
13#include "select.h" 14#include "select.h"
14 15
15/*=========================================================================*\ 16/*=========================================================================*\
@@ -48,19 +49,21 @@ int select_open(lua_State *L) {
48* Waits for a set of sockets until a condition is met or timeout. 49* Waits for a set of sockets until a condition is met or timeout.
49\*-------------------------------------------------------------------------*/ 50\*-------------------------------------------------------------------------*/
50static int global_select(lua_State *L) { 51static int global_select(lua_State *L) {
51 int timeout, rtab, wtab, itab, max_fd, ret, ndirty; 52 int rtab, wtab, itab, max_fd, ret, ndirty;
52 fd_set rset, wset; 53 fd_set rset, wset;
54 t_tm tm;
55 double t = luaL_optnumber(L, 3, -1);
53 FD_ZERO(&rset); FD_ZERO(&wset); 56 FD_ZERO(&rset); FD_ZERO(&wset);
54 lua_settop(L, 3); 57 lua_settop(L, 3);
55 timeout = lua_isnil(L, 3) ? -1 : (int)(luaL_checknumber(L, 3) * 1000);
56 lua_newtable(L); itab = lua_gettop(L); 58 lua_newtable(L); itab = lua_gettop(L);
57 lua_newtable(L); rtab = lua_gettop(L); 59 lua_newtable(L); rtab = lua_gettop(L);
58 lua_newtable(L); wtab = lua_gettop(L); 60 lua_newtable(L); wtab = lua_gettop(L);
59 max_fd = collect_fd(L, 1, -1, itab, &rset); 61 max_fd = collect_fd(L, 1, -1, itab, &rset);
60 ndirty = check_dirty(L, 1, rtab, &rset); 62 ndirty = check_dirty(L, 1, rtab, &rset);
61 timeout = ndirty > 0? 0: timeout; 63 t = ndirty > 0? 0.0: t;
64 tm_init(&tm, t, -1);
62 max_fd = collect_fd(L, 2, max_fd, itab, &wset); 65 max_fd = collect_fd(L, 2, max_fd, itab, &wset);
63 ret = sock_select(max_fd+1, &rset, &wset, NULL, timeout); 66 ret = sock_select(max_fd+1, &rset, &wset, NULL, &tm);
64 if (ret > 0 || (ret == 0 && ndirty > 0)) { 67 if (ret > 0 || (ret == 0 && ndirty > 0)) {
65 return_fd(L, &rset, max_fd+1, itab, rtab, ndirty); 68 return_fd(L, &rset, max_fd+1, itab, rtab, ndirty);
66 return_fd(L, &wset, max_fd+1, itab, wtab, 0); 69 return_fd(L, &wset, max_fd+1, itab, wtab, 0);
diff --git a/src/socket.h b/src/socket.h
index 5da1ccc..787b7a5 100644
--- a/src/socket.h
+++ b/src/socket.h
@@ -41,17 +41,15 @@ int sock_open(void);
41int sock_close(void); 41int sock_close(void);
42void sock_destroy(p_sock ps); 42void sock_destroy(p_sock ps);
43void sock_shutdown(p_sock ps, int how); 43void sock_shutdown(p_sock ps, int how);
44int sock_send(p_sock ps, const char *data, size_t count, 44int sock_send(p_sock ps, const char *data, size_t count, size_t *sent, p_tm tm);
45 size_t *sent, int timeout); 45int sock_recv(p_sock ps, char *data, size_t count, size_t *got, p_tm tm);
46int sock_recv(p_sock ps, char *data, size_t count,
47 size_t *got, int timeout);
48int sock_sendto(p_sock ps, const char *data, size_t count, 46int sock_sendto(p_sock ps, const char *data, size_t count,
49 size_t *sent, SA *addr, socklen_t addr_len, int timeout); 47 size_t *sent, SA *addr, socklen_t addr_len, p_tm tm);
50int sock_recvfrom(p_sock ps, char *data, size_t count, 48int sock_recvfrom(p_sock ps, char *data, size_t count,
51 size_t *got, SA *addr, socklen_t *addr_len, int timeout); 49 size_t *got, SA *addr, socklen_t *addr_len, p_tm tm);
52void sock_setnonblocking(p_sock ps); 50void sock_setnonblocking(p_sock ps);
53void sock_setblocking(p_sock ps); 51void sock_setblocking(p_sock ps);
54int sock_select(int n, fd_set *rfds, fd_set *wfds, fd_set *efds, int timeout); 52int sock_select(int n, fd_set *rfds, fd_set *wfds, fd_set *efds, p_tm tm);
55 53
56const char *sock_connect(p_sock ps, SA *addr, socklen_t addr_len, p_tm tm); 54const char *sock_connect(p_sock ps, SA *addr, socklen_t addr_len, p_tm tm);
57const char *sock_create(p_sock ps, int domain, int type, int protocol); 55const char *sock_create(p_sock ps, int domain, int type, int protocol);
@@ -60,6 +58,8 @@ const char *sock_listen(p_sock ps, int backlog);
60const char *sock_accept(p_sock ps, p_sock pa, SA *addr, 58const char *sock_accept(p_sock ps, p_sock pa, SA *addr,
61 socklen_t *addr_len, p_tm tm); 59 socklen_t *addr_len, p_tm tm);
62 60
61const char *sock_geterr(p_sock ps, int code);
63const char *sock_hoststrerror(void); 62const char *sock_hoststrerror(void);
63const char *sock_strerror(void);
64 64
65#endif /* SOCK_H */ 65#endif /* SOCK_H */
diff --git a/src/tcp.c b/src/tcp.c
index 6c58494..8ab7d62 100644
--- a/src/tcp.c
+++ b/src/tcp.c
@@ -163,7 +163,8 @@ static int meth_accept(lua_State *L)
163 /* initialize structure fields */ 163 /* initialize structure fields */
164 sock_setnonblocking(&sock); 164 sock_setnonblocking(&sock);
165 clnt->sock = sock; 165 clnt->sock = sock;
166 io_init(&clnt->io, (p_send)sock_send, (p_recv)sock_recv, &clnt->sock); 166 io_init(&clnt->io, (p_send) sock_send, (p_recv) sock_recv,
167 (p_geterr) sock_geterr, &clnt->sock);
167 tm_init(&clnt->tm, -1, -1); 168 tm_init(&clnt->tm, -1, -1);
168 buf_init(&clnt->buf, &clnt->io, &clnt->tm); 169 buf_init(&clnt->buf, &clnt->io, &clnt->tm);
169 return 1; 170 return 1;
@@ -313,7 +314,8 @@ static int global_create(lua_State *L)
313 /* initialize remaining structure fields */ 314 /* initialize remaining structure fields */
314 sock_setnonblocking(&sock); 315 sock_setnonblocking(&sock);
315 tcp->sock = sock; 316 tcp->sock = sock;
316 io_init(&tcp->io, (p_send) sock_send, (p_recv) sock_recv, &tcp->sock); 317 io_init(&tcp->io, (p_send) sock_send, (p_recv) sock_recv,
318 (p_geterr) sock_geterr, &tcp->sock);
317 tm_init(&tcp->tm, -1, -1); 319 tm_init(&tcp->tm, -1, -1);
318 buf_init(&tcp->buf, &tcp->io, &tcp->tm); 320 buf_init(&tcp->buf, &tcp->io, &tcp->tm);
319 return 1; 321 return 1;
diff --git a/src/timeout.c b/src/timeout.c
index dcc2105..74ba968 100644
--- a/src/timeout.c
+++ b/src/timeout.c
@@ -46,8 +46,7 @@ static luaL_reg func[] = {
46/*-------------------------------------------------------------------------*\ 46/*-------------------------------------------------------------------------*\
47* Initialize structure 47* Initialize structure
48\*-------------------------------------------------------------------------*/ 48\*-------------------------------------------------------------------------*/
49void tm_init(p_tm tm, int block, int total) 49void tm_init(p_tm tm, double block, double total) {
50{
51 tm->block = block; 50 tm->block = block;
52 tm->total = total; 51 tm->total = total;
53} 52}
@@ -60,18 +59,17 @@ void tm_init(p_tm tm, int block, int total)
60* Returns 59* Returns
61* the number of ms left or -1 if there is no time limit 60* the number of ms left or -1 if there is no time limit
62\*-------------------------------------------------------------------------*/ 61\*-------------------------------------------------------------------------*/
63int tm_get(p_tm tm) 62double tm_get(p_tm tm) {
64{ 63 if (tm->block < 0.0 && tm->total < 0.0) {
65 if (tm->block < 0 && tm->total < 0) {
66 return -1; 64 return -1;
67 } else if (tm->block < 0) { 65 } else if (tm->block < 0.0) {
68 int t = tm->total - tm_gettime() + tm->start; 66 double t = tm->total - tm_gettime() + tm->start;
69 return MAX(t, 0); 67 return MAX(t, 0.0);
70 } else if (tm->total < 0) { 68 } else if (tm->total < 0.0) {
71 return tm->block; 69 return tm->block;
72 } else { 70 } else {
73 int t = tm->total - tm_gettime() + tm->start; 71 double t = tm->total - tm_gettime() + tm->start;
74 return MIN(tm->block, MAX(t, 0)); 72 return MIN(tm->block, MAX(t, 0.0));
75 } 73 }
76} 74}
77 75
@@ -82,8 +80,7 @@ int tm_get(p_tm tm)
82* Returns 80* Returns
83* start field of structure 81* start field of structure
84\*-------------------------------------------------------------------------*/ 82\*-------------------------------------------------------------------------*/
85int tm_getstart(p_tm tm) 83double tm_getstart(p_tm tm) {
86{
87 return tm->start; 84 return tm->start;
88} 85}
89 86
@@ -95,19 +92,18 @@ int tm_getstart(p_tm tm)
95* Returns 92* Returns
96* the number of ms left or -1 if there is no time limit 93* the number of ms left or -1 if there is no time limit
97\*-------------------------------------------------------------------------*/ 94\*-------------------------------------------------------------------------*/
98int tm_getretry(p_tm tm) 95double tm_getretry(p_tm tm) {
99{ 96 if (tm->block < 0.0 && tm->total < 0.0) {
100 if (tm->block < 0 && tm->total < 0) {
101 return -1; 97 return -1;
102 } else if (tm->block < 0) { 98 } else if (tm->block < 0.0) {
103 int t = tm->total - tm_gettime() + tm->start; 99 double t = tm->total - tm_gettime() + tm->start;
104 return MAX(t, 0); 100 return MAX(t, 0.0);
105 } else if (tm->total < 0) { 101 } else if (tm->total < 0.0) {
106 int t = tm->block - tm_gettime() + tm->start; 102 double t = tm->block - tm_gettime() + tm->start;
107 return MAX(t, 0); 103 return MAX(t, 0.0);
108 } else { 104 } else {
109 int t = tm->total - tm_gettime() + tm->start; 105 double t = tm->total - tm_gettime() + tm->start;
110 return MIN(tm->block, MAX(t, 0)); 106 return MIN(tm->block, MAX(t, 0.0));
111 } 107 }
112} 108}
113 109
@@ -116,8 +112,7 @@ int tm_getretry(p_tm tm)
116* Input 112* Input
117* tm: timeout control structure 113* tm: timeout control structure
118\*-------------------------------------------------------------------------*/ 114\*-------------------------------------------------------------------------*/
119p_tm tm_markstart(p_tm tm) 115p_tm tm_markstart(p_tm tm) {
120{
121 tm->start = tm_gettime(); 116 tm->start = tm_gettime();
122 return tm; 117 return tm;
123} 118}
@@ -128,24 +123,23 @@ p_tm tm_markstart(p_tm tm)
128* time in ms. 123* time in ms.
129\*-------------------------------------------------------------------------*/ 124\*-------------------------------------------------------------------------*/
130#ifdef _WIN32 125#ifdef _WIN32
131int tm_gettime(void) 126double tm_gettime(void) {
132{ 127 FILETIME ft;
133 return GetTickCount(); 128 GetSystemTimeAsFileTime(&ft);
129 return ft.dwLowDateTime/1.0e7 + ft.dwHighDateTime*(4294967296.0/1.0e7);
134} 130}
135#else 131#else
136int tm_gettime(void) 132double tm_gettime(void) {
137{
138 struct timeval v; 133 struct timeval v;
139 gettimeofday(&v, (struct timezone *) NULL); 134 gettimeofday(&v, (struct timezone *) NULL);
140 return v.tv_sec * 1000 + v.tv_usec/1000; 135 return v.tv_sec + v.tv_usec/1.0e6;
141} 136}
142#endif 137#endif
143 138
144/*-------------------------------------------------------------------------*\ 139/*-------------------------------------------------------------------------*\
145* Initializes module 140* Initializes module
146\*-------------------------------------------------------------------------*/ 141\*-------------------------------------------------------------------------*/
147int tm_open(lua_State *L) 142int tm_open(lua_State *L) {
148{
149 luaL_openlib(L, NULL, func, 0); 143 luaL_openlib(L, NULL, func, 0);
150 return 0; 144 return 0;
151} 145}
@@ -156,16 +150,15 @@ int tm_open(lua_State *L)
156* time: time out value in seconds 150* time: time out value in seconds
157* mode: "b" for block timeout, "t" for total timeout. (default: b) 151* mode: "b" for block timeout, "t" for total timeout. (default: b)
158\*-------------------------------------------------------------------------*/ 152\*-------------------------------------------------------------------------*/
159int tm_meth_settimeout(lua_State *L, p_tm tm) 153int tm_meth_settimeout(lua_State *L, p_tm tm) {
160{ 154 double t = luaL_optnumber(L, 2, -1);
161 int ms = lua_isnil(L, 2) ? -1 : (int) (luaL_checknumber(L, 2)*1000.0);
162 const char *mode = luaL_optstring(L, 3, "b"); 155 const char *mode = luaL_optstring(L, 3, "b");
163 switch (*mode) { 156 switch (*mode) {
164 case 'b': 157 case 'b':
165 tm->block = ms; 158 tm->block = t;
166 break; 159 break;
167 case 'r': case 't': 160 case 'r': case 't':
168 tm->total = ms; 161 tm->total = t;
169 break; 162 break;
170 default: 163 default:
171 luaL_argcheck(L, 0, 3, "invalid timeout mode"); 164 luaL_argcheck(L, 0, 3, "invalid timeout mode");
@@ -183,7 +176,7 @@ int tm_meth_settimeout(lua_State *L, p_tm tm)
183\*-------------------------------------------------------------------------*/ 176\*-------------------------------------------------------------------------*/
184static int tm_lua_gettime(lua_State *L) 177static int tm_lua_gettime(lua_State *L)
185{ 178{
186 lua_pushnumber(L, tm_gettime()/1000.0); 179 lua_pushnumber(L, tm_gettime());
187 return 1; 180 return 1;
188} 181}
189 182
diff --git a/src/timeout.h b/src/timeout.h
index 6b105c3..817922f 100644
--- a/src/timeout.h
+++ b/src/timeout.h
@@ -10,19 +10,19 @@
10 10
11/* timeout control structure */ 11/* timeout control structure */
12typedef struct t_tm_ { 12typedef struct t_tm_ {
13 int total; /* total number of miliseconds for operation */ 13 double total; /* total number of miliseconds for operation */
14 int block; /* maximum time for blocking calls */ 14 double block; /* maximum time for blocking calls */
15 int start; /* time of start of operation */ 15 double start; /* time of start of operation */
16} t_tm; 16} t_tm;
17typedef t_tm *p_tm; 17typedef t_tm *p_tm;
18 18
19int tm_open(lua_State *L); 19int tm_open(lua_State *L);
20void tm_init(p_tm tm, int block, int total); 20void tm_init(p_tm tm, double block, double total);
21int tm_get(p_tm tm); 21double tm_get(p_tm tm);
22int tm_getretry(p_tm tm); 22double tm_getretry(p_tm tm);
23p_tm tm_markstart(p_tm tm); 23p_tm tm_markstart(p_tm tm);
24int tm_getstart(p_tm tm); 24double tm_getstart(p_tm tm);
25int tm_gettime(void); 25double tm_gettime(void);
26int tm_meth_settimeout(lua_State *L, p_tm tm); 26int tm_meth_settimeout(lua_State *L, p_tm tm);
27 27
28#endif /* TM_H */ 28#endif /* TM_H */
diff --git a/src/udp.c b/src/udp.c
index d20d61b..a71be73 100644
--- a/src/udp.c
+++ b/src/udp.c
@@ -41,25 +41,26 @@ static int meth_settimeout(lua_State *L);
41static int meth_getfd(lua_State *L); 41static int meth_getfd(lua_State *L);
42static int meth_setfd(lua_State *L); 42static int meth_setfd(lua_State *L);
43static int meth_dirty(lua_State *L); 43static int meth_dirty(lua_State *L);
44static void pusherror(lua_State *L, int code);
44 45
45/* udp object methods */ 46/* udp object methods */
46static luaL_reg udp[] = { 47static luaL_reg udp[] = {
47 {"setpeername", meth_setpeername},
48 {"setsockname", meth_setsockname},
49 {"getsockname", meth_getsockname},
50 {"getpeername", meth_getpeername},
51 {"send", meth_send},
52 {"sendto", meth_sendto},
53 {"receive", meth_receive},
54 {"receivefrom", meth_receivefrom},
55 {"settimeout", meth_settimeout},
56 {"close", meth_close},
57 {"setoption", meth_setoption},
58 {"__gc", meth_close}, 48 {"__gc", meth_close},
59 {"__tostring", aux_tostring}, 49 {"__tostring", aux_tostring},
50 {"close", meth_close},
51 {"dirty", meth_dirty},
60 {"getfd", meth_getfd}, 52 {"getfd", meth_getfd},
53 {"getpeername", meth_getpeername},
54 {"getsockname", meth_getsockname},
55 {"receive", meth_receive},
56 {"receivefrom", meth_receivefrom},
57 {"send", meth_send},
58 {"sendto", meth_sendto},
61 {"setfd", meth_setfd}, 59 {"setfd", meth_setfd},
62 {"dirty", meth_dirty}, 60 {"setoption", meth_setoption},
61 {"setpeername", meth_setpeername},
62 {"setsockname", meth_setsockname},
63 {"settimeout", meth_settimeout},
63 {NULL, NULL} 64 {NULL, NULL}
64}; 65};
65 66
@@ -99,35 +100,43 @@ int udp_open(lua_State *L)
99 return 0; 100 return 0;
100} 101}
101 102
103
102/*=========================================================================*\ 104/*=========================================================================*\
103* Lua methods 105* Lua methods
104\*=========================================================================*/ 106\*=========================================================================*/
105/*-------------------------------------------------------------------------*\ 107/*-------------------------------------------------------------------------*\
108* Pushes the error message
109\*-------------------------------------------------------------------------*/
110void pusherror(lua_State *L, int code) {
111 const char *err = code != IO_USER? io_strerror(code): "refused";
112 err = err? err: sock_strerror();
113 if (err) lua_pushstring(L, err);
114 else lua_pushnil(L);
115}
116
117/*-------------------------------------------------------------------------*\
106* Send data through connected udp socket 118* Send data through connected udp socket
107\*-------------------------------------------------------------------------*/ 119\*-------------------------------------------------------------------------*/
108static int meth_send(lua_State *L) 120static int meth_send(lua_State *L) {
109{
110 p_udp udp = (p_udp) aux_checkclass(L, "udp{connected}", 1); 121 p_udp udp = (p_udp) aux_checkclass(L, "udp{connected}", 1);
111 p_tm tm = &udp->tm; 122 p_tm tm = &udp->tm;
112 size_t count, sent = 0; 123 size_t count, sent = 0;
113 int err; 124 int err;
114 const char *data = luaL_checklstring(L, 2, &count); 125 const char *data = luaL_checklstring(L, 2, &count);
115 tm_markstart(tm); 126 tm_markstart(tm);
116 do err = sock_send(&udp->sock, data, count, &sent, tm_getretry(tm)); 127 err = sock_send(&udp->sock, data, count, &sent, tm);
117 while (err == IO_RETRY);
118 if (err == IO_DONE) lua_pushnumber(L, sent); 128 if (err == IO_DONE) lua_pushnumber(L, sent);
119 else lua_pushnil(L); 129 else lua_pushnil(L);
120 /* a 'closed' error on an unconnected means the target address was not 130 /* a 'closed' error on an unconnected means the target address was not
121 * accepted by the transport layer */ 131 * accepted by the transport layer */
122 io_pusherror(L, err == IO_CLOSED ? IO_REFUSED : err); 132 pusherror(L, err == IO_CLOSED ? IO_USER : err);
123 return 2; 133 return 2;
124} 134}
125 135
126/*-------------------------------------------------------------------------*\ 136/*-------------------------------------------------------------------------*\
127* Send data through unconnected udp socket 137* Send data through unconnected udp socket
128\*-------------------------------------------------------------------------*/ 138\*-------------------------------------------------------------------------*/
129static int meth_sendto(lua_State *L) 139static int meth_sendto(lua_State *L) {
130{
131 p_udp udp = (p_udp) aux_checkclass(L, "udp{unconnected}", 1); 140 p_udp udp = (p_udp) aux_checkclass(L, "udp{unconnected}", 1);
132 size_t count, sent = 0; 141 size_t count, sent = 0;
133 const char *data = luaL_checklstring(L, 2, &count); 142 const char *data = luaL_checklstring(L, 2, &count);
@@ -142,22 +151,20 @@ static int meth_sendto(lua_State *L)
142 addr.sin_family = AF_INET; 151 addr.sin_family = AF_INET;
143 addr.sin_port = htons(port); 152 addr.sin_port = htons(port);
144 tm_markstart(tm); 153 tm_markstart(tm);
145 do err = sock_sendto(&udp->sock, data, count, &sent, 154 err = sock_sendto(&udp->sock, data, count, &sent,
146 (SA *) &addr, sizeof(addr), tm_get(tm)); 155 (SA *) &addr, sizeof(addr), tm);
147 while (err == IO_RETRY);
148 if (err == IO_DONE) lua_pushnumber(L, sent); 156 if (err == IO_DONE) lua_pushnumber(L, sent);
149 else lua_pushnil(L); 157 else lua_pushnil(L);
150 /* a 'closed' error on an unconnected means the target address was not 158 /* a 'closed' error on an unconnected means the target address was not
151 * accepted by the transport layer */ 159 * accepted by the transport layer */
152 io_pusherror(L, err == IO_CLOSED ? IO_REFUSED : err); 160 pusherror(L, err == IO_CLOSED ? IO_USER : err);
153 return 2; 161 return 2;
154} 162}
155 163
156/*-------------------------------------------------------------------------*\ 164/*-------------------------------------------------------------------------*\
157* Receives data from a UDP socket 165* Receives data from a UDP socket
158\*-------------------------------------------------------------------------*/ 166\*-------------------------------------------------------------------------*/
159static int meth_receive(lua_State *L) 167static int meth_receive(lua_State *L) {
160{
161 p_udp udp = (p_udp) aux_checkgroup(L, "udp{any}", 1); 168 p_udp udp = (p_udp) aux_checkgroup(L, "udp{any}", 1);
162 char buffer[UDP_DATAGRAMSIZE]; 169 char buffer[UDP_DATAGRAMSIZE];
163 size_t got, count = (size_t) luaL_optnumber(L, 2, sizeof(buffer)); 170 size_t got, count = (size_t) luaL_optnumber(L, 2, sizeof(buffer));
@@ -165,19 +172,17 @@ static int meth_receive(lua_State *L)
165 p_tm tm = &udp->tm; 172 p_tm tm = &udp->tm;
166 count = MIN(count, sizeof(buffer)); 173 count = MIN(count, sizeof(buffer));
167 tm_markstart(tm); 174 tm_markstart(tm);
168 do err = sock_recv(&udp->sock, buffer, count, &got, tm_get(tm)); 175 err = sock_recv(&udp->sock, buffer, count, &got, tm);
169 while (err == IO_RETRY);
170 if (err == IO_DONE) lua_pushlstring(L, buffer, got); 176 if (err == IO_DONE) lua_pushlstring(L, buffer, got);
171 else lua_pushnil(L); 177 else lua_pushnil(L);
172 io_pusherror(L, err); 178 pusherror(L, err);
173 return 2; 179 return 2;
174} 180}
175 181
176/*-------------------------------------------------------------------------*\ 182/*-------------------------------------------------------------------------*\
177* Receives data and sender from a UDP socket 183* Receives data and sender from a UDP socket
178\*-------------------------------------------------------------------------*/ 184\*-------------------------------------------------------------------------*/
179static int meth_receivefrom(lua_State *L) 185static int meth_receivefrom(lua_State *L) {
180{
181 p_udp udp = (p_udp) aux_checkclass(L, "udp{unconnected}", 1); 186 p_udp udp = (p_udp) aux_checkclass(L, "udp{unconnected}", 1);
182 struct sockaddr_in addr; 187 struct sockaddr_in addr;
183 socklen_t addr_len = sizeof(addr); 188 socklen_t addr_len = sizeof(addr);
@@ -187,9 +192,8 @@ static int meth_receivefrom(lua_State *L)
187 p_tm tm = &udp->tm; 192 p_tm tm = &udp->tm;
188 tm_markstart(tm); 193 tm_markstart(tm);
189 count = MIN(count, sizeof(buffer)); 194 count = MIN(count, sizeof(buffer));
190 do err = sock_recvfrom(&udp->sock, buffer, count, &got, 195 err = sock_recvfrom(&udp->sock, buffer, count, &got,
191 (SA *) &addr, &addr_len, tm_get(tm)); 196 (SA *) &addr, &addr_len, tm);
192 while (err == IO_RETRY);
193 if (err == IO_DONE) { 197 if (err == IO_DONE) {
194 lua_pushlstring(L, buffer, got); 198 lua_pushlstring(L, buffer, got);
195 lua_pushstring(L, inet_ntoa(addr.sin_addr)); 199 lua_pushstring(L, inet_ntoa(addr.sin_addr));
@@ -197,7 +201,7 @@ static int meth_receivefrom(lua_State *L)
197 return 3; 201 return 3;
198 } else { 202 } else {
199 lua_pushnil(L); 203 lua_pushnil(L);
200 io_pusherror(L, err); 204 pusherror(L, err);
201 return 2; 205 return 2;
202 } 206 }
203} 207}
@@ -205,23 +209,20 @@ static int meth_receivefrom(lua_State *L)
205/*-------------------------------------------------------------------------*\ 209/*-------------------------------------------------------------------------*\
206* Select support methods 210* Select support methods
207\*-------------------------------------------------------------------------*/ 211\*-------------------------------------------------------------------------*/
208static int meth_getfd(lua_State *L) 212static int meth_getfd(lua_State *L) {
209{
210 p_udp udp = (p_udp) aux_checkgroup(L, "udp{any}", 1); 213 p_udp udp = (p_udp) aux_checkgroup(L, "udp{any}", 1);
211 lua_pushnumber(L, (int) udp->sock); 214 lua_pushnumber(L, (int) udp->sock);
212 return 1; 215 return 1;
213} 216}
214 217
215/* this is very dangerous, but can be handy for those that are brave enough */ 218/* this is very dangerous, but can be handy for those that are brave enough */
216static int meth_setfd(lua_State *L) 219static int meth_setfd(lua_State *L) {
217{
218 p_udp udp = (p_udp) aux_checkgroup(L, "udp{any}", 1); 220 p_udp udp = (p_udp) aux_checkgroup(L, "udp{any}", 1);
219 udp->sock = (t_sock) luaL_checknumber(L, 2); 221 udp->sock = (t_sock) luaL_checknumber(L, 2);
220 return 0; 222 return 0;
221} 223}
222 224
223static int meth_dirty(lua_State *L) 225static int meth_dirty(lua_State *L) {
224{
225 p_udp udp = (p_udp) aux_checkgroup(L, "udp{any}", 1); 226 p_udp udp = (p_udp) aux_checkgroup(L, "udp{any}", 1);
226 (void) udp; 227 (void) udp;
227 lua_pushboolean(L, 0); 228 lua_pushboolean(L, 0);
@@ -231,14 +232,12 @@ static int meth_dirty(lua_State *L)
231/*-------------------------------------------------------------------------*\ 232/*-------------------------------------------------------------------------*\
232* Just call inet methods 233* Just call inet methods
233\*-------------------------------------------------------------------------*/ 234\*-------------------------------------------------------------------------*/
234static int meth_getpeername(lua_State *L) 235static int meth_getpeername(lua_State *L) {
235{
236 p_udp udp = (p_udp) aux_checkclass(L, "udp{connected}", 1); 236 p_udp udp = (p_udp) aux_checkclass(L, "udp{connected}", 1);
237 return inet_meth_getpeername(L, &udp->sock); 237 return inet_meth_getpeername(L, &udp->sock);
238} 238}
239 239
240static int meth_getsockname(lua_State *L) 240static int meth_getsockname(lua_State *L) {
241{
242 p_udp udp = (p_udp) aux_checkgroup(L, "udp{any}", 1); 241 p_udp udp = (p_udp) aux_checkgroup(L, "udp{any}", 1);
243 return inet_meth_getsockname(L, &udp->sock); 242 return inet_meth_getsockname(L, &udp->sock);
244} 243}
@@ -246,8 +245,7 @@ static int meth_getsockname(lua_State *L)
246/*-------------------------------------------------------------------------*\ 245/*-------------------------------------------------------------------------*\
247* Just call option handler 246* Just call option handler
248\*-------------------------------------------------------------------------*/ 247\*-------------------------------------------------------------------------*/
249static int meth_setoption(lua_State *L) 248static int meth_setoption(lua_State *L) {
250{
251 p_udp udp = (p_udp) aux_checkgroup(L, "udp{any}", 1); 249 p_udp udp = (p_udp) aux_checkgroup(L, "udp{any}", 1);
252 return opt_meth_setoption(L, opt, &udp->sock); 250 return opt_meth_setoption(L, opt, &udp->sock);
253} 251}
@@ -255,8 +253,7 @@ static int meth_setoption(lua_State *L)
255/*-------------------------------------------------------------------------*\ 253/*-------------------------------------------------------------------------*\
256* Just call tm methods 254* Just call tm methods
257\*-------------------------------------------------------------------------*/ 255\*-------------------------------------------------------------------------*/
258static int meth_settimeout(lua_State *L) 256static int meth_settimeout(lua_State *L) {
259{
260 p_udp udp = (p_udp) aux_checkgroup(L, "udp{any}", 1); 257 p_udp udp = (p_udp) aux_checkgroup(L, "udp{any}", 1);
261 return tm_meth_settimeout(L, &udp->tm); 258 return tm_meth_settimeout(L, &udp->tm);
262} 259}
@@ -264,8 +261,7 @@ static int meth_settimeout(lua_State *L)
264/*-------------------------------------------------------------------------*\ 261/*-------------------------------------------------------------------------*\
265* Turns a master udp object into a client object. 262* Turns a master udp object into a client object.
266\*-------------------------------------------------------------------------*/ 263\*-------------------------------------------------------------------------*/
267static int meth_setpeername(lua_State *L) 264static int meth_setpeername(lua_State *L) {
268{
269 p_udp udp = (p_udp) aux_checkclass(L, "udp{unconnected}", 1); 265 p_udp udp = (p_udp) aux_checkclass(L, "udp{unconnected}", 1);
270 p_tm tm = &udp->tm; 266 p_tm tm = &udp->tm;
271 const char *address = luaL_checkstring(L, 2); 267 const char *address = luaL_checkstring(L, 2);
@@ -289,8 +285,7 @@ static int meth_setpeername(lua_State *L)
289/*-------------------------------------------------------------------------*\ 285/*-------------------------------------------------------------------------*\
290* Closes socket used by object 286* Closes socket used by object
291\*-------------------------------------------------------------------------*/ 287\*-------------------------------------------------------------------------*/
292static int meth_close(lua_State *L) 288static int meth_close(lua_State *L) {
293{
294 p_udp udp = (p_udp) aux_checkgroup(L, "udp{any}", 1); 289 p_udp udp = (p_udp) aux_checkgroup(L, "udp{any}", 1);
295 sock_destroy(&udp->sock); 290 sock_destroy(&udp->sock);
296 return 0; 291 return 0;
@@ -299,8 +294,7 @@ static int meth_close(lua_State *L)
299/*-------------------------------------------------------------------------*\ 294/*-------------------------------------------------------------------------*\
300* Turns a master object into a server object 295* Turns a master object into a server object
301\*-------------------------------------------------------------------------*/ 296\*-------------------------------------------------------------------------*/
302static int meth_setsockname(lua_State *L) 297static int meth_setsockname(lua_State *L) {
303{
304 p_udp udp = (p_udp) aux_checkclass(L, "udp{unconnected}", 1); 298 p_udp udp = (p_udp) aux_checkclass(L, "udp{unconnected}", 1);
305 const char *address = luaL_checkstring(L, 2); 299 const char *address = luaL_checkstring(L, 2);
306 unsigned short port = (unsigned short) luaL_checknumber(L, 3); 300 unsigned short port = (unsigned short) luaL_checknumber(L, 3);
@@ -320,8 +314,7 @@ static int meth_setsockname(lua_State *L)
320/*-------------------------------------------------------------------------*\ 314/*-------------------------------------------------------------------------*\
321* Creates a master udp object 315* Creates a master udp object
322\*-------------------------------------------------------------------------*/ 316\*-------------------------------------------------------------------------*/
323static int global_create(lua_State *L) 317static int global_create(lua_State *L) {
324{
325 t_sock sock; 318 t_sock sock;
326 const char *err = inet_trycreate(&sock, SOCK_DGRAM); 319 const char *err = inet_trycreate(&sock, SOCK_DGRAM);
327 /* try to allocate a system socket */ 320 /* try to allocate a system socket */
diff --git a/src/usocket.c b/src/usocket.c
index cf0458d..12a13a5 100644
--- a/src/usocket.c
+++ b/src/usocket.c
@@ -20,17 +20,10 @@
20 20
21#include "socket.h" 21#include "socket.h"
22 22
23static const char *sock_createstrerror(int err);
24static const char *sock_bindstrerror(int err);
25static const char *sock_connectstrerror(int err);
26static const char *sock_acceptstrerror(int err);
27static const char *sock_listenstrerror(int err);
28
29/*-------------------------------------------------------------------------*\ 23/*-------------------------------------------------------------------------*\
30* Initializes module 24* Initializes module
31\*-------------------------------------------------------------------------*/ 25\*-------------------------------------------------------------------------*/
32int sock_open(void) 26int sock_open(void) {
33{
34#if DOESNT_COMPILE_TRY_THIS 27#if DOESNT_COMPILE_TRY_THIS
35 struct sigaction ignore; 28 struct sigaction ignore;
36 memset(&ignore, 0, sizeof(ignore)); 29 memset(&ignore, 0, sizeof(ignore));
@@ -45,16 +38,14 @@ int sock_open(void)
45/*-------------------------------------------------------------------------*\ 38/*-------------------------------------------------------------------------*\
46* Close module 39* Close module
47\*-------------------------------------------------------------------------*/ 40\*-------------------------------------------------------------------------*/
48int sock_close(void) 41int sock_close(void) {
49{
50 return 1; 42 return 1;
51} 43}
52 44
53/*-------------------------------------------------------------------------*\ 45/*-------------------------------------------------------------------------*\
54* Close and inutilize socket 46* Close and inutilize socket
55\*-------------------------------------------------------------------------*/ 47\*-------------------------------------------------------------------------*/
56void sock_destroy(p_sock ps) 48void sock_destroy(p_sock ps) {
57{
58 if (*ps != SOCK_INVALID) { 49 if (*ps != SOCK_INVALID) {
59 sock_setblocking(ps); 50 sock_setblocking(ps);
60 close(*ps); 51 close(*ps);
@@ -63,23 +54,26 @@ void sock_destroy(p_sock ps)
63} 54}
64 55
65/*-------------------------------------------------------------------------*\ 56/*-------------------------------------------------------------------------*\
66* Select with int timeout in ms 57* Select with timeout control
67\*-------------------------------------------------------------------------*/ 58\*-------------------------------------------------------------------------*/
68int sock_select(int n, fd_set *rfds, fd_set *wfds, fd_set *efds, int timeout) 59int sock_select(int n, fd_set *rfds, fd_set *wfds, fd_set *efds, p_tm tm) {
69{ 60 int ret;
70 struct timeval tv; 61 do {
71 tv.tv_sec = timeout / 1000; 62 struct timeval tv;
72 tv.tv_usec = (timeout % 1000) * 1000; 63 double t = tm_getretry(tm);
73 return select(n, rfds, wfds, efds, timeout >= 0? &tv: NULL); 64 tv.tv_sec = (int) t;
65 tv.tv_usec = (int) ((t - tv.tv_sec) * 1.0e6);
66 ret = select(n, rfds, wfds, efds, t >= 0.0? &tv: NULL);
67 } while (ret < 0 && errno == EINTR);
68 return ret;
74} 69}
75 70
76/*-------------------------------------------------------------------------*\ 71/*-------------------------------------------------------------------------*\
77* Creates and sets up a socket 72* Creates and sets up a socket
78\*-------------------------------------------------------------------------*/ 73\*-------------------------------------------------------------------------*/
79const char *sock_create(p_sock ps, int domain, int type, int protocol) 74const char *sock_create(p_sock ps, int domain, int type, int protocol) {
80{
81 t_sock sock = socket(domain, type, protocol); 75 t_sock sock = socket(domain, type, protocol);
82 if (sock == SOCK_INVALID) return sock_createstrerror(errno); 76 if (sock == SOCK_INVALID) return sock_strerror();
83 *ps = sock; 77 *ps = sock;
84 return NULL; 78 return NULL;
85} 79}
@@ -87,50 +81,49 @@ const char *sock_create(p_sock ps, int domain, int type, int protocol)
87/*-------------------------------------------------------------------------*\ 81/*-------------------------------------------------------------------------*\
88* Connects or returns error message 82* Connects or returns error message
89\*-------------------------------------------------------------------------*/ 83\*-------------------------------------------------------------------------*/
90const char *sock_connect(p_sock ps, SA *addr, socklen_t addr_len, p_tm tm) 84const char *sock_connect(p_sock ps, SA *addr, socklen_t addr_len, p_tm tm) {
91{
92 t_sock sock = *ps; 85 t_sock sock = *ps;
93 int err; 86 int err;
94 /* don't call on closed socket */ 87 /* don't call on closed socket */
95 if (sock == SOCK_INVALID) return io_strerror(IO_CLOSED); 88 if (sock == SOCK_INVALID) return io_strerror(IO_CLOSED);
96 /* ask system to connect */ 89 /* ask system to connect */
97 do err = connect(sock, addr, addr_len); 90 do err = connect(sock, addr, addr_len);
98 while (err < 0 && errno == EINTR); 91 while (err < 0 && errno == EINTR);
99 /* if no error, we're done */ 92 /* if no error, we're done */
100 if (err == 0) return NULL; 93 if (err == 0) return NULL;
101 /* make sure the system is trying to connect */ 94 /* make sure the system is trying to connect */
102 if (errno != EINPROGRESS) return sock_connectstrerror(errno); 95 if (errno != EINPROGRESS) return sock_strerror();
96 /* optimize for timeout = 0 */
97 if (tm_get(tm) == 0.0) return io_strerror(IO_TIMEOUT);
103 /* wait for a timeout or for the system's answer */ 98 /* wait for a timeout or for the system's answer */
104 for ( ;; ) { 99 for ( ;; ) {
105 fd_set rfds, wfds, efds; 100 fd_set rfds, wfds;
106 FD_ZERO(&rfds); FD_SET(sock, &rfds); 101 FD_ZERO(&rfds); FD_SET(sock, &rfds);
107 FD_ZERO(&wfds); FD_SET(sock, &wfds); 102 FD_ZERO(&wfds); FD_SET(sock, &wfds);
108 FD_ZERO(&efds); FD_SET(sock, &efds);
109 /* we run select to avoid busy waiting */ 103 /* we run select to avoid busy waiting */
110 do err = sock_select(sock+1, &rfds, &wfds, &efds, tm_getretry(tm)); 104 err = sock_select(sock+1, &rfds, &wfds, NULL, tm);
111 while (err < 0 && errno == EINTR); 105 /* if there was an event, check what happened */
112 /* if selects readable, try reading */
113 if (err > 0) { 106 if (err > 0) {
114 char dummy; 107 char dummy;
115 /* recv will set errno to the value a blocking connect would set */ 108 /* recv will set errno to the value a blocking connect would set */
116 if (recv(sock, &dummy, 0, 0) < 0 && errno != EAGAIN) 109 if (err > 1 && FD_ISSET(sock, &rfds) &&
117 return sock_connectstrerror(errno); 110 recv(sock, &dummy, 0, 0) < 0 && errno != EAGAIN)
111 return sock_strerror();
118 else 112 else
119 return NULL; 113 return NULL;
120 /* if no event happened, there was a timeout */ 114 /* if no event happened, there was a timeout */
121 } else return io_strerror(IO_TIMEOUT); 115 } else if (err == 0) return io_strerror(IO_TIMEOUT);
122 } 116 }
123 return io_strerror(IO_TIMEOUT); /* can't get here */ 117 return sock_strerror();
124} 118}
125 119
126/*-------------------------------------------------------------------------*\ 120/*-------------------------------------------------------------------------*\
127* Binds or returns error message 121* Binds or returns error message
128\*-------------------------------------------------------------------------*/ 122\*-------------------------------------------------------------------------*/
129const char *sock_bind(p_sock ps, SA *addr, socklen_t addr_len) 123const char *sock_bind(p_sock ps, SA *addr, socklen_t addr_len) {
130{
131 const char *err = NULL; 124 const char *err = NULL;
132 sock_setblocking(ps); 125 sock_setblocking(ps);
133 if (bind(*ps, addr, addr_len) < 0) err = sock_bindstrerror(errno); 126 if (bind(*ps, addr, addr_len) < 0) err = sock_strerror();
134 sock_setnonblocking(ps); 127 sock_setnonblocking(ps);
135 return err; 128 return err;
136} 129}
@@ -138,12 +131,10 @@ const char *sock_bind(p_sock ps, SA *addr, socklen_t addr_len)
138/*-------------------------------------------------------------------------*\ 131/*-------------------------------------------------------------------------*\
139* 132*
140\*-------------------------------------------------------------------------*/ 133\*-------------------------------------------------------------------------*/
141const char* sock_listen(p_sock ps, int backlog) 134const char* sock_listen(p_sock ps, int backlog) {
142{
143 const char *err = NULL; 135 const char *err = NULL;
144 sock_setblocking(ps); 136 sock_setblocking(ps);
145 if (listen(*ps, backlog)) 137 if (listen(*ps, backlog)) err = sock_strerror();
146 err = sock_listenstrerror(errno);
147 sock_setnonblocking(ps); 138 sock_setnonblocking(ps);
148 return err; 139 return err;
149} 140}
@@ -151,8 +142,7 @@ const char* sock_listen(p_sock ps, int backlog)
151/*-------------------------------------------------------------------------*\ 142/*-------------------------------------------------------------------------*\
152* 143*
153\*-------------------------------------------------------------------------*/ 144\*-------------------------------------------------------------------------*/
154void sock_shutdown(p_sock ps, int how) 145void sock_shutdown(p_sock ps, int how) {
155{
156 sock_setblocking(ps); 146 sock_setblocking(ps);
157 shutdown(*ps, how); 147 shutdown(*ps, how);
158 sock_setnonblocking(ps); 148 sock_setnonblocking(ps);
@@ -162,12 +152,11 @@ void sock_shutdown(p_sock ps, int how)
162* Accept with timeout 152* Accept with timeout
163\*-------------------------------------------------------------------------*/ 153\*-------------------------------------------------------------------------*/
164const char *sock_accept(p_sock ps, p_sock pa, SA *addr, 154const char *sock_accept(p_sock ps, p_sock pa, SA *addr,
165 socklen_t *addr_len, p_tm tm) 155 socklen_t *addr_len, p_tm tm) {
166{
167 t_sock sock = *ps; 156 t_sock sock = *ps;
168 SA dummy_addr; 157 SA dummy_addr;
169 socklen_t dummy_len = sizeof(dummy_addr); 158 socklen_t dummy_len = sizeof(dummy_addr);
170 if (sock == SOCK_INVALID) return io_strerror(IO_CLOSED); 159 if (sock == SOCK_INVALID) return io_strerror(IO_CLOSED);
171 if (!addr) addr = &dummy_addr; 160 if (!addr) addr = &dummy_addr;
172 if (!addr_len) addr_len = &dummy_len; 161 if (!addr_len) addr_len = &dummy_len;
173 for (;;) { 162 for (;;) {
@@ -179,14 +168,16 @@ const char *sock_accept(p_sock ps, p_sock pa, SA *addr,
179 /* if result is valid, we are done */ 168 /* if result is valid, we are done */
180 if (*pa != SOCK_INVALID) return NULL; 169 if (*pa != SOCK_INVALID) return NULL;
181 /* find out if we failed for a fatal reason */ 170 /* find out if we failed for a fatal reason */
182 if (errno != EAGAIN && errno != ECONNABORTED) 171 /* if connection was aborted, we can try again if we have time */
183 return sock_acceptstrerror(errno); 172 if (errno != EAGAIN && errno != ECONNABORTED) return sock_strerror();
173 /* optimize for timeout = 0 case */
174 if (tm_get(tm) == 0.0) return io_strerror(IO_TIMEOUT);
184 /* call select to avoid busy-wait. */ 175 /* call select to avoid busy-wait. */
185 FD_ZERO(&fds); 176 FD_ZERO(&fds);
186 FD_SET(sock, &fds); 177 FD_SET(sock, &fds);
187 do err = sock_select(sock+1, &fds, NULL, NULL, tm_getretry(tm)); 178 err = sock_select(sock+1, &fds, NULL, NULL, tm);
188 while (err < 0 && errno == EINTR);
189 if (err == 0) return io_strerror(IO_TIMEOUT); 179 if (err == 0) return io_strerror(IO_TIMEOUT);
180 else if (err < 0) return sock_strerror();
190 } 181 }
191 return io_strerror(IO_TIMEOUT); /* can't get here */ 182 return io_strerror(IO_TIMEOUT); /* can't get here */
192} 183}
@@ -194,136 +185,136 @@ const char *sock_accept(p_sock ps, p_sock pa, SA *addr,
194/*-------------------------------------------------------------------------*\ 185/*-------------------------------------------------------------------------*\
195* Send with timeout 186* Send with timeout
196\*-------------------------------------------------------------------------*/ 187\*-------------------------------------------------------------------------*/
197int sock_send(p_sock ps, const char *data, size_t count, size_t *sent, 188int sock_send(p_sock ps, const char *data, size_t count, size_t *sent, p_tm tm)
198 int timeout)
199{ 189{
200 t_sock sock = *ps; 190 t_sock sock = *ps;
201 ssize_t put;
202 /* avoid making system calls on closed sockets */ 191 /* avoid making system calls on closed sockets */
203 if (sock == SOCK_INVALID) return IO_CLOSED; 192 if (sock == SOCK_INVALID) return IO_CLOSED;
204 /* make sure we repeat in case the call was interrupted */ 193 /* loop until we send something or we give up on error */
205 do put = send(sock, data, count, 0); 194 for ( ;; ) {
206 while (put < 0 && errno == EINTR);
207 /* deal with failure */
208 if (put <= 0) {
209 int ret; 195 int ret;
210 fd_set fds; 196 fd_set fds;
211 /* in any case, nothing has been sent */ 197 ssize_t put;
198 /* make sure we repeat in case the call was interrupted */
199 do put = send(sock, data, count, 0);
200 while (put < 0 && errno == EINTR);
201 /* if we sent something, get out */
202 if (put > 0) {
203 *sent = put;
204 return IO_DONE;
205 }
206 /* deal with failure */
212 *sent = 0; 207 *sent = 0;
213 /* only proceed to select if no error happened */
214 if (errno != EAGAIN) return IO_ERROR;
215 /* optimize for the timeout = 0 case */
216 if (timeout == 0) return IO_TIMEOUT;
217 /* here we know the connection has been closed */ 208 /* here we know the connection has been closed */
218 if (errno == EPIPE) return IO_CLOSED; 209 if (put < 0 && errno == EPIPE) return IO_CLOSED;
210 /* send shouldn't return zero and we can only proceed if
211 * there was no serious error */
212 if (put == 0 || errno != EAGAIN) return IO_USER;
213 /* optimize for the timeout = 0 case */
214 if (tm_get(tm) == 0.0) return IO_TIMEOUT;
219 /* run select to avoid busy wait */ 215 /* run select to avoid busy wait */
220 FD_ZERO(&fds); 216 FD_ZERO(&fds);
221 FD_SET(sock, &fds); 217 FD_SET(sock, &fds);
222 ret = sock_select(sock+1, NULL, &fds, NULL, timeout); 218 ret = sock_select(sock+1, NULL, &fds, NULL, tm);
223 if (ret == 0) return IO_TIMEOUT; 219 if (ret == 0) return IO_TIMEOUT;
224 else if (ret > 0 || errno == EINTR) return IO_RETRY; 220 if (ret < 0) return IO_USER;
225 else return IO_ERROR; 221 /* otherwise, try sending again */
226 /* here we successfully sent something */ 222 }
227 } else {
228 *sent = put;
229 return IO_DONE;
230 }
231} 223}
232 224
233/*-------------------------------------------------------------------------*\ 225/*-------------------------------------------------------------------------*\
234* Sendto with timeout 226* Sendto with timeout
235\*-------------------------------------------------------------------------*/ 227\*-------------------------------------------------------------------------*/
236int sock_sendto(p_sock ps, const char *data, size_t count, size_t *sent, 228int sock_sendto(p_sock ps, const char *data, size_t count, size_t *sent,
237 SA *addr, socklen_t addr_len, int timeout) 229 SA *addr, socklen_t addr_len, p_tm tm)
238{ 230{
239 t_sock sock = *ps; 231 t_sock sock = *ps;
240 ssize_t put; 232 /* avoid making system calls on closed sockets */
241 if (sock == SOCK_INVALID) return IO_CLOSED; 233 if (sock == SOCK_INVALID) return IO_CLOSED;
242 do put = sendto(sock, data, count, 0, addr, addr_len); 234 /* loop until we send something or we give up on error */
243 while (put < 0 && errno == EINTR); 235 for ( ;; ) {
244 if (put <= 0) {
245 int ret; 236 int ret;
246 fd_set fds; 237 fd_set fds;
238 ssize_t put;
239 do put = sendto(sock, data, count, 0, addr, addr_len);
240 while (put < 0 && errno == EINTR);
241 if (put > 0) {
242 *sent = put;
243 return IO_DONE;
244 }
247 *sent = 0; 245 *sent = 0;
248 if (errno != EAGAIN) return IO_ERROR; 246 if (put < 0 && errno == EPIPE) return IO_CLOSED;
249 if (timeout == 0) return IO_TIMEOUT; 247 if (put == 0 || errno != EAGAIN) return IO_USER;
250 if (errno == EPIPE) return IO_CLOSED; 248 if (tm_get(tm) == 0.0) return IO_TIMEOUT;
251 FD_ZERO(&fds); 249 FD_ZERO(&fds);
252 FD_SET(sock, &fds); 250 FD_SET(sock, &fds);
253 ret = sock_select(sock+1, NULL, &fds, NULL, timeout); 251 ret = sock_select(sock+1, NULL, &fds, NULL, tm);
254 if (ret == 0) return IO_TIMEOUT; 252 if (ret == 0) return IO_TIMEOUT;
255 else if (ret > 0 || errno == EINTR) return IO_RETRY; 253 if (ret < 0) return IO_USER;
256 else return IO_ERROR; 254 }
257 } else {
258 *sent = put;
259 return IO_DONE;
260 }
261} 255}
262 256
263/*-------------------------------------------------------------------------*\ 257/*-------------------------------------------------------------------------*\
264* Receive with timeout 258* Receive with timeout
265\*-------------------------------------------------------------------------*/ 259\*-------------------------------------------------------------------------*/
266int sock_recv(p_sock ps, char *data, size_t count, size_t *got, int timeout) 260int sock_recv(p_sock ps, char *data, size_t count, size_t *got, p_tm tm) {
267{
268 t_sock sock = *ps; 261 t_sock sock = *ps;
269 ssize_t taken;
270 if (sock == SOCK_INVALID) return IO_CLOSED; 262 if (sock == SOCK_INVALID) return IO_CLOSED;
271 do taken = read(sock, data, count); 263 for ( ;; ) {
272 while (taken < 0 && errno == EINTR);
273 if (taken <= 0) {
274 fd_set fds; 264 fd_set fds;
275 int ret; 265 int ret;
266 ssize_t taken;
267 do taken = read(sock, data, count);
268 while (taken < 0 && errno == EINTR);
269 if (taken > 0) {
270 *got = taken;
271 return IO_DONE;
272 }
276 *got = 0; 273 *got = 0;
277 if (taken == 0) return IO_CLOSED; 274 if (taken == 0) return IO_CLOSED;
278 if (errno != EAGAIN) return IO_ERROR; 275 if (errno != EAGAIN) return IO_USER;
279 if (timeout == 0) return IO_TIMEOUT; 276 if (tm_get(tm) == 0.0) return IO_TIMEOUT;
280 FD_ZERO(&fds); 277 FD_ZERO(&fds);
281 FD_SET(sock, &fds); 278 FD_SET(sock, &fds);
282 ret = sock_select(sock+1, &fds, NULL, NULL, timeout); 279 ret = sock_select(sock+1, &fds, NULL, NULL, tm);
283 if (ret == 0) return IO_TIMEOUT; 280 if (ret == 0) return IO_TIMEOUT;
284 else if (ret > 0 || errno == EINTR) return IO_RETRY; 281 if (ret < 0) return IO_USER;
285 else return IO_ERROR; 282 }
286 } else {
287 *got = taken;
288 return IO_DONE;
289 }
290} 283}
291 284
292/*-------------------------------------------------------------------------*\ 285/*-------------------------------------------------------------------------*\
293* Recvfrom with timeout 286* Recvfrom with timeout
294\*-------------------------------------------------------------------------*/ 287\*-------------------------------------------------------------------------*/
295int sock_recvfrom(p_sock ps, char *data, size_t count, size_t *got, 288int sock_recvfrom(p_sock ps, char *data, size_t count, size_t *got,
296 SA *addr, socklen_t *addr_len, int timeout) 289 SA *addr, socklen_t *addr_len, p_tm tm) {
297{
298 t_sock sock = *ps; 290 t_sock sock = *ps;
299 ssize_t taken;
300 if (sock == SOCK_INVALID) return IO_CLOSED; 291 if (sock == SOCK_INVALID) return IO_CLOSED;
301 do taken = recvfrom(sock, data, count, 0, addr, addr_len); 292 for ( ;; ) {
302 while (taken < 0 && errno == EINTR);
303 if (taken <= 0) {
304 fd_set fds; 293 fd_set fds;
305 int ret; 294 int ret;
295 ssize_t taken;
296 do taken = recvfrom(sock, data, count, 0, addr, addr_len);
297 while (taken < 0 && errno == EINTR);
298 if (taken > 0) {
299 *got = taken;
300 return IO_DONE;
301 }
306 *got = 0; 302 *got = 0;
307 if (taken == 0) return IO_CLOSED; 303 if (taken == 0) return IO_CLOSED;
308 if (errno != EAGAIN) return IO_ERROR; 304 if (errno != EAGAIN) return IO_USER;
309 if (timeout == 0) return IO_TIMEOUT; 305 if (tm_get(tm) == 0.0) return IO_TIMEOUT;
310 FD_ZERO(&fds); 306 FD_ZERO(&fds);
311 FD_SET(sock, &fds); 307 FD_SET(sock, &fds);
312 ret = sock_select(sock+1, &fds, NULL, NULL, timeout); 308 ret = sock_select(sock+1, &fds, NULL, NULL, tm);
313 if (ret == 0) return IO_TIMEOUT; 309 if (ret == 0) return IO_TIMEOUT;
314 else if (ret > 0 || errno == EINTR) return IO_RETRY; 310 if (ret < 0) return IO_USER;
315 else return IO_ERROR; 311 }
316 } else {
317 *got = taken;
318 return IO_DONE;
319 }
320} 312}
321 313
322/*-------------------------------------------------------------------------*\ 314/*-------------------------------------------------------------------------*\
323* Put socket into blocking mode 315* Put socket into blocking mode
324\*-------------------------------------------------------------------------*/ 316\*-------------------------------------------------------------------------*/
325void sock_setblocking(p_sock ps) 317void sock_setblocking(p_sock ps) {
326{
327 int flags = fcntl(*ps, F_GETFL, 0); 318 int flags = fcntl(*ps, F_GETFL, 0);
328 flags &= (~(O_NONBLOCK)); 319 flags &= (~(O_NONBLOCK));
329 fcntl(*ps, F_SETFL, flags); 320 fcntl(*ps, F_SETFL, flags);
@@ -332,8 +323,7 @@ void sock_setblocking(p_sock ps)
332/*-------------------------------------------------------------------------*\ 323/*-------------------------------------------------------------------------*\
333* Put socket into non-blocking mode 324* Put socket into non-blocking mode
334\*-------------------------------------------------------------------------*/ 325\*-------------------------------------------------------------------------*/
335void sock_setnonblocking(p_sock ps) 326void sock_setnonblocking(p_sock ps) {
336{
337 int flags = fcntl(*ps, F_GETFL, 0); 327 int flags = fcntl(*ps, F_GETFL, 0);
338 flags |= O_NONBLOCK; 328 flags |= O_NONBLOCK;
339 fcntl(*ps, F_SETFL, flags); 329 fcntl(*ps, F_SETFL, flags);
@@ -342,98 +332,20 @@ void sock_setnonblocking(p_sock ps)
342/*-------------------------------------------------------------------------*\ 332/*-------------------------------------------------------------------------*\
343* Error translation functions 333* Error translation functions
344\*-------------------------------------------------------------------------*/ 334\*-------------------------------------------------------------------------*/
345/* return error messages for the known errors reported by gethostbyname */ 335const char *sock_hoststrerror(void) {
346const char *sock_hoststrerror(void) 336 return hstrerror(h_errno);
347{
348 switch (h_errno) {
349 case HOST_NOT_FOUND: return "host not found";
350 case NO_ADDRESS: return "valid host but no ip found";
351 case NO_RECOVERY: return "name server error";
352 case TRY_AGAIN: return "name server unavailable, try again later";
353 default: return "unknown error";
354 }
355}
356
357/* return error messages for the known errors reported by socket */
358static const char *sock_createstrerror(int err)
359{
360 switch (err) {
361 case EPROTONOSUPPORT: return "protocol not supported";
362 case EACCES: return "access denied";
363 case EMFILE: return "process file table is full";
364 case ENFILE: return "kernel file table is full";
365 case EINVAL: return "unknown protocol or family";
366 case ENOBUFS: return "insuffucient buffer space";
367 default: return "unknown error";
368 }
369} 337}
370 338
371/* return error messages for the known errors reported by accept */ 339/* make sure important error messages are standard */
372static const char *sock_acceptstrerror(int err) 340const char *sock_strerror(void) {
373{ 341 switch (errno) {
374 switch (err) { 342 case EADDRINUSE:
375 case EAGAIN: return io_strerror(IO_RETRY); 343 return "address already in use";
376 case EBADF: return "invalid descriptor"; 344 default:
377 case ENOBUFS: case ENOMEM: return "insuffucient buffer space"; 345 return strerror(errno);
378 case ENOTSOCK: return "descriptor not a socket";
379 case EOPNOTSUPP: return "not supported";
380 case EINTR: return "call interrupted";
381 case ECONNABORTED: return "connection aborted";
382 case EINVAL: return "not listening";
383 case EMFILE: return "process file table is full";
384 case ENFILE: return "kernel file table is full";
385 case EFAULT: return "invalid memory address";
386 default: return "unknown error";
387 }
388}
389
390
391/* return error messages for the known errors reported by bind */
392static const char *sock_bindstrerror(int err)
393{
394 switch (err) {
395 case EBADF: return "invalid descriptor";
396 case ENOTSOCK: return "descriptor not a socket";
397 case EADDRNOTAVAIL: return "address unavailable in local host";
398 case EADDRINUSE: return "address already in use";
399 case EINVAL: return "already bound";
400 case EACCES: return "access denied";
401 case EFAULT: return "invalid memory address";
402 case ENOMEM: return "out of memory";
403 default: return "unknown error";
404 } 346 }
405} 347}
406 348
407/* return error messages for the known errors reported by listen */ 349const char *sock_geterr(p_sock ps, int code) {
408static const char *sock_listenstrerror(int err) 350 return sock_strerror();
409{
410 switch (err) {
411 case EADDRINUSE: return "local address already in use";
412 case EBADF: return "invalid descriptor";
413 case ENOTSOCK: return "descriptor not a socket";
414 case EOPNOTSUPP: return "not supported";
415 default: return "unknown error";
416 }
417}
418
419/* return error messages for the known errors reported by connect */
420static const char *sock_connectstrerror(int err)
421{
422 switch (err) {
423 case EBADF: return "invalid descriptor";
424 case EFAULT: return "invalid memory address";
425 case ENOTSOCK: return "descriptor not a socket";
426 case EADDRNOTAVAIL: return "address not available in local host";
427 case EISCONN: return "already connected";
428 case ECONNREFUSED: return "connection refused";
429 case ETIMEDOUT: return io_strerror(IO_TIMEOUT);
430 case ENETUNREACH: return "network is unreachable";
431 case EADDRINUSE: return "local address already in use";
432 case EINPROGRESS: return "would block";
433 case EALREADY: return "connect already in progress";
434 case EAGAIN: return "not enough free ports";
435 case EAFNOSUPPORT: return "address family not supported";
436 case EPERM: return "broadcast not enabled or firewall block";
437 default: return "unknown error";
438 }
439} 351}
diff --git a/src/usocket.h b/src/usocket.h
index b9255cb..d3d4f48 100644
--- a/src/usocket.h
+++ b/src/usocket.h
@@ -16,14 +16,12 @@
16#include <unistd.h> 16#include <unistd.h>
17/* fnctnl function and associated constants */ 17/* fnctnl function and associated constants */
18#include <fcntl.h> 18#include <fcntl.h>
19/* struct timeval and CLK_TCK */
20#include <sys/time.h>
21/* times function and struct tms */
22#include <sys/times.h>
23/* struct sockaddr */ 19/* struct sockaddr */
24#include <sys/types.h> 20#include <sys/types.h>
25/* socket function */ 21/* socket function */
26#include <sys/socket.h> 22#include <sys/socket.h>
23/* struct timeval */
24#include <sys/time.h>
27/* gethostbyname and gethostbyaddr functions */ 25/* gethostbyname and gethostbyaddr functions */
28#include <netdb.h> 26#include <netdb.h>
29/* sigpipe handling */ 27/* sigpipe handling */
diff --git a/test/testclnt.lua b/test/testclnt.lua
index 9aa07fe..58a3574 100644
--- a/test/testclnt.lua
+++ b/test/testclnt.lua
@@ -228,6 +228,7 @@ function test_totaltimeoutsend(len, tm, sl)
228 data:settimeout(tm, "total") 228 data:settimeout(tm, "total")
229 str = string.rep("a", 2*len) 229 str = string.rep("a", 2*len)
230 total, err, partial, elapsed = data:send(str) 230 total, err, partial, elapsed = data:send(str)
231print(elapsed, "!")
231 check_timeout(tm, sl, elapsed, err, "send", "total", 232 check_timeout(tm, sl, elapsed, err, "send", "total",
232 total == 2*len) 233 total == 2*len)
233end 234end
@@ -400,27 +401,27 @@ function accept_errors()
400 d:setfd(c:getfd()) 401 d:setfd(c:getfd())
401 d:settimeout(2) 402 d:settimeout(2)
402 local r, e = d:accept() 403 local r, e = d:accept()
403 assert(not r and e == "not listening", e) 404 assert(not r and e)
404 print("ok") 405 print("ok: ", e)
405 io.stderr:write("not supported: ") 406 io.stderr:write("not supported: ")
406 local c, e = socket.udp() 407 local c, e = socket.udp()
407 assert(c, e); 408 assert(c, e);
408 d:setfd(c:getfd()) 409 d:setfd(c:getfd())
409 local r, e = d:accept() 410 local r, e = d:accept()
410 assert(not r and e == "not supported" or e == "not listening", e) 411 assert(not r and e)
411 print("ok") 412 print("ok: ", e)
412end 413end
413 414
414------------------------------------------------------------------------ 415------------------------------------------------------------------------
415function connect_errors() 416function connect_errors()
416 io.stderr:write("connection refused: ") 417 io.stderr:write("connection refused: ")
417 local c, e = socket.connect("localhost", 1); 418 local c, e = socket.connect("localhost", 1);
418 assert(not c and e == "connection refused", e) 419 assert(not c and e)
419 print("ok") 420 print("ok: ", e)
420 io.stderr:write("host not found: ") 421 io.stderr:write("host not found: ")
421 local c, e = socket.connect("host.is.invalid", 1); 422 local c, e = socket.connect("host.is.invalid", 1);
422 assert(not c and e == "host not found", e) 423 assert(not c and e, e)
423 print("ok") 424 print("ok: ", e)
424end 425end
425 426
426------------------------------------------------------------------------ 427------------------------------------------------------------------------
@@ -432,36 +433,25 @@ function rebind_test()
432 s:setoption("reuseaddr", false) 433 s:setoption("reuseaddr", false)
433 r, e = s:bind("localhost", p) 434 r, e = s:bind("localhost", p)
434 assert(not r, "managed to rebind!") 435 assert(not r, "managed to rebind!")
435 assert(e == "address already in use") 436 assert(e)
436 print("ok") 437 print("ok: ", e)
437end 438end
438 439
439------------------------------------------------------------------------ 440------------------------------------------------------------------------
440
441test("character line")
442test_asciiline(1)
443test_asciiline(17)
444test_asciiline(200)
445test_asciiline(4091)
446test_asciiline(80199)
447test_asciiline(8000000)
448test_asciiline(80199)
449test_asciiline(4091)
450test_asciiline(200)
451test_asciiline(17)
452test_asciiline(1)
453
454test("method registration") 441test("method registration")
455test_methods(socket.tcp(), { 442test_methods(socket.tcp(), {
456 "accept", 443 "accept",
457 "bind", 444 "bind",
458 "close", 445 "close",
459 "connect", 446 "connect",
447 "dirty",
448 "getfd",
460 "getpeername", 449 "getpeername",
461 "getsockname", 450 "getsockname",
462 "listen", 451 "listen",
463 "receive", 452 "receive",
464 "send", 453 "send",
454 "setfd",
465 "setoption", 455 "setoption",
466 "setpeername", 456 "setpeername",
467 "setsockname", 457 "setsockname",
@@ -472,15 +462,19 @@ test_methods(socket.tcp(), {
472test_methods(socket.udp(), { 462test_methods(socket.udp(), {
473 "close", 463 "close",
474 "getpeername", 464 "getpeername",
465 "dirty",
466 "getfd",
467 "getpeername",
475 "getsockname", 468 "getsockname",
476 "receive", 469 "receive",
477 "receivefrom", 470 "receivefrom",
478 "send", 471 "send",
479 "sendto", 472 "sendto",
473 "setfd",
480 "setoption", 474 "setoption",
481 "setpeername", 475 "setpeername",
482 "setsockname", 476 "setsockname",
483 "settimeout", 477 "settimeout"
484}) 478})
485 479
486test("select function") 480test("select function")
@@ -504,7 +498,18 @@ test("accept function: ")
504accept_timeout() 498accept_timeout()
505accept_errors() 499accept_errors()
506 500
507 501test("character line")
502test_asciiline(1)
503test_asciiline(17)
504test_asciiline(200)
505test_asciiline(4091)
506test_asciiline(80199)
507test_asciiline(8000000)
508test_asciiline(80199)
509test_asciiline(4091)
510test_asciiline(200)
511test_asciiline(17)
512test_asciiline(1)
508 513
509test("mixed patterns") 514test("mixed patterns")
510test_mixed(1) 515test_mixed(1)
@@ -566,9 +571,10 @@ test_raw(1)
566test("total timeout on send") 571test("total timeout on send")
567test_totaltimeoutsend(800091, 1, 3) 572test_totaltimeoutsend(800091, 1, 3)
568test_totaltimeoutsend(800091, 2, 3) 573test_totaltimeoutsend(800091, 2, 3)
569test_totaltimeoutsend(800091, 3, 2) 574test_totaltimeoutsend(800091, 5, 2)
570test_totaltimeoutsend(800091, 3, 1) 575test_totaltimeoutsend(800091, 3, 1)
571 576
577
572test("total timeout on receive") 578test("total timeout on receive")
573test_totaltimeoutreceive(800091, 1, 3) 579test_totaltimeoutreceive(800091, 1, 3)
574test_totaltimeoutreceive(800091, 2, 3) 580test_totaltimeoutreceive(800091, 2, 3)