diff options
Diffstat (limited to 'lem/io/core.c')
-rw-r--r-- | lem/io/core.c | 111 |
1 files changed, 110 insertions, 1 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 @@ -259,6 +259,109 @@ io_open(lua_State *T) } /* + * 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() */ static const char *const io_popen_modes[] = { "r", "w", "rw", NULL }; @@ -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); |