From 0a26f4881e863aa1f12dbe5d2c1bb11e24c5ad7c Mon Sep 17 00:00:00 2001 From: Emil Renner Berthing Date: Mon, 19 Aug 2013 15:06:57 +0200 Subject: io: add io.fromfd() --- lem/io/core.c | 111 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- lem/io/server.c | 15 ++++++++ lem/io/tcp.c | 13 +------ lem/io/unix.c | 16 +------- 4 files changed, 128 insertions(+), 27 deletions(-) diff --git a/lem/io/core.c b/lem/io/core.c index f600879..bd4f72a 100644 --- a/lem/io/core.c +++ b/lem/io/core.c @@ -258,6 +258,109 @@ io_open(lua_State *T) return lua_yield(T, 3); } +/* + * io.fromfd() + */ +struct fromfd { + struct lem_async a; + int fd; + int ret; +}; + +static int +io_socket_listening(int fd) +{ + int val; + socklen_t len = sizeof(int); + + if (getsockopt(fd, SOL_SOCKET, SO_ACCEPTCONN, &val, &len) == 0 && val) + return 1; + + return 0; +} + +static void +io_fromfd_work(struct lem_async *a) +{ + struct fromfd *ff = (struct fromfd *)a; + struct stat st; + + if (fstat(ff->fd, &st)) { + ff->ret = -errno; + return; + } + + lem_debug("st.st_mode & S_IFMT = %o", st.st_mode & S_IFMT); + switch (st.st_mode & S_IFMT) { + case S_IFREG: + case S_IFBLK: + ff->ret = 0; + break; + + case S_IFSOCK: + if (io_socket_listening(ff->fd)) { + ff->ret = 2; + goto nonblock; + } + /* fallthrough */ + case S_IFCHR: + case S_IFIFO: + ff->ret = 1; + goto nonblock; + + default: + ff->ret = -EINVAL; + break; + } + return; +nonblock: + if (fcntl(ff->fd, F_SETFL, O_NONBLOCK) == -1) + ff->ret = -errno; +} + +static void +io_fromfd_reap(struct lem_async *a) +{ + struct fromfd *ff = (struct fromfd *)a; + lua_State *T = ff->a.T; + int fd = ff->fd; + int ret = ff->ret; + + lem_debug("ret = %d", ret); + free(ff); + + switch (ret) { + case 0: file_new(T, fd, 1); break; + case 1: stream_new(T, fd, 2); break; + case 2: server_new(T, fd, 3); break; + default: + lem_queue(T, io_strerror(T, -ret)); + return; + } + + lem_queue(T, 1); +} + +static int +io_fromfd(lua_State *T) +{ + int fd = luaL_checkint(T, 1); + struct fromfd *ff; + + if (fd < 0) + return luaL_argerror(T, 1, "invalid fd"); + + ff = lem_xmalloc(sizeof(struct fromfd)); + ff->fd = fd; + lem_async_do(&ff->a, T, io_fromfd_work, io_fromfd_reap); + + lua_settop(T, 0); + lua_pushvalue(T, lua_upvalueindex(1)); + lua_pushvalue(T, lua_upvalueindex(2)); + lua_pushvalue(T, lua_upvalueindex(3)); + return lua_yield(T, 3); +} + /* * io.popen() */ @@ -577,10 +680,16 @@ luaopen_lem_io_core(lua_State *L) lua_setfield(L, -2, "Server"); /* insert open function */ - lua_getfield(L, -1, "File"); /* upvalue 1 = File */ + lua_getfield(L, -1, "File"); /* upvalue 1 = File */ lua_getfield(L, -2, "Stream"); /* upvalue 2 = Stream */ lua_pushcclosure(L, io_open, 2); lua_setfield(L, -2, "open"); + /* insert the fromfd function */ + lua_getfield(L, -1, "File"); /* upvalue 1 = File */ + lua_getfield(L, -2, "Stream"); /* upvalue 2 = Stream */ + lua_getfield(L, -3, "Server"); /* upvalue 3 = Server */ + lua_pushcclosure(L, io_fromfd, 3); + lua_setfield(L, -2, "fromfd"); /* insert popen function */ lua_getfield(L, -1, "Stream"); /* upvalue 1 = Stream */ lua_pushcclosure(L, io_popen, 1); diff --git a/lem/io/server.c b/lem/io/server.c index 08c4d54..a47bf03 100644 --- a/lem/io/server.c +++ b/lem/io/server.c @@ -16,6 +16,21 @@ * License along with LEM. If not, see . */ +static struct ev_io * +server_new(lua_State *T, int fd, int mt) +{ + /* create userdata and set the metatable */ + struct ev_io *w = lua_newuserdata(T, sizeof(struct ev_io)); + lua_pushvalue(T, mt); + lua_setmetatable(T, -2); + + /* initialize userdata */ + ev_io_init(w, NULL, fd, EV_READ); + w->data = NULL; + + return w; +} + static int server_closed(lua_State *T) { diff --git a/lem/io/tcp.c b/lem/io/tcp.c index b11d59b..91ab187 100644 --- a/lem/io/tcp.c +++ b/lem/io/tcp.c @@ -257,19 +257,8 @@ tcp_listen_reap(struct lem_async *a) g->node = "*"; if (sock >= 0) { - struct ev_io *w; - free(g); - - /* create userdata and set the metatable */ - w = lua_newuserdata(T, sizeof(struct ev_io)); - lua_pushvalue(T, 3); - lua_setmetatable(T, -2); - - /* initialize userdata */ - ev_io_init(w, NULL, sock, EV_READ); - w->data = NULL; - + server_new(T, sock, 3); lem_queue(T, 1); return; } diff --git a/lem/io/unix.c b/lem/io/unix.c index 0a59d3d..ccc9994 100644 --- a/lem/io/unix.c +++ b/lem/io/unix.c @@ -134,8 +134,7 @@ unix_listen_work(struct lem_async *a) SOCK_CLOEXEC | #endif SOCK_STREAM, 0); - if (sock < 0 - ) { + if (sock < 0) { u->sock = -1; u->err = errno; return; @@ -191,19 +190,8 @@ unix_listen_reap(struct lem_async *a) int sock = u->sock; if (sock >= 0) { - struct ev_io *w; - free(u); - - /* 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; - + server_new(T, sock, 2); lem_queue(T, 1); return; } -- cgit v1.2.1