diff options
author | Diego Nehab <diego@tecgraf.puc-rio.br> | 2004-07-01 03:32:09 +0000 |
---|---|---|
committer | Diego Nehab <diego@tecgraf.puc-rio.br> | 2004-07-01 03:32:09 +0000 |
commit | 7115c12fbc9aae1cd46fdf049697a27fb996181a (patch) | |
tree | 2e918f54f729766701aabdef488a6461bc623da1 | |
parent | 7aaba59909e8527190694285f56ca68772c97f6a (diff) | |
download | luasocket-7115c12fbc9aae1cd46fdf049697a27fb996181a.tar.gz luasocket-7115c12fbc9aae1cd46fdf049697a27fb996181a.tar.bz2 luasocket-7115c12fbc9aae1cd46fdf049697a27fb996181a.zip |
Moving on to beta2.
-rw-r--r-- | FIX | 7 | ||||
-rw-r--r-- | TODO | 8 | ||||
-rw-r--r-- | etc/tftp.lua | 25 | ||||
-rw-r--r-- | samples/lpr.lua | 51 | ||||
-rw-r--r-- | src/buffer.c | 68 | ||||
-rw-r--r-- | src/io.c | 20 | ||||
-rw-r--r-- | src/io.h | 22 | ||||
-rw-r--r-- | src/select.c | 11 | ||||
-rw-r--r-- | src/socket.h | 14 | ||||
-rw-r--r-- | src/tcp.c | 6 | ||||
-rw-r--r-- | src/timeout.c | 73 | ||||
-rw-r--r-- | src/timeout.h | 16 | ||||
-rw-r--r-- | src/udp.c | 105 | ||||
-rw-r--r-- | src/usocket.c | 334 | ||||
-rw-r--r-- | src/usocket.h | 6 | ||||
-rw-r--r-- | test/testclnt.lua | 62 |
16 files changed, 388 insertions, 440 deletions
@@ -1,8 +1,9 @@ | |||
1 | setup error messages in the default case. | ||
1 | listen defaults to 32 backlog | 2 | listen defaults to 32 backlog |
2 | smtp sends quit on exceptions | 3 | smtp/ftp/http fail gracefully |
3 | accept/connect interrupt safe | 4 | accept/connect/select interrupt safe |
4 | accepted sockets are nonblocking | 5 | accepted sockets are nonblocking |
5 | new timming functions. better sleep/gettime | 6 | new timming functions. higher resolution, no wrap around |
6 | bug fixes in the manual | 7 | bug fixes in the manual |
7 | getfd missing cast | 8 | getfd missing cast |
8 | added unix domain support example | 9 | added unix domain support example |
@@ -1,8 +1,8 @@ | |||
1 | setup error messages in the default case. | 1 | create the getstats method. |
2 | 2 | ||
3 | ajeitar 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) ... | 5 | take a look at DB's smtp patch |
6 | 6 | ||
7 | sort out the wrap around of gettime... | 7 | sort 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 |
120 | end | 121 | end |
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 @@ | |||
1 | local lp = require("lp") | ||
2 | |||
3 | local 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 | ||
23 | end | ||
24 | |||
25 | if not arg or not arg[1] then | ||
26 | return usage() | ||
27 | end | ||
28 | |||
29 | do | ||
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 | ||
46 | end | ||
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 | \*-------------------------------------------------------------------------*/ |
36 | int buf_open(lua_State *L) | 36 | int 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 | \*-------------------------------------------------------------------------*/ |
45 | void buf_init(p_buf buf, p_io io, p_tm tm) | 44 | void 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 | \*-------------------------------------------------------------------------*/ |
55 | int buf_meth_send(lua_State *L, p_buf buf) | 53 | int 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 | \*-------------------------------------------------------------------------*/ |
89 | int buf_meth_receive(lua_State *L, p_buf buf) | 85 | int 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 | \*-------------------------------------------------------------------------*/ |
129 | int buf_isempty(p_buf buf) | 123 | int 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 | \*-------------------------------------------------------------------------*/ |
140 | static | 133 | static int sendraw(p_buf buf, const char *data, size_t count, size_t *sent) { |
141 | int 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 | \*-------------------------------------------------------------------------*/ |
159 | static | 150 | static int recvraw(p_buf buf, size_t wanted, luaL_Buffer *b) { |
160 | int 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 | \*-------------------------------------------------------------------------*/ |
178 | static | 167 | static int recvall(p_buf buf, luaL_Buffer *b) { |
179 | int 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 | \*-------------------------------------------------------------------------*/ |
196 | static | 183 | static int recvline(p_buf buf, luaL_Buffer *b) { |
197 | int 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 | \*-------------------------------------------------------------------------*/ |
222 | static | 207 | static void buf_skip(p_buf buf, size_t count) { |
223 | void 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 | \*-------------------------------------------------------------------------*/ |
234 | static | 217 | static int buf_get(p_buf buf, const char **data, size_t *count) { |
235 | int 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 | |||
@@ -12,34 +12,34 @@ | |||
12 | /*-------------------------------------------------------------------------*\ | 12 | /*-------------------------------------------------------------------------*\ |
13 | * Initializes C structure | 13 | * Initializes C structure |
14 | \*-------------------------------------------------------------------------*/ | 14 | \*-------------------------------------------------------------------------*/ |
15 | void io_init(p_io io, p_send send, p_recv recv, void *ctx) | 15 | void 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 | \*-------------------------------------------------------------------------*/ |
25 | const char *io_strerror(int code) | 25 | const 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 | \*-------------------------------------------------------------------------*/ |
40 | void io_pusherror(lua_State *L, int code) | 38 | void 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 | } |
@@ -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 */ |
21 | enum { | 23 | enum { |
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 */ | ||
41 | typedef 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; |
54 | typedef t_io *p_io; | 62 | typedef t_io *p_io; |
55 | 63 | ||
56 | const char *io_strerror(int code); | 64 | const char *io_strerror(int code); |
57 | void io_pusherror(lua_State *L, int code); | 65 | void io_pusherror(lua_State *L, p_io io, int code); |
58 | void io_init(p_io io, p_send send, p_recv recv, void *ctx); | 66 | void 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 | \*-------------------------------------------------------------------------*/ |
50 | static int global_select(lua_State *L) { | 51 | static 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); | |||
41 | int sock_close(void); | 41 | int sock_close(void); |
42 | void sock_destroy(p_sock ps); | 42 | void sock_destroy(p_sock ps); |
43 | void sock_shutdown(p_sock ps, int how); | 43 | void sock_shutdown(p_sock ps, int how); |
44 | int sock_send(p_sock ps, const char *data, size_t count, | 44 | int sock_send(p_sock ps, const char *data, size_t count, size_t *sent, p_tm tm); |
45 | size_t *sent, int timeout); | 45 | int sock_recv(p_sock ps, char *data, size_t count, size_t *got, p_tm tm); |
46 | int sock_recv(p_sock ps, char *data, size_t count, | ||
47 | size_t *got, int timeout); | ||
48 | int sock_sendto(p_sock ps, const char *data, size_t count, | 46 | int 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); |
50 | int sock_recvfrom(p_sock ps, char *data, size_t count, | 48 | int 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); |
52 | void sock_setnonblocking(p_sock ps); | 50 | void sock_setnonblocking(p_sock ps); |
53 | void sock_setblocking(p_sock ps); | 51 | void sock_setblocking(p_sock ps); |
54 | int sock_select(int n, fd_set *rfds, fd_set *wfds, fd_set *efds, int timeout); | 52 | int sock_select(int n, fd_set *rfds, fd_set *wfds, fd_set *efds, p_tm tm); |
55 | 53 | ||
56 | const char *sock_connect(p_sock ps, SA *addr, socklen_t addr_len, p_tm tm); | 54 | const char *sock_connect(p_sock ps, SA *addr, socklen_t addr_len, p_tm tm); |
57 | const char *sock_create(p_sock ps, int domain, int type, int protocol); | 55 | const 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); | |||
60 | const char *sock_accept(p_sock ps, p_sock pa, SA *addr, | 58 | const 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 | ||
61 | const char *sock_geterr(p_sock ps, int code); | ||
63 | const char *sock_hoststrerror(void); | 62 | const char *sock_hoststrerror(void); |
63 | const char *sock_strerror(void); | ||
64 | 64 | ||
65 | #endif /* SOCK_H */ | 65 | #endif /* SOCK_H */ |
@@ -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 | \*-------------------------------------------------------------------------*/ |
49 | void tm_init(p_tm tm, int block, int total) | 49 | void 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 | \*-------------------------------------------------------------------------*/ |
63 | int tm_get(p_tm tm) | 62 | double 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 | \*-------------------------------------------------------------------------*/ |
85 | int tm_getstart(p_tm tm) | 83 | double 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 | \*-------------------------------------------------------------------------*/ |
98 | int tm_getretry(p_tm tm) | 95 | double 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 | \*-------------------------------------------------------------------------*/ |
119 | p_tm tm_markstart(p_tm tm) | 115 | p_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 |
131 | int tm_gettime(void) | 126 | double 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 |
136 | int tm_gettime(void) | 132 | double 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 | \*-------------------------------------------------------------------------*/ |
147 | int tm_open(lua_State *L) | 142 | int 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 | \*-------------------------------------------------------------------------*/ |
159 | int tm_meth_settimeout(lua_State *L, p_tm tm) | 153 | int 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 | \*-------------------------------------------------------------------------*/ |
184 | static int tm_lua_gettime(lua_State *L) | 177 | static 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 */ |
12 | typedef struct t_tm_ { | 12 | typedef 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; |
17 | typedef t_tm *p_tm; | 17 | typedef t_tm *p_tm; |
18 | 18 | ||
19 | int tm_open(lua_State *L); | 19 | int tm_open(lua_State *L); |
20 | void tm_init(p_tm tm, int block, int total); | 20 | void tm_init(p_tm tm, double block, double total); |
21 | int tm_get(p_tm tm); | 21 | double tm_get(p_tm tm); |
22 | int tm_getretry(p_tm tm); | 22 | double tm_getretry(p_tm tm); |
23 | p_tm tm_markstart(p_tm tm); | 23 | p_tm tm_markstart(p_tm tm); |
24 | int tm_getstart(p_tm tm); | 24 | double tm_getstart(p_tm tm); |
25 | int tm_gettime(void); | 25 | double tm_gettime(void); |
26 | int tm_meth_settimeout(lua_State *L, p_tm tm); | 26 | int tm_meth_settimeout(lua_State *L, p_tm tm); |
27 | 27 | ||
28 | #endif /* TM_H */ | 28 | #endif /* TM_H */ |
@@ -41,25 +41,26 @@ static int meth_settimeout(lua_State *L); | |||
41 | static int meth_getfd(lua_State *L); | 41 | static int meth_getfd(lua_State *L); |
42 | static int meth_setfd(lua_State *L); | 42 | static int meth_setfd(lua_State *L); |
43 | static int meth_dirty(lua_State *L); | 43 | static int meth_dirty(lua_State *L); |
44 | static void pusherror(lua_State *L, int code); | ||
44 | 45 | ||
45 | /* udp object methods */ | 46 | /* udp object methods */ |
46 | static luaL_reg udp[] = { | 47 | static 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 | \*-------------------------------------------------------------------------*/ | ||
110 | void 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 | \*-------------------------------------------------------------------------*/ |
108 | static int meth_send(lua_State *L) | 120 | static 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 | \*-------------------------------------------------------------------------*/ |
129 | static int meth_sendto(lua_State *L) | 139 | static 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 | \*-------------------------------------------------------------------------*/ |
159 | static int meth_receive(lua_State *L) | 167 | static 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 | \*-------------------------------------------------------------------------*/ |
179 | static int meth_receivefrom(lua_State *L) | 185 | static 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 | \*-------------------------------------------------------------------------*/ |
208 | static int meth_getfd(lua_State *L) | 212 | static 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 */ |
216 | static int meth_setfd(lua_State *L) | 219 | static 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 | ||
223 | static int meth_dirty(lua_State *L) | 225 | static 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 | \*-------------------------------------------------------------------------*/ |
234 | static int meth_getpeername(lua_State *L) | 235 | static 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 | ||
240 | static int meth_getsockname(lua_State *L) | 240 | static 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 | \*-------------------------------------------------------------------------*/ |
249 | static int meth_setoption(lua_State *L) | 248 | static 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 | \*-------------------------------------------------------------------------*/ |
258 | static int meth_settimeout(lua_State *L) | 256 | static 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 | \*-------------------------------------------------------------------------*/ |
267 | static int meth_setpeername(lua_State *L) | 264 | static 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 | \*-------------------------------------------------------------------------*/ |
292 | static int meth_close(lua_State *L) | 288 | static 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 | \*-------------------------------------------------------------------------*/ |
302 | static int meth_setsockname(lua_State *L) | 297 | static 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 | \*-------------------------------------------------------------------------*/ |
323 | static int global_create(lua_State *L) | 317 | static 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 | ||
23 | static const char *sock_createstrerror(int err); | ||
24 | static const char *sock_bindstrerror(int err); | ||
25 | static const char *sock_connectstrerror(int err); | ||
26 | static const char *sock_acceptstrerror(int err); | ||
27 | static const char *sock_listenstrerror(int err); | ||
28 | |||
29 | /*-------------------------------------------------------------------------*\ | 23 | /*-------------------------------------------------------------------------*\ |
30 | * Initializes module | 24 | * Initializes module |
31 | \*-------------------------------------------------------------------------*/ | 25 | \*-------------------------------------------------------------------------*/ |
32 | int sock_open(void) | 26 | int 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 | \*-------------------------------------------------------------------------*/ |
48 | int sock_close(void) | 41 | int 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 | \*-------------------------------------------------------------------------*/ |
56 | void sock_destroy(p_sock ps) | 48 | void 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 | \*-------------------------------------------------------------------------*/ |
68 | int sock_select(int n, fd_set *rfds, fd_set *wfds, fd_set *efds, int timeout) | 59 | int 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 | \*-------------------------------------------------------------------------*/ |
79 | const char *sock_create(p_sock ps, int domain, int type, int protocol) | 74 | const 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 | \*-------------------------------------------------------------------------*/ |
90 | const char *sock_connect(p_sock ps, SA *addr, socklen_t addr_len, p_tm tm) | 84 | const 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 | \*-------------------------------------------------------------------------*/ |
129 | const char *sock_bind(p_sock ps, SA *addr, socklen_t addr_len) | 123 | const 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 | \*-------------------------------------------------------------------------*/ |
141 | const char* sock_listen(p_sock ps, int backlog) | 134 | const 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 | \*-------------------------------------------------------------------------*/ |
154 | void sock_shutdown(p_sock ps, int how) | 145 | void 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 | \*-------------------------------------------------------------------------*/ |
164 | const char *sock_accept(p_sock ps, p_sock pa, SA *addr, | 154 | const 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 | \*-------------------------------------------------------------------------*/ |
197 | int sock_send(p_sock ps, const char *data, size_t count, size_t *sent, | 188 | int 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 | \*-------------------------------------------------------------------------*/ |
236 | int sock_sendto(p_sock ps, const char *data, size_t count, size_t *sent, | 228 | int 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 | \*-------------------------------------------------------------------------*/ |
266 | int sock_recv(p_sock ps, char *data, size_t count, size_t *got, int timeout) | 260 | int 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 | \*-------------------------------------------------------------------------*/ |
295 | int sock_recvfrom(p_sock ps, char *data, size_t count, size_t *got, | 288 | int 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 | \*-------------------------------------------------------------------------*/ |
325 | void sock_setblocking(p_sock ps) | 317 | void 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 | \*-------------------------------------------------------------------------*/ |
335 | void sock_setnonblocking(p_sock ps) | 326 | void 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 */ | 335 | const char *sock_hoststrerror(void) { |
346 | const 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 */ | ||
358 | static 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 */ |
372 | static const char *sock_acceptstrerror(int err) | 340 | const 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 */ | ||
392 | static 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 */ | 349 | const char *sock_geterr(p_sock ps, int code) { |
408 | static 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 */ | ||
420 | static 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) |
231 | print(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) |
233 | end | 234 | end |
@@ -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) |
412 | end | 413 | end |
413 | 414 | ||
414 | ------------------------------------------------------------------------ | 415 | ------------------------------------------------------------------------ |
415 | function connect_errors() | 416 | function 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) |
424 | end | 425 | end |
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) |
437 | end | 438 | end |
438 | 439 | ||
439 | ------------------------------------------------------------------------ | 440 | ------------------------------------------------------------------------ |
440 | |||
441 | test("character line") | ||
442 | test_asciiline(1) | ||
443 | test_asciiline(17) | ||
444 | test_asciiline(200) | ||
445 | test_asciiline(4091) | ||
446 | test_asciiline(80199) | ||
447 | test_asciiline(8000000) | ||
448 | test_asciiline(80199) | ||
449 | test_asciiline(4091) | ||
450 | test_asciiline(200) | ||
451 | test_asciiline(17) | ||
452 | test_asciiline(1) | ||
453 | |||
454 | test("method registration") | 441 | test("method registration") |
455 | test_methods(socket.tcp(), { | 442 | test_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(), { | |||
472 | test_methods(socket.udp(), { | 462 | test_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 | ||
486 | test("select function") | 480 | test("select function") |
@@ -504,7 +498,18 @@ test("accept function: ") | |||
504 | accept_timeout() | 498 | accept_timeout() |
505 | accept_errors() | 499 | accept_errors() |
506 | 500 | ||
507 | 501 | test("character line") | |
502 | test_asciiline(1) | ||
503 | test_asciiline(17) | ||
504 | test_asciiline(200) | ||
505 | test_asciiline(4091) | ||
506 | test_asciiline(80199) | ||
507 | test_asciiline(8000000) | ||
508 | test_asciiline(80199) | ||
509 | test_asciiline(4091) | ||
510 | test_asciiline(200) | ||
511 | test_asciiline(17) | ||
512 | test_asciiline(1) | ||
508 | 513 | ||
509 | test("mixed patterns") | 514 | test("mixed patterns") |
510 | test_mixed(1) | 515 | test_mixed(1) |
@@ -566,9 +571,10 @@ test_raw(1) | |||
566 | test("total timeout on send") | 571 | test("total timeout on send") |
567 | test_totaltimeoutsend(800091, 1, 3) | 572 | test_totaltimeoutsend(800091, 1, 3) |
568 | test_totaltimeoutsend(800091, 2, 3) | 573 | test_totaltimeoutsend(800091, 2, 3) |
569 | test_totaltimeoutsend(800091, 3, 2) | 574 | test_totaltimeoutsend(800091, 5, 2) |
570 | test_totaltimeoutsend(800091, 3, 1) | 575 | test_totaltimeoutsend(800091, 3, 1) |
571 | 576 | ||
577 | |||
572 | test("total timeout on receive") | 578 | test("total timeout on receive") |
573 | test_totaltimeoutreceive(800091, 1, 3) | 579 | test_totaltimeoutreceive(800091, 1, 3) |
574 | test_totaltimeoutreceive(800091, 2, 3) | 580 | test_totaltimeoutreceive(800091, 2, 3) |