diff options
author | Emil Renner Berthing <esmil@mailme.dk> | 2013-01-05 22:26:36 +0100 |
---|---|---|
committer | Emil Renner Berthing <esmil@mailme.dk> | 2013-01-06 20:46:37 +0100 |
commit | 72400068a26edb6f2d88f62a70d2023d2a19a03c (patch) | |
tree | 44f6834f1b25095f2a051f2383a31d86cc6c2c6e | |
parent | 62c631fd7d5d5c66694af9266688851ac442508a (diff) | |
download | lem-72400068a26edb6f2d88f62a70d2023d2a19a03c.tar.gz lem-72400068a26edb6f2d88f62a70d2023d2a19a03c.tar.xz lem-72400068a26edb6f2d88f62a70d2023d2a19a03c.zip |
io/tcp: add MultiServer wrapper
..to easily liston on both IPv4 and IPv6
-rw-r--r-- | lem/io.lua | 69 | ||||
-rw-r--r-- | lem/io/core.c | 10 | ||||
-rw-r--r-- | lem/io/tcp.c | 32 | ||||
-rwxr-xr-x | test/ctest.lua | 2 | ||||
-rwxr-xr-x | test/stest.lua | 2 |
5 files changed, 103 insertions, 12 deletions
@@ -16,7 +16,8 @@ -- along with LEM. If not, see <http://www.gnu.org/licenses/>. -- -local io = require 'lem.io.core' +local utils = require 'lem.utils' +local io = require 'lem.io.core' local type = type local assert = assert @@ -88,6 +89,72 @@ do end end +do + local MultiServer = {} + MultiServer.__index = MultiServer + io.MultiServer = MultiServer + + function MultiServer:interrupt() + return self[1]:interrupt() + end + + function MultiServer:close() + local rok, rerr = true + for i = 1, #self do + local ok, err = self[i]:close() + if not ok then + rok, rerr = ok, err + end + end + return rok, rerr + end + + + local function autospawn(self, i, handler) + local ok, err = self[i]:autospawn(handler) + if self.running then + self.running, self.ok, self.err = false, ok, err + end + for i = 1, #self do + self[i]:interrupt() + end + end + + local spawn = utils.spawn + + function MultiServer:autospawn(handler) + local n = #self + + self.running = true + for i = 1, n-1 do + spawn(autospawn, self, i, handler) + end + autospawn(self, n, handler) + + return self.ok, self.err + end + + local setmetatable = setmetatable + local listen4, listen6 = io.tcp.listen4, io.tcp.listen6 + + function io.tcp.listen(host, port) + if host:match(':') then + return listen6(host, port) + end + + local s6, err = listen6(host, port) + if s6 then + local s4 = listen4(host, port) + if s4 then + return setmetatable({ s6, s4 }, MultiServer) + end + return s6 + else + return listen4(host, port) + end + end +end + return io -- vim: ts=2 sw=2 noet: diff --git a/lem/io/core.c b/lem/io/core.c index dffbe5c..83ac5bf 100644 --- a/lem/io/core.c +++ b/lem/io/core.c @@ -351,10 +351,14 @@ luaopen_lem_io_core(lua_State *L) lua_getfield(L, -2, "Stream"); /* upvalue 1 = Stream */ lua_pushcclosure(L, tcp_connect, 1); lua_setfield(L, -2, "connect"); - /* insert the listen function */ + /* insert the listen4 function */ lua_getfield(L, -2, "Server"); /* upvalue 1 = Server */ - lua_pushcclosure(L, tcp_listen, 1); - lua_setfield(L, -2, "listen"); + lua_pushcclosure(L, tcp_listen4, 1); + lua_setfield(L, -2, "listen4"); + /* insert the listen6 function */ + lua_getfield(L, -2, "Server"); /* upvalue 1 = Server */ + lua_pushcclosure(L, tcp_listen6, 1); + lua_setfield(L, -2, "listen6"); /* insert the tcp table */ lua_setfield(L, -2, "tcp"); diff --git a/lem/io/tcp.c b/lem/io/tcp.c index 2a209b2..481563f 100644 --- a/lem/io/tcp.c +++ b/lem/io/tcp.c @@ -176,8 +176,8 @@ tcp_listen_work(struct lem_async *a) { struct tcp_getaddr *g = (struct tcp_getaddr *)a; struct addrinfo hints = { - .ai_flags = AI_CANONNAME | AI_PASSIVE, - .ai_family = tcp_famnumber[g->sock], + .ai_flags = AI_PASSIVE, + .ai_family = g->sock, .ai_socktype = SOCK_STREAM, .ai_protocol = IPPROTO_TCP, .ai_addrlen = 0, @@ -190,6 +190,9 @@ tcp_listen_work(struct lem_async *a) int ret; uint16_t port; + if (g->node != NULL) + hints.ai_flags |= AI_CANONNAME; + /* lookup name */ ret = getaddrinfo(g->node, g->service, &hints, &addr); if (ret) { @@ -210,6 +213,10 @@ tcp_listen_work(struct lem_async *a) /* set SO_REUSEADDR option if possible */ ret = 1; setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &ret, sizeof(int)); +#ifdef IPV6_V6ONLY + if (g->sock == AF_INET6) + setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &ret, sizeof(int)); +#endif /* bind */ if (bind(sock, addr->ai_addr, addr->ai_addrlen)) { @@ -254,6 +261,8 @@ tcp_listen_reap(struct lem_async *a) lua_State *T = g->a.T; int sock = g->sock; + if (g->node == NULL) + g->node = "*"; if (sock >= 0) { struct addrinfo *result = g->result; @@ -310,16 +319,15 @@ tcp_listen_reap(struct lem_async *a) } static int -tcp_listen(lua_State *T) +tcp_listen(lua_State *T, int family) { const char *node = luaL_checkstring(T, 1); const char *service = luaL_checkstring(T, 2); - int family = luaL_checkoption(T, 3, "any", tcp_famnames); - int backlog = (int)luaL_optnumber(T, 4, MAXPENDING); + int backlog = (int)luaL_optnumber(T, 3, MAXPENDING); struct tcp_getaddr *g; if (node[0] == '*' && node[1] == '\0') - node = "0.0.0.0"; + node = NULL; g = lem_xmalloc(sizeof(struct tcp_getaddr)); g->node = node; @@ -332,3 +340,15 @@ tcp_listen(lua_State *T) lua_pushvalue(T, lua_upvalueindex(1)); return lua_yield(T, 3); } + +static int +tcp_listen4(lua_State *T) +{ + return tcp_listen(T, AF_INET); +} + +static int +tcp_listen6(lua_State *T) +{ + return tcp_listen(T, AF_INET6); +} diff --git a/test/ctest.lua b/test/ctest.lua index adf117e..c49d677 100755 --- a/test/ctest.lua +++ b/test/ctest.lua @@ -25,7 +25,7 @@ package.cpath = '?.so' local utils = require 'lem.utils' local io = require 'lem.io' -local conn = assert(io.tcp.connect('localhost', arg[1] or 8080)) +local conn = assert(io.tcp.connect('localhost', arg[1] or '8080')) for i = 1, 10 do assert(conn:write('ping\n')) diff --git a/test/stest.lua b/test/stest.lua index 78c3406..82b432a 100755 --- a/test/stest.lua +++ b/test/stest.lua @@ -25,7 +25,7 @@ package.cpath = '?.so' local utils = require 'lem.utils' local io = require 'lem.io' -local server = assert(io.tcp.listen('*', arg[1] or 8080)) +local server = assert(io.tcp.listen('*', arg[1] or '8080')) --timer(10, function() exit(0) end) utils.spawn(function() |