From a7708b9e47299c6c48742e446d7705a75d5a3603 Mon Sep 17 00:00:00 2001 From: XeonSquared Date: Wed, 20 Sep 2023 00:01:21 +1000 Subject: [PATCH] address RPC loop issues as described in https://github.com/ShadowKatStudios/OC-Minitel/pull/40 plus implement ACLs like the OpenOS version of the RPC library --- lib/rpc.lua | 50 ++++++++++++++++++++++++++++++++++---------------- 1 file changed, 34 insertions(+), 16 deletions(-) diff --git a/lib/rpc.lua b/lib/rpc.lua index 23dac4c..ab92fa4 100644 --- a/lib/rpc.lua +++ b/lib/rpc.lua @@ -5,19 +5,34 @@ local rpc = {} _G.rpcf = {} rpc.port = 111 -local function rpcexec(_, from, port, data) - if port == rpc.port then - local rpcrq = serial.unserialize(data) - local rpcn, rpcid = table.remove(rpcrq,1), table.remove(rpcrq,1) - if rpcf[rpcn] then - local rt = {pcall(rpcf[rpcn],table.unpack(rpcrq))} - if rt[1] == true then - table.remove(rt,1) - end - minitel.send(from,port,serial.serialize({rpcid,table.unpack(rt)})) - else - end +local function setacl(self, fname, host) + self[fname] = self[fname] or {} + self[fname][host] = true +end +rpc.allow = setmetatable({},{__call=setacl}) +rpc.deny = setmetatable({},{__call=setacl}) + +local function isPermitted(host,fn) + if rpc.allow[fn] then + return rpc.allow[fn][host] or false end + if rpc.deny[fn] and rpc.deny[fn][host] then + return false + end + return true +end + +local function rpcexec(_, from, port, data) + os.spawn(function() + if port == rpc.port then + local rpcrq = serial.unserialize(data) or {} + if rpcf[rpcrq[1]] and isPermitted(from,rpcrq[1]) then + minitel.send(from,port,serial.serialize({rpcrq[2],pcall(rpcf[rpcrq[1]],table.unpack(rpcrq,3))})) + elseif type(rpcrq[2]) == "string" then + minitel.send(from,port,serial.serialize({rpcrq[2],false,"function unavailable"})) + end + end + end,"rpc worker for "..tostring(from)) end function rpcf.list() local rt = {} @@ -39,10 +54,13 @@ function rpc.call(hostname,fn,...) -- string string -- boolean -- Calls exported local _, from, port, data = event.pull(30, "net_msg", hostname, rpc.port) rt = serial.unserialize(tostring(data)) or {} until (type(rt) == "table" and rt[1] == rv) or computer.uptime() > st + 30 - if table.remove(rt,1) == rv then - return table.unpack(rt) + if rt[1] == rv then + if rt[2] then + return table.unpack(rt,3) + end + error(rt[3]) end - return false + error("timed out") end function rpc.proxy(hostname,filter) -- string string -- table -- Returns a component.proxy()-like table from the functions on *hostname* with names matching *filter*. filter=(filter or "").."(.+)" @@ -69,7 +87,7 @@ function rpc.register(name,fn) -- string function -- -- Registers a function to if not rpcrunning then os.spawn(function() while true do - rpcexec(event.pull("net_msg")) + pcall(rpcexec,event.pull("net_msg")) end end,"rpc daemon") end