mirror of
https://github.com/lunarmodules/luasocket.git
synced 2024-12-26 04:28:20 +01:00
Added support to UDP socket options.
This commit is contained in:
parent
561177a1dd
commit
8c6473577d
216
src/luasocket.c
216
src/luasocket.c
@ -159,7 +159,7 @@ static int global_tohostname(lua_State *L);
|
|||||||
static int global_udpsocket(lua_State *L);
|
static int global_udpsocket(lua_State *L);
|
||||||
|
|
||||||
#ifndef LUASOCKET_NOGLOBALS
|
#ifndef LUASOCKET_NOGLOBALS
|
||||||
static int global_calltable(lua_State *L);
|
static int global_callfromtable(lua_State *L);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* luasocket table method API functions */
|
/* luasocket table method API functions */
|
||||||
@ -219,6 +219,7 @@ static const char *udp_setpeername(p_sock sock, const char *address,
|
|||||||
unsigned short port);
|
unsigned short port);
|
||||||
static const char *udp_setsockname(p_sock sock, const char *address,
|
static const char *udp_setsockname(p_sock sock, const char *address,
|
||||||
unsigned short port);
|
unsigned short port);
|
||||||
|
static int set_option(lua_State *L, p_sock sock);
|
||||||
static void set_reuseaddr(p_sock sock);
|
static void set_reuseaddr(p_sock sock);
|
||||||
static void set_blocking(p_sock sock);
|
static void set_blocking(p_sock sock);
|
||||||
static void set_nonblocking(p_sock sock);
|
static void set_nonblocking(p_sock sock);
|
||||||
@ -305,8 +306,6 @@ static int global_tcpconnect(lua_State *L)
|
|||||||
|
|
||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Creates a udp socket object and returns it to the Lua script.
|
* Creates a udp socket object and returns it to the Lua script.
|
||||||
* The timeout values are initialized as -1 so that the socket will block
|
|
||||||
* at any IO operation.
|
|
||||||
* Lua Returns
|
* Lua Returns
|
||||||
* On success: udp socket
|
* On success: udp socket
|
||||||
* On error: nil, followed by an error message
|
* On error: nil, followed by an error message
|
||||||
@ -314,8 +313,16 @@ static int global_tcpconnect(lua_State *L)
|
|||||||
static int global_udpsocket(lua_State *L)
|
static int global_udpsocket(lua_State *L)
|
||||||
{
|
{
|
||||||
p_tags tags = pop_tags(L);
|
p_tags tags = pop_tags(L);
|
||||||
|
int top = lua_gettop(L);
|
||||||
p_sock sock = push_udptable(L, tags);
|
p_sock sock = push_udptable(L, tags);
|
||||||
if (!sock) return 2;
|
if (!sock) return 2;
|
||||||
|
if (top >= 1 && lua_istable(L, 1)) {
|
||||||
|
lua_pushnil(L);
|
||||||
|
while (lua_next(L, 1)) {
|
||||||
|
if (!set_option(L, sock)) lua_error(L, "invalid socket option");
|
||||||
|
lua_pop(L, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -483,8 +490,8 @@ static int table_tcpsend(lua_State *L)
|
|||||||
for (arg = 2; arg <= top; arg++) { /* skip self table */
|
for (arg = 2; arg <= top; arg++) { /* skip self table */
|
||||||
int sent;
|
int sent;
|
||||||
size_t wanted;
|
size_t wanted;
|
||||||
const char *data = luaL_opt_lstr(L, arg, NULL, &wanted);
|
const char *data = luaL_opt_lstr(L, arg, NULL, &wanted);
|
||||||
if (!data || err != NET_DONE) break;
|
if (!data || err != NET_DONE) break;
|
||||||
err = send_raw(sock, data, wanted, &sent);
|
err = send_raw(sock, data, wanted, &sent);
|
||||||
total += sent;
|
total += sent;
|
||||||
}
|
}
|
||||||
@ -542,14 +549,14 @@ static int table_udpsendto(lua_State *L)
|
|||||||
* Global function that calls corresponding table method.
|
* Global function that calls corresponding table method.
|
||||||
\*-------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------*/
|
||||||
#ifndef LUASOCKET_NOGLOBALS
|
#ifndef LUASOCKET_NOGLOBALS
|
||||||
int global_calltable(lua_State *L)
|
int global_callfromtable(lua_State *L)
|
||||||
{
|
{
|
||||||
p_tags tags = pop_tags(L);
|
p_tags tags = pop_tags(L);
|
||||||
if (lua_tag(L, 1) != tags->table) lua_error(L, "invalid socket object");
|
if (lua_tag(L, 1) != tags->table) lua_error(L, "invalid socket object");
|
||||||
lua_gettable(L, 1);
|
lua_gettable(L, 1);
|
||||||
lua_insert(L, 1);
|
lua_insert(L, 1);
|
||||||
lua_call(L, lua_gettop(L)-1, LUA_MULTRET);
|
lua_call(L, lua_gettop(L)-1, LUA_MULTRET);
|
||||||
return lua_gettop(L);
|
return lua_gettop(L);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -571,8 +578,8 @@ int global_select(lua_State *L)
|
|||||||
fd_set readfds, *prfds = NULL, writefds, *pwfds = NULL;
|
fd_set readfds, *prfds = NULL, writefds, *pwfds = NULL;
|
||||||
struct timeval tm, *ptm = NULL;
|
struct timeval tm, *ptm = NULL;
|
||||||
int ret;
|
int ret;
|
||||||
unsigned max = 0;
|
unsigned max = 0;
|
||||||
SOCKET s;
|
SOCKET s;
|
||||||
int byfds, canread, canwrite;
|
int byfds, canread, canwrite;
|
||||||
/* reset the file descriptor sets */
|
/* reset the file descriptor sets */
|
||||||
FD_ZERO(&readfds); FD_ZERO(&writefds);
|
FD_ZERO(&readfds); FD_ZERO(&writefds);
|
||||||
@ -588,25 +595,25 @@ int global_select(lua_State *L)
|
|||||||
while (lua_next(L, 1)) {
|
while (lua_next(L, 1)) {
|
||||||
if (lua_tag(L, -1) == tags->table) { /* skip strange fields */
|
if (lua_tag(L, -1) == tags->table) { /* skip strange fields */
|
||||||
p_sock sock = get_sock(L, -1, tags, NULL);
|
p_sock sock = get_sock(L, -1, tags, NULL);
|
||||||
if (sock->sock != INVALID_SOCKET) { /* skip closed sockets */
|
if (sock->sock != INVALID_SOCKET) { /* skip closed sockets */
|
||||||
lua_pushnumber(L, sock->sock);
|
lua_pushnumber(L, sock->sock);
|
||||||
lua_pushvalue(L, -2);
|
lua_pushvalue(L, -2);
|
||||||
lua_settable(L, byfds);
|
lua_settable(L, byfds);
|
||||||
if (sock->sock > max) max = sock->sock;
|
if (sock->sock > max) max = sock->sock;
|
||||||
/* a socket can have unread data in our internal
|
/* a socket can have unread data in our internal
|
||||||
buffer. in that case, we only call select to find
|
buffer. in that case, we only call select to find
|
||||||
out which of the other sockets can be written to
|
out which of the other sockets can be written to
|
||||||
or read from immediately. */
|
or read from immediately. */
|
||||||
if (!bf_isempty(sock)) {
|
if (!bf_isempty(sock)) {
|
||||||
ms = 0;
|
ms = 0;
|
||||||
lua_pushnumber(L, lua_getn(L, canread) + 1);
|
lua_pushnumber(L, lua_getn(L, canread) + 1);
|
||||||
lua_pushvalue(L, -2);
|
lua_pushvalue(L, -2);
|
||||||
lua_settable(L, canread);
|
lua_settable(L, canread);
|
||||||
} else {
|
} else {
|
||||||
FD_SET(sock->sock, &readfds);
|
FD_SET(sock->sock, &readfds);
|
||||||
prfds = &readfds;
|
prfds = &readfds;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* get rid of lua_next value and expose index */
|
/* get rid of lua_next value and expose index */
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
@ -618,14 +625,14 @@ int global_select(lua_State *L)
|
|||||||
while (lua_next(L, 2)) {
|
while (lua_next(L, 2)) {
|
||||||
if (lua_tag(L, -1) == tags->table) { /* skip strange fields */
|
if (lua_tag(L, -1) == tags->table) { /* skip strange fields */
|
||||||
p_sock sock = get_sock(L, -1, tags, NULL);
|
p_sock sock = get_sock(L, -1, tags, NULL);
|
||||||
if (sock->sock != INVALID_SOCKET) { /* skip closed sockets */
|
if (sock->sock != INVALID_SOCKET) { /* skip closed sockets */
|
||||||
lua_pushnumber(L, sock->sock);
|
lua_pushnumber(L, sock->sock);
|
||||||
lua_pushvalue(L, -2);
|
lua_pushvalue(L, -2);
|
||||||
lua_settable(L, byfds);
|
lua_settable(L, byfds);
|
||||||
if (sock->sock > max) max = sock->sock;
|
if (sock->sock > max) max = sock->sock;
|
||||||
FD_SET(sock->sock, &writefds);
|
FD_SET(sock->sock, &writefds);
|
||||||
pwfds = &writefds;
|
pwfds = &writefds;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* get rid of lua_next value and expose index */
|
/* get rid of lua_next value and expose index */
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
@ -1049,6 +1056,61 @@ void set_reuseaddr(p_sock sock)
|
|||||||
setsockopt(sock->sock, SOL_SOCKET, SO_REUSEADDR, (char *)&val, sizeof(val));
|
setsockopt(sock->sock, SOL_SOCKET, SO_REUSEADDR, (char *)&val, sizeof(val));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------------*\
|
||||||
|
* Set socket options from a table on top of Lua stack.
|
||||||
|
* Supports SO_KEEPALIVE, SO_DONTROUTE, SO_BROADCAST, and SO_LINGER options.
|
||||||
|
* Input
|
||||||
|
* L: Lua state to use
|
||||||
|
* sock: socket to set option
|
||||||
|
* Returns
|
||||||
|
* 1 if successful, 0 otherwise
|
||||||
|
\*-------------------------------------------------------------------------*/
|
||||||
|
static int set_option(lua_State *L, p_sock sock)
|
||||||
|
{
|
||||||
|
static const char *const optionnames[] = {
|
||||||
|
"SO_KEEPALIVE", "SO_DONTROUTE", "SO_BROADCAST", "SO_LINGER", NULL
|
||||||
|
};
|
||||||
|
const char *option = lua_tostring(L, -2);
|
||||||
|
int err;
|
||||||
|
switch (luaL_findstring(option, optionnames)) {
|
||||||
|
case 0: {
|
||||||
|
int bool = (int) lua_tonumber(L, -1);
|
||||||
|
err = setsockopt(sock->sock, SOL_SOCKET, SO_KEEPALIVE, &bool,
|
||||||
|
sizeof(bool));
|
||||||
|
return err >= 0;
|
||||||
|
}
|
||||||
|
case 1: {
|
||||||
|
int bool = (int) lua_tonumber(L, -1);
|
||||||
|
err = setsockopt(sock->sock, SOL_SOCKET, SO_DONTROUTE, &bool,
|
||||||
|
sizeof(bool));
|
||||||
|
return err >= 0;
|
||||||
|
}
|
||||||
|
case 2: {
|
||||||
|
int bool = (int) lua_tonumber(L, -1);
|
||||||
|
err = setsockopt(sock->sock, SOL_SOCKET, SO_BROADCAST, &bool,
|
||||||
|
sizeof(bool));
|
||||||
|
return err >= 0;
|
||||||
|
}
|
||||||
|
case 3: {
|
||||||
|
struct linger linger;
|
||||||
|
if (!lua_istable(L, -1)) return 0;
|
||||||
|
lua_pushstring(L, "l_onoff");
|
||||||
|
lua_gettable(L, -2);
|
||||||
|
linger.l_onoff = lua_tonumber(L, -1);
|
||||||
|
lua_pop(L, 1);
|
||||||
|
lua_pushstring(L, "l_linger");
|
||||||
|
lua_gettable(L, -2);
|
||||||
|
linger.l_linger = lua_tonumber(L, -1);
|
||||||
|
lua_pop(L, 1);
|
||||||
|
err = setsockopt(sock->sock, SOL_SOCKET, SO_LINGER, &linger,
|
||||||
|
sizeof(linger));
|
||||||
|
return err >= 0;
|
||||||
|
}
|
||||||
|
default: return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------*\
|
||||||
* Tries to create a TCP socket and bind it to (address, port)
|
* Tries to create a TCP socket and bind it to (address, port)
|
||||||
* Input
|
* Input
|
||||||
@ -1462,20 +1524,20 @@ static int receive_dosline(lua_State *L, p_sock sock)
|
|||||||
}
|
}
|
||||||
buffer = bf_receive(sock, &got);
|
buffer = bf_receive(sock, &got);
|
||||||
if (got <= 0) {
|
if (got <= 0) {
|
||||||
luaL_pushresult(&b);
|
luaL_pushresult(&b);
|
||||||
return NET_CLOSED;
|
return NET_CLOSED;
|
||||||
}
|
}
|
||||||
pos = 0;
|
pos = 0;
|
||||||
while (pos < got && buffer[pos] != '\n') {
|
while (pos < got && buffer[pos] != '\n') {
|
||||||
/* we ignore all \r's */
|
/* we ignore all \r's */
|
||||||
if (buffer[pos] != '\r') luaL_putchar(&b, buffer[pos]);
|
if (buffer[pos] != '\r') luaL_putchar(&b, buffer[pos]);
|
||||||
pos++;
|
pos++;
|
||||||
}
|
}
|
||||||
if (pos < got) {
|
if (pos < got) {
|
||||||
luaL_pushresult(&b);
|
luaL_pushresult(&b);
|
||||||
bf_skip(sock, pos+1); /* skip '\n' too */
|
bf_skip(sock, pos+1); /* skip '\n' too */
|
||||||
return NET_DONE;
|
return NET_DONE;
|
||||||
} else bf_skip(sock, pos);
|
} else bf_skip(sock, pos);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1501,17 +1563,17 @@ static int receive_unixline(lua_State *L, p_sock sock)
|
|||||||
}
|
}
|
||||||
buffer = bf_receive(sock, &got);
|
buffer = bf_receive(sock, &got);
|
||||||
if (got <= 0) {
|
if (got <= 0) {
|
||||||
luaL_pushresult(&b);
|
luaL_pushresult(&b);
|
||||||
return NET_CLOSED;
|
return NET_CLOSED;
|
||||||
}
|
}
|
||||||
pos = 0;
|
pos = 0;
|
||||||
while (pos < got && buffer[pos] != '\n') pos++;
|
while (pos < got && buffer[pos] != '\n') pos++;
|
||||||
luaL_addlstring(&b, buffer, pos);
|
luaL_addlstring(&b, buffer, pos);
|
||||||
if (pos < got) {
|
if (pos < got) {
|
||||||
luaL_pushresult(&b);
|
luaL_pushresult(&b);
|
||||||
bf_skip(sock, pos+1); /* skip '\n' too */
|
bf_skip(sock, pos+1); /* skip '\n' too */
|
||||||
return NET_DONE;
|
return NET_DONE;
|
||||||
} else bf_skip(sock, pos);
|
} else bf_skip(sock, pos);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1545,7 +1607,7 @@ static int receive_word(lua_State *L, p_sock sock)
|
|||||||
bf_skip(sock, pos);
|
bf_skip(sock, pos);
|
||||||
if (pos < got) {
|
if (pos < got) {
|
||||||
buffer += pos;
|
buffer += pos;
|
||||||
got -= pos;
|
got -= pos;
|
||||||
pos = 0;
|
pos = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1620,20 +1682,20 @@ void lua_socketlibopen(lua_State *L)
|
|||||||
lua_pushcfunction(L, global_time); lua_setglobal(L, "time");
|
lua_pushcfunction(L, global_time); lua_setglobal(L, "time");
|
||||||
#endif
|
#endif
|
||||||
#ifndef LUASOCKET_NOGLOBALS
|
#ifndef LUASOCKET_NOGLOBALS
|
||||||
{
|
{
|
||||||
char *global[] = {
|
char *global[] = {
|
||||||
"accept", "close", "getpeername",
|
"accept", "close", "getpeername",
|
||||||
"getsockname", "receive", "send",
|
"getsockname", "receive", "send",
|
||||||
"receivefrom", "sendto"
|
"receivefrom", "sendto"
|
||||||
};
|
};
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
for (i = 0; i < sizeof(global)/sizeof(char *); i++) {
|
for (i = 0; i < sizeof(global)/sizeof(char *); i++) {
|
||||||
lua_pushstring(L, global[i]);
|
lua_pushstring(L, global[i]);
|
||||||
lua_pushuserdata(L, tags);
|
lua_pushuserdata(L, tags);
|
||||||
lua_pushcclosure(L, global_calltable, 2);
|
lua_pushcclosure(L, global_callfromtable, 2);
|
||||||
lua_setglobal(L, global[i]);
|
lua_setglobal(L, global[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user