Commits

Anonymous committed a191011

initial commit

Comments (0)

Files changed (3)

+all:
+	gcc -fPIC -c eio.c -o eio.o
+	gcc -shared eio.o -o libeio.so
+clean:
+	rm -f eio.o
+	rm -f libeio.so
+#include <lua.h>
+#include <lauxlib.h>
+
+#include <string.h>
+#include <unistd.h>
+#include <sys/select.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <errno.h>
+
+#define LUA_EIOLIBNAME "libeio"
+
+#define MAX_WAIT_QUEUE_LENGTH 5
+
+#define EIO_RETURN(L, r, errno) \
+	do { \
+		if (r < 0) { \
+			lua_pushnumber(L, -errno); \
+		} else { \
+			lua_pushnumber(L, r); \
+		} \
+		return 1; \
+	} while (0);
+
+#define EIO_GET_NUMBER(L, x, i)	\
+	do { \
+		if (!lua_isnumber(L, i)) { \
+			lua_pushnumber(L, -EINVAL); \
+			return 1;\
+		} \
+		x = lua_tonumber(L, i); \
+	} while (0)
+
+
+int eio_read(lua_State *L) {
+	int r;
+	int fd;
+	int size;
+	char buf[BUFSIZ];
+
+	EIO_GET_NUMBER(L, fd, 1);
+	EIO_GET_NUMBER(L, size, 2);
+
+	if (size > BUFSIZ) size = BUFSIZ;
+
+	r = read(fd, buf, (size_t) size);
+	if (r < 0) {
+		lua_pushnumber(L, -errno);
+		return 1;
+	}
+
+	lua_pushnumber(L, r);
+	lua_pushlstring(L, buf, r);
+	return 2;
+}
+
+int eio_write(lua_State *L) {
+	int r;
+	int fd;
+	const char *s;
+
+	EIO_GET_NUMBER(L, fd, 1);
+	s = lua_tostring(L, 2);
+	r = write(fd, s, lua_strlen(L, 2));
+	EIO_RETURN(L, r, errno);
+}
+
+int eio_close(lua_State *L) {
+	int r;
+	int fd;
+
+	EIO_GET_NUMBER(L, fd, 1);
+	r = close(fd);
+	EIO_RETURN(L, r, errno);
+}
+
+int eio_listen(lua_State *L) {
+	int fd;
+	struct sockaddr_in addr;
+	int on = 1;
+	int port;
+
+	EIO_GET_NUMBER(L, port, 1);
+
+	fd = socket(AF_INET, SOCK_STREAM, 0);
+	if (fd < 0) {
+		lua_pushnumber(L, -errno);
+		return 1;
+	}
+
+	setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
+
+	memset(&addr, 0, sizeof(addr));
+	addr.sin_family = AF_INET;
+	addr.sin_port = htons(port);
+	addr.sin_addr.s_addr = INADDR_ANY;
+
+	if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+		lua_pushnumber(L, -errno);
+		return 1;
+	}
+
+	if (listen(fd, MAX_WAIT_QUEUE_LENGTH) < 0) {
+		lua_pushnumber(L, -errno);
+		return 1;
+	}
+
+	lua_pushnumber(L, fd);
+	return 1;
+}
+
+int eio_accept(lua_State *L) {
+	int srvfd, fd;
+	EIO_GET_NUMBER(L, srvfd, 1);
+
+	fd = accept(srvfd, NULL, NULL);
+
+	EIO_RETURN(L, fd, errno);
+}
+
+int eio_select(lua_State *L) {
+	int r, i, j;
+	int nfds, maxfd = 0;
+	int fd;
+	fd_set rfds, wfds;
+
+	FD_ZERO(&rfds);
+	FD_ZERO(&wfds);
+
+	nfds = lua_objlen(L, 1);
+	for (i = 1; i <= nfds; i++) {
+		lua_pushnumber(L, i);
+		lua_gettable(L, 1); // get rfds[i]
+		fd = lua_tonumber(L, -1);
+		FD_SET(fd, &rfds);
+		if (fd > maxfd) maxfd = fd;
+		lua_pop(L, 1);
+		//printf("read: %d\n", fd);
+	}
+
+	nfds = lua_objlen(L, 2);
+	for (i = 1; i <= nfds; i++) {
+		lua_pushnumber(L, i);
+		lua_gettable(L, 1); // get rfds[i]
+		fd = lua_tonumber(L, -1);
+		if (fd > maxfd) maxfd = fd;
+		FD_SET(fd, &wfds);
+		lua_pop(L, 1);
+		//printf("write: %d\n", fd);
+	}
+
+	r = select(maxfd+1, &rfds, &wfds, NULL, NULL);
+
+
+	if (r < 0) {
+		lua_pushnumber(L, -errno);
+		return 1;
+	}
+	lua_pushnumber(L, r);
+	lua_newtable(L);
+	lua_newtable(L);
+
+	for (fd = 0; fd <= maxfd; fd++) {
+		if (FD_ISSET(fd, &rfds)) {
+			lua_pushnumber(L, fd);
+			lua_pushnumber(L, 1);
+			lua_settable(L, -4);
+			//printf("read ready: %d\n", fd);
+		}
+		if (FD_ISSET(fd, &wfds)) {
+			lua_pushnumber(L, fd);
+			lua_pushnumber(L, 1);
+			lua_settable(L, -3);
+			//printf("write ready: %d\n", fd);
+		}
+	}
+	return 3;
+}
+
+static const luaL_reg eiolib[] = {
+	{"listen", eio_listen},
+	{"accept", eio_accept},
+	{"read", eio_read},
+	{"write", eio_write},
+	{"close", eio_close},
+	{"select", eio_select},
+	{NULL, NULL}
+};
+
+LUALIB_API int luaopen_libeio(lua_State *L) {
+	luaL_register(L, LUA_EIOLIBNAME, eiolib);
+	lua_pushnumber(L, STDIN_FILENO);
+	lua_setfield(L, -2, "stdin");
+	lua_pushnumber(L, STDOUT_FILENO);
+	lua_setfield(L, -2, "stdout");
+	lua_pushnumber(L, STDERR_FILENO);
+	lua_setfield(L, -2, "stderr");
+	return 1;
+}
+
+local libeio = require("libeio")
+
+local http = {}
+
+function http:serve(port, handlers)
+	self.fds = {}
+	self.crs = {}
+	self.handlers = handlers
+
+	local f = libeio.listen(port)
+	if f < 0 then error("listen(): "..f) end
+	self.fd = f
+
+	while true do 
+		local n
+		local rfds, wfds = {}, {}
+		-- add listening socket
+		table.insert(self.fds, self.fd, {fd=self.fd, r=true})
+
+		-- add other file descriptors to rfds/wfds
+		for _, fd in pairs(self.fds) do
+			if fd.r then 
+				table.insert(rfds, fd.fd)
+			end
+			if fd.w then
+				table.insert(wfds, fd.fd)
+			end
+		end
+
+		-- wait for the events
+		n, rfds, wfds = libeio.select(rfds, wfds)
+		if n < 0 then error("select(): "..n) end
+
+		-- special case: read on listening socket (accept event)
+		if rfds[self.fd] ~= nil then
+			self:accept()
+		end
+
+		-- dispatch the rest of the events
+		for fd, cr in pairs(self.crs) do
+			self.fds[fd].can_read = (rfds[fd] ~= nil)
+			self.fds[fd].can_write = (wfds[fd] ~= nil)
+			coroutine.resume(cr)
+			if coroutine.status(cr) == 'dead' then
+				libeio.close(fd)
+				self.crs[fd] = nil
+				self.fds[fd] = nil
+			end
+		end
+	end
+end
+
+function http:accept()
+	local fd = libeio.accept(self.fd)
+	print('accept')
+
+	self.fds[fd] = {fd = fd}
+
+	local read_header = function()
+		local request = ""
+
+		while request:find("\r\n\r\n") == nil do
+		--while request:find("\n\n") == nil do
+			local n, buf = self:read(fd, 1)
+			if n > 0 then 
+				request = request..tostring(buf)
+			elseif n == 0 then
+				return -- connection was closed
+			end
+		end
+
+		local r = {
+			req = request,
+			read = function(self,n) return self:read(fd, n) end,
+			write = function(self,s) return libeio.write(fd, s) end
+		}
+		print(request)
+
+		local handler = function(r) r:write("404 Not Found\r\n") end
+		for uri, h in pairs(self.handlers) do
+			if uri == "/" then
+				handler = h
+				break
+			end
+		end
+
+		handler(r)
+	end
+
+	self.crs[fd] = coroutine.create(read_header)
+end
+
+function http:read(fd, size)
+	if self.fds[fd].can_read then
+		self.fds[fd].can_read = false
+		self.fds[fd].r = false
+		return libeio.read(fd, size)
+	else
+		self.fds[fd].r = true
+		coroutine.yield()
+		return -1, nil
+	end
+end
+
+--------------------------
+
+function http_handler(r)
+	print(r.req)
+	r:write("hello")
+end
+
+h = {}
+http:serve(8080, {["/"] = http_handler})
+
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.