summaryrefslogtreecommitdiffstats
path: root/lem/io/core.c
diff options
context:
space:
mode:
Diffstat (limited to 'lem/io/core.c')
-rw-r--r--lem/io/core.c111
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);