AnnounceZeroPlugin.py 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. import hashlib
  2. import time
  3. from Plugin import PluginManager
  4. from Peer import Peer
  5. from util import helper
  6. from Crypt import CryptRsa
  7. allow_reload = False # No source reload supported in this plugin
  8. time_full_announced = {} # Tracker address: Last announced all site to tracker
  9. connection_pool = {} # Tracker address: Peer object
  10. # Process result got back from tracker
  11. def processPeerRes(site, peers):
  12. added = 0
  13. # Ip4
  14. found_ip4 = 0
  15. for packed_address in peers["ip4"]:
  16. found_ip4 += 1
  17. peer_ip, peer_port = helper.unpackAddress(packed_address)
  18. if site.addPeer(peer_ip, peer_port):
  19. added += 1
  20. # Onion
  21. found_onion = 0
  22. for packed_address in peers["onion"]:
  23. found_onion += 1
  24. peer_onion, peer_port = helper.unpackOnionAddress(packed_address)
  25. if site.addPeer(peer_onion, peer_port):
  26. added += 1
  27. if added:
  28. site.worker_manager.onPeers()
  29. site.updateWebsocket(peers_added=added)
  30. site.log.debug("Found %s ip4, %s onion peers, new: %s" % (found_ip4, found_onion, added))
  31. @PluginManager.registerTo("Site")
  32. class SitePlugin(object):
  33. def announceTracker(self, tracker_protocol, tracker_address, fileserver_port=0, add_types=[], my_peer_id="", mode="start"):
  34. if tracker_protocol != "zero":
  35. return super(SitePlugin, self).announceTracker(
  36. tracker_protocol, tracker_address, fileserver_port, add_types, my_peer_id, mode
  37. )
  38. s = time.time()
  39. need_types = ["ip4"]
  40. if self.connection_server and self.connection_server.tor_manager and self.connection_server.tor_manager.enabled:
  41. need_types.append("onion")
  42. if mode == "start" or mode == "more": # Single: Announce only this site
  43. sites = [self]
  44. full_announce = False
  45. else: # Multi: Announce all currently serving site
  46. full_announce = True
  47. if time.time() - time_full_announced.get(tracker_address, 0) < 60 * 5: # No reannounce all sites within 5 minute
  48. return True
  49. time_full_announced[tracker_address] = time.time()
  50. from Site import SiteManager
  51. sites = [site for site in SiteManager.site_manager.sites.values() if site.settings["serving"]]
  52. # Create request
  53. request = {
  54. "hashes": [], "onions": [], "port": fileserver_port, "need_types": need_types, "need_num": 20, "add": add_types
  55. }
  56. for site in sites:
  57. if "onion" in add_types:
  58. onion = self.connection_server.tor_manager.getOnion(site.address)
  59. request["onions"].append(onion)
  60. request["hashes"].append(hashlib.sha256(site.address).digest())
  61. # Tracker can remove sites that we don't announce
  62. if full_announce:
  63. request["delete"] = True
  64. # Sent request to tracker
  65. tracker = connection_pool.get(tracker_address) # Re-use tracker connection if possible
  66. if not tracker:
  67. tracker_ip, tracker_port = tracker_address.split(":")
  68. tracker = Peer(tracker_ip, tracker_port, connection_server=self.connection_server)
  69. connection_pool[tracker_address] = tracker
  70. res = tracker.request("announce", request)
  71. if not res or "peers" not in res:
  72. self.log.debug("Announce to %s failed: %s" % (tracker_address, res))
  73. if full_announce:
  74. time_full_announced[tracker_address] = 0
  75. return False
  76. # Add peers from response to site
  77. site_index = 0
  78. for site_res in res["peers"]:
  79. site = sites[site_index]
  80. processPeerRes(site, site_res)
  81. site_index += 1
  82. # Check if we need to sign prove the onion addresses
  83. if "onion_sign_this" in res:
  84. self.log.debug("Signing %s for %s to add %s onions" % (res["onion_sign_this"], tracker_address, len(sites)))
  85. request["onion_signs"] = {}
  86. request["onion_sign_this"] = res["onion_sign_this"]
  87. request["need_num"] = 0
  88. for site in sites:
  89. onion = self.connection_server.tor_manager.getOnion(site.address)
  90. publickey = self.connection_server.tor_manager.getPublickey(onion)
  91. if publickey not in request["onion_signs"]:
  92. sign = CryptRsa.sign(res["onion_sign_this"], self.connection_server.tor_manager.getPrivatekey(onion))
  93. request["onion_signs"][publickey] = sign
  94. res = tracker.request("announce", request)
  95. if not res or "onion_sign_this" in res:
  96. self.log.debug("Announce onion address to %s failed: %s" % (tracker_address, res))
  97. if full_announce:
  98. time_full_announced[tracker_address] = 0
  99. return False
  100. if full_announce:
  101. tracker.remove() # Close connection, we don't need it in next 5 minute
  102. return time.time() - s