mirror of
https://github.com/lunarmodules/luasocket.git
synced 2024-12-25 12:08:21 +01:00
Fixed functions that return messages in ?socket.c.
Moved complexity of connect and accept there. Created a new options.c module to take care of options. Auxiliar.c is now cleaner.
This commit is contained in:
parent
e63f500d24
commit
195069cf5f
1
TODO
1
TODO
@ -22,6 +22,7 @@ tests
|
||||
trust character constants in mime.c? noooooo.
|
||||
smtp.lua needs stuff filter
|
||||
|
||||
add comments into each C module.
|
||||
new option.c module to put all options (TCP and UDP share...)?
|
||||
testar os options!
|
||||
add _tostring methods!
|
||||
|
@ -65,26 +65,6 @@ int aux_checkboolean(lua_State *L, int objidx)
|
||||
return lua_toboolean(L, objidx);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Calls appropriate option handler
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int aux_meth_setoption(lua_State *L, luaL_reg *opt)
|
||||
{
|
||||
const char *name = luaL_checkstring(L, 2); /* obj, name, args */
|
||||
while (opt->name && strcmp(name, opt->name))
|
||||
opt++;
|
||||
if (!opt->func) {
|
||||
char msg[45];
|
||||
sprintf(msg, "unknown option `%.35s'", name);
|
||||
luaL_argerror(L, 2, msg);
|
||||
}
|
||||
lua_remove(L, 2); /* obj, args */
|
||||
lua_pushcfunction(L, opt->func); /* obj, args, func */
|
||||
lua_insert(L, 1); /* func, obj, args */
|
||||
lua_call(L, lua_gettop(L)-1, LUA_MULTRET);
|
||||
return lua_gettop(L);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Return userdata pointer if object belongs to a given class, abort with
|
||||
* error otherwise
|
||||
|
@ -48,7 +48,6 @@ void *aux_checkclass(lua_State *L, const char *classname, int objidx);
|
||||
void *aux_checkgroup(lua_State *L, const char *groupname, int objidx);
|
||||
void *aux_getclassudata(lua_State *L, const char *groupname, int objidx);
|
||||
void *aux_getgroupudata(lua_State *L, const char *groupname, int objidx);
|
||||
int aux_meth_setoption(lua_State *L, luaL_reg *opt);
|
||||
int aux_checkboolean(lua_State *L, int objidx);
|
||||
|
||||
#endif /* AUX_H */
|
||||
|
56
src/inet.c
56
src/inet.c
@ -177,14 +177,22 @@ static void inet_pushresolved(lua_State *L, struct hostent *hp)
|
||||
lua_settable(L, resolved);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Tries to create a new inet socket
|
||||
\*-------------------------------------------------------------------------*/
|
||||
const char *inet_trycreate(p_sock ps, int type)
|
||||
{
|
||||
return sock_create(ps, AF_INET, type, 0);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Tries to connect to remote address (address, port)
|
||||
\*-------------------------------------------------------------------------*/
|
||||
const char *inet_tryconnect(p_sock ps, p_tm tm, const char *address,
|
||||
unsigned short port)
|
||||
const char *inet_tryconnect(p_sock ps, const char *address,
|
||||
unsigned short port, p_tm tm)
|
||||
{
|
||||
struct sockaddr_in remote;
|
||||
int err;
|
||||
const char *err;
|
||||
memset(&remote, 0, sizeof(remote));
|
||||
remote.sin_family = AF_INET;
|
||||
remote.sin_port = htons(port);
|
||||
@ -197,14 +205,9 @@ const char *inet_tryconnect(p_sock ps, p_tm tm, const char *address,
|
||||
memcpy(&remote.sin_addr, *addr, sizeof(struct in_addr));
|
||||
}
|
||||
} else remote.sin_family = AF_UNSPEC;
|
||||
do err = sock_connect(ps, (SA *) &remote, sizeof(remote), tm_getretry(tm));
|
||||
while (err == IO_RETRY && tm_getretry(tm));
|
||||
if (err != IO_DONE) {
|
||||
sock_destroy(ps);
|
||||
*ps = SOCK_INVALID;
|
||||
if (err == IO_ERROR) return sock_connectstrerror();
|
||||
else return io_strerror(err);
|
||||
} else return NULL;
|
||||
err = sock_connect(ps, (SA *) &remote, sizeof(remote), tm);
|
||||
if (err) sock_destroy(ps);
|
||||
return err;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
@ -214,6 +217,7 @@ const char *inet_trybind(p_sock ps, const char *address, unsigned short port,
|
||||
int backlog)
|
||||
{
|
||||
struct sockaddr_in local;
|
||||
const char *err;
|
||||
memset(&local, 0, sizeof(local));
|
||||
/* address is either wildcard or a valid ip address */
|
||||
local.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
@ -228,10 +232,10 @@ const char *inet_trybind(p_sock ps, const char *address, unsigned short port,
|
||||
memcpy(&local.sin_addr, *addr, sizeof(struct in_addr));
|
||||
}
|
||||
sock_setblocking(ps);
|
||||
if (sock_bind(ps, (SA *) &local, sizeof(local)) != IO_DONE) {
|
||||
err = sock_bind(ps, (SA *) &local, sizeof(local));
|
||||
if (err) {
|
||||
sock_destroy(ps);
|
||||
*ps = SOCK_INVALID;
|
||||
return sock_bindstrerror();
|
||||
return err;
|
||||
} else {
|
||||
sock_setnonblocking(ps);
|
||||
if (backlog >= 0) sock_listen(ps, backlog);
|
||||
@ -239,30 +243,6 @@ const char *inet_trybind(p_sock ps, const char *address, unsigned short port,
|
||||
}
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Tries to create a new inet socket
|
||||
\*-------------------------------------------------------------------------*/
|
||||
const char *inet_trycreate(p_sock ps, int type)
|
||||
{
|
||||
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);
|
||||
if (err == IO_RETRY) err = IO_TIMEOUT;
|
||||
return io_strerror(err);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Some systems do not provide this so that we provide our own. It's not
|
||||
* marvelously fast, but it works just fine.
|
||||
|
@ -26,12 +26,11 @@
|
||||
|
||||
void inet_open(lua_State *L);
|
||||
|
||||
const char *inet_tryconnect(p_sock ps, p_tm tm, const char *address,
|
||||
unsigned short port);
|
||||
const char *inet_trycreate(p_sock ps, int type);
|
||||
const char *inet_tryconnect(p_sock ps, const char *address,
|
||||
unsigned short port, p_tm tm);
|
||||
const char *inet_trybind(p_sock ps, const char *address,
|
||||
unsigned short port, int backlog);
|
||||
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_getsockname(lua_State *L, p_sock ps);
|
||||
|
137
src/options.c
Normal file
137
src/options.c
Normal file
@ -0,0 +1,137 @@
|
||||
#include <lauxlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "auxiliar.h"
|
||||
#include "options.h"
|
||||
|
||||
static int opt_setmembership(lua_State *L, p_sock ps, int level, int name);
|
||||
static int opt_setboolean(lua_State *L, p_sock ps, int level, int name);
|
||||
static int opt_set(lua_State *L, p_sock ps, int level, int name,
|
||||
void *val, int len);
|
||||
|
||||
/*=========================================================================*\
|
||||
* Exported functions
|
||||
\*=========================================================================*/
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Calls appropriate option handler
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int opt_meth_setoption(lua_State *L, p_opt opt, p_sock ps)
|
||||
{
|
||||
const char *name = luaL_checkstring(L, 2); /* obj, name, ... */
|
||||
while (opt->name && strcmp(name, opt->name))
|
||||
opt++;
|
||||
if (!opt->func) {
|
||||
char msg[45];
|
||||
sprintf(msg, "unsupported option `%.35s'", name);
|
||||
luaL_argerror(L, 2, msg);
|
||||
}
|
||||
return opt->func(L, ps);
|
||||
}
|
||||
|
||||
/* enables reuse of local address */
|
||||
int opt_reuseaddr(lua_State *L, p_sock ps)
|
||||
{
|
||||
return opt_setboolean(L, ps, SOL_SOCKET, SO_REUSEADDR);
|
||||
}
|
||||
|
||||
/* disables the Naggle algorithm */
|
||||
int opt_tcp_nodelay(lua_State *L, p_sock ps)
|
||||
{
|
||||
return opt_setboolean(L, ps, IPPROTO_TCP, TCP_NODELAY);
|
||||
}
|
||||
|
||||
int opt_keepalive(lua_State *L, p_sock ps)
|
||||
{
|
||||
return opt_setboolean(L, ps, SOL_SOCKET, SO_KEEPALIVE);
|
||||
}
|
||||
|
||||
int opt_dontroute(lua_State *L, p_sock ps)
|
||||
{
|
||||
return opt_setboolean(L, ps, SOL_SOCKET, SO_DONTROUTE);
|
||||
}
|
||||
|
||||
int opt_broadcast(lua_State *L, p_sock ps)
|
||||
{
|
||||
return opt_setboolean(L, ps, SOL_SOCKET, SO_BROADCAST);
|
||||
}
|
||||
|
||||
int opt_ip_multicast_loop(lua_State *L, p_sock ps)
|
||||
{
|
||||
return opt_setboolean(L, ps, IPPROTO_IP, IP_MULTICAST_LOOP);
|
||||
}
|
||||
|
||||
int opt_linger(lua_State *L, p_sock ps)
|
||||
{
|
||||
struct linger li; /* obj, name, table */
|
||||
if (!lua_istable(L, 3)) luaL_typerror(L, 3, lua_typename(L, LUA_TTABLE));
|
||||
lua_pushstring(L, "on");
|
||||
lua_gettable(L, 3);
|
||||
if (!lua_isboolean(L, -1))
|
||||
luaL_argerror(L, 3, "boolean 'on' field expected");
|
||||
li.l_onoff = lua_toboolean(L, -1);
|
||||
lua_pushstring(L, "timeout");
|
||||
lua_gettable(L, 3);
|
||||
if (!lua_isnumber(L, -1))
|
||||
luaL_argerror(L, 3, "number 'timeout' field expected");
|
||||
li.l_linger = (int) lua_tonumber(L, -1);
|
||||
return opt_set(L, ps, SOL_SOCKET, SO_LINGER, (char *) &li, sizeof(li));
|
||||
}
|
||||
|
||||
int opt_ip_multicast_ttl(lua_State *L, p_sock ps)
|
||||
{
|
||||
int val = (int) luaL_checknumber(L, 3); /* obj, name, int */
|
||||
return opt_set(L, ps, SOL_SOCKET, SO_LINGER, (char *) &val, sizeof(val));
|
||||
}
|
||||
|
||||
int opt_ip_add_membership(lua_State *L, p_sock ps)
|
||||
{
|
||||
return opt_setmembership(L, ps, IPPROTO_IP, IP_ADD_MEMBERSHIP);
|
||||
}
|
||||
|
||||
int opt_ip_drop_membersip(lua_State *L, p_sock ps)
|
||||
{
|
||||
return opt_setmembership(L, ps, IPPROTO_IP, IP_DROP_MEMBERSHIP);
|
||||
}
|
||||
|
||||
/*=========================================================================*\
|
||||
* Auxiliar functions
|
||||
\*=========================================================================*/
|
||||
static int opt_setmembership(lua_State *L, p_sock ps, int level, int name)
|
||||
{
|
||||
struct ip_mreq val; /* obj, name, table */
|
||||
if (!lua_istable(L, 3)) luaL_typerror(L, 3, lua_typename(L, LUA_TTABLE));
|
||||
lua_pushstring(L, "multiaddr");
|
||||
lua_gettable(L, 3);
|
||||
if (!lua_isstring(L, -1))
|
||||
luaL_argerror(L, 3, "string 'multiaddr' field expected");
|
||||
if (!inet_aton(lua_tostring(L, -1), &val.imr_multiaddr))
|
||||
luaL_argerror(L, 3, "invalid 'multiaddr' ip address");
|
||||
lua_pushstring(L, "interface");
|
||||
lua_gettable(L, 3);
|
||||
if (!lua_isstring(L, -1))
|
||||
luaL_argerror(L, 3, "string 'interface' field expected");
|
||||
val.imr_interface.s_addr = htonl(INADDR_ANY);
|
||||
if (strcmp(lua_tostring(L, -1), "*") &&
|
||||
!inet_aton(lua_tostring(L, -1), &val.imr_interface))
|
||||
luaL_argerror(L, 3, "invalid 'interface' ip address");
|
||||
return opt_set(L, ps, level, name, (char *) &val, sizeof(val));
|
||||
}
|
||||
|
||||
static
|
||||
int opt_set(lua_State *L, p_sock ps, int level, int name, void *val, int len)
|
||||
{
|
||||
if (setsockopt(*ps, level, name, (char *) val, len) < 0) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, "setsockopt failed");
|
||||
return 2;
|
||||
}
|
||||
lua_pushnumber(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int opt_setboolean(lua_State *L, p_sock ps, int level, int name)
|
||||
{
|
||||
int val = aux_checkboolean(L, 3); /* obj, name, bool */
|
||||
return opt_set(L, ps, level, name, (char *) &val, sizeof(val));
|
||||
}
|
||||
|
30
src/options.h
Normal file
30
src/options.h
Normal file
@ -0,0 +1,30 @@
|
||||
#ifndef OPTIONS_H
|
||||
#define OPTIONS_H
|
||||
|
||||
#include <lua.h>
|
||||
#include "socket.h"
|
||||
|
||||
/* option registry */
|
||||
typedef struct t_opt {
|
||||
const char *name;
|
||||
int (*func)(lua_State *L, p_sock ps);
|
||||
} t_opt;
|
||||
typedef t_opt *p_opt;
|
||||
|
||||
/* supported options */
|
||||
int opt_dontroute(lua_State *L, p_sock ps);
|
||||
int opt_broadcast(lua_State *L, p_sock ps);
|
||||
int opt_reuseaddr(lua_State *L, p_sock ps);
|
||||
int opt_tcp_nodelay(lua_State *L, p_sock ps);
|
||||
int opt_keepalive(lua_State *L, p_sock ps);
|
||||
int opt_linger(lua_State *L, p_sock ps);
|
||||
int opt_reuseaddr(lua_State *L, p_sock ps);
|
||||
int opt_ip_multicast_ttl(lua_State *L, p_sock ps);
|
||||
int opt_ip_multicast_loop(lua_State *L, p_sock ps);
|
||||
int opt_ip_add_membership(lua_State *L, p_sock ps);
|
||||
int opt_ip_drop_membersip(lua_State *L, p_sock ps);
|
||||
|
||||
/* invokes the appropriate option handler */
|
||||
int opt_meth_setoption(lua_State *L, p_opt opt, p_sock ps);
|
||||
|
||||
#endif
|
21
src/socket.h
21
src/socket.h
@ -22,6 +22,14 @@
|
||||
#include "usocket.h"
|
||||
#endif
|
||||
|
||||
/*=========================================================================*\
|
||||
* The connect and accept functions accept a timeout and their
|
||||
* implementations are somewhat complicated. We chose to move
|
||||
* the timeout control into this module for these functions in
|
||||
* order to simplify the modules that use them.
|
||||
\*=========================================================================*/
|
||||
#include "timeout.h"
|
||||
|
||||
/* we are lazy... */
|
||||
typedef struct sockaddr SA;
|
||||
|
||||
@ -30,12 +38,7 @@ typedef struct sockaddr SA;
|
||||
* interface to sockets
|
||||
\*=========================================================================*/
|
||||
int sock_open(void);
|
||||
int sock_create(p_sock ps, int domain, int type, int protocol);
|
||||
void sock_destroy(p_sock ps);
|
||||
int sock_accept(p_sock ps, p_sock pa, SA *addr, socklen_t *addr_len,
|
||||
int timeout);
|
||||
int sock_connect(p_sock ps, SA *addr, socklen_t addr_len, int timeout);
|
||||
int sock_bind(p_sock ps, SA *addr, socklen_t addr_len);
|
||||
void sock_listen(p_sock ps, int backlog);
|
||||
void sock_shutdown(p_sock ps, int how);
|
||||
int sock_send(p_sock ps, const char *data, size_t count,
|
||||
@ -48,10 +51,10 @@ int sock_recvfrom(p_sock ps, char *data, size_t count,
|
||||
size_t *got, SA *addr, socklen_t *addr_len, int timeout);
|
||||
void sock_setnonblocking(p_sock ps);
|
||||
void sock_setblocking(p_sock ps);
|
||||
|
||||
int sock_accept(p_sock ps, p_sock pa, 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_bind(p_sock ps, SA *addr, socklen_t addr_len);
|
||||
const char *sock_hoststrerror(void);
|
||||
const char *sock_createstrerror(void);
|
||||
const char *sock_bindstrerror(void);
|
||||
const char *sock_connectstrerror(void);
|
||||
|
||||
#endif /* SOCK_H */
|
||||
|
82
src/tcp.c
82
src/tcp.c
@ -14,6 +14,7 @@
|
||||
#include "auxiliar.h"
|
||||
#include "socket.h"
|
||||
#include "inet.h"
|
||||
#include "options.h"
|
||||
#include "tcp.h"
|
||||
|
||||
/*=========================================================================*\
|
||||
@ -33,10 +34,6 @@ static int meth_setoption(lua_State *L);
|
||||
static int meth_settimeout(lua_State *L);
|
||||
static int meth_fd(lua_State *L);
|
||||
static int meth_dirty(lua_State *L);
|
||||
static int opt_tcp_nodelay(lua_State *L);
|
||||
static int opt_keepalive(lua_State *L);
|
||||
static int opt_linger(lua_State *L);
|
||||
static int opt_reuseaddr(lua_State *L);
|
||||
|
||||
/* tcp object methods */
|
||||
static luaL_reg tcp[] = {
|
||||
@ -60,7 +57,7 @@ static luaL_reg tcp[] = {
|
||||
};
|
||||
|
||||
/* socket option handlers */
|
||||
static luaL_reg opt[] = {
|
||||
static t_opt opt[] = {
|
||||
{"keepalive", opt_keepalive},
|
||||
{"reuseaddr", opt_reuseaddr},
|
||||
{"tcp-nodelay", opt_tcp_nodelay},
|
||||
@ -116,65 +113,12 @@ static int meth_receive(lua_State *L)
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Option handlers
|
||||
* Just call option handler
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int meth_setoption(lua_State *L)
|
||||
{
|
||||
return aux_meth_setoption(L, opt);
|
||||
}
|
||||
|
||||
static int opt_boolean(lua_State *L, int level, int name)
|
||||
{
|
||||
p_tcp tcp = (p_tcp) aux_checkgroup(L, "tcp{any}", 1);
|
||||
int val = aux_checkboolean(L, 2);
|
||||
if (setsockopt(tcp->sock, level, name, (char *) &val, sizeof(val)) < 0) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, "setsockopt failed");
|
||||
return 2;
|
||||
}
|
||||
lua_pushnumber(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* enables reuse of local address */
|
||||
static int opt_reuseaddr(lua_State *L)
|
||||
{
|
||||
return opt_boolean(L, SOL_SOCKET, SO_REUSEADDR);
|
||||
}
|
||||
|
||||
/* disables the Naggle algorithm */
|
||||
static int opt_tcp_nodelay(lua_State *L)
|
||||
{
|
||||
return opt_boolean(L, IPPROTO_TCP, TCP_NODELAY);
|
||||
}
|
||||
|
||||
static int opt_keepalive(lua_State *L)
|
||||
{
|
||||
return opt_boolean(L, SOL_SOCKET, SO_KEEPALIVE);
|
||||
}
|
||||
|
||||
static int opt_linger(lua_State *L)
|
||||
{
|
||||
p_tcp tcp = (p_tcp) aux_checkclass(L, "tcp{client}", 1);
|
||||
struct linger li;
|
||||
if (!lua_istable(L, 2))
|
||||
luaL_typerror(L, 2, lua_typename(L, LUA_TTABLE));
|
||||
lua_pushstring(L, "on");
|
||||
lua_gettable(L, 2);
|
||||
if (!lua_isboolean(L, -1)) luaL_argerror(L, 2, "invalid 'on' field");
|
||||
li.l_onoff = lua_toboolean(L, -1);
|
||||
lua_pushstring(L, "timeout");
|
||||
lua_gettable(L, 2);
|
||||
if (!lua_isnumber(L, -1)) luaL_argerror(L, 2, "invalid 'timeout' field");
|
||||
li.l_linger = (int) lua_tonumber(L, -1);
|
||||
if (setsockopt(tcp->sock, SOL_SOCKET, SO_LINGER,
|
||||
(char *) &li, sizeof(li) < 0)) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, "setsockopt failed");
|
||||
return 2;
|
||||
}
|
||||
lua_pushnumber(L, 1);
|
||||
return 1;
|
||||
p_tcp tcp = aux_checkgroup(L, "tcp{any}", 1);
|
||||
return opt_meth_setoption(L, opt, &tcp->sock);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
@ -201,13 +145,11 @@ static int meth_dirty(lua_State *L)
|
||||
static int meth_accept(lua_State *L)
|
||||
{
|
||||
p_tcp server = (p_tcp) aux_checkclass(L, "tcp{server}", 1);
|
||||
p_tm tm = &server->tm;
|
||||
p_tm tm = tm_markstart(&server->tm);
|
||||
t_sock sock;
|
||||
const char *err;
|
||||
tm_markstart(tm);
|
||||
err = inet_tryaccept(&server->sock, tm, &sock);
|
||||
int err = sock_accept(&server->sock, &sock, NULL, NULL, tm);
|
||||
/* if successful, push client socket */
|
||||
if (!err) {
|
||||
if (err == IO_DONE) {
|
||||
p_tcp clnt = lua_newuserdata(L, sizeof(t_tcp));
|
||||
aux_setclass(L, "tcp{client}", -1);
|
||||
/* initialize structure fields */
|
||||
@ -218,7 +160,7 @@ static int meth_accept(lua_State *L)
|
||||
return 1;
|
||||
} else {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, err);
|
||||
io_pusherror(L, err);
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
@ -252,10 +194,8 @@ static int meth_connect(lua_State *L)
|
||||
p_tcp tcp = (p_tcp) aux_checkclass(L, "tcp{master}", 1);
|
||||
const char *address = luaL_checkstring(L, 2);
|
||||
unsigned short port = (unsigned short) luaL_checknumber(L, 3);
|
||||
p_tm tm = &tcp->tm;
|
||||
const char *err;
|
||||
tm_markstart(tm);
|
||||
err = inet_tryconnect(&tcp->sock, tm, address, port);
|
||||
p_tm tm = tm_markstart(&tcp->tm);
|
||||
const char *err = inet_tryconnect(&tcp->sock, address, port, tm);
|
||||
if (err) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, err);
|
||||
|
@ -28,6 +28,7 @@ typedef struct t_tcp_ {
|
||||
t_buf buf;
|
||||
t_tm tm;
|
||||
} t_tcp;
|
||||
|
||||
typedef t_tcp *p_tcp;
|
||||
|
||||
void tcp_open(lua_State *L);
|
||||
|
@ -114,9 +114,10 @@ int tm_getretry(p_tm tm)
|
||||
* Input
|
||||
* tm: timeout control structure
|
||||
\*-------------------------------------------------------------------------*/
|
||||
void tm_markstart(p_tm tm)
|
||||
p_tm tm_markstart(p_tm tm)
|
||||
{
|
||||
tm->start = tm_gettime();
|
||||
return tm;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
|
@ -20,7 +20,7 @@ void tm_open(lua_State *L);
|
||||
void tm_init(p_tm tm, int block, int total);
|
||||
int tm_get(p_tm tm);
|
||||
int tm_getretry(p_tm tm);
|
||||
void tm_markstart(p_tm tm);
|
||||
p_tm tm_markstart(p_tm tm);
|
||||
int tm_getstart(p_tm tm);
|
||||
int tm_gettime(void);
|
||||
int tm_meth_settimeout(lua_State *L, p_tm tm);
|
||||
|
99
src/udp.c
99
src/udp.c
@ -14,6 +14,7 @@
|
||||
#include "auxiliar.h"
|
||||
#include "socket.h"
|
||||
#include "inet.h"
|
||||
#include "options.h"
|
||||
#include "udp.h"
|
||||
|
||||
/*=========================================================================*\
|
||||
@ -34,13 +35,6 @@ static int meth_setoption(lua_State *L);
|
||||
static int meth_settimeout(lua_State *L);
|
||||
static int meth_fd(lua_State *L);
|
||||
static int meth_dirty(lua_State *L);
|
||||
static int opt_dontroute(lua_State *L);
|
||||
static int opt_broadcast(lua_State *L);
|
||||
static int opt_reuseaddr(lua_State *L);
|
||||
static int opt_ip_multicast_ttl(lua_State *L);
|
||||
static int opt_ip_multicast_loop(lua_State *L);
|
||||
static int opt_ip_add_membership(lua_State *L);
|
||||
static int opt_ip_drop_membersip(lua_State *L);
|
||||
|
||||
/* udp object methods */
|
||||
static luaL_reg udp[] = {
|
||||
@ -63,7 +57,7 @@ static luaL_reg udp[] = {
|
||||
};
|
||||
|
||||
/* socket options */
|
||||
static luaL_reg opt[] = {
|
||||
static t_opt opt[] = {
|
||||
{"dontroute", opt_dontroute},
|
||||
{"broadcast", opt_broadcast},
|
||||
{"reuseaddr", opt_reuseaddr},
|
||||
@ -231,95 +225,12 @@ static int meth_getsockname(lua_State *L)
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Option handlers
|
||||
* Just call option handler
|
||||
\*-------------------------------------------------------------------------*/
|
||||
static int meth_setoption(lua_State *L)
|
||||
{
|
||||
return aux_meth_setoption(L, opt);
|
||||
}
|
||||
|
||||
static int opt_boolean(lua_State *L, int level, int name)
|
||||
{
|
||||
p_udp udp = (p_udp) aux_checkgroup(L, "udp{any}", 1);
|
||||
int val = aux_checkboolean(L, 2);
|
||||
if (setsockopt(udp->sock, level, name, (char *) &val, sizeof(val)) < 0) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, "setsockopt failed");
|
||||
return 2;
|
||||
}
|
||||
lua_pushnumber(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int opt_dontroute(lua_State *L)
|
||||
{
|
||||
return opt_boolean(L, SOL_SOCKET, SO_DONTROUTE);
|
||||
}
|
||||
|
||||
static int opt_reuseaddr(lua_State *L)
|
||||
{
|
||||
return opt_boolean(L, SOL_SOCKET, SO_REUSEADDR);
|
||||
}
|
||||
|
||||
static int opt_broadcast(lua_State *L)
|
||||
{
|
||||
return opt_boolean(L, SOL_SOCKET, SO_BROADCAST);
|
||||
}
|
||||
|
||||
static int opt_ip_multicast_loop(lua_State *L)
|
||||
{
|
||||
return opt_boolean(L, IPPROTO_IP, IP_MULTICAST_LOOP);
|
||||
}
|
||||
|
||||
static int opt_ip_multicast_ttl(lua_State *L)
|
||||
{
|
||||
p_udp udp = (p_udp) aux_checkgroup(L, "udp{any}", 1);
|
||||
int val = (int) luaL_checknumber(L, 2);
|
||||
if (setsockopt(udp->sock, IPPROTO_IP, IP_MULTICAST_TTL,
|
||||
(char *) &val, sizeof(val)) < 0) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, "setsockopt failed");
|
||||
return 2;
|
||||
}
|
||||
lua_pushnumber(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int opt_membership(lua_State *L, int level, int name)
|
||||
{
|
||||
p_udp udp = (p_udp) aux_checkgroup(L, "udp{any}", 1);
|
||||
struct ip_mreq val;
|
||||
if (!lua_istable(L, 2))
|
||||
luaL_typerror(L, 2, lua_typename(L, LUA_TTABLE));
|
||||
lua_pushstring(L, "multiaddr");
|
||||
lua_gettable(L, 2);
|
||||
if (!lua_isstring(L, -1)) luaL_argerror(L, 2, "invalid 'group' field");
|
||||
if (!inet_aton(lua_tostring(L, -1), &val.imr_multiaddr))
|
||||
luaL_argerror(L, 3, "invalid 'multiaddr' ip address");
|
||||
lua_pushstring(L, "interface");
|
||||
lua_gettable(L, 2);
|
||||
if (!lua_isstring(L, -1)) luaL_argerror(L, 2, "invalid 'interface' field");
|
||||
val.imr_interface.s_addr = htonl(INADDR_ANY);
|
||||
if (strcmp(lua_tostring(L, -1), "*") &&
|
||||
!inet_aton(lua_tostring(L, -1), &val.imr_interface))
|
||||
luaL_argerror(L, 3, "invalid 'interface' ip address");
|
||||
if (setsockopt(udp->sock, level, name, (char *) &val, sizeof(val)) < 0) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, "setsockopt failed");
|
||||
return 2;
|
||||
}
|
||||
lua_pushnumber(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int opt_ip_add_membership(lua_State *L)
|
||||
{
|
||||
return opt_membership(L, IPPROTO_IP, IP_ADD_MEMBERSHIP);
|
||||
}
|
||||
|
||||
static int opt_ip_drop_membersip(lua_State *L)
|
||||
{
|
||||
return opt_membership(L, IPPROTO_IP, IP_DROP_MEMBERSHIP);
|
||||
return opt_meth_setoption(L, opt, &udp->sock);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
@ -343,7 +254,7 @@ static int meth_setpeername(lua_State *L)
|
||||
unsigned short port = connecting ?
|
||||
(unsigned short) luaL_checknumber(L, 3) :
|
||||
(unsigned short) luaL_optnumber(L, 3, 0);
|
||||
const char *err = inet_tryconnect(&udp->sock, tm, address, port);
|
||||
const char *err = inet_tryconnect(&udp->sock, address, port, tm);
|
||||
if (err) {
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, err);
|
||||
|
@ -20,6 +20,10 @@
|
||||
|
||||
#include "socket.h"
|
||||
|
||||
static const char *sock_createstrerror(void);
|
||||
static const char *sock_bindstrerror(void);
|
||||
static const char *sock_connectstrerror(void);
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Initializes module
|
||||
\*-------------------------------------------------------------------------*/
|
||||
@ -50,31 +54,37 @@ void sock_destroy(p_sock ps)
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Creates and sets up a socket
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int sock_create(p_sock ps, int domain, int type, int protocol)
|
||||
const char *sock_create(p_sock ps, int domain, int type, int protocol)
|
||||
{
|
||||
int val = 1;
|
||||
t_sock sock = socket(domain, type, protocol);
|
||||
if (sock == SOCK_INVALID) return IO_ERROR;
|
||||
if (sock == SOCK_INVALID) return sock_createstrerror();
|
||||
*ps = sock;
|
||||
sock_setnonblocking(ps);
|
||||
setsockopt(*ps, SOL_SOCKET, SO_REUSEADDR, (char *) &val, sizeof(val));
|
||||
return IO_DONE;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Connects or returns error message
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int sock_connect(p_sock ps, SA *addr, socklen_t addr_len, int timeout)
|
||||
const char *sock_connect(p_sock ps, SA *addr, socklen_t addr_len, p_tm tm)
|
||||
{
|
||||
t_sock sock = *ps;
|
||||
if (sock == SOCK_INVALID) return IO_CLOSED;
|
||||
/* if connect fails, we have to find out why */
|
||||
if (connect(sock, addr, addr_len) < 0) {
|
||||
int err;
|
||||
/* don't call on closed socket */
|
||||
if (sock == SOCK_INVALID) return io_strerror(IO_CLOSED);
|
||||
/* ask system to connect */
|
||||
err = connect(sock, addr, addr_len);
|
||||
/* if no error, we're done */
|
||||
if (err == 0) return NULL;
|
||||
/* make sure the system is trying to connect */
|
||||
if (errno != EINPROGRESS) return io_strerror(IO_ERROR);
|
||||
/* wait for a timeout or for the system's answer */
|
||||
for ( ;; ) {
|
||||
struct timeval tv;
|
||||
fd_set rfds, efds, wfds;
|
||||
int err;
|
||||
/* make sure the system is trying to connect */
|
||||
if (errno != EINPROGRESS) return IO_ERROR;
|
||||
fd_set rfds, wfds, efds;
|
||||
int timeout = tm_getretry(tm);
|
||||
tv.tv_sec = timeout / 1000;
|
||||
tv.tv_usec = (timeout % 1000) * 1000;
|
||||
FD_ZERO(&rfds); FD_SET(sock, &rfds);
|
||||
@ -82,28 +92,29 @@ int sock_connect(p_sock ps, SA *addr, socklen_t addr_len, int timeout)
|
||||
FD_ZERO(&efds); FD_SET(sock, &efds);
|
||||
/* we run select to avoid busy waiting */
|
||||
err = select(sock+1, &rfds, &wfds, &efds, timeout >= 0? &tv: NULL);
|
||||
/* if select was interrupted, ask the user to retry */
|
||||
if (err < 0 && errno == EINTR) return IO_RETRY;
|
||||
/* if select was interrupted, try again */
|
||||
if (err < 0 && errno == EINTR) continue;
|
||||
/* if selects readable, try reading */
|
||||
if (err > 0) {
|
||||
char dummy;
|
||||
/* try reading so that errno is set */
|
||||
/* recv will set errno to the value a blocking connect would set */
|
||||
if (recv(sock, &dummy, 0, 0) < 0 && errno != EAGAIN)
|
||||
return IO_ERROR;
|
||||
else return IO_DONE;
|
||||
return sock_connectstrerror();
|
||||
else
|
||||
return NULL;
|
||||
/* if no event happened, there was a timeout */
|
||||
} else return IO_TIMEOUT;
|
||||
/* otherwise connection succeeded */
|
||||
} else return IO_DONE;
|
||||
} else return io_strerror(IO_TIMEOUT);
|
||||
}
|
||||
return io_strerror(IO_TIMEOUT); /* can't get here */
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Binds or returns error message
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int sock_bind(p_sock ps, SA *addr, socklen_t addr_len)
|
||||
const char *sock_bind(p_sock ps, SA *addr, socklen_t addr_len)
|
||||
{
|
||||
if (bind(*ps, addr, addr_len) < 0) return IO_ERROR;
|
||||
else return IO_DONE;
|
||||
if (bind(*ps, addr, addr_len) < 0) return sock_bindstrerror();
|
||||
else return NULL;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
@ -125,8 +136,7 @@ void sock_shutdown(p_sock ps, int how)
|
||||
/*-------------------------------------------------------------------------*\
|
||||
* Accept with timeout
|
||||
\*-------------------------------------------------------------------------*/
|
||||
int sock_accept(p_sock ps, p_sock pa, SA *addr, socklen_t *addr_len,
|
||||
int timeout)
|
||||
int sock_accept(p_sock ps, p_sock pa, SA *addr, socklen_t *addr_len, p_tm tm)
|
||||
{
|
||||
t_sock sock = *ps;
|
||||
SA dummy_addr;
|
||||
@ -134,19 +144,21 @@ int sock_accept(p_sock ps, p_sock pa, SA *addr, socklen_t *addr_len,
|
||||
if (sock == SOCK_INVALID) return IO_CLOSED;
|
||||
if (!addr) addr = &dummy_addr;
|
||||
if (!addr_len) addr_len = &dummy_len;
|
||||
*pa = accept(sock, addr, addr_len);
|
||||
if (*pa == SOCK_INVALID) {
|
||||
for (;;) {
|
||||
int timeout = tm_getretry(tm);
|
||||
struct timeval tv;
|
||||
fd_set fds;
|
||||
*pa = accept(sock, addr, addr_len);
|
||||
if (*pa != SOCK_INVALID) return IO_DONE;
|
||||
if (timeout == 0) return IO_TIMEOUT;
|
||||
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 */
|
||||
/* call select just to avoid busy-wait. */
|
||||
select(sock+1, &fds, NULL, NULL, timeout >= 0? &tv: NULL);
|
||||
return IO_RETRY;
|
||||
} else return IO_DONE;
|
||||
}
|
||||
return IO_TIMEOUT; /* can't get here */
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*\
|
||||
@ -314,7 +326,7 @@ const char *sock_hoststrerror(void)
|
||||
}
|
||||
}
|
||||
|
||||
const char *sock_createstrerror(void)
|
||||
static const char *sock_createstrerror(void)
|
||||
{
|
||||
switch (errno) {
|
||||
case EACCES: return "access denied";
|
||||
@ -325,7 +337,7 @@ const char *sock_createstrerror(void)
|
||||
}
|
||||
}
|
||||
|
||||
const char *sock_bindstrerror(void)
|
||||
static const char *sock_bindstrerror(void)
|
||||
{
|
||||
switch (errno) {
|
||||
case EBADF: return "invalid descriptor";
|
||||
@ -339,7 +351,7 @@ const char *sock_bindstrerror(void)
|
||||
}
|
||||
}
|
||||
|
||||
const char *sock_connectstrerror(void)
|
||||
static const char *sock_connectstrerror(void)
|
||||
{
|
||||
switch (errno) {
|
||||
case EBADF: return "invalid descriptor";
|
||||
|
@ -49,8 +49,7 @@ local check_result = function(response, expect, ignore)
|
||||
for i,v in response do
|
||||
if not ignore[i] then
|
||||
if v ~= expect[i] then
|
||||
v = string.sub(type(v) == "string" and v or "", 1, 70)
|
||||
print(v)
|
||||
print(string.sub(tostring(v), 1, 70))
|
||||
fail(i .. " differs!")
|
||||
end
|
||||
end
|
||||
@ -59,7 +58,7 @@ local check_result = function(response, expect, ignore)
|
||||
if not ignore[i] then
|
||||
if v ~= response[i] then
|
||||
v = string.sub(type(v) == "string" and v or "", 1, 70)
|
||||
print(v)
|
||||
print(string.sub(tostring(v), 1, 70))
|
||||
fail(i .. " differs!")
|
||||
end
|
||||
end
|
||||
|
@ -378,6 +378,19 @@ function connect_timeout()
|
||||
c:close()
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------
|
||||
function rebind_test()
|
||||
local c = socket.bind("localhost", 0)
|
||||
local i, p = c:getsockname()
|
||||
local s, e = socket.tcp()
|
||||
assert(s, e)
|
||||
s:setoption("reuseaddr", false)
|
||||
r, e = s:bind("localhost", p)
|
||||
assert(not r, "managed to rebind!")
|
||||
assert(e == "address already in use")
|
||||
print("ok")
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------
|
||||
test("method registration")
|
||||
test_methods(socket.tcp(), {
|
||||
@ -416,6 +429,9 @@ test_selectbugs()
|
||||
test("empty host connect: ")
|
||||
empty_connect()
|
||||
|
||||
test("rebinding: ")
|
||||
rebind_test()
|
||||
|
||||
test("active close: ")
|
||||
active_close()
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user