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) |
