AnnounceZeroPlugin.py 5.3 KB

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