Operating system for OpenComputers
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

168 line
4.3KB

  1. local computer,event = computer,event
  2. if _OSVERSION:sub(1,6) == "OpenOS" then
  3. computer = require "computer"
  4. event = require "event"
  5. elseif _OSVERSION:sub(1,7) == "PsychOS" then
  6. event = require "event"
  7. end
  8. local net = {}
  9. net.mtu = 4096
  10. net.streamdelay = 30
  11. net.minport = 32768
  12. net.maxport = 65535
  13. net.openports = {}
  14. function net.genPacketID() -- generate a random 16-character string, for use in packet IDs
  15. local npID = ""
  16. for i = 1, 16 do
  17. npID = npID .. string.char(math.random(32,126))
  18. end
  19. return npID
  20. end
  21. function net.usend(to,port,data,npID) -- send an unreliable packet to host *to* on port *port* with data *data*, optionally with the packet ID *npID*
  22. computer.pushSignal("net_send",0,to,port,data,npID)
  23. end
  24. function net.rsend(to,port,data,block) -- send a reliable packet to host *to* on port *port* with data *data*, with *block* set to true to disable blocking
  25. local pid, stime = net.genPacketID(), computer.uptime() + net.streamdelay
  26. computer.pushSignal("net_send",1,to,port,data,pid)
  27. if block then return false end
  28. repeat
  29. _,rpid = event.pull(0.5,"net_ack")
  30. until rpid == pid or computer.uptime() > stime
  31. if not rpid then return false end
  32. return true
  33. end
  34. -- ordered packet delivery, layer 4?
  35. function net.send(to,port,ldata) -- send arbitrary data *ldata* reliably to host *to* on port *port*
  36. local tdata = {}
  37. if ldata:len() > net.mtu then
  38. for i = 1, ldata:len(), net.mtu do
  39. tdata[#tdata+1] = ldata:sub(1,net.mtu)
  40. ldata = ldata:sub(net.mtu+1)
  41. end
  42. else
  43. tdata = {ldata}
  44. end
  45. for k,v in ipairs(tdata) do
  46. if not net.rsend(to,port,v) then return false end
  47. end
  48. return true
  49. end
  50. -- socket stuff, layer 5?
  51. local function cwrite(self,data)
  52. if self.state == "open" then
  53. if not net.send(self.addr,self.port,data) then
  54. self:close()
  55. return false, "timed out"
  56. end
  57. end
  58. end
  59. local function cread(self,length)
  60. length = length or "\n"
  61. local rdata = ""
  62. if type(length) == "number" then
  63. rdata = self.rbuffer:sub(1,length)
  64. self.rbuffer = self.rbuffer:sub(length+1)
  65. return rdata
  66. elseif type(length) == "string" then
  67. if length:sub(1,2) == "*a" then
  68. rdata = self.rbuffer
  69. self.rbuffer = ""
  70. return rdata
  71. elseif length:len() == 1 then
  72. local pre, post = self.rbuffer:match("(.-)"..length.."(.*)")
  73. if pre and post then
  74. self.rbuffer = post
  75. return pre
  76. end
  77. return nil
  78. end
  79. end
  80. end
  81. local function socket(addr,port,sclose)
  82. local conn = {}
  83. conn.addr,conn.port = addr,tonumber(port)
  84. conn.rbuffer = ""
  85. conn.write = cwrite
  86. conn.read = cread
  87. conn.state = "open"
  88. conn.sclose = sclose
  89. local function listener(_,f,p,d)
  90. if f == conn.addr and p == conn.port then
  91. if d == sclose then
  92. conn:close()
  93. else
  94. conn.rbuffer = conn.rbuffer .. d
  95. end
  96. end
  97. end
  98. event.listen("net_msg",listener)
  99. function conn.close(self)
  100. event.ignore("net_msg",listener)
  101. conn.state = "closed"
  102. net.rsend(addr,port,sclose)
  103. end
  104. return conn
  105. end
  106. function net.open(to,port) -- open a socket to host *to* on port *port*
  107. if not net.rsend(to,port,"openstream") then return false, "no ack from host" end
  108. local st = computer.uptime()+net.streamdelay
  109. local est = false
  110. while true do
  111. _,from,rport,data = event.pull("net_msg")
  112. if to == from and rport == port then
  113. if tonumber(data) then
  114. est = true
  115. end
  116. break
  117. end
  118. if st < computer.uptime() then
  119. return nil, "timed out"
  120. end
  121. end
  122. if not est then
  123. return nil, "refused"
  124. end
  125. data = tonumber(data)
  126. sclose = ""
  127. repeat
  128. _,from,nport,sclose = event.pull("net_msg")
  129. until from == to and nport == data
  130. return socket(to,data,sclose)
  131. end
  132. function net.listen(port) -- listen for connections on port *port* in a blocking manner
  133. repeat
  134. _, from, rport, data = event.pull("net_msg")
  135. until rport == port and data == "openstream"
  136. local nport = math.random(net.minport,net.maxport)
  137. local sclose = net.genPacketID()
  138. net.rsend(from,rport,tostring(nport))
  139. net.rsend(from,nport,sclose)
  140. return socket(from,nport,sclose)
  141. end
  142. function net.flisten(port,listener) -- run function *listener* on a connection to *port*
  143. local function helper(_,from,rport,data)
  144. if rport == port and data == "openstream" then
  145. local nport = math.random(net.minport,net.maxport)
  146. local sclose = net.genPacketID()
  147. net.rsend(from,rport,tostring(nport))
  148. net.rsend(from,nport,sclose)
  149. listener(socket(from,nport,sclose))
  150. end
  151. end
  152. event.listen("net_msg",helper)
  153. return helper
  154. end
  155. return net