OC-PsychOS/modules/net/ncd.lua

157 lines
4.1 KiB
Lua

net = {}
net.id = computer.address():sub(1,8)
net.delay = 2
net.np = 4957
net.cache = true
net.cache_time = 16
net.log = false
if cdlib and relib then
spawn("ncd",function() print(pcall(function()
local olog = log
local function log(...)
if net.log then
for k,v in ipairs({...}) do
olog("[ncd] " .. tostring(v))
end
end
end
local mtab = {} -- modem table
local lkr = {} -- LKR cache, contains copper_name = {modem="modem address last received from",addr="address last received from"}
local rpackets = {} -- packets that have already been seen
local pqueue = {} -- queue for packets to be sent. same format as relib.encode accepts. contains:
-- packet_id = {
-- pid = "3 char string of random data, same as packet_id",
-- addr = "address to send to",
-- port = #port number, 0-65535,
-- msg = "the packet data",
-- wf = "packet ID to wait till ack'd"
-- at = #attempts,
-- lst = #time of last attempt (USE UPTIME, NOT os.time() BECAUSE WINDOWS IS DUMB)
-- }
for modem in component.list("modem") do
mtab[#mtab+1] = modem
log("added "..modem)
component.invoke(modem,"open",net.np)
end
local function send(addr,msg,hops,src)
log("sending packet "..msg.." to "..addr)
local src=src or net.id
local hops=hops or 0
if lkr[addr] and net.cache then
component.invoke(lkr[addr].modem,"send",lkr[addr].addr,net.np,"copper",cdlib.encode(hops,src,addr,msg))
else
for _,modem in ipairs(mtab) do
-- log(modem,"broadcast",net.np,hops,net.id,addr,msg,cdlib.encode(hops,net.id,addr,msg))
component.invoke(modem,"broadcast",net.np,"copper",cdlib.encode(hops,net.id,addr,msg))
end
end
end
local function enqueue(addr,port,msg,waitfor)
local qp = {}
qp.msg = msg
qp.addr = addr
qp.port = port
qp.wf = waitfor
qp.pid = os.gensalt(3)
qp.at = 0
qp.pt = 1
qp.lst = 0
pqueue[qp.pid] = qp
for k,v in pairs(qp) do log(k.." = "..tostring(v)) end
return qp.pid
end
net.send = enqueue
local function ppacket(hops,src,dst,data)
if not rpackets[src..dst..data] then
if dst == net.id then
log("packet addressed here")
event.push("net_rmsg",src,data)
local pd = relib.decode(data)
log(pd)
if pd then
log("valid relib packet")
for k,v in pairs(pd) do log(k.." = "..v) end
if pd.port and pd.pid and pd.at and pd.pt then
if pd.pt == 0 then
log("unreliable packet")
event.push("net_msg",src,pd.port,pd.msg)
elseif pd.pt == 1 then
log("reliable packet, sending ack")
event.push("net_msg",src,pd.port,pd.msg)
pd.pt = 2
pd.addr = src
pd.lst = 0
pd.msg = ""
pd.unreliable=true
pqueue[pd.pid] = pd
for k,v in pairs(pqueue[pd.pid]) do log(k.." = "..tostring(v)) end
elseif pd.pt == 2 then
log("ack packet: "..pd.pid)
pqueue[pd.pid] = nil
end
end
end
elseif src ~= net.id then
if hops < 255 then
send(dst,data,hops+1,src)
end
end
rpackets[src..dst..data] = computer.uptime()
end
end
while true do
local ev = {event.pull()}
if ev[1] == "rsendmsg" or ev[1] == "sendmsg" or ev[1] == "modem_message" then
-- log(table.unpack(ev))
end
if ev[1] == "rsendmsg" then
send(ev[2],ev[3])
elseif ev[1] == "sendmsg" then
table.remove(ev,1)
enqueue(table.unpack(ev))
elseif ev[1] == "modem_message" and ev[4] == net.np and ev[6] == "copper" then
local hops,src,dst,data = cdlib.decode(ev[7])
if hops and src and dst and data then
if lkr[src] ~= ev[3] then
log("lkr["..tostring(src).."] = "..tostring(ev[3]))
lkr[src] = {modem=ev[2],addr=ev[3],time=computer.uptime()}
end
ppacket(hops,src,dst,data)
end
end
for k,v in pairs(pqueue) do
if computer.uptime() > v.lst+net.delay and pqueue[v.wf] == nil then
send(v.addr,relib.encode(v))
v.lst = computer.uptime()
v.at = v.at+1
if v.at > 254 then
pqueue[k] = nil
end
if v.unreliable then pqueue[k] = nil end
end
end
for k,v in pairs(lkr) do
if computer.uptime() > v.time+net.cache_time then
lkr[k] = nil
end
end
for k,v in pairs(rpackets) do
if computer.uptime() > v+net.cache_time then
rpackets[k] = nil
end
end
end
end)) end)
end