summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Pointner <equinox@spreadspace.org>2010-11-17 21:21:49 +0000
committerChristian Pointner <equinox@spreadspace.org>2010-11-17 21:21:49 +0000
commitc4ff2ad81a78d7e608e7df4be1a61a347eaf9400 (patch)
tree76bb09cee4b7d3dce7a4886e70aa8bc4eba87b31
parentadded out module api to dummy module (diff)
added rawio lua module
added stdio module (not working yet) git-svn-id: https://svn.spreadspace.org/gcsd/trunk@37 ac14a137-c7f1-4531-abe0-07747231d213
-rw-r--r--TODO3
-rw-r--r--src/Makefile1
-rw-r--r--src/gcsd.c3
-rw-r--r--src/l_rawio.c141
-rw-r--r--src/l_rawio.h41
-rw-r--r--src/modules/stdio.lua134
-rw-r--r--src/modules/stdout.lua25
7 files changed, 336 insertions, 12 deletions
diff --git a/TODO b/TODO
index 87914df..e7cc298 100644
--- a/TODO
+++ b/TODO
@@ -1,6 +1,5 @@
- * debug-shell: enqueue command
+ * correct reimplementation of select, read, write, exec
* command-queue + expected responses
- * first output module
* input modules
- stdio
- tcp
diff --git a/src/Makefile b/src/Makefile
index 91461fd..0bb1ff4 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -44,6 +44,7 @@ C_OBJS := log.o \
string_list.o \
sig_handler.o \
l_sig_handler.o \
+ l_rawio.o \
gcsd.o
C_SRCS := $(C_OBJS:%.o=%.c)
diff --git a/src/gcsd.c b/src/gcsd.c
index dbcc6d0..c6d3e7c 100644
--- a/src/gcsd.c
+++ b/src/gcsd.c
@@ -42,6 +42,7 @@
#include "options.h"
#include "string_list.h"
#include "log.h"
+#include "l_rawio.h"
#include "l_log.h"
#include "l_sig_handler.h"
@@ -60,7 +61,7 @@ static const luaL_Reg gcsd_lualibs[] = {
{LUA_TABLIBNAME, luaopen_table},
{LUA_STRLIBNAME, luaopen_string},
{LUA_MATHLIBNAME, luaopen_math},
- {LUA_IOLIBNAME, luaopen_io},
+ {LUA_RAWIOLIBNAME, luaopen_rawio},
{LUA_LOGLIBNAME, luaopen_log},
{LUA_SIGNALLIBNAME, luaopen_signal},
{NULL, NULL}
diff --git a/src/l_rawio.c b/src/l_rawio.c
new file mode 100644
index 0000000..25d98ee
--- /dev/null
+++ b/src/l_rawio.c
@@ -0,0 +1,141 @@
+/*
+ * gcsd
+ *
+ * gcsd the generic command sequencer daemon can be used to serialize
+ * commands sent over various paralell communication channels to a
+ * single command output. It can be seen as a multiplexer for any
+ * kind of communication between a single resource and various clients
+ * which want to submit commands to it or query information from it.
+ * gcsd is written in C and Lua. The goal is to provide an easy to
+ * understand high level API based on Lua which can be used to
+ * implement the business logic of the so formed multiplexer daemon.
+ *
+ *
+ * Copyright (C) 2009-2010 Markus Grueneis <gimpf@spreadspace.org>
+ * Christian Pointner <equinox@spreadspace.org>
+ *
+ * This file is part of gcsd.
+ *
+ * gcsd is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * gcsd is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with gcsd. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <lua.h>
+#include <lauxlib.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <fcntl.h>
+
+#include "l_rawio.h"
+
+
+static int l_rawio_open(lua_State *L)
+{
+ const char* filename = luaL_checkstring(L,1);
+ const char* mode_str = luaL_checkstring(L,2);
+ int mode = 0;
+
+ if(strstr(mode_str, "O_RDONLY")) mode |= O_RDONLY;
+ if(strstr(mode_str, "O_WRONLY")) mode |= O_WRONLY;
+ if(strstr(mode_str, "O_RDWR")) mode |= O_RDWR;
+ int fd = open(filename, mode);
+
+ lua_pushinteger(L, fd);
+ return 1;
+}
+
+static int l_rawio_setnonblock(lua_State *L)
+{
+ int fd = luaL_checkinteger(L,1);
+ int ret = fcntl(fd, F_SETFL, O_NONBLOCK);
+
+ if(ret == -1) {
+ lua_pushnil(L);
+// FIXXXXXME: strerror is not threadsafe!!!
+ lua_pushstring(L, strerror(errno));
+ return 2;
+ }
+ lua_pushboolean(L, 1);
+ return 1;
+}
+
+static int l_rawio_write(lua_State *L)
+{
+ int fd = luaL_checkinteger(L,1);
+ size_t len = 0;
+ const char* data = luaL_checklstring(L, 2, &len);
+
+ int ret = write(fd, data, len);
+
+ if(ret == -1) {
+ lua_pushnil(L);
+// FIXXXXXME: strerror is not threadsafe!!!
+ lua_pushstring(L, strerror(errno));
+ return 2;
+ }
+ lua_pushinteger(L, ret);
+ return 1;
+}
+
+static int l_rawio_read(lua_State *L)
+{
+ int fd = luaL_checkinteger(L,1);
+ size_t len = luaL_checkinteger(L,2);
+ char* data = malloc(len);
+ if(!data) {
+ lua_pushboolean(L, 0);
+ lua_pushstring(L, "bad alloc");
+ return 2;
+ }
+
+ int ret = read(fd, data, len);
+
+ if(ret == -1) {
+ lua_pushnil(L);
+// FIXXXXXME: strerror is not threadsafe!!!
+ lua_pushstring(L, strerror(errno));
+ free(data);
+ return 2;
+ }
+ lua_pushlstring(L, data, ret);
+ free(data);
+ return 1;
+}
+
+static int l_rawio_close(lua_State *L)
+{
+ close(luaL_checkinteger(L,1));
+ return 0;
+}
+
+static const struct luaL_reg rawio_funcs [] = {
+ { "open", l_rawio_open },
+ { "setnonblock", l_rawio_setnonblock },
+ { "write", l_rawio_write },
+ { "read", l_rawio_read },
+ { "close", l_rawio_close },
+ { NULL, NULL }
+};
+
+
+LUALIB_API int luaopen_rawio(lua_State *L)
+{
+ luaL_register(L, LUA_RAWIOLIBNAME, rawio_funcs);
+ return 1;
+}
diff --git a/src/l_rawio.h b/src/l_rawio.h
new file mode 100644
index 0000000..9fa8713
--- /dev/null
+++ b/src/l_rawio.h
@@ -0,0 +1,41 @@
+/*
+ * gcsd
+ *
+ * gcsd the generic command sequencer daemon can be used to serialize
+ * commands sent over various paralell communication channels to a
+ * single command output. It can be seen as a multiplexer for any
+ * kind of communication between a single resource and various clients
+ * which want to submit commands to it or query information from it.
+ * gcsd is written in C and Lua. The goal is to provide an easy to
+ * understand high level API based on Lua which can be used to
+ * implement the business logic of the so formed multiplexer daemon.
+ *
+ *
+ * Copyright (C) 2009-2010 Markus Grueneis <gimpf@spreadspace.org>
+ * Christian Pointner <equinox@spreadspace.org>
+ *
+ * This file is part of gcsd.
+ *
+ * gcsd is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * gcsd is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with gcsd. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GCSD_l_rawio_h_INCLUDED
+#define GCSD_l_rawio_h_INCLUDED
+
+#include <lua.h>
+
+#define LUA_RAWIOLIBNAME "rawio"
+LUALIB_API int luaopen_rawio(lua_State *L);
+
+#endif
diff --git a/src/modules/stdio.lua b/src/modules/stdio.lua
new file mode 100644
index 0000000..21d314e
--- /dev/null
+++ b/src/modules/stdio.lua
@@ -0,0 +1,134 @@
+--
+-- gcsd
+--
+-- gcsd the generic command sequencer daemon can be used to serialize
+-- commands sent over various paralell communication channels to a
+-- single command output. It can be seen as a multiplexer for any
+-- kind of communication between a single resource and various clients
+-- which want to submit commands to it or query information from it.
+-- gcsd is written in C and Lua. The goal is to provide an easy to
+-- understand high level API based on Lua which can be used to
+-- implement the business logic of the so formed multiplexer daemon.
+--
+--
+-- Copyright (C) 2009-2010 Markus Grueneis <gimpf@spreadspace.org>
+-- Christian Pointner <equinox@spreadspace.org>
+--
+-- This file is part of gcsd.
+--
+-- gcsd is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation, either version 3 of the License, or
+-- any later version.
+--
+-- gcsd is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with gcsd. If not, see <http://www.gnu.org/licenses/>.
+--
+
+local defines = require("defines")
+
+-- stdio module class
+local stdio = {}
+stdio.properties = { type=defines.INOUT_MODULE, name="stdio", max_instances=1 }
+
+-- create new instance of stdio module class
+function stdio:new(config)
+ local inst = {}
+ inst.class = self.properties.name
+ inst.config = config
+ if(config.name == nil or config.name == "") then
+ inst.name = self.properties.name
+ else
+ inst.name = config.name
+ end
+
+ local in_handle = {}
+ in_handle.fd = 0
+ rawio.setnonblock(in_handle.fd)
+ in_handle.client_instance = nil
+ in_handle.in_buffer = ""
+ function in_handle:getfd() return self.fd end
+ function in_handle:dirty() return 0 end
+ function in_handle:read()
+ -- TODO: support read until matched command
+ local buffer, err = rawio.read(0, 100)
+ if(buffer == nil) then
+ log.printf(log.ERROR, inst.name .. ": connection error: %s", err)
+ return defines.KILL_MODULE_CLASS
+ else
+ self.in_buffer = self.in_buffer .. buffer
+ end
+
+ -- TODO: dispatch table et al
+ command_queue:command_completed()
+
+ return defines.OK
+ end
+ function in_handle:write() end
+
+ local out_handle = {}
+ out_handle.fd = 1
+ rawio.setnonblock(out_handle.fd)
+ out_handle.client_instance = nil
+ out_handle.out_buffer = ""
+ function out_handle:getfd() return self.fd end
+ function out_handle:dirty() return 0 end
+ function out_handle:read() end
+ function out_handle:write()
+ local len, err = rawio.write(1, self.out_buffer)
+ if(len == nil) then
+ log.printf(log.ERROR, inst.name .. ": connection error: %s", err)
+ ret = defines.KILL_MODULE_CLASS
+ else
+ self.out_buffer = string.sub(self.out_buffer, len+1)
+ end
+ if(self.out_buffer == "") then
+ command_queue:command_sent()
+ end
+ return defines.OK
+ end
+
+ local client = {}
+ client.module_instance = inst
+ client.name = inst.name .. "#0"
+ function client:process_response() end
+ function client:process_timeout() end
+ function client:get_read_handles()
+ return { in_handle }
+ end
+ function client:get_write_handles()
+ if(out_handle.out_buffer ~= "") then
+ return { out_handle }
+ else
+ return {}
+ end
+ end
+ function client:cleanup() end
+ in_handle.client_instance = client
+ out_handle.client_instance = client
+
+ function inst:cleanup()
+ client_list:unregister_by_module(self)
+ end
+ function inst:get_read_handles()
+ return {}
+ end
+ function inst:get_write_handles()
+ return {}
+ end
+ function inst:start_command(command)
+ out_handle.out_buffer = command
+ end
+ setmetatable(inst, {})
+ getmetatable(inst).__gc = function() inst:cleanup() end
+
+ client_list:register(client)
+ return inst
+end
+
+return stdio
diff --git a/src/modules/stdout.lua b/src/modules/stdout.lua
index c88812d..c82aa1f 100644
--- a/src/modules/stdout.lua
+++ b/src/modules/stdout.lua
@@ -34,8 +34,7 @@ local defines = require("defines")
-- stdout module class
local stdout = {}
-stdout.properties = { type=defines.OUT_MODULE, name="stdout", max_instances=-1 }
-stdout.next_id = 0
+stdout.properties = { type=defines.OUT_MODULE, name="stdout", max_instances=1 }
-- create new instance of stdout module class
function stdout:new(config)
@@ -43,25 +42,33 @@ function stdout:new(config)
inst.class = self.properties.name
inst.config = config
if(config.name == nil or config.name == "") then
- inst.name = self.properties.name .. self.next_id
- self.next_id = self.next_id + 1
+ inst.name = self.properties.name
else
inst.name = config.name
end
+
local handle = {}
handle.fd = 1
+ rawio.setnonblock(handle.fd)
handle.client_instance = nil
handle.out_buffer = nil
function handle:getfd() return self.fd end
function handle:dirty() return 0 end
function handle:read() end
function handle:write()
- io.stdout:write(self.out_buffer)
- io.stdout:flush()
- self.out_buffer = nil
- command_queue:command_sent()
- command_queue:command_completed()
+ local len, err = rawio.write(1, self.out_buffer)
+ if(len == nil) then
+ log.printf(log.INFO, inst.name .. ": connection error: %s", err)
+ ret = defines.KILL_MODULE_CLASS
+ else
+ self.out_buffer = string.sub(self.out_buffer, len+1)
+ end
+ if(self.out_buffer == "") then
+ command_queue:command_sent()
+ command_queue:command_completed()
+ end
+ return defines.OK
end
local client = {}