diff --git a/culib.lua b/culib.lua index f111d57..ef91760 100644 --- a/culib.lua +++ b/culib.lua @@ -26,18 +26,18 @@ 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 + local tuningMaxSeenBeforeCountBeforeEmergencyFlush = 0x300 -- Expect a response by this many seconds, -- or else clear the known receivers cache and resend. - local tuningExpectResponse = 10 + local tuningExpectResponse = 120 -- Flush the loop detector every so often. -- This is not a complete clear. - local tuningFlushLoopDetector = 10 + local tuningFlushLoopDetector = 120 - -- Do not change this value. I mean it. Don't. Just. Don't. - local tuningAutorejectLen = 4000 + -- Do not change this value unless protocol has changed accordingly. + local tuningAutorejectLen = 1506 local loopDetectorNext = time() + tuningFlushLoopDetector @@ -68,10 +68,11 @@ return function (hostname, transmit, onReceive, time) seenBeforeCount = seenBeforeCount - 1 end end - loopDetectorNext = time() + tuningFlushLoopDetector + loopDetectorNext = t + tuningFlushLoopDetector end for k, v in pairs(lastKnownReceiver) do if t >= v[2] then + print("It was decided LKV[" .. k .. "] was out of date @ " .. v[2]) lastKnownReceiver[k] = nil for _, m in ipairs(v[3]) do transmit(nil, m) @@ -86,14 +87,16 @@ return function (hostname, transmit, onReceive, time) culib.hostname = hostname culib.input = function (node, message) local t = time() - if message:len() > tuningAutorejectLen then - return - end + + -- Eliminate the hops value first of all. + local hops = message:byte(1) + message = message:sub(2) + if seenBefore[message] then seenBefore[message] = seenBefore[message] + 1 return else - seenBefore[message] = 0 + seenBefore[message] = 2 seenBeforeCount = seenBeforeCount + 1 if seenBeforeCount > tuningMaxSeenBeforeCountBeforeEmergencyFlush then -- Panic @@ -101,7 +104,8 @@ return function (hostname, transmit, onReceive, time) seenBefore = {} end end - -- Begin parsing + -- Begin parsing. + local rawmessage = message if message:len() < 2 then return end @@ -114,12 +118,34 @@ return function (hostname, transmit, onReceive, time) local tnam = message:sub(2, nlen + 1) message = message:sub(nlen + 2) - lastKnownReceiver[fnam] = {node, t + tuningExpectResponse, {}} + if message:len() > tuningAutorejectLen then + return + end + + local restart = true + if lastKnownReceiver[fnam] then + if lastKnownReceiver[fnam][1] == node then + restart = false + -- allow frequently-used links to last longer + lastKnownReceiver[fnam][2] = lastKnownReceiver[fnam][2] + tuningExpectResponse + lastKnownReceiver[fnam][3] = {} + end + else + end + if restart then + lastKnownReceiver[fnam] = {node, t + tuningExpectResponse, {}} + end onReceive(fnam, tnam, message) if culib.hostname == tnam then return end -- Redistribution of messages not aimed here + if hops == 255 then + return + else + rawmessage = string.char(hops + 1) .. rawmessage + end + local lkr = lastKnownReceiver[tnam] if lkr then transmit(lkr[1], rawmessage) @@ -137,7 +163,7 @@ return function (hostname, transmit, onReceive, time) culib.output = function (fnam, tnam, message) onReceive(fnam, tnam, message) if tnam == culib.hostname then return end - local m = encodeName(fnam) .. encodeName(tnam) .. message + local m = "\x00" .. encodeName(fnam) .. encodeName(tnam) .. message transmit(nil, m) end return culib diff --git a/protocol.0 b/protocol.0 index bf394e4..5f94507 100644 --- a/protocol.0 +++ b/protocol.0 @@ -15,14 +15,15 @@ Copper addresses are names. In the context of a system not implementing a hierarchial gateway, this is as much about Copper addressing as matters. -Copper base packets contain 3 fields. +Copper base packets contain 4 fields. +One byte indicating how many nodes have retransmitted the message + (the original sender should use 0), A name (as a length-minus-1-byte-prefixed-string), another name (in the same format), and the rest is data. -Copper packets may be up to 4000 bytes long, including base. -(It's assumed the additional 96 bytes will be useful for any additional - framing, assuming a 4K packet limit.) +Copper packet data may be up to 1506 bytes long - + this does not include header data, which may be up to (256*2) + 3 bytes long. Loop detection should performed by checking if a packet exactly the same has been seen recently - other rejection, alteration and routing measures @@ -36,4 +37,4 @@ Should a situation be dire enough, hierarchial networks (described in file 2, 'protocol.1'), and custom routing software in general, can be used to split networks however the system requires. -Copper isn't very picky. + diff --git a/protocol.1 b/protocol.1 index b926b9b..b5e4592 100644 --- a/protocol.1 +++ b/protocol.1 @@ -8,8 +8,7 @@ They are simply base low-level Copper nodes with two interfaces and the For the FROM address: -If it's on the parent side, reject if it's prefixed with hostname .. -"/", +If it's on the parent side, reject if it's prefixed with hostname .. "/", otherwise prefix it with "<" and forward to child side. If it's on the child side, reject if it's prefixed with "<", otherwise prefix it with hostname .. "/" and forward to parent side. diff --git a/protocol.2 b/protocol.2 index 12fb0df..59adf0d 100644 --- a/protocol.2 +++ b/protocol.2 @@ -17,15 +17,14 @@ All implementations of Copper that synthesize their own packets SHOULD follow this protocol when doing so, unless they are a custom system that will not be connected to any global network. - Firstly, note that, to the application, a Reliability Layer packet can - be up to 59,895 bytes in size, though a fragment can only be up to 3993 bytes. + be up to 22,500 bytes in size, though a fragment can only be up to 1500 bytes. Secondly, note that an application should be able to ask to be notified when a packet is received successfully or when the implementation gives up, with a flag indicating which is which. -Reliability Layer packets have a simple format. +Reliability Layer packets have a simple 6-byte header. The first two bytes are the port number, in big-endian format. The next three bytes are a number to this application-side packet. They should be as random as possible. diff --git a/runtest.lua b/runtest.lua index d0b8771..3f44f1e 100644 --- a/runtest.lua +++ b/runtest.lua @@ -7,7 +7,7 @@ local nodenames = {} local systime = 0 local function getsystime() - return systime / 20 + return systime / 10 end local queuedCalls = {} @@ -58,13 +58,24 @@ end) -- Start testing +local targetables = {} +local targetableCount = 10 +for i = 1, targetableCount do + targetables[i] = math.random(#nodes) +end + local function generateMessage() - local na = math.random(#nodes) - local nb = math.random(#nodes) + local na = 1 + local nb = 1 + while na == nb do + na = targetables[math.random(#targetables)] + nb = targetables[math.random(#targetables)] + end nodes[na].output(nodenames[na], nodenames[nb], "T" .. tostring(math.random())) end -local generateEvery = 1 +-- ~Once every 5 seconds, think a polling script +local generateEvery = math.floor(50 / targetableCount) local generateCount = 10000 while (generateCount > 0) or (#queuedCalls > 0) do if (systime % generateEvery) == 0 then @@ -81,8 +92,8 @@ while (generateCount > 0) or (#queuedCalls > 0) do for _, v in ipairs(qc) do v() end - print("run iteration, " .. #qc .. " calls") + --print("run iteration, " .. #qc .. " calls") systime = systime + 1 end -print(statSD, statPT) +print(#nodes, statSD, statPT)