Add. acceptfd method.

socket.tcp can accept fd and socket type ('master'(default), 'client')

acceptfd method can be used to write multi-threaded server.
```lua
-- main thread
local fd = srv_sock:acceptfd()
Threads.runfile('echo.lua', fd)

-- echo.lua
local fd = ...
local sock = socket.tcp(fd,'client')
```

or to interact with library such as [ESL](http://wiki.freeswitch.org/wiki/Event_Socket_Library)
```lua
local fd = srv_sock:acceptfd()
Threads.runfile('worker.lua', fd)

-- worker.lua
local sock = ESLconnection((...))
```

If we need just close fd (for example we can not run worker thread) we should call `socket.tcp(fd,'client'):close()`
This commit is contained in:
moteus 2013-05-30 10:55:13 +04:00
parent 5341131cd0
commit addee9d8fb
2 changed files with 59 additions and 2 deletions

View File

@ -3,6 +3,7 @@
* LuaSocket toolkit
\*=========================================================================*/
#include <string.h>
#include <assert.h>
#include "lua.h"
#include "lauxlib.h"
@ -31,6 +32,7 @@ static int meth_getpeername(lua_State *L);
static int meth_shutdown(lua_State *L);
static int meth_receive(lua_State *L);
static int meth_accept(lua_State *L);
static int meth_acceptfd(lua_State *L);
static int meth_close(lua_State *L);
static int meth_getoption(lua_State *L);
static int meth_setoption(lua_State *L);
@ -44,6 +46,7 @@ static luaL_Reg tcp_methods[] = {
{"__gc", meth_close},
{"__tostring", auxiliar_tostring},
{"accept", meth_accept},
{"acceptfd", meth_acceptfd},
{"bind", meth_bind},
{"close", meth_close},
{"connect", meth_connect},
@ -213,6 +216,28 @@ static int meth_accept(lua_State *L)
}
}
/*-------------------------------------------------------------------------*\
* Waits for and returns a client object attempting connection to the
* server object
\*-------------------------------------------------------------------------*/
static int meth_acceptfd(lua_State *L)
{
p_tcp server = (p_tcp) auxiliar_checkclass(L, "tcp{server}", 1);
p_timeout tm = timeout_markstart(&server->tm);
t_socket sock;
const char *err = inet_tryaccept(&server->sock, server->family, &sock, tm);
/* if successful, push client socket */
if (err == NULL) {
lua_pushnumber(L, sock);
assert((t_socket)lua_tonumber(L, -1) == sock); // do we need check at runtime?
return 1;
} else {
lua_pushnil(L);
lua_pushstring(L, err);
return 2;
}
}
/*-------------------------------------------------------------------------*\
* Binds an object to an address
\*-------------------------------------------------------------------------*/
@ -356,14 +381,24 @@ static int meth_settimeout(lua_State *L)
\*-------------------------------------------------------------------------*/
static int tcp_create(lua_State *L, int family) {
t_socket sock;
const char *err = inet_trycreate(&sock, family, SOCK_STREAM);
const char *err;
const int is_inherite = lua_isnumber(L,1);
const char *obj_type = "tcp{master}";
if (is_inherite){
err = NULL;
sock = (t_socket)lua_tonumber(L, 1);
if(strstr(luaL_optstring(L,2,""),"client"))
obj_type = "tcp{client}";
}
else
err = inet_trycreate(&sock, family, SOCK_STREAM);
/* try to allocate a system socket */
if (!err) {
/* allocate tcp object */
p_tcp tcp = (p_tcp) lua_newuserdata(L, sizeof(t_tcp));
memset(tcp, 0, sizeof(t_tcp));
/* set its type as master object */
auxiliar_setclass(L, "tcp{master}", -1);
auxiliar_setclass(L, obj_type, -1);
/* initialize remaining structure fields */
socket_setnonblocking(&sock);
if (family == PF_INET6) {

22
test/test_acceptfd.lua Normal file
View File

@ -0,0 +1,22 @@
local socket = require "socket"
local host, port = "127.0.0.1", "5462"
local srv = assert(socket.bind(host, port))
local sock = socket.tcp()
assert(sock:connect(host, port))
local fd = assert(srv:acceptfd())
assert(type(fd) == "number")
local cli = assert(socket.tcp(fd, "client"))
assert(5 == assert(cli:send("hello")))
assert("hello" == assert(sock:receive(5)))
cli:close()
sock:close()
srv:close()
print("done!")