Compare commits

..

No commits in common. "e20c9546eafa8a0da2b5b3451f223301b671910d" and "0712210768921f06505711a2edc6da38ad61fc7a" have entirely different histories.

6 changed files with 157 additions and 180 deletions

View File

@ -1,47 +1,38 @@
local computer = require "computer" local computer = require "computer"
local minitel = require "minitel" local minitel = require "minitel"
local event = require "event"
local rpc = require "rpc" local rpc = require "rpc"
local netutil = {} local netutil = {}
function netutil.importfs(host,rpath,lpath) -- import filesystem *rpath* from *host* and attach it to *lpath* function netutil.importfs(host,rpath,lpath)
local px = rpc.proxy(host,rpath.."_") local px = rpc.proxy(host,rpath.."_")
function px.getLabel() function px.getLabel()
return host..":"..rpath return host..":"..rpath
end end
return fs.mount(lpath,px) fs.mount(lpath,px)
end end
function netutil.exportfs(path) -- export the directory *path* over RPC function netutil.exportfs(path)
local path = "/"..table.concat(fs.segments(path),"/") local path = "/"..table.concat(fs.segments(path),"/")
local px = ufs.create(path) local px = ufs.create(path)
for k,v in pairs(px) do for k,v in pairs(px) do
rpcs.register(path.."_"..k,v) rpcs.register(path.."_"..k,v)
print(path.."_"..k) print(path.."_"..k)
end end
return true
end end
function netutil.ping(addr,times,timeout, silent) -- Request acknowledgment from *addr*, waiting *timeout* seconds each try, and try *times* times. If *silent* is true, don't print status. Returns true if there was at least one successful ping, the number of successes, the number of failures, and the average round trip time. function netutil.ping(addr,times,timeout)
local times, timeout = times or 5, timeout or 30 local times, timeout = times or 5, timeout or 30
local success, fail, time, avg = 0, 0, 0, 0
for i = 1, times do for i = 1, times do
local ipt = computer.uptime() local ipt = computer.uptime()
local pid = minitel.genPacketID() local pid = minitel.genPacketID()
computer.pushSignal("net_send",1,addr,0,"ping",pid) computer.pushSignal("net_send",1,addr,0,"ping",pid)
local t,a = event.pull(timeout,"net_ack") local t,a = event.pull(timeout,"net_ack")
if t == "net_ack" and a == pid then if t == "net_ack" and a == pid then
if not silent then print("Ping reply: "..tostring(computer.uptime()-ipt).." seconds.") end print("Ping reply: "..tostring(computer.uptime()-ipt).." seconds.")
success = success + 1
time = time + computer.uptime()-ipt
avg = time / success
else else
if not silent then print("Timed out.") end print("Timed out.")
fail = fail + 1
end end
end end
if not silent then print(string.format("%d packets transmitted, %d received, %0.0f%% packet loss, %0.1fs",times,success,fail/times*100,time)) end
return success > 0, success, fail, avg
end end
return netutil return netutil

View File

@ -1,76 +0,0 @@
local serial = require "serialization"
local rc = {}
local service = {}
local cfg = {}
cfg.enabled = {}
local function loadConfig()
local f = io.open("/boot/cfg/rc.cfg","rb")
if not f then return false end
cfg = serial.unserialize(f:read("*a")) or {}
f:close()
cfg.enabled = cfg.enabled or {}
return true
end
local function saveConfig()
local f = io.open("/boot/cfg/rc.cfg","wb")
if not f then return false end
f:write(serial.serialize(cfg))
f:close()
return true
end
function rc.load(name,force)
if force then
rc.stop(name)
service[name] = nil
end
if service[name] then return true end
service[name] = setmetatable({},{__index=_G})
local f = io.open("/boot/service/"..name..".lua","rb")
local res = load(f:read("*a"),name,"t",service[name])()
f:close()
return res
end
function rc.stop(name,...)
if not service[name] then return false, "service not found" end
service[name].stop(...)
end
function rc.start(name,...)
rc.load(name)
if not service[name] then return false, "service not found" end
return service[name].start(...)
end
function rc.restart(name)
rc.stop(name)
rc.start(name)
end
function rc.enable(name)
for k,v in pairs(cfg.enabled) do
if v == name then return false end
end
saveConfig()
end
function rc.disable(name)
local disabled = false
for k,v in pairs(cfg.enabled) do
if v == name then table.remove(cfg.enabled,k) disabled = true break end
end
saveConfig()
return disabled
end
loadConfig()
for k,v in pairs(cfg.enabled) do
rc.start(v)
end
_G.service = service
return rc

View File

@ -22,16 +22,20 @@ os.spawn(function()
os.setenv("HOSTNAME",hostname) os.setenv("HOSTNAME",hostname)
syslog(string.format("Hostname set to %s",hostname)) syslog(string.format("Hostname set to %s",hostname))
local pids = {} local pids = {}
local rc = require "rc" local function loadlist()
for k,v in pairs(rc.cfg.enabled) do local f = io.open("/boot/cfg/init.txt","rb")
pids[v] = -1 if not f then return false end
dprint(v) for line in f:read("*a"):gmatch("[^\r\n]+") do
pids[line] = -1
end end
f:close()
end
loadlist()
while true do while true do
for k,v in pairs(pids) do for k,v in pairs(pids) do
if not os.taskInfo(v) then if not os.taskInfo(v) then
syslog("Starting service "..k) syslog("Starting service "..k)
pids[k] = rc.start(k) pids[k] = os.spawnfile("/boot/service/"..k)
end end
end end
coroutine.yield() coroutine.yield()

View File

@ -1,12 +1,12 @@
io = {} io = {}
function io.open(path,mode) -- Open file *path* in *mode*. Returns a buffer object. function io.open(path,mode)
local f,e = fs.open(path, mode) local f,e = fs.open(path, mode)
if not f then return false, e end if not f then return false, e end
return buffer.new(mode,f) return buffer.new(mode,f)
end end
function io.input(fd) -- Sets the default input stream to *fd* if provided, either as a buffer as a path. Returns the default input stream. function io.input(fd)
if type(fd) == "string" then if type(fd) == "string" then
fd=io.open(fd,"rb") fd=io.open(fd,"rb")
end end
@ -15,7 +15,7 @@ function io.input(fd) -- Sets the default input stream to *fd* if provided, eith
end end
return os.getenv("STDIN") return os.getenv("STDIN")
end end
function io.output(fd) -- Sets the default output stream to *fd* if provided, either as a buffer as a path. Returns the default output stream. function io.output(fd)
if type(fd) == "string" then if type(fd) == "string" then
fd=io.open(fd,"wb") fd=io.open(fd,"wb")
end end
@ -25,14 +25,14 @@ function io.output(fd) -- Sets the default output stream to *fd* if provided, ei
return os.getenv("STDOUT") return os.getenv("STDOUT")
end end
function io.read(...) -- Reads from the default input stream. function io.read(...)
return io.input():read(...) return io.input():read()
end end
function io.write(...) -- Writes its arguments to the default output stream. function io.write(...)
io.output():write(...) io.output():write(...)
end end
function print(...) -- Writes each argument to the default output stream, separated by newlines. function print(...)
for k,v in ipairs({...}) do for k,v in ipairs({...}) do
io.write(tostring(v).."\n") io.write(tostring(v).."\n")
end end

View File

@ -1,5 +1,4 @@
local gpus,screens,ttyn,pids = {}, {}, 0, {} local gpus,screens,ttyn,pids = {}, {}, 0, {}
local basepid = nil
local shell = require "shell" local shell = require "shell"
local function scan() local function scan()
local w,di = pcall(computer.getDeviceInfo) local w,di = pcall(computer.getDeviceInfo)
@ -54,11 +53,9 @@ local function allocate()
end end
end end
function start()
scan() scan()
allocate() allocate()
dprint("screens ready") dprint("screens ready")
basepid = os.spawn(function()
while true do while true do
coroutine.yield() coroutine.yield()
for k,v in pairs(pids) do for k,v in pairs(pids) do
@ -69,10 +66,3 @@ while true do
end end
end end
end end
end,"getty")
return basepid
end
function stop()
os.kill(basepid)
basepid = nil
end

View File

@ -10,27 +10,36 @@ sender: original sender of packet
data: the actual packet data, duh. data: the actual packet data, duh.
]]-- ]]--
local listeners = {} local listeners,timers,processes,modems = {},{},{},{}
local timers = {} local hostname = os.getenv("HOSTNAME")
local cfg = {} local cfg = {}
local event = require "event"
local component = require "component"
local computer = require "computer"
local serial = require "serialization"
local hostname = computer.address():sub(1,8)
local modems = {}
local pid = nil
cfg.debug = false cfg.debug = false
cfg.port = 4096 cfg.port = 4096
cfg.retry = 10 cfg.retry = 10
cfg.retrycount = 3 cfg.retrycount = 64
cfg.route = true cfg.route = true
local event, component, computer, serial = event, component, computer, serial
local hnpath, cfgpath = "", ""
OPENOS, PSYCHOS, KITTENOS = false, false, false
if _OSVERSION:sub(1,6) == "OpenOS" then
OPENOS = true
hnpath = "/etc/hostname"
cfgpath = "/etc/minitel.cfg"
elseif _OSVERSION:sub(1,7) == "PsychOS" then
PSYCHOS = true
hnpath = "/boot/cfg/hostname"
cfgpath = "/boot/cfg/minitel.cfg"
elseif _OSVERSION:sub(1,8) == "KittenOS" then
KITTENOS = true
end
-- packet cache: [packet ID]=uptime
local pcache = {}
cfg.pctime = 30
--[[ --[[
LKR format: LKR format:
address { address {
@ -39,6 +48,7 @@ address {
time last received time last received
} }
]]-- ]]--
cfg.sroutes = {} cfg.sroutes = {}
local rcache = setmetatable({},{__index=cfg.sroutes}) local rcache = setmetatable({},{__index=cfg.sroutes})
cfg.rctime = 15 cfg.rctime = 15
@ -56,27 +66,26 @@ packet queue format:
]]-- ]]--
local pqueue = {} local pqueue = {}
-- packet cache: [packet ID]=uptime
local pcache = {}
cfg.pctime = 30
local function dprint(...)
if cfg.debug then
print(...)
end
end
local function saveconfig() local function saveconfig()
local f = io.open("/boot/cfg/minitel.cfg","wb") if OPENOS or PSYCHOS then
local f = io.open(cfgpath,"wb")
if f then if f then
f:write(serial.serialize(cfg)) f:write(serial.serialize(cfg))
f:close() f:close()
end end
end
end end
local function loadconfig() local function loadconfig()
local f = io.open("/boot/cfg/minitel.cfg","rb") hostname = os.getenv("HOSTNAME") or computer.address():sub(1,8)
if OPENOS or PSYCHOS then
local f,g=io.open(hnpath,"rb")
if f then if f then
local newcfg = serial.unserialize(f:read("*a")) hostname = f:read("*a"):match("(.-)\n")
f:close()
end
local f = io.open(cfgpath,"rb")
if f then
local newcfg = serial.unserialize(f:read("*a")) or {}
f:close() f:close()
for k,v in pairs(newcfg) do for k,v in pairs(newcfg) do
cfg[k] = v cfg[k] = v
@ -84,26 +93,69 @@ local function loadconfig()
else else
saveconfig() saveconfig()
end end
elseif KITTENOS then
local globals = neo.requestAccess("x.neo.pub.globals") -- KittenOS standard hostname stuff
if globals then
hostname = globals.getSetting("hostname") or hostname
globals.setSetting("hostname",hostname)
end
end
end
-- specific OS support here
if PSYCHOS then -- PsychOS specific code
serial = require "serialization"
elseif OPENOS then -- OpenOS specific code
event = require "event"
component = require "component"
computer = require "computer"
serial = require "serialization"
listener = false
elseif KITTENOS then
neo.requireAccess("s.h.modem_message","pulling packets")
computer = {["uptime"]=os.uptime,["address"]=os.address} -- wrap computer so the OpenOS code more or less works
function computer.pushSignal(...)
for k,v in pairs(processes) do
v(...)
end
end
end
local function dprint(...)
if cfg.debug then
print(...)
end
end end
function start() function start()
loadconfig() loadconfig()
hostname = os.getenv("HOSTNAME") or computer.address():sub(1,8)
print("Hostname: "..hostname) print("Hostname: "..hostname)
if listener then return end
if pid then return false end if OPENOS or PSYCHOS then
modems={}
for a,t in component.list("modem") do for a,t in component.list("modem") do
modems[#modems+1] = component.proxy(a) modems[#modems+1] = component.proxy(a)
end end
for k,v in ipairs(modems) do for k,v in ipairs(modems) do
v.open(cfg.port) v.open(cfg.port)
print("Opened port "..cfg.port.." on "..v.address) print("Opened port "..cfg.port.." on "..v.address:sub(1,8))
end end
for a,t in component.list("tunnel") do for a,t in component.list("tunnel") do
modems[#modems+1] = component.proxy(a) modems[#modems+1] = component.proxy(a)
end end
elseif KITTENOS then
for p in neo.requireAccess("c.modem","networking").list() do -- fun stuff for KittenOS
dprint(p.address)
modems[p.address] = p
end
for k,v in pairs(modems) do
v.open(port)
print("Opened port "..port.." on "..v.address)
end
for p in neo.requireAccess("c.tunnel","networking").list() do
dprint(p.address)
modems[p.address] = p
end
end
local function genPacketID() local function genPacketID()
local npID = "" local npID = ""
@ -124,11 +176,10 @@ function start()
else else
dprint("Not cached", cfg.port,packetID,packetType,dest,sender,vPort,data) dprint("Not cached", cfg.port,packetID,packetType,dest,sender,vPort,data)
for k,v in pairs(modems) do for k,v in pairs(modems) do
-- do not send message back to the wired or linked modem it came from
-- the check for tunnels is for short circuiting `v.isWireless()`, which does not exist for tunnels
if v.address ~= repeatingFrom or (v.type ~= "tunnel" and v.isWireless()) then if v.address ~= repeatingFrom or (v.type ~= "tunnel" and v.isWireless()) then
if v.type == "modem" then if v.type == "modem" then
v.broadcast(cfg.port,packetID,packetType,dest,sender,vPort,data) v.broadcast(cfg.port,packetID,packetType,dest,sender,vPort,data)
elseif v.type == "tunnel" then
v.send(packetID,packetType,dest,sender,vPort,data) v.send(packetID,packetType,dest,sender,vPort,data)
end end
end end
@ -204,6 +255,7 @@ function start()
dprint(npID,table.unpack(pqueue[npID])) dprint(npID,table.unpack(pqueue[npID]))
end end
local function packetPusher() local function packetPusher()
for k,v in pairs(pqueue) do for k,v in pairs(pqueue) do
if v[5] < computer.uptime() then if v[5] < computer.uptime() then
@ -221,29 +273,43 @@ function start()
listeners["modem_message"]=processPacket listeners["modem_message"]=processPacket
listeners["net_send"]=queuePacket listeners["net_send"]=queuePacket
listeners["net_ack"]=dprint if OPENOS then
event.listen("modem_message",processPacket)
print("Started packet listening daemon: "..tostring(processPacket))
event.listen("net_send",queuePacket)
print("Started packet queueing daemon: "..tostring(queuePacket))
timers[#timers+1]=event.timer(0,packetPusher,math.huge)
print("Started packet pusher: "..tostring(timers[#timers]))
elseif KITTENOS then
neo.requireAccess("r.svc.minitel","minitel daemon")(function(pkg,pid,sendSig)
processes[pid] = sendSig
return {["sendPacket"]=queuePacket}
end)
end
pid=os.spawn(function() if KITTENOS or PSYCHOS then
while true do while true do
local ev = {coroutine.yield()} local ev = {coroutine.yield()}
packetPusher() packetPusher()
pruneCache() pruneCache()
if ev[1] == "k.procdie" then
processes[ev[3]] = nil
end
if listeners[ev[1]] then if listeners[ev[1]] then
pcall(listeners[ev[1]],table.unpack(ev)) pcall(listeners[ev[1]],table.unpack(ev))
end end
end end
end,"minitel") end
print("Started Minitel daemon: "..tostring(pid))
return pid
end end
function stop() function stop()
if pid then for k,v in pairs(listeners) do
os.kill(pid) event.ignore(k,v)
pid = nil print("Stopped listener: "..tostring(v))
return true end
else for k,v in pairs(timers) do
return false event.cancel(v)
print("Stopped timer: "..tostring(v))
end end
end end
@ -265,9 +331,11 @@ end
function set_route(to,laddr,raddr) function set_route(to,laddr,raddr)
cfg.sroutes[to] = {laddr,raddr,0} cfg.sroutes[to] = {laddr,raddr,0}
saveconfig()
end end
function del_route(to) function del_route(to)
cfg.sroutes[to] = nil cfg.sroutes[to] = nil
saveconfig() end
if not OPENOS then
start()
end end