From 01bc21b0da89a513c4c862e4edc0fa7e1beb8534 Mon Sep 17 00:00:00 2001 From: Major General Relativity Date: Thu, 25 Mar 2021 16:54:16 -0400 Subject: [PATCH] GERTi v1.4 - Release (#73) * GERTi v1.2.1 with feeling Finish properly sending arguments in GERTi.send and update the version number * GERTi v1.2.2 I hate Lua dynamic typing. Fixes a problem with floats that should be integers. * Add an RC version of GERTiMNC Adds a RC version of GERTiMNC for an alternative method of autoloading it on boot and having it run in the background * Rename file Apparently, GitHub only loads Readme.md * GERTi v1.3 Build 1 Begin cleanup of functions and start shrinking size. At this point, still compatible with v1.2, but this will change. Completely untested and likely contains bugs. * GERTi v1.3 - Build 2 Continued cleanup of the route opening logic and the startup logic. This is now protocol incompatible with v1.2. Fixed at least one bug in Build 1, but still untested and likely broken. * GERTiClient v1.3 - Build 3 Finish all the theoretical changes to GERTiClient to simplify route opening from 3 functions down to 2. Socket opening changed to reflect this. Only remaining work is bugtesting and GERTiMNC feature addition * GERTiMNC v1.3 - Build 3 -- Change: GERTiMNC now solely resides as an RC service in /etc/rc.d --Change: Configuration files have moved to /etc -- Feature Addition: triggering the loadAddress command will have the MNC reload the list of addresses. This way, you can change the modem address tied to a certain GERTi address without restarting the entire network. The GERTiClient for that node must be restarted for it to take effect. * GERTi v1.3 - Build 4 Fix some errors that result in the Client failing to boot or obtain an address. More errors likely await in connection handling. * GERTiClient v1.3 - Build 5 Now comes with the ability to open connections at least to neighbors. With the exception of GERTi.send(), data transmission is still bugged * GERTi v1.3 - Build 6 Data transmission now works between neighbors at least. Final testing will involve linked cards and multiple hops. * GERTi v1.3 - Build 7 Fixes a bug that prevents users from closing connections * GERTi v1.3 Release After testing and bugfixing, GERTi is now stable. Protocol incompatible with v1.2, but API compatible * Update Reserved GERTe numbers.txt * Update Reserved GERTe numbers.txt * Cleanup * GERTeAPI v1.3 - Build 1 Update the GERTeAPI to fit the GERTiMNC RC daemon. Pending testing. * GERTi v1.3.1 Update GERTiMNC to resolve performance drop with incoming GERTe packets * GERTi v1.4 Build 1 Lifts the linked and modem card combination limits. Completely untested and likely has bugs * GERTi v1.4 Build 2 More bugfixes. Now it will 1) Actually load 2) Support multiple cards on the MNC properly 3) Actually open connections * GERTi v1.4 Build 3 All known currently existing bugs have been patched. This should be suitable for temporary deployment. Subsequent builds will likely include more bugs. * GERTi v1.4 RC 1 This addition includes all planned features and has been bugtested. It is suitable for deployment across networks. Release candidate instead of final only because a slight change to Data handling may occur where computers may be able to silently re-add connections to their connection tables, thus allowing for more graceful handling of hard power restarts. * GERTi v1.4 - Release Fixed a bug with GERTiMNC address assignment Added a feature allowing the receiving end of a connection to automatically regenerate the connection if it reboots improperly without executing the shutdown or reboot command. --- GERTi/GERTiClient.lua | 186 ++++++++++++++++++++++++------------------ GERTi/GERTiMNC.lua | 170 +++++++++++++++++++++----------------- 2 files changed, 202 insertions(+), 154 deletions(-) diff --git a/GERTi/GERTiClient.lua b/GERTi/GERTiClient.lua index 62e002e..6e36af3 100644 --- a/GERTi/GERTiClient.lua +++ b/GERTi/GERTiClient.lua @@ -1,24 +1,29 @@ --- GERT v1.3 +-- GERT v1.4 local GERTi = {} local component = require("component") local computer = require("computer") local event = require("event") local serialize = require("serialization") -local modem -local tunnel +local mTable, tTable if (component.isAvailable("modem")) then - modem = component.modem - modem.open(4378) - if (component.modem.isWireless()) then - modem.setStrength(500) + mTable = {} + for address, value in component.list("modem") do + mTable[address] = component.proxy(address) + mTable[address].open(4378) + if (mTable[address].isWireless()) then + mTable[address].setStrength(500) + end end end if (component.isAvailable("tunnel")) then - tunnel = component.tunnel + tTable = {} + for address, value in component.list("tunnel") do + tTable[address] = component.proxy(address) + end end -if not (modem or tunnel) then - io.stderr:write("This program requires a network or linked card to run.") +if not (mTable or tTable) then + io.stderr:write("This program requires a network card or linked card to run.") os.exit(1) end @@ -28,7 +33,7 @@ local tier = 3 local nodes = {} local firstN = {} --- connections[connectDex][data/order] Connections are established at any point along a route +-- Connections are established at any point along a route local connections = {} local cPend = {} local rPend = {} @@ -43,23 +48,21 @@ local function waitWithCancel(timeout, cancelCheck) end end -local function storeNodes(gAddress, sendingModem, port, nTier) - nodes[gAddress] = {add = sendingModem, port = tonumber(port), tier = nTier} +local function storeNodes(gAddress, receiverM, sendM, port, nTier) + nodes[gAddress] = {add = sendM, receiveM = receiverM, port = tonumber(port), tier = nTier} if (not firstN["tier"]) or nTier < firstN["tier"] then tier = nTier+1 firstN = nodes[gAddress] firstN["gAdd"] = gAddress end end -local function storeConnection(origin, ID, GAdd, nextHop, port) +local function storeConnection(origin, ID, GAdd, nextHop, sendM, port) ID = math.floor(ID) local connectDex = origin.."|"..GAdd.."|"..ID - connections[connectDex] = {} - connections[connectDex]["origin"]=origin - connections[connectDex]["dest"]=GAdd - connections[connectDex]["ID"]=ID + connections[connectDex] = {["origin"]=origin, ["dest"]=GAdd, ["ID"]=ID} if GAdd ~= iAdd then connections[connectDex]["nextHop"]=nextHop + connections[connectDex]["sendM"] = sendM connections[connectDex]["port"]=port else connections[connectDex]["data"]={} @@ -80,25 +83,25 @@ local function storeData(connectDex, data, order) computer.pushSignal("GERTData", connections[connectDex]["origin"], connections[connectDex]["ID"]) end -local function transInfo(sendTo, port, ...) - if modem and port ~= 0 then - modem.send(sendTo, port, ...) - elseif tunnel then - tunnel.send(...) +local function transInfo(sendTo, localM, port, ...) + if mTable and mTable[localM] then + mTable[localM].send(sendTo, port, ...) + elseif tTable and tTable[localM] then + tTable[localM].send(...) end end local handler = {} -handler.CloseConnection = function(sendingModem, port, connectDex) +handler.CloseConnection = function(_, _, port, connectDex) if connections[connectDex]["nextHop"] then - transInfo(connections[connectDex]["nextHop"], connections[connectDex]["port"], "CloseConnection", connectDex) + transInfo(connections[connectDex]["nextHop"], connections[connectDex]["sendM"], connections[connectDex]["port"], "CloseConnection", connectDex) else computer.pushSignal("GERTConnectionClose", connections[connectDex]["origin"], connections[connectDex]["dest"], connections[connectDex]["ID"]) end connections[connectDex] = nil end -handler.Data = function (sendingModem, port, data, connectDex, order, origin) +handler.Data = function (_, _, port, data, connectDex, order, origin) if connectDex == -1 then return computer.pushSignal("GERTData", origin, -1, data) end @@ -106,83 +109,96 @@ handler.Data = function (sendingModem, port, data, connectDex, order, origin) if connections[connectDex]["dest"] == iAdd then storeData(connectDex, data, order) else - transInfo(connections[connectDex]["nextHop"], connections[connectDex]["port"], "Data", data, connectDex, order) + transInfo(connections[connectDex]["nextHop"], connections[connectDex]["sendM"], connections[connectDex]["port"], "Data", data, connectDex, order) + end + else + origin = string.sub(connectDex, 1, string.find(connectDex, "|")-1) + local dest = string.sub(connectDex, #origin+2, string.find(connectDex, "|", #origin+2)-1) + local ID = string.sub(connectDex, #origin+#dest+3) + origin = tonumber(origin) + dest = tonumber(dest) + ID = tonumber(ID) + if dest == iAdd then + storeConnection(origin, ID, dest) + handler.Data(_, _, port, data, connectDex, order) end end end -handler.NewNode = function (sendingModem, port, gAddress, nTier) +handler.NewNode = function (receiveM, sendM, port, gAddress, nTier) if gAddress then - storeNodes(tonumber(gAddress), sendingModem, port, nTier) + storeNodes(tonumber(gAddress), receiveM, sendM, port, nTier) else - transInfo(sendingModem, port, "NewNode", iAdd, tier) + transInfo(sendM, receiveM, port, "NewNode", iAdd, tier) end end -local function sendOK(bHop, recPort, dest, origin, ID) +local function sendOK(bHop, receiveM, recPort, dest, origin, ID) if dest==iAdd then computer.pushSignal("GERTConnectionID", origin, ID) end if origin ~= iAdd then - transInfo(bHop, recPort, "RouteOpen", dest, origin, ID) + transInfo(bHop, receiveM, recPort, "RouteOpen", dest, origin, ID) end end -handler.OpenRoute = function (sendingModem, port, dest, intermediary, origin, ID) +handler.OpenRoute = function (receiveM, sendM, port, dest, intermediary, origin, ID) if dest == iAdd then storeConnection(origin, ID, dest) - sendOK(sendingModem, port, dest, origin, ID) + sendOK(sendM, receiveM, port, dest, origin, ID) elseif nodes[dest] then - transInfo(nodes[dest]["add"], nodes[dest]["port"], "OpenRoute", dest, nil, origin, ID) + transInfo(nodes[dest]["add"], nodes[dest]["receiveM"], nodes[dest]["port"], "OpenRoute", dest, nil, origin, ID) elseif not intermediary then - transInfo(firstN["add"], firstN["port"], "OpenRoute", dest, nil, origin, ID) + transInfo(firstN["add"], firstN["receiveM"], firstN["port"], "OpenRoute", dest, nil, origin, ID) else local nextHop = tonumber(string.sub(intermediary, 1, string.find(intermediary, "|")-1)) intermediary = string.sub(intermediary, string.find(intermediary, "|")+1) - transInfo(nodes[nextHop]["add"], nodes[nextHop]["port"], "OpenRoute", dest, intermediary, origin, ID) + transInfo(nodes[nextHop]["add"], nodes[nextHop]["receiveM"], nodes[nextHop]["port"], "OpenRoute", dest, intermediary, origin, ID) end - cPend[dest..origin]={["bHop"]=sendingModem, ["port"]=port} + cPend[dest..origin]={["bHop"]=sendM, ["port"]=port, ["receiveM"]=receiveM} end -handler.RegisterComplete = function(sender, port, target, newG) - if (modem and target == modem.address) or (tunnel and target == tunnel.address) then +handler.RegisterComplete = function(receiveM, _, port, target, newG) + if (mTable and mTable[target]) or (tTable and tTable[target]) then iAdd = tonumber(newG) elseif rPend[target] then - transInfo(rPend[target]["add"], rPend[target]["port"], "RegisterComplete", target, newG) + transInfo(rPend[target]["add"], rPend[target]["receiveM"], rPend[target]["port"], "RegisterComplete", target, newG) rPend[target] = nil end end -handler.RegisterNode = function (sender, sPort, origin, nTier, serialTable) - transInfo(firstN["add"], firstN["port"], "RegisterNode", origin, nTier, serialTable) - rPend[origin] = {} - rPend[origin]["add"] = sender - rPend[origin]["port"] = sPort +handler.RegisterNode = function (receiveM, sendM, sPort, origin, nTier, serialTable) + transInfo(firstN["add"], firstN["receiveM"], firstN["port"], "RegisterNode", origin, nTier, serialTable) + rPend[origin] = {["receiveM"]=receiveM, ["add"]=sendM, ["port"] = sPort} end -handler.RemoveNeighbor = function (sendingModem, port, origination) +handler.RemoveNeighbor = function (receiveM, _, port, origination) if nodes[origination] then nodes[origination] = nil end - transInfo(firstN["add"], firstN["port"], "RemoveNeighbor", origination) + transInfo(firstN["add"], receiveM, firstN["port"], "RemoveNeighbor", origination) end -handler.RouteOpen = function (sModem, sPort, pktDest, pktOrig, ID) +handler.RouteOpen = function (receiveM, sendM, sPort, pktDest, pktOrig, ID) if cPend[pktDest..pktOrig] then - sendOK(cPend[pktDest..pktOrig]["bHop"], cPend[pktDest..pktOrig]["port"], pktDest, pktOrig, ID) - storeConnection(pktOrig, ID, pktDest, sModem, sPort) + sendOK(cPend[pktDest..pktOrig]["bHop"], cPend[pktDest..pktOrig]["receiveM"], cPend[pktDest..pktOrig]["port"], pktDest, pktOrig, ID) + storeConnection(pktOrig, ID, pktDest, sendM, receiveM, sPort) cPend[pktDest..pktOrig] = nil end end -local function receivePacket(eventName, receivingModem, sendingModem, port, distance, code, ...) +local function receivePacket(_, receiveM, sendM, port, distance, code, ...) if handler[code] then - handler[code](sendingModem, port, ...) + handler[code](receiveM, sendM, port, ...) end end ------------------------------------------ event.listen("modem_message", receivePacket) -if tunnel then - tunnel.send("NewNode") +if tTable then + for key, value in pairs(tTable) do + tTable[key].send("NewNode") + end end -if modem then - modem.broadcast(4378, "NewNode") +if mTable then + for key, value in pairs(mTable) do + mTable[key].broadcast(4378, "NewNode") + end end os.sleep(2) @@ -190,38 +206,47 @@ os.sleep(2) local serialTable = serialize.serialize(nodes) if serialTable ~= "{}" then local mncUnavailable = true - local addr = (modem or tunnel).address - transInfo(firstN["add"], firstN["port"], "RegisterNode", addr, tier, serialTable) + local addr + transInfo(firstN["add"], firstN["receiveM"], firstN["port"], "RegisterNode", firstN["receiveM"], tier, serialTable) waitWithCancel(5, function () return iAdd end) if not iAdd then print("Unable to contact the MNC. Functionality will be impaired.") end end -if tunnel then - tunnel.send("NewNode", iAdd, tier) +if tTable then + for key, value in pairs(tTable) do + tTable[key].send("NewNode", iAdd, tier) + end end -if modem then - modem.broadcast(4378, "NewNode", iAdd, tier) +if mTable then + for key, value in pairs(mTable) do + mTable[key].broadcast(4378, "NewNode", iAdd, tier) + end end + --Listen to computer.shutdown to allow for better network leaves local function safedown() for key, value in pairs(connections) do - handler.CloseConnection((modem or tunnel).address, 4378, key) + handler.CloseConnection(_, _, 4378, key) end - if tunnel then - tunnel.send("RemoveNeighbor", iAdd) + if tTable then + for key, value in pairs(tTable) do + tTable[key].send("RemoveNeighbor", iAdd) end - if modem then - modem.broadcast(4378, "RemoveNeighbor", iAdd) +end +if mTable then + for key, value in pairs(mTable) do + mTable[key].broadcast(4378, "RemoveNeighbor", iAdd) end end +end event.listen("shutdown", safedown) ------------------- local function writeData(self, data) - if type(data) ~= "table" or type(data) ~= "function" then - transInfo(self.nextHop, self.outPort, "Data", data, self.outDex, self.order) + if type(data) ~= "table" and type(data) ~= "function" then + transInfo(self.nextHop, self.receiveM, self.outPort, "Data", data, self.outDex, self.order) self.order=self.order+1 end end @@ -239,13 +264,13 @@ local function readData(self, doPeek) end local function closeSock(self) - handler.CloseConnection((modem or tunnel).address, 4378, self.outDex) + handler.CloseConnection(_, _, 4378, self.outDex) end function GERTi.openSocket(gAddress, doEvent, outID) if type(doEvent) ~= "boolean" then outID = doEvent end - local port, add + local port, add, receiveM if not outID then outID = #connections + 1 end @@ -253,9 +278,10 @@ function GERTi.openSocket(gAddress, doEvent, outID) if nodes[gAddress] then port = nodes[gAddress]["port"] add = nodes[gAddress]["add"] - handler.OpenRoute((modem or tunnel).address, 4378, gAddress, nil, iAdd, outID) + receiveM = nodes[gAddress]["receiveM"] + handler.OpenRoute(receiveM, receiveM, 4378, gAddress, nil, iAdd, outID) else - handler.OpenRoute((modem or tunnel).address, 4378, gAddress, nil, iAdd, outID) + handler.OpenRoute(firstN["receiveM"], firstN["receiveM"], 4378, gAddress, nil, iAdd, outID) end waitWithCancel(3, function () return (not cPend[gAddress..iAdd]) end) if not cPend[gAddress..iAdd] then @@ -263,6 +289,7 @@ function GERTi.openSocket(gAddress, doEvent, outID) destination = gAddress, outPort = port or firstN["port"], nextHop = add or firstN["add"], + receiveM = receiveM or firstN["receiveM"], ID = outID, order = 1, outDex=iAdd.."|"..gAddress.."|"..outID, @@ -276,13 +303,13 @@ function GERTi.openSocket(gAddress, doEvent, outID) end end function GERTi.broadcast(data) - if modem and (type(data) ~= "table" or type(data) ~= "function") then - modem.broadcast(4378, data, -1, iAdd, -1) + if mTable and (type(data) ~= "table" and type(data) ~= "function") then + component.modem.broadcast(4378, "Data", data, -1, 0, iAdd) end end function GERTi.send(dest, data) - if nodes[dest] and (type(data) ~= "table" or type(data) ~= "function") then - transInfo(nodes[dest]["add"], nodes[dest]["port"], "Data", data, -1, 0, iAdd) + if nodes[dest] and (type(data) ~= "table" and type(data) ~= "function") then + transInfo(nodes[dest]["add"], nodes[dest]["receiveM"], nodes[dest]["port"], "Data", data, -1, 0, iAdd) end end function GERTi.getConnections() @@ -293,6 +320,7 @@ function GERTi.getConnections() tempTable[key]["destination"] = value["dest"] tempTable[key]["ID"] = value["ID"] tempTable[key]["nextHop"] = value["nextHop"] + tempTable[key]["receiveM"] = value["receiveM"] tempTable[key]["port"] = value["port"] tempTable[key]["order"] = value["order"] end @@ -307,6 +335,6 @@ function GERTi.getAddress() return iAdd end function GERTi.getVersion() - return "v1.3", "1.3 Release" + return "v1.4", "1.4" end return GERTi \ No newline at end of file diff --git a/GERTi/GERTiMNC.lua b/GERTi/GERTiMNC.lua index 673ccb4..723c450 100644 --- a/GERTi/GERTiMNC.lua +++ b/GERTi/GERTiMNC.lua @@ -1,21 +1,19 @@ --- GERT v1.3 +-- GERT v1.4 local component = require("component") local computer = require("computer") local event = require("event") local filesystem = require("filesystem") -local GERTe = nil +local GERTe local os = require("os") local serialize = require("serialization") -local modem = nil -local tunnel = nil +local mTable, tTable local nodes = {} local connections = {} local addressP1 = 0 local addressP2 = 1 -local gAddress = nil -local gKey = nil -local timerID = nil +local gAddress, gKey +local timerID ={} local savedAddresses = {} local directory = "/etc/GERTaddresses.gert" -- this function adds a handler for a set time in seconds, or until that handler returns a truthful value (whichever comes first) @@ -46,11 +44,11 @@ local function waitWithCancel(timeout, cancelCheck) return cancelCheck() end -local function storeChild(rAddress, port, tier) +local function storeChild(rAddress, receiveM, port, tier) -- parents means the direct connections a computer can make to another computer that is a higher tier than it -- children means the direct connections a computer can make to another computer that is a lower tier than it local childGA - if savedAddresses[rAddress] then + if savedAddresses[rAddress] then -- check to see if the address is already saved childGA = savedAddresses[rAddress] end if not childGA then @@ -69,16 +67,16 @@ local function storeChild(rAddress, port, tier) else addressP2 = addressP2 + 1 end + if (addressP2 % 10) == 0 then + addressP2 = addressP2 +1 + end end childGA = tonumber(childGA) - nodes[childGA] = {} - nodes[childGA]["add"] = rAddress - nodes[childGA]["tier"] = tonumber(tier) - nodes[childGA]["port"] = tonumber(port) + nodes[childGA] = {["add"] = rAddress, ["receiveM"] = receiveM, ["tier"] = tonumber(tier), ["port"] = tonumber(port)} -- Store modem address of the endpoint, modem address of the modem used to contact it, the tier, and the transmission port used to contact the client. return childGA end -local function storeConnection(origin, ID, dest, nextHop, port, lieAdd) +local function storeConnection(origin, ID, dest, nextHop, sendM, port, lieAdd) -- GERT address of the connection origin, Connection ID, GERT address of the destination, next node in the connection, modem used to reach the next node, port used to reach the next mode, and the full GERTc address (if necessary) local connectDex ID = math.floor(ID) if lieAdd then @@ -86,62 +84,57 @@ local function storeConnection(origin, ID, dest, nextHop, port, lieAdd) else connectDex = origin.."|"..dest.."|"..ID end - connections[connectDex] = {} - connections[connectDex]["origin"]=origin - connections[connectDex]["dest"]=dest - connections[connectDex]["ID"]=ID - connections[connectDex]["nextHop"]=nextHop - connections[connectDex]["port"]=port + connections[connectDex] = {["origin"]=origin, ["dest"]=dest, ["ID"]=ID, ["nextHop"]=nextHop, ["sendM"] = sendM, ["port"]=port} end -local function transInfo(sendTo, port, ...) - if (port ~= 0) and (modem) then - return modem.send(sendTo, port, ...) - elseif (tunnel) then - return tunnel.send(...) +local function transInfo(sendTo, localM, port, ...) + if mTable and mTable[localM] then + mTable[localM].send(sendTo, port, ...) + elseif tTable then + tTable[localM].send(...) end end local handler = {} -handler.CloseConnection = function(sendingModem, port, connectDex) - if connections[connectDex]["nextHop"] == (modem or tunnel).address then +handler.CloseConnection = function(receiveM, sendM, port, connectDex) + if connections[connectDex]["nextHop"] == 1 then connections[connectDex] = nil return else if string.find(connectDex, ":") then - transInfo(connections[connectDex]["nextHop"], connections[connectDex]["port"], "CloseConnection", connections[connectDex]["origin"].."|"..connections[connectDex]["dest"].."|"..connections[connectDex]["ID"]) + transInfo(connections[connectDex]["nextHop"], connections[connectDex]["sendM"], connections[connectDex]["port"], "CloseConnection", connections[connectDex]["origin"].."|"..connections[connectDex]["dest"].."|"..connections[connectDex]["ID"]) end - transInfo(connections[connectDex]["nextHop"], connections[connectDex]["port"], "CloseConnection", connectDex) + transInfo(connections[connectDex]["nextHop"], connections[connectDex]["sendM"], connections[connectDex]["port"], "CloseConnection", connectDex) connections[connectDex] = nil end end -handler.Data = function (sendingModem, port, data, connectDex, order, origin) +handler.Data = function (_, _, _, data, connectDex, order, origin) if string.find(connectDex, ":") and GERTe and string.sub(connectDex, 1, string.find(connectDex, ":")) ~= gAddress then local pipeDex = string.find(connectDex, "|") GERTe.transmitTo(string.sub(connectDex, 1, pipeDex), string.sub(connectDex, pipeDex+1, string.find(connectDex, "|", pipeDex)), data) elseif string.find(connectDex, ":") then - transInfo(connections[connectDex]["nextHop"], connections[connectDex]["port"], "Data", data, connections[connectDex]["origin"].."|"..connections[connectDex]["dest"].."|"..connections[connectDex]["ID"], order) + transInfo(connections[connectDex]["nextHop"], connections[connectDex]["sendM"], connections[connectDex]["port"], "Data", data, connections[connectDex]["origin"].."|"..connections[connectDex]["dest"].."|"..connections[connectDex]["ID"], order) elseif connections[connectDex] then - transInfo(connections[connectDex]["nextHop"], connections[connectDex]["port"], "Data", data, connectDex, order) + transInfo(connections[connectDex]["nextHop"], connections[connectDex]["sendM"], connections[connectDex]["port"], "Data", data, connectDex, order) end end -handler.NewNode = function (sendingModem, port, gAddres, nTier) +handler.NewNode = function (receiveM, sendM, port, gAddres, nTier) if not gAddress then - transInfo(sendingModem, port, "NewNode", 0.0, 0) + transInfo(sendM, receiveM, port, "NewNode", 0.0, 0) end end --- Used in handler["OPENROUTE"] -local function routeOpener(dest, origin, bHop, nextHop, hop2, recPort, transPort, ID, lieAdd) +-- Used in handler["OPENROUTE"] and marked for fusion/rearrangement in v1.5 +local function routeOpener(dest, origin, receiveM, sendM, bHop, nextHop, hop2, recPort, transPort, ID, lieAdd) print("Opening Route") local function sendOKResponse() - transInfo(bHop, recPort, "RouteOpen", (lieAdd or dest), origin, ID) - storeConnection(origin, ID, dest, nextHop, transPort, lieAdd) + transInfo(bHop, sendM, recPort, "RouteOpen", (lieAdd or dest), origin, ID) + storeConnection(origin, ID, dest, nextHop, receiveM, transPort, lieAdd) end if lieAdd or (not string.find(tostring(dest), ":")) then - transInfo(nextHop, transPort, "OpenRoute", dest, hop2, origin, ID) + transInfo(nextHop, receiveM, transPort, "OpenRoute", dest, hop2, origin, ID) addTempHandler(3, "RouteOpen", function (eventName, recv, sender, port, distance, code, pktDest, pktOrig, ID) if (dest == pktDest) and (origin == pktOrig) then sendOKResponse() @@ -152,25 +145,25 @@ local function routeOpener(dest, origin, bHop, nextHop, hop2, recPort, transPort sendOKResponse() end end - -handler.OpenRoute = function (sendingModem, port, dest, intermediary, origin, ID) +--marked for fusion/rearrangement in v1.5 +handler.OpenRoute = function (receiveM, sendM, port, dest, intermediary, origin, ID) local lieAdd dest = tostring(dest) - if string.find(dest, ":") and string.sub(dest, 1, string.find(dest, ":")-1)~= tostring(gAddress) then - return routeOpener(tonumber(dest), origin, sendingModem, modem.address, modem.address, port, port, ID) - elseif string.find(dest, ":") and string.sub(dest, 1, string.find(dest, ":")-1)== tostring(gAddress) then + if string.find(dest, ":") and string.sub(dest, 1, string.find(dest, ":")-1)~= tostring(gAddress) then -- If a GERTc address is entered and the GERTe component points to an endpoint other than the MNC, leave the destination intact. This will allow the MNC to send GERTe messages for this connection. + return routeOpener(dest, origin, receiveM, sendM, receiveM, receiveM, port, port, ID) + elseif string.find(dest, ":") and string.sub(dest, 1, string.find(dest, ":")-1)== tostring(gAddress) then -- If a GERTc address is entered and the GERTe component points to the MNC, fragment the address to allow for a hairpin turn. Marked for fusion/rearrangement in v1.5 lieAdd = dest dest = string.sub(dest, string.find(dest, ":")+1) end dest = tonumber(dest) if nodes[dest][0.0] then - return routeOpener(dest, origin, sendingModem, nodes[dest]["add"], nodes[dest]["add"], port, nodes[dest]["port"], ID, lieAdd) + return routeOpener(dest, origin, nodes[dest]["receiveM"], receiveM, sendM, nodes[dest]["add"], nodes[dest]["add"], port, nodes[dest]["port"], ID, lieAdd) -- If the destination is immediately adjacent to the MNC, configure the route as appropriate end local interTier = 1000 local nodeDex = dest local inter = "" - while interTier > 1 do + while interTier > 1 do -- Assemble the intermediary value while less than 1000. Marked for recursion testing in v1.5 for i=1, nodes[nodeDex]["tier"] do if nodes[nodeDex][i] then for key,value in pairs(nodes[nodeDex][i]) do @@ -183,16 +176,16 @@ handler.OpenRoute = function (sendingModem, port, dest, intermediary, origin, ID end end end - local nextHop = tonumber(string.sub(inter, 1, string.find(inter, "|")-1)) + local nextHop = tonumber(string.sub(inter, 1, string.find(inter, "|")-1)) -- Pull out the first intermediary inter = string.sub(inter, string.find(inter, "|")+1) - return routeOpener(dest, origin, sendingModem, nodes[nextHop]["add"], inter, port, nodes[nextHop]["port"], ID, lieAdd) + return routeOpener(dest, origin, nodes[nextHop]["receiveM"], receiveM, sendM, nodes[nextHop]["add"], inter, port, nodes[nextHop]["port"], ID, lieAdd) -- Send on information for further handling, optionally with lieAdd being the GERTi fragment of the full GERTc address end - -handler.RegisterNode = function (sendingModem, port, originatorAddress, childTier, childTable) +-- marked for enhancement in v1.5. Does not support updating old nodes to allow for properly refreshing the network table +handler.RegisterNode = function (receiveM, sendM, port, originatorAddress, childTier, childTable) childTable = serialize.unserialize(childTable) - childGA = storeChild(originatorAddress, port, childTier) - transInfo(sendingModem, port, "RegisterComplete", originatorAddress, childGA) - for key, value in pairs(childTable) do + childGA = storeChild(originatorAddress, receiveM, port, childTier) -- Store the node in the nodes table and retrieve the GERTi address of the node for sending it back. + transInfo(sendM, receiveM, port, "RegisterComplete", originatorAddress, childGA) + for key, value in pairs(childTable) do -- Load the node's neighbors into the nodes table if not nodes[childGA][value["tier"]] then nodes[childGA][value["tier"]] = {} end @@ -200,16 +193,16 @@ handler.RegisterNode = function (sendingModem, port, originatorAddress, childTie end end -handler.RemoveNeighbor = function (sendingModem, port, origination) +handler.RemoveNeighbor = function (_, _, _, origination) -- Checks to see if the nodes table contains the appropriate client, and removes it if so. if nodes[origination] ~= nil then nodes[origination] = nil end end -local function receivePacket(eventName, receivingModem, sendingModem, port, distance, code, ...) +local function receivePacket(_, receiveM, sendM, port, distance, code, ...) print(code) if handler[code] ~= nil then - handler[code](sendingModem, port, ...) + handler[code](receiveM, sendM, port, ...) end end @@ -220,10 +213,10 @@ local function readGMessage() while not errC and message do local target = string.sub(message["target"], string.find(message["target"], ":")+1) if connections[message["source"]..target..0] ~= nil then - handler["Data"](_, _, message["data"], target, message["source"], 0) + handler["Data"](_, _, _, message["data"], target, message["source"], 0) else - handler["OpenRoute"](modem.address, 4378, target, _, message["source"], 0) - handler["Data"](_, _, message["data"], target, message["source"], 0) + handler["OpenRoute"](nodes[target]["receiveM"], nodes[target]["port"], target, _, message["source"], 0) + handler["Data"](_, _, _, message["data"], target, message["source"], 0) end errC, message = pcall(GERTe.parse) end @@ -236,12 +229,15 @@ end local function safedown() if GERTe then - event.cancel(timerID) GERTe.shutdown() end + for key, value in pairs(timerID) do + event.cancel(value) + end + filesystem.remove("/etc/networkTables.gert") -- remove the network tables file on proper shut down to allow for recovering the MNC from a corrupted network configuration. end -function loadAddress() +local function loadAddress() -- load GERTi address file to restore cached GERTi addresses if filesystem.exists(directory) then print("Address file located; loading now.") local f = io.open(directory, "r") @@ -265,28 +261,50 @@ function loadAddress() end end +local function loadTables() -- reload the network tables if they have been cached after an improper restart + if filesystem.exists("/etc/networkTables.gert") then + print("Reloading cached network tables") + local f = io.open("/etc/networkTables.gert", r) + nodes = serialize.unserialize(f:read("*l")) + connections = serialize.unserialize(f:read("*l")) + f:close() + end +end + +-- Function that runs on a timer to cache the nodes and connections table. In this manner, they can be recovered successfully if the MNC is abruptly powered off +local function cacheNetworkTables() + local f = io.open("/etc/networkTables.gert", "w") + f:write(serialize.serialize(nodes).."\n") + f:write(serialize.serialize(connections)) + f:close() +end + function realStart() - if component.isAvailable("modem") then - modem = component.modem - modem.open(4378) - if modem.isWireless() then - modem.setStrength(500) +------------------------ Startup procedure + if (component.isAvailable("modem")) then + mTable = {} + for address, value in component.list("modem") do + mTable[address] = component.proxy(address) + mTable[address].open(4378) + if (mTable[address].isWireless()) then + mTable[address].setStrength(500) + end end end - - if component.isAvailable("tunnel") then - tunnel = component.tunnel + if (component.isAvailable("tunnel")) then + tTable = {} + for address, value in component.list("tunnel") do + tTable[address] = component.proxy(address) + end end - - if not (modem or tunnel) then - io.stderr:write("This program requires a network or linked card to run.") + if not (mTable or tTable) then + io.stderr:write("This program requires a network card or linked card to run.") os.exit(1) end if filesystem.exists("/lib/GERTeAPI.lua") then GERTe = require("GERTeAPI") end - ------------------------ Startup procedure event.listen("modem_message", receivePacket) if GERTe then @@ -298,10 +316,12 @@ function realStart() if not success then io.stderr:write("Error in connecting to GEDS! Error code: "..errCode) end - timerID = event.timer(0.1, readGMessage, math.huge) - event.listen("shutdown", safedown) + table.insert(timerID, event.timer(0.1, readGMessage, math.huge)) end loadAddress() + loadTables() + table.insert(timerID, event.timer(30, cacheNetworkTables, math.huge)) + event.listen("shutdown", safedown) print("Setup Complete!") end