Compare commits

..

5 Commits

6 changed files with 180 additions and 157 deletions

View File

@ -1,38 +1,47 @@
local computer = require "computer"
local minitel = require "minitel"
local event = require "event"
local rpc = require "rpc"
local netutil = {}
function netutil.importfs(host,rpath,lpath)
function netutil.importfs(host,rpath,lpath) -- import filesystem *rpath* from *host* and attach it to *lpath*
local px = rpc.proxy(host,rpath.."_")
function px.getLabel()
return host..":"..rpath
end
fs.mount(lpath,px)
return fs.mount(lpath,px)
end
function netutil.exportfs(path)
function netutil.exportfs(path) -- export the directory *path* over RPC
local path = "/"..table.concat(fs.segments(path),"/")
local px = ufs.create(path)
for k,v in pairs(px) do
rpcs.register(path.."_"..k,v)
print(path.."_"..k)
end
return true
end
function netutil.ping(addr,times,timeout)
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.
local times, timeout = times or 5, timeout or 30
local success, fail, time, avg = 0, 0, 0, 0
for i = 1, times do
local ipt = computer.uptime()
local pid = minitel.genPacketID()
computer.pushSignal("net_send",1,addr,0,"ping",pid)
local t,a = event.pull(timeout,"net_ack")
if t == "net_ack" and a == pid then
print("Ping reply: "..tostring(computer.uptime()-ipt).." seconds.")
if not silent then print("Ping reply: "..tostring(computer.uptime()-ipt).." seconds.") end
success = success + 1
time = time + computer.uptime()-ipt
avg = time / success
else
print("Timed out.")
if not silent then print("Timed out.") end
fail = fail + 1
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
return netutil

76
lib/rc.lua Normal file
View File

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

View File

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

View File

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

View File

@ -10,36 +10,27 @@ sender: original sender of packet
data: the actual packet data, duh.
]]--
local listeners,timers,processes,modems = {},{},{},{}
local hostname = os.getenv("HOSTNAME")
local listeners = {}
local timers = {}
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.port = 4096
cfg.retry = 10
cfg.retrycount = 64
cfg.retrycount = 3
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:
address {
@ -48,7 +39,6 @@ address {
time last received
}
]]--
cfg.sroutes = {}
local rcache = setmetatable({},{__index=cfg.sroutes})
cfg.rctime = 15
@ -66,60 +56,9 @@ packet queue format:
]]--
local pqueue = {}
local function saveconfig()
if OPENOS or PSYCHOS then
local f = io.open(cfgpath,"wb")
if f then
f:write(serial.serialize(cfg))
f:close()
end
end
end
local function loadconfig()
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
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()
for k,v in pairs(newcfg) do
cfg[k] = v
end
else
saveconfig()
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
-- packet cache: [packet ID]=uptime
local pcache = {}
cfg.pctime = 30
local function dprint(...)
if cfg.debug then
@ -127,35 +66,44 @@ local function dprint(...)
end
end
local function saveconfig()
local f = io.open("/boot/cfg/minitel.cfg","wb")
if f then
f:write(serial.serialize(cfg))
f:close()
end
end
local function loadconfig()
local f = io.open("/boot/cfg/minitel.cfg","rb")
if f then
local newcfg = serial.unserialize(f:read("*a"))
f:close()
for k,v in pairs(newcfg) do
cfg[k] = v
end
else
saveconfig()
end
end
function start()
loadconfig()
hostname = os.getenv("HOSTNAME") or computer.address():sub(1,8)
print("Hostname: "..hostname)
if listener then return end
if OPENOS or PSYCHOS then
if pid then return false end
modems={}
for a,t in component.list("modem") do
modems[#modems+1] = component.proxy(a)
end
for k,v in ipairs(modems) do
v.open(cfg.port)
print("Opened port "..cfg.port.." on "..v.address:sub(1,8))
print("Opened port "..cfg.port.." on "..v.address)
end
for a,t in component.list("tunnel") do
modems[#modems+1] = component.proxy(a)
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 npID = ""
@ -176,10 +124,11 @@ function start()
else
dprint("Not cached", cfg.port,packetID,packetType,dest,sender,vPort,data)
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.type == "modem" then
v.broadcast(cfg.port,packetID,packetType,dest,sender,vPort,data)
elseif v.type == "tunnel" then
v.send(packetID,packetType,dest,sender,vPort,data)
end
end
@ -255,7 +204,6 @@ function start()
dprint(npID,table.unpack(pqueue[npID]))
end
local function packetPusher()
for k,v in pairs(pqueue) do
if v[5] < computer.uptime() then
@ -273,43 +221,29 @@ function start()
listeners["modem_message"]=processPacket
listeners["net_send"]=queuePacket
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
listeners["net_ack"]=dprint
if KITTENOS or PSYCHOS then
pid=os.spawn(function()
while true do
local ev = {coroutine.yield()}
packetPusher()
pruneCache()
if ev[1] == "k.procdie" then
processes[ev[3]] = nil
end
if listeners[ev[1]] then
pcall(listeners[ev[1]],table.unpack(ev))
end
end
end
end,"minitel")
print("Started Minitel daemon: "..tostring(pid))
return pid
end
function stop()
for k,v in pairs(listeners) do
event.ignore(k,v)
print("Stopped listener: "..tostring(v))
end
for k,v in pairs(timers) do
event.cancel(v)
print("Stopped timer: "..tostring(v))
if pid then
os.kill(pid)
pid = nil
return true
else
return false
end
end
@ -331,11 +265,9 @@ end
function set_route(to,laddr,raddr)
cfg.sroutes[to] = {laddr,raddr,0}
saveconfig()
end
function del_route(to)
cfg.sroutes[to] = nil
end
if not OPENOS then
start()
saveconfig()
end