summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorSteven Barth <steven@midlink.org>2009-02-08 14:01:48 +0000
committerSteven Barth <steven@midlink.org>2009-02-08 14:01:48 +0000
commit56d142a1a1b0286b8611040ea47ddf3a9844bb91 (patch)
treeb538774fc3c689230d151247beb31d36227424b7
parentf52ec227175c9db1bfee95f8a59c7c56d01911d4 (diff)
nixio linux IO/socket api (incomplete / WIP)
-rw-r--r--libs/nixio/Makefile14
-rw-r--r--libs/nixio/src/address.c259
-rw-r--r--libs/nixio/src/bind.c291
-rw-r--r--libs/nixio/src/nixio.c122
-rw-r--r--libs/nixio/src/nixio.h31
-rw-r--r--libs/nixio/src/select.c110
-rw-r--r--libs/nixio/src/socket.c163
-rw-r--r--libs/nixio/src/sockopt.c188
8 files changed, 1178 insertions, 0 deletions
diff --git a/libs/nixio/Makefile b/libs/nixio/Makefile
new file mode 100644
index 0000000000..a2ce5dae68
--- /dev/null
+++ b/libs/nixio/Makefile
@@ -0,0 +1,14 @@
+include ../../build/config.mk
+include ../../build/module.mk
+include ../../build/gccconfig.mk
+
+%.o: %.c
+ $(COMPILE) $(LUA_CFLAGS) $(FPIC) -c -o $@ $<
+
+compile: src/nixio.o src/socket.o src/sockopt.o src/bind.o src/address.o src/select.o
+ $(LINK) $(SHLIB_FLAGS) -o src/nixio.so src/*.o
+ mkdir -p dist$(LUA_LIBRARYDIR)
+ cp src/nixio.so dist$(LUA_LIBRARYDIR)/nixio.so
+
+clean: luaclean
+ rm -f src/*.o src/*.so
diff --git a/libs/nixio/src/address.c b/libs/nixio/src/address.c
new file mode 100644
index 0000000000..ae01c19ea0
--- /dev/null
+++ b/libs/nixio/src/address.c
@@ -0,0 +1,259 @@
+/*
+ * nixio - Linux I/O library for lua
+ *
+ * Copyright (C) 2009 Steven Barth <steven@midlink.org>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <lua.h>
+#include <lualib.h>
+#include <lauxlib.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <string.h>
+#include <netdb.h>
+#include "nixio.h"
+
+/**
+ * getaddrinfo(host, family, port)
+ */
+static int nixio_getaddrinfo(lua_State *L) {
+ const char *host = NULL;
+ if (!lua_isnoneornil(L, 1)) {
+ host = luaL_checklstring(L, 1, NULL);
+ }
+ const char *family = luaL_optlstring(L, 2, "any", NULL);
+ const char *port = lua_tolstring(L, 3, NULL);
+
+ struct addrinfo hints, *result, *rp;
+ memset(&hints, 0, sizeof(hints));
+
+ if (!strcmp(family, "any")) {
+ hints.ai_family = AF_UNSPEC;
+ } else if (!strcmp(family, "inet")) {
+ hints.ai_family = AF_INET;
+ } else if (!strcmp(family, "inet6")) {
+ hints.ai_family = AF_INET6;
+ } else {
+ return luaL_argerror(L, 2, "supported values: any, inet, inet6");
+ }
+
+ hints.ai_socktype = 0;
+ hints.ai_protocol = 0;
+
+ int aistat = getaddrinfo(host, port, &hints, &result);
+ if (aistat) {
+ lua_pushnil(L);
+ lua_pushinteger(L, aistat);
+ lua_pushstring(L, gai_strerror(aistat));
+ return 3;
+ }
+
+ /* create socket object */
+ lua_newtable(L);
+ int i = 1;
+
+ for (rp = result; rp != NULL; rp = rp->ai_next) {
+ /* avoid duplicate results */
+ if (!port && rp->ai_socktype != SOCK_STREAM) {
+ continue;
+ }
+
+ if (rp->ai_family == AF_INET || rp->ai_family == AF_INET6) {
+ lua_createtable(L, 0, port ? 4 : 2);
+ if (rp->ai_family == AF_INET) {
+ lua_pushliteral(L, "inet");
+ } else if (rp->ai_family == AF_INET6) {
+ lua_pushliteral(L, "inet6");
+ }
+ lua_setfield(L, -2, "family");
+
+ if (port) {
+ switch (rp->ai_socktype) {
+ case SOCK_STREAM:
+ lua_pushliteral(L, "stream");
+ break;
+ case SOCK_DGRAM:
+ lua_pushliteral(L, "dgram");
+ break;
+ case SOCK_RAW:
+ lua_pushliteral(L, "raw");
+ break;
+ default:
+ lua_pushnil(L);
+ break;
+ }
+ lua_setfield(L, -2, "socktype");
+ }
+
+ char ip[INET6_ADDRSTRLEN];
+ void *binaddr = NULL;
+ uint16_t binport = 0;
+
+ if (rp->ai_family == AF_INET) {
+ struct sockaddr_in *v4addr = (struct sockaddr_in*)rp->ai_addr;
+ binport = v4addr->sin_port;
+ binaddr = (void *)&v4addr->sin_addr;
+ } else if (rp->ai_family == AF_INET6) {
+ struct sockaddr_in6 *v6addr = (struct sockaddr_in6*)rp->ai_addr;
+ binport = v6addr->sin6_port;
+ binaddr = (void *)&v6addr->sin6_addr;
+ }
+
+ if (!inet_ntop(rp->ai_family, binaddr, ip, sizeof(ip))) {
+ freeaddrinfo(result);
+ return nixio__perror(L);
+ }
+
+ if (port) {
+ lua_pushinteger(L, ntohs(binport));
+ lua_setfield(L, -2, "port");
+ }
+
+ lua_pushstring(L, ip);
+ lua_setfield(L, -2, "address");
+ lua_rawseti(L, -2, i++);
+ }
+ }
+
+ freeaddrinfo(result);
+
+ return 1;
+}
+
+/**
+ * getnameinfo(address, family)
+ */
+static int nixio_getnameinfo(lua_State *L) {
+ const char *ip = luaL_checklstring(L, 1, NULL);
+ const char *family = luaL_optlstring(L, 2, "inet", NULL);
+ char host[NI_MAXHOST];
+
+ struct sockaddr *addr = NULL;
+ socklen_t alen = 0;
+ int res;
+
+ if (!strcmp(family, "inet")) {
+ struct sockaddr_in inetaddr;
+ memset(&inetaddr, 0, sizeof(inetaddr));
+ inetaddr.sin_family = AF_INET;
+ if (inet_pton(AF_INET, ip, &inetaddr.sin_addr) < 1) {
+ return luaL_argerror(L, 1, "invalid address");
+ }
+ alen = sizeof(inetaddr);
+ addr = (struct sockaddr *)&inetaddr;
+ } else if (!strcmp(family, "inet6")) {
+ struct sockaddr_in6 inet6addr;
+ memset(&inet6addr, 0, sizeof(inet6addr));
+ inet6addr.sin6_family = AF_INET6;
+ if (inet_pton(AF_INET6, ip, &inet6addr.sin6_addr) < 1) {
+ return luaL_argerror(L, 1, "invalid address");
+ }
+ alen = sizeof(inet6addr);
+ addr = (struct sockaddr *)&inet6addr;
+ } else {
+ return luaL_argerror(L, 2, "supported values: inet, inet6");
+ }
+
+ res = getnameinfo(addr, alen, host, sizeof(host), NULL, 0, NI_NAMEREQD);
+ if (res) {
+ lua_pushnil(L);
+ lua_pushinteger(L, res);
+ lua_pushstring(L, gai_strerror(res));
+ return 3;
+ } else {
+ lua_pushstring(L, host);
+ return 1;
+ }
+}
+
+/**
+ * getsockname() / getpeername() helper
+ */
+static int nixio_sock__getname(lua_State *L, int sock) {
+ int sockfd = nixio__checksockfd(L);
+ struct sockaddr_storage addr;
+ socklen_t addrlen = sizeof(addr);
+ char ipaddr[INET6_ADDRSTRLEN];
+ void *binaddr;
+ uint16_t port;
+
+ if (sock) {
+ if (getsockname(sockfd, (struct sockaddr*)&addr, &addrlen)) {
+ return nixio__perror(L);
+ }
+ } else {
+ if (getpeername(sockfd, (struct sockaddr*)&addr, &addrlen)) {
+ return nixio__perror(L);
+ }
+ }
+
+ if (addr.ss_family == AF_INET) {
+ struct sockaddr_in *inetaddr = (struct sockaddr_in*)&addr;
+ port = inetaddr->sin_port;
+ binaddr = &inetaddr->sin_addr;
+ } else if (addr.ss_family == AF_INET6) {
+ struct sockaddr_in6 *inet6addr = (struct sockaddr_in6*)&addr;
+ port = inet6addr->sin6_port;
+ binaddr = &inet6addr->sin6_addr;
+ } else {
+ return luaL_error(L, "unknown address family");
+ }
+
+ if (!inet_ntop(addr.ss_family, binaddr, ipaddr, sizeof(ipaddr))) {
+ return nixio__perror(L);
+ }
+
+ lua_pushstring(L, ipaddr);
+ lua_pushinteger(L, ntohs(port));
+ return 2;
+}
+
+/**
+ * getsockname()
+ */
+static int nixio_sock_getsockname(lua_State *L) {
+ return nixio_sock__getname(L, 1);
+}
+
+/**
+ * getpeername()
+ */
+static int nixio_sock_getpeername(lua_State *L) {
+ return nixio_sock__getname(L, 0);
+}
+
+
+/* module table */
+static const luaL_reg R[] = {
+ {"getaddrinfo", nixio_getaddrinfo},
+ {"getnameinfo", nixio_getnameinfo},
+ {NULL, NULL}
+};
+
+/* object table */
+static const luaL_reg M[] = {
+ {"getsockname", nixio_sock_getsockname},
+ {"getpeername", nixio_sock_getpeername},
+ {NULL, NULL}
+};
+
+void nixio_open_address(lua_State *L) {
+ luaL_register(L, NULL, R);
+
+ lua_pushvalue(L, -2);
+ luaL_register(L, NULL, M);
+ lua_pop(L, 1);
+}
diff --git a/libs/nixio/src/bind.c b/libs/nixio/src/bind.c
new file mode 100644
index 0000000000..66337eeb5f
--- /dev/null
+++ b/libs/nixio/src/bind.c
@@ -0,0 +1,291 @@
+/*
+ * nixio - Linux I/O library for lua
+ *
+ * Copyright (C) 2009 Steven Barth <steven@midlink.org>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <lua.h>
+#include <lualib.h>
+#include <lauxlib.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <sys/un.h>
+#include <string.h>
+#include <unistd.h>
+#include <netdb.h>
+#include "nixio.h"
+
+/**
+ * connect()/bind() shortcut
+ */
+static int nixio__bind_connect(lua_State *L, int do_bind) {
+ const char *host = NULL;
+ if (!lua_isnoneornil(L, 1)) {
+ host = luaL_checklstring(L, 1, NULL);
+ }
+ const char *port = luaL_checklstring(L, 2, NULL);
+ const char *family = luaL_optlstring(L, 3, "any", NULL);
+ const char *socktype = luaL_optlstring(L, 4, "stream", NULL);
+
+ struct addrinfo hints, *result, *rp;
+ memset(&hints, 0, sizeof(hints));
+
+ if (!strcmp(family, "any")) {
+ hints.ai_family = AF_UNSPEC;
+ } else if (!strcmp(family, "inet")) {
+ hints.ai_family = AF_INET;
+ } else if (!strcmp(family, "inet6")) {
+ hints.ai_family = AF_INET6;
+ } else {
+ return luaL_argerror(L, 3, "supported values: any, inet, inet6");
+ }
+
+ if (!strcmp(socktype, "any")) {
+ hints.ai_socktype = 0;
+ } else if (!strcmp(socktype, "stream")) {
+ hints.ai_socktype = SOCK_STREAM;
+ } else if (!strcmp(socktype, "dgram")) {
+ hints.ai_socktype = SOCK_DGRAM;
+ } else {
+ return luaL_argerror(L, 4, "supported values: any, stream, dgram");
+ }
+
+ if (do_bind) {
+ hints.ai_flags |= AI_PASSIVE;
+ }
+
+ hints.ai_protocol = 0;
+
+ int aistat = getaddrinfo(host, port, &hints, &result);
+ if (aistat) {
+ lua_pushnil(L);
+ lua_pushinteger(L, aistat);
+ lua_pushstring(L, gai_strerror(aistat));
+ return 3;
+ }
+
+ /* create socket object */
+ nixio_sock *sock = lua_newuserdata(L, sizeof(nixio_sock));
+ int status = -1;
+
+ for (rp = result; rp != NULL; rp = rp->ai_next) {
+ sock->fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
+ if (sock->fd == -1) {
+ continue;
+ }
+
+ if (do_bind) {
+ status = bind(sock->fd, rp->ai_addr, rp->ai_addrlen);
+ } else {
+ status = connect(sock->fd, rp->ai_addr, rp->ai_addrlen);
+ }
+
+ /* on success */
+ if (!status) {
+ sock->domain = rp->ai_family;
+ sock->type = rp->ai_socktype;
+ sock->protocol = rp->ai_protocol;
+ break;
+ }
+
+ close(sock->fd);
+ }
+
+ freeaddrinfo(result);
+
+ /* on failure */
+ if (status) {
+ return nixio__perror(L);
+ }
+
+ luaL_getmetatable(L, NIXIO_META);
+ lua_setmetatable(L, -2);
+
+ return 1;
+}
+
+/**
+ * bind(host, port, [family=any], [type=any]) shortcut
+ */
+static int nixio_bind(lua_State *L) {
+ return nixio__bind_connect(L, 1);
+}
+
+/**
+ * connect(host, port, [family=any], [type=any]) shortcut
+ */
+static int nixio_connect(lua_State *L) {
+ return nixio__bind_connect(L, 0);
+}
+
+/**
+ * bind()/connect() helper
+ */
+static int nixio_sock__bind_connect(lua_State *L, int do_bind) {
+ nixio_sock *sock = nixio__checksock(L);
+ int status = -1;
+
+ if (sock->domain == AF_INET || sock->domain == AF_INET6) {
+ const char *host = NULL;
+ if (!lua_isnoneornil(L, 2)) {
+ host = luaL_checklstring(L, 2, NULL);
+ }
+ const char *port = luaL_checklstring(L, 3, NULL);
+
+ struct addrinfo hints, *result, *rp;
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = sock->domain;
+ hints.ai_socktype = sock->type;
+ hints.ai_protocol = sock->protocol;
+
+ if (do_bind) {
+ hints.ai_flags |= AI_PASSIVE;
+ }
+
+ int aistat = getaddrinfo(host, port, &hints, &result);
+ if (aistat) {
+ lua_pushnil(L);
+ lua_pushinteger(L, aistat);
+ lua_pushstring(L, gai_strerror(aistat));
+ return 3;
+ }
+
+ for (rp = result; rp != NULL; rp = rp->ai_next) {
+ if (do_bind) {
+ status = bind(sock->fd, rp->ai_addr, rp->ai_addrlen);
+ } else {
+ status = connect(sock->fd, rp->ai_addr, rp->ai_addrlen);
+ }
+
+ /* on success */
+ if (!status) {
+ break;
+ }
+ }
+
+ freeaddrinfo(result);
+ } else if (sock->domain == AF_UNIX) {
+ size_t pathlen;
+ const char *path = luaL_checklstring(L, 2, &pathlen);
+
+ struct sockaddr_un addr;
+ addr.sun_family = AF_UNIX;
+ luaL_argcheck(L, pathlen < sizeof(addr.sun_path), 2, "out of range");
+ strncpy(addr.sun_path, path, sizeof(addr.sun_path));
+
+ if (do_bind) {
+ status = bind(sock->fd, (struct sockaddr*)&addr, sizeof(addr));
+ } else {
+ status = connect(sock->fd, (struct sockaddr*)&addr, sizeof(addr));
+ }
+ } else {
+ return luaL_error(L, "not supported");
+ }
+ return nixio__pstatus(L, !status);
+}
+
+/**
+ * bind()
+ */
+static int nixio_sock_bind(lua_State *L) {
+ return nixio_sock__bind_connect(L, 1);
+}
+
+/**
+ * connect()
+ */
+static int nixio_sock_connect(lua_State *L) {
+ return nixio_sock__bind_connect(L, 0);
+}
+
+/**
+ * listen()
+ */
+static int nixio_sock_listen(lua_State *L) {
+ int sockfd = nixio__checksockfd(L);
+ lua_Integer backlog = luaL_checkinteger(L, 2);
+ return nixio__pstatus(L, !listen(sockfd, backlog));
+}
+
+/**
+ * accept()
+ */
+static int nixio_sock_accept(lua_State *L) {
+ nixio_sock *sock = nixio__checksock(L);
+ struct sockaddr_storage addr;
+ socklen_t addrlen = sizeof(addr);
+ char ipaddr[INET6_ADDRSTRLEN];
+ void *binaddr;
+ uint16_t port;
+
+ int newfd = accept(sock->fd, (struct sockaddr *)&addr, &addrlen);
+ if (newfd < 0) {
+ return nixio__perror(L);
+ }
+
+ /* create userdata */
+ nixio_sock *clsock = lua_newuserdata(L, sizeof(nixio_sock));
+ luaL_getmetatable(L, NIXIO_META);
+ lua_setmetatable(L, -2);
+
+ memcpy(clsock, sock, sizeof(clsock));
+ clsock->fd = newfd;
+
+ if (addr.ss_family == AF_INET) {
+ struct sockaddr_in *inetaddr = (struct sockaddr_in*)&addr;
+ port = inetaddr->sin_port;
+ binaddr = &inetaddr->sin_addr;
+ } else if (addr.ss_family == AF_INET6) {
+ struct sockaddr_in6 *inet6addr = (struct sockaddr_in6*)&addr;
+ port = inet6addr->sin6_port;
+ binaddr = &inet6addr->sin6_addr;
+ } else {
+ return luaL_error(L, "unknown address family");
+ }
+
+ if (!inet_ntop(addr.ss_family, binaddr, ipaddr, sizeof(ipaddr))) {
+ return nixio__perror(L);
+ }
+
+ lua_pushstring(L, ipaddr);
+ lua_pushinteger(L, ntohs(port));
+ return 3;
+}
+
+/* module table */
+static const luaL_reg R[] = {
+ {"bind", nixio_bind},
+ {"connect", nixio_connect},
+ {NULL, NULL}
+};
+
+/* object table */
+static const luaL_reg M[] = {
+ {"bind", nixio_sock_bind},
+ {"connect", nixio_sock_connect},
+ {"listen", nixio_sock_listen},
+ {"accept", nixio_sock_accept},
+ {NULL, NULL}
+};
+
+void nixio_open_bind(lua_State *L) {
+ luaL_register(L, NULL, R);
+
+ lua_pushvalue(L, -2);
+ luaL_register(L, NULL, M);
+ lua_pop(L, 1);
+}
diff --git a/libs/nixio/src/nixio.c b/libs/nixio/src/nixio.c
new file mode 100644
index 0000000000..1152f2cc88
--- /dev/null
+++ b/libs/nixio/src/nixio.c
@@ -0,0 +1,122 @@
+/*
+ * nixio - Linux I/O library for lua
+ *
+ * Copyright (C) 2009 Steven Barth <steven@midlink.org>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <lua.h>
+#include <lualib.h>
+#include <lauxlib.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <errno.h>
+#include "nixio.h"
+
+#define VERSION 0.1
+
+
+/* pushes nil, error number and errstring on the stack */
+int nixio__perror(lua_State *L) {
+ lua_pushnil(L);
+ lua_pushinteger(L, errno);
+ lua_pushstring(L, strerror(errno));
+ return 3;
+}
+
+/* pushes true, if operation succeeded, otherwise call nixio__perror */
+int nixio__pstatus(lua_State *L, int condition) {
+ if (condition) {
+ lua_pushboolean(L, 1);
+ return 1;
+ } else {
+ return nixio__perror(L);
+ }
+}
+
+/* checks whether the first argument is a socket and returns it */
+nixio_sock* nixio__checksock(lua_State *L) {
+ nixio_sock *sock = (nixio_sock*)luaL_checkudata(L, 1, NIXIO_META);
+ luaL_argcheck(L, sock->fd != -1, 1, "invalid socket object");
+ return sock;
+}
+
+/* read fd from nixio_sock object */
+int nixio__checksockfd(lua_State *L) {
+ return nixio__checksock(L)->fd;
+}
+
+/* return any possible fd, otherwise error out */
+int nixio__checkfd(lua_State *L, int ud) {
+ int fd = nixio__tofd(L, ud);
+ return (fd != -1) ? fd : luaL_argerror(L, ud, "invalid file descriptor");
+}
+
+/* return any possible fd */
+int nixio__tofd(lua_State *L, int ud) {
+ void *udata = lua_touserdata(L, ud);
+ int fd = -1;
+ if (udata && lua_getmetatable(L, ud)) {
+ luaL_getmetatable(L, NIXIO_META);
+ luaL_getmetatable(L, LUA_FILEHANDLE);
+ if (lua_rawequal(L, -2, -3)) {
+ fd = ((nixio_sock*)udata)->fd;
+ } else if (lua_rawequal(L, -1, -3)) {
+ fd = fileno(*((FILE **)udata));
+ }
+ lua_pop(L, 3);
+ }
+ return fd;
+}
+
+/* object table */
+static const luaL_reg R[] = {
+ {NULL, NULL}
+};
+
+/* entry point */
+LUALIB_API int luaopen_nixio(lua_State *L) {
+ /* create metatable */
+ luaL_newmetatable(L, NIXIO_META);
+
+ /* method table */
+ lua_newtable(L);
+ lua_pushvalue(L, -1);
+
+ /* metatable.__index = M */
+ lua_setfield(L, -3, "__index");
+ lua_remove(L, -2);
+
+ /* register module */
+ luaL_register(L, "nixio", R);
+
+ /* register methods */
+ nixio_open_socket(L);
+ nixio_open_sockopt(L);
+ nixio_open_bind(L);
+ nixio_open_address(L);
+ nixio_open_select(L);
+
+ /* module version */
+ lua_pushnumber(L, VERSION);
+ lua_setfield(L, -2, "version");
+
+ /* remove meta table */
+ lua_remove(L, -2);
+
+ return 1;
+}
diff --git a/libs/nixio/src/nixio.h b/libs/nixio/src/nixio.h
new file mode 100644
index 0000000000..ce79c9aa64
--- /dev/null
+++ b/libs/nixio/src/nixio.h
@@ -0,0 +1,31 @@
+#ifndef NIXIO_H_
+#define NIXIO_H_
+
+#define NIXIO_META "nixio.socket"
+
+struct nixio_socket {
+ int fd;
+ int domain;
+ int type;
+ int protocol;
+};
+
+typedef struct nixio_socket nixio_sock;
+
+int nixio__perror(lua_State *L);
+int nixio__pstatus(lua_State *L, int condition);
+nixio_sock* nixio__checksock(lua_State *L);
+int nixio__checksockfd(lua_State *L);
+int nixio__checkfd(lua_State *L, int ud);
+int nixio__tofd(lua_State *L, int ud);
+
+/* Module functions */
+void nixio_open_socket(lua_State *L);
+void nixio_open_sockopt(lua_State *L);
+void nixio_open_bind(lua_State *L);
+void nixio_open_address(lua_State *L);
+void nixio_open_select(lua_State *L);
+
+/* Method functions */
+
+#endif /* NIXIO_H_ */
diff --git a/libs/nixio/src/select.c b/libs/nixio/src/select.c
new file mode 100644
index 0000000000..e88075ce41
--- /dev/null
+++ b/libs/nixio/src/select.c
@@ -0,0 +1,110 @@
+/*
+ * nixio - Linux I/O library for lua
+ *
+ * Copyright (C) 2009 Steven Barth <steven@midlink.org>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <lua.h>
+#include <lualib.h>
+#include <lauxlib.h>
+#include <sys/select.h>
+#include "nixio.h"
+
+static int nixio_select(lua_State *L) {
+ int nfds = 0, tmpfd = -1, i = 0, j = 0, o = 0, k, tlen;
+ fd_set rfds, wfds, xfds;
+ fd_set *fdsets[3] = {&rfds, &wfds, &xfds};
+ FD_ZERO(fdsets[0]);
+ FD_ZERO(fdsets[1]);
+ FD_ZERO(fdsets[2]);
+
+ struct timeval timeout;
+ timeout.tv_sec = luaL_optinteger(L, 4, 0);
+ timeout.tv_usec = luaL_optinteger(L, 5, 0);
+
+ /* create fdsets */
+ for (i=0; i<3; i++) {
+ o = i + 1;
+ if (lua_isnoneornil(L, o)) {
+ fdsets[i] = NULL;
+ continue;
+ }
+
+ luaL_checktype(L, o, LUA_TTABLE);
+ tlen = lua_objlen(L, o);
+ luaL_argcheck(L, tlen <= FD_SETSIZE, o, "too many fds");
+
+ for (j=1; j<=tlen; j++) {
+ lua_rawgeti(L, o, j);
+ tmpfd = nixio__checkfd(L, -1);
+ FD_SET(tmpfd, fdsets[i]);
+ if (tmpfd >= nfds) {
+ nfds = tmpfd + 1;
+ }
+ lua_pop(L, 1);
+ }
+ }
+
+ int stat = select(nfds, fdsets[0], fdsets[1], fdsets[2], &timeout);
+
+ if (stat < 0) {
+ return nixio__perror(L);
+ } else if (stat == 0) {
+ lua_pushinteger(L, stat);
+ for (i=1; i<=3; i++) {
+ if (lua_isnoneornil(L, i)) {
+ lua_pushnil(L);
+ } else {
+ lua_newtable(L);
+ }
+ }
+ } else {
+ lua_pushinteger(L, stat);
+
+ /* create return tables */
+ for (i=0; i<3; i++) {
+ o = i + 1;
+ if (lua_isnoneornil(L, o)) {
+ lua_pushnil(L);
+ continue;
+ }
+
+ lua_newtable(L);
+ tlen = lua_objlen(L, o);
+ k = 1;
+
+ for (j=1; j<=tlen; j++) {
+ lua_rawgeti(L, o, j);
+ tmpfd = nixio__tofd(L, -1);
+ if (FD_ISSET(tmpfd, fdsets[i])) {
+ lua_rawseti(L, -2, k++);
+ } else {
+ lua_pop(L, 1);
+ }
+ }
+ }
+ }
+ return 4;
+}
+
+/* module table */
+static const luaL_reg R[] = {
+ {"select", nixio_select},
+ {NULL, NULL}
+};
+
+void nixio_open_select(lua_State *L) {
+ luaL_register(L, NULL, R);
+}
diff --git a/libs/nixio/src/socket.c b/libs/nixio/src/socket.c
new file mode 100644
index 0000000000..acfa9aeb22
--- /dev/null
+++ b/libs/nixio/src/socket.c
@@ -0,0 +1,163 @@
+/*
+ * nixio - Linux I/O library for lua
+ *
+ * Copyright (C) 2009 Steven Barth <steven@midlink.org>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <lua.h>
+#include <lualib.h>
+#include <lauxlib.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include "nixio.h"
+
+
+/**
+ * create new socket
+ */
+static int nixio_socket(lua_State *L) {
+ const char *domain = luaL_optlstring(L, 1, "", NULL);
+ const char *type = luaL_optlstring(L, 2, "", NULL);
+ const char *proto = lua_tolstring(L, 3, NULL);
+
+ nixio_sock *sock = lua_newuserdata(L, sizeof(nixio_sock));
+
+ if (!strcmp(domain, "inet")) {
+ sock->domain = AF_INET;
+ } else if (!strcmp(domain, "inet6")) {
+ sock->domain = AF_INET6;
+ } else if (!strcmp(domain, "unix")) {
+ sock->domain = AF_UNIX;
+ } else if (!strcmp(domain, "packet")) {
+ sock->domain = AF_PACKET;
+ } else {
+ return luaL_argerror(L, 1,
+ "supported values: inet, inet6, unix, packet"
+ );
+ }
+
+ if (!strcmp(type, "stream")) {
+ sock->type = SOCK_STREAM;
+ } else if (!strcmp(type, "dgram")) {
+ sock->type = SOCK_DGRAM;
+ } else if (!strcmp(type, "raw")) {
+ sock->type = SOCK_RAW;
+ } else {
+ return luaL_argerror(L, 2, "supported values: stream, dgram, raw");
+ }
+
+ if (!proto) {
+ sock->protocol = 0;
+ } else if (!strcmp(proto, "icmp")) {
+ sock->protocol = IPPROTO_ICMP;
+ } else if (!strcmp(proto, "icmpv6")) {
+ sock->protocol = IPPROTO_ICMPV6;
+ } else {
+ return luaL_argerror(L, 3, "supported values: [empty], icmp, icmpv6");
+ }
+
+ /* create userdata */
+ luaL_getmetatable(L, NIXIO_META);
+ lua_setmetatable(L, -2);
+
+ sock->fd = socket(sock->domain, sock->type, sock->protocol);
+
+ if (sock->fd < 0) {
+ return nixio__perror(L);
+ }
+
+ return 1;
+}
+
+/**
+ * close a socket
+ */
+static int nixio_sock_close(lua_State *L) {
+ nixio_sock *sock = nixio__checksock(L);
+ int sockfd = sock->fd;
+ sock->fd = -1;
+ return nixio__pstatus(L, !close(sockfd));
+}
+
+/**
+ * garbage collector
+ */
+static int nixio_sock__gc(lua_State *L) {
+ nixio_sock *sock = (nixio_sock*)luaL_checkudata(L, 1, NIXIO_META);
+ if (sock && sock->fd != -1) {
+ close(sock->fd);
+ }
+ return 0;
+}
+
+/**
+ * string representation
+ */
+static int nixio_sock__tostring(lua_State *L) {
+ lua_pushfstring(L, "nixio socket %d", nixio__checksockfd(L));
+ return 1;
+}
+
+/**
+ * shutdown a socket
+ */
+static int nixio_sock_shutdown(lua_State *L) {
+ int sockfd = nixio__checksockfd(L);
+ const char *what = luaL_optlstring(L, 2, "rdwr", NULL);
+ int how;
+
+ if (!strcmp(what, "rdwr") || !strcmp(what, "both")) {
+ how = SHUT_RDWR;
+ } else if (!strcmp(what, "rd") || !strcmp(what, "read")) {
+ how = SHUT_RD;
+ } else if (!strcmp(what, "wr") || !strcmp(what, "write")) {
+ how = SHUT_WR;
+ } else {
+ return luaL_argerror(L, 2, "supported values: both, read, write");
+ }
+
+ return nixio__pstatus(L, !shutdown(sockfd, how));
+}
+
+/* module table */
+static const luaL_reg R[] = {
+ {"socket", nixio_socket},
+ {NULL, NULL}
+};
+
+/* object table */
+static const luaL_reg M[] = {
+ {"close", nixio_sock_close},
+ {"shutdown", nixio_sock_shutdown},
+ {NULL, NULL}
+};
+
+void nixio_open_socket(lua_State *L) {
+ luaL_getmetatable(L, NIXIO_META);
+ lua_pushcfunction(L, nixio_sock__gc);
+ lua_setfield(L, -2, "__gc");
+ lua_pushcfunction(L, nixio_sock__tostring);
+ lua_setfield(L, -2, "__tostring");
+ lua_pop(L, 1);
+
+ luaL_register(L, NULL, R);
+
+ lua_pushvalue(L, -2);
+ luaL_register(L, NULL, M);
+ lua_pop(L, 1);
+}
diff --git a/libs/nixio/src/sockopt.c b/libs/nixio/src/sockopt.c
new file mode 100644
index 0000000000..f1a326c754
--- /dev/null
+++ b/libs/nixio/src/sockopt.c
@@ -0,0 +1,188 @@
+/*
+ * nixio - Linux I/O library for lua
+ *
+ * Copyright (C) 2009 Steven Barth <steven@midlink.org>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <lua.h>
+#include <lualib.h>
+#include <lauxlib.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <sys/time.h>
+#include <string.h>
+#include <fcntl.h>
+#include "nixio.h"
+
+/**
+ * setblocking()
+ */
+static int nixio_sock_setblocking(lua_State *L) {
+ int fd = nixio__checkfd(L, 1);
+ int set = lua_toboolean(L, 2);
+ int flags = fcntl(fd, F_GETFL);
+
+ if (flags == -1) {
+ return nixio__perror(L);
+ }
+
+ if (set) {
+ flags |= O_NONBLOCK;
+ } else {
+ flags &= ~O_NONBLOCK;
+ }
+
+ return nixio__pstatus(L, !fcntl(fd, F_SETFL, flags));
+}
+
+static int nixio__gso_int(lua_State *L, int fd, int level, int opt, int set) {
+ int value;
+ socklen_t optlen = sizeof(value);
+ if (!set) {
+ if (!getsockopt(fd, level, opt, &value, &optlen)) {
+ lua_pushinteger(L, value);
+ return 1;
+ }
+ } else {
+ value = luaL_checkinteger(L, set);
+ if (!setsockopt(fd, level, opt, &value, optlen)) {
+ lua_pushboolean(L, 1);
+ return 1;
+ }
+ }
+ return nixio__perror(L);
+}
+
+static int nixio__gso_ling(lua_State *L, int fd, int level, int opt, int set) {
+ struct linger value;
+ socklen_t optlen = sizeof(value);
+ if (!set) {
+ if (!getsockopt(fd, level, opt, &value, &optlen)) {
+ lua_pushinteger(L, value.l_onoff ? value.l_linger : 0);
+ return 1;
+ }
+ } else {
+ value.l_linger = luaL_checkinteger(L, set);
+ value.l_onoff = value.l_linger ? 1 : 0;
+ if (!setsockopt(fd, level, opt, &value, optlen)) {
+ lua_pushboolean(L, 1);
+ return 1;
+ }
+ }
+ return nixio__perror(L);
+}
+
+static int nixio__gso_timev(lua_State *L, int fd, int level, int opt, int set) {
+ struct timeval value;
+ socklen_t optlen = sizeof(value);
+ if (!set) {
+ if (!getsockopt(fd, level, opt, &value, &optlen)) {
+ lua_pushinteger(L, value.tv_sec);
+ lua_pushinteger(L, value.tv_usec);
+ return 2;
+ }
+ } else {
+ value.tv_sec = luaL_checkinteger(L, set);
+ value.tv_usec = luaL_optinteger(L, set + 1, 0);
+ if (!setsockopt(fd, level, opt, &value, optlen)) {
+ lua_pushboolean(L, 1);
+ return 1;
+ }
+ }
+ return nixio__perror(L);
+}
+
+/**
+ * get/setsockopt() helper
+ */
+static int nixio__getsetsockopt(lua_State *L, int set) {
+ nixio_sock *sock = nixio__checksock(L);
+ const char *level = luaL_optlstring(L, 2, "", NULL);
+ const char *option = luaL_optlstring(L, 3, "", NULL);
+ set = (set) ? 4 : 0;
+
+ if (!strcmp(level, "socket")) {
+ if (!strcmp(option, "keepalive")) {
+ return nixio__gso_int(L, sock->fd, SOL_SOCKET, SO_KEEPALIVE, set);
+ } else if (!strcmp(option, "reuseaddr")) {
+ return nixio__gso_int(L, sock->fd, SOL_SOCKET, SO_REUSEADDR, set);
+ } else if (!strcmp(option, "rcvbuf")) {
+ return nixio__gso_int(L, sock->fd, SOL_SOCKET, SO_RCVBUF, set);
+ } else if (!strcmp(option, "sndbuf")) {
+ return nixio__gso_int(L, sock->fd, SOL_SOCKET, SO_SNDBUF, set);
+ } else if (!strcmp(option, "priority")) {
+ return nixio__gso_int(L, sock->fd, SOL_SOCKET, SO_PRIORITY, set);
+ } else if (!strcmp(option, "broadcast")) {
+ return nixio__gso_int(L, sock->fd, SOL_SOCKET, SO_BROADCAST, set);
+ } else if (!strcmp(option, "linger")) {
+ return nixio__gso_ling(L, sock->fd, SOL_SOCKET, SO_LINGER, set);
+ } else if (!strcmp(option, "sndtimeo")) {
+ return nixio__gso_timev(L, sock->fd, SOL_SOCKET, SO_SNDTIMEO, set);
+ } else if (!strcmp(option, "rcvtimeo")) {
+ return nixio__gso_timev(L, sock->fd, SOL_SOCKET, SO_RCVTIMEO, set);
+ } else {
+ return luaL_argerror(L, 3, "supported values: keepalive, reuseaddr,"
+ " sndbuf, rcvbuf, priority, broadcast, linger, sndtimeo, rcvtimeo"
+ );
+ }
+ } else if (!strcmp(level, "tcp")) {
+ if (sock->type != SOCK_STREAM) {
+ return luaL_error(L, "not a TCP socket");
+ }
+ if (!strcmp(option, "cork")) {
+ return nixio__gso_int(L, sock->fd, SOL_TCP, TCP_CORK, set);
+ } else if (!strcmp(option, "nodelay")) {
+ return nixio__gso_int(L, sock->fd, SOL_TCP, TCP_NODELAY, set);
+ } else {
+ return luaL_argerror(L, 3, "supported values: cork, nodelay");
+ }
+ } else {
+ return luaL_argerror(L, 2, "supported values: socket, tcp");
+ }
+}
+
+/**
+ * getsockopt()
+ */
+static int nixio_sock_getsockopt(lua_State *L) {
+ return nixio__getsetsockopt(L, 0);
+}
+
+/**
+ * setsockopt()
+ */
+static int nixio_sock_setsockopt(lua_State *L) {
+ return nixio__getsetsockopt(L, 1);
+}
+
+/* module table */
+static const luaL_reg M[] = {
+ {"setblocking", nixio_sock_setblocking},
+ {"getsockopt", nixio_sock_getsockopt},
+ {"setsockopt", nixio_sock_setsockopt},
+ {NULL, NULL}
+};
+
+void nixio_open_sockopt(lua_State *L) {
+ lua_pushvalue(L, -2);
+ luaL_register(L, NULL, M);
+ lua_pop(L, 1);
+
+ luaL_getmetatable(L, LUA_FILEHANDLE);
+ lua_pushcfunction(L, nixio_sock_setblocking);
+ lua_setfield(L, -2, "setblocking");
+ lua_pop(L, 1);
+}