@@ -1,63 +0,0 @@ | |||||
local imt = {} | |||||
imt.ttypes = {} | |||||
imt.ttypes.string=1 | |||||
imt.ttypes.number=2 | |||||
imt.ftypes = {tostring,tonumber} | |||||
function imt.to16bn(n) | |||||
return string.char(math.floor(n/256))..string.char(math.floor(n%256)) | |||||
end | |||||
function imt.from16bn(s) | |||||
return (string.byte(s,1,1)*256)+string.byte(s,2,2) | |||||
end | |||||
function imt.encodePacket(...) | |||||
local tArgs = {...} | |||||
local packet = string.char(#tArgs%256) | |||||
for _,segment in ipairs(tArgs) do | |||||
local segtype = type(segment) | |||||
segment = tostring(segment) | |||||
packet = packet .. imt.to16bn(segment:len()) .. string.char(imt.ttypes[segtype]) .. tostring(segment) | |||||
end | |||||
packet = imt.to16bn(packet:len()) .. packet | |||||
return packet | |||||
end | |||||
function imt.decodePacket(s) | |||||
local function getfirst(n) | |||||
local ns = s:sub(1,n) | |||||
s=s:sub(n+1) | |||||
return ns | |||||
end | |||||
if s:len() < 2 then return false end | |||||
local plen = imt.from16bn(getfirst(2)) | |||||
local segments = {} | |||||
if s:len() < plen then return false end | |||||
local nsegments = string.byte(getfirst(1)) | |||||
--print(tostring(plen).." bytes, "..tostring(nsegments).." segments") | |||||
for i = 1, nsegments do | |||||
local seglen = imt.from16bn(getfirst(2)) | |||||
local segtype = imt.ftypes[string.byte(getfirst(1))] | |||||
local segment = segtype(getfirst(seglen)) | |||||
--print(seglen,segtype,segment,type(segment)) | |||||
segments[#segments+1] = segment | |||||
end | |||||
return table.unpack(segments) | |||||
end | |||||
function imt.getRemainder(s) | |||||
local function getfirst(n) | |||||
local ns = s:sub(1,n) | |||||
s=s:sub(n+1) | |||||
return ns | |||||
end | |||||
local plen = imt.from16bn(getfirst(2)) | |||||
if s:len() > plen then | |||||
getfirst(plen) | |||||
return s | |||||
end | |||||
return nil | |||||
end | |||||
return imt |
@@ -1,197 +0,0 @@ | |||||
local proxylist = {} | |||||
local proxyobjs = {} | |||||
local typelist = {} | |||||
local doclist = {} | |||||
local oproxy = component.proxy | |||||
function component.proxy(address) | |||||
checkArg(1,address,"string") | |||||
if proxyobjs[address] ~= nil then | |||||
return proxyobjs[address] | |||||
end | |||||
return oproxy(address) | |||||
end | |||||
local olist = component.list | |||||
function component.list(filter, exact) | |||||
checkArg(1,filter,"string","nil") | |||||
local result = {} | |||||
local data = {} | |||||
for k,v in olist(filter, exact) do | |||||
data[#data + 1] = k | |||||
data[#data + 1] = v | |||||
result[k] = v | |||||
end | |||||
for k,v in pairs(typelist) do | |||||
if filter == nil or (exact and v == filter) or (not exact and v:find(filter, nil, true)) then | |||||
data[#data + 1] = k | |||||
data[#data + 1] = v | |||||
result[k] = v | |||||
end | |||||
end | |||||
local place = 1 | |||||
return setmetatable(result, | |||||
{__call=function() | |||||
local addr,type = data[place], data[place + 1] | |||||
place = place + 2 | |||||
return addr, type | |||||
end} | |||||
) | |||||
end | |||||
local otype = component.type | |||||
function component.type(address) | |||||
checkArg(1,address,"string") | |||||
if typelist[address] ~= nil then | |||||
return typelist[address] | |||||
end | |||||
return otype(address) | |||||
end | |||||
local odoc = component.doc | |||||
function component.doc(address, method) | |||||
checkArg(1,address,"string") | |||||
checkArg(2,method,"string") | |||||
if proxylist[address] ~= nil then | |||||
if proxylist[address][method] == nil then | |||||
error("no such method",2) | |||||
end | |||||
if doclist[address] ~= nil then | |||||
return doclist[address][method] | |||||
end | |||||
return nil | |||||
end | |||||
return odoc(address, method) | |||||
end | |||||
local oslot = component.slot | |||||
function component.slot(address) | |||||
checkArg(1,address,"string") | |||||
if proxylist[address] ~= nil then | |||||
return -1 -- vcomponents do not exist in a slot | |||||
end | |||||
return oslot(address) | |||||
end | |||||
local omethods = component.methods | |||||
function component.methods(address) | |||||
checkArg(1,address,"string") | |||||
if proxylist[address] ~= nil then | |||||
local methods = {} | |||||
for k,v in pairs(proxylist[address]) do | |||||
if type(v) == "function" then | |||||
methods[k] = true -- All vcomponent methods are direct | |||||
end | |||||
end | |||||
return methods | |||||
end | |||||
return omethods(address) | |||||
end | |||||
local oinvoke = component.invoke | |||||
function component.invoke(address, method, ...) | |||||
checkArg(1,address,"string") | |||||
checkArg(2,method,"string") | |||||
if proxylist[address] ~= nil then | |||||
if proxylist[address][method] == nil then | |||||
error("no such method",2) | |||||
end | |||||
return proxylist[address][method](...) | |||||
end | |||||
return oinvoke(address, method, ...) | |||||
end | |||||
local ofields = component.fields | |||||
function component.fields(address) | |||||
checkArg(1,address,"string") | |||||
if proxylist[address] ~= nil then | |||||
return {} -- What even is this? | |||||
end | |||||
return ofields(address) | |||||
end | |||||
local componentCallback = | |||||
{ | |||||
__call = function(self, ...) return proxylist[self.address][self.name](...) end, | |||||
__tostring = function(self) return (doclist[self.address] ~= nil and doclist[self.address][self.name] ~= nil) and doclist[self.address][self.name] or "function" end | |||||
} | |||||
local vcomponent = {} | |||||
function vcomponent.register(address, ctype, proxy, doc) | |||||
checkArg(1,address,"string") | |||||
checkArg(2,ctype,"string") | |||||
checkArg(3,proxy,"table") | |||||
if proxylist[address] ~= nil then | |||||
return nil, "component already at address" | |||||
elseif component.type(address) ~= nil then | |||||
return nil, "cannot register over real component" | |||||
end | |||||
proxy.address = address | |||||
proxy.type = ctype | |||||
local proxyobj = {} | |||||
for k,v in pairs(proxy) do | |||||
if type(v) == "function" then | |||||
proxyobj[k] = setmetatable({name=k,address=address},componentCallback) | |||||
else | |||||
proxyobj[k] = v | |||||
end | |||||
end | |||||
proxylist[address] = proxy | |||||
proxyobjs[address] = proxyobj | |||||
typelist[address] = ctype | |||||
doclist[address] = doc | |||||
computer.pushSignal("component_added",address,ctype) | |||||
return true | |||||
end | |||||
function vcomponent.unregister(address) | |||||
checkArg(1,address,"string") | |||||
if proxylist[address] == nil then | |||||
if component.type(address) ~= nil then | |||||
return nil, "cannot unregister real component" | |||||
else | |||||
return nil, "no component at address" | |||||
end | |||||
end | |||||
local thetype = typelist[address] | |||||
proxylist[address] = nil | |||||
proxyobjs[address] = nil | |||||
typelist[address] = nil | |||||
doclist[address] = nil | |||||
computer.pushSignal("component_removed",address,thetype) | |||||
return true | |||||
end | |||||
function vcomponent.list() | |||||
local list = {} | |||||
for k,v in pairs(proxylist) do | |||||
list[#list + 1] = {k,typelist[k],v} | |||||
end | |||||
return list | |||||
end | |||||
function vcomponent.resolve(address, componentType) | |||||
checkArg(1, address, "string") | |||||
checkArg(2, componentType, "string", "nil") | |||||
for k,v in pairs(typelist) do | |||||
if componentType == nil or v == componentType then | |||||
if k:sub(1, #address) == address then | |||||
return k | |||||
end | |||||
end | |||||
end | |||||
return nil, "no such component" | |||||
end | |||||
local r = math.random | |||||
function vcomponent.uuid() | |||||
return string.format("%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", | |||||
r(0,255),r(0,255),r(0,255),r(0,255), | |||||
r(0,255),r(0,255), | |||||
r(64,79),r(0,255), | |||||
r(128,191),r(0,255), | |||||
r(0,255),r(0,255),r(0,255),r(0,255),r(0,255),r(0,255)) | |||||
end | |||||
return vcomponent |
@@ -1,162 +0,0 @@ | |||||
local vcomponent = require "vcomponent" | |||||
local serial = require "serialization" | |||||
local component = require "component" | |||||
local computer = require "computer" | |||||
local event = require "event" | |||||
local imt = require "interminitel" | |||||
local cfg = {} | |||||
cfg.peers = {} | |||||
cfg.rtimer = 5 | |||||
cfg.katimer = 30 | |||||
local listeners = {} | |||||
local proxies = {} | |||||
local function loadcfg() | |||||
local f = io.open("/boot/cfg/vtunnel.cfg","rb") | |||||
if not f then return false end | |||||
for k,v in pairs(serial.unserialize(f:read("*a")) or {}) do | |||||
cfg[k] = v | |||||
end | |||||
f:close() | |||||
end | |||||
local function savecfg() | |||||
local f = io.open("/boot/cfg/vtunnel.cfg","wb") | |||||
if not f then | |||||
print("Warning: unable to save configuration.") | |||||
return false | |||||
end | |||||
f:write(serial.serialize(cfg)) | |||||
f:close() | |||||
end | |||||
local function createTunnel(host,port,addr,raddr) | |||||
local proxy = {address=addr,buffer=""} | |||||
function proxy.connect() | |||||
if proxy.socket then | |||||
proxy.socket.close() | |||||
end | |||||
proxy.socket = component.invoke(component.list("internet")(),"connect",host,port) | |||||
local st = computer.uptime() | |||||
repeat | |||||
coroutine.yield() | |||||
until proxy.socket.finishConnect() or computer.uptime() > st+5 | |||||
end | |||||
function proxy.send(...) | |||||
rt = 0 | |||||
while not proxy.socket.write(imt.encodePacket(...)) and rt < 10 do | |||||
proxy.connect() | |||||
rt = rt + 1 | |||||
end | |||||
proxy.last = computer.uptime() | |||||
end | |||||
function proxy.read() | |||||
local rb, r | |||||
local rt = 0 | |||||
while true do | |||||
rb,r = proxy.socket.read(4096) | |||||
if rb or rt > 10 then break end | |||||
if type(rb) == "nil" then | |||||
proxy.connect() | |||||
end | |||||
rt = rt + 1 | |||||
end | |||||
proxy.buffer = proxy.buffer .. rb | |||||
while imt.decodePacket(proxy.buffer) do | |||||
computer.pushSignal("modem_message",addr,raddr,0,0,imt.decodePacket(proxy.buffer)) | |||||
proxy.buffer = imt.getRemainder(proxy.buffer) or "" | |||||
end | |||||
if computer.uptime() > proxy.last + cfg.katimer then | |||||
proxy.socket.write("\0\1\0") | |||||
proxy.last = computer.uptime() | |||||
end | |||||
end | |||||
function proxy.getWakeMessage() | |||||
return false | |||||
end | |||||
proxy.setWakeMessage = proxy.getWakeMessage | |||||
function proxy.maxPacketSize() | |||||
return 8192 | |||||
end | |||||
function proxy.getChannel() | |||||
return host..":"..tostring(port) | |||||
end | |||||
proxy.connect() | |||||
proxy.last = computer.uptime() | |||||
return proxy | |||||
end | |||||
vt = {} | |||||
function start() | |||||
loadcfg() | |||||
for k,v in pairs(cfg.peers) do | |||||
print(string.format("Connecting to %s:%d",v.host,v.port)) | |||||
v.addr = v.addr or vcomponent.uuid() | |||||
v.raddr = v.raddr or vcomponent.uuid() | |||||
local px = createTunnel(v.host, v.port, v.addr, v.raddr) | |||||
vcomponent.register(v.addr, "tunnel", px) | |||||
proxies[v.addr] = px | |||||
end | |||||
for k,v in pairs(os.tasks()) do | |||||
if os.taskInfo(v).name:match("minitel") then | |||||
os.kill(v) | |||||
end | |||||
end | |||||
end | |||||
function vt.stop() | |||||
for k,v in pairs(proxies) do | |||||
vcomponent.unregister(k) | |||||
end | |||||
end | |||||
function vt.listpeers() | |||||
for k,v in pairs(cfg.peers) do | |||||
print(string.format("#%d (%s:%d)\n Local address: %s\n Remote address: %s",k,v.host,v.port,v.addr,v.raddr)) | |||||
end | |||||
end | |||||
function vt.addpeer(host,port) | |||||
port = tonumber(port) or 4096 | |||||
local t = {} | |||||
t.host = host | |||||
t.port = port | |||||
t.addr = vcomponent.uuid() | |||||
t.raddr = vcomponent.uuid() | |||||
cfg.peers[#cfg.peers+1] = t | |||||
print(string.format("Added peer #%d (%s:%d) to the configuration.\nRestart to apply changes.",#cfg.peers,host,port)) | |||||
savecfg() | |||||
end | |||||
function vt.delpeer(n) | |||||
n=tonumber(n) | |||||
if not n then | |||||
print("delpeer requires a number, representing the peer number, as an argument.") | |||||
return false | |||||
end | |||||
local dp = table.remove(cfg.peers, n) | |||||
savecfg() | |||||
print(string.format("Removed peer %s:%d",dp.host, dp.port)) | |||||
end | |||||
function vt.settimer(time) | |||||
time = tonumber(time) | |||||
if not time then | |||||
print("Timer must be a number.") | |||||
return false | |||||
end | |||||
cfg.rtime = time | |||||
savecfg() | |||||
end | |||||
vt.start = start | |||||
_G.libs.vtunnel = vt | |||||
start() | |||||
local last = computer.uptime() | |||||
while true do | |||||
local tE = {coroutine.yield()} | |||||
if computer.uptime() > last + cfg.rtimer then | |||||
for k,v in pairs(proxies) do | |||||
v.read() | |||||
end | |||||
last = computer.uptime() | |||||
end | |||||
end |