summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEmil Renner Berthing <esmil@mailme.dk>2013-08-19 15:06:57 +0200
committerEmil Renner Berthing <esmil@mailme.dk>2013-08-21 15:25:19 +0200
commit0a26f4881e863aa1f12dbe5d2c1bb11e24c5ad7c (patch)
tree504cb6e7b6a3b7c85ccdcd7abff84c924bf10bde
parentcbf66767ea6092cd1a90be82a00321e723fc2a88 (diff)
downloadlem-0a26f4881e863aa1f12dbe5d2c1bb11e24c5ad7c.tar.gz
lem-0a26f4881e863aa1f12dbe5d2c1bb11e24c5ad7c.tar.xz
lem-0a26f4881e863aa1f12dbe5d2c1bb11e24c5ad7c.zip
io: add io.fromfd()
-rw-r--r--lem/io/core.c111
-rw-r--r--lem/io/server.c15
-rw-r--r--lem/io/tcp.c13
-rw-r--r--lem/io/unix.c16
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
@@ -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);
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 <http://www.gnu.org/licenses/>.
*/
+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;
}