summaryrefslogtreecommitdiff
path: root/lib/supple/comms.lua
diff options
context:
space:
mode:
Diffstat (limited to 'lib/supple/comms.lua')
-rw-r--r--lib/supple/comms.lua125
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