Added network loot disk

This commit is contained in:
Łukasz Magiera 2014-11-16 14:38:41 +01:00
parent 7704d3fff9
commit 715d4fedc6
16 changed files with 1073 additions and 3 deletions

View File

@ -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")

View File

@ -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

View File

@ -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")

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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")

View File

@ -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"

View File

@ -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 .. "/"

View File

@ -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