import time import urllib.request import struct import socket import lib.bencode_open as bencode_open from lib.subtl.subtl import UdpTrackerClient import socks import sockshandler import gevent from Plugin import PluginManager from Config import config from Debug import Debug from util import helper # We can only import plugin host clases after the plugins are loaded @PluginManager.afterLoad def importHostClasses(): global Peer, AnnounceError from Peer import Peer from Site.SiteAnnouncer import AnnounceError @PluginManager.registerTo("SiteAnnouncer") class SiteAnnouncerPlugin(object): def getSupportedTrackers(self): trackers = super(SiteAnnouncerPlugin, self).getSupportedTrackers() if config.disable_udp or config.trackers_proxy != "disable": trackers = [tracker for tracker in trackers if not tracker.startswith("udp://")] return trackers def getTrackerHandler(self, protocol): if protocol == "udp": handler = self.announceTrackerUdp elif protocol == "http": handler = self.announceTrackerHttp elif protocol == "https": handler = self.announceTrackerHttps else: handler = super(SiteAnnouncerPlugin, self).getTrackerHandler(protocol) return handler def announceTrackerUdp(self, tracker_address, mode="start", num_want=10): s = time.time() if config.disable_udp: raise AnnounceError("Udp disabled by config") if config.trackers_proxy != "disable": raise AnnounceError("Udp trackers not available with proxies") ip, port = tracker_address.split("/")[0].split(":") tracker = UdpTrackerClient(ip, int(port)) if helper.getIpType(ip) in self.getOpenedServiceTypes(): tracker.peer_port = self.fileserver_port else: tracker.peer_port = 0 tracker.connect() if not tracker.poll_once(): raise AnnounceError("Could not connect") tracker.announce(info_hash=self.site.address_sha1, num_want=num_want, left=431102370) back = tracker.poll_once() if not back: raise AnnounceError("No response after %.0fs" % (time.time() - s)) elif type(back) is dict and "response" in back: peers = back["response"]["peers"] else: raise AnnounceError("Invalid response: %r" % back) return peers def httpRequest(self, url): headers = { 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.64 Safari/537.11', 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 'Accept-Charset': 'ISO-8859-1,utf-8;q=0.7,*;q=0.3', 'Accept-Encoding': 'none', 'Accept-Language': 'en-US,en;q=0.8', 'Connection': 'keep-alive' } req = urllib.request.Request(url, headers=headers) if config.trackers_proxy == "tor": tor_manager = self.site.connection_server.tor_manager handler = sockshandler.SocksiPyHandler(socks.SOCKS5, tor_manager.proxy_ip, tor_manager.proxy_port) opener = urllib.request.build_opener(handler) return opener.open(req, timeout=50) elif config.trackers_proxy == "disable": return urllib.request.urlopen(req, timeout=25) else: proxy_ip, proxy_port = config.trackers_proxy.split(":") handler = sockshandler.SocksiPyHandler(socks.SOCKS5, proxy_ip, int(proxy_port)) opener = urllib.request.build_opener(handler) return opener.open(req, timeout=50) def announceTrackerHttps(self, *args, **kwargs): kwargs["protocol"] = "https" return self.announceTrackerHttp(*args, **kwargs) def announceTrackerHttp(self, tracker_address, mode="start", num_want=10, protocol="http"): tracker_ip, tracker_port = tracker_address.rsplit(":", 1) if helper.getIpType(tracker_ip) in self.getOpenedServiceTypes(): port = self.fileserver_port else: port = 1 params = { 'info_hash': self.site.address_sha1, 'peer_id': self.peer_id, 'port': port, 'uploaded': 0, 'downloaded': 0, 'left': 431102370, 'compact': 1, 'numwant': num_want, 'event': 'started' } url = protocol + "://" + tracker_address + "?" + urllib.parse.urlencode(params) s = time.time() response = None # Load url if config.tor == "always" or config.trackers_proxy != "disable": timeout = 60 else: timeout = 30 with gevent.Timeout(timeout, False): # Make sure of timeout req = self.httpRequest(url) response = req.read() req.close() req = None if not response: raise AnnounceError("No response after %.0fs" % (time.time() - s)) # Decode peers try: peer_data = bencode_open.loads(response)[b"peers"] response = None peer_count = int(len(peer_data) / 6) peers = [] for peer_offset in range(peer_count): off = 6 * peer_offset peer = peer_data[off:off + 6] addr, port = struct.unpack('!LH', peer) peers.append({"addr": socket.inet_ntoa(struct.pack('!L', addr)), "port": port}) except Exception as err: raise AnnounceError("Invalid response: %r (%s)" % (response, Debug.formatException(err))) return peers