Moving on to beta2.

This commit is contained in:
Diego Nehab 2004-07-01 03:32:09 +00:00
parent 7aaba59909
commit 7115c12fbc
16 changed files with 391 additions and 443 deletions

7
FIX
View File

@ -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
View File

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

View File

@ -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
View 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

View File

@ -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;
} }

View File

@ -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);
} }

View File

@ -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 */

View File

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

View File

@ -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 */

View File

@ -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;

View File

@ -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;
} }

View File

@ -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
View File

@ -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 */

View File

@ -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;
struct timeval tv; do {
tv.tv_sec = timeout / 1000; struct timeval tv;
tv.tv_usec = (timeout % 1000) * 1000; double t = tm_getretry(tm);
return select(n, rfds, wfds, efds, timeout >= 0? &tv: NULL); 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 * 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,50 +81,49 @@ 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 */
if (sock == SOCK_INVALID) return io_strerror(IO_CLOSED); if (sock == SOCK_INVALID) return io_strerror(IO_CLOSED);
/* ask system to connect */ /* ask system to connect */
do err = connect(sock, addr, addr_len); do err = connect(sock, addr, addr_len);
while (err < 0 && errno == EINTR); while (err < 0 && errno == EINTR);
/* 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,12 +152,11 @@ 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);
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) addr = &dummy_addr;
if (!addr_len) addr_len = &dummy_len; if (!addr_len) addr_len = &dummy_len;
for (;;) { 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 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,136 +185,136 @@ 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;
/* make sure we repeat in case the call was interrupted */ /* loop until we send something or we give up on error */
do put = send(sock, data, count, 0); for ( ;; ) {
while (put < 0 && errno == EINTR);
/* deal with failure */
if (put <= 0) {
int ret; int ret;
fd_set fds; 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; *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;
}
} }
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* 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;
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; *sent = 0;
if (errno != EAGAIN) return IO_ERROR; if (put < 0 && errno == EPIPE) return IO_CLOSED;
if (timeout == 0) return IO_TIMEOUT; if (put == 0 || errno != EAGAIN) return IO_USER;
if (errno == EPIPE) return IO_CLOSED; if (tm_get(tm) == 0.0) return IO_TIMEOUT;
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; }
} else {
*sent = put;
return IO_DONE;
}
} }
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* 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;
ssize_t taken;
do taken = read(sock, data, count);
while (taken < 0 && errno == EINTR);
if (taken > 0) {
*got = taken;
return IO_DONE;
}
*got = 0; *got = 0;
if (taken == 0) return IO_CLOSED; if (taken == 0) return IO_CLOSED;
if (errno != EAGAIN) return IO_ERROR; if (errno != EAGAIN) return IO_USER;
if (timeout == 0) return IO_TIMEOUT; if (tm_get(tm) == 0.0) return IO_TIMEOUT;
FD_ZERO(&fds); FD_ZERO(&fds);
FD_SET(sock, &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; 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; }
} else {
*got = taken;
return IO_DONE;
}
} }
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* 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;
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; *got = 0;
if (taken == 0) return IO_CLOSED; if (taken == 0) return IO_CLOSED;
if (errno != EAGAIN) return IO_ERROR; if (errno != EAGAIN) return IO_USER;
if (timeout == 0) return IO_TIMEOUT; if (tm_get(tm) == 0.0) return IO_TIMEOUT;
FD_ZERO(&fds); FD_ZERO(&fds);
FD_SET(sock, &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; 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; }
} else {
*got = taken;
return IO_DONE;
}
} }
/*-------------------------------------------------------------------------*\ /*-------------------------------------------------------------------------*\
* 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";
}
} }

View File

@ -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 */

View File

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