mirror of
https://github.com/lunarmodules/luasocket.git
synced 2024-11-16 02:08:21 +01:00
Trying to get connect-with-timeout to work. Darwin works...
This commit is contained in:
parent
02ef4e7daa
commit
c8d58798f0
12
src/buffer.c
12
src/buffer.c
@ -138,8 +138,7 @@ int sendraw(p_buf buf, const char *data, size_t count, size_t *sent)
|
|||||||
int err = IO_DONE;
|
int err = IO_DONE;
|
||||||
while (total < count && err == IO_DONE) {
|
while (total < count && err == IO_DONE) {
|
||||||
size_t done;
|
size_t done;
|
||||||
err = io->send(io->ctx, data+total, count-total, &done,
|
err = io->send(io->ctx, data+total, count-total, &done, tm_get(tm));
|
||||||
tm_getsuccess(tm));
|
|
||||||
total += done;
|
total += done;
|
||||||
}
|
}
|
||||||
*sent = total;
|
*sent = total;
|
||||||
@ -156,7 +155,7 @@ int recvraw(lua_State *L, p_buf buf, size_t wanted)
|
|||||||
size_t total = 0;
|
size_t total = 0;
|
||||||
luaL_Buffer b;
|
luaL_Buffer b;
|
||||||
luaL_buffinit(L, &b);
|
luaL_buffinit(L, &b);
|
||||||
while (total < wanted && err == IO_DONE) {
|
while (total < wanted && (err == IO_DONE || err == IO_RETRY)) {
|
||||||
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);
|
||||||
@ -177,7 +176,7 @@ int recvall(lua_State *L, p_buf buf)
|
|||||||
int err = IO_DONE;
|
int err = IO_DONE;
|
||||||
luaL_Buffer b;
|
luaL_Buffer b;
|
||||||
luaL_buffinit(L, &b);
|
luaL_buffinit(L, &b);
|
||||||
while (err == IO_DONE) {
|
while (err == IO_DONE || err == IO_RETRY) {
|
||||||
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);
|
||||||
@ -197,7 +196,7 @@ int recvline(lua_State *L, p_buf buf)
|
|||||||
int err = IO_DONE;
|
int err = IO_DONE;
|
||||||
luaL_Buffer b;
|
luaL_Buffer b;
|
||||||
luaL_buffinit(L, &b);
|
luaL_buffinit(L, &b);
|
||||||
while (err == IO_DONE) {
|
while (err == IO_DONE || err == IO_RETRY) {
|
||||||
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;
|
||||||
@ -240,8 +239,7 @@ int buf_get(p_buf buf, const char **data, size_t *count)
|
|||||||
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,
|
err = io->recv(io->ctx, buf->data, BUF_SIZE, &got, tm_get(tm));
|
||||||
tm_getsuccess(tm));
|
|
||||||
buf->first = 0;
|
buf->first = 0;
|
||||||
buf->last = got;
|
buf->last = got;
|
||||||
}
|
}
|
||||||
|
@ -549,10 +549,16 @@ function request_cb(reqt, respt)
|
|||||||
reqt.headers = fill_headers(reqt.headers, parsed)
|
reqt.headers = fill_headers(reqt.headers, parsed)
|
||||||
-- try to connect to server
|
-- try to connect to server
|
||||||
local sock
|
local sock
|
||||||
sock, respt.error = socket.connect(parsed.host, parsed.port)
|
sock, respt.error = socket.tcp()
|
||||||
if not sock then return respt end
|
if not sock then return respt end
|
||||||
-- set connection timeout so that we do not hang forever
|
-- set connection timeout so that we do not hang forever
|
||||||
sock:settimeout(TIMEOUT)
|
sock:settimeout(TIMEOUT)
|
||||||
|
local ret
|
||||||
|
ret, respt.error = sock:connect(parsed.host, parsed.port)
|
||||||
|
if not ret then
|
||||||
|
sock:close()
|
||||||
|
return respt
|
||||||
|
end
|
||||||
-- send request message
|
-- send request message
|
||||||
respt.error = send_request(sock, reqt.method,
|
respt.error = send_request(sock, reqt.method,
|
||||||
request_uri(parsed), reqt.headers, reqt.body_cb)
|
request_uri(parsed), reqt.headers, reqt.body_cb)
|
||||||
|
41
src/inet.c
41
src/inet.c
@ -180,11 +180,11 @@ static void inet_pushresolved(lua_State *L, struct hostent *hp)
|
|||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Tries to connect to remote address (address, port)
|
* Tries to connect to remote address (address, port)
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
const char *inet_tryconnect(p_sock ps, const char *address,
|
const char *inet_tryconnect(p_sock ps, p_tm tm, const char *address,
|
||||||
unsigned short port, int timeout)
|
unsigned short port)
|
||||||
{
|
{
|
||||||
struct sockaddr_in remote;
|
struct sockaddr_in remote;
|
||||||
const char *err;
|
int err;
|
||||||
memset(&remote, 0, sizeof(remote));
|
memset(&remote, 0, sizeof(remote));
|
||||||
remote.sin_family = AF_INET;
|
remote.sin_family = AF_INET;
|
||||||
remote.sin_port = htons(port);
|
remote.sin_port = htons(port);
|
||||||
@ -197,14 +197,14 @@ const char *inet_tryconnect(p_sock ps, const char *address,
|
|||||||
memcpy(&remote.sin_addr, *addr, sizeof(struct in_addr));
|
memcpy(&remote.sin_addr, *addr, sizeof(struct in_addr));
|
||||||
}
|
}
|
||||||
} else remote.sin_family = AF_UNSPEC;
|
} else remote.sin_family = AF_UNSPEC;
|
||||||
err = sock_connect(ps, (SA *) &remote, sizeof(remote), timeout);
|
do err = sock_connect(ps, (SA *) &remote, sizeof(remote), tm_getretry(tm));
|
||||||
if (err) {
|
while (err == IO_RETRY && tm_getretry(tm));
|
||||||
|
if (err != IO_DONE) {
|
||||||
sock_destroy(ps);
|
sock_destroy(ps);
|
||||||
*ps = SOCK_INVALID;
|
*ps = SOCK_INVALID;
|
||||||
return err;
|
if (err == IO_ERROR) return sock_connectstrerror();
|
||||||
} else {
|
else return io_strerror(err);
|
||||||
return NULL;
|
} else return NULL;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
@ -214,7 +214,6 @@ const char *inet_trybind(p_sock ps, const char *address, unsigned short port,
|
|||||||
int backlog)
|
int backlog)
|
||||||
{
|
{
|
||||||
struct sockaddr_in local;
|
struct sockaddr_in local;
|
||||||
const char *err;
|
|
||||||
memset(&local, 0, sizeof(local));
|
memset(&local, 0, sizeof(local));
|
||||||
/* address is either wildcard or a valid ip address */
|
/* address is either wildcard or a valid ip address */
|
||||||
local.sin_addr.s_addr = htonl(INADDR_ANY);
|
local.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||||
@ -229,11 +228,10 @@ const char *inet_trybind(p_sock ps, const char *address, unsigned short port,
|
|||||||
memcpy(&local.sin_addr, *addr, sizeof(struct in_addr));
|
memcpy(&local.sin_addr, *addr, sizeof(struct in_addr));
|
||||||
}
|
}
|
||||||
sock_setblocking(ps);
|
sock_setblocking(ps);
|
||||||
err = sock_bind(ps, (SA *) &local, sizeof(local));
|
if (sock_bind(ps, (SA *) &local, sizeof(local)) != IO_DONE) {
|
||||||
if (err) {
|
|
||||||
sock_destroy(ps);
|
sock_destroy(ps);
|
||||||
*ps = SOCK_INVALID;
|
*ps = SOCK_INVALID;
|
||||||
return err;
|
return sock_bindstrerror();
|
||||||
} else {
|
} else {
|
||||||
sock_setnonblocking(ps);
|
sock_setnonblocking(ps);
|
||||||
if (backlog > 0) sock_listen(ps, backlog);
|
if (backlog > 0) sock_listen(ps, backlog);
|
||||||
@ -246,7 +244,22 @@ const char *inet_trybind(p_sock ps, const char *address, unsigned short port,
|
|||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
const char *inet_trycreate(p_sock ps, int type)
|
const char *inet_trycreate(p_sock ps, int type)
|
||||||
{
|
{
|
||||||
return sock_create(ps, AF_INET, type, 0);
|
if (sock_create(ps, AF_INET, type, 0) == IO_DONE) return NULL;
|
||||||
|
else return sock_createstrerror();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------------*\
|
||||||
|
* Tries to accept an inet socket
|
||||||
|
\*-------------------------------------------------------------------------*/
|
||||||
|
const char *inet_tryaccept(p_sock ps, p_tm tm, p_sock pc)
|
||||||
|
{
|
||||||
|
struct sockaddr_in addr;
|
||||||
|
socklen_t addr_len = sizeof(addr);
|
||||||
|
int err;
|
||||||
|
/* loop until connection accepted or timeout happens */
|
||||||
|
do err = sock_accept(ps, pc, (SA *) &addr, &addr_len, tm_getretry(tm));
|
||||||
|
while (err == IO_RETRY && tm_getretry(tm) != 0);
|
||||||
|
return io_strerror(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
|
@ -18,17 +18,21 @@
|
|||||||
\*=========================================================================*/
|
\*=========================================================================*/
|
||||||
#include <lua.h>
|
#include <lua.h>
|
||||||
#include "socket.h"
|
#include "socket.h"
|
||||||
|
#include "timeout.h"
|
||||||
|
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
#define INET_ATON
|
#define INET_ATON
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void inet_open(lua_State *L);
|
void inet_open(lua_State *L);
|
||||||
const char *inet_tryconnect(p_sock ps, const char *address,
|
|
||||||
unsigned short port, int timeout);
|
const char *inet_tryconnect(p_sock ps, p_tm tm, const char *address,
|
||||||
|
unsigned short port);
|
||||||
const char *inet_trybind(p_sock ps, const char *address,
|
const char *inet_trybind(p_sock ps, const char *address,
|
||||||
unsigned short port, int backlog);
|
unsigned short port, int backlog);
|
||||||
const char *inet_trycreate(p_sock ps, int type);
|
const char *inet_trycreate(p_sock ps, int type);
|
||||||
|
const char *inet_tryaccept(p_sock ps, p_tm tm, p_sock pc);
|
||||||
|
|
||||||
int inet_meth_getpeername(lua_State *L, p_sock ps);
|
int inet_meth_getpeername(lua_State *L, p_sock ps);
|
||||||
int inet_meth_getsockname(lua_State *L, p_sock ps);
|
int inet_meth_getsockname(lua_State *L, p_sock ps);
|
||||||
|
|
||||||
|
35
src/io.c
35
src/io.c
@ -22,27 +22,24 @@ void io_init(p_io io, p_send send, p_recv recv, void *ctx)
|
|||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Translate error codes to Lua
|
* Translate error codes to Lua
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
void io_pusherror(lua_State *L, int code)
|
const char *io_strerror(int code)
|
||||||
{
|
{
|
||||||
switch (code) {
|
switch (code) {
|
||||||
case IO_DONE:
|
case IO_DONE: return NULL;
|
||||||
lua_pushnil(L);
|
case IO_TIMEOUT: return "timeout";
|
||||||
break;
|
case IO_RETRY: return "retry";
|
||||||
case IO_TIMEOUT:
|
case IO_CLOSED: return "closed";
|
||||||
lua_pushstring(L, "timeout");
|
case IO_REFUSED: return "refused";
|
||||||
break;
|
default: return "unknown error";
|
||||||
case IO_LIMITED:
|
|
||||||
lua_pushstring(L, "limited");
|
|
||||||
break;
|
|
||||||
case IO_CLOSED:
|
|
||||||
lua_pushstring(L, "closed");
|
|
||||||
break;
|
|
||||||
case IO_REFUSED:
|
|
||||||
lua_pushstring(L, "refused");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
lua_pushstring(L, "unknown error");
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------------*\
|
||||||
|
* Translate error codes to Lua
|
||||||
|
\*-------------------------------------------------------------------------*/
|
||||||
|
void io_pusherror(lua_State *L, int code)
|
||||||
|
{
|
||||||
|
const char *err = io_strerror(code);
|
||||||
|
if (err) lua_pushstring(L, err);
|
||||||
|
else lua_pushnil(L);
|
||||||
|
}
|
||||||
|
6
src/io.h
6
src/io.h
@ -20,12 +20,11 @@
|
|||||||
/* 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_ERROR, /* something wrong... */
|
|
||||||
IO_REFUSED, /* transfer has been refused */
|
IO_REFUSED, /* transfer has been refused */
|
||||||
IO_RETRY, /* please try again */
|
IO_ERROR /* something else wrong... */
|
||||||
IO_LIMITED /* maximum number of bytes reached */
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* interface to send function */
|
/* interface to send function */
|
||||||
@ -54,6 +53,7 @@ typedef struct t_io_ {
|
|||||||
} t_io;
|
} t_io;
|
||||||
typedef t_io *p_io;
|
typedef t_io *p_io;
|
||||||
|
|
||||||
|
const char *io_strerror(int code);
|
||||||
void io_pusherror(lua_State *L, 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_init(p_io io, p_send send, p_recv recv, void *ctx);
|
||||||
|
|
||||||
|
@ -30,12 +30,12 @@ typedef struct sockaddr SA;
|
|||||||
* interface to sockets
|
* interface to sockets
|
||||||
\*=========================================================================*/
|
\*=========================================================================*/
|
||||||
int sock_open(void);
|
int sock_open(void);
|
||||||
const char *sock_create(p_sock ps, int domain, int type, int protocol);
|
int sock_create(p_sock ps, int domain, int type, int protocol);
|
||||||
void sock_destroy(p_sock ps);
|
void sock_destroy(p_sock ps);
|
||||||
int sock_accept(p_sock ps, p_sock pa, SA *addr, socklen_t *addr_len,
|
int sock_accept(p_sock ps, p_sock pa, SA *addr, socklen_t *addr_len,
|
||||||
int timeout);
|
int timeout);
|
||||||
const char *sock_connect(p_sock ps, SA *addr, socklen_t addr_len, int timeout);
|
int sock_connect(p_sock ps, SA *addr, socklen_t addr_len, int timeout);
|
||||||
const char *sock_bind(p_sock ps, SA *addr, socklen_t addr_len);
|
int sock_bind(p_sock ps, SA *addr, socklen_t addr_len);
|
||||||
void sock_listen(p_sock ps, int backlog);
|
void sock_listen(p_sock ps, int backlog);
|
||||||
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,
|
||||||
@ -48,6 +48,7 @@ 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, int timeout);
|
||||||
void sock_setnonblocking(p_sock ps);
|
void sock_setnonblocking(p_sock ps);
|
||||||
void sock_setblocking(p_sock ps);
|
void sock_setblocking(p_sock ps);
|
||||||
|
|
||||||
const char *sock_hoststrerror(void);
|
const char *sock_hoststrerror(void);
|
||||||
const char *sock_createstrerror(void);
|
const char *sock_createstrerror(void);
|
||||||
const char *sock_bindstrerror(void);
|
const char *sock_bindstrerror(void);
|
||||||
|
69
src/tcp.c
69
src/tcp.c
@ -63,7 +63,7 @@ static luaL_reg tcp[] = {
|
|||||||
static luaL_reg opt[] = {
|
static luaL_reg opt[] = {
|
||||||
{"keepalive", opt_keepalive},
|
{"keepalive", opt_keepalive},
|
||||||
{"reuseaddr", opt_reuseaddr},
|
{"reuseaddr", opt_reuseaddr},
|
||||||
{"tcp-nodelay", opt_tcp_nodelay},
|
{"tcp-nodelay", opt_tcp_nodelay},
|
||||||
{"linger", opt_linger},
|
{"linger", opt_linger},
|
||||||
{NULL, NULL}
|
{NULL, NULL}
|
||||||
};
|
};
|
||||||
@ -200,32 +200,26 @@ static int meth_dirty(lua_State *L)
|
|||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
static int meth_accept(lua_State *L)
|
static int meth_accept(lua_State *L)
|
||||||
{
|
{
|
||||||
struct sockaddr_in addr;
|
|
||||||
socklen_t addr_len = sizeof(addr);
|
|
||||||
int err = IO_ERROR;
|
|
||||||
p_tcp server = (p_tcp) aux_checkclass(L, "tcp{server}", 1);
|
p_tcp server = (p_tcp) aux_checkclass(L, "tcp{server}", 1);
|
||||||
p_tm tm = &server->tm;
|
p_tm tm = &server->tm;
|
||||||
p_tcp client;
|
|
||||||
t_sock sock;
|
t_sock sock;
|
||||||
tm_markstart(tm);
|
tm_markstart(tm);
|
||||||
/* loop until connection accepted or timeout happens */
|
const char *err = inet_tryaccept(&server->sock, tm, &sock);
|
||||||
while (err != IO_DONE) {
|
/* if successful, push client socket */
|
||||||
err = sock_accept(&server->sock, &sock,
|
if (!err) {
|
||||||
(SA *) &addr, &addr_len, tm_getfailure(tm));
|
p_tcp clnt = lua_newuserdata(L, sizeof(t_tcp));
|
||||||
if (err == IO_CLOSED || (err == IO_TIMEOUT && !tm_getfailure(tm))) {
|
aux_setclass(L, "tcp{client}", -1);
|
||||||
lua_pushnil(L);
|
/* initialize structure fields */
|
||||||
io_pusherror(L, err);
|
clnt->sock = sock;
|
||||||
return 2;
|
io_init(&clnt->io, (p_send)sock_send, (p_recv)sock_recv, &clnt->sock);
|
||||||
}
|
tm_init(&clnt->tm, -1, -1);
|
||||||
|
buf_init(&clnt->buf, &clnt->io, &clnt->tm);
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
lua_pushnil(L);
|
||||||
|
lua_pushstring(L, err);
|
||||||
|
return 2;
|
||||||
}
|
}
|
||||||
client = lua_newuserdata(L, sizeof(t_tcp));
|
|
||||||
aux_setclass(L, "tcp{client}", -1);
|
|
||||||
client->sock = sock;
|
|
||||||
/* initialize remaining structure fields */
|
|
||||||
io_init(&client->io, (p_send) sock_send, (p_recv) sock_recv, &client->sock);
|
|
||||||
tm_init(&client->tm, -1, -1);
|
|
||||||
buf_init(&client->buf, &client->io, &client->tm);
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
@ -260,7 +254,7 @@ static int meth_connect(lua_State *L)
|
|||||||
p_tm tm = &tcp->tm;
|
p_tm tm = &tcp->tm;
|
||||||
const char *err;
|
const char *err;
|
||||||
tm_markstart(tm);
|
tm_markstart(tm);
|
||||||
err = inet_tryconnect(&tcp->sock, address, port, tm_getfailure(tm));
|
err = inet_tryconnect(&tcp->sock, tm, address, port);
|
||||||
if (err) {
|
if (err) {
|
||||||
lua_pushnil(L);
|
lua_pushnil(L);
|
||||||
lua_pushstring(L, err);
|
lua_pushstring(L, err);
|
||||||
@ -283,7 +277,7 @@ static int meth_close(lua_State *L)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Shuts the connection down
|
* Shuts the connection down partially
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
static int meth_shutdown(lua_State *L)
|
static int meth_shutdown(lua_State *L)
|
||||||
{
|
{
|
||||||
@ -341,22 +335,23 @@ static int meth_settimeout(lua_State *L)
|
|||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
int global_create(lua_State *L)
|
int global_create(lua_State *L)
|
||||||
{
|
{
|
||||||
const char *err;
|
t_sock sock;
|
||||||
/* allocate tcp object */
|
const char *err = inet_trycreate(&sock, SOCK_STREAM);
|
||||||
p_tcp tcp = (p_tcp) lua_newuserdata(L, sizeof(t_tcp));
|
|
||||||
/* set its type as master object */
|
|
||||||
aux_setclass(L, "tcp{master}", -1);
|
|
||||||
/* try to allocate a system socket */
|
/* try to allocate a system socket */
|
||||||
err = inet_trycreate(&tcp->sock, SOCK_STREAM);
|
if (!err) {
|
||||||
if (err) { /* get rid of object on stack and push error */
|
/* allocate tcp object */
|
||||||
lua_pop(L, 1);
|
p_tcp tcp = (p_tcp) lua_newuserdata(L, sizeof(t_tcp));
|
||||||
|
tcp->sock = sock;
|
||||||
|
/* set its type as master object */
|
||||||
|
aux_setclass(L, "tcp{master}", -1);
|
||||||
|
/* initialize remaining structure fields */
|
||||||
|
io_init(&tcp->io, (p_send) sock_send, (p_recv) sock_recv, &tcp->sock);
|
||||||
|
tm_init(&tcp->tm, -1, -1);
|
||||||
|
buf_init(&tcp->buf, &tcp->io, &tcp->tm);
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
lua_pushnil(L);
|
lua_pushnil(L);
|
||||||
lua_pushstring(L, err);
|
lua_pushstring(L, err);
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
/* initialize remaining structure fields */
|
|
||||||
io_init(&tcp->io, (p_send) sock_send, (p_recv) sock_recv, &tcp->sock);
|
|
||||||
tm_init(&tcp->tm, -1, -1);
|
|
||||||
buf_init(&tcp->buf, &tcp->io, &tcp->tm);
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
@ -54,7 +54,7 @@ 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_getsuccess(p_tm tm)
|
int tm_get(p_tm tm)
|
||||||
{
|
{
|
||||||
if (tm->block < 0 && tm->total < 0) {
|
if (tm->block < 0 && tm->total < 0) {
|
||||||
return -1;
|
return -1;
|
||||||
@ -89,7 +89,7 @@ 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_getfailure(p_tm tm)
|
int tm_getretry(p_tm tm)
|
||||||
{
|
{
|
||||||
if (tm->block < 0 && tm->total < 0) {
|
if (tm->block < 0 && tm->total < 0) {
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -18,8 +18,8 @@ typedef t_tm *p_tm;
|
|||||||
|
|
||||||
void tm_open(lua_State *L);
|
void tm_open(lua_State *L);
|
||||||
void tm_init(p_tm tm, int block, int total);
|
void tm_init(p_tm tm, int block, int total);
|
||||||
int tm_getsuccess(p_tm tm);
|
int tm_get(p_tm tm);
|
||||||
int tm_getfailure(p_tm tm);
|
int tm_getretry(p_tm tm);
|
||||||
void tm_markstart(p_tm tm);
|
void tm_markstart(p_tm tm);
|
||||||
int tm_getstart(p_tm tm);
|
int tm_getstart(p_tm tm);
|
||||||
int tm_gettime(void);
|
int tm_gettime(void);
|
||||||
|
64
src/udp.c
64
src/udp.c
@ -29,6 +29,7 @@ static int meth_getpeername(lua_State *L);
|
|||||||
static int meth_setsockname(lua_State *L);
|
static int meth_setsockname(lua_State *L);
|
||||||
static int meth_setpeername(lua_State *L);
|
static int meth_setpeername(lua_State *L);
|
||||||
static int meth_close(lua_State *L);
|
static int meth_close(lua_State *L);
|
||||||
|
static int meth_shutdown(lua_State *L);
|
||||||
static int meth_setoption(lua_State *L);
|
static int meth_setoption(lua_State *L);
|
||||||
static int meth_settimeout(lua_State *L);
|
static int meth_settimeout(lua_State *L);
|
||||||
static int meth_fd(lua_State *L);
|
static int meth_fd(lua_State *L);
|
||||||
@ -53,6 +54,7 @@ static luaL_reg udp[] = {
|
|||||||
{"receivefrom", meth_receivefrom},
|
{"receivefrom", meth_receivefrom},
|
||||||
{"settimeout", meth_settimeout},
|
{"settimeout", meth_settimeout},
|
||||||
{"close", meth_close},
|
{"close", meth_close},
|
||||||
|
{"shutdown", meth_shutdown},
|
||||||
{"setoption", meth_setoption},
|
{"setoption", meth_setoption},
|
||||||
{"__gc", meth_close},
|
{"__gc", meth_close},
|
||||||
{"fd", meth_fd},
|
{"fd", meth_fd},
|
||||||
@ -110,7 +112,7 @@ static int meth_send(lua_State *L)
|
|||||||
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);
|
||||||
err = sock_send(&udp->sock, data, count, &sent, tm_getsuccess(tm));
|
err = sock_send(&udp->sock, data, count, &sent, tm_get(tm));
|
||||||
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
|
||||||
@ -139,7 +141,7 @@ static int meth_sendto(lua_State *L)
|
|||||||
addr.sin_port = htons(port);
|
addr.sin_port = htons(port);
|
||||||
tm_markstart(tm);
|
tm_markstart(tm);
|
||||||
err = sock_sendto(&udp->sock, data, count, &sent,
|
err = sock_sendto(&udp->sock, data, count, &sent,
|
||||||
(SA *) &addr, sizeof(addr), tm_getsuccess(tm));
|
(SA *) &addr, sizeof(addr), tm_get(tm));
|
||||||
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
|
||||||
@ -160,7 +162,7 @@ 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);
|
||||||
err = sock_recv(&udp->sock, buffer, count, &got, tm_getsuccess(tm));
|
err = sock_recv(&udp->sock, buffer, count, &got, tm_get(tm));
|
||||||
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);
|
io_pusherror(L, err);
|
||||||
@ -182,7 +184,7 @@ static int meth_receivefrom(lua_State *L)
|
|||||||
tm_markstart(tm);
|
tm_markstart(tm);
|
||||||
count = MIN(count, sizeof(buffer));
|
count = MIN(count, sizeof(buffer));
|
||||||
err = sock_recvfrom(&udp->sock, buffer, count, &got,
|
err = sock_recvfrom(&udp->sock, buffer, count, &got,
|
||||||
(SA *) &addr, &addr_len, tm_getsuccess(tm));
|
(SA *) &addr, &addr_len, tm_get(tm));
|
||||||
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));
|
||||||
@ -341,8 +343,7 @@ static int meth_setpeername(lua_State *L)
|
|||||||
unsigned short port = connecting ?
|
unsigned short port = connecting ?
|
||||||
(unsigned short) luaL_checknumber(L, 3) :
|
(unsigned short) luaL_checknumber(L, 3) :
|
||||||
(unsigned short) luaL_optnumber(L, 3, 0);
|
(unsigned short) luaL_optnumber(L, 3, 0);
|
||||||
const char *err;
|
const char *err = inet_tryconnect(&udp->sock, tm, address, port);
|
||||||
err = inet_tryconnect(&udp->sock, address, port, tm_getfailure(tm));
|
|
||||||
if (err) {
|
if (err) {
|
||||||
lua_pushnil(L);
|
lua_pushnil(L);
|
||||||
lua_pushstring(L, err);
|
lua_pushstring(L, err);
|
||||||
@ -365,6 +366,33 @@ static int meth_close(lua_State *L)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------------*\
|
||||||
|
* Shuts the connection down partially
|
||||||
|
\*-------------------------------------------------------------------------*/
|
||||||
|
static int meth_shutdown(lua_State *L)
|
||||||
|
{
|
||||||
|
p_udp udp = (p_udp) aux_checkgroup(L, "udp{any}", 1);
|
||||||
|
const char *how = luaL_optstring(L, 2, "both");
|
||||||
|
switch (how[0]) {
|
||||||
|
case 'b':
|
||||||
|
if (strcmp(how, "both")) goto error;
|
||||||
|
sock_shutdown(&udp->sock, 2);
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
if (strcmp(how, "send")) goto error;
|
||||||
|
sock_shutdown(&udp->sock, 1);
|
||||||
|
break;
|
||||||
|
case 'r':
|
||||||
|
if (strcmp(how, "receive")) goto error;
|
||||||
|
sock_shutdown(&udp->sock, 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
error:
|
||||||
|
luaL_argerror(L, 2, "invalid shutdown method");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Turns a master object into a server object
|
* Turns a master object into a server object
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
@ -391,21 +419,21 @@ static int meth_setsockname(lua_State *L)
|
|||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
int global_create(lua_State *L)
|
int global_create(lua_State *L)
|
||||||
{
|
{
|
||||||
const char *err;
|
t_sock sock;
|
||||||
/* allocate udp object */
|
const char *err = inet_trycreate(&sock, SOCK_DGRAM);
|
||||||
p_udp udp = (p_udp) lua_newuserdata(L, sizeof(t_udp));
|
|
||||||
/* set its type as master object */
|
|
||||||
aux_setclass(L, "udp{unconnected}", -1);
|
|
||||||
/* try to allocate a system socket */
|
/* try to allocate a system socket */
|
||||||
err = inet_trycreate(&udp->sock, SOCK_DGRAM);
|
if (!err) {
|
||||||
if (err) {
|
/* allocate tcp object */
|
||||||
/* get rid of object on stack and push error */
|
p_udp udp = (p_udp) lua_newuserdata(L, sizeof(t_udp));
|
||||||
lua_pop(L, 1);
|
udp->sock = sock;
|
||||||
|
/* set its type as master object */
|
||||||
|
aux_setclass(L, "udp{unconnected}", -1);
|
||||||
|
/* initialize remaining structure fields */
|
||||||
|
tm_init(&udp->tm, -1, -1);
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
lua_pushnil(L);
|
lua_pushnil(L);
|
||||||
lua_pushstring(L, err);
|
lua_pushstring(L, err);
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
/* initialize timeout management */
|
|
||||||
tm_init(&udp->tm, -1, -1);
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
165
src/usocket.c
165
src/usocket.c
@ -46,50 +46,59 @@ void sock_destroy(p_sock ps)
|
|||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* 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)
|
int sock_create(p_sock ps, int domain, int type, int protocol)
|
||||||
{
|
{
|
||||||
int val = 1;
|
int val = 1;
|
||||||
t_sock sock = socket(domain, type, protocol);
|
t_sock sock = socket(domain, type, protocol);
|
||||||
if (sock == SOCK_INVALID) return sock_createstrerror();
|
if (sock == SOCK_INVALID) return IO_ERROR;
|
||||||
*ps = sock;
|
*ps = sock;
|
||||||
sock_setnonblocking(ps);
|
sock_setnonblocking(ps);
|
||||||
setsockopt(*ps, SOL_SOCKET, SO_REUSEADDR, (char *) &val, sizeof(val));
|
setsockopt(*ps, SOL_SOCKET, SO_REUSEADDR, (char *) &val, sizeof(val));
|
||||||
return NULL;
|
return IO_DONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Connects or returns error message
|
* Connects or returns error message
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
const char *sock_connect(p_sock ps, SA *addr, socklen_t addr_len, int timeout)
|
int sock_connect(p_sock ps, SA *addr, socklen_t addr_len, int timeout)
|
||||||
{
|
{
|
||||||
t_sock sock = *ps;
|
t_sock sock = *ps;
|
||||||
if (sock == SOCK_INVALID) return "closed";
|
if (sock == SOCK_INVALID) return IO_CLOSED;
|
||||||
|
/* if connect fails, we have to find out why */
|
||||||
if (connect(sock, addr, addr_len) < 0) {
|
if (connect(sock, addr, addr_len) < 0) {
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
fd_set wfds, efds;
|
fd_set rfds, efds, wfds;
|
||||||
int err;
|
int err;
|
||||||
|
/* make sure the system is trying to connect */
|
||||||
|
if (errno != EINPROGRESS) return IO_ERROR;
|
||||||
tv.tv_sec = timeout / 1000;
|
tv.tv_sec = timeout / 1000;
|
||||||
tv.tv_usec = (timeout % 1000) * 1000;
|
tv.tv_usec = (timeout % 1000) * 1000;
|
||||||
FD_ZERO(&wfds); FD_ZERO(&efds);
|
FD_ZERO(&rfds); FD_SET(sock, &rfds);
|
||||||
FD_SET(sock, &wfds); FD_SET(sock, &efds);
|
FD_ZERO(&wfds); FD_SET(sock, &wfds);
|
||||||
do err = select(sock+1, NULL, &wfds, &efds, timeout >= 0 ? &tv : NULL);
|
FD_ZERO(&efds); FD_SET(sock, &efds);
|
||||||
while (err < 0 && errno == EINTR);
|
/* we run select to avoid busy waiting */
|
||||||
if (err <= 0) return "timeout";
|
err = select(sock+1, &rfds, &wfds, &efds, timeout >= 0? &tv: NULL);
|
||||||
if (FD_ISSET(sock, &efds)) {
|
/* if select was interrupted, ask the user to retry */
|
||||||
|
if (err < 0 && errno == EINTR) return IO_RETRY;
|
||||||
|
/* if selects readable, try reading */
|
||||||
|
if (err > 0) {
|
||||||
char dummy;
|
char dummy;
|
||||||
recv(sock, &dummy, 0, 0);
|
/* try reading so that errno is set */
|
||||||
return sock_connectstrerror();
|
if (recv(sock, &dummy, 0, 0) < 0) return IO_ERROR;
|
||||||
} else return NULL;
|
return IO_DONE;
|
||||||
} else return NULL;
|
/* if no event happened, there was a timeout */
|
||||||
|
} else return IO_TIMEOUT;
|
||||||
|
/* otherwise connection succeeded */
|
||||||
|
} else return IO_DONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Binds or returns error message
|
* Binds or returns error message
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
const char *sock_bind(p_sock ps, SA *addr, socklen_t addr_len)
|
int sock_bind(p_sock ps, SA *addr, socklen_t addr_len)
|
||||||
{
|
{
|
||||||
if (bind(*ps, addr, addr_len) < 0) return sock_bindstrerror();
|
if (bind(*ps, addr, addr_len) < 0) return IO_ERROR;
|
||||||
else return NULL;
|
else return IO_DONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
@ -115,25 +124,24 @@ int sock_accept(p_sock ps, p_sock pa, SA *addr, socklen_t *addr_len,
|
|||||||
int timeout)
|
int timeout)
|
||||||
{
|
{
|
||||||
t_sock sock = *ps;
|
t_sock sock = *ps;
|
||||||
struct timeval tv;
|
|
||||||
SA dummy_addr;
|
SA dummy_addr;
|
||||||
socklen_t dummy_len;
|
socklen_t dummy_len;
|
||||||
fd_set fds;
|
|
||||||
int err;
|
|
||||||
if (sock == SOCK_INVALID) return IO_CLOSED;
|
if (sock == SOCK_INVALID) return IO_CLOSED;
|
||||||
tv.tv_sec = timeout / 1000;
|
|
||||||
tv.tv_usec = (timeout % 1000) * 1000;
|
|
||||||
FD_ZERO(&fds);
|
|
||||||
FD_SET(sock, &fds);
|
|
||||||
*pa = SOCK_INVALID;
|
|
||||||
do err = select(sock+1, &fds, NULL, NULL, timeout >= 0 ? &tv : NULL);
|
|
||||||
while (err < 0 && errno == EINTR);
|
|
||||||
if (err <= 0) return IO_TIMEOUT;
|
|
||||||
if (!addr) addr = &dummy_addr;
|
if (!addr) addr = &dummy_addr;
|
||||||
if (!addr_len) addr_len = &dummy_len;
|
if (!addr_len) addr_len = &dummy_len;
|
||||||
*pa = accept(sock, addr, addr_len);
|
*pa = accept(sock, addr, addr_len);
|
||||||
if (*pa == SOCK_INVALID) return IO_ERROR;
|
if (*pa == SOCK_INVALID) {
|
||||||
else return IO_DONE;
|
struct timeval tv;
|
||||||
|
fd_set fds;
|
||||||
|
tv.tv_sec = timeout / 1000;
|
||||||
|
tv.tv_usec = (timeout % 1000) * 1000;
|
||||||
|
FD_ZERO(&fds);
|
||||||
|
FD_SET(sock, &fds);
|
||||||
|
/* just call select to avoid busy-wait. doesn't really matter
|
||||||
|
* what happens. the caller will choose to retry or not */
|
||||||
|
select(sock+1, &fds, NULL, NULL, timeout >= 0? &tv: NULL);
|
||||||
|
return IO_RETRY;
|
||||||
|
} else return IO_DONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
@ -144,32 +152,31 @@ int sock_send(p_sock ps, const char *data, size_t count, size_t *sent,
|
|||||||
{
|
{
|
||||||
t_sock sock = *ps;
|
t_sock sock = *ps;
|
||||||
ssize_t put;
|
ssize_t put;
|
||||||
int ret;
|
|
||||||
/* 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 */
|
/* make sure we repeat in case the call was interrupted */
|
||||||
do put = write(sock, data, count);
|
do put = send(sock, data, count, 0);
|
||||||
while (put <= 0 && errno == EINTR);
|
while (put < 0 && errno == EINTR);
|
||||||
/* deal with failure */
|
/* deal with failure */
|
||||||
if (put <= 0) {
|
if (put <= 0) {
|
||||||
|
struct timeval tv;
|
||||||
|
fd_set fds;
|
||||||
/* in any case, nothing has been sent */
|
/* in any case, nothing has been sent */
|
||||||
*sent = 0;
|
*sent = 0;
|
||||||
/* run select to avoid busy wait */
|
|
||||||
if (errno != EPIPE) {
|
|
||||||
struct timeval tv;
|
|
||||||
fd_set fds;
|
|
||||||
tv.tv_sec = timeout / 1000;
|
|
||||||
tv.tv_usec = (timeout % 1000) * 1000;
|
|
||||||
FD_ZERO(&fds);
|
|
||||||
FD_SET(sock, &fds);
|
|
||||||
do ret = select(sock+1, NULL, &fds, NULL, timeout >= 0 ?&tv : NULL);
|
|
||||||
while (ret < 0 && errno == EINTR);
|
|
||||||
/* tell the caller to call us again because there is more data */
|
|
||||||
if (ret > 0) return IO_DONE;
|
|
||||||
/* tell the caller there was no data before timeout */
|
|
||||||
else return IO_TIMEOUT;
|
|
||||||
/* here we know the connection has been closed */
|
/* here we know the connection has been closed */
|
||||||
} else return IO_CLOSED;
|
if (errno == EPIPE) return IO_CLOSED;
|
||||||
|
/* run select to avoid busy wait */
|
||||||
|
tv.tv_sec = timeout / 1000;
|
||||||
|
tv.tv_usec = (timeout % 1000) * 1000;
|
||||||
|
FD_ZERO(&fds);
|
||||||
|
FD_SET(sock, &fds);
|
||||||
|
if (select(sock+1, NULL, &fds, NULL, timeout >= 0? &tv: NULL) <= 0) {
|
||||||
|
/* here the call was interrupted. calling again might work */
|
||||||
|
if (errno == EINTR) return IO_RETRY;
|
||||||
|
/* here there was no data before timeout */
|
||||||
|
else return IO_TIMEOUT;
|
||||||
|
/* here we didn't send anything, but now we can */
|
||||||
|
} else return IO_DONE;
|
||||||
/* here we successfully sent something */
|
/* here we successfully sent something */
|
||||||
} else {
|
} else {
|
||||||
*sent = put;
|
*sent = put;
|
||||||
@ -185,33 +192,22 @@ int sock_sendto(p_sock ps, const char *data, size_t count, size_t *sent,
|
|||||||
{
|
{
|
||||||
t_sock sock = *ps;
|
t_sock sock = *ps;
|
||||||
ssize_t put;
|
ssize_t put;
|
||||||
int ret;
|
|
||||||
/* 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 */
|
|
||||||
do put = sendto(sock, data, count, 0, addr, addr_len);
|
do put = sendto(sock, data, count, 0, addr, addr_len);
|
||||||
while (put <= 0 && errno == EINTR);
|
while (put < 0 && errno == EINTR);
|
||||||
/* deal with failure */
|
|
||||||
if (put <= 0) {
|
if (put <= 0) {
|
||||||
/* in any case, nothing has been sent */
|
struct timeval tv;
|
||||||
|
fd_set fds;
|
||||||
*sent = 0;
|
*sent = 0;
|
||||||
/* run select to avoid busy wait */
|
if (errno == EPIPE) return IO_CLOSED;
|
||||||
if (errno != EPIPE) {
|
tv.tv_sec = timeout / 1000;
|
||||||
struct timeval tv;
|
tv.tv_usec = (timeout % 1000) * 1000;
|
||||||
fd_set fds;
|
FD_ZERO(&fds);
|
||||||
tv.tv_sec = timeout / 1000;
|
FD_SET(sock, &fds);
|
||||||
tv.tv_usec = (timeout % 1000) * 1000;
|
if (select(sock+1, NULL, &fds, NULL, timeout >= 0? &tv: NULL) <= 0) {
|
||||||
FD_ZERO(&fds);
|
if (errno == EINTR) return IO_RETRY;
|
||||||
FD_SET(sock, &fds);
|
|
||||||
do ret = select(sock+1, NULL, &fds, NULL, timeout >= 0? &tv: NULL);
|
|
||||||
while (ret < 0 && errno == EINTR);
|
|
||||||
/* tell the caller to call us again because there is more data */
|
|
||||||
if (ret > 0) return IO_DONE;
|
|
||||||
/* tell the caller there was no data before timeout */
|
|
||||||
else return IO_TIMEOUT;
|
else return IO_TIMEOUT;
|
||||||
/* here we know the connection has been closed */
|
} else return IO_DONE;
|
||||||
} else return IO_CLOSED;
|
|
||||||
/* here we successfully sent something */
|
|
||||||
} else {
|
} else {
|
||||||
*sent = put;
|
*sent = put;
|
||||||
return IO_DONE;
|
return IO_DONE;
|
||||||
@ -220,11 +216,6 @@ int sock_sendto(p_sock ps, const char *data, size_t count, size_t *sent,
|
|||||||
|
|
||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Receive with timeout
|
* Receive with timeout
|
||||||
* Here we exchanged the order of the calls to write and select
|
|
||||||
* The idea is that the outer loop (whoever is calling sock_send)
|
|
||||||
* will call the function again if we didn't time out, so we can
|
|
||||||
* call write and then select only if it fails.
|
|
||||||
* Should speed things up!
|
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
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, int timeout)
|
||||||
{
|
{
|
||||||
@ -232,7 +223,7 @@ int sock_recv(p_sock ps, char *data, size_t count, size_t *got, int timeout)
|
|||||||
ssize_t taken;
|
ssize_t taken;
|
||||||
if (sock == SOCK_INVALID) return IO_CLOSED;
|
if (sock == SOCK_INVALID) return IO_CLOSED;
|
||||||
do taken = read(sock, data, count);
|
do taken = read(sock, data, count);
|
||||||
while (taken <= 0 && errno == EINTR);
|
while (taken < 0 && errno == EINTR);
|
||||||
if (taken <= 0) {
|
if (taken <= 0) {
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
fd_set fds;
|
fd_set fds;
|
||||||
@ -243,10 +234,10 @@ int sock_recv(p_sock ps, char *data, size_t count, size_t *got, int timeout)
|
|||||||
tv.tv_usec = (timeout % 1000) * 1000;
|
tv.tv_usec = (timeout % 1000) * 1000;
|
||||||
FD_ZERO(&fds);
|
FD_ZERO(&fds);
|
||||||
FD_SET(sock, &fds);
|
FD_SET(sock, &fds);
|
||||||
do ret = select(sock+1, &fds, NULL, NULL, timeout >= 0 ? &tv : NULL);
|
ret = select(sock+1, &fds, NULL, NULL, timeout >= 0 ? &tv : NULL);
|
||||||
while (ret < 0 && errno == EINTR);
|
if (ret < 0 && errno == EINTR) return IO_RETRY;
|
||||||
if (ret > 0) return IO_DONE;
|
if (ret == 0) return IO_TIMEOUT;
|
||||||
else return IO_TIMEOUT;
|
else return IO_DONE;
|
||||||
} else {
|
} else {
|
||||||
*got = taken;
|
*got = taken;
|
||||||
return IO_DONE;
|
return IO_DONE;
|
||||||
@ -263,7 +254,7 @@ int sock_recvfrom(p_sock ps, char *data, size_t count, size_t *got,
|
|||||||
ssize_t taken;
|
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);
|
do taken = recvfrom(sock, data, count, 0, addr, addr_len);
|
||||||
while (taken <= 0 && errno == EINTR);
|
while (taken < 0 && errno == EINTR);
|
||||||
if (taken <= 0) {
|
if (taken <= 0) {
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
fd_set fds;
|
fd_set fds;
|
||||||
@ -274,10 +265,10 @@ int sock_recvfrom(p_sock ps, char *data, size_t count, size_t *got,
|
|||||||
tv.tv_usec = (timeout % 1000) * 1000;
|
tv.tv_usec = (timeout % 1000) * 1000;
|
||||||
FD_ZERO(&fds);
|
FD_ZERO(&fds);
|
||||||
FD_SET(sock, &fds);
|
FD_SET(sock, &fds);
|
||||||
do ret = select(sock+1, &fds, NULL, NULL, timeout >= 0 ? &tv : NULL);
|
ret = select(sock+1, &fds, NULL, NULL, timeout >= 0 ? &tv : NULL);
|
||||||
while (ret < 0 && errno == EINTR);
|
if (ret < 0 && errno == EINTR) return IO_RETRY;
|
||||||
if (ret > 0) return IO_DONE;
|
if (ret == 0) return IO_TIMEOUT;
|
||||||
else return IO_TIMEOUT;
|
else return IO_DONE;
|
||||||
} else {
|
} else {
|
||||||
*got = taken;
|
*got = taken;
|
||||||
return IO_DONE;
|
return IO_DONE;
|
||||||
|
@ -314,9 +314,10 @@ body = socket.http.get {
|
|||||||
check(body == index)
|
check(body == index)
|
||||||
|
|
||||||
io.write("testing HEAD method: ")
|
io.write("testing HEAD method: ")
|
||||||
|
socket.http.TIMEOUT = 1
|
||||||
response = socket.http.request {
|
response = socket.http.request {
|
||||||
method = "HEAD",
|
method = "HEAD",
|
||||||
url = "http://www.tecgraf.puc-rio.br/~diego/"
|
url = "http://www.cs.princeton.edu/~diego/"
|
||||||
}
|
}
|
||||||
check(response and response.headers)
|
check(response and response.headers)
|
||||||
|
|
||||||
|
@ -359,6 +359,7 @@ test_methods(socket.tcp(), {
|
|||||||
"getsockname",
|
"getsockname",
|
||||||
"setoption",
|
"setoption",
|
||||||
"settimeout",
|
"settimeout",
|
||||||
|
"shutdown",
|
||||||
"close",
|
"close",
|
||||||
})
|
})
|
||||||
test_methods(socket.udp(), {
|
test_methods(socket.udp(), {
|
||||||
@ -372,6 +373,7 @@ test_methods(socket.udp(), {
|
|||||||
"receivefrom",
|
"receivefrom",
|
||||||
"setoption",
|
"setoption",
|
||||||
"settimeout",
|
"settimeout",
|
||||||
|
"shutdown",
|
||||||
"close",
|
"close",
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -484,6 +486,4 @@ test_blockingtimeoutreceive(800091, 3, 2)
|
|||||||
test_blockingtimeoutreceive(800091, 3, 1)
|
test_blockingtimeoutreceive(800091, 3, 1)
|
||||||
]]
|
]]
|
||||||
|
|
||||||
socket.done()
|
|
||||||
|
|
||||||
test(string.format("done in %.2fs", socket.time() - start))
|
test(string.format("done in %.2fs", socket.time() - start))
|
||||||
|
Loading…
Reference in New Issue
Block a user