mirror of
https://github.com/lunarmodules/luasocket.git
synced 2024-12-26 12:28:21 +01:00
Moving on to beta2.
This commit is contained in:
parent
7aaba59909
commit
7115c12fbc
7
FIX
7
FIX
@ -1,8 +1,9 @@
|
|||||||
|
setup error messages in the default case.
|
||||||
listen defaults to 32 backlog
|
listen defaults to 32 backlog
|
||||||
smtp sends quit on exceptions
|
smtp/ftp/http fail gracefully
|
||||||
accept/connect interrupt safe
|
accept/connect/select interrupt safe
|
||||||
accepted sockets are nonblocking
|
accepted sockets are nonblocking
|
||||||
new timming functions. better sleep/gettime
|
new timming functions. higher resolution, no wrap around
|
||||||
bug fixes in the manual
|
bug fixes in the manual
|
||||||
getfd missing cast
|
getfd missing cast
|
||||||
added unix domain support example
|
added unix domain support example
|
||||||
|
8
TODO
8
TODO
@ -1,8 +1,8 @@
|
|||||||
setup error messages in the default case.
|
create the getstats method.
|
||||||
|
|
||||||
ajeitar o connect com a dica do mike
|
sent, received, age = sock:getstats()
|
||||||
if ((err > 1 || !FD_ISSET(sock, &wfds)) &&
|
|
||||||
recv(sock, &dummy, 0, 0) < 0 && errno != EWOULDBLOCK) ...
|
take a look at DB's smtp patch
|
||||||
|
|
||||||
sort out the wrap around of gettime...
|
sort out the wrap around of gettime...
|
||||||
use doubles all over
|
use doubles all over
|
||||||
|
25
etc/tftp.lua
25
etc/tftp.lua
@ -72,50 +72,51 @@ local function tget(gett)
|
|||||||
local retries, dgram, sent, datahost, dataport, code
|
local retries, dgram, sent, datahost, dataport, code
|
||||||
local last = 0
|
local last = 0
|
||||||
local con = socket.try(socket.udp())
|
local con = socket.try(socket.udp())
|
||||||
|
local try = socket.newtry(function() con:close() end)
|
||||||
-- convert from name to ip if needed
|
-- convert from name to ip if needed
|
||||||
gett.host = socket.try(socket.dns.toip(gett.host))
|
gett.host = try(socket.dns.toip(gett.host))
|
||||||
con:settimeout(1)
|
con:settimeout(1)
|
||||||
-- first packet gives data host/port to be used for data transfers
|
-- first packet gives data host/port to be used for data transfers
|
||||||
retries = 0
|
retries = 0
|
||||||
repeat
|
repeat
|
||||||
sent = socket.try(con:sendto(RRQ(gett.path, "octet"),
|
sent = try(con:sendto(RRQ(gett.path, "octet"),
|
||||||
gett.host, gett.port))
|
gett.host, gett.port))
|
||||||
dgram, datahost, dataport = con:receivefrom()
|
dgram, datahost, dataport = con:receivefrom()
|
||||||
retries = retries + 1
|
retries = retries + 1
|
||||||
until dgram or datahost ~= "timeout" or retries > 5
|
until dgram or datahost ~= "timeout" or retries > 5
|
||||||
socket.try(dgram, datahost)
|
try(dgram, datahost)
|
||||||
-- associate socket with data host/port
|
-- associate socket with data host/port
|
||||||
socket.try(con:setpeername(datahost, dataport))
|
try(con:setpeername(datahost, dataport))
|
||||||
-- default sink
|
-- default sink
|
||||||
local sink = gett.sink or ltn12.sink.null()
|
local sink = gett.sink or ltn12.sink.null()
|
||||||
-- process all data packets
|
-- process all data packets
|
||||||
while 1 do
|
while 1 do
|
||||||
-- decode packet
|
-- decode packet
|
||||||
code = get_OP(dgram)
|
code = get_OP(dgram)
|
||||||
socket.try(code ~= OP_ERROR, get_ERROR(dgram))
|
try(code ~= OP_ERROR, get_ERROR(dgram))
|
||||||
socket.try(code == OP_DATA, "unhandled opcode " .. code)
|
try(code == OP_DATA, "unhandled opcode " .. code)
|
||||||
-- get data packet parts
|
-- get data packet parts
|
||||||
local block, data = split_DATA(dgram)
|
local block, data = split_DATA(dgram)
|
||||||
-- if not repeated, write
|
-- if not repeated, write
|
||||||
if block == last+1 then
|
if block == last+1 then
|
||||||
socket.try(sink(data))
|
try(sink(data))
|
||||||
last = block
|
last = block
|
||||||
end
|
end
|
||||||
-- last packet brings less than 512 bytes of data
|
-- last packet brings less than 512 bytes of data
|
||||||
if string.len(data) < 512 then
|
if string.len(data) < 512 then
|
||||||
socket.try(con:send(ACK(block)))
|
try(con:send(ACK(block)))
|
||||||
socket.try(con:close())
|
try(con:close())
|
||||||
socket.try(sink(nil))
|
try(sink(nil))
|
||||||
return 1
|
return 1
|
||||||
end
|
end
|
||||||
-- get the next packet
|
-- get the next packet
|
||||||
retries = 0
|
retries = 0
|
||||||
repeat
|
repeat
|
||||||
sent = socket.try(con:send(ACK(last)))
|
sent = try(con:send(ACK(last)))
|
||||||
dgram, err = con:receive()
|
dgram, err = con:receive()
|
||||||
retries = retries + 1
|
retries = retries + 1
|
||||||
until dgram or err ~= "timeout" or retries > 5
|
until dgram or err ~= "timeout" or retries > 5
|
||||||
socket.try(dgram, err)
|
try(dgram, err)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
51
samples/lpr.lua
Normal file
51
samples/lpr.lua
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
local lp = require("lp")
|
||||||
|
|
||||||
|
local function usage()
|
||||||
|
print('\nUsage: lp filename [keyword=val...]\n')
|
||||||
|
print('Valid keywords are :')
|
||||||
|
print(
|
||||||
|
' host=remote host or IP address (default "localhost")\n' ..
|
||||||
|
' queue=remote queue or printer name (default "printer")\n' ..
|
||||||
|
' port=remote port number (default 515)\n' ..
|
||||||
|
' user=sending user name\n' ..
|
||||||
|
' format=["binary" | "text" | "ps" | "pr" | "fortran"] (default "binary")\n' ..
|
||||||
|
' banner=true|false\n' ..
|
||||||
|
' indent=number of columns to indent\n' ..
|
||||||
|
' mail=email of address to notify when print is complete\n' ..
|
||||||
|
' title=title to use for "pr" format\n' ..
|
||||||
|
' width=width for "text" or "pr" formats\n' ..
|
||||||
|
' class=\n' ..
|
||||||
|
' job=\n' ..
|
||||||
|
' name=\n' ..
|
||||||
|
' localbind=true|false\n'
|
||||||
|
)
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
if not arg or not arg[1] then
|
||||||
|
return usage()
|
||||||
|
end
|
||||||
|
|
||||||
|
do
|
||||||
|
local s="opt = {"
|
||||||
|
for i = 2 , table.getn(arg), 1 do
|
||||||
|
s = s .. string.gsub(arg[i],"[%s%c%p]*([%w]*)=([\"]?[%w%s_!@#$%%^&*()<>:;]+[\"]\?\.?)","%1%=\"%2\",\n")
|
||||||
|
end
|
||||||
|
s = s .. "};\n"
|
||||||
|
assert(loadstring(s))();
|
||||||
|
if not arg[2] then
|
||||||
|
return usage()
|
||||||
|
end
|
||||||
|
if arg[1] ~= "query" then
|
||||||
|
r,e=lp.send(arg[1],opt)
|
||||||
|
io.stderr:write(tostring(r or e),'\n')
|
||||||
|
else
|
||||||
|
r,e=lp.query(opt)
|
||||||
|
io.stderr:write(tostring(r or e), '\n')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- trivial tests
|
||||||
|
--lua lp.lua lp.lua queue=default host=localhost
|
||||||
|
--lua lp.lua lp.lua queue=default host=localhost format=binary localbind=1
|
||||||
|
--lua lp.lua query queue=default host=localhost
|
66
src/buffer.c
66
src/buffer.c
@ -33,8 +33,7 @@ static int sendraw(p_buf buf, const char *data, size_t count, size_t *sent);
|
|||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Initializes module
|
* Initializes module
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
int buf_open(lua_State *L)
|
int buf_open(lua_State *L) {
|
||||||
{
|
|
||||||
(void) L;
|
(void) L;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -42,8 +41,7 @@ int buf_open(lua_State *L)
|
|||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Initializes C structure
|
* Initializes C structure
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
void buf_init(p_buf buf, p_io io, p_tm tm)
|
void buf_init(p_buf buf, p_io io, p_tm tm) {
|
||||||
{
|
|
||||||
buf->first = buf->last = 0;
|
buf->first = buf->last = 0;
|
||||||
buf->io = io;
|
buf->io = io;
|
||||||
buf->tm = tm;
|
buf->tm = tm;
|
||||||
@ -52,13 +50,11 @@ void buf_init(p_buf buf, p_io io, p_tm tm)
|
|||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* object:send() interface
|
* object:send() interface
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
int buf_meth_send(lua_State *L, p_buf buf)
|
int buf_meth_send(lua_State *L, p_buf buf) {
|
||||||
{
|
|
||||||
int top = lua_gettop(L);
|
int top = lua_gettop(L);
|
||||||
size_t total = 0;
|
size_t total = 0;
|
||||||
int arg, err = IO_DONE;
|
int arg, err = IO_DONE;
|
||||||
p_tm tm = buf->tm;
|
p_tm tm = tm_markstart(buf->tm);
|
||||||
tm_markstart(tm);
|
|
||||||
for (arg = 2; arg <= top; arg++) { /* first arg is socket object */
|
for (arg = 2; arg <= top; arg++) { /* first arg is socket object */
|
||||||
size_t sent, count;
|
size_t sent, count;
|
||||||
const char *data = luaL_optlstring(L, arg, NULL, &count);
|
const char *data = luaL_optlstring(L, arg, NULL, &count);
|
||||||
@ -69,7 +65,7 @@ int buf_meth_send(lua_State *L, p_buf buf)
|
|||||||
/* check if there was an error */
|
/* check if there was an error */
|
||||||
if (err != IO_DONE) {
|
if (err != IO_DONE) {
|
||||||
lua_pushnil(L);
|
lua_pushnil(L);
|
||||||
io_pusherror(L, err);
|
io_pusherror(L, buf->io, err);
|
||||||
lua_pushnumber(L, total);
|
lua_pushnumber(L, total);
|
||||||
} else {
|
} else {
|
||||||
lua_pushnumber(L, total);
|
lua_pushnumber(L, total);
|
||||||
@ -78,7 +74,7 @@ int buf_meth_send(lua_State *L, p_buf buf)
|
|||||||
}
|
}
|
||||||
#ifdef LUASOCKET_DEBUG
|
#ifdef LUASOCKET_DEBUG
|
||||||
/* push time elapsed during operation as the last return value */
|
/* push time elapsed during operation as the last return value */
|
||||||
lua_pushnumber(L, (tm_gettime() - tm_getstart(tm))/1000.0);
|
lua_pushnumber(L, tm_gettime() - tm_getstart(tm));
|
||||||
#endif
|
#endif
|
||||||
return lua_gettop(L) - top;
|
return lua_gettop(L) - top;
|
||||||
}
|
}
|
||||||
@ -86,13 +82,11 @@ int buf_meth_send(lua_State *L, p_buf buf)
|
|||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* object:receive() interface
|
* object:receive() interface
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
int buf_meth_receive(lua_State *L, p_buf buf)
|
int buf_meth_receive(lua_State *L, p_buf buf) {
|
||||||
{
|
|
||||||
int err = IO_DONE, top = lua_gettop(L);
|
int err = IO_DONE, top = lua_gettop(L);
|
||||||
p_tm tm = buf->tm;
|
p_tm tm = tm_markstart(buf->tm);
|
||||||
luaL_Buffer b;
|
luaL_Buffer b;
|
||||||
luaL_buffinit(L, &b);
|
luaL_buffinit(L, &b);
|
||||||
tm_markstart(tm);
|
|
||||||
/* receive all patterns */
|
/* receive all patterns */
|
||||||
if (!lua_isnumber(L, 2)) {
|
if (!lua_isnumber(L, 2)) {
|
||||||
static const char *patternnames[] = {"*l", "*a", NULL};
|
static const char *patternnames[] = {"*l", "*a", NULL};
|
||||||
@ -107,7 +101,7 @@ int buf_meth_receive(lua_State *L, p_buf buf)
|
|||||||
/* check if there was an error */
|
/* check if there was an error */
|
||||||
if (err != IO_DONE) {
|
if (err != IO_DONE) {
|
||||||
luaL_pushresult(&b);
|
luaL_pushresult(&b);
|
||||||
io_pusherror(L, err);
|
io_pusherror(L, buf->io, err);
|
||||||
lua_pushvalue(L, -2);
|
lua_pushvalue(L, -2);
|
||||||
lua_pushnil(L);
|
lua_pushnil(L);
|
||||||
lua_replace(L, -4);
|
lua_replace(L, -4);
|
||||||
@ -118,7 +112,7 @@ int buf_meth_receive(lua_State *L, p_buf buf)
|
|||||||
}
|
}
|
||||||
#ifdef LUASOCKET_DEBUG
|
#ifdef LUASOCKET_DEBUG
|
||||||
/* push time elapsed during operation as the last return value */
|
/* push time elapsed during operation as the last return value */
|
||||||
lua_pushnumber(L, (tm_gettime() - tm_getstart(tm))/1000.0);
|
lua_pushnumber(L, tm_gettime() - tm_getstart(tm));
|
||||||
#endif
|
#endif
|
||||||
return lua_gettop(L) - top;
|
return lua_gettop(L) - top;
|
||||||
}
|
}
|
||||||
@ -126,8 +120,7 @@ int buf_meth_receive(lua_State *L, p_buf buf)
|
|||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Determines if there is any data in the read buffer
|
* Determines if there is any data in the read buffer
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
int buf_isempty(p_buf buf)
|
int buf_isempty(p_buf buf) {
|
||||||
{
|
|
||||||
return buf->first >= buf->last;
|
return buf->first >= buf->last;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -137,16 +130,14 @@ int buf_isempty(p_buf buf)
|
|||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Sends a block of data (unbuffered)
|
* Sends a block of data (unbuffered)
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
static
|
static int sendraw(p_buf buf, const char *data, size_t count, size_t *sent) {
|
||||||
int sendraw(p_buf buf, const char *data, size_t count, size_t *sent)
|
|
||||||
{
|
|
||||||
p_io io = buf->io;
|
p_io io = buf->io;
|
||||||
p_tm tm = buf->tm;
|
p_tm tm = buf->tm;
|
||||||
size_t total = 0;
|
size_t total = 0;
|
||||||
int err = IO_DONE;
|
int err = IO_DONE;
|
||||||
while (total < count && (err == IO_DONE || err == IO_RETRY)) {
|
while (total < count && err == IO_DONE) {
|
||||||
size_t done;
|
size_t done;
|
||||||
err = io->send(io->ctx, data+total, count-total, &done, tm_get(tm));
|
err = io->send(io->ctx, data+total, count-total, &done, tm);
|
||||||
total += done;
|
total += done;
|
||||||
}
|
}
|
||||||
*sent = total;
|
*sent = total;
|
||||||
@ -156,12 +147,10 @@ int sendraw(p_buf buf, const char *data, size_t count, size_t *sent)
|
|||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Reads a fixed number of bytes (buffered)
|
* Reads a fixed number of bytes (buffered)
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
static
|
static int recvraw(p_buf buf, size_t wanted, luaL_Buffer *b) {
|
||||||
int recvraw(p_buf buf, size_t wanted, luaL_Buffer *b)
|
|
||||||
{
|
|
||||||
int err = IO_DONE;
|
int err = IO_DONE;
|
||||||
size_t total = 0;
|
size_t total = 0;
|
||||||
while (total < wanted && (err == IO_DONE || err == IO_RETRY)) {
|
while (total < wanted && err == IO_DONE) {
|
||||||
size_t count; const char *data;
|
size_t count; const char *data;
|
||||||
err = buf_get(buf, &data, &count);
|
err = buf_get(buf, &data, &count);
|
||||||
count = MIN(count, wanted - total);
|
count = MIN(count, wanted - total);
|
||||||
@ -175,11 +164,9 @@ int recvraw(p_buf buf, size_t wanted, luaL_Buffer *b)
|
|||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Reads everything until the connection is closed (buffered)
|
* Reads everything until the connection is closed (buffered)
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
static
|
static int recvall(p_buf buf, luaL_Buffer *b) {
|
||||||
int recvall(p_buf buf, luaL_Buffer *b)
|
|
||||||
{
|
|
||||||
int err = IO_DONE;
|
int err = IO_DONE;
|
||||||
while (err == IO_DONE || err == IO_RETRY) {
|
while (err == IO_DONE) {
|
||||||
const char *data; size_t count;
|
const char *data; size_t count;
|
||||||
err = buf_get(buf, &data, &count);
|
err = buf_get(buf, &data, &count);
|
||||||
luaL_addlstring(b, data, count);
|
luaL_addlstring(b, data, count);
|
||||||
@ -193,11 +180,9 @@ int recvall(p_buf buf, luaL_Buffer *b)
|
|||||||
* Reads a line terminated by a CR LF pair or just by a LF. The CR and LF
|
* Reads a line terminated by a CR LF pair or just by a LF. The CR and LF
|
||||||
* are not returned by the function and are discarded from the buffer
|
* are not returned by the function and are discarded from the buffer
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
static
|
static int recvline(p_buf buf, luaL_Buffer *b) {
|
||||||
int recvline(p_buf buf, luaL_Buffer *b)
|
|
||||||
{
|
|
||||||
int err = IO_DONE;
|
int err = IO_DONE;
|
||||||
while (err == IO_DONE || err == IO_RETRY) {
|
while (err == IO_DONE) {
|
||||||
size_t count, pos; const char *data;
|
size_t count, pos; const char *data;
|
||||||
err = buf_get(buf, &data, &count);
|
err = buf_get(buf, &data, &count);
|
||||||
pos = 0;
|
pos = 0;
|
||||||
@ -219,9 +204,7 @@ int recvline(p_buf buf, luaL_Buffer *b)
|
|||||||
* Skips a given number of bytes from read buffer. No data is read from the
|
* Skips a given number of bytes from read buffer. No data is read from the
|
||||||
* transport layer
|
* transport layer
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
static
|
static void buf_skip(p_buf buf, size_t count) {
|
||||||
void buf_skip(p_buf buf, size_t count)
|
|
||||||
{
|
|
||||||
buf->first += count;
|
buf->first += count;
|
||||||
if (buf_isempty(buf))
|
if (buf_isempty(buf))
|
||||||
buf->first = buf->last = 0;
|
buf->first = buf->last = 0;
|
||||||
@ -231,15 +214,13 @@ void buf_skip(p_buf buf, size_t count)
|
|||||||
* Return any data available in buffer, or get more data from transport layer
|
* Return any data available in buffer, or get more data from transport layer
|
||||||
* if buffer is empty
|
* if buffer is empty
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
static
|
static int buf_get(p_buf buf, const char **data, size_t *count) {
|
||||||
int buf_get(p_buf buf, const char **data, size_t *count)
|
|
||||||
{
|
|
||||||
int err = IO_DONE;
|
int err = IO_DONE;
|
||||||
p_io io = buf->io;
|
p_io io = buf->io;
|
||||||
p_tm tm = buf->tm;
|
p_tm tm = buf->tm;
|
||||||
if (buf_isempty(buf)) {
|
if (buf_isempty(buf)) {
|
||||||
size_t got;
|
size_t got;
|
||||||
err = io->recv(io->ctx, buf->data, BUF_SIZE, &got, tm_get(tm));
|
err = io->recv(io->ctx, buf->data, BUF_SIZE, &got, tm);
|
||||||
buf->first = 0;
|
buf->first = 0;
|
||||||
buf->last = got;
|
buf->last = got;
|
||||||
}
|
}
|
||||||
@ -247,4 +228,3 @@ int buf_get(p_buf buf, const char **data, size_t *count)
|
|||||||
*data = buf->data + buf->first;
|
*data = buf->data + buf->first;
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
20
src/io.c
20
src/io.c
@ -12,34 +12,34 @@
|
|||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Initializes C structure
|
* Initializes C structure
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
void io_init(p_io io, p_send send, p_recv recv, void *ctx)
|
void io_init(p_io io, p_send send, p_recv recv, p_geterr geterr, void *ctx) {
|
||||||
{
|
|
||||||
io->send = send;
|
io->send = send;
|
||||||
io->recv = recv;
|
io->recv = recv;
|
||||||
|
io->geterr = geterr;
|
||||||
io->ctx = ctx;
|
io->ctx = ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Translate error codes to Lua
|
* Translate error codes to Lua
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
const char *io_strerror(int code)
|
const char *io_strerror(int code) {
|
||||||
{
|
|
||||||
switch (code) {
|
switch (code) {
|
||||||
case IO_DONE: return NULL;
|
case IO_DONE: return NULL;
|
||||||
case IO_TIMEOUT: return "timeout";
|
|
||||||
case IO_RETRY: return "retry";
|
|
||||||
case IO_CLOSED: return "closed";
|
case IO_CLOSED: return "closed";
|
||||||
case IO_REFUSED: return "refused";
|
case IO_TIMEOUT: return "timeout";
|
||||||
|
case IO_CLIPPED: return "clipped";
|
||||||
default: return "unknown error";
|
default: return "unknown error";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Translate error codes to Lua
|
* Push error message from code or from driver
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
void io_pusherror(lua_State *L, int code)
|
void io_pusherror(lua_State *L, p_io io, int code)
|
||||||
{
|
{
|
||||||
const char *err = io_strerror(code);
|
const char *err = NULL;
|
||||||
|
if (code < IO_USER) err = io_strerror(code);
|
||||||
|
else err = io->geterr(io->ctx, code);
|
||||||
if (err) lua_pushstring(L, err);
|
if (err) lua_pushstring(L, err);
|
||||||
else lua_pushnil(L);
|
else lua_pushnil(L);
|
||||||
}
|
}
|
||||||
|
22
src/io.h
22
src/io.h
@ -17,14 +17,15 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <lua.h>
|
#include <lua.h>
|
||||||
|
|
||||||
|
#include "timeout.h"
|
||||||
|
|
||||||
/* IO error codes */
|
/* IO error codes */
|
||||||
enum {
|
enum {
|
||||||
IO_DONE, /* operation completed successfully */
|
IO_DONE, /* operation completed successfully */
|
||||||
IO_RETRY, /* please try again */
|
|
||||||
IO_TIMEOUT, /* operation timed out */
|
IO_TIMEOUT, /* operation timed out */
|
||||||
IO_CLOSED, /* the connection has been closed */
|
IO_CLOSED, /* the connection has been closed */
|
||||||
IO_REFUSED, /* transfer has been refused */
|
IO_CLIPPED, /* maxium bytes count reached */
|
||||||
IO_ERROR /* something else wrong... */
|
IO_USER /* last element in enum is user custom error */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* interface to send function */
|
/* interface to send function */
|
||||||
@ -33,7 +34,13 @@ typedef int (*p_send) (
|
|||||||
const char *data, /* pointer to buffer with data to send */
|
const char *data, /* pointer to buffer with data to send */
|
||||||
size_t count, /* number of bytes to send from buffer */
|
size_t count, /* number of bytes to send from buffer */
|
||||||
size_t *sent, /* number of bytes sent uppon return */
|
size_t *sent, /* number of bytes sent uppon return */
|
||||||
int timeout /* number of miliseconds left for transmission */
|
p_tm tm /* timeout control */
|
||||||
|
);
|
||||||
|
|
||||||
|
/* returns an error string */
|
||||||
|
typedef const char *(*p_geterr) (
|
||||||
|
void *ctx, /* context needed by geterror */
|
||||||
|
int code /* error code */
|
||||||
);
|
);
|
||||||
|
|
||||||
/* interface to recv function */
|
/* interface to recv function */
|
||||||
@ -42,7 +49,7 @@ typedef int (*p_recv) (
|
|||||||
char *data, /* pointer to buffer where data will be writen */
|
char *data, /* pointer to buffer where data will be writen */
|
||||||
size_t count, /* number of bytes to receive into buffer */
|
size_t count, /* number of bytes to receive into buffer */
|
||||||
size_t *got, /* number of bytes received uppon return */
|
size_t *got, /* number of bytes received uppon return */
|
||||||
int timeout /* number of miliseconds left for transmission */
|
p_tm tm /* timeout control */
|
||||||
);
|
);
|
||||||
|
|
||||||
/* IO driver definition */
|
/* IO driver definition */
|
||||||
@ -50,11 +57,12 @@ typedef struct t_io_ {
|
|||||||
void *ctx; /* context needed by send/recv */
|
void *ctx; /* context needed by send/recv */
|
||||||
p_send send; /* send function pointer */
|
p_send send; /* send function pointer */
|
||||||
p_recv recv; /* receive function pointer */
|
p_recv recv; /* receive function pointer */
|
||||||
|
p_geterr geterr; /* receive function pointer */
|
||||||
} t_io;
|
} t_io;
|
||||||
typedef t_io *p_io;
|
typedef t_io *p_io;
|
||||||
|
|
||||||
const char *io_strerror(int code);
|
const char *io_strerror(int code);
|
||||||
void io_pusherror(lua_State *L, int code);
|
void io_pusherror(lua_State *L, p_io io, int code);
|
||||||
void io_init(p_io io, p_send send, p_recv recv, void *ctx);
|
void io_init(p_io io, p_send send, p_recv recv, p_geterr geterr, void *ctx);
|
||||||
|
|
||||||
#endif /* IO_H */
|
#endif /* IO_H */
|
||||||
|
11
src/select.c
11
src/select.c
@ -10,6 +10,7 @@
|
|||||||
#include <lauxlib.h>
|
#include <lauxlib.h>
|
||||||
|
|
||||||
#include "socket.h"
|
#include "socket.h"
|
||||||
|
#include "timeout.h"
|
||||||
#include "select.h"
|
#include "select.h"
|
||||||
|
|
||||||
/*=========================================================================*\
|
/*=========================================================================*\
|
||||||
@ -48,19 +49,21 @@ int select_open(lua_State *L) {
|
|||||||
* Waits for a set of sockets until a condition is met or timeout.
|
* Waits for a set of sockets until a condition is met or timeout.
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
static int global_select(lua_State *L) {
|
static int global_select(lua_State *L) {
|
||||||
int timeout, rtab, wtab, itab, max_fd, ret, ndirty;
|
int rtab, wtab, itab, max_fd, ret, ndirty;
|
||||||
fd_set rset, wset;
|
fd_set rset, wset;
|
||||||
|
t_tm tm;
|
||||||
|
double t = luaL_optnumber(L, 3, -1);
|
||||||
FD_ZERO(&rset); FD_ZERO(&wset);
|
FD_ZERO(&rset); FD_ZERO(&wset);
|
||||||
lua_settop(L, 3);
|
lua_settop(L, 3);
|
||||||
timeout = lua_isnil(L, 3) ? -1 : (int)(luaL_checknumber(L, 3) * 1000);
|
|
||||||
lua_newtable(L); itab = lua_gettop(L);
|
lua_newtable(L); itab = lua_gettop(L);
|
||||||
lua_newtable(L); rtab = lua_gettop(L);
|
lua_newtable(L); rtab = lua_gettop(L);
|
||||||
lua_newtable(L); wtab = lua_gettop(L);
|
lua_newtable(L); wtab = lua_gettop(L);
|
||||||
max_fd = collect_fd(L, 1, -1, itab, &rset);
|
max_fd = collect_fd(L, 1, -1, itab, &rset);
|
||||||
ndirty = check_dirty(L, 1, rtab, &rset);
|
ndirty = check_dirty(L, 1, rtab, &rset);
|
||||||
timeout = ndirty > 0? 0: timeout;
|
t = ndirty > 0? 0.0: t;
|
||||||
|
tm_init(&tm, t, -1);
|
||||||
max_fd = collect_fd(L, 2, max_fd, itab, &wset);
|
max_fd = collect_fd(L, 2, max_fd, itab, &wset);
|
||||||
ret = sock_select(max_fd+1, &rset, &wset, NULL, timeout);
|
ret = sock_select(max_fd+1, &rset, &wset, NULL, &tm);
|
||||||
if (ret > 0 || (ret == 0 && ndirty > 0)) {
|
if (ret > 0 || (ret == 0 && ndirty > 0)) {
|
||||||
return_fd(L, &rset, max_fd+1, itab, rtab, ndirty);
|
return_fd(L, &rset, max_fd+1, itab, rtab, ndirty);
|
||||||
return_fd(L, &wset, max_fd+1, itab, wtab, 0);
|
return_fd(L, &wset, max_fd+1, itab, wtab, 0);
|
||||||
|
14
src/socket.h
14
src/socket.h
@ -41,17 +41,15 @@ int sock_open(void);
|
|||||||
int sock_close(void);
|
int sock_close(void);
|
||||||
void sock_destroy(p_sock ps);
|
void sock_destroy(p_sock ps);
|
||||||
void sock_shutdown(p_sock ps, int how);
|
void sock_shutdown(p_sock ps, int how);
|
||||||
int sock_send(p_sock ps, const char *data, size_t count,
|
int sock_send(p_sock ps, const char *data, size_t count, size_t *sent, p_tm tm);
|
||||||
size_t *sent, int timeout);
|
int sock_recv(p_sock ps, char *data, size_t count, size_t *got, p_tm tm);
|
||||||
int sock_recv(p_sock ps, char *data, size_t count,
|
|
||||||
size_t *got, int timeout);
|
|
||||||
int sock_sendto(p_sock ps, const char *data, size_t count,
|
int sock_sendto(p_sock ps, const char *data, size_t count,
|
||||||
size_t *sent, SA *addr, socklen_t addr_len, int timeout);
|
size_t *sent, SA *addr, socklen_t addr_len, p_tm tm);
|
||||||
int sock_recvfrom(p_sock ps, char *data, size_t count,
|
int sock_recvfrom(p_sock ps, char *data, size_t count,
|
||||||
size_t *got, SA *addr, socklen_t *addr_len, int timeout);
|
size_t *got, SA *addr, socklen_t *addr_len, p_tm tm);
|
||||||
void sock_setnonblocking(p_sock ps);
|
void sock_setnonblocking(p_sock ps);
|
||||||
void sock_setblocking(p_sock ps);
|
void sock_setblocking(p_sock ps);
|
||||||
int sock_select(int n, fd_set *rfds, fd_set *wfds, fd_set *efds, int timeout);
|
int sock_select(int n, fd_set *rfds, fd_set *wfds, fd_set *efds, p_tm tm);
|
||||||
|
|
||||||
const char *sock_connect(p_sock ps, SA *addr, socklen_t addr_len, p_tm tm);
|
const char *sock_connect(p_sock ps, SA *addr, socklen_t addr_len, p_tm tm);
|
||||||
const char *sock_create(p_sock ps, int domain, int type, int protocol);
|
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);
|
|||||||
const char *sock_accept(p_sock ps, p_sock pa, SA *addr,
|
const char *sock_accept(p_sock ps, p_sock pa, SA *addr,
|
||||||
socklen_t *addr_len, p_tm tm);
|
socklen_t *addr_len, p_tm tm);
|
||||||
|
|
||||||
|
const char *sock_geterr(p_sock ps, int code);
|
||||||
const char *sock_hoststrerror(void);
|
const char *sock_hoststrerror(void);
|
||||||
|
const char *sock_strerror(void);
|
||||||
|
|
||||||
#endif /* SOCK_H */
|
#endif /* SOCK_H */
|
||||||
|
@ -163,7 +163,8 @@ static int meth_accept(lua_State *L)
|
|||||||
/* initialize structure fields */
|
/* initialize structure fields */
|
||||||
sock_setnonblocking(&sock);
|
sock_setnonblocking(&sock);
|
||||||
clnt->sock = sock;
|
clnt->sock = sock;
|
||||||
io_init(&clnt->io, (p_send)sock_send, (p_recv)sock_recv, &clnt->sock);
|
io_init(&clnt->io, (p_send) sock_send, (p_recv) sock_recv,
|
||||||
|
(p_geterr) sock_geterr, &clnt->sock);
|
||||||
tm_init(&clnt->tm, -1, -1);
|
tm_init(&clnt->tm, -1, -1);
|
||||||
buf_init(&clnt->buf, &clnt->io, &clnt->tm);
|
buf_init(&clnt->buf, &clnt->io, &clnt->tm);
|
||||||
return 1;
|
return 1;
|
||||||
@ -313,7 +314,8 @@ static int global_create(lua_State *L)
|
|||||||
/* initialize remaining structure fields */
|
/* initialize remaining structure fields */
|
||||||
sock_setnonblocking(&sock);
|
sock_setnonblocking(&sock);
|
||||||
tcp->sock = sock;
|
tcp->sock = sock;
|
||||||
io_init(&tcp->io, (p_send) sock_send, (p_recv) sock_recv, &tcp->sock);
|
io_init(&tcp->io, (p_send) sock_send, (p_recv) sock_recv,
|
||||||
|
(p_geterr) sock_geterr, &tcp->sock);
|
||||||
tm_init(&tcp->tm, -1, -1);
|
tm_init(&tcp->tm, -1, -1);
|
||||||
buf_init(&tcp->buf, &tcp->io, &tcp->tm);
|
buf_init(&tcp->buf, &tcp->io, &tcp->tm);
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -46,8 +46,7 @@ static luaL_reg func[] = {
|
|||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Initialize structure
|
* Initialize structure
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
void tm_init(p_tm tm, int block, int total)
|
void tm_init(p_tm tm, double block, double total) {
|
||||||
{
|
|
||||||
tm->block = block;
|
tm->block = block;
|
||||||
tm->total = total;
|
tm->total = total;
|
||||||
}
|
}
|
||||||
@ -60,18 +59,17 @@ void tm_init(p_tm tm, int block, int total)
|
|||||||
* Returns
|
* Returns
|
||||||
* the number of ms left or -1 if there is no time limit
|
* the number of ms left or -1 if there is no time limit
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
int tm_get(p_tm tm)
|
double tm_get(p_tm tm) {
|
||||||
{
|
if (tm->block < 0.0 && tm->total < 0.0) {
|
||||||
if (tm->block < 0 && tm->total < 0) {
|
|
||||||
return -1;
|
return -1;
|
||||||
} else if (tm->block < 0) {
|
} else if (tm->block < 0.0) {
|
||||||
int t = tm->total - tm_gettime() + tm->start;
|
double t = tm->total - tm_gettime() + tm->start;
|
||||||
return MAX(t, 0);
|
return MAX(t, 0.0);
|
||||||
} else if (tm->total < 0) {
|
} else if (tm->total < 0.0) {
|
||||||
return tm->block;
|
return tm->block;
|
||||||
} else {
|
} else {
|
||||||
int t = tm->total - tm_gettime() + tm->start;
|
double t = tm->total - tm_gettime() + tm->start;
|
||||||
return MIN(tm->block, MAX(t, 0));
|
return MIN(tm->block, MAX(t, 0.0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,8 +80,7 @@ int tm_get(p_tm tm)
|
|||||||
* Returns
|
* Returns
|
||||||
* start field of structure
|
* start field of structure
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
int tm_getstart(p_tm tm)
|
double tm_getstart(p_tm tm) {
|
||||||
{
|
|
||||||
return tm->start;
|
return tm->start;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -95,19 +92,18 @@ int tm_getstart(p_tm tm)
|
|||||||
* Returns
|
* Returns
|
||||||
* the number of ms left or -1 if there is no time limit
|
* the number of ms left or -1 if there is no time limit
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
int tm_getretry(p_tm tm)
|
double tm_getretry(p_tm tm) {
|
||||||
{
|
if (tm->block < 0.0 && tm->total < 0.0) {
|
||||||
if (tm->block < 0 && tm->total < 0) {
|
|
||||||
return -1;
|
return -1;
|
||||||
} else if (tm->block < 0) {
|
} else if (tm->block < 0.0) {
|
||||||
int t = tm->total - tm_gettime() + tm->start;
|
double t = tm->total - tm_gettime() + tm->start;
|
||||||
return MAX(t, 0);
|
return MAX(t, 0.0);
|
||||||
} else if (tm->total < 0) {
|
} else if (tm->total < 0.0) {
|
||||||
int t = tm->block - tm_gettime() + tm->start;
|
double t = tm->block - tm_gettime() + tm->start;
|
||||||
return MAX(t, 0);
|
return MAX(t, 0.0);
|
||||||
} else {
|
} else {
|
||||||
int t = tm->total - tm_gettime() + tm->start;
|
double t = tm->total - tm_gettime() + tm->start;
|
||||||
return MIN(tm->block, MAX(t, 0));
|
return MIN(tm->block, MAX(t, 0.0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -116,8 +112,7 @@ int tm_getretry(p_tm tm)
|
|||||||
* Input
|
* Input
|
||||||
* tm: timeout control structure
|
* tm: timeout control structure
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
p_tm tm_markstart(p_tm tm)
|
p_tm tm_markstart(p_tm tm) {
|
||||||
{
|
|
||||||
tm->start = tm_gettime();
|
tm->start = tm_gettime();
|
||||||
return tm;
|
return tm;
|
||||||
}
|
}
|
||||||
@ -128,24 +123,23 @@ p_tm tm_markstart(p_tm tm)
|
|||||||
* time in ms.
|
* time in ms.
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
int tm_gettime(void)
|
double tm_gettime(void) {
|
||||||
{
|
FILETIME ft;
|
||||||
return GetTickCount();
|
GetSystemTimeAsFileTime(&ft);
|
||||||
|
return ft.dwLowDateTime/1.0e7 + ft.dwHighDateTime*(4294967296.0/1.0e7);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
int tm_gettime(void)
|
double tm_gettime(void) {
|
||||||
{
|
|
||||||
struct timeval v;
|
struct timeval v;
|
||||||
gettimeofday(&v, (struct timezone *) NULL);
|
gettimeofday(&v, (struct timezone *) NULL);
|
||||||
return v.tv_sec * 1000 + v.tv_usec/1000;
|
return v.tv_sec + v.tv_usec/1.0e6;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Initializes module
|
* Initializes module
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
int tm_open(lua_State *L)
|
int tm_open(lua_State *L) {
|
||||||
{
|
|
||||||
luaL_openlib(L, NULL, func, 0);
|
luaL_openlib(L, NULL, func, 0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -156,16 +150,15 @@ int tm_open(lua_State *L)
|
|||||||
* time: time out value in seconds
|
* time: time out value in seconds
|
||||||
* mode: "b" for block timeout, "t" for total timeout. (default: b)
|
* mode: "b" for block timeout, "t" for total timeout. (default: b)
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
int tm_meth_settimeout(lua_State *L, p_tm tm)
|
int tm_meth_settimeout(lua_State *L, p_tm tm) {
|
||||||
{
|
double t = luaL_optnumber(L, 2, -1);
|
||||||
int ms = lua_isnil(L, 2) ? -1 : (int) (luaL_checknumber(L, 2)*1000.0);
|
|
||||||
const char *mode = luaL_optstring(L, 3, "b");
|
const char *mode = luaL_optstring(L, 3, "b");
|
||||||
switch (*mode) {
|
switch (*mode) {
|
||||||
case 'b':
|
case 'b':
|
||||||
tm->block = ms;
|
tm->block = t;
|
||||||
break;
|
break;
|
||||||
case 'r': case 't':
|
case 'r': case 't':
|
||||||
tm->total = ms;
|
tm->total = t;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
luaL_argcheck(L, 0, 3, "invalid timeout mode");
|
luaL_argcheck(L, 0, 3, "invalid timeout mode");
|
||||||
@ -183,7 +176,7 @@ int tm_meth_settimeout(lua_State *L, p_tm tm)
|
|||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
static int tm_lua_gettime(lua_State *L)
|
static int tm_lua_gettime(lua_State *L)
|
||||||
{
|
{
|
||||||
lua_pushnumber(L, tm_gettime()/1000.0);
|
lua_pushnumber(L, tm_gettime());
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,19 +10,19 @@
|
|||||||
|
|
||||||
/* timeout control structure */
|
/* timeout control structure */
|
||||||
typedef struct t_tm_ {
|
typedef struct t_tm_ {
|
||||||
int total; /* total number of miliseconds for operation */
|
double total; /* total number of miliseconds for operation */
|
||||||
int block; /* maximum time for blocking calls */
|
double block; /* maximum time for blocking calls */
|
||||||
int start; /* time of start of operation */
|
double start; /* time of start of operation */
|
||||||
} t_tm;
|
} t_tm;
|
||||||
typedef t_tm *p_tm;
|
typedef t_tm *p_tm;
|
||||||
|
|
||||||
int tm_open(lua_State *L);
|
int tm_open(lua_State *L);
|
||||||
void tm_init(p_tm tm, int block, int total);
|
void tm_init(p_tm tm, double block, double total);
|
||||||
int tm_get(p_tm tm);
|
double tm_get(p_tm tm);
|
||||||
int tm_getretry(p_tm tm);
|
double tm_getretry(p_tm tm);
|
||||||
p_tm tm_markstart(p_tm tm);
|
p_tm tm_markstart(p_tm tm);
|
||||||
int tm_getstart(p_tm tm);
|
double tm_getstart(p_tm tm);
|
||||||
int tm_gettime(void);
|
double tm_gettime(void);
|
||||||
int tm_meth_settimeout(lua_State *L, p_tm tm);
|
int tm_meth_settimeout(lua_State *L, p_tm tm);
|
||||||
|
|
||||||
#endif /* TM_H */
|
#endif /* TM_H */
|
||||||
|
107
src/udp.c
107
src/udp.c
@ -41,25 +41,26 @@ static int meth_settimeout(lua_State *L);
|
|||||||
static int meth_getfd(lua_State *L);
|
static int meth_getfd(lua_State *L);
|
||||||
static int meth_setfd(lua_State *L);
|
static int meth_setfd(lua_State *L);
|
||||||
static int meth_dirty(lua_State *L);
|
static int meth_dirty(lua_State *L);
|
||||||
|
static void pusherror(lua_State *L, int code);
|
||||||
|
|
||||||
/* udp object methods */
|
/* udp object methods */
|
||||||
static luaL_reg udp[] = {
|
static luaL_reg udp[] = {
|
||||||
{"setpeername", meth_setpeername},
|
|
||||||
{"setsockname", meth_setsockname},
|
|
||||||
{"getsockname", meth_getsockname},
|
|
||||||
{"getpeername", meth_getpeername},
|
|
||||||
{"send", meth_send},
|
|
||||||
{"sendto", meth_sendto},
|
|
||||||
{"receive", meth_receive},
|
|
||||||
{"receivefrom", meth_receivefrom},
|
|
||||||
{"settimeout", meth_settimeout},
|
|
||||||
{"close", meth_close},
|
|
||||||
{"setoption", meth_setoption},
|
|
||||||
{"__gc", meth_close},
|
{"__gc", meth_close},
|
||||||
{"__tostring", aux_tostring},
|
{"__tostring", aux_tostring},
|
||||||
{"getfd", meth_getfd},
|
{"close", meth_close},
|
||||||
{"setfd", meth_setfd},
|
|
||||||
{"dirty", meth_dirty},
|
{"dirty", meth_dirty},
|
||||||
|
{"getfd", meth_getfd},
|
||||||
|
{"getpeername", meth_getpeername},
|
||||||
|
{"getsockname", meth_getsockname},
|
||||||
|
{"receive", meth_receive},
|
||||||
|
{"receivefrom", meth_receivefrom},
|
||||||
|
{"send", meth_send},
|
||||||
|
{"sendto", meth_sendto},
|
||||||
|
{"setfd", meth_setfd},
|
||||||
|
{"setoption", meth_setoption},
|
||||||
|
{"setpeername", meth_setpeername},
|
||||||
|
{"setsockname", meth_setsockname},
|
||||||
|
{"settimeout", meth_settimeout},
|
||||||
{NULL, NULL}
|
{NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -99,35 +100,43 @@ int udp_open(lua_State *L)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*=========================================================================*\
|
/*=========================================================================*\
|
||||||
* Lua methods
|
* Lua methods
|
||||||
\*=========================================================================*/
|
\*=========================================================================*/
|
||||||
|
/*-------------------------------------------------------------------------*\
|
||||||
|
* Pushes the error message
|
||||||
|
\*-------------------------------------------------------------------------*/
|
||||||
|
void pusherror(lua_State *L, int code) {
|
||||||
|
const char *err = code != IO_USER? io_strerror(code): "refused";
|
||||||
|
err = err? err: sock_strerror();
|
||||||
|
if (err) lua_pushstring(L, err);
|
||||||
|
else lua_pushnil(L);
|
||||||
|
}
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Send data through connected udp socket
|
* Send data through connected udp socket
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
static int meth_send(lua_State *L)
|
static int meth_send(lua_State *L) {
|
||||||
{
|
|
||||||
p_udp udp = (p_udp) aux_checkclass(L, "udp{connected}", 1);
|
p_udp udp = (p_udp) aux_checkclass(L, "udp{connected}", 1);
|
||||||
p_tm tm = &udp->tm;
|
p_tm tm = &udp->tm;
|
||||||
size_t count, sent = 0;
|
size_t count, sent = 0;
|
||||||
int err;
|
int err;
|
||||||
const char *data = luaL_checklstring(L, 2, &count);
|
const char *data = luaL_checklstring(L, 2, &count);
|
||||||
tm_markstart(tm);
|
tm_markstart(tm);
|
||||||
do err = sock_send(&udp->sock, data, count, &sent, tm_getretry(tm));
|
err = sock_send(&udp->sock, data, count, &sent, tm);
|
||||||
while (err == IO_RETRY);
|
|
||||||
if (err == IO_DONE) lua_pushnumber(L, sent);
|
if (err == IO_DONE) lua_pushnumber(L, sent);
|
||||||
else lua_pushnil(L);
|
else lua_pushnil(L);
|
||||||
/* a 'closed' error on an unconnected means the target address was not
|
/* a 'closed' error on an unconnected means the target address was not
|
||||||
* accepted by the transport layer */
|
* accepted by the transport layer */
|
||||||
io_pusherror(L, err == IO_CLOSED ? IO_REFUSED : err);
|
pusherror(L, err == IO_CLOSED ? IO_USER : err);
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Send data through unconnected udp socket
|
* Send data through unconnected udp socket
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
static int meth_sendto(lua_State *L)
|
static int meth_sendto(lua_State *L) {
|
||||||
{
|
|
||||||
p_udp udp = (p_udp) aux_checkclass(L, "udp{unconnected}", 1);
|
p_udp udp = (p_udp) aux_checkclass(L, "udp{unconnected}", 1);
|
||||||
size_t count, sent = 0;
|
size_t count, sent = 0;
|
||||||
const char *data = luaL_checklstring(L, 2, &count);
|
const char *data = luaL_checklstring(L, 2, &count);
|
||||||
@ -142,22 +151,20 @@ static int meth_sendto(lua_State *L)
|
|||||||
addr.sin_family = AF_INET;
|
addr.sin_family = AF_INET;
|
||||||
addr.sin_port = htons(port);
|
addr.sin_port = htons(port);
|
||||||
tm_markstart(tm);
|
tm_markstart(tm);
|
||||||
do err = sock_sendto(&udp->sock, data, count, &sent,
|
err = sock_sendto(&udp->sock, data, count, &sent,
|
||||||
(SA *) &addr, sizeof(addr), tm_get(tm));
|
(SA *) &addr, sizeof(addr), tm);
|
||||||
while (err == IO_RETRY);
|
|
||||||
if (err == IO_DONE) lua_pushnumber(L, sent);
|
if (err == IO_DONE) lua_pushnumber(L, sent);
|
||||||
else lua_pushnil(L);
|
else lua_pushnil(L);
|
||||||
/* a 'closed' error on an unconnected means the target address was not
|
/* a 'closed' error on an unconnected means the target address was not
|
||||||
* accepted by the transport layer */
|
* accepted by the transport layer */
|
||||||
io_pusherror(L, err == IO_CLOSED ? IO_REFUSED : err);
|
pusherror(L, err == IO_CLOSED ? IO_USER : err);
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Receives data from a UDP socket
|
* Receives data from a UDP socket
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
static int meth_receive(lua_State *L)
|
static int meth_receive(lua_State *L) {
|
||||||
{
|
|
||||||
p_udp udp = (p_udp) aux_checkgroup(L, "udp{any}", 1);
|
p_udp udp = (p_udp) aux_checkgroup(L, "udp{any}", 1);
|
||||||
char buffer[UDP_DATAGRAMSIZE];
|
char buffer[UDP_DATAGRAMSIZE];
|
||||||
size_t got, count = (size_t) luaL_optnumber(L, 2, sizeof(buffer));
|
size_t got, count = (size_t) luaL_optnumber(L, 2, sizeof(buffer));
|
||||||
@ -165,19 +172,17 @@ static int meth_receive(lua_State *L)
|
|||||||
p_tm tm = &udp->tm;
|
p_tm tm = &udp->tm;
|
||||||
count = MIN(count, sizeof(buffer));
|
count = MIN(count, sizeof(buffer));
|
||||||
tm_markstart(tm);
|
tm_markstart(tm);
|
||||||
do err = sock_recv(&udp->sock, buffer, count, &got, tm_get(tm));
|
err = sock_recv(&udp->sock, buffer, count, &got, tm);
|
||||||
while (err == IO_RETRY);
|
|
||||||
if (err == IO_DONE) lua_pushlstring(L, buffer, got);
|
if (err == IO_DONE) lua_pushlstring(L, buffer, got);
|
||||||
else lua_pushnil(L);
|
else lua_pushnil(L);
|
||||||
io_pusherror(L, err);
|
pusherror(L, err);
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Receives data and sender from a UDP socket
|
* Receives data and sender from a UDP socket
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
static int meth_receivefrom(lua_State *L)
|
static int meth_receivefrom(lua_State *L) {
|
||||||
{
|
|
||||||
p_udp udp = (p_udp) aux_checkclass(L, "udp{unconnected}", 1);
|
p_udp udp = (p_udp) aux_checkclass(L, "udp{unconnected}", 1);
|
||||||
struct sockaddr_in addr;
|
struct sockaddr_in addr;
|
||||||
socklen_t addr_len = sizeof(addr);
|
socklen_t addr_len = sizeof(addr);
|
||||||
@ -187,9 +192,8 @@ static int meth_receivefrom(lua_State *L)
|
|||||||
p_tm tm = &udp->tm;
|
p_tm tm = &udp->tm;
|
||||||
tm_markstart(tm);
|
tm_markstart(tm);
|
||||||
count = MIN(count, sizeof(buffer));
|
count = MIN(count, sizeof(buffer));
|
||||||
do err = sock_recvfrom(&udp->sock, buffer, count, &got,
|
err = sock_recvfrom(&udp->sock, buffer, count, &got,
|
||||||
(SA *) &addr, &addr_len, tm_get(tm));
|
(SA *) &addr, &addr_len, tm);
|
||||||
while (err == IO_RETRY);
|
|
||||||
if (err == IO_DONE) {
|
if (err == IO_DONE) {
|
||||||
lua_pushlstring(L, buffer, got);
|
lua_pushlstring(L, buffer, got);
|
||||||
lua_pushstring(L, inet_ntoa(addr.sin_addr));
|
lua_pushstring(L, inet_ntoa(addr.sin_addr));
|
||||||
@ -197,7 +201,7 @@ static int meth_receivefrom(lua_State *L)
|
|||||||
return 3;
|
return 3;
|
||||||
} else {
|
} else {
|
||||||
lua_pushnil(L);
|
lua_pushnil(L);
|
||||||
io_pusherror(L, err);
|
pusherror(L, err);
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -205,23 +209,20 @@ static int meth_receivefrom(lua_State *L)
|
|||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Select support methods
|
* Select support methods
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
static int meth_getfd(lua_State *L)
|
static int meth_getfd(lua_State *L) {
|
||||||
{
|
|
||||||
p_udp udp = (p_udp) aux_checkgroup(L, "udp{any}", 1);
|
p_udp udp = (p_udp) aux_checkgroup(L, "udp{any}", 1);
|
||||||
lua_pushnumber(L, (int) udp->sock);
|
lua_pushnumber(L, (int) udp->sock);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* this is very dangerous, but can be handy for those that are brave enough */
|
/* this is very dangerous, but can be handy for those that are brave enough */
|
||||||
static int meth_setfd(lua_State *L)
|
static int meth_setfd(lua_State *L) {
|
||||||
{
|
|
||||||
p_udp udp = (p_udp) aux_checkgroup(L, "udp{any}", 1);
|
p_udp udp = (p_udp) aux_checkgroup(L, "udp{any}", 1);
|
||||||
udp->sock = (t_sock) luaL_checknumber(L, 2);
|
udp->sock = (t_sock) luaL_checknumber(L, 2);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int meth_dirty(lua_State *L)
|
static int meth_dirty(lua_State *L) {
|
||||||
{
|
|
||||||
p_udp udp = (p_udp) aux_checkgroup(L, "udp{any}", 1);
|
p_udp udp = (p_udp) aux_checkgroup(L, "udp{any}", 1);
|
||||||
(void) udp;
|
(void) udp;
|
||||||
lua_pushboolean(L, 0);
|
lua_pushboolean(L, 0);
|
||||||
@ -231,14 +232,12 @@ static int meth_dirty(lua_State *L)
|
|||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Just call inet methods
|
* Just call inet methods
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
static int meth_getpeername(lua_State *L)
|
static int meth_getpeername(lua_State *L) {
|
||||||
{
|
|
||||||
p_udp udp = (p_udp) aux_checkclass(L, "udp{connected}", 1);
|
p_udp udp = (p_udp) aux_checkclass(L, "udp{connected}", 1);
|
||||||
return inet_meth_getpeername(L, &udp->sock);
|
return inet_meth_getpeername(L, &udp->sock);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int meth_getsockname(lua_State *L)
|
static int meth_getsockname(lua_State *L) {
|
||||||
{
|
|
||||||
p_udp udp = (p_udp) aux_checkgroup(L, "udp{any}", 1);
|
p_udp udp = (p_udp) aux_checkgroup(L, "udp{any}", 1);
|
||||||
return inet_meth_getsockname(L, &udp->sock);
|
return inet_meth_getsockname(L, &udp->sock);
|
||||||
}
|
}
|
||||||
@ -246,8 +245,7 @@ static int meth_getsockname(lua_State *L)
|
|||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Just call option handler
|
* Just call option handler
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
static int meth_setoption(lua_State *L)
|
static int meth_setoption(lua_State *L) {
|
||||||
{
|
|
||||||
p_udp udp = (p_udp) aux_checkgroup(L, "udp{any}", 1);
|
p_udp udp = (p_udp) aux_checkgroup(L, "udp{any}", 1);
|
||||||
return opt_meth_setoption(L, opt, &udp->sock);
|
return opt_meth_setoption(L, opt, &udp->sock);
|
||||||
}
|
}
|
||||||
@ -255,8 +253,7 @@ static int meth_setoption(lua_State *L)
|
|||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Just call tm methods
|
* Just call tm methods
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
static int meth_settimeout(lua_State *L)
|
static int meth_settimeout(lua_State *L) {
|
||||||
{
|
|
||||||
p_udp udp = (p_udp) aux_checkgroup(L, "udp{any}", 1);
|
p_udp udp = (p_udp) aux_checkgroup(L, "udp{any}", 1);
|
||||||
return tm_meth_settimeout(L, &udp->tm);
|
return tm_meth_settimeout(L, &udp->tm);
|
||||||
}
|
}
|
||||||
@ -264,8 +261,7 @@ static int meth_settimeout(lua_State *L)
|
|||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Turns a master udp object into a client object.
|
* Turns a master udp object into a client object.
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
static int meth_setpeername(lua_State *L)
|
static int meth_setpeername(lua_State *L) {
|
||||||
{
|
|
||||||
p_udp udp = (p_udp) aux_checkclass(L, "udp{unconnected}", 1);
|
p_udp udp = (p_udp) aux_checkclass(L, "udp{unconnected}", 1);
|
||||||
p_tm tm = &udp->tm;
|
p_tm tm = &udp->tm;
|
||||||
const char *address = luaL_checkstring(L, 2);
|
const char *address = luaL_checkstring(L, 2);
|
||||||
@ -289,8 +285,7 @@ static int meth_setpeername(lua_State *L)
|
|||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Closes socket used by object
|
* Closes socket used by object
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
static int meth_close(lua_State *L)
|
static int meth_close(lua_State *L) {
|
||||||
{
|
|
||||||
p_udp udp = (p_udp) aux_checkgroup(L, "udp{any}", 1);
|
p_udp udp = (p_udp) aux_checkgroup(L, "udp{any}", 1);
|
||||||
sock_destroy(&udp->sock);
|
sock_destroy(&udp->sock);
|
||||||
return 0;
|
return 0;
|
||||||
@ -299,8 +294,7 @@ static int meth_close(lua_State *L)
|
|||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Turns a master object into a server object
|
* Turns a master object into a server object
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
static int meth_setsockname(lua_State *L)
|
static int meth_setsockname(lua_State *L) {
|
||||||
{
|
|
||||||
p_udp udp = (p_udp) aux_checkclass(L, "udp{unconnected}", 1);
|
p_udp udp = (p_udp) aux_checkclass(L, "udp{unconnected}", 1);
|
||||||
const char *address = luaL_checkstring(L, 2);
|
const char *address = luaL_checkstring(L, 2);
|
||||||
unsigned short port = (unsigned short) luaL_checknumber(L, 3);
|
unsigned short port = (unsigned short) luaL_checknumber(L, 3);
|
||||||
@ -320,8 +314,7 @@ static int meth_setsockname(lua_State *L)
|
|||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Creates a master udp object
|
* Creates a master udp object
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
static int global_create(lua_State *L)
|
static int global_create(lua_State *L) {
|
||||||
{
|
|
||||||
t_sock sock;
|
t_sock sock;
|
||||||
const char *err = inet_trycreate(&sock, SOCK_DGRAM);
|
const char *err = inet_trycreate(&sock, SOCK_DGRAM);
|
||||||
/* try to allocate a system socket */
|
/* try to allocate a system socket */
|
||||||
|
336
src/usocket.c
336
src/usocket.c
@ -20,17 +20,10 @@
|
|||||||
|
|
||||||
#include "socket.h"
|
#include "socket.h"
|
||||||
|
|
||||||
static const char *sock_createstrerror(int err);
|
|
||||||
static const char *sock_bindstrerror(int err);
|
|
||||||
static const char *sock_connectstrerror(int err);
|
|
||||||
static const char *sock_acceptstrerror(int err);
|
|
||||||
static const char *sock_listenstrerror(int err);
|
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Initializes module
|
* Initializes module
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
int sock_open(void)
|
int sock_open(void) {
|
||||||
{
|
|
||||||
#if DOESNT_COMPILE_TRY_THIS
|
#if DOESNT_COMPILE_TRY_THIS
|
||||||
struct sigaction ignore;
|
struct sigaction ignore;
|
||||||
memset(&ignore, 0, sizeof(ignore));
|
memset(&ignore, 0, sizeof(ignore));
|
||||||
@ -45,16 +38,14 @@ int sock_open(void)
|
|||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Close module
|
* Close module
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
int sock_close(void)
|
int sock_close(void) {
|
||||||
{
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Close and inutilize socket
|
* Close and inutilize socket
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
void sock_destroy(p_sock ps)
|
void sock_destroy(p_sock ps) {
|
||||||
{
|
|
||||||
if (*ps != SOCK_INVALID) {
|
if (*ps != SOCK_INVALID) {
|
||||||
sock_setblocking(ps);
|
sock_setblocking(ps);
|
||||||
close(*ps);
|
close(*ps);
|
||||||
@ -63,23 +54,26 @@ void sock_destroy(p_sock ps)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Select with int timeout in ms
|
* Select with timeout control
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
int sock_select(int n, fd_set *rfds, fd_set *wfds, fd_set *efds, int timeout)
|
int sock_select(int n, fd_set *rfds, fd_set *wfds, fd_set *efds, p_tm tm) {
|
||||||
{
|
int ret;
|
||||||
|
do {
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
tv.tv_sec = timeout / 1000;
|
double t = tm_getretry(tm);
|
||||||
tv.tv_usec = (timeout % 1000) * 1000;
|
tv.tv_sec = (int) t;
|
||||||
return select(n, rfds, wfds, efds, timeout >= 0? &tv: NULL);
|
tv.tv_usec = (int) ((t - tv.tv_sec) * 1.0e6);
|
||||||
|
ret = select(n, rfds, wfds, efds, t >= 0.0? &tv: NULL);
|
||||||
|
} while (ret < 0 && errno == EINTR);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Creates and sets up a socket
|
* Creates and sets up a socket
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
const char *sock_create(p_sock ps, int domain, int type, int protocol)
|
const char *sock_create(p_sock ps, int domain, int type, int protocol) {
|
||||||
{
|
|
||||||
t_sock sock = socket(domain, type, protocol);
|
t_sock sock = socket(domain, type, protocol);
|
||||||
if (sock == SOCK_INVALID) return sock_createstrerror(errno);
|
if (sock == SOCK_INVALID) return sock_strerror();
|
||||||
*ps = sock;
|
*ps = sock;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -87,8 +81,7 @@ const char *sock_create(p_sock ps, int domain, int type, int protocol)
|
|||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Connects or returns error message
|
* Connects or returns error message
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
const char *sock_connect(p_sock ps, SA *addr, socklen_t addr_len, p_tm tm)
|
const char *sock_connect(p_sock ps, SA *addr, socklen_t addr_len, p_tm tm) {
|
||||||
{
|
|
||||||
t_sock sock = *ps;
|
t_sock sock = *ps;
|
||||||
int err;
|
int err;
|
||||||
/* don't call on closed socket */
|
/* don't call on closed socket */
|
||||||
@ -99,38 +92,38 @@ const char *sock_connect(p_sock ps, SA *addr, socklen_t addr_len, p_tm tm)
|
|||||||
/* if no error, we're done */
|
/* if no error, we're done */
|
||||||
if (err == 0) return NULL;
|
if (err == 0) return NULL;
|
||||||
/* make sure the system is trying to connect */
|
/* make sure the system is trying to connect */
|
||||||
if (errno != EINPROGRESS) return sock_connectstrerror(errno);
|
if (errno != EINPROGRESS) return sock_strerror();
|
||||||
|
/* optimize for timeout = 0 */
|
||||||
|
if (tm_get(tm) == 0.0) return io_strerror(IO_TIMEOUT);
|
||||||
/* wait for a timeout or for the system's answer */
|
/* wait for a timeout or for the system's answer */
|
||||||
for ( ;; ) {
|
for ( ;; ) {
|
||||||
fd_set rfds, wfds, efds;
|
fd_set rfds, wfds;
|
||||||
FD_ZERO(&rfds); FD_SET(sock, &rfds);
|
FD_ZERO(&rfds); FD_SET(sock, &rfds);
|
||||||
FD_ZERO(&wfds); FD_SET(sock, &wfds);
|
FD_ZERO(&wfds); FD_SET(sock, &wfds);
|
||||||
FD_ZERO(&efds); FD_SET(sock, &efds);
|
|
||||||
/* we run select to avoid busy waiting */
|
/* we run select to avoid busy waiting */
|
||||||
do err = sock_select(sock+1, &rfds, &wfds, &efds, tm_getretry(tm));
|
err = sock_select(sock+1, &rfds, &wfds, NULL, tm);
|
||||||
while (err < 0 && errno == EINTR);
|
/* if there was an event, check what happened */
|
||||||
/* if selects readable, try reading */
|
|
||||||
if (err > 0) {
|
if (err > 0) {
|
||||||
char dummy;
|
char dummy;
|
||||||
/* recv will set errno to the value a blocking connect would set */
|
/* recv will set errno to the value a blocking connect would set */
|
||||||
if (recv(sock, &dummy, 0, 0) < 0 && errno != EAGAIN)
|
if (err > 1 && FD_ISSET(sock, &rfds) &&
|
||||||
return sock_connectstrerror(errno);
|
recv(sock, &dummy, 0, 0) < 0 && errno != EAGAIN)
|
||||||
|
return sock_strerror();
|
||||||
else
|
else
|
||||||
return NULL;
|
return NULL;
|
||||||
/* if no event happened, there was a timeout */
|
/* if no event happened, there was a timeout */
|
||||||
} else return io_strerror(IO_TIMEOUT);
|
} else if (err == 0) return io_strerror(IO_TIMEOUT);
|
||||||
}
|
}
|
||||||
return io_strerror(IO_TIMEOUT); /* can't get here */
|
return sock_strerror();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Binds or returns error message
|
* Binds or returns error message
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
const char *sock_bind(p_sock ps, SA *addr, socklen_t addr_len)
|
const char *sock_bind(p_sock ps, SA *addr, socklen_t addr_len) {
|
||||||
{
|
|
||||||
const char *err = NULL;
|
const char *err = NULL;
|
||||||
sock_setblocking(ps);
|
sock_setblocking(ps);
|
||||||
if (bind(*ps, addr, addr_len) < 0) err = sock_bindstrerror(errno);
|
if (bind(*ps, addr, addr_len) < 0) err = sock_strerror();
|
||||||
sock_setnonblocking(ps);
|
sock_setnonblocking(ps);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
@ -138,12 +131,10 @@ const char *sock_bind(p_sock ps, SA *addr, socklen_t addr_len)
|
|||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
*
|
*
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
const char* sock_listen(p_sock ps, int backlog)
|
const char* sock_listen(p_sock ps, int backlog) {
|
||||||
{
|
|
||||||
const char *err = NULL;
|
const char *err = NULL;
|
||||||
sock_setblocking(ps);
|
sock_setblocking(ps);
|
||||||
if (listen(*ps, backlog))
|
if (listen(*ps, backlog)) err = sock_strerror();
|
||||||
err = sock_listenstrerror(errno);
|
|
||||||
sock_setnonblocking(ps);
|
sock_setnonblocking(ps);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
@ -151,8 +142,7 @@ const char* sock_listen(p_sock ps, int backlog)
|
|||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
*
|
*
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
void sock_shutdown(p_sock ps, int how)
|
void sock_shutdown(p_sock ps, int how) {
|
||||||
{
|
|
||||||
sock_setblocking(ps);
|
sock_setblocking(ps);
|
||||||
shutdown(*ps, how);
|
shutdown(*ps, how);
|
||||||
sock_setnonblocking(ps);
|
sock_setnonblocking(ps);
|
||||||
@ -162,8 +152,7 @@ void sock_shutdown(p_sock ps, int how)
|
|||||||
* Accept with timeout
|
* Accept with timeout
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
const char *sock_accept(p_sock ps, p_sock pa, SA *addr,
|
const char *sock_accept(p_sock ps, p_sock pa, SA *addr,
|
||||||
socklen_t *addr_len, p_tm tm)
|
socklen_t *addr_len, p_tm tm) {
|
||||||
{
|
|
||||||
t_sock sock = *ps;
|
t_sock sock = *ps;
|
||||||
SA dummy_addr;
|
SA dummy_addr;
|
||||||
socklen_t dummy_len = sizeof(dummy_addr);
|
socklen_t dummy_len = sizeof(dummy_addr);
|
||||||
@ -179,14 +168,16 @@ const char *sock_accept(p_sock ps, p_sock pa, SA *addr,
|
|||||||
/* if result is valid, we are done */
|
/* if result is valid, we are done */
|
||||||
if (*pa != SOCK_INVALID) return NULL;
|
if (*pa != SOCK_INVALID) return NULL;
|
||||||
/* find out if we failed for a fatal reason */
|
/* find out if we failed for a fatal reason */
|
||||||
if (errno != EAGAIN && errno != ECONNABORTED)
|
/* if connection was aborted, we can try again if we have time */
|
||||||
return sock_acceptstrerror(errno);
|
if (errno != EAGAIN && errno != ECONNABORTED) return sock_strerror();
|
||||||
|
/* optimize for timeout = 0 case */
|
||||||
|
if (tm_get(tm) == 0.0) return io_strerror(IO_TIMEOUT);
|
||||||
/* call select to avoid busy-wait. */
|
/* call select to avoid busy-wait. */
|
||||||
FD_ZERO(&fds);
|
FD_ZERO(&fds);
|
||||||
FD_SET(sock, &fds);
|
FD_SET(sock, &fds);
|
||||||
do err = sock_select(sock+1, &fds, NULL, NULL, tm_getretry(tm));
|
err = sock_select(sock+1, &fds, NULL, NULL, tm);
|
||||||
while (err < 0 && errno == EINTR);
|
|
||||||
if (err == 0) return io_strerror(IO_TIMEOUT);
|
if (err == 0) return io_strerror(IO_TIMEOUT);
|
||||||
|
else if (err < 0) return sock_strerror();
|
||||||
}
|
}
|
||||||
return io_strerror(IO_TIMEOUT); /* can't get here */
|
return io_strerror(IO_TIMEOUT); /* can't get here */
|
||||||
}
|
}
|
||||||
@ -194,39 +185,40 @@ const char *sock_accept(p_sock ps, p_sock pa, SA *addr,
|
|||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Send with timeout
|
* Send with timeout
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
int sock_send(p_sock ps, const char *data, size_t count, size_t *sent,
|
int sock_send(p_sock ps, const char *data, size_t count, size_t *sent, p_tm tm)
|
||||||
int timeout)
|
|
||||||
{
|
{
|
||||||
t_sock sock = *ps;
|
t_sock sock = *ps;
|
||||||
ssize_t put;
|
|
||||||
/* avoid making system calls on closed sockets */
|
/* avoid making system calls on closed sockets */
|
||||||
if (sock == SOCK_INVALID) return IO_CLOSED;
|
if (sock == SOCK_INVALID) return IO_CLOSED;
|
||||||
|
/* loop until we send something or we give up on error */
|
||||||
|
for ( ;; ) {
|
||||||
|
int ret;
|
||||||
|
fd_set fds;
|
||||||
|
ssize_t put;
|
||||||
/* make sure we repeat in case the call was interrupted */
|
/* make sure we repeat in case the call was interrupted */
|
||||||
do put = send(sock, data, count, 0);
|
do put = send(sock, data, count, 0);
|
||||||
while (put < 0 && errno == EINTR);
|
while (put < 0 && errno == EINTR);
|
||||||
|
/* if we sent something, get out */
|
||||||
|
if (put > 0) {
|
||||||
|
*sent = put;
|
||||||
|
return IO_DONE;
|
||||||
|
}
|
||||||
/* deal with failure */
|
/* deal with failure */
|
||||||
if (put <= 0) {
|
|
||||||
int ret;
|
|
||||||
fd_set fds;
|
|
||||||
/* in any case, nothing has been sent */
|
|
||||||
*sent = 0;
|
*sent = 0;
|
||||||
/* only proceed to select if no error happened */
|
|
||||||
if (errno != EAGAIN) return IO_ERROR;
|
|
||||||
/* optimize for the timeout = 0 case */
|
|
||||||
if (timeout == 0) return IO_TIMEOUT;
|
|
||||||
/* here we know the connection has been closed */
|
/* here we know the connection has been closed */
|
||||||
if (errno == EPIPE) return IO_CLOSED;
|
if (put < 0 && errno == EPIPE) return IO_CLOSED;
|
||||||
|
/* send shouldn't return zero and we can only proceed if
|
||||||
|
* there was no serious error */
|
||||||
|
if (put == 0 || errno != EAGAIN) return IO_USER;
|
||||||
|
/* optimize for the timeout = 0 case */
|
||||||
|
if (tm_get(tm) == 0.0) return IO_TIMEOUT;
|
||||||
/* run select to avoid busy wait */
|
/* run select to avoid busy wait */
|
||||||
FD_ZERO(&fds);
|
FD_ZERO(&fds);
|
||||||
FD_SET(sock, &fds);
|
FD_SET(sock, &fds);
|
||||||
ret = sock_select(sock+1, NULL, &fds, NULL, timeout);
|
ret = sock_select(sock+1, NULL, &fds, NULL, tm);
|
||||||
if (ret == 0) return IO_TIMEOUT;
|
if (ret == 0) return IO_TIMEOUT;
|
||||||
else if (ret > 0 || errno == EINTR) return IO_RETRY;
|
if (ret < 0) return IO_USER;
|
||||||
else return IO_ERROR;
|
/* otherwise, try sending again */
|
||||||
/* here we successfully sent something */
|
|
||||||
} else {
|
|
||||||
*sent = put;
|
|
||||||
return IO_DONE;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -234,96 +226,95 @@ int sock_send(p_sock ps, const char *data, size_t count, size_t *sent,
|
|||||||
* Sendto with timeout
|
* Sendto with timeout
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
int sock_sendto(p_sock ps, const char *data, size_t count, size_t *sent,
|
int sock_sendto(p_sock ps, const char *data, size_t count, size_t *sent,
|
||||||
SA *addr, socklen_t addr_len, int timeout)
|
SA *addr, socklen_t addr_len, p_tm tm)
|
||||||
{
|
{
|
||||||
t_sock sock = *ps;
|
t_sock sock = *ps;
|
||||||
ssize_t put;
|
/* avoid making system calls on closed sockets */
|
||||||
if (sock == SOCK_INVALID) return IO_CLOSED;
|
if (sock == SOCK_INVALID) return IO_CLOSED;
|
||||||
do put = sendto(sock, data, count, 0, addr, addr_len);
|
/* loop until we send something or we give up on error */
|
||||||
while (put < 0 && errno == EINTR);
|
for ( ;; ) {
|
||||||
if (put <= 0) {
|
|
||||||
int ret;
|
int ret;
|
||||||
fd_set fds;
|
fd_set fds;
|
||||||
*sent = 0;
|
ssize_t put;
|
||||||
if (errno != EAGAIN) return IO_ERROR;
|
do put = sendto(sock, data, count, 0, addr, addr_len);
|
||||||
if (timeout == 0) return IO_TIMEOUT;
|
while (put < 0 && errno == EINTR);
|
||||||
if (errno == EPIPE) return IO_CLOSED;
|
if (put > 0) {
|
||||||
FD_ZERO(&fds);
|
|
||||||
FD_SET(sock, &fds);
|
|
||||||
ret = sock_select(sock+1, NULL, &fds, NULL, timeout);
|
|
||||||
if (ret == 0) return IO_TIMEOUT;
|
|
||||||
else if (ret > 0 || errno == EINTR) return IO_RETRY;
|
|
||||||
else return IO_ERROR;
|
|
||||||
} else {
|
|
||||||
*sent = put;
|
*sent = put;
|
||||||
return IO_DONE;
|
return IO_DONE;
|
||||||
}
|
}
|
||||||
|
*sent = 0;
|
||||||
|
if (put < 0 && errno == EPIPE) return IO_CLOSED;
|
||||||
|
if (put == 0 || errno != EAGAIN) return IO_USER;
|
||||||
|
if (tm_get(tm) == 0.0) return IO_TIMEOUT;
|
||||||
|
FD_ZERO(&fds);
|
||||||
|
FD_SET(sock, &fds);
|
||||||
|
ret = sock_select(sock+1, NULL, &fds, NULL, tm);
|
||||||
|
if (ret == 0) return IO_TIMEOUT;
|
||||||
|
if (ret < 0) return IO_USER;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Receive with timeout
|
* Receive with timeout
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
int sock_recv(p_sock ps, char *data, size_t count, size_t *got, int timeout)
|
int sock_recv(p_sock ps, char *data, size_t count, size_t *got, p_tm tm) {
|
||||||
{
|
|
||||||
t_sock sock = *ps;
|
t_sock sock = *ps;
|
||||||
ssize_t taken;
|
|
||||||
if (sock == SOCK_INVALID) return IO_CLOSED;
|
if (sock == SOCK_INVALID) return IO_CLOSED;
|
||||||
do taken = read(sock, data, count);
|
for ( ;; ) {
|
||||||
while (taken < 0 && errno == EINTR);
|
|
||||||
if (taken <= 0) {
|
|
||||||
fd_set fds;
|
fd_set fds;
|
||||||
int ret;
|
int ret;
|
||||||
*got = 0;
|
ssize_t taken;
|
||||||
if (taken == 0) return IO_CLOSED;
|
do taken = read(sock, data, count);
|
||||||
if (errno != EAGAIN) return IO_ERROR;
|
while (taken < 0 && errno == EINTR);
|
||||||
if (timeout == 0) return IO_TIMEOUT;
|
if (taken > 0) {
|
||||||
FD_ZERO(&fds);
|
|
||||||
FD_SET(sock, &fds);
|
|
||||||
ret = sock_select(sock+1, &fds, NULL, NULL, timeout);
|
|
||||||
if (ret == 0) return IO_TIMEOUT;
|
|
||||||
else if (ret > 0 || errno == EINTR) return IO_RETRY;
|
|
||||||
else return IO_ERROR;
|
|
||||||
} else {
|
|
||||||
*got = taken;
|
*got = taken;
|
||||||
return IO_DONE;
|
return IO_DONE;
|
||||||
}
|
}
|
||||||
|
*got = 0;
|
||||||
|
if (taken == 0) return IO_CLOSED;
|
||||||
|
if (errno != EAGAIN) return IO_USER;
|
||||||
|
if (tm_get(tm) == 0.0) return IO_TIMEOUT;
|
||||||
|
FD_ZERO(&fds);
|
||||||
|
FD_SET(sock, &fds);
|
||||||
|
ret = sock_select(sock+1, &fds, NULL, NULL, tm);
|
||||||
|
if (ret == 0) return IO_TIMEOUT;
|
||||||
|
if (ret < 0) return IO_USER;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Recvfrom with timeout
|
* Recvfrom with timeout
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
int sock_recvfrom(p_sock ps, char *data, size_t count, size_t *got,
|
int sock_recvfrom(p_sock ps, char *data, size_t count, size_t *got,
|
||||||
SA *addr, socklen_t *addr_len, int timeout)
|
SA *addr, socklen_t *addr_len, p_tm tm) {
|
||||||
{
|
|
||||||
t_sock sock = *ps;
|
t_sock sock = *ps;
|
||||||
ssize_t taken;
|
|
||||||
if (sock == SOCK_INVALID) return IO_CLOSED;
|
if (sock == SOCK_INVALID) return IO_CLOSED;
|
||||||
do taken = recvfrom(sock, data, count, 0, addr, addr_len);
|
for ( ;; ) {
|
||||||
while (taken < 0 && errno == EINTR);
|
|
||||||
if (taken <= 0) {
|
|
||||||
fd_set fds;
|
fd_set fds;
|
||||||
int ret;
|
int ret;
|
||||||
*got = 0;
|
ssize_t taken;
|
||||||
if (taken == 0) return IO_CLOSED;
|
do taken = recvfrom(sock, data, count, 0, addr, addr_len);
|
||||||
if (errno != EAGAIN) return IO_ERROR;
|
while (taken < 0 && errno == EINTR);
|
||||||
if (timeout == 0) return IO_TIMEOUT;
|
if (taken > 0) {
|
||||||
FD_ZERO(&fds);
|
|
||||||
FD_SET(sock, &fds);
|
|
||||||
ret = sock_select(sock+1, &fds, NULL, NULL, timeout);
|
|
||||||
if (ret == 0) return IO_TIMEOUT;
|
|
||||||
else if (ret > 0 || errno == EINTR) return IO_RETRY;
|
|
||||||
else return IO_ERROR;
|
|
||||||
} else {
|
|
||||||
*got = taken;
|
*got = taken;
|
||||||
return IO_DONE;
|
return IO_DONE;
|
||||||
}
|
}
|
||||||
|
*got = 0;
|
||||||
|
if (taken == 0) return IO_CLOSED;
|
||||||
|
if (errno != EAGAIN) return IO_USER;
|
||||||
|
if (tm_get(tm) == 0.0) return IO_TIMEOUT;
|
||||||
|
FD_ZERO(&fds);
|
||||||
|
FD_SET(sock, &fds);
|
||||||
|
ret = sock_select(sock+1, &fds, NULL, NULL, tm);
|
||||||
|
if (ret == 0) return IO_TIMEOUT;
|
||||||
|
if (ret < 0) return IO_USER;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Put socket into blocking mode
|
* Put socket into blocking mode
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
void sock_setblocking(p_sock ps)
|
void sock_setblocking(p_sock ps) {
|
||||||
{
|
|
||||||
int flags = fcntl(*ps, F_GETFL, 0);
|
int flags = fcntl(*ps, F_GETFL, 0);
|
||||||
flags &= (~(O_NONBLOCK));
|
flags &= (~(O_NONBLOCK));
|
||||||
fcntl(*ps, F_SETFL, flags);
|
fcntl(*ps, F_SETFL, flags);
|
||||||
@ -332,8 +323,7 @@ void sock_setblocking(p_sock ps)
|
|||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Put socket into non-blocking mode
|
* Put socket into non-blocking mode
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
void sock_setnonblocking(p_sock ps)
|
void sock_setnonblocking(p_sock ps) {
|
||||||
{
|
|
||||||
int flags = fcntl(*ps, F_GETFL, 0);
|
int flags = fcntl(*ps, F_GETFL, 0);
|
||||||
flags |= O_NONBLOCK;
|
flags |= O_NONBLOCK;
|
||||||
fcntl(*ps, F_SETFL, flags);
|
fcntl(*ps, F_SETFL, flags);
|
||||||
@ -342,98 +332,20 @@ void sock_setnonblocking(p_sock ps)
|
|||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Error translation functions
|
* Error translation functions
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
/* return error messages for the known errors reported by gethostbyname */
|
const char *sock_hoststrerror(void) {
|
||||||
const char *sock_hoststrerror(void)
|
return hstrerror(h_errno);
|
||||||
{
|
}
|
||||||
switch (h_errno) {
|
|
||||||
case HOST_NOT_FOUND: return "host not found";
|
/* make sure important error messages are standard */
|
||||||
case NO_ADDRESS: return "valid host but no ip found";
|
const char *sock_strerror(void) {
|
||||||
case NO_RECOVERY: return "name server error";
|
switch (errno) {
|
||||||
case TRY_AGAIN: return "name server unavailable, try again later";
|
case EADDRINUSE:
|
||||||
default: return "unknown error";
|
return "address already in use";
|
||||||
|
default:
|
||||||
|
return strerror(errno);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* return error messages for the known errors reported by socket */
|
const char *sock_geterr(p_sock ps, int code) {
|
||||||
static const char *sock_createstrerror(int err)
|
return sock_strerror();
|
||||||
{
|
|
||||||
switch (err) {
|
|
||||||
case EPROTONOSUPPORT: return "protocol not supported";
|
|
||||||
case EACCES: return "access denied";
|
|
||||||
case EMFILE: return "process file table is full";
|
|
||||||
case ENFILE: return "kernel file table is full";
|
|
||||||
case EINVAL: return "unknown protocol or family";
|
|
||||||
case ENOBUFS: return "insuffucient buffer space";
|
|
||||||
default: return "unknown error";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* return error messages for the known errors reported by accept */
|
|
||||||
static const char *sock_acceptstrerror(int err)
|
|
||||||
{
|
|
||||||
switch (err) {
|
|
||||||
case EAGAIN: return io_strerror(IO_RETRY);
|
|
||||||
case EBADF: return "invalid descriptor";
|
|
||||||
case ENOBUFS: case ENOMEM: return "insuffucient buffer space";
|
|
||||||
case ENOTSOCK: return "descriptor not a socket";
|
|
||||||
case EOPNOTSUPP: return "not supported";
|
|
||||||
case EINTR: return "call interrupted";
|
|
||||||
case ECONNABORTED: return "connection aborted";
|
|
||||||
case EINVAL: return "not listening";
|
|
||||||
case EMFILE: return "process file table is full";
|
|
||||||
case ENFILE: return "kernel file table is full";
|
|
||||||
case EFAULT: return "invalid memory address";
|
|
||||||
default: return "unknown error";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* return error messages for the known errors reported by bind */
|
|
||||||
static const char *sock_bindstrerror(int err)
|
|
||||||
{
|
|
||||||
switch (err) {
|
|
||||||
case EBADF: return "invalid descriptor";
|
|
||||||
case ENOTSOCK: return "descriptor not a socket";
|
|
||||||
case EADDRNOTAVAIL: return "address unavailable in local host";
|
|
||||||
case EADDRINUSE: return "address already in use";
|
|
||||||
case EINVAL: return "already bound";
|
|
||||||
case EACCES: return "access denied";
|
|
||||||
case EFAULT: return "invalid memory address";
|
|
||||||
case ENOMEM: return "out of memory";
|
|
||||||
default: return "unknown error";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* return error messages for the known errors reported by listen */
|
|
||||||
static const char *sock_listenstrerror(int err)
|
|
||||||
{
|
|
||||||
switch (err) {
|
|
||||||
case EADDRINUSE: return "local address already in use";
|
|
||||||
case EBADF: return "invalid descriptor";
|
|
||||||
case ENOTSOCK: return "descriptor not a socket";
|
|
||||||
case EOPNOTSUPP: return "not supported";
|
|
||||||
default: return "unknown error";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* return error messages for the known errors reported by connect */
|
|
||||||
static const char *sock_connectstrerror(int err)
|
|
||||||
{
|
|
||||||
switch (err) {
|
|
||||||
case EBADF: return "invalid descriptor";
|
|
||||||
case EFAULT: return "invalid memory address";
|
|
||||||
case ENOTSOCK: return "descriptor not a socket";
|
|
||||||
case EADDRNOTAVAIL: return "address not available in local host";
|
|
||||||
case EISCONN: return "already connected";
|
|
||||||
case ECONNREFUSED: return "connection refused";
|
|
||||||
case ETIMEDOUT: return io_strerror(IO_TIMEOUT);
|
|
||||||
case ENETUNREACH: return "network is unreachable";
|
|
||||||
case EADDRINUSE: return "local address already in use";
|
|
||||||
case EINPROGRESS: return "would block";
|
|
||||||
case EALREADY: return "connect already in progress";
|
|
||||||
case EAGAIN: return "not enough free ports";
|
|
||||||
case EAFNOSUPPORT: return "address family not supported";
|
|
||||||
case EPERM: return "broadcast not enabled or firewall block";
|
|
||||||
default: return "unknown error";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -16,14 +16,12 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
/* fnctnl function and associated constants */
|
/* fnctnl function and associated constants */
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
/* struct timeval and CLK_TCK */
|
|
||||||
#include <sys/time.h>
|
|
||||||
/* times function and struct tms */
|
|
||||||
#include <sys/times.h>
|
|
||||||
/* struct sockaddr */
|
/* struct sockaddr */
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
/* socket function */
|
/* socket function */
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
|
/* struct timeval */
|
||||||
|
#include <sys/time.h>
|
||||||
/* gethostbyname and gethostbyaddr functions */
|
/* gethostbyname and gethostbyaddr functions */
|
||||||
#include <netdb.h>
|
#include <netdb.h>
|
||||||
/* sigpipe handling */
|
/* sigpipe handling */
|
||||||
|
@ -228,6 +228,7 @@ function test_totaltimeoutsend(len, tm, sl)
|
|||||||
data:settimeout(tm, "total")
|
data:settimeout(tm, "total")
|
||||||
str = string.rep("a", 2*len)
|
str = string.rep("a", 2*len)
|
||||||
total, err, partial, elapsed = data:send(str)
|
total, err, partial, elapsed = data:send(str)
|
||||||
|
print(elapsed, "!")
|
||||||
check_timeout(tm, sl, elapsed, err, "send", "total",
|
check_timeout(tm, sl, elapsed, err, "send", "total",
|
||||||
total == 2*len)
|
total == 2*len)
|
||||||
end
|
end
|
||||||
@ -400,27 +401,27 @@ function accept_errors()
|
|||||||
d:setfd(c:getfd())
|
d:setfd(c:getfd())
|
||||||
d:settimeout(2)
|
d:settimeout(2)
|
||||||
local r, e = d:accept()
|
local r, e = d:accept()
|
||||||
assert(not r and e == "not listening", e)
|
assert(not r and e)
|
||||||
print("ok")
|
print("ok: ", e)
|
||||||
io.stderr:write("not supported: ")
|
io.stderr:write("not supported: ")
|
||||||
local c, e = socket.udp()
|
local c, e = socket.udp()
|
||||||
assert(c, e);
|
assert(c, e);
|
||||||
d:setfd(c:getfd())
|
d:setfd(c:getfd())
|
||||||
local r, e = d:accept()
|
local r, e = d:accept()
|
||||||
assert(not r and e == "not supported" or e == "not listening", e)
|
assert(not r and e)
|
||||||
print("ok")
|
print("ok: ", e)
|
||||||
end
|
end
|
||||||
|
|
||||||
------------------------------------------------------------------------
|
------------------------------------------------------------------------
|
||||||
function connect_errors()
|
function connect_errors()
|
||||||
io.stderr:write("connection refused: ")
|
io.stderr:write("connection refused: ")
|
||||||
local c, e = socket.connect("localhost", 1);
|
local c, e = socket.connect("localhost", 1);
|
||||||
assert(not c and e == "connection refused", e)
|
assert(not c and e)
|
||||||
print("ok")
|
print("ok: ", e)
|
||||||
io.stderr:write("host not found: ")
|
io.stderr:write("host not found: ")
|
||||||
local c, e = socket.connect("host.is.invalid", 1);
|
local c, e = socket.connect("host.is.invalid", 1);
|
||||||
assert(not c and e == "host not found", e)
|
assert(not c and e, e)
|
||||||
print("ok")
|
print("ok: ", e)
|
||||||
end
|
end
|
||||||
|
|
||||||
------------------------------------------------------------------------
|
------------------------------------------------------------------------
|
||||||
@ -432,36 +433,25 @@ function rebind_test()
|
|||||||
s:setoption("reuseaddr", false)
|
s:setoption("reuseaddr", false)
|
||||||
r, e = s:bind("localhost", p)
|
r, e = s:bind("localhost", p)
|
||||||
assert(not r, "managed to rebind!")
|
assert(not r, "managed to rebind!")
|
||||||
assert(e == "address already in use")
|
assert(e)
|
||||||
print("ok")
|
print("ok: ", e)
|
||||||
end
|
end
|
||||||
|
|
||||||
------------------------------------------------------------------------
|
------------------------------------------------------------------------
|
||||||
|
|
||||||
test("character line")
|
|
||||||
test_asciiline(1)
|
|
||||||
test_asciiline(17)
|
|
||||||
test_asciiline(200)
|
|
||||||
test_asciiline(4091)
|
|
||||||
test_asciiline(80199)
|
|
||||||
test_asciiline(8000000)
|
|
||||||
test_asciiline(80199)
|
|
||||||
test_asciiline(4091)
|
|
||||||
test_asciiline(200)
|
|
||||||
test_asciiline(17)
|
|
||||||
test_asciiline(1)
|
|
||||||
|
|
||||||
test("method registration")
|
test("method registration")
|
||||||
test_methods(socket.tcp(), {
|
test_methods(socket.tcp(), {
|
||||||
"accept",
|
"accept",
|
||||||
"bind",
|
"bind",
|
||||||
"close",
|
"close",
|
||||||
"connect",
|
"connect",
|
||||||
|
"dirty",
|
||||||
|
"getfd",
|
||||||
"getpeername",
|
"getpeername",
|
||||||
"getsockname",
|
"getsockname",
|
||||||
"listen",
|
"listen",
|
||||||
"receive",
|
"receive",
|
||||||
"send",
|
"send",
|
||||||
|
"setfd",
|
||||||
"setoption",
|
"setoption",
|
||||||
"setpeername",
|
"setpeername",
|
||||||
"setsockname",
|
"setsockname",
|
||||||
@ -472,15 +462,19 @@ test_methods(socket.tcp(), {
|
|||||||
test_methods(socket.udp(), {
|
test_methods(socket.udp(), {
|
||||||
"close",
|
"close",
|
||||||
"getpeername",
|
"getpeername",
|
||||||
|
"dirty",
|
||||||
|
"getfd",
|
||||||
|
"getpeername",
|
||||||
"getsockname",
|
"getsockname",
|
||||||
"receive",
|
"receive",
|
||||||
"receivefrom",
|
"receivefrom",
|
||||||
"send",
|
"send",
|
||||||
"sendto",
|
"sendto",
|
||||||
|
"setfd",
|
||||||
"setoption",
|
"setoption",
|
||||||
"setpeername",
|
"setpeername",
|
||||||
"setsockname",
|
"setsockname",
|
||||||
"settimeout",
|
"settimeout"
|
||||||
})
|
})
|
||||||
|
|
||||||
test("select function")
|
test("select function")
|
||||||
@ -504,7 +498,18 @@ test("accept function: ")
|
|||||||
accept_timeout()
|
accept_timeout()
|
||||||
accept_errors()
|
accept_errors()
|
||||||
|
|
||||||
|
test("character line")
|
||||||
|
test_asciiline(1)
|
||||||
|
test_asciiline(17)
|
||||||
|
test_asciiline(200)
|
||||||
|
test_asciiline(4091)
|
||||||
|
test_asciiline(80199)
|
||||||
|
test_asciiline(8000000)
|
||||||
|
test_asciiline(80199)
|
||||||
|
test_asciiline(4091)
|
||||||
|
test_asciiline(200)
|
||||||
|
test_asciiline(17)
|
||||||
|
test_asciiline(1)
|
||||||
|
|
||||||
test("mixed patterns")
|
test("mixed patterns")
|
||||||
test_mixed(1)
|
test_mixed(1)
|
||||||
@ -566,9 +571,10 @@ test_raw(1)
|
|||||||
test("total timeout on send")
|
test("total timeout on send")
|
||||||
test_totaltimeoutsend(800091, 1, 3)
|
test_totaltimeoutsend(800091, 1, 3)
|
||||||
test_totaltimeoutsend(800091, 2, 3)
|
test_totaltimeoutsend(800091, 2, 3)
|
||||||
test_totaltimeoutsend(800091, 3, 2)
|
test_totaltimeoutsend(800091, 5, 2)
|
||||||
test_totaltimeoutsend(800091, 3, 1)
|
test_totaltimeoutsend(800091, 3, 1)
|
||||||
|
|
||||||
|
|
||||||
test("total timeout on receive")
|
test("total timeout on receive")
|
||||||
test_totaltimeoutreceive(800091, 1, 3)
|
test_totaltimeoutreceive(800091, 1, 3)
|
||||||
test_totaltimeoutreceive(800091, 2, 3)
|
test_totaltimeoutreceive(800091, 2, 3)
|
||||||
|
Loading…
Reference in New Issue
Block a user