summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEmil Renner Berthing <esmil@mailme.dk>2012-12-13 10:36:50 +0100
committerEmil Renner Berthing <esmil@mailme.dk>2012-12-17 10:11:06 +0100
commita78969df5a9589ca51c17dfc20b3a2cfb3f50c46 (patch)
treebff1c6533977a680d873a1a8befaeafd527eb02f
parentccd4ec76f226acda8843f60d5230f7f8db876074 (diff)
downloadlem-a78969df5a9589ca51c17dfc20b3a2cfb3f50c46.tar.gz
lem-a78969df5a9589ca51c17dfc20b3a2cfb3f50c46.tar.xz
lem-a78969df5a9589ca51c17dfc20b3a2cfb3f50c46.zip
io: unify io.tcp_listen()
-rw-r--r--lem/hathaway.lua4
-rw-r--r--lem/io/core.c10
-rw-r--r--lem/io/tcp.c217
-rwxr-xr-xtest/stest.lua2
4 files changed, 128 insertions, 105 deletions
diff --git a/lem/hathaway.lua b/lem/hathaway.lua
index 2cde2ca..032a938 100644
--- a/lem/hathaway.lua
+++ b/lem/hathaway.lua
@@ -347,8 +347,8 @@ do
client:close()
end
- function M.Hathaway(address, port)
- local server, err = io.tcp4_listen(address, port)
+ function M.Hathaway(...)
+ local server, err = io.tcp_listen(...)
if not server then M.debug(err) return nil, err end
M.server = server
diff --git a/lem/io/core.c b/lem/io/core.c
index c6dfaa2..72861db 100644
--- a/lem/io/core.c
+++ b/lem/io/core.c
@@ -366,14 +366,10 @@ luaopen_lem_io_core(lua_State *L)
lua_getfield(L, -1, "Stream"); /* upvalue 1 = Stream */
lua_pushcclosure(L, tcp_connect, 1);
lua_setfield(L, -2, "tcp_connect");
- /* insert the tcp4_listen function */
+ /* insert the tcp_listen function */
lua_getfield(L, -1, "Server"); /* upvalue 1 = Server */
- lua_pushcclosure(L, tcp4_listen, 1);
- lua_setfield(L, -2, "tcp4_listen");
- /* insert the tcp6_listen function */
- lua_getfield(L, -1, "Server"); /* upvalue 1 = Server */
- lua_pushcclosure(L, tcp6_listen, 1);
- lua_setfield(L, -2, "tcp6_listen");
+ lua_pushcclosure(L, tcp_listen, 1);
+ lua_setfield(L, -2, "tcp_listen");
/* create parser table */
lua_createtable(L, 0, 4);
diff --git a/lem/io/tcp.c b/lem/io/tcp.c
index 1d0f911..81516cd 100644
--- a/lem/io/tcp.c
+++ b/lem/io/tcp.c
@@ -159,125 +159,152 @@ tcp_connect(lua_State *T)
return lua_yield(T, 2);
}
-static int
-tcp_listen(lua_State *T, struct sockaddr *address, socklen_t alen,
- int sock, int backlog)
+static void
+tcp_listen_work(struct lem_async *a)
{
- struct ev_io *w;
- int optval = 1;
+ struct tcp_getaddr *g = (struct tcp_getaddr *)a;
+ struct addrinfo hints = {
+ .ai_flags = AI_PASSIVE,
+ .ai_family = tcp_famnumber[g->sock],
+ .ai_socktype = SOCK_STREAM,
+ .ai_protocol = IPPROTO_TCP,
+ .ai_addrlen = 0,
+ .ai_addr = NULL,
+ .ai_canonname = NULL,
+ .ai_next = NULL
+ };
+ struct addrinfo *addr = NULL;
+ int sock = -1;
+ int ret;
- /* set SO_REUSEADDR option */
- if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
- &optval, sizeof(int))) {
- close(sock);
- lua_pushnil(T);
- lua_pushfstring(T, "error setting SO_REUSEADDR on socket: %s",
- strerror(errno));
- return 2;
+ /* lookup name */
+ ret = getaddrinfo(g->node, g->service, &hints, &addr);
+ if (ret) {
+ g->sock = -1;
+ g->err = ret;
+ goto error;
}
- /* make the socket non-blocking */
- if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0) {
- close(sock);
- lua_pushnil(T);
- lua_pushfstring(T, "error making socket non-blocking: %s",
- strerror(errno));
- return 2;
+ /* create the TCP socket */
+ sock = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
+ lem_debug("addr->ai_family = %d, sock = %d", addr->ai_family, sock);
+ if (sock < 0) {
+ g->sock = -2;
+ g->err = errno;
+ goto error;
}
+ /* set SO_REUSEADDR option if possible */
+ ret = 1;
+ setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &ret, sizeof(int));
+
/* bind */
- if (bind(sock, address, alen)) {
- close(sock);
- lua_pushnil(T);
- lua_pushfstring(T, "error binding socket: %s",
- strerror(errno));
- return 2;
+ if (bind(sock, addr->ai_addr, addr->ai_addrlen)) {
+ g->sock = -3;
+ g->err = errno;
+ goto error;
}
+ freeaddrinfo(addr);
+ addr = NULL;
/* listen to the socket */
- if (listen(sock, backlog) < 0) {
- lua_pushnil(T);
- lua_pushfstring(T, "error listening to the socket: %s",
- strerror(errno));
- return 2;
+ if (listen(sock, g->err)) {
+ g->sock = -4;
+ g->err = errno;
+ goto error;
}
- /* create userdata and set the metatable */
- w = lua_newuserdata(T, sizeof(struct ev_io));
- lua_pushvalue(T, lua_upvalueindex(1));
- lua_setmetatable(T, -2);
+ /* make the socket non-blocking */
+ if (fcntl(sock, F_SETFL, O_NONBLOCK)) {
+ g->sock = -5;
+ g->err = errno;
+ goto error;
+ }
- /* initialize userdata */
- ev_io_init(w, NULL, sock, EV_READ);
- w->data = NULL;
+ g->sock = sock;
+ return;
- return 1;
+error:
+ if (addr != NULL)
+ freeaddrinfo(addr);
+ if (sock >= 0)
+ close(sock);
}
-static int
-tcp4_listen(lua_State *T)
+static void
+tcp_listen_reap(struct lem_async *a)
{
- const char *addr = luaL_checkstring(T, 1);
- uint16_t port = (uint16_t)luaL_checknumber(T, 2);
- int backlog = (int)luaL_optnumber(T, 3, MAXPENDING);
- int sock;
- struct sockaddr_in address;
-
- /* initialise the socketadr_in structure */
- memset(&address, 0, sizeof(struct sockaddr_in));
- address.sin_family = AF_INET;
- if (addr[0] == '*' && addr[1] == '\0')
- address.sin_addr.s_addr = INADDR_ANY;
- else if (!inet_pton(AF_INET, addr, &address.sin_addr)) {
- lua_pushnil(T);
- lua_pushfstring(T, "cannot bind to '%s'", addr);
- return 2;
- }
- address.sin_port = htons(port);
+ struct tcp_getaddr *g = (struct tcp_getaddr *)a;
+ lua_State *T = g->a.T;
+ const char *node = g->node;
+ const char *service = g->service;
+ int sock = g->sock;
+ int err = g->err;
- /* create the TCP socket */
- sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
- if (sock < 0) {
- lua_pushnil(T);
- lua_pushfstring(T, "error creating TCP socket: %s",
- strerror(errno));
- return 2;
+ free(g);
+
+ if (sock >= 0) {
+ struct ev_io *w;
+
+ /* create userdata and set the metatable */
+ w = lua_newuserdata(T, sizeof(struct ev_io));
+ lua_pushvalue(T, 2);
+ lua_setmetatable(T, -2);
+
+ /* initialize userdata */
+ ev_io_init(w, NULL, sock, EV_READ);
+ w->data = NULL;
+ lem_queue(T, 1);
+ return;
}
- return tcp_listen(T, (struct sockaddr *)&address,
- sizeof(struct sockaddr_in), sock, backlog);
+ lua_pushnil(T);
+ switch (-sock) {
+ case 1:
+ lua_pushfstring(T, "error looking up '%s:%s': %s",
+ node, service, gai_strerror(err));
+ break;
+ case 2:
+ lua_pushfstring(T, "error creating socket: %s",
+ strerror(err));
+ break;
+ case 3:
+ lua_pushfstring(T, "error binding to '%s:%s': %s",
+ node, service, strerror(err));
+ break;
+ case 4:
+ lua_pushfstring(T, "error listening on '%s:%s': %s",
+ node, service, strerror(err));
+ break;
+
+ case 5:
+ lua_pushfstring(T, "error making socket non-blocking: %s",
+ strerror(err));
+ break;
+ }
+ lem_queue(T, 2);
}
static int
-tcp6_listen(lua_State *T)
+tcp_listen(lua_State *T)
{
- const char *addr = luaL_checkstring(T, 1);
- uint16_t port = (uint16_t)luaL_checknumber(T, 2);
- int backlog = (int)luaL_optnumber(T, 3, MAXPENDING);
- int sock;
- struct sockaddr_in6 address;
-
- /* initialise the socketadr_in structure */
- memset(&address, 0, sizeof(struct sockaddr_in6));
- address.sin6_family = AF_INET6;
- if (addr[0] == '*' && addr[1] == '\0')
- address.sin6_addr = in6addr_any;
- else if (!inet_pton(AF_INET6, addr, &address.sin6_addr)) {
- lua_pushnil(T);
- lua_pushfstring(T, "cannot bind to '%s'", addr);
- return 2;
- }
- address.sin6_port = htons(port);
+ 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);
+ struct tcp_getaddr *g;
- /* create the TCP socket */
- sock = socket(PF_INET6, SOCK_STREAM, IPPROTO_TCP);
- if (sock < 0) {
- lua_pushnil(T);
- lua_pushfstring(T, "error creating TCP socket: %s",
- strerror(errno));
- return 2;
- }
+ if (node[0] == '*' && node[1] == '\0')
+ node = "0.0.0.0";
+
+ g = lem_xmalloc(sizeof(struct tcp_getaddr));
+ g->node = node;
+ g->service = service;
+ g->sock = family;
+ g->err = backlog;
+ lem_async_do(&g->a, T, tcp_listen_work, tcp_listen_reap);
- return tcp_listen(T, (struct sockaddr *)&address,
- sizeof(struct sockaddr_in6), sock, backlog);
+ lua_settop(T, 1);
+ lua_pushvalue(T, lua_upvalueindex(1));
+ return lua_yield(T, 2);
}
diff --git a/test/stest.lua b/test/stest.lua
index 60ea03d..f156ce7 100755
--- a/test/stest.lua
+++ b/test/stest.lua
@@ -22,7 +22,7 @@ print('Entered ' .. arg[0])
local utils = require 'lem.utils'
local io = require 'lem.io'
-local server = assert(io.tcp4_listen('*', arg[1] or 8080))
+local server = assert(io.tcp_listen('*', arg[1] or 8080))
--timer(10, function() exit(0) end)
utils.spawn(function()