2019-01-08 02:10:22 -05:00
local computer , event = computer , event
if _OSVERSION : sub ( 1 , 6 ) == " OpenOS " then
computer = require " computer "
event = require " event "
elseif _OSVERSION : sub ( 1 , 7 ) == " PsychOS " then
event = require " event "
end
local net = { }
net.mtu = 4096
net.streamdelay = 30
net.minport = 32768
net.maxport = 65535
net.openports = { }
2020-05-11 20:57:13 -04:00
function net . genPacketID ( ) -- -- string -- generate a random 16-character string, for use in packet IDs
2019-01-08 02:10:22 -05:00
local npID = " "
for i = 1 , 16 do
npID = npID .. string.char ( math.random ( 32 , 126 ) )
end
return npID
end
2020-05-11 20:57:13 -04:00
function net . usend ( to , port , data , npID ) -- string number string string -- -- send an unreliable packet to host *to* on port *port* with data *data*, optionally with the packet ID *npID*
2019-01-08 02:10:22 -05:00
computer.pushSignal ( " net_send " , 0 , to , port , data , npID )
end
2020-05-11 20:57:13 -04:00
function net . rsend ( to , port , data , block ) -- string number string boolean -- boolean -- send a reliable packet to host *to* on port *port* with data *data*, with *block* set to true to disable blocking
2019-01-08 02:10:22 -05:00
local pid , stime = net.genPacketID ( ) , computer.uptime ( ) + net.streamdelay
computer.pushSignal ( " net_send " , 1 , to , port , data , pid )
if block then return false end
repeat
_ , rpid = event.pull ( 0.5 , " net_ack " )
until rpid == pid or computer.uptime ( ) > stime
if not rpid then return false end
return true
end
-- ordered packet delivery, layer 4?
2020-05-11 20:57:13 -04:00
function net . send ( to , port , ldata ) -- string number string -- boolean -- send arbitrary data *ldata* reliably to host *to* on port *port*
2019-01-08 02:10:22 -05:00
local tdata = { }
if ldata : len ( ) > net.mtu then
for i = 1 , ldata : len ( ) , net.mtu do
tdata [ # tdata + 1 ] = ldata : sub ( 1 , net.mtu )
ldata = ldata : sub ( net.mtu + 1 )
end
else
tdata = { ldata }
end
for k , v in ipairs ( tdata ) do
if not net.rsend ( to , port , v ) then return false end
end
return true
end
-- socket stuff, layer 5?
local function cwrite ( self , data )
if self.state == " open " then
if not net.send ( self.addr , self.port , data ) then
self : close ( )
return false , " timed out "
end
end
end
local function cread ( self , length )
length = length or " \n "
local rdata = " "
if type ( length ) == " number " then
rdata = self.rbuffer : sub ( 1 , length )
self.rbuffer = self.rbuffer : sub ( length + 1 )
return rdata
elseif type ( length ) == " string " then
if length : sub ( 1 , 2 ) == " *a " then
rdata = self.rbuffer
self.rbuffer = " "
return rdata
elseif length : len ( ) == 1 then
local pre , post = self.rbuffer : match ( " (.-) " .. length .. " (.*) " )
if pre and post then
self.rbuffer = post
return pre
end
return nil
end
end
end
local function socket ( addr , port , sclose )
local conn = { }
conn.addr , conn.port = addr , tonumber ( port )
conn.rbuffer = " "
conn.write = cwrite
conn.read = cread
conn.state = " open "
conn.sclose = sclose
local function listener ( _ , f , p , d )
if f == conn.addr and p == conn.port then
if d == sclose then
conn : close ( )
else
conn.rbuffer = conn.rbuffer .. d
end
end
end
event.listen ( " net_msg " , listener )
function conn . close ( self )
event.ignore ( " net_msg " , listener )
conn.state = " closed "
net.rsend ( addr , port , sclose )
end
return conn
end
2020-05-11 20:57:13 -04:00
function net . open ( to , port ) -- string number -- buffer -- open a socket to host *to* on port *port*
2019-01-08 02:10:22 -05:00
if not net.rsend ( to , port , " openstream " ) then return false , " no ack from host " end
local st = computer.uptime ( ) + net.streamdelay
local est = false
while true do
_ , from , rport , data = event.pull ( " net_msg " )
if to == from and rport == port then
if tonumber ( data ) then
est = true
end
break
end
if st < computer.uptime ( ) then
return nil , " timed out "
end
end
if not est then
return nil , " refused "
end
data = tonumber ( data )
sclose = " "
repeat
_ , from , nport , sclose = event.pull ( " net_msg " )
until from == to and nport == data
return socket ( to , data , sclose )
end
2020-05-11 20:57:13 -04:00
function net . listen ( port ) -- number -- buffer -- listen for connections on port *port* in a blocking manner
2019-01-08 02:10:22 -05:00
repeat
_ , from , rport , data = event.pull ( " net_msg " )
until rport == port and data == " openstream "
local nport = math.random ( net.minport , net.maxport )
local sclose = net.genPacketID ( )
net.rsend ( from , rport , tostring ( nport ) )
net.rsend ( from , nport , sclose )
return socket ( from , nport , sclose )
end
2020-05-11 20:57:13 -04:00
function net . flisten ( port , listener ) -- number function -- function -- run function *listener* on a connection to *port*
2019-01-08 02:10:22 -05:00
local function helper ( _ , from , rport , data )
if rport == port and data == " openstream " then
local nport = math.random ( net.minport , net.maxport )
local sclose = net.genPacketID ( )
net.rsend ( from , rport , tostring ( nport ) )
net.rsend ( from , nport , sclose )
listener ( socket ( from , nport , sclose ) )
end
end
event.listen ( " net_msg " , helper )
return helper
end
return net