summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Pointner <equinox@spreadspace.org>2010-11-08 20:14:02 +0000
committerChristian Pointner <equinox@spreadspace.org>2010-11-08 20:14:02 +0000
commitc56fafa5a7e85af0aede981a2de5ddb337e2fa40 (patch)
treec0a9db84da108edbacca706d89d52185d6245869
parentupdated main_loop (diff)
moved debug shell to modules
git-svn-id: https://svn.spreadspace.org/gcsd/trunk@10 ac14a137-c7f1-4531-abe0-07747231d213
-rw-r--r--src/Makefile6
-rw-r--r--src/debug_shell.lua174
-rw-r--r--src/defines.lua41
-rw-r--r--src/main_loop.lua44
-rw-r--r--src/modules/debug_shell.lua204
5 files changed, 277 insertions, 192 deletions
diff --git a/src/Makefile b/src/Makefile
index 007bae8..f6c8fee 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -48,12 +48,10 @@ C_OBJS := log.o \
C_SRCS := $(C_OBJS:%.o=%.c)
-#MODULES := dummy
+#MODULES := dummy debug_shell
#MODULE_SRC := $(MODULES:%=modules/%.lua)
-LUA_SRCS := main_loop.lua \
- debug_shell.lua
-
+LUA_SRCS := main_loop.lua
LUA_BYTECODE := $(EXECUTABLE).lc
LUA_BYTECODE_OBJ := $(EXECUTABLE)_lua_bytecode.o
diff --git a/src/debug_shell.lua b/src/debug_shell.lua
deleted file mode 100644
index 49df934..0000000
--- a/src/debug_shell.lua
+++ /dev/null
@@ -1,174 +0,0 @@
---
--- 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/>.
---
-
-socket = require("socket")
-
-debug_shell = {}
-
-debug_shell.socks = {};
-
-debug_shell.init = function(host, port)
- local ip, err = socket.dns.toip(host)
- if(ip == nil) then
- log.printf(log.ERROR, "debug shell: can't resolve %s: %s", host, err)
- return nil
- end
-
- debug_shell.socks[1], err = socket.tcp()
- if(debug_shell.socks[1] == nil) then
- log.printf(log.ERROR, "debug shell: can't create tcp socket")
- return nil
- end
-
- debug_shell.socks[1]:setoption('reuseaddr', true);
-
- local ret, err = debug_shell.socks[1]:bind(ip, port)
- if(ret == nil) then
- log.printf(log.ERROR, "debug shell: bind(%s,%s) failed: %s", ip, port, err)
- return nil
- end
-
- local ret, err = debug_shell.socks[1]:listen()
- if(ret == nil) then
- log.printf(log.ERROR, "debug shell: listen() failed: %s", err)
- return nil
- end
-
- debug_shell.socks[1]:settimeout(0);
- debug_shell.buffer = "";
-
- log.printf(log.WARNING, "debug shell: listening on %s:%s (this is a huge security risk)", ip, port);
-
- return debug_shell.socks[1]
-end
-
-debug_shell.close = function()
- debug_shell.socks[1]:close()
- if(debug_shell.socks[2]) then debug_shell.socks[2]:close() end
-end
-
-debug_shell.handle = function(sock)
- local ret = 0
- if(sock == debug_shell.socks[1]) then
- local newclient, err = debug_shell.socks[1]:accept()
- if(newclient == nil) then
- log.printf(log.ERROR, "debug shell: accept() failed: %s", err)
- end
- local ip, port = newclient:getpeername();
- if(debug_shell.socks[2]) then
- log.printf(log.INFO, "debug shell: refusing connection from %s:%s, already connected", ip, port)
- newclient:close();
- else
- log.printf(log.INFO, "debug shell: connection from %s:%s accepted", ip, port)
- debug_shell.socks[2] = newclient
- debug_shell.socks[2]:settimeout(0);
- debug_shell.socks[2]:setoption('tcp-nodelay', true);
- debug_shell.buffer = "";
- end
- else
- local data, err, partial = debug_shell.socks[2]:receive('*l')
- if(data == nil) then
- if(err == 'closed') then
- log.printf(log.INFO, "debug shell: connection closed by peer")
- debug_shell.socks[2]:close()
- debug_shell.socks[2] = nil
- elseif(err == 'timeout') then
- debug_shell.buffer = debug_shell.buffer .. partial
- else
- log.printf(log.INFO, "debug shell: connection error: %s", err)
- debug_shell.socks[2]:close()
- debug_shell.socks[2] = nil
- end
- else
- debug_shell.buffer = debug_shell.buffer .. data
- ret = debug_shell.exec_cmd()
- if(ret == 1) then
- debug_shell.socks[2]:close()
- debug_shell.socks[2] = nil
- ret = 0
- end
- debug_shell.buffer = ""
- end
- end
-
- return ret
-end
-
-debug_shell.exec_cmd = function()
- log.printf(log.DEBUG, "debug shell: received string: '%s'", debug_shell.buffer)
-
- local ret = 0
- local luacode = string.match(debug_shell.buffer, "^!(.*)$");
- if(luacode and luacode ~= "") then
- local chunk = loadstring(luacode)
- if(chunk) then
- log.printf(log.DEBUG, "debug shell: calling lua command: '%s'", luacode)
- local results = { pcall(chunk) }
- if(results[1]) then
- for i,result in ipairs(results) do
- if(i > 1) then
- debug_shell.socks[2]:send(string.format("#%d: %s\n", i-1, tostring(result)))
- end
- end
- else
- debug_shell.socks[2]:send(string.format("lua call failed: %s\n", tostring(results[2])))
- end
- else
- debug_shell.socks[2]:send("syntax error\n")
- end
- else
- local cmd, sep, param = string.match(debug_shell.buffer, "^(%w+)(.?)(.*)$");
-
- if(cmd == 'quit') then
- if(sep and sep ~= "") then debug_shell.socks[2]:send("unknown command\n") end
- log.printf(log.INFO, "debug shell: quitting debug session")
- ret = 1
- elseif(cmd == 'terminate') then
- if(sep and sep ~= "") then debug_shell.socks[2]:send("unknown command\n") end
- log.printf(log.NOTICE, "debug shell: terminate command received")
- ret = 2
- elseif(cmd == 'help') then
- if(sep and sep ~= "") then debug_shell.socks[2]:send("unknown command\n") end
- debug_shell.socks[2]:send("!<lua code> execute lua code\n" ..
- "quit quit this debug session\n" ..
- "ping[ <data>] echo request (response will be 'pong[ <data>]')\n" ..
- "terminate terminate the daemon\n")
- elseif(cmd == 'ping') then
- if(sep == ' ') then debug_shell.socks[2]:send("pong " .. (param or "") .. "\n")
- else debug_shell.socks[2]:send("pong\n") end
- else
- debug_shell.socks[2]:send("unknown command\n")
- end
- end
-
- return ret
-end
diff --git a/src/defines.lua b/src/defines.lua
new file mode 100644
index 0000000..017fb6f
--- /dev/null
+++ b/src/defines.lua
@@ -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/>.
+--
+
+local defines = {}
+
+defines.OK = 0
+defines.KILL_CLIENT = 1
+defines.KILL_MODULE = 2
+defines.KILL_MODULE_TYPE = 3
+defines.KILL_DAEMON = 4
+
+return defines \ No newline at end of file
diff --git a/src/main_loop.lua b/src/main_loop.lua
index da48515..68924df 100644
--- a/src/main_loop.lua
+++ b/src/main_loop.lua
@@ -30,7 +30,8 @@
-- along with gcsd. If not, see <http://www.gnu.org/licenses/>.
--
-socket = require("socket")
+local socket = require("socket")
+local defines = require("defines")
function main_loop(opt)
log.printf(log.NOTICE, "main_loop started")
@@ -41,20 +42,23 @@ function main_loop(opt)
log.printf(log.DEBUG, "gcsd input[%d] = %s", idx, input)
end
+--- TODO: load configured modules (use own module loader)
local modules = {}
-- parse module config
local old_path = package.path
package.path = "./modules/?.lua"
dummy = require ("dummy")
+ if(opt.debug) then
+ debug_shell = require ("debug_shell")
+ end
package.path = old_path
- table.insert(modules, dummy.new("module config"))
-
+ table.insert(modules, dummy.new({}))
if(opt.debug) then
- local ret = debug_shell.init("localhost", 9000)
- if(ret == nil) then return -1 end
+ table.insert(modules, debug_shell.new({[host]="127.0.0.1", [port]="9000"}))
end
+--------
local return_value = 0
while return_value == 0 do
@@ -65,14 +69,17 @@ function main_loop(opt)
table.insert(readables, fd)
end
end
+-- TODO: add read handles of all clients
+
local writeables = { }
for _, module in ipairs(modules) do
for _, fd in ipairs(module.get_write_handles()) do
table.insert(writeables, fd)
end
end
+-- TODO: add write handles of all clients
- local readable, writeable, err = socket.select(readables , writeables)
+ local readable, writeable, err = socket.select(readables, writeables)
if(err) then
log.printf(log.ERROR, "select returned with error: %s", err)
return_value = -1
@@ -81,24 +88,33 @@ function main_loop(opt)
if(input == sig) then
return_value = signal.handle()
if(return_value == 1) then break end
- elseif(input == debug_shell.socks[1] or input == debug_shell.socks[2]) then
- return_value = debug_shell.handle(input)
- if(return_value == 2) then break end
else
- input.read()
+ local ret = input.read()
+ if(ret == defines.KILL_DAEMON) then
+ return_value = 2
+ break
+ elseif(ret == defines.KILL_MODULE_TYPE) then
+ -- TODO: remove all modules of same type as this and
+ -- unload module
+ elseif(ret == defines.KILL_MODULE) then
+ -- TODO: remove module
+ elseif(ret == defines.KILL_CLIENT) then
+ -- TODO: remove client from list
+ end
end
end
for _, output in ipairs(writeable) do
- output.write()
+ ret = output.write()
+ if(ret ~= defines.OK) then
+ -- TODO: remove client from list
+ end
end
end
end
if(return_value == 2) then return_value = 0 end
- if(opt.debug) then
- debug_shell.close();
- end
+ -- TODO: cleanup clients and modules
signal.stop()
return return_value
end
diff --git a/src/modules/debug_shell.lua b/src/modules/debug_shell.lua
new file mode 100644
index 0000000..1e48d9c
--- /dev/null
+++ b/src/modules/debug_shell.lua
@@ -0,0 +1,204 @@
+--
+-- 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 socket = require("socket")
+local defines = require("defines")
+
+local debug_shell = {}
+debug_shell.properties = { input=true, output=true, max_instances=1 }
+function debug_shell:new(config)
+ local ip, err = socket.dns.toip(config.host)
+ if(ip == nil) then
+ log.printf(log.ERROR, "debug shell: can't resolve %s: %s", config.host, err)
+ return nil
+ end
+
+ local server_sock, err = socket.tcp()
+ if(server_sock == nil) then
+ log.printf(log.ERROR, "debug shell: can't create tcp socket")
+ return nil
+ end
+
+ server_sock:setoption('reuseaddr', true);
+
+ local ret, err = server_sock:bind(ip, config.port)
+ if(ret == nil) then
+ log.printf(log.ERROR, "debug shell: bind(%s,%s) failed: %s", ip, config.port, err)
+ return nil
+ end
+
+ local ret, err = server_sock:listen()
+ if(ret == nil) then
+ log.printf(log.ERROR, "debug shell: listen() failed: %s", err)
+ return nil
+ end
+
+ server_sock:settimeout(0);
+ function server_sock:read()
+ local client_sock, err = server_sock:accept()
+ if(newclient == nil) then
+ log.printf(log.ERROR, "debug shell: accept() failed: %s", err)
+ end
+ local ip, port = client_sock:getpeername();
+ log.printf(log.INFO, "debug shell: connection from %s:%s accepted", ip, port)
+ client_sock:settimeout(0);
+ client_sock:setoption('tcp-nodelay', true);
+ client_sock.in_buffer = ""
+ client_sock.out_buffer = ""
+ function client_sock:read()
+ local ret = 0
+ local data, err, partial = self.receive('*l')
+ if(data == nil) then
+ if(err == 'closed') then
+ log.printf(log.INFO, "debug shell: connection closed by peer")
+ -- TODO: remove client
+ elseif(err == 'timeout') then
+ self.in_buffer = self.in_buffer .. partial
+ else
+ log.printf(log.INFO, "debug shell: connection error: %s", err)
+ -- TODO: remove client
+ end
+ else
+ self.in_buffer = self.in_buffer .. data
+ ret = debug_shell:exec_cmd(self)
+ if(ret == 1) then
+ -- TODO: remove client
+ ret = 0
+ end
+ self.in_buffer = ""
+ end
+ end
+ function client_sock:write()
+ self.send(self.out_buffer)
+ self.out_buffer = ""
+ end
+
+ local client = {}
+ client.sock = client_sock
+ function client:process_response(response)
+ self.sock.out_buffer = self.sock.out_buffer .. response
+ end
+ function client:process_timeout() end
+ function client:get_read_handles()
+ return { self.sock }
+ end
+ function client:get_write_handles()
+ if(self.sock.out_buffer ~= "") then
+ return { self.sock }
+ else
+ return {}
+ end
+ end
+ function client:cleanup()
+ self.sock.close()
+ end
+
+ -- TODO: register new client
+
+ return defines.OK
+ end
+ function server_sock:write() return defines.OK end
+
+ log.printf(log.WARNING, "debug shell: listening on %s:%s (this is a huge security risk)", ip, config.port);
+
+ local inst = {
+ cleanup = function()
+ -- TODO: close all clients !!!
+ server_sock:close()
+ end,
+ get_read_handles = function()
+ return { server_sock }
+ end,
+ get_write_handles = function()
+ return {}
+ end
+ }
+ metatable(inst).__gc = inst.cleanup()
+ return inst
+end
+
+function debug_shell:exec_cmd(socket)
+ log.printf(log.DEBUG, "debug shell: received string: '%s'", socket.in_buffer)
+
+ local ret = 0
+ local luacode = string.match(socket.in_buffer, "^!(.*)$");
+ if(luacode and luacode ~= "") then
+ local chunk = loadstring(luacode)
+ if(chunk) then
+ log.printf(log.DEBUG, "debug shell: calling lua command: '%s'", luacode)
+ local results = { pcall(chunk) }
+ if(results[1]) then
+ for i,result in ipairs(results) do
+ if(i > 1) then
+ socket.out_buffer = socket.out_buffer .. string.format("#%d: %s\n", i-1, tostring(result))
+ end
+ end
+ else
+ socket.out_buffer = socket.out_buffer .. string.format("lua call failed: %s\n", tostring(results[2]))
+ end
+ else
+ socket.out_buffer = socket.out_buffer .. "syntax error\n"
+ end
+ else
+ local cmd, sep, param = string.match(socket.in_buffer, "^(%w+)(.?)(.*)$");
+
+ if(cmd == 'quit') then
+ if(sep and sep ~= "") then socket.out_buffer = socket.out_buffer .. "unknown command\n" end
+ log.printf(log.INFO, "debug shell: quitting debug session")
+ ret = 1
+ elseif(cmd == 'terminate') then
+ if(sep and sep ~= "") then socket.out_buffer = socket.out_buffer .. "unknown command\n" end
+ log.printf(log.NOTICE, "debug shell: terminate command received")
+ ret = 2
+ elseif(cmd == 'help') then
+ if(sep and sep ~= "") then socket.out_buffer = socket.out_buffer .. "unknown command\n" end
+ socket.out_buffer = socket.out_buffer .. "!<lua code> execute lua code\n" ..
+ "quit quit this debug session\n" ..
+ "ping[ <data>] echo request (response will be 'pong[ <data>]')\n" ..
+ "terminate terminate the daemon\n"
+ elseif(cmd == 'ping') then
+ if(sep == ' ') then socket.out_buffer = socket.out_buffer .. "pong " .. (param or "") .. "\n"
+ else socket.out_buffer = socket.out_buffer .. "pong\n" end
+ else
+ socket.out_buffer = socket.out_buffer .. "unknown command\n"
+ end
+ end
+
+ return ret
+end
+
+return debug_shell
+
+
+
+
+