summaryrefslogtreecommitdiff
path: root/src/modules
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 /src/modules
parentupdated main_loop (diff)
moved debug shell to modules
git-svn-id: https://svn.spreadspace.org/gcsd/trunk@10 ac14a137-c7f1-4531-abe0-07747231d213
Diffstat (limited to 'src/modules')
-rw-r--r--src/modules/debug_shell.lua204
1 files changed, 204 insertions, 0 deletions
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
+
+
+
+
+