mirror of
https://github.com/XeonSquared/OC-Copper.git
synced 2024-11-08 10:58:10 +11:00
121 lines
3.6 KiB
Lua
121 lines
3.6 KiB
Lua
|
-- 'Copper' networking test implementation.
|
||
|
-- This is meant as a portable (even into OC) library for networking.
|
||
|
-- This 'outer function' is the instantiator.
|
||
|
|
||
|
-- Note that it is probably possible to cause this code to run out of
|
||
|
-- memory in several hilarious ways.
|
||
|
|
||
|
-- Interfaces have no meaning, since addresses are names.
|
||
|
-- Which "side" a system is on is irrelevant.
|
||
|
-- For sending, the following function is used:
|
||
|
-- transmit(nodeId, message)
|
||
|
-- The nodeId is a string or number that has been given via culib.input,
|
||
|
-- or nil for broadcast.
|
||
|
-- It's more of a suggestion than a requirement to check nodeId.
|
||
|
|
||
|
-- The message is always a string.
|
||
|
-- This mirrors the message format usable by sendPacket and onReceive.
|
||
|
|
||
|
-- "onReceive" is a function which is called when a packet is decoded.
|
||
|
-- onReceive(namefrom, nameto, data)
|
||
|
|
||
|
-- "time" is a function which returns the real time, in seconds.
|
||
|
-- It need not be precise.
|
||
|
-- (This is used for caches.)
|
||
|
return function (hostname, transmit, onReceive, time)
|
||
|
|
||
|
-- How many packets need to be stored in seenBefore's keyspace
|
||
|
-- before 'panic' is the best response?
|
||
|
local tuningMaxSeenBeforeCountBeforeEmergencyFlush = 0x100
|
||
|
|
||
|
-- Expect a response by this many seconds,
|
||
|
-- or else clear the known receivers cache and resend.
|
||
|
local tuningExpectResponse = 20
|
||
|
|
||
|
-- Flush the loop detector every so often.
|
||
|
-- This is not a complete clear.
|
||
|
local tuningFlushLoopDetector = 120
|
||
|
|
||
|
-- Do not change this value. I mean it. Don't. Just. Don't.
|
||
|
local tuningAutorejectLen = 4000
|
||
|
|
||
|
local loopDetectorNext = time() + tuningFlushLoopDetector
|
||
|
|
||
|
-- Packets that have been seen before.
|
||
|
-- The values are the amount of times a packet has been seen.
|
||
|
-- This is flushed every tuningFlushLoopDetector seconds -
|
||
|
-- the flushing decrements the value until it reaches 0,
|
||
|
-- so packets which have looped before get a longer timeout.
|
||
|
local seenBefore = {}
|
||
|
local seenBeforeCount = 0
|
||
|
|
||
|
-- Unacknowledged packets.
|
||
|
-- Can cause an earlier cache flush.
|
||
|
-- [address] = giveupTime
|
||
|
-- (These are just forgotten after a while)
|
||
|
--local sentBNR = {}--NYI
|
||
|
|
||
|
-- [address] = {
|
||
|
-- node,
|
||
|
-- expiry
|
||
|
-- }
|
||
|
--local lastKnownReceiver = {}--NYI
|
||
|
|
||
|
local function refresh()
|
||
|
local t = time()
|
||
|
if t >= loopDetectorNext then
|
||
|
for k, v in pairs(seenBefore) do
|
||
|
local n = v - 1
|
||
|
if n > 0 then
|
||
|
seenBefore[k] = n
|
||
|
else
|
||
|
seenBefore[k] = nil
|
||
|
seenBeforeCount = seenBeforeCount - 1
|
||
|
end
|
||
|
end
|
||
|
loopDetectorNext = time() + tuningFlushLoopDetector
|
||
|
end
|
||
|
end
|
||
|
|
||
|
local culib = {}
|
||
|
|
||
|
-- Can be changed.
|
||
|
culib.hostname = hostname
|
||
|
culib.input = function (node, message)
|
||
|
if message:len() > tuningAutorejectLen then
|
||
|
return
|
||
|
end
|
||
|
if seenBefore[message] then
|
||
|
seenBefore[message] = seenBefore[message] + 1
|
||
|
return
|
||
|
else
|
||
|
seenBefore[message] = 0
|
||
|
seenBeforeCount = seenBeforeCount + 1
|
||
|
if seenBeforeCount > tuningMaxSeenBeforeCountBeforeEmergencyFlush then
|
||
|
-- Panic
|
||
|
seenBeforeCount = 0
|
||
|
seenBefore = {}
|
||
|
end
|
||
|
end
|
||
|
if message:len() < 2 then return end
|
||
|
local nlen = message:byte(1) + 1
|
||
|
local fnam = message:sub(1, nlen)
|
||
|
message = message:sub(nlen + 1)
|
||
|
if message:len() < 2 then return end
|
||
|
local nlen = message:byte(1) + 1
|
||
|
local tnam = message:sub(1, nlen)
|
||
|
message = message:sub(nlen + 1)
|
||
|
if message:len() < 1 then return end
|
||
|
onReceive(fnam, tnam, message)
|
||
|
if culib.hostname == tnam then return end
|
||
|
-- Redistribution of messages not aimed here
|
||
|
transmit(nil, message)
|
||
|
end
|
||
|
culib.output = function (fnam, tnam, message)
|
||
|
onReceive(fnam, tnam, message)
|
||
|
if tnam == culib.hostname then return end
|
||
|
transmit(nil, encodeName(fnam) .. encodeName(tnam) .. message)
|
||
|
end
|
||
|
return culib
|
||
|
end
|