mirror of
https://github.com/MightyPirates/OpenComputers.git
synced 2025-09-18 11:48:02 -04:00
Added network loot disk
This commit is contained in:
parent
7704d3fff9
commit
715d4fedc6
@ -0,0 +1,7 @@
|
||||
local filesystem = require("filesystem")
|
||||
local shell = require("shell")
|
||||
|
||||
local args = {...}
|
||||
shell.setPath(shell.getPath() .. ":/mnt/"..args[1].address:sub(1,3).."/")
|
||||
--shell.execute("installNetwork")
|
||||
|
@ -0,0 +1,32 @@
|
||||
local network = require "network"
|
||||
local computer = require "computer"
|
||||
local args = {...}
|
||||
|
||||
local function align(txt)return txt .. (" "):sub(#txt+1)end
|
||||
|
||||
if #args < 1 then
|
||||
print("Network interfaces:")
|
||||
local info = network.info.getInfo()
|
||||
for node, info in pairs(info.interfaces)do
|
||||
print(align(node).."Link encap:"..info.linkName)
|
||||
print(" HWaddr "..info.selfAddr)
|
||||
if node == "lo" then print(" HWaddr "..computer.address()) end
|
||||
local pktIn, pktOut, bytesIn, bytesOut = network.info.getInterfaceInfo(node)
|
||||
print(" RX packets:"..tostring(pktIn))
|
||||
print(" TX packets:"..tostring(pktOut))
|
||||
print(" RX bytes:"..tostring(bytesIn).." TX bytes:"..tostring(bytesOut))
|
||||
end
|
||||
elseif args[1] == "bind" and args[2] then
|
||||
print("Address attached")
|
||||
network.ip.bind(args[2])
|
||||
else
|
||||
print("Usage:")
|
||||
print(" ifconfig - view network summary")
|
||||
print(" ifconfig bind [addr] - 'attach' addnitional address to computer")
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -0,0 +1,21 @@
|
||||
local network = require "network"
|
||||
local event = require "event"
|
||||
local computer = require "computer"
|
||||
|
||||
local args = {...}
|
||||
|
||||
if #args < 1 then
|
||||
print("Usage: ping: [addr]")
|
||||
end
|
||||
|
||||
print("Pinging "..args[1].." with 16 bytes of data:")
|
||||
local pingID = network.icmp.ping(args[1], "0123456789abcdef")
|
||||
local start = computer.uptime()
|
||||
|
||||
local e, replier, id, payload
|
||||
repeat
|
||||
e, replier, id, payload = event.pull("ping_reply")
|
||||
until id == pingID
|
||||
|
||||
print("Got reply in "..tostring(computer.uptime()-start).." seconds")
|
||||
|
@ -0,0 +1,367 @@
|
||||
local event = require "event"
|
||||
local computer = require "computer"
|
||||
local network = require "network"
|
||||
|
||||
local _rawSend
|
||||
local isAccessible
|
||||
local getNodes
|
||||
local getInterfaceInfo
|
||||
local startNetwork
|
||||
|
||||
local dataHandler --Layer 2 data handler
|
||||
|
||||
local posix
|
||||
|
||||
|
||||
------------------------
|
||||
--Layer 1
|
||||
|
||||
local initated = false
|
||||
|
||||
local function start()
|
||||
if initated then return end
|
||||
initated = true
|
||||
|
||||
local computer = require "computer"
|
||||
local filesystem = require "filesystem"
|
||||
--local posix = require "posix"
|
||||
|
||||
---------
|
||||
--Debug
|
||||
--posix.verbose(print)
|
||||
---------
|
||||
|
||||
|
||||
local accessibleHosts = {}
|
||||
local nodes = {}
|
||||
|
||||
--DRIVER INIT
|
||||
--print("Loading drivers")
|
||||
|
||||
local drivers = {}
|
||||
|
||||
for file in filesystem.list("/lib/network") do
|
||||
|
||||
--print("Loading driver:", file)
|
||||
drivers[file] = {driver = loadfile("/lib/network/"..file)()}
|
||||
|
||||
local eventHandler = {}--EVENT HANDLERS FOR DRIVER EVENTS
|
||||
--eventHandler.debug = print
|
||||
eventHandler.debug = function()end
|
||||
|
||||
function eventHandler.newHost(node, address)--New interface in net node
|
||||
--print("New host: ",node, address)
|
||||
accessibleHosts[address] = {driver = drivers[file], node = node}
|
||||
nodes[node].hosts[address] = address--mark host in node
|
||||
end
|
||||
|
||||
function eventHandler.newInterface(interface, selfAddr, linkName)--New node
|
||||
--print("New interface: ",interface, selfaddr)
|
||||
nodes[interface] = {hosts={}, driver = drivers[file], selfAddr = selfAddr, linkName = linkName}
|
||||
end
|
||||
|
||||
function eventHandler.recvData(data, node, origin)
|
||||
dataHandler(data, node, origin)
|
||||
end
|
||||
|
||||
function eventHandler.setListener(evt, listener)
|
||||
return event.listen(evt, function(...)
|
||||
local args = {...}
|
||||
local res = {pcall(function()listener(table.unpack(args))end)}
|
||||
if not res[1] then
|
||||
print("ERROR IN NET EVENTHANDLER["..file.."]:",res[2])
|
||||
end
|
||||
return table.unpack(res,2)
|
||||
end)
|
||||
end
|
||||
|
||||
drivers[file].handle = drivers[file].driver.start(eventHandler)
|
||||
end
|
||||
|
||||
_rawSend = function(addr, node, data)
|
||||
--print("TrySend:",node,addr,":",data)
|
||||
if accessibleHosts[addr] then
|
||||
accessibleHosts[addr].driver.driver.send(accessibleHosts[addr].driver.handle, node, addr, data)
|
||||
end
|
||||
end
|
||||
|
||||
isAccessible = function(addr)
|
||||
if not accessibleHosts[addr] then return end
|
||||
return accessibleHosts[addr].node, accessibleHosts[addr].driver
|
||||
end
|
||||
|
||||
getNodes = function()
|
||||
return nodes
|
||||
end
|
||||
|
||||
getInterfaceInfo = function(interface)
|
||||
if nodes[interface] then
|
||||
return nodes[interface].driver.driver.info(interface)
|
||||
end
|
||||
end
|
||||
|
||||
print("Link Control initated")
|
||||
startNetwork()
|
||||
print("Network initated")
|
||||
end
|
||||
|
||||
------------------------
|
||||
--Layer 2
|
||||
|
||||
startNetwork = function()
|
||||
|
||||
local ttl = 32
|
||||
local rawSend
|
||||
local send
|
||||
|
||||
local routeRequests = {} -- Table by dest addressed of tables {type = T[, data=..]}, types: D(own waiting data), R(route request for someone), E(routed data we should be able to route..)
|
||||
local routes = {} --Table of pairs -> [this or route] / {thisHost=true} / {router = [addr]}
|
||||
|
||||
routes[computer.address()] = {thisHost=true}
|
||||
|
||||
-----Utils
|
||||
local function sizeToString(size)
|
||||
return string.char((size)%256) .. string.char(math.floor(size/256)%256) .. string.char(math.floor(size/65536)%256)
|
||||
end
|
||||
|
||||
local function readSizeStr(str, pos)
|
||||
local len = str:sub(pos,pos):byte()
|
||||
return str:sub(pos+1, pos+len), len+1
|
||||
end
|
||||
|
||||
local toByte = string.char
|
||||
-----Data out
|
||||
|
||||
local function onRecv(origin, data)
|
||||
computer.pushSignal("network_message", origin, data)
|
||||
end
|
||||
|
||||
-----Sending
|
||||
|
||||
local function sendDirectData(addr, data)--D[ttl-byte][data]
|
||||
return rawSend(addr, "D"..toByte(ttl)..data)
|
||||
end
|
||||
|
||||
local function sendRoutedData(addr, data)--E[ttl-byte][hostlen-byte][dest host][hostlen-byte][origin host]message
|
||||
local nodes = getNodes()
|
||||
local msg = "E"..toByte(ttl)..toByte(addr:len())..addr..toByte(nodes[routes[addr].node].selfAddr:len())..nodes[routes[addr].node].selfAddr..data
|
||||
_rawSend(routes[addr].router, routes[addr].node, msg)
|
||||
end
|
||||
|
||||
local function sendRoutedDataAs(addr, origin, data, ottl)--E[ttl-byte][hostlen-byte][dest host][hostlen-byte][origin host]message
|
||||
local msg = "E"..toByte(ottl-1)..toByte(addr:len())..addr..toByte(origin:len())..origin..data
|
||||
_rawSend(routes[addr].router, routes[addr].node, msg)
|
||||
end
|
||||
|
||||
local function sendRouteRequest(addr)--R[ttl-byte][Addr len][Requested addr][Route hosts-byte][ [addrLen-byte][addr] ]
|
||||
local base = "R"..toByte(ttl)..toByte(addr:len())..addr..toByte(1)
|
||||
local nodes = getNodes()
|
||||
local sent = {}
|
||||
for node, n in pairs(nodes) do
|
||||
for host in pairs(n.hosts)do
|
||||
if not sent[host]then
|
||||
sent[host] = true
|
||||
_rawSend(host, node, base..toByte(n.selfAddr:len())..n.selfAddr)
|
||||
end
|
||||
end
|
||||
end
|
||||
sent = nil
|
||||
end
|
||||
|
||||
local function resendRouteRequest(orig, node, host, nttl)--R[ttl-byte][Addr len][Requested addr][Route hosts-byte][ [addrLen-byte][addr] ]
|
||||
local nodes = getNodes()
|
||||
local hlen = orig:sub(3,3):byte()
|
||||
|
||||
--local msg = "R" .. toByte(nttl) .. toByte(hlen+1) .. orig:sub(pos+4) .. toByte(nodes[node].selfAddr) .. nodes[node].selfAddr --broken, TODO repair
|
||||
local msg = "R" .. toByte(nttl) .. orig:sub(3) --workaround
|
||||
_rawSend(host, node, msg)
|
||||
end
|
||||
|
||||
local function sendHostFound(dest, addr)--H[ttl-byte][Found host]
|
||||
return rawSend(dest, "H"..toByte(ttl)..addr)
|
||||
end
|
||||
|
||||
rawSend = function(addr, data)
|
||||
local node, driver = isAccessible(addr)
|
||||
if node then
|
||||
_rawSend(addr, node, data)
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
send = function(addr, data)
|
||||
if type(addr) ~= "string" then error("Address must be string!!") end
|
||||
if not sendDirectData(addr, data) then--Try send directly
|
||||
if routes[addr] then
|
||||
if routes[addr].thisHost then
|
||||
onRecv("localhost", data)--it's this host, use loopback
|
||||
else
|
||||
sendRoutedData(addr, data)--We know route, try to send it that way
|
||||
end
|
||||
else
|
||||
--route is unknown, we have to request it if we havent did it already
|
||||
if not routeRequests[addr] then
|
||||
routeRequests[addr] = {}
|
||||
routeRequests[addr][#routeRequests[addr]+1] = {type = "D", data = data}
|
||||
sendRouteRequest(addr)
|
||||
else
|
||||
routeRequests[addr][#routeRequests[addr]+1] = {type = "D", data = data}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function processRouteRequests(host)
|
||||
if routeRequests[host] then
|
||||
for _, request in pairs(routeRequests[host]) do
|
||||
if request.type == "D" then
|
||||
sendRoutedData(host, request.data)
|
||||
elseif request.type == "E" then
|
||||
if request.ttl-1 > 1 then
|
||||
sendRoutedDataAs(host, request.origin, request.data, request.ttl)
|
||||
end
|
||||
elseif request.type == "R" then
|
||||
sendHostFound(request.host, host)
|
||||
end
|
||||
end
|
||||
routeRequests[host] = nil
|
||||
end
|
||||
end
|
||||
|
||||
local function checkRouteDest(dest, origin, node, data)
|
||||
local nodes = getNodes()
|
||||
if dest == nodes[node].selfAddr then
|
||||
return true
|
||||
elseif routes[dest] and routes[dest].thisHost then
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
bindAddr = function(addr)
|
||||
routes[addr] = {thisHost=true}
|
||||
processRouteRequests(addr)
|
||||
end
|
||||
|
||||
dataHandler = function(data, node, origin)
|
||||
--print("DATA:", data, node, origin)
|
||||
|
||||
if data:sub(1,1) == "D" then --Direct data
|
||||
onRecv(origin, data:sub(3))
|
||||
elseif data:sub(1,1) == "E" then --Routed data
|
||||
local ttl = data:byte(2)
|
||||
local dest, destlen = readSizeStr(data, 3)
|
||||
local orig, origlen = readSizeStr(data, 3+destlen)
|
||||
local dat = data:sub(3+destlen+origlen)
|
||||
if checkRouteDest(dest, orig, node, dat) then
|
||||
onRecv(orig, dat)
|
||||
else
|
||||
if routes[dest] then
|
||||
if ttl-1 > 0 then
|
||||
sendRoutedDataAs(dest, orig, dat, ttl)
|
||||
end
|
||||
else
|
||||
local _node, driver = isAccessible(dest)
|
||||
if _node then
|
||||
routes[dest] = {router = dest, node = _node}
|
||||
if ttl-1 > 0 then
|
||||
sendRoutedDataAs(dest, orig, dat, ttl)
|
||||
end
|
||||
else
|
||||
if not routeRequests[dest] then routeRequests[dest] = {} end
|
||||
routeRequests[dest][#routeRequests[dest]+1] = {type = "E", origin = orig, ttl = ttl, data = dat}
|
||||
sendRouteRequest(dest)
|
||||
end
|
||||
end
|
||||
end
|
||||
elseif data:sub(1,1) == "R" then --Route request
|
||||
local dest, l = readSizeStr(data, 3)
|
||||
if not routeRequests[dest] then
|
||||
|
||||
--check if accessible interface
|
||||
local nodes = getNodes()
|
||||
for _node, n in pairs(nodes) do
|
||||
if _node ~= node then --requested host won't ever be in same node
|
||||
for host in pairs(n.hosts)do
|
||||
if host == dest then
|
||||
--Found it!
|
||||
sendHostFound(origin, dest)
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--check if route known
|
||||
if routes[dest] then
|
||||
if routes[dest].thisHost then
|
||||
--sendHostFound(origin, nodes[node].selfAddr)
|
||||
sendHostFound(origin, dest)
|
||||
elseif routes[dest].router ~= origin then--Routen might have rebooted and is asking about route
|
||||
--sendHostFound(origin, routes[dest].router)
|
||||
sendHostFound(origin, dest)
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
routeRequests[dest] = {}
|
||||
routeRequests[dest][#routeRequests[dest]+1] = {type = "R", host = origin}
|
||||
|
||||
local nttl = data:byte(2)-1
|
||||
if nttl > 1 then
|
||||
local sent = {}
|
||||
--Bcast request
|
||||
for _node, n in pairs(nodes) do
|
||||
if _node ~= node then --We mustn't send it to origin node
|
||||
for host in pairs(n.hosts)do
|
||||
if not sent[host] then
|
||||
sent[host] = true
|
||||
resendRouteRequest(data, _node, host, nttl)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
sent = nil
|
||||
else
|
||||
--we've already requested this addr so if we get the route
|
||||
--we'll respond
|
||||
routeRequests[dest][#routeRequests[dest]+1] = {type = "R", host = origin}
|
||||
end
|
||||
elseif data:sub(1,1) == "H" then --Host found
|
||||
local nttl = data:byte(2)-1
|
||||
local host = data:sub(3)
|
||||
|
||||
if not routes[host] then
|
||||
routes[host] = {router = origin, node = node}
|
||||
processRouteRequests(host)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
network.core.setCallback("send", send)
|
||||
network.core.setCallback("bind", bindAddr)
|
||||
|
||||
---------------
|
||||
--Network stats&info
|
||||
|
||||
local function getInfo()
|
||||
local res = {}
|
||||
|
||||
res.interfaces = {}
|
||||
for k, node in pairs(getNodes())do
|
||||
res.interfaces[k] = {selfAddr = node.selfAddr, linkName = node.linkName}
|
||||
end
|
||||
|
||||
return res
|
||||
end
|
||||
|
||||
network.core.setCallback("netstat", getInfo)
|
||||
network.core.setCallback("intstat", getInterfaceInfo)
|
||||
|
||||
network.core.lockCore()
|
||||
end
|
||||
|
||||
event.listen("init", start)
|
||||
|
@ -0,0 +1,222 @@
|
||||
local event = require "event"
|
||||
local computer = require "computer"
|
||||
|
||||
local driver = {}
|
||||
|
||||
local network = {}
|
||||
local internal = {}
|
||||
|
||||
------------
|
||||
--Core communication
|
||||
network.core = {}
|
||||
|
||||
function network.core.setCallback(name, fn)
|
||||
driver[name] = fn
|
||||
end
|
||||
|
||||
function network.core.lockCore()
|
||||
network.core = nil
|
||||
end
|
||||
|
||||
------------
|
||||
--ICMP
|
||||
|
||||
network.icmp = {}
|
||||
internal.icmp = {}
|
||||
|
||||
local pingid = 0
|
||||
function network.icmp.ping(addr, payload)
|
||||
pingid = pingid + 1
|
||||
driver.send(addr, "IP"..computer.address()..":"..tostring(pingid)..":"..payload)
|
||||
return pingid
|
||||
end
|
||||
|
||||
function internal.icmp.hanlde(origin, data)
|
||||
if data:sub(2,2) == "P" then
|
||||
local matcher = data:sub(3):gmatch("[^:]+")
|
||||
local compid = matcher()
|
||||
local id = tonumber(matcher())
|
||||
local payload = matcher()
|
||||
if compid == computer.address() then
|
||||
computer.pushSignal("ping_reply", origin, tonumber(id), payload)
|
||||
else
|
||||
driver.send(origin, data)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
------------
|
||||
--Datagrams - UDP like protocol
|
||||
|
||||
network.udp = {}
|
||||
internal.udp = {ports = {}}
|
||||
|
||||
function internal.udp.checkPortRange(port)
|
||||
if port < 0 or port > 65535 then error("Wrong port!")end
|
||||
end
|
||||
|
||||
function network.udp.open(port)
|
||||
internal.udp.checkPortRange(port)
|
||||
internal.udp.ports[port] = true
|
||||
end
|
||||
|
||||
function network.udp.close(port)
|
||||
internal.udp.checkPortRange(port)
|
||||
internal.udp.ports[port] = nil
|
||||
end
|
||||
|
||||
function network.udp.send(addr, port, data)
|
||||
internal.udp.checkPortRange(port)
|
||||
driver.send(addr, "D".. string.char(math.floor(port/256))..string.char(port%256)..data)
|
||||
end
|
||||
|
||||
function internal.udp.hanlde(origin, data)
|
||||
local port = data:byte(2)*256 + data:byte(3)
|
||||
if internal.udp.ports[port] then
|
||||
computer.pushSignal("datagram", origin, port, data:sub(4))
|
||||
end
|
||||
end
|
||||
|
||||
-----------
|
||||
--TCP - TCP like protocol
|
||||
|
||||
--O[port,2B][openers channel,2B] --Try open connection
|
||||
--A[opened channel,2B][openers channel,2B] --Accept connection
|
||||
--R[openers channel,2B] --Reject connection i.e. closed port
|
||||
--C[remote channel,2B] --Close connection(user request or adta at closed/wrong channel)
|
||||
--D[remote channel,2B][data] --Data
|
||||
|
||||
network.tcp = {}
|
||||
internal.tcp = {ports = {}, channels = {}, freeCh = 1}
|
||||
|
||||
function network.tcp.listen(port)
|
||||
internal.udp.checkPortRange(port)
|
||||
internal.tcp.ports[port] = true
|
||||
|
||||
end
|
||||
|
||||
function network.tcp.unlisten(port)
|
||||
internal.udp.checkPortRange(port)
|
||||
internal.tcp.ports[port] = nil
|
||||
end
|
||||
|
||||
function network.tcp.open(addr, port)
|
||||
internal.udp.checkPortRange(port)
|
||||
local ch = internal.tcp.freeCh
|
||||
if internal.tcp.channels[ch] and internal.tcp.channels[ch].next then
|
||||
internal.tcp.freeCh = internal.tcp.channels[ch].next
|
||||
else
|
||||
internal.tcp.freeCh = #internal.tcp.channels+1
|
||||
end
|
||||
internal.tcp.channels[ch] = {open = false, waiting = true, addr = addr, port = port}--mark openning
|
||||
|
||||
driver.send(addr, "TO".. string.char(math.floor(port/256))..string.char(port%256).. string.char(math.floor(ch/256))..string.char(ch%256))
|
||||
return ch
|
||||
end
|
||||
|
||||
function network.tcp.close(channel)
|
||||
if internal.tcp.channels[channel] then
|
||||
if internal.tcp.channels[channel].open or internal.tcp.channels[channel].waiting then
|
||||
driver.send(addr, "TC".. string.char(math.floor(internal.tcp.channels[channel].remote/256))..string.char(internal.tcp.channels[channel].remote%256))
|
||||
end
|
||||
internal.tcp.channels[channel] = {next = internal.tcp.freeCh}
|
||||
internal.tcp.freeCh = channel
|
||||
--computer.pushSignal("tcp_close", ch, internal.tcp.channels[ch].addr, internal.tcp.channels[ch].port)
|
||||
end
|
||||
end
|
||||
|
||||
function network.tcp.send(channel, data)
|
||||
if internal.tcp.channels[channel] and internal.tcp.channels[channel].open then
|
||||
driver.send(internal.tcp.channels[channel].addr, "TD".. string.char(math.floor(internal.tcp.channels[channel].remote/256))..string.char(internal.tcp.channels[channel].remote%256)..data)
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function internal.tcp.hanlde(origin, data)
|
||||
if data:sub(2,2) == "O" then
|
||||
local port = data:byte(3)*256 + data:byte(4)
|
||||
local rchan = data:byte(5)*256 + data:byte(6)
|
||||
|
||||
if internal.tcp.ports[port] then
|
||||
local ch = internal.tcp.freeCh
|
||||
if internal.tcp.channels[ch] and internal.tcp.channels[ch].next then
|
||||
internal.tcp.freeCh = internal.tcp.channels[ch].next
|
||||
else
|
||||
internal.tcp.freeCh = #internal.tcp.channels+1
|
||||
end
|
||||
internal.tcp.channels[ch] = {open = true, remote = rchan, addr = origin, port = port}
|
||||
driver.send(origin, "TA".. string.char(math.floor(ch/256))..string.char(ch%256) .. string.char(math.floor(rchan/256)) .. string.char(rchan%256))
|
||||
computer.pushSignal("tcp", "connection", ch, internal.tcp.channels[ch].addr, internal.tcp.channels[ch].port)
|
||||
else
|
||||
driver.send(origin, "TR".. string.char(math.floor(rchan/256))..string.char(rchan%256))
|
||||
end
|
||||
elseif data:sub(2,2) == "R" then
|
||||
local ch = data:byte(3)*256 + data:byte(4)
|
||||
if internal.tcp.channels[ch] and internal.tcp.channels[ch].waiting then
|
||||
internal.tcp.channels[ch] = {next = internal.tcp.freeCh}
|
||||
internal.tcp.freeCh = ch
|
||||
end
|
||||
elseif data:sub(2,2) == "A" then
|
||||
local remote = data:byte(3)*256 + data:byte(4)
|
||||
local ch = data:byte(3)*256 + data:byte(4)
|
||||
if internal.tcp.channels[ch] and internal.tcp.channels[ch].waiting then
|
||||
internal.tcp.channels[ch].waiting = nil
|
||||
internal.tcp.channels[ch].open = true
|
||||
internal.tcp.channels[ch].remote = remote
|
||||
computer.pushSignal("tcp", "connection", ch, internal.tcp.channels[ch].addr, internal.tcp.channels[ch].port)
|
||||
end
|
||||
elseif data:sub(2,2) == "C" then
|
||||
local ch = data:byte(3)*256 + data:byte(4)
|
||||
if internal.tcp.channels[ch] and internal.tcp.channels[ch].open then
|
||||
internal.tcp.channels[ch] = {next = internal.tcp.freeCh}
|
||||
internal.tcp.freeCh = ch
|
||||
computer.pushSignal("tcp" ,"close", ch, internal.tcp.channels[ch].addr, internal.tcp.channels[ch].port)
|
||||
end
|
||||
elseif data:sub(2,2) == "D" then
|
||||
local ch = data:byte(3)*256 + data:byte(4)
|
||||
if internal.tcp.channels[ch] and internal.tcp.channels[ch].open then
|
||||
computer.pushSignal("tcp", "message", ch, data:sub(5), internal.tcp.channels[ch].addr, internal.tcp.channels[ch].port)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-----------
|
||||
--IP
|
||||
|
||||
network.ip = {}
|
||||
|
||||
function network.ip.bind(addr)
|
||||
driver.bind(addr)
|
||||
end
|
||||
|
||||
------------
|
||||
--Data processing
|
||||
|
||||
event.listen("network_message", function(_, origin, data)
|
||||
--print("NETMSG/",origin,data)
|
||||
if data:sub(1,1) == "I" then internal.icmp.hanlde(origin, data)
|
||||
elseif data:sub(1,1) == "T" then internal.tcp.hanlde(origin, data)
|
||||
elseif data:sub(1,1) == "D" then internal.udp.hanlde(origin, data) end
|
||||
|
||||
end)
|
||||
|
||||
|
||||
------------
|
||||
--Info
|
||||
|
||||
network.info = {}
|
||||
network.info.getInfo = function(...)return driver.netstat(...) end
|
||||
network.info.getInterfaceInfo = function(...)return driver.intstat(...) end
|
||||
|
||||
------------
|
||||
|
||||
return network
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -0,0 +1,27 @@
|
||||
local driver = {}
|
||||
|
||||
local pktIn,pktOut,bytesIn,bytesOut = 0,0,0,0
|
||||
|
||||
function driver.start(eventHandler)
|
||||
eventHandler.newInterface("lo", "localhost", "Local Loopback")
|
||||
eventHandler.newHost("lo", "localhost")
|
||||
return {send = function(data)eventHandler.recvData(data, "lo", "localhost")end}
|
||||
end
|
||||
|
||||
function driver.send(handle, interface, destination, data)
|
||||
if interface == "lo" and destination == "localhost" then
|
||||
pktIn, pktOut = pktIn+1,pktOut+1
|
||||
bytesIn,bytesOut = bytesIn + data:len(), bytesOut + data:len()
|
||||
handle.send(data)
|
||||
end
|
||||
end
|
||||
|
||||
function driver.info(interface)
|
||||
if interface == "lo" then
|
||||
return pktIn,pktOut,bytesIn,bytesOut
|
||||
end
|
||||
return 0,0,0,0
|
||||
end
|
||||
|
||||
return driver
|
||||
|
@ -0,0 +1,87 @@
|
||||
--[[
|
||||
|
||||
Communication on port 1!
|
||||
|
||||
Node protocol:
|
||||
|
||||
Hello/broadcast(sent by new host in node): H (modem addersses are in event)
|
||||
Hi/direct(sent by hosts to new host): I (^)
|
||||
Host quitting/broadcast Q (^)
|
||||
Data/direct D[data] (origin from event)
|
||||
|
||||
]]
|
||||
local component = require "component"
|
||||
local event = require "event"
|
||||
|
||||
local driver = {}
|
||||
|
||||
local nodes = {}
|
||||
local eventHnd
|
||||
|
||||
function driver.start(eventHandler)
|
||||
eventHnd = eventHandler
|
||||
local c = 0
|
||||
|
||||
eventHandler.setListener("modem_message", function(_, interface, origin, port, _, data)
|
||||
if not nodes[interface] then return end --other kind of modem(possibly tunnel)
|
||||
|
||||
eventHandler.debug("modemmsg["..nodes[interface].name.."]/"..origin..":"..data)
|
||||
|
||||
nodes[interface].pktIn = nodes[interface].pktIn + 1
|
||||
nodes[interface].bytesIn = nodes[interface].bytesIn + data:len()
|
||||
|
||||
if data:sub(1,1) == "H" then
|
||||
eventHandler.newHost(nodes[interface].name, origin)
|
||||
component.invoke(interface, "send", origin, 1, "I")
|
||||
eventHandler.debug("REPL:",interface,origin)
|
||||
elseif data:sub(1,1) == "I"then
|
||||
eventHandler.newHost(nodes[interface].name, origin)
|
||||
elseif data:sub(1,1) == "Q"then
|
||||
eventHandler.delHost(nodes[interface].name, origin)
|
||||
elseif data:sub(1,1) == "D"then
|
||||
eventHandler.recvData(data:sub(2), nodes[interface].name, origin)
|
||||
end
|
||||
|
||||
end)
|
||||
|
||||
for int in component.list("modem", true)do
|
||||
eventHandler.newInterface("eth"..tostring(c), int, "Ethernet")
|
||||
|
||||
nodes["eth"..tostring(c)] = {modem = int, name = "eth"..tostring(c), pktIn = 0, pktOut = 1, bytesIn = 0, bytesOut = 1}
|
||||
nodes[int] = nodes["eth"..tostring(c)]
|
||||
|
||||
component.invoke(int, "open", 1)
|
||||
component.invoke(int, "broadcast", 1, "H")
|
||||
|
||||
eventHandler.newHost("eth"..tostring(c), int)--register loopback
|
||||
c = c + 1
|
||||
end
|
||||
|
||||
--eventHandler.newHost("lo", "localhost")
|
||||
return {}
|
||||
end
|
||||
|
||||
function driver.send(handle, interface, destination, data)
|
||||
if nodes[interface] then
|
||||
if nodes[interface].modem == destination then
|
||||
nodes[interface].pktOut = nodes[interface].pktOut + 1
|
||||
nodes[interface].bytesOut = nodes[interface].bytesOut + data:len()
|
||||
nodes[interface].pktIn = nodes[interface].pktIn + 1
|
||||
nodes[interface].bytesIn = nodes[interface].bytesIn + data:len()
|
||||
eventHnd.recvData(data, interface, destination)
|
||||
else
|
||||
nodes[interface].pktOut = nodes[interface].pktOut + 1
|
||||
nodes[interface].bytesOut = nodes[interface].bytesOut + 1 + data:len()
|
||||
component.invoke(nodes[interface].modem, "send", destination, 1, "D"..data)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function driver.info(interface)
|
||||
if nodes[interface] then
|
||||
return nodes[interface].pktIn,nodes[interface].pktOut,nodes[interface].bytesIn,nodes[interface].bytesOut
|
||||
end
|
||||
return 0,0,0,0
|
||||
end
|
||||
|
||||
return driver
|
@ -0,0 +1,77 @@
|
||||
local component = require "component"
|
||||
local event = require "event"
|
||||
--For protocol info look to at modem driver
|
||||
|
||||
local driver = {}
|
||||
|
||||
local nodes = {}
|
||||
local eventHnd
|
||||
|
||||
function driver.start(eventHandler)
|
||||
eventHnd = eventHandler
|
||||
local c = 0
|
||||
|
||||
eventHandler.setListener("modem_message", function(_, interface, origin, port, _, data)
|
||||
if not nodes[interface] then return end --other kind of modem(possibly modem)
|
||||
|
||||
eventHandler.debug("modemmsg["..nodes[interface].name.."]/"..origin..":"..data)
|
||||
|
||||
nodes[interface].pktIn = nodes[interface].pktIn + 1
|
||||
nodes[interface].bytesIn = nodes[interface].bytesIn + data:len()
|
||||
|
||||
if data:sub(1,1) == "H" then
|
||||
eventHandler.newHost(nodes[interface].name, origin)
|
||||
component.invoke(interface, "send", "I")
|
||||
eventHandler.debug("REPL:",interface,origin)
|
||||
elseif data:sub(1,1) == "I"then
|
||||
eventHandler.newHost(nodes[interface].name, origin)
|
||||
elseif data:sub(1,1) == "Q"then
|
||||
eventHandler.delHost(nodes[interface].name, origin)
|
||||
elseif data:sub(1,1) == "D"then
|
||||
eventHandler.recvData(data:sub(2), nodes[interface].name, origin)
|
||||
end
|
||||
|
||||
end)
|
||||
|
||||
for int in component.list("tunnel", true)do
|
||||
eventHandler.newInterface("tun"..tostring(c), int, "Tunnel")
|
||||
|
||||
nodes["tun"..tostring(c)] = {modem = int, name = "tun"..tostring(c), pktIn = 0, pktOut = 1, bytesIn = 0, bytesOut = 1}
|
||||
nodes[int] = nodes["tun"..tostring(c)]
|
||||
|
||||
component.invoke(int, "send", "H")
|
||||
|
||||
eventHandler.newHost("tun"..tostring(c), int)--register loopback
|
||||
c = c + 1
|
||||
end
|
||||
|
||||
--eventHandler.newInterface("lo", "localhost", "Local Loopback")
|
||||
--eventHandler.newHost("lo", "localhost")
|
||||
return {}
|
||||
end
|
||||
|
||||
function driver.send(handle, interface, destination, data)
|
||||
if nodes[interface] then
|
||||
if nodes[interface].modem == destination then
|
||||
nodes[interface].pktOut = nodes[interface].pktOut + 1
|
||||
nodes[interface].bytesOut = nodes[interface].bytesOut + data:len()
|
||||
nodes[interface].pktIn = nodes[interface].pktIn + 1
|
||||
nodes[interface].bytesIn = nodes[interface].bytesIn + data:len()
|
||||
eventHnd.recvData(data, interface, destination)
|
||||
else
|
||||
nodes[interface].pktOut = nodes[interface].pktOut + 1
|
||||
nodes[interface].bytesOut = nodes[interface].bytesOut + 1 + data:len()
|
||||
component.invoke(nodes[interface].modem, "send", "D"..data)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function driver.info(interface)
|
||||
if nodes[interface] then
|
||||
return nodes[interface].pktIn,nodes[interface].pktOut,nodes[interface].bytesIn,nodes[interface].bytesOut
|
||||
end
|
||||
return 0,0,0,0
|
||||
end
|
||||
|
||||
return driver
|
||||
|
@ -0,0 +1,55 @@
|
||||
local network = require "network"
|
||||
local event = require "event"
|
||||
local term = require "term"
|
||||
|
||||
local args = {...}
|
||||
|
||||
local listen = false
|
||||
local port = -1
|
||||
local addr
|
||||
|
||||
for _,par in ipairs(args) do
|
||||
if par == "-l" then
|
||||
listen = true
|
||||
elseif port < 1 then
|
||||
local p = tonumber(par)
|
||||
if p then
|
||||
port = p
|
||||
end
|
||||
else
|
||||
addr = par
|
||||
end
|
||||
end
|
||||
|
||||
if port < 0 then error("Unspecified port")end
|
||||
if not listen and not addr then error("Unspecified address")end
|
||||
|
||||
|
||||
local function handleTcp()
|
||||
local channel
|
||||
while true do
|
||||
local e = {event.pull()}
|
||||
if e[1] then
|
||||
if e[1] == "tcp" then
|
||||
if e[2] == "connection" then
|
||||
channel = e[3]
|
||||
if listen then network.tcp.unlisten(port)end
|
||||
print("connected")
|
||||
elseif e[2] == "message" then
|
||||
term.write(e[4])
|
||||
end
|
||||
elseif e[1] == "key_up" and channel then
|
||||
network.tcp.send(channel, string.char(e[3]))
|
||||
term.write(string.char(e[3]))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if listen then
|
||||
network.tcp.listen(port)
|
||||
handleTcp()
|
||||
else
|
||||
network.tcp.open(addr, port)
|
||||
handleTcp()
|
||||
end
|
@ -0,0 +1,16 @@
|
||||
NAME
|
||||
ifconfig - network information and configuration manager
|
||||
|
||||
SYNOPSIS
|
||||
ifconfig [command] [command arguments]
|
||||
|
||||
DESCRIPTION
|
||||
Displays information about current network status and configures its parts
|
||||
|
||||
EXAMPLES
|
||||
ifconfig
|
||||
Output network status information
|
||||
|
||||
ifconfig bind [address]
|
||||
Binds addnitional address to this device. Address should match [A-Za-z0-9%-]+ and be max 64 characters length
|
||||
|
@ -0,0 +1,47 @@
|
||||
NAME
|
||||
network - Advanced self-routing API
|
||||
|
||||
METHODS
|
||||
network.icmp.ping(addr, payload)
|
||||
Sends ping message to addr, message will come back triggering
|
||||
'ping_reply' event
|
||||
|
||||
network.ip.bind(addr)
|
||||
Attaches addnitional address to this computer, useful for
|
||||
core servers which addresses must me easisy rememberable
|
||||
Address SOULD be up to 64 characters, allowed characters: a-zA-Z, '-'
|
||||
|
||||
network.udp.open(port)
|
||||
Starts listening on specified port, when data arrives at port "datagram"
|
||||
event is triggered with origin, port, data parameters
|
||||
|
||||
network.udp.close(port)
|
||||
Stops listening on specified port
|
||||
|
||||
network.udp.send(addr, port, data)
|
||||
Sends data to specified host and port. Specified port MUST be open
|
||||
on remote machine
|
||||
|
||||
network.tcp.listen(port)
|
||||
Starts listening at specified port. When connection arrives event
|
||||
"tcp", "connection", channel, remoteaddr, port
|
||||
is trigerred
|
||||
|
||||
network.tcp.unlisten(port)
|
||||
Stops listening on specified port. Note that all connections made to
|
||||
this port will remain untouched
|
||||
|
||||
network.tcp.open(addr, port)
|
||||
Tries to open a new connection. Will trigger event
|
||||
"tcp", "connection", channel, remoteaddr, port
|
||||
When remote host accepted the connection
|
||||
|
||||
network.tcp.close(channel)
|
||||
Closes earlier opened connection, will trigger
|
||||
"tcp", "close", channel, remoteaddr, port
|
||||
on remote side
|
||||
|
||||
network.tcp.send(channel, data)
|
||||
Sends data to other side, will trigger
|
||||
"tcp", "message", ch, data, remoteaddr, port
|
||||
event on remote side
|
@ -0,0 +1,16 @@
|
||||
NAME
|
||||
ping - check if host is reachable
|
||||
|
||||
SYNOPSIS
|
||||
ping [address]
|
||||
|
||||
DESCRIPTION
|
||||
Sends special ping packet to remote host and waits for answer
|
||||
|
||||
EXAMPLES
|
||||
ping localhost
|
||||
Pings self
|
||||
|
||||
ping somehost
|
||||
Sends ping to somehost
|
||||
|
@ -0,0 +1,8 @@
|
||||
local filesystem = require "filesystem"
|
||||
local shell = require "shell"
|
||||
local process = require "process"
|
||||
print("installNetwork")
|
||||
|
||||
local status, installDir = shell.execute("install --noboot --nolabelset --name=Network --fromDir=/data/ --from="..filesystem.get(process.running()).address)
|
||||
|
||||
print("You must reboot to start network services")
|
@ -0,0 +1,84 @@
|
||||
MCNET
|
||||
=========
|
||||
|
||||
1. Definitions
|
||||
1. Network interface - any networking device that can send and recieve data and discover other cards in network node
|
||||
2. Network node - subnetwork of few compatibile network interfaces
|
||||
3. Address - unique name of network interface in network, by default unique id. One interface can have more than one address.
|
||||
|
||||
2. Network layers
|
||||
1. Physical - Implemented by network interface drivers, is able to send and recieve data form other interface in node, is responsible for host discovery in node
|
||||
2. Network - Implements routing.
|
||||
3. Transport - Other protocols allowing simple data transfer
|
||||
-This driver implements layer 2 and is interface to layer 1 implementations as well as part of layer 1
|
||||
|
||||
3. Layer implementation guidelines
|
||||
1. Physical
|
||||
1. Driver - Network interface driver is written in way libraries are written in LUA for OC. Each driver shold implement following methods:
|
||||
1. start(eventHandler): handle
|
||||
Starts a networking device, returns driver-defined handler. eventHandler is a table provded by higher layer, containing callbacks to it.
|
||||
2. send(handle, interface, destination, data)
|
||||
destination is address of another interface in node
|
||||
data is string data to send
|
||||
3. stop(handle, interface)
|
||||
Deactivates network interface. if interface is nil then driver should deactivate all its interfaces
|
||||
4. info(interface): pktIn, pktOut, bytesIn, bytesOut - usage stats
|
||||
2. Driver interface (or eventHandler) is table containing set of functions allowing lower layers to communicate with higher ones. The table must contain following methods:
|
||||
1. recvData(data, node, origin) - this function allows driver to pass incoming data to higher layer
|
||||
2. newInterface(interfaceAddr, selfAddr) - Register new interface. Interface is considered as node I/O, interface addr is internal node name
|
||||
3. delInterface(interfaceAddr)
|
||||
4. newHost(node, address) - this function must be called when new interface is detected in node
|
||||
5. delHost(node, address) - this function must be called when interface is removed from node
|
||||
6. setListener(evt, function) - event.listen wrapper
|
||||
|
||||
4. Network layer packets:
|
||||
Direct Data:
|
||||
D[ttl-byte][data]
|
||||
|
||||
Routed data:
|
||||
E[ttl-byte][hostlen-byte][dest host][hostlen-byte][origin host]message
|
||||
|
||||
Route Discovery:
|
||||
R[ttl-byte][Addr len][Requested addr][Route hosts-byte][ [addrLen-byte][addr] ]
|
||||
|
||||
Host found:
|
||||
H[ttl-byte][Found host]
|
||||
|
||||
Example case
|
||||
|
||||
a. network:
|
||||
|
||||
A G
|
||||
| |
|
||||
C--x--D--F--x
|
||||
| | |
|
||||
B E H
|
||||
|
||||
b: nodes
|
||||
1. A,B,C,D
|
||||
2. D,E
|
||||
3. D,F
|
||||
4. F,G,H
|
||||
|
||||
Example cases:
|
||||
I. Network booted, nodes know hosts in them
|
||||
1. Host A sends message to host B
|
||||
-Host A is hnown to host B, so host A sends to B direct message
|
||||
-Network data:
|
||||
A -> B: "Dmessage"
|
||||
2. Host A sends message to G
|
||||
-Host A doesn't know host G so it sends route request to all hosts
|
||||
host F knows G so it sends Host found packet back to A and another
|
||||
Host found to G so it will be able to reply faster
|
||||
-Network data:
|
||||
A -> B,C,D: "R[32][1]G[1][1]A"
|
||||
B,C = Connected to one node, do nothing
|
||||
D -> E,F: "R[31][1]G[2][1]A[1]D" - also D save A to requester table of G
|
||||
E = Connected to one node, but it's nice to know A
|
||||
F -> D "H[32]G"
|
||||
F -> G "H[32]A"
|
||||
D -> A "H[31]G" - D had A in requester table of G so the packet is sent
|
||||
A -> D "E[32][1]G[1]Amessage"
|
||||
D -> F "E[31][1]G[1]Amessage"
|
||||
F -> G "E[30][1]G[1]Amessage"
|
||||
|
@ -47,11 +47,12 @@ end
|
||||
candidates = nil
|
||||
|
||||
local name = options.name or "OpenOS"
|
||||
local origin = options.from and options.from:sub(1,3) or computer.getBootAddress():sub(1, 3)
|
||||
print("Installing " .. name .." to device " .. (choice.getLabel() or choice.address))
|
||||
os.sleep(0.25)
|
||||
local origin = options.from and options.from:sub(1,3) or computer.getBootAddress():sub(1, 3)
|
||||
local fromDir = options.fromDir or "/"
|
||||
local mnt = choice.address:sub(1, 3)
|
||||
local result, reason = os.execute("/bin/cp -vr /mnt/" .. origin .. "/* /mnt/" .. mnt .. "/")
|
||||
local result, reason = os.execute("/bin/cp -vr /mnt/" .. origin .. fromDir .. "* /mnt/" .. mnt .. "/")
|
||||
if not result then
|
||||
error(reason, 0)
|
||||
end
|
||||
@ -67,4 +68,6 @@ if not options.noreboot then
|
||||
end
|
||||
end
|
||||
print("Returning to shell.")
|
||||
return "/mnt/" .. origin .. "/"
|
||||
|
||||
|
||||
|
@ -6,10 +6,11 @@
|
||||
# weight 1. The color defaults to gray. It must be a dye's ore-dict name.
|
||||
BetterShell=besh
|
||||
Builder=build:1:dyeCyan
|
||||
MazeGen=maze:1:dyeBrown
|
||||
Network=network:1:dyeYellow
|
||||
OpenIRC=irc:1:dyeRed
|
||||
OpenLoader=openloader:1:dyeOrange
|
||||
OpenOS=openos:1:dyeGreen
|
||||
MazeGen=maze:1:dyeBrown
|
||||
OPPM=oppm:1:dyeLime
|
||||
# Higher chance to find the dig program, because it has the most immediate
|
||||
# use - OpenOS is craftable and IRC can be downloaded once an internet card
|
||||
|
Loading…
x
Reference in New Issue
Block a user