mirror of
https://github.com/lunarmodules/luasocket.git
synced 2024-12-25 12:08: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
|
||||
smtp sends quit on exceptions
|
||||
accept/connect interrupt safe
|
||||
smtp/ftp/http fail gracefully
|
||||
accept/connect/select interrupt safe
|
||||
accepted sockets are nonblocking
|
||||
new timming functions. better sleep/gettime
|
||||
new timming functions. higher resolution, no wrap around
|
||||
bug fixes in the manual
|
||||
getfd missing cast
|
||||
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
|
||||
if ((err > 1 || !FD_ISSET(sock, &wfds)) &&
|
||||
recv(sock, &dummy, 0, 0) < 0 && errno != EWOULDBLOCK) ...
|
||||
sent, received, age = sock:getstats()
|
||||
|
||||
take a look at DB's smtp patch
|
||||
|
||||
sort out the wrap around of gettime...
|
||||
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 last = 0
|
||||
local con = socket.try(socket.udp())
|
||||
local try = socket.newtry(function() con:close() end)
|
||||
-- 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)
|
||||
-- first packet gives data host/port to be used for data transfers
|
||||
retries = 0
|
||||
repeat
|
||||
sent = socket.try(con:sendto(RRQ(gett.path, "octet"),
|
||||
sent = try(con:sendto(RRQ(gett.path, "octet"),
|
||||
gett.host, gett.port))
|
||||
dgram, datahost, dataport = con:receivefrom()
|
||||
retries = retries + 1
|
||||
until dgram or datahost ~= "timeout" or retries > 5
|
||||
socket.try(dgram, datahost)
|
||||
try(dgram, datahost)
|
||||
-- associate socket with data host/port
|
||||
socket.try(con:setpeername(datahost, dataport))
|
||||
try(con:setpeername(datahost, dataport))
|
||||
-- default sink
|
||||
local sink = gett.sink or ltn12.sink.null()
|
||||
-- process all data packets
|
||||
while 1 do
|
||||
-- decode packet
|
||||
code = get_OP(dgram)
|
||||
socket.try(code ~= OP_ERROR, get_ERROR(dgram))
|
||||
socket.try(code == OP_DATA, "unhandled opcode " .. code)
|
||||
try(code ~= OP_ERROR, get_ERROR(dgram))
|
||||
try(code == OP_DATA, "unhandled opcode " .. code)
|
||||
-- get data packet parts
|
||||
local block, data = split_DATA(dgram)
|
||||
-- if not repeated, write
|
||||
if block == last+1 then
|
||||
socket.try(sink(data))
|
||||
try(sink(data))
|
||||
last = block
|
||||
end
|
||||
-- last packet brings less than 512 bytes of data
|
||||
if string.len(data) < 512 then
|
||||
socket.try(con:send(ACK(block)))
|
||||
socket.try(con:close())
|
||||
socket.try(sink(nil))
|
||||
try(con:send(ACK(block)))
|
||||
try(con:close())
|
||||
try(sink(nil))
|
||||
return 1
|
||||
end
|
||||
-- get the next packet
|
||||
retries = 0
|
||||
repeat
|
||||
sent = socket.try(con:send(ACK(last)))
|
||||
sent = try(con:send(ACK(last)))
|
||||
dgram, err = con:receive()
|
||||
retries = retries + 1
|
||||
until dgram or err ~= "timeout" or retries > 5
|
||||
socket.try(dgram, err)
|
||||
try(dgram, err)
|
||||
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
|
68
src/buffer.c
68
src/buffer.c
@ -33,8 +33,7 @@ static int sendraw(p_buf buf, const char *data, size_t count, size_t *sent);
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Initializes module
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int buf_open(lua_State *L)
|
||||
{
|
||||
int buf_open(lua_State *L) {
|
||||
(void) L;
|
||||
return 0;
|
||||
}
|
||||
@ -42,8 +41,7 @@ int buf_open(lua_State *L)
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* 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->io = io;
|
||||
buf->tm = tm;
|
||||
@ -52,13 +50,11 @@ void buf_init(p_buf buf, p_io io, p_tm tm)
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* 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);
|
||||
size_t total = 0;
|
||||
int arg, err = IO_DONE;
|
||||
p_tm tm = buf->tm;
|
||||
tm_markstart(tm);
|
||||
p_tm tm = tm_markstart(buf->tm);
|
||||
for (arg = 2; arg <= top; arg++) { /* first arg is socket object */
|
||||
size_t sent, 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 */
|
||||
if (err != IO_DONE) {
|
||||
lua_pushnil(L);
|
||||
io_pusherror(L, err);
|
||||
io_pusherror(L, buf->io, err);
|
||||
lua_pushnumber(L, total);
|
||||
} else {
|
||||
lua_pushnumber(L, total);
|
||||
@ -78,7 +74,7 @@ int buf_meth_send(lua_State *L, p_buf buf)
|
||||
}
|
||||
#ifdef LUASOCKET_DEBUG
|
||||
/* 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
|
||||
return lua_gettop(L) - top;
|
||||
}
|
||||
@ -86,13 +82,11 @@ int buf_meth_send(lua_State *L, p_buf buf)
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* 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);
|
||||
p_tm tm = buf->tm;
|
||||
p_tm tm = tm_markstart(buf->tm);
|
||||
luaL_Buffer b;
|
||||
luaL_buffinit(L, &b);
|
||||
tm_markstart(tm);
|
||||
/* receive all patterns */
|
||||
if (!lua_isnumber(L, 2)) {
|
||||
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 */
|
||||
if (err != IO_DONE) {
|
||||
luaL_pushresult(&b);
|
||||
io_pusherror(L, err);
|
||||
io_pusherror(L, buf->io, err);
|
||||
lua_pushvalue(L, -2);
|
||||
lua_pushnil(L);
|
||||
lua_replace(L, -4);
|
||||
@ -118,7 +112,7 @@ int buf_meth_receive(lua_State *L, p_buf buf)
|
||||
}
|
||||
#ifdef LUASOCKET_DEBUG
|
||||
/* 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
|
||||
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
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int buf_isempty(p_buf buf)
|
||||
{
|
||||
int buf_isempty(p_buf buf) {
|
||||
return buf->first >= buf->last;
|
||||
}
|
||||
|
||||
@ -137,16 +130,14 @@ int buf_isempty(p_buf buf)
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Sends a block of data (unbuffered)
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static
|
||||
int sendraw(p_buf buf, const char *data, size_t count, size_t *sent)
|
||||
{
|
||||
static int sendraw(p_buf buf, const char *data, size_t count, size_t *sent) {
|
||||
p_io io = buf->io;
|
||||
p_tm tm = buf->tm;
|
||||
size_t total = 0;
|
||||
int err = IO_DONE;
|
||||
while (total < count && (err == IO_DONE || err == IO_RETRY)) {
|
||||
while (total < count && err == IO_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;
|
||||
}
|
||||
*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)
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static
|
||||
int recvraw(p_buf buf, size_t wanted, luaL_Buffer *b)
|
||||
{
|
||||
int err = IO_DONE;
|
||||
static int recvraw(p_buf buf, size_t wanted, luaL_Buffer *b) {
|
||||
int err = IO_DONE;
|
||||
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;
|
||||
err = buf_get(buf, &data, &count);
|
||||
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)
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static
|
||||
int recvall(p_buf buf, luaL_Buffer *b)
|
||||
{
|
||||
static int recvall(p_buf buf, luaL_Buffer *b) {
|
||||
int err = IO_DONE;
|
||||
while (err == IO_DONE || err == IO_RETRY) {
|
||||
while (err == IO_DONE) {
|
||||
const char *data; size_t count;
|
||||
err = buf_get(buf, &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
|
||||
* are not returned by the function and are discarded from the buffer
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static
|
||||
int recvline(p_buf buf, luaL_Buffer *b)
|
||||
{
|
||||
static int recvline(p_buf buf, luaL_Buffer *b) {
|
||||
int err = IO_DONE;
|
||||
while (err == IO_DONE || err == IO_RETRY) {
|
||||
while (err == IO_DONE) {
|
||||
size_t count, pos; const char *data;
|
||||
err = buf_get(buf, &data, &count);
|
||||
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
|
||||
* transport layer
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static
|
||||
void buf_skip(p_buf buf, size_t count)
|
||||
{
|
||||
static void buf_skip(p_buf buf, size_t count) {
|
||||
buf->first += count;
|
||||
if (buf_isempty(buf))
|
||||
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
|
||||
* if buffer is empty
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static
|
||||
int buf_get(p_buf buf, const char **data, size_t *count)
|
||||
{
|
||||
static int buf_get(p_buf buf, const char **data, size_t *count) {
|
||||
int err = IO_DONE;
|
||||
p_io io = buf->io;
|
||||
p_tm tm = buf->tm;
|
||||
if (buf_isempty(buf)) {
|
||||
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->last = got;
|
||||
}
|
||||
@ -247,4 +228,3 @@ int buf_get(p_buf buf, const char **data, size_t *count)
|
||||
*data = buf->data + buf->first;
|
||||
return err;
|
||||
}
|
||||
|
||||
|
20
src/io.c
20
src/io.c
@ -12,34 +12,34 @@
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* 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->recv = recv;
|
||||
io->geterr = geterr;
|
||||
io->ctx = ctx;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Translate error codes to Lua
|
||||
\*-------------------------------------------------------------------------*/
|
||||
const char *io_strerror(int code)
|
||||
{
|
||||
const char *io_strerror(int code) {
|
||||
switch (code) {
|
||||
case IO_DONE: return NULL;
|
||||
case IO_TIMEOUT: return "timeout";
|
||||
case IO_RETRY: return "retry";
|
||||
case IO_CLOSED: return "closed";
|
||||
case IO_REFUSED: return "refused";
|
||||
case IO_TIMEOUT: return "timeout";
|
||||
case IO_CLIPPED: return "clipped";
|
||||
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);
|
||||
else lua_pushnil(L);
|
||||
}
|
||||
|
22
src/io.h
22
src/io.h
@ -17,14 +17,15 @@
|
||||
#include <stdio.h>
|
||||
#include <lua.h>
|
||||
|
||||
#include "timeout.h"
|
||||
|
||||
/* IO error codes */
|
||||
enum {
|
||||
IO_DONE, /* operation completed successfully */
|
||||
IO_RETRY, /* please try again */
|
||||
IO_TIMEOUT, /* operation timed out */
|
||||
IO_CLOSED, /* the connection has been closed */
|
||||
IO_REFUSED, /* transfer has been refused */
|
||||
IO_ERROR /* something else wrong... */
|
||||
IO_CLIPPED, /* maxium bytes count reached */
|
||||
IO_USER /* last element in enum is user custom error */
|
||||
};
|
||||
|
||||
/* interface to send function */
|
||||
@ -33,7 +34,13 @@ typedef int (*p_send) (
|
||||
const char *data, /* pointer to buffer with data to send */
|
||||
size_t count, /* number of bytes to send from buffer */
|
||||
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 */
|
||||
@ -42,7 +49,7 @@ typedef int (*p_recv) (
|
||||
char *data, /* pointer to buffer where data will be writen */
|
||||
size_t count, /* number of bytes to receive into buffer */
|
||||
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 */
|
||||
@ -50,11 +57,12 @@ typedef struct t_io_ {
|
||||
void *ctx; /* context needed by send/recv */
|
||||
p_send send; /* send function pointer */
|
||||
p_recv recv; /* receive function pointer */
|
||||
p_geterr geterr; /* receive function pointer */
|
||||
} t_io;
|
||||
typedef t_io *p_io;
|
||||
|
||||
const char *io_strerror(int code);
|
||||
void io_pusherror(lua_State *L, int code);
|
||||
void io_init(p_io io, p_send send, p_recv recv, void *ctx);
|
||||
void io_pusherror(lua_State *L, p_io io, int code);
|
||||
void io_init(p_io io, p_send send, p_recv recv, p_geterr geterr, void *ctx);
|
||||
|
||||
#endif /* IO_H */
|
||||
|
11
src/select.c
11
src/select.c
@ -10,6 +10,7 @@
|
||||
#include <lauxlib.h>
|
||||
|
||||
#include "socket.h"
|
||||
#include "timeout.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.
|
||||
\*-------------------------------------------------------------------------*/
|
||||
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;
|
||||
t_tm tm;
|
||||
double t = luaL_optnumber(L, 3, -1);
|
||||
FD_ZERO(&rset); FD_ZERO(&wset);
|
||||
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); rtab = lua_gettop(L);
|
||||
lua_newtable(L); wtab = lua_gettop(L);
|
||||
max_fd = collect_fd(L, 1, -1, itab, &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);
|
||||
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)) {
|
||||
return_fd(L, &rset, max_fd+1, itab, rtab, ndirty);
|
||||
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);
|
||||
void sock_destroy(p_sock ps);
|
||||
void sock_shutdown(p_sock ps, int how);
|
||||
int sock_send(p_sock ps, const char *data, size_t count,
|
||||
size_t *sent, int timeout);
|
||||
int sock_recv(p_sock ps, char *data, size_t count,
|
||||
size_t *got, int timeout);
|
||||
int sock_send(p_sock ps, const char *data, size_t count, size_t *sent, p_tm tm);
|
||||
int sock_recv(p_sock ps, char *data, size_t count, size_t *got, p_tm tm);
|
||||
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,
|
||||
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_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_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,
|
||||
socklen_t *addr_len, p_tm tm);
|
||||
|
||||
const char *sock_geterr(p_sock ps, int code);
|
||||
const char *sock_hoststrerror(void);
|
||||
const char *sock_strerror(void);
|
||||
|
||||
#endif /* SOCK_H */
|
||||
|
@ -163,7 +163,8 @@ static int meth_accept(lua_State *L)
|
||||
/* initialize structure fields */
|
||||
sock_setnonblocking(&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);
|
||||
buf_init(&clnt->buf, &clnt->io, &clnt->tm);
|
||||
return 1;
|
||||
@ -313,7 +314,8 @@ static int global_create(lua_State *L)
|
||||
/* initialize remaining structure fields */
|
||||
sock_setnonblocking(&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);
|
||||
buf_init(&tcp->buf, &tcp->io, &tcp->tm);
|
||||
return 1;
|
||||
|
@ -46,8 +46,7 @@ static luaL_reg func[] = {
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* 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->total = total;
|
||||
}
|
||||
@ -60,18 +59,17 @@ void tm_init(p_tm tm, int block, int total)
|
||||
* Returns
|
||||
* the number of ms left or -1 if there is no time limit
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int tm_get(p_tm tm)
|
||||
{
|
||||
if (tm->block < 0 && tm->total < 0) {
|
||||
double tm_get(p_tm tm) {
|
||||
if (tm->block < 0.0 && tm->total < 0.0) {
|
||||
return -1;
|
||||
} else if (tm->block < 0) {
|
||||
int t = tm->total - tm_gettime() + tm->start;
|
||||
return MAX(t, 0);
|
||||
} else if (tm->total < 0) {
|
||||
} else if (tm->block < 0.0) {
|
||||
double t = tm->total - tm_gettime() + tm->start;
|
||||
return MAX(t, 0.0);
|
||||
} else if (tm->total < 0.0) {
|
||||
return tm->block;
|
||||
} else {
|
||||
int t = tm->total - tm_gettime() + tm->start;
|
||||
return MIN(tm->block, MAX(t, 0));
|
||||
double t = tm->total - tm_gettime() + tm->start;
|
||||
return MIN(tm->block, MAX(t, 0.0));
|
||||
}
|
||||
}
|
||||
|
||||
@ -82,8 +80,7 @@ int tm_get(p_tm tm)
|
||||
* Returns
|
||||
* start field of structure
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int tm_getstart(p_tm tm)
|
||||
{
|
||||
double tm_getstart(p_tm tm) {
|
||||
return tm->start;
|
||||
}
|
||||
|
||||
@ -95,19 +92,18 @@ int tm_getstart(p_tm tm)
|
||||
* Returns
|
||||
* the number of ms left or -1 if there is no time limit
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int tm_getretry(p_tm tm)
|
||||
{
|
||||
if (tm->block < 0 && tm->total < 0) {
|
||||
double tm_getretry(p_tm tm) {
|
||||
if (tm->block < 0.0 && tm->total < 0.0) {
|
||||
return -1;
|
||||
} else if (tm->block < 0) {
|
||||
int t = tm->total - tm_gettime() + tm->start;
|
||||
return MAX(t, 0);
|
||||
} else if (tm->total < 0) {
|
||||
int t = tm->block - tm_gettime() + tm->start;
|
||||
return MAX(t, 0);
|
||||
} else if (tm->block < 0.0) {
|
||||
double t = tm->total - tm_gettime() + tm->start;
|
||||
return MAX(t, 0.0);
|
||||
} else if (tm->total < 0.0) {
|
||||
double t = tm->block - tm_gettime() + tm->start;
|
||||
return MAX(t, 0.0);
|
||||
} else {
|
||||
int t = tm->total - tm_gettime() + tm->start;
|
||||
return MIN(tm->block, MAX(t, 0));
|
||||
double t = tm->total - tm_gettime() + tm->start;
|
||||
return MIN(tm->block, MAX(t, 0.0));
|
||||
}
|
||||
}
|
||||
|
||||
@ -116,8 +112,7 @@ int tm_getretry(p_tm tm)
|
||||
* Input
|
||||
* tm: timeout control structure
|
||||
\*-------------------------------------------------------------------------*/
|
||||
p_tm tm_markstart(p_tm tm)
|
||||
{
|
||||
p_tm tm_markstart(p_tm tm) {
|
||||
tm->start = tm_gettime();
|
||||
return tm;
|
||||
}
|
||||
@ -128,24 +123,23 @@ p_tm tm_markstart(p_tm tm)
|
||||
* time in ms.
|
||||
\*-------------------------------------------------------------------------*/
|
||||
#ifdef _WIN32
|
||||
int tm_gettime(void)
|
||||
{
|
||||
return GetTickCount();
|
||||
double tm_gettime(void) {
|
||||
FILETIME ft;
|
||||
GetSystemTimeAsFileTime(&ft);
|
||||
return ft.dwLowDateTime/1.0e7 + ft.dwHighDateTime*(4294967296.0/1.0e7);
|
||||
}
|
||||
#else
|
||||
int tm_gettime(void)
|
||||
{
|
||||
double tm_gettime(void) {
|
||||
struct timeval v;
|
||||
gettimeofday(&v, (struct timezone *) NULL);
|
||||
return v.tv_sec * 1000 + v.tv_usec/1000;
|
||||
return v.tv_sec + v.tv_usec/1.0e6;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Initializes module
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int tm_open(lua_State *L)
|
||||
{
|
||||
int tm_open(lua_State *L) {
|
||||
luaL_openlib(L, NULL, func, 0);
|
||||
return 0;
|
||||
}
|
||||
@ -156,16 +150,15 @@ int tm_open(lua_State *L)
|
||||
* time: time out value in seconds
|
||||
* mode: "b" for block timeout, "t" for total timeout. (default: b)
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int tm_meth_settimeout(lua_State *L, p_tm tm)
|
||||
{
|
||||
int ms = lua_isnil(L, 2) ? -1 : (int) (luaL_checknumber(L, 2)*1000.0);
|
||||
int tm_meth_settimeout(lua_State *L, p_tm tm) {
|
||||
double t = luaL_optnumber(L, 2, -1);
|
||||
const char *mode = luaL_optstring(L, 3, "b");
|
||||
switch (*mode) {
|
||||
case 'b':
|
||||
tm->block = ms;
|
||||
tm->block = t;
|
||||
break;
|
||||
case 'r': case 't':
|
||||
tm->total = ms;
|
||||
tm->total = t;
|
||||
break;
|
||||
default:
|
||||
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)
|
||||
{
|
||||
lua_pushnumber(L, tm_gettime()/1000.0);
|
||||
lua_pushnumber(L, tm_gettime());
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -10,19 +10,19 @@
|
||||
|
||||
/* timeout control structure */
|
||||
typedef struct t_tm_ {
|
||||
int total; /* total number of miliseconds for operation */
|
||||
int block; /* maximum time for blocking calls */
|
||||
int start; /* time of start of operation */
|
||||
double total; /* total number of miliseconds for operation */
|
||||
double block; /* maximum time for blocking calls */
|
||||
double start; /* time of start of operation */
|
||||
} t_tm;
|
||||
typedef t_tm *p_tm;
|
||||
|
||||
int tm_open(lua_State *L);
|
||||
void tm_init(p_tm tm, int block, int total);
|
||||
int tm_get(p_tm tm);
|
||||
int tm_getretry(p_tm tm);
|
||||
void tm_init(p_tm tm, double block, double total);
|
||||
double tm_get(p_tm tm);
|
||||
double tm_getretry(p_tm tm);
|
||||
p_tm tm_markstart(p_tm tm);
|
||||
int tm_getstart(p_tm tm);
|
||||
int tm_gettime(void);
|
||||
double tm_getstart(p_tm tm);
|
||||
double tm_gettime(void);
|
||||
int tm_meth_settimeout(lua_State *L, p_tm tm);
|
||||
|
||||
#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_setfd(lua_State *L);
|
||||
static int meth_dirty(lua_State *L);
|
||||
static void pusherror(lua_State *L, int code);
|
||||
|
||||
/* udp object methods */
|
||||
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},
|
||||
{"__tostring", aux_tostring},
|
||||
{"getfd", meth_getfd},
|
||||
{"setfd", meth_setfd},
|
||||
{"close", meth_close},
|
||||
{"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}
|
||||
};
|
||||
|
||||
@ -99,35 +100,43 @@ int udp_open(lua_State *L)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*=========================================================================*\
|
||||
* 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
|
||||
\*-------------------------------------------------------------------------*/
|
||||
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_tm tm = &udp->tm;
|
||||
size_t count, sent = 0;
|
||||
int err;
|
||||
const char *data = luaL_checklstring(L, 2, &count);
|
||||
tm_markstart(tm);
|
||||
do err = sock_send(&udp->sock, data, count, &sent, tm_getretry(tm));
|
||||
while (err == IO_RETRY);
|
||||
err = sock_send(&udp->sock, data, count, &sent, tm);
|
||||
if (err == IO_DONE) lua_pushnumber(L, sent);
|
||||
else lua_pushnil(L);
|
||||
/* a 'closed' error on an unconnected means the target address was not
|
||||
* accepted by the transport layer */
|
||||
io_pusherror(L, err == IO_CLOSED ? IO_REFUSED : err);
|
||||
pusherror(L, err == IO_CLOSED ? IO_USER : err);
|
||||
return 2;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* 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);
|
||||
size_t count, sent = 0;
|
||||
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_port = htons(port);
|
||||
tm_markstart(tm);
|
||||
do err = sock_sendto(&udp->sock, data, count, &sent,
|
||||
(SA *) &addr, sizeof(addr), tm_get(tm));
|
||||
while (err == IO_RETRY);
|
||||
err = sock_sendto(&udp->sock, data, count, &sent,
|
||||
(SA *) &addr, sizeof(addr), tm);
|
||||
if (err == IO_DONE) lua_pushnumber(L, sent);
|
||||
else lua_pushnil(L);
|
||||
/* a 'closed' error on an unconnected means the target address was not
|
||||
* accepted by the transport layer */
|
||||
io_pusherror(L, err == IO_CLOSED ? IO_REFUSED : err);
|
||||
pusherror(L, err == IO_CLOSED ? IO_USER : err);
|
||||
return 2;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* 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);
|
||||
char buffer[UDP_DATAGRAMSIZE];
|
||||
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;
|
||||
count = MIN(count, sizeof(buffer));
|
||||
tm_markstart(tm);
|
||||
do err = sock_recv(&udp->sock, buffer, count, &got, tm_get(tm));
|
||||
while (err == IO_RETRY);
|
||||
err = sock_recv(&udp->sock, buffer, count, &got, tm);
|
||||
if (err == IO_DONE) lua_pushlstring(L, buffer, got);
|
||||
else lua_pushnil(L);
|
||||
io_pusherror(L, err);
|
||||
pusherror(L, err);
|
||||
return 2;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* 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);
|
||||
struct sockaddr_in addr;
|
||||
socklen_t addr_len = sizeof(addr);
|
||||
@ -187,9 +192,8 @@ static int meth_receivefrom(lua_State *L)
|
||||
p_tm tm = &udp->tm;
|
||||
tm_markstart(tm);
|
||||
count = MIN(count, sizeof(buffer));
|
||||
do err = sock_recvfrom(&udp->sock, buffer, count, &got,
|
||||
(SA *) &addr, &addr_len, tm_get(tm));
|
||||
while (err == IO_RETRY);
|
||||
err = sock_recvfrom(&udp->sock, buffer, count, &got,
|
||||
(SA *) &addr, &addr_len, tm);
|
||||
if (err == IO_DONE) {
|
||||
lua_pushlstring(L, buffer, got);
|
||||
lua_pushstring(L, inet_ntoa(addr.sin_addr));
|
||||
@ -197,7 +201,7 @@ static int meth_receivefrom(lua_State *L)
|
||||
return 3;
|
||||
} else {
|
||||
lua_pushnil(L);
|
||||
io_pusherror(L, err);
|
||||
pusherror(L, err);
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
@ -205,23 +209,20 @@ static int meth_receivefrom(lua_State *L)
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* 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);
|
||||
lua_pushnumber(L, (int) udp->sock);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
udp->sock = (t_sock) luaL_checknumber(L, 2);
|
||||
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);
|
||||
(void) udp;
|
||||
lua_pushboolean(L, 0);
|
||||
@ -231,14 +232,12 @@ static int meth_dirty(lua_State *L)
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* 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);
|
||||
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);
|
||||
return inet_meth_getsockname(L, &udp->sock);
|
||||
}
|
||||
@ -246,8 +245,7 @@ static int meth_getsockname(lua_State *L)
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* 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);
|
||||
return opt_meth_setoption(L, opt, &udp->sock);
|
||||
}
|
||||
@ -255,8 +253,7 @@ static int meth_setoption(lua_State *L)
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* 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);
|
||||
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.
|
||||
\*-------------------------------------------------------------------------*/
|
||||
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_tm tm = &udp->tm;
|
||||
const char *address = luaL_checkstring(L, 2);
|
||||
@ -289,8 +285,7 @@ static int meth_setpeername(lua_State *L)
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* 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);
|
||||
sock_destroy(&udp->sock);
|
||||
return 0;
|
||||
@ -299,8 +294,7 @@ static int meth_close(lua_State *L)
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* 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);
|
||||
const char *address = luaL_checkstring(L, 2);
|
||||
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
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int global_create(lua_State *L)
|
||||
{
|
||||
static int global_create(lua_State *L) {
|
||||
t_sock sock;
|
||||
const char *err = inet_trycreate(&sock, SOCK_DGRAM);
|
||||
/* try to allocate a system socket */
|
||||
|
338
src/usocket.c
338
src/usocket.c
@ -20,17 +20,10 @@
|
||||
|
||||
#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
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int sock_open(void)
|
||||
{
|
||||
int sock_open(void) {
|
||||
#if DOESNT_COMPILE_TRY_THIS
|
||||
struct sigaction ignore;
|
||||
memset(&ignore, 0, sizeof(ignore));
|
||||
@ -45,16 +38,14 @@ int sock_open(void)
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Close module
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int sock_close(void)
|
||||
{
|
||||
int sock_close(void) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Close and inutilize socket
|
||||
\*-------------------------------------------------------------------------*/
|
||||
void sock_destroy(p_sock ps)
|
||||
{
|
||||
void sock_destroy(p_sock ps) {
|
||||
if (*ps != SOCK_INVALID) {
|
||||
sock_setblocking(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)
|
||||
{
|
||||
struct timeval tv;
|
||||
tv.tv_sec = timeout / 1000;
|
||||
tv.tv_usec = (timeout % 1000) * 1000;
|
||||
return select(n, rfds, wfds, efds, timeout >= 0? &tv: NULL);
|
||||
int sock_select(int n, fd_set *rfds, fd_set *wfds, fd_set *efds, p_tm tm) {
|
||||
int ret;
|
||||
do {
|
||||
struct timeval tv;
|
||||
double t = tm_getretry(tm);
|
||||
tv.tv_sec = (int) t;
|
||||
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
|
||||
\*-------------------------------------------------------------------------*/
|
||||
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);
|
||||
if (sock == SOCK_INVALID) return sock_createstrerror(errno);
|
||||
if (sock == SOCK_INVALID) return sock_strerror();
|
||||
*ps = sock;
|
||||
return NULL;
|
||||
}
|
||||
@ -87,50 +81,49 @@ const char *sock_create(p_sock ps, int domain, int type, int protocol)
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* 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;
|
||||
int err;
|
||||
/* don't call on closed socket */
|
||||
if (sock == SOCK_INVALID) return io_strerror(IO_CLOSED);
|
||||
if (sock == SOCK_INVALID) return io_strerror(IO_CLOSED);
|
||||
/* ask system to connect */
|
||||
do err = connect(sock, addr, addr_len);
|
||||
while (err < 0 && errno == EINTR);
|
||||
/* if no error, we're done */
|
||||
if (err == 0) return NULL;
|
||||
/* 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 */
|
||||
for ( ;; ) {
|
||||
fd_set rfds, wfds, efds;
|
||||
fd_set rfds, wfds;
|
||||
FD_ZERO(&rfds); FD_SET(sock, &rfds);
|
||||
FD_ZERO(&wfds); FD_SET(sock, &wfds);
|
||||
FD_ZERO(&efds); FD_SET(sock, &efds);
|
||||
/* we run select to avoid busy waiting */
|
||||
do err = sock_select(sock+1, &rfds, &wfds, &efds, tm_getretry(tm));
|
||||
while (err < 0 && errno == EINTR);
|
||||
/* if selects readable, try reading */
|
||||
err = sock_select(sock+1, &rfds, &wfds, NULL, tm);
|
||||
/* if there was an event, check what happened */
|
||||
if (err > 0) {
|
||||
char dummy;
|
||||
/* recv will set errno to the value a blocking connect would set */
|
||||
if (recv(sock, &dummy, 0, 0) < 0 && errno != EAGAIN)
|
||||
return sock_connectstrerror(errno);
|
||||
if (err > 1 && FD_ISSET(sock, &rfds) &&
|
||||
recv(sock, &dummy, 0, 0) < 0 && errno != EAGAIN)
|
||||
return sock_strerror();
|
||||
else
|
||||
return NULL;
|
||||
/* 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
|
||||
\*-------------------------------------------------------------------------*/
|
||||
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;
|
||||
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);
|
||||
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;
|
||||
sock_setblocking(ps);
|
||||
if (listen(*ps, backlog))
|
||||
err = sock_listenstrerror(errno);
|
||||
if (listen(*ps, backlog)) err = sock_strerror();
|
||||
sock_setnonblocking(ps);
|
||||
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);
|
||||
shutdown(*ps, how);
|
||||
sock_setnonblocking(ps);
|
||||
@ -162,12 +152,11 @@ void sock_shutdown(p_sock ps, int how)
|
||||
* Accept with timeout
|
||||
\*-------------------------------------------------------------------------*/
|
||||
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;
|
||||
SA dummy_addr;
|
||||
socklen_t dummy_len = sizeof(dummy_addr);
|
||||
if (sock == SOCK_INVALID) return io_strerror(IO_CLOSED);
|
||||
if (sock == SOCK_INVALID) return io_strerror(IO_CLOSED);
|
||||
if (!addr) addr = &dummy_addr;
|
||||
if (!addr_len) addr_len = &dummy_len;
|
||||
for (;;) {
|
||||
@ -179,14 +168,16 @@ const char *sock_accept(p_sock ps, p_sock pa, SA *addr,
|
||||
/* if result is valid, we are done */
|
||||
if (*pa != SOCK_INVALID) return NULL;
|
||||
/* find out if we failed for a fatal reason */
|
||||
if (errno != EAGAIN && errno != ECONNABORTED)
|
||||
return sock_acceptstrerror(errno);
|
||||
/* if connection was aborted, we can try again if we have time */
|
||||
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. */
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(sock, &fds);
|
||||
do err = sock_select(sock+1, &fds, NULL, NULL, tm_getretry(tm));
|
||||
while (err < 0 && errno == EINTR);
|
||||
err = sock_select(sock+1, &fds, NULL, NULL, tm);
|
||||
if (err == 0) return io_strerror(IO_TIMEOUT);
|
||||
else if (err < 0) return sock_strerror();
|
||||
}
|
||||
return io_strerror(IO_TIMEOUT); /* can't get here */
|
||||
}
|
||||
@ -194,136 +185,136 @@ const char *sock_accept(p_sock ps, p_sock pa, SA *addr,
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Send with timeout
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int sock_send(p_sock ps, const char *data, size_t count, size_t *sent,
|
||||
int timeout)
|
||||
int sock_send(p_sock ps, const char *data, size_t count, size_t *sent, p_tm tm)
|
||||
{
|
||||
t_sock sock = *ps;
|
||||
ssize_t put;
|
||||
/* avoid making system calls on closed sockets */
|
||||
if (sock == SOCK_INVALID) return IO_CLOSED;
|
||||
/* make sure we repeat in case the call was interrupted */
|
||||
do put = send(sock, data, count, 0);
|
||||
while (put < 0 && errno == EINTR);
|
||||
/* deal with failure */
|
||||
if (put <= 0) {
|
||||
/* loop until we send something or we give up on error */
|
||||
for ( ;; ) {
|
||||
int ret;
|
||||
fd_set fds;
|
||||
/* in any case, nothing has been sent */
|
||||
ssize_t put;
|
||||
/* make sure we repeat in case the call was interrupted */
|
||||
do put = send(sock, data, count, 0);
|
||||
while (put < 0 && errno == EINTR);
|
||||
/* if we sent something, get out */
|
||||
if (put > 0) {
|
||||
*sent = put;
|
||||
return IO_DONE;
|
||||
}
|
||||
/* deal with failure */
|
||||
*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 */
|
||||
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 */
|
||||
FD_ZERO(&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;
|
||||
else if (ret > 0 || errno == EINTR) return IO_RETRY;
|
||||
else return IO_ERROR;
|
||||
/* here we successfully sent something */
|
||||
} else {
|
||||
*sent = put;
|
||||
return IO_DONE;
|
||||
}
|
||||
if (ret < 0) return IO_USER;
|
||||
/* otherwise, try sending again */
|
||||
}
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Sendto with timeout
|
||||
\*-------------------------------------------------------------------------*/
|
||||
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;
|
||||
ssize_t put;
|
||||
/* avoid making system calls on closed sockets */
|
||||
if (sock == SOCK_INVALID) return IO_CLOSED;
|
||||
do put = sendto(sock, data, count, 0, addr, addr_len);
|
||||
while (put < 0 && errno == EINTR);
|
||||
if (put <= 0) {
|
||||
/* loop until we send something or we give up on error */
|
||||
for ( ;; ) {
|
||||
int ret;
|
||||
fd_set fds;
|
||||
ssize_t put;
|
||||
do put = sendto(sock, data, count, 0, addr, addr_len);
|
||||
while (put < 0 && errno == EINTR);
|
||||
if (put > 0) {
|
||||
*sent = put;
|
||||
return IO_DONE;
|
||||
}
|
||||
*sent = 0;
|
||||
if (errno != EAGAIN) return IO_ERROR;
|
||||
if (timeout == 0) return IO_TIMEOUT;
|
||||
if (errno == EPIPE) return IO_CLOSED;
|
||||
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, timeout);
|
||||
ret = sock_select(sock+1, NULL, &fds, NULL, tm);
|
||||
if (ret == 0) return IO_TIMEOUT;
|
||||
else if (ret > 0 || errno == EINTR) return IO_RETRY;
|
||||
else return IO_ERROR;
|
||||
} else {
|
||||
*sent = put;
|
||||
return IO_DONE;
|
||||
}
|
||||
if (ret < 0) return IO_USER;
|
||||
}
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* 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;
|
||||
ssize_t taken;
|
||||
if (sock == SOCK_INVALID) return IO_CLOSED;
|
||||
do taken = read(sock, data, count);
|
||||
while (taken < 0 && errno == EINTR);
|
||||
if (taken <= 0) {
|
||||
for ( ;; ) {
|
||||
fd_set fds;
|
||||
int ret;
|
||||
ssize_t taken;
|
||||
do taken = read(sock, data, count);
|
||||
while (taken < 0 && errno == EINTR);
|
||||
if (taken > 0) {
|
||||
*got = taken;
|
||||
return IO_DONE;
|
||||
}
|
||||
*got = 0;
|
||||
if (taken == 0) return IO_CLOSED;
|
||||
if (errno != EAGAIN) return IO_ERROR;
|
||||
if (timeout == 0) return IO_TIMEOUT;
|
||||
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, timeout);
|
||||
ret = sock_select(sock+1, &fds, NULL, NULL, tm);
|
||||
if (ret == 0) return IO_TIMEOUT;
|
||||
else if (ret > 0 || errno == EINTR) return IO_RETRY;
|
||||
else return IO_ERROR;
|
||||
} else {
|
||||
*got = taken;
|
||||
return IO_DONE;
|
||||
}
|
||||
if (ret < 0) return IO_USER;
|
||||
}
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Recvfrom with timeout
|
||||
\*-------------------------------------------------------------------------*/
|
||||
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;
|
||||
ssize_t taken;
|
||||
if (sock == SOCK_INVALID) return IO_CLOSED;
|
||||
do taken = recvfrom(sock, data, count, 0, addr, addr_len);
|
||||
while (taken < 0 && errno == EINTR);
|
||||
if (taken <= 0) {
|
||||
for ( ;; ) {
|
||||
fd_set fds;
|
||||
int ret;
|
||||
ssize_t taken;
|
||||
do taken = recvfrom(sock, data, count, 0, addr, addr_len);
|
||||
while (taken < 0 && errno == EINTR);
|
||||
if (taken > 0) {
|
||||
*got = taken;
|
||||
return IO_DONE;
|
||||
}
|
||||
*got = 0;
|
||||
if (taken == 0) return IO_CLOSED;
|
||||
if (errno != EAGAIN) return IO_ERROR;
|
||||
if (timeout == 0) return IO_TIMEOUT;
|
||||
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, timeout);
|
||||
ret = sock_select(sock+1, &fds, NULL, NULL, tm);
|
||||
if (ret == 0) return IO_TIMEOUT;
|
||||
else if (ret > 0 || errno == EINTR) return IO_RETRY;
|
||||
else return IO_ERROR;
|
||||
} else {
|
||||
*got = taken;
|
||||
return IO_DONE;
|
||||
}
|
||||
if (ret < 0) return IO_USER;
|
||||
}
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Put socket into blocking mode
|
||||
\*-------------------------------------------------------------------------*/
|
||||
void sock_setblocking(p_sock ps)
|
||||
{
|
||||
void sock_setblocking(p_sock ps) {
|
||||
int flags = fcntl(*ps, F_GETFL, 0);
|
||||
flags &= (~(O_NONBLOCK));
|
||||
fcntl(*ps, F_SETFL, flags);
|
||||
@ -332,8 +323,7 @@ void sock_setblocking(p_sock ps)
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* 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);
|
||||
flags |= O_NONBLOCK;
|
||||
fcntl(*ps, F_SETFL, flags);
|
||||
@ -342,98 +332,20 @@ void sock_setnonblocking(p_sock ps)
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Error translation functions
|
||||
\*-------------------------------------------------------------------------*/
|
||||
/* return error messages for the known errors reported by gethostbyname */
|
||||
const char *sock_hoststrerror(void)
|
||||
{
|
||||
switch (h_errno) {
|
||||
case HOST_NOT_FOUND: return "host not found";
|
||||
case NO_ADDRESS: return "valid host but no ip found";
|
||||
case NO_RECOVERY: return "name server error";
|
||||
case TRY_AGAIN: return "name server unavailable, try again later";
|
||||
default: return "unknown error";
|
||||
const char *sock_hoststrerror(void) {
|
||||
return hstrerror(h_errno);
|
||||
}
|
||||
|
||||
/* make sure important error messages are standard */
|
||||
const char *sock_strerror(void) {
|
||||
switch (errno) {
|
||||
case EADDRINUSE:
|
||||
return "address already in use";
|
||||
default:
|
||||
return strerror(errno);
|
||||
}
|
||||
}
|
||||
|
||||
/* return error messages for the known errors reported by socket */
|
||||
static const char *sock_createstrerror(int err)
|
||||
{
|
||||
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";
|
||||
}
|
||||
const char *sock_geterr(p_sock ps, int code) {
|
||||
return sock_strerror();
|
||||
}
|
||||
|
@ -16,14 +16,12 @@
|
||||
#include <unistd.h>
|
||||
/* fnctnl function and associated constants */
|
||||
#include <fcntl.h>
|
||||
/* struct timeval and CLK_TCK */
|
||||
#include <sys/time.h>
|
||||
/* times function and struct tms */
|
||||
#include <sys/times.h>
|
||||
/* struct sockaddr */
|
||||
#include <sys/types.h>
|
||||
/* socket function */
|
||||
#include <sys/socket.h>
|
||||
/* struct timeval */
|
||||
#include <sys/time.h>
|
||||
/* gethostbyname and gethostbyaddr functions */
|
||||
#include <netdb.h>
|
||||
/* sigpipe handling */
|
||||
|
@ -228,6 +228,7 @@ function test_totaltimeoutsend(len, tm, sl)
|
||||
data:settimeout(tm, "total")
|
||||
str = string.rep("a", 2*len)
|
||||
total, err, partial, elapsed = data:send(str)
|
||||
print(elapsed, "!")
|
||||
check_timeout(tm, sl, elapsed, err, "send", "total",
|
||||
total == 2*len)
|
||||
end
|
||||
@ -400,27 +401,27 @@ function accept_errors()
|
||||
d:setfd(c:getfd())
|
||||
d:settimeout(2)
|
||||
local r, e = d:accept()
|
||||
assert(not r and e == "not listening", e)
|
||||
print("ok")
|
||||
assert(not r and e)
|
||||
print("ok: ", e)
|
||||
io.stderr:write("not supported: ")
|
||||
local c, e = socket.udp()
|
||||
assert(c, e);
|
||||
d:setfd(c:getfd())
|
||||
local r, e = d:accept()
|
||||
assert(not r and e == "not supported" or e == "not listening", e)
|
||||
print("ok")
|
||||
assert(not r and e)
|
||||
print("ok: ", e)
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------
|
||||
function connect_errors()
|
||||
io.stderr:write("connection refused: ")
|
||||
local c, e = socket.connect("localhost", 1);
|
||||
assert(not c and e == "connection refused", e)
|
||||
print("ok")
|
||||
assert(not c and e)
|
||||
print("ok: ", e)
|
||||
io.stderr:write("host not found: ")
|
||||
local c, e = socket.connect("host.is.invalid", 1);
|
||||
assert(not c and e == "host not found", e)
|
||||
print("ok")
|
||||
assert(not c and e, e)
|
||||
print("ok: ", e)
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------
|
||||
@ -432,36 +433,25 @@ function rebind_test()
|
||||
s:setoption("reuseaddr", false)
|
||||
r, e = s:bind("localhost", p)
|
||||
assert(not r, "managed to rebind!")
|
||||
assert(e == "address already in use")
|
||||
print("ok")
|
||||
assert(e)
|
||||
print("ok: ", e)
|
||||
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_methods(socket.tcp(), {
|
||||
"accept",
|
||||
"accept",
|
||||
"bind",
|
||||
"close",
|
||||
"connect",
|
||||
"dirty",
|
||||
"getfd",
|
||||
"getpeername",
|
||||
"getsockname",
|
||||
"listen",
|
||||
"receive",
|
||||
"send",
|
||||
"setfd",
|
||||
"setoption",
|
||||
"setpeername",
|
||||
"setsockname",
|
||||
@ -472,15 +462,19 @@ test_methods(socket.tcp(), {
|
||||
test_methods(socket.udp(), {
|
||||
"close",
|
||||
"getpeername",
|
||||
"dirty",
|
||||
"getfd",
|
||||
"getpeername",
|
||||
"getsockname",
|
||||
"receive",
|
||||
"receivefrom",
|
||||
"send",
|
||||
"sendto",
|
||||
"setfd",
|
||||
"setoption",
|
||||
"setpeername",
|
||||
"setsockname",
|
||||
"settimeout",
|
||||
"settimeout"
|
||||
})
|
||||
|
||||
test("select function")
|
||||
@ -504,7 +498,18 @@ test("accept function: ")
|
||||
accept_timeout()
|
||||
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(1)
|
||||
@ -566,9 +571,10 @@ test_raw(1)
|
||||
test("total timeout on send")
|
||||
test_totaltimeoutsend(800091, 1, 3)
|
||||
test_totaltimeoutsend(800091, 2, 3)
|
||||
test_totaltimeoutsend(800091, 3, 2)
|
||||
test_totaltimeoutsend(800091, 5, 2)
|
||||
test_totaltimeoutsend(800091, 3, 1)
|
||||
|
||||
|
||||
test("total timeout on receive")
|
||||
test_totaltimeoutreceive(800091, 1, 3)
|
||||
test_totaltimeoutreceive(800091, 2, 3)
|
||||
|
Loading…
Reference in New Issue
Block a user