diff options
author | Christian Pointner <equinox@spreadspace.org> | 2010-11-08 20:14:02 +0000 |
---|---|---|
committer | Christian Pointner <equinox@spreadspace.org> | 2010-11-08 20:14:02 +0000 |
commit | c56fafa5a7e85af0aede981a2de5ddb337e2fa40 (patch) | |
tree | c0a9db84da108edbacca706d89d52185d6245869 /src/modules | |
parent | updated 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.lua | 204 |
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 + + + + + |