diff options
Diffstat (limited to 'lib/supple/comms.lua')
-rw-r--r-- | lib/supple/comms.lua | 125 |
1 files changed, 125 insertions, 0 deletions
diff --git a/lib/supple/comms.lua b/lib/supple/comms.lua new file mode 100644 index 0000000..efe737f --- /dev/null +++ b/lib/supple/comms.lua @@ -0,0 +1,125 @@ +-- lib/supple/comms.lua +-- +-- Sandbox (for) Untrusted Procedure Partitioning (in) Lua Engine +-- +-- Management of communications between host and sandbox +-- +-- Copyright 2012 Daniel Silverstone <dsilvers@digital-scurf.org> +-- +-- For licence terms, see COPYING +-- + +local luxio = require "luxio" + +local capi = require "supple.capi" +local request = require "supple.request" +local objects = require "supple.objects" + +local unpack = unpack +local tonumber = tonumber +local error = error + +local fd = -1 + +local function set_fd(_fd) + fd = _fd +end + +local function send_msg(msg) + if (#msg > 99999) then + error("Message too long") + end + local msglen = ("%05d"):format(#msg) + luxio.write(fd, msglen .. msg) +end + +local function recv_msg() + local len = luxio.read(fd, 5) + if #len < 5 then + error("Unable to read 5 byte length") + end + len = tonumber(len) + if len == nil or len < 1 or len > 99999 then + error("Odd, len didn't translate properly") + end + local str = luxio.read(fd, len) + if type(str) ~= "string" or #str ~= len then + error("Unable to read " .. tostring(len) .. " bytes of msg") + end + return str +end + +local function wait_for_response() + local back = request.deserialise(recv_msg()) + -- back could be three things + -- an error (raise it) + if back.error then + error(back.message .. "\n" .. back.traceback) + end + -- A result, return it + if back.error == false then + return unpack(back.results) + end + -- A method call, call it + + local function safe_method(fn) + local ok, res = pcall(fn) + local resp + if not ok then + resp = request.error(res, "") + else + resp = request.response(unpack(res)) + end + send_msg(resp) + end + if back.method == "__gc" then + -- __gc is the garbage collect mechanism + objects.forget_mine(back.object) + send_msg(request.response()) + elseif back.method == "__call" then + -- __call is the function call mechanism + safe_method(function() + local obj = objects.receive { tag = back.object } + return {obj(unpack(back.args))} + end) + elseif back.method == "__len" then + safe_method(function() + local obj = objects.receive { tag = back.object } + return {#obj} + end) + elseif back.method == "__index" then + safe_method(function() + local obj = objects.receive { tag = back.object } + return {obj[back.args[1]]} + end) + elseif back.method == "__newindex" then + safe_method(function() + local obj = objects.receive { tag = back.object } + obj[back.args[1]] = back.args[2] + return {} + end) + else + safe_method(function() + local obj = objects.receive { tag = back.object } + local meth = capi.raw_getmm(obj, back.method) + if not meth then + error("Unknown or disallowed method: " .. back.method, "") + end + return {meth(obj, unpack(back.args))} + end) + end + -- And try again + return wait_for_response() +end + +local function make_call(object, method, ...) + local req = request.request(object, method, ...) + send_msg(req) + return wait_for_response() +end + +return { + call = make_call, + _wait = wait_for_response, + _set_fd = set_fd, +}
\ No newline at end of file |