turtle5204

patched rednet

Oct 10th, 2016
131
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 8.37 KB | None | 0 0
  1.  
  2. CHANNEL_BROADCAST = 65535
  3. CHANNEL_REPEAT = 65533
  4.  
  5. local tReceivedMessages = {}
  6. local tReceivedMessageTimeouts = {}
  7. local tHostnames = {}
  8.  
  9. function open( sModem )
  10. if type( sModem ) ~= "string" then
  11. error( "expected string", 2 )
  12. end
  13. if peripheral.getType( sModem ) ~= "modem" then
  14. error( "No such modem: "..sModem, 2 )
  15. end
  16. peripheral.call( sModem, "open", os.getComputerID() )
  17. peripheral.call( sModem, "open", CHANNEL_BROADCAST )
  18. end
  19.  
  20. function close( sModem )
  21. if sModem then
  22. -- Close a specific modem
  23. if type( sModem ) ~= "string" then
  24. error( "expected string", 2 )
  25. end
  26. if peripheral.getType( sModem ) ~= "modem" then
  27. error( "No such modem: "..sModem, 2 )
  28. end
  29. peripheral.call( sModem, "close", os.getComputerID() )
  30. peripheral.call( sModem, "close", CHANNEL_BROADCAST )
  31. else
  32. -- Close all modems
  33. for n,sModem in ipairs( peripheral.getNames() ) do
  34. if isOpen( sModem ) then
  35. close( sModem )
  36. end
  37. end
  38. end
  39. end
  40.  
  41. function isOpen( sModem )
  42. if sModem then
  43. -- Check if a specific modem is open
  44. if type( sModem ) ~= "string" then
  45. error( "expected string", 2 )
  46. end
  47. if peripheral.getType( sModem ) == "modem" then
  48. return peripheral.call( sModem, "isOpen", os.getComputerID() ) and peripheral.call( sModem, "isOpen", CHANNEL_BROADCAST )
  49. end
  50. else
  51. -- Check if any modem is open
  52. for n,sModem in ipairs( peripheral.getNames() ) do
  53. if isOpen( sModem ) then
  54. return true
  55. end
  56. end
  57. end
  58. return false
  59. end
  60.  
  61. function send( nRecipient, message, sProtocol )
  62. -- Generate a (probably) unique message ID
  63. -- We could do other things to guarantee uniqueness, but we really don't need to
  64. -- Store it to ensure we don't get our own messages back
  65. local nMessageID = math.random( 1, 2147483647 )
  66. tReceivedMessages[ nMessageID ] = true
  67. tReceivedMessageTimeouts[ os.startTimer( 30 ) ] = nMessageID
  68.  
  69. -- Create the message
  70. local nReplyChannel = os.getComputerID()
  71. local tMessage = {
  72. nMessageID = nMessageID,
  73. nRecipient = nRecipient,
  74. message = message,
  75. sProtocol = sProtocol,
  76. }
  77.  
  78. if nRecipient == os.getComputerID() then
  79. -- Loopback to ourselves
  80. os.queueEvent( "rednet_message", nReplyChannel, message, sProtocol )
  81.  
  82. else
  83. -- Send on all open modems, to the target and to repeaters
  84. local sent = false
  85. for n,sModem in ipairs( peripheral.getNames() ) do
  86. if isOpen( sModem ) then
  87. peripheral.call( sModem, "transmit", nRecipient, nReplyChannel, tMessage );
  88. peripheral.call( sModem, "transmit", CHANNEL_REPEAT, nReplyChannel, tMessage );
  89. sent = true
  90. end
  91. end
  92. end
  93. end
  94.  
  95. function broadcast( message, sProtocol )
  96. send( CHANNEL_BROADCAST, message, sProtocol )
  97. end
  98.  
  99. function receive( sProtocolFilter, nTimeout )
  100. -- The parameters used to be ( nTimeout ), detect this case for backwards compatibility
  101. if type(sProtocolFilter) == "number" and nTimeout == nil then
  102. sProtocolFilter, nTimeout = nil, sProtocolFilter
  103. end
  104.  
  105. -- Start the timer
  106. local timer = nil
  107. local sFilter = nil
  108. if nTimeout then
  109. timer = os.startTimer( nTimeout )
  110. sFilter = nil
  111. else
  112. sFilter = "rednet_message"
  113. end
  114.  
  115. -- Wait for events
  116. while true do
  117. local sEvent, p1, p2, p3 = os.pullEvent( sFilter )
  118. if sEvent == "rednet_message" then
  119. -- Return the first matching rednet_message
  120. local nSenderID, message, sProtocol = p1, p2, p3
  121. if sProtocolFilter == nil or sProtocol == sProtocolFilter then
  122. return nSenderID, message, sProtocol
  123. end
  124. elseif sEvent == "timer" then
  125. -- Return nil if we timeout
  126. if p1 == timer then
  127. return nil
  128. end
  129. end
  130. end
  131. end
  132.  
  133. function host( sProtocol, sHostname )
  134. if type( sProtocol ) ~= "string" or type( sHostname ) ~= "string" then
  135. error( "expected string, string", 2 )
  136. end
  137. if sHostname == "localhost" then
  138. error( "Reserved hostname", 2 )
  139. end
  140. if tHostnames[ sProtocol ] ~= sHostname then
  141. if lookup( sProtocol, sHostname ) ~= nil then
  142. error( "Hostname in use", 2 )
  143. end
  144. tHostnames[ sProtocol ] = sHostname
  145. end
  146. end
  147.  
  148. function unhost( sProtocol )
  149. if type( sProtocol ) ~= "string" then
  150. error( "expected string", 2 )
  151. end
  152. tHostnames[ sProtocol ] = nil
  153. end
  154.  
  155. function lookup( sProtocol, sHostname )
  156. if type( sProtocol ) ~= "string" then
  157. error( "expected string", 2 )
  158. end
  159.  
  160. -- Build list of host IDs
  161. local tResults = nil
  162. if sHostname == nil then
  163. tResults = {}
  164. end
  165.  
  166. -- Check localhost first
  167. if tHostnames[ sProtocol ] then
  168. if sHostname == nil then
  169. table.insert( tResults, os.getComputerID() )
  170. elseif sHostname == "localhost" or sHostname == tHostnames[ sProtocol ] then
  171. return os.getComputerID()
  172. end
  173. end
  174.  
  175. if not isOpen() then
  176. if tResults then
  177. return table.unpack( tResults )
  178. end
  179. return nil
  180. end
  181.  
  182. -- Broadcast a lookup packet
  183. broadcast( {
  184. sType = "lookup",
  185. sProtocol = sProtocol,
  186. sHostname = sHostname,
  187. }, "dns" )
  188.  
  189. -- Start a timer
  190. local timer = os.startTimer( 2 )
  191.  
  192. -- Wait for events
  193. while true do
  194. local event, p1, p2, p3 = os.pullEvent()
  195. if event == "rednet_message" then
  196. -- Got a rednet message, check if it's the response to our request
  197. local nSenderID, tMessage, sMessageProtocol = p1, p2, p3
  198. if sMessageProtocol == "dns" and tMessage.sType == "lookup response" then
  199. if tMessage.sProtocol == sProtocol then
  200. if sHostname == nil then
  201. table.insert( tResults, nSenderID )
  202. elseif tMessage.sHostname == sHostname then
  203. return nSenderID
  204. end
  205. end
  206. end
  207. else
  208. -- Got a timer event, check it's the end of our timeout
  209. if p1 == timer then
  210. break
  211. end
  212. end
  213. end
  214. if tResults then
  215. return table.unpack( tResults )
  216. end
  217. return nil
  218. end
  219.  
  220. local bRunning = false
  221. function run()
  222. if bRunning then
  223. error( "rednet is already running", 2 )
  224. end
  225. bRunning = true
  226.  
  227. while bRunning do
  228. local sEvent, p1, p2, p3, p4 = os.pullEventRaw()
  229. if sEvent == "modem_message" then
  230. -- Got a modem message, process it and add it to the rednet event queue
  231. local sModem, nChannel, nReplyChannel, tMessage = p1, p2, p3, p4
  232. if isOpen( sModem ) and ( nChannel == os.getComputerID() or nChannel == CHANNEL_BROADCAST ) then
  233. if type( tMessage ) == "table" and tMessage.nMessageID then
  234. if not tReceivedMessages[ tMessage.nMessageID ] then
  235. tReceivedMessages[ tMessage.nMessageID ] = true
  236. tReceivedMessageTimeouts[ os.startTimer( 30 ) ] = nMessageID
  237. os.queueEvent( "rednet_message", nReplyChannel, tMessage.message, tMessage.sProtocol )
  238. end
  239. end
  240. end
  241.  
  242. elseif sEvent == "rednet_message" then
  243. -- Got a rednet message (queued from above), respond to dns lookup
  244. local nSenderID, tMessage, sProtocol = p1, p2, p3
  245. tMessage = tostring(tMessage)
  246. if sProtocol == "dns" and tMessage.sType == "lookup" then
  247. local sHostname = tHostnames[ tMessage.sProtocol ]
  248. if sHostname ~= nil and (tMessage.sHostname == nil or tMessage.sHostname == sHostname) then
  249. rednet.send( nSenderID, {
  250. sType = "lookup response",
  251. sHostname = sHostname,
  252. sProtocol = tMessage.sProtocol,
  253. }, "dns" )
  254. end
  255. end
  256.  
  257. elseif sEvent == "timer" then
  258. -- Got a timer event, use it to clear the event queue
  259. local nTimer = p1
  260. local nMessage = tReceivedMessageTimeouts[ nTimer ]
  261. if nMessage then
  262. tReceivedMessageTimeouts[ nTimer ] = nil
  263. tReceivedMessages[ nMessage ] = nil
  264. end
  265. end
  266. end
  267. end
Advertisement
Add Comment
Please, Sign In to add comment