From 2c418ff14347f5ae5c4f93c74dcdca9ce8f7e4b0 Mon Sep 17 00:00:00 2001 From: Christian Pointner Date: Wed, 29 Dec 2010 02:54:55 +0000 Subject: debug shell not using lua sockets any more updated TODO and README git-svn-id: https://svn.spreadspace.org/gcsd/trunk@86 ac14a137-c7f1-4531-abe0-07747231d213 --- README | 5 +- TODO | 2 +- src/modules/debug_shell.lua | 228 ++++++++++++++++++++------------------------ 3 files changed, 106 insertions(+), 129 deletions(-) diff --git a/README b/README index 8323847..cc812b3 100644 --- a/README +++ b/README @@ -26,7 +26,7 @@ if you want to rebuild the manpage: asciidoc modules: - liblua5.1-socket2 + FreeBSD @@ -37,7 +37,8 @@ core: lang/lua modules: - net/luasocket + + Windows ------- diff --git a/TODO b/TODO index 85bef3e..3c1401e 100644 --- a/TODO +++ b/TODO @@ -1,4 +1,4 @@ - * stop daemon when output module is supposed be removed + * stop daemon when output module is supposed to be removed * send response to requestor * out-of-order responses * add listener tables (for requests, responses and other messages) diff --git a/src/modules/debug_shell.lua b/src/modules/debug_shell.lua index 9632383..a629d3b 100644 --- a/src/modules/debug_shell.lua +++ b/src/modules/debug_shell.lua @@ -30,8 +30,6 @@ -- along with gcsd. If not, see . -- -local socket = require("socket") - -- debug shell module class local debug_shell = {} debug_shell.properties = { type=defines.MISC_MODULE, name="debug_shell", max_instances=-1 } @@ -52,143 +50,121 @@ function debug_shell:new(config, runtype) if(not config.host) then config.host = self.defaults.host end if(not config.port) then config.port = self.defaults.port end - local ip, err = socket.dns.toip(config.host) - if(ip == nil) then - log.printf(log.ERROR, inst.name .. ": can't resolve %s: %s", config.host, err) - return nil - end - - local server_sock_raw, err = socket.tcp() - if(server_sock_raw == nil) then - log.printf(log.ERROR, inst.name .. ": can't create tcp socket") + local lst, err = tcp.server(config.addr, config.port, config.resolv_type) + if(not lst) then return nil - end + end - server_sock_raw:setoption('reuseaddr', true); - - local ret, err = server_sock_raw:bind(ip, config.port) - if(ret == nil) then - log.printf(log.ERROR, inst.name .. ": bind(%s,%s) failed: %s", ip, config.port, err) - return nil - end - - local ret, err = server_sock_raw:listen() - if(ret == nil) then - log.printf(log.ERROR, inst.name .. ": listen() failed: %s", err) - return nil - end - - server_sock_raw:settimeout(0) + inst.listeners = lst + for _, l in ipairs(inst.listeners) do + log.printf(log.NOTICE, "%s: listening on %s (this is a huge security risk)", inst.name, tcp.endtostring(l.local_end)) - local server_sock = {} - server_sock.fd = server_sock_raw:getfd() - server_sock.sock = server_sock_raw - function server_sock:read() - local client_sock_raw, err = self.sock:accept() - if(client_sock_raw == nil) then - log.printf(log.ERROR, inst.name .. ": accept() failed: %s", err) - end - local ip, port = client_sock_raw:getpeername(); - log.printf(log.INFO, inst.name .. ": connection from %s:%s accepted", ip, port) - client_sock_raw:settimeout(0); - client_sock_raw:setoption('tcp-nodelay', true); - - local client_sock = {} - client_sock.fd = client_sock_raw:getfd() - client_sock.sock = client_sock_raw - client_sock.client_instance = nil - client_sock.in_buffer = "" - client_sock.out_buffer = "" - function client_sock:read() - local ret = defines.OK - local data, err, partial = self.sock:receive('*l') - if(data == nil) then - if(err == 'closed') then - log.printf(log.INFO, inst.name .. ": connection closed by peer") + function l:read() + local new_client, addr = tcp.accept(self.fd) + if(not new_client) then + log.printf(ERROR, "inst.name: %s", addr) + return defines.KILL_MODULE + end + + local client_handle = {} + client_handle.fd = new_client + client_handle.client_instance = nil + client_handle.in_buffer = "" + client_handle.out_buffer = "" + function client_handle:read() + -- TODO: which size should we request?? + local buffer, err = tcp.recv(self.fd, 100) + if(buffer == nil) then + log.printf(log.ERROR, inst.name .. ": connection error: %s", err) + return defines.KILL_CLIENT + end + if(#buffer == 0) then + log.printf(log.INFO, inst.name .. ": connection closed") + return defines.KILL_CLIENT + end + self.in_buffer = self.in_buffer .. buffer + return debug_shell:parse_cmd(self) + end + function client_handle:write() + local len, err = tcp.send(self.fd, self.out_buffer) + if(len == nil) then + log.printf(log.ERROR, inst.name .. ": connection error: %s", err) ret = defines.KILL_CLIENT - elseif(err == 'timeout') then - self.in_buffer = self.in_buffer .. partial else - log.printf(log.INFO, inst.name .. ": connection error: %s", err) - ret = defines.KILL_CLIENT + self.out_buffer = string.sub(self.out_buffer, len+1) end - else - self.in_buffer = self.in_buffer .. data - ret = debug_shell:exec_cmd(self) - self.in_buffer = "" + return defines.OK end - return ret - end - function client_sock:write() - local ret = defines.OK - local len, err, partiallen = self.sock:send(self.out_buffer) - if(len == nil) then - if(err == 'closed') then - log.printf(log.INFO, inst.name .. ": connection closed by peer") - ret = defines.KILL_CLIENT - elseif(err == 'timeout') then - self.out_buffer = string.sub(self.out_buffer, partiallen+1) + + local client = {} + client.module_instance = inst + client.addr = addr + client.name = inst.name .. "#" .. tcp.endtostring(addr) + function client:process_response() end + function client:process_timeout() end + function client:get_read_handles() + return { client_handle } + end + function client:get_write_handles() + if(client_handle.out_buffer ~= "") then + return { client_handle } else - log.printf(log.INFO, inst.name .. ": connection error: %s", err) - ret = defines.KILL_CLIENT + return {} end - else - self.out_buffer = string.sub(self.out_buffer, len+1) end - return ret - end - - local client = {} - client.module_instance = inst - client.name = inst.name .. "#" .. ip .. ":" .. port - 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 {} + function client:cleanup() + rawio.close(client_handle.fd) end + client_handle.client_instance = client + client_list:register(client) + return defines.OK end - function client:cleanup() - self.sock.sock:close() - end - client_sock.client_instance = client - - client_list:register(client) - return defines.OK + function l:write() return defines.OK end end - function server_sock:write() return defines.OK end - - log.printf(log.WARNING, inst.name .. ": listening on %s:%s (this is a huge security risk)", ip, config.port); function inst:cleanup() client_list:unregister_by_module(self) - server_sock.sock:close() + for _, l in ipairs(self.listeners) do + rawio.close(l.fd); + end end - function inst:get_read_handles() - return { server_sock } + function inst:get_read_handles() + return self.listeners end function inst:get_write_handles() return {} end setmetatable(inst, {}) getmetatable(inst).__gc = function() inst:cleanup() end + return inst end -function debug_shell:exec_cmd(socket) - local client_name = socket.client_instance.name - log.printf(log.DEBUG, client_name .. ": received string: '%s'", socket.in_buffer) +function debug_shell:parse_cmd(handle) + local ret = defines.OK + local init = 1 + repeat + local had_match = false + local cmd, delim = string.match(handle.in_buffer, "([^\n\r]*)(\r?\n)", init) + if cmd and delim then + ret = self:exec_cmd(handle, cmd) + had_match = true + init = init + string.len(cmd) + string.len(delim) + break + end + until (not had_match or ret ~= defines.OK) + + handle.in_buffer = string.sub(handle.in_buffer, init + 1) + + return ret +end + +function debug_shell:exec_cmd(handle, buffer) + local client_name = handle.client_instance.name + log.printf(log.DEBUG, client_name .. ": received string: '%s'", buffer) local ret = defines.OK - local luacode = string.match(socket.in_buffer, "^!(.*)$"); + local luacode = string.match(buffer, "^!(.*)$"); if(luacode and luacode ~= "") then local chunk = loadstring(luacode) if(chunk) then @@ -197,37 +173,37 @@ function debug_shell:exec_cmd(socket) 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)) + handle.out_buffer = handle.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])) + handle.out_buffer = handle.out_buffer .. string.format("lua call failed: %s\n", tostring(results[2])) end else - socket.out_buffer = socket.out_buffer .. "syntax error\n" + handle.out_buffer = handle.out_buffer .. "syntax error\n" end else - local cmd, sep, param = string.match(socket.in_buffer, "^(%w+)(.?)(.*)$"); + local cmd, sep, param = string.match(buffer, "^(%w+)(.?)(.*)$"); if(cmd == 'quit') then - if(sep and sep ~= "") then socket.out_buffer = socket.out_buffer .. "unknown command\n" end + if(sep and sep ~= "") then handle.out_buffer = handle.out_buffer .. "unknown command\n" end log.printf(log.INFO, client_name .. ": quitting debug session") ret = defines.KILL_CLIENT elseif(cmd == 'disable') then - if(sep and sep ~= "") then socket.out_buffer = socket.out_buffer .. "unknown command\n" end + if(sep and sep ~= "") then handle.out_buffer = handle.out_buffer .. "unknown command\n" end log.printf(log.NOTICE, client_name .. ": disabling this debug shell instance and close all connections") ret = defines.KILL_MODULE elseif(cmd == 'disableall') then - if(sep and sep ~= "") then socket.out_buffer = socket.out_buffer .. "unknown command\n" end + if(sep and sep ~= "") then handle.out_buffer = handle.out_buffer .. "unknown command\n" end log.printf(log.NOTICE, client_name .. ": disabling all debug shell instances and close all connections") ret = defines.KILL_MODULE_CLASS elseif(cmd == 'terminate') then - if(sep and sep ~= "") then socket.out_buffer = socket.out_buffer .. "unknown command\n" end + if(sep and sep ~= "") then handle.out_buffer = handle.out_buffer .. "unknown command\n" end log.printf(log.NOTICE, client_name .. ": terminate command received") ret = defines.KILL_DAEMON 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 .. "! execute lua code\n" .. + if(sep and sep ~= "") then handle.out_buffer = handle.out_buffer .. "unknown command\n" end + handle.out_buffer = handle.out_buffer .. "! execute lua code\n" .. "cmd add the command to the command queue\n" .. "quit quit this debug session\n" .. "ping[ ] echo request (response will be 'pong[ ]')\n" .. @@ -235,16 +211,16 @@ function debug_shell:exec_cmd(socket) "disableall close all debug shell instances and close all connections\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 + if(sep == ' ') then handle.out_buffer = handle.out_buffer .. "pong " .. (param or "") .. "\n" + else handle.out_buffer = handle.out_buffer .. "pong\n" end elseif(cmd == 'cmd') then - if(not param or param == '') then socket.out_buffer = socket.out_buffer .. "Error: please specify a command\n" + if(not param or param == '') then handle.out_buffer = handle.out_buffer .. "Error: please specify a command\n" else - socket.out_buffer = socket.out_buffer .. "enqueing command: " .. param .. "\n" + handle.out_buffer = handle.out_buffer .. "enqueing command: " .. param .. "\n" command_queue:enqueue(param, "ok\n", 2500) end else - socket.out_buffer = socket.out_buffer .. "unknown command\n" + handle.out_buffer = handle.out_buffer .. "unknown command\n" end end -- cgit v1.2.3