diff options
author | Christian Pointner <equinox@spreadspace.org> | 2010-11-17 21:21:49 +0000 |
---|---|---|
committer | Christian Pointner <equinox@spreadspace.org> | 2010-11-17 21:21:49 +0000 |
commit | c4ff2ad81a78d7e608e7df4be1a61a347eaf9400 (patch) | |
tree | 76bb09cee4b7d3dce7a4886e70aa8bc4eba87b31 | |
parent | added 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-- | TODO | 3 | ||||
-rw-r--r-- | src/Makefile | 1 | ||||
-rw-r--r-- | src/gcsd.c | 3 | ||||
-rw-r--r-- | src/l_rawio.c | 141 | ||||
-rw-r--r-- | src/l_rawio.h | 41 | ||||
-rw-r--r-- | src/modules/stdio.lua | 134 | ||||
-rw-r--r-- | src/modules/stdout.lua | 25 |
7 files changed, 336 insertions, 12 deletions
@@ -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) @@ -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 = {} |