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