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 = {} function net.genPacketID() -- -- string -- generate a random 16-character string, for use in packet IDs local npID = "" for i = 1, 16 do npID = npID .. string.char(math.random(32,126)) end return npID end 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* computer.pushSignal("net_send",0,to,port,data,npID) end 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 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? function net.send(to,port,ldata) -- string number string -- boolean -- send arbitrary data *ldata* reliably to host *to* on port *port* 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 function net.open(to,port) -- string number -- buffer -- open a socket to host *to* on port *port* 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 function net.listen(port) -- number -- buffer -- listen for connections on port *port* in a blocking manner 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 function net.flisten(port,listener) -- number function -- function -- run function *listener* on a connection to *port* 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