⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 track.py

📁 BitTorrent(简称BT
💻 PY
📖 第 1 页 / 共 3 页
字号:
# The contents of this file are subject to the BitTorrent Open Source License# Version 1.0 (the License).  You may not copy or use this file, in either# source code or executable form, except in compliance with the License.  You# may obtain a copy of the License at http://www.bittorrent.com/license/.## Software distributed under the License is distributed on an AS IS basis,# WITHOUT WARRANTY OF ANY KIND, either express or implied.  See the License# for the specific language governing rights and limitations under the# License.# Written by Bram Cohen and John Hoffmanimport sysimport osimport signalimport refrom threading import Eventfrom urlparse import urlparsefrom traceback import print_excfrom time import time, gmtime, strftime, localtimefrom random import shufflefrom types import StringType, IntType, LongType, ListType, DictTypefrom binascii import b2a_hexfrom cStringIO import StringIOfrom BitTorrent.obsoletepythonsupport import *from BitTorrent.parseargs import parseargs, formatDefinitionsfrom BitTorrent.RawServer import RawServerfrom BitTorrent.HTTPHandler import HTTPHandler, months, weekdaysfrom BitTorrent.parsedir import parsedirfrom BitTorrent.NatCheck import NatCheckfrom BitTorrent.bencode import bencode, bdecode, Bencachedfrom BitTorrent.zurllib import quote, unquotefrom BitTorrent import versiondefaults = [    ('port', 80, "Port to listen on."),    ('dfile', None, 'file to store recent downloader info in'),    ('bind', '', 'ip to bind to locally'),    ('socket_timeout', 15, 'timeout for closing connections'),    ('close_with_rst', 0, 'close connections with RST and avoid the TCP TIME_WAIT state'),    ('save_dfile_interval', 5 * 60, 'seconds between saving dfile'),    ('timeout_downloaders_interval', 45 * 60, 'seconds between expiring downloaders'),    ('reannounce_interval', 30 * 60, 'seconds downloaders should wait between reannouncements'),    ('response_size', 50, 'default number of peers to send in an info message if the client does not specify a number'),    ('timeout_check_interval', 5,        'time to wait between checking if any connections have timed out'),    ('nat_check', 3,        "how many times to check if a downloader is behind a NAT (0 = don't check)"),    ('log_nat_checks', 0,        "whether to add entries to the log for nat-check results"),    ('min_time_between_log_flushes', 3.0,        'minimum time it must have been since the last flush to do another one'),    ('min_time_between_cache_refreshes', 600.0,        'minimum time in seconds before a cache is considered stale and is flushed'),    ('allowed_dir', '', 'only allow downloads for .torrents in this dir (and recursively in subdirectories of directories that have no .torrent files themselves). If set, torrents in this directory show up on infopage/scrape whether they have peers or not'),    ('parse_dir_interval', 60, 'how often to rescan the torrent directory, in seconds'),    ('allowed_controls', 0, 'allow special keys in torrents in the allowed_dir to affect tracker access'),    ('hupmonitor', 0, 'whether to reopen the log file upon receipt of HUP signal'),    ('show_infopage', 1, "whether to display an info page when the tracker's root dir is loaded"),    ('infopage_redirect', '', 'a URL to redirect the info page to'),    ('show_names', 1, 'whether to display names from allowed dir'),    ('favicon', '', 'file containing x-icon data to return when browser requests favicon.ico'),    ('only_local_override_ip', 2, "ignore the ip GET parameter from machines which aren't on local network IPs (0 = never, 1 = always, 2 = ignore if NAT checking is not enabled). HTTP proxy headers giving address of original client are treated the same as --ip."),    ('logfile', '', 'file to write the tracker logs, use - for stdout (default)'),    ('allow_get', 0, 'use with allowed_dir; adds a /file?hash={hash} url that allows users to download the torrent file'),    ('keep_dead', 0, 'keep dead torrents after they expire (so they still show up on your /scrape and web page). Only matters if allowed_dir is not set'),    ('scrape_allowed', 'full', 'scrape access allowed (can be none, specific or full)'),    ('max_give', 200, 'maximum number of peers to give with any one request'),    ]def statefiletemplate(x):    if type(x) != DictType:        raise ValueError    for cname, cinfo in x.items():        if cname == 'peers':            for y in cinfo.values():      # The 'peers' key is a dictionary of SHA hashes (torrent ids)                 if type(y) != DictType:   # ... for the active torrents, and each is a dictionary                     raise ValueError                 for peerid, info in y.items(): # ... of client ids interested in that torrent                     if (len(peerid) != 20):                         raise ValueError                     if type(info) != DictType:  # ... each of which is also a dictionary                         raise ValueError # ... which has an IP, a Port, and a Bytes Left count for that client for that torrent                     if type(info.get('ip', '')) != StringType:                         raise ValueError                     port = info.get('port')                     if type(port) not in (IntType, LongType) or port < 0:                         raise ValueError                     left = info.get('left')                     if type(left) not in (IntType, LongType) or left < 0:                         raise ValueError        elif cname == 'completed':            if (type(cinfo) != DictType): # The 'completed' key is a dictionary of SHA hashes (torrent ids)                raise ValueError          # ... for keeping track of the total completions per torrent            for y in cinfo.values():      # ... each torrent has an integer value                if type(y) not in (IntType,LongType):                    raise ValueError      # ... for the number of reported completions for that torrent        elif cname == 'allowed':            if (type(cinfo) != DictType): # a list of info_hashes and included data                raise ValueError            if x.has_key('allowed_dir_files'):                adlist = [z[1] for z in x['allowed_dir_files'].values()]                for y in cinfo.keys():        # and each should have a corresponding key here                    if not y in adlist:                        raise ValueError        elif cname == 'allowed_dir_files':            if (type(cinfo) != DictType): # a list of files, their attributes and info hashes                raise ValueError            dirkeys = {}            for y in cinfo.values():      # each entry should have a corresponding info_hash                if not y[1]:                    continue                if not x['allowed'].has_key(y[1]):                    raise ValueError                if dirkeys.has_key(y[1]): # and each should have a unique info_hash                    raise ValueError                dirkeys[y[1]] = 1alas = 'your file may exist elsewhere in the universe\nbut alas, not here\n'def isotime(secs = None):    if secs == None:        secs = time()    return strftime('%Y-%m-%d %H:%M UTC', gmtime(secs))http_via_filter = re.compile(' for ([0-9.]+)\Z')def _get_forwarded_ip(headers):    if headers.has_key('http_x_forwarded_for'):        header = headers['http_x_forwarded_for']        try:            x,y = header.split(',')        except:            return header        if not is_local_ip(x):            return x        return y    if headers.has_key('http_client_ip'):        return headers['http_client_ip']    if headers.has_key('http_via'):        x = http_via_filter.search(headers['http_via'])        try:            return x.group(1)        except:            pass    if headers.has_key('http_from'):        return headers['http_from']    return Nonedef get_forwarded_ip(headers):    x = _get_forwarded_ip(headers)    if x is None or not is_valid_ipv4(x) or is_local_ip(x):        return None    return xdef compact_peer_info(ip, port):    try:        s = ( ''.join([chr(int(i)) for i in ip.split('.')])              + chr((port & 0xFF00) >> 8) + chr(port & 0xFF) )        if len(s) != 6:            s = ''    except:        s = ''  # not a valid IP, must be a domain name    return sdef is_valid_ipv4(ip):    a = ip.split('.')    if len(a) != 4:        return False    try:        for x in a:            chr(int(x))        return True    except:        return Falsedef is_local_ip(ip):    try:        v = [int(x) for x in ip.split('.')]        if v[0] == 10 or v[0] == 127 or v[:2] in ([192, 168], [169, 254]):            return 1        if v[0] == 172 and v[1] >= 16 and v[1] <= 31:            return 1    except ValueError:        return 0class Tracker(object):    def __init__(self, config, rawserver):        self.config = config        self.response_size = config['response_size']        self.max_give = config['max_give']        self.dfile = config['dfile']        self.natcheck = config['nat_check']        favicon = config['favicon']        self.favicon = None        if favicon:            try:                h = open(favicon,'r')                self.favicon = h.read()                h.close()            except:                print "**warning** specified favicon file -- %s -- does not exist." % favicon        self.rawserver = rawserver        self.cached = {}    # format: infohash: [[time1, l1, s1], [time2, l2, s2], [time3, l3, s3]]        self.cached_t = {}  # format: infohash: [time, cache]        self.times = {}        self.state = {}        self.seedcount = {}        self.only_local_override_ip = config['only_local_override_ip']        if self.only_local_override_ip == 2:            self.only_local_override_ip = not config['nat_check']        if os.path.exists(self.dfile):            try:                h = open(self.dfile, 'rb')                ds = h.read()                h.close()                tempstate = bdecode(ds)                if not tempstate.has_key('peers'):                    tempstate = {'peers': tempstate}                statefiletemplate(tempstate)                self.state = tempstate            except:                print '**warning** statefile '+self.dfile+' corrupt; resetting'        self.downloads    = self.state.setdefault('peers', {})        self.completed    = self.state.setdefault('completed', {})        self.becache = {}   # format: infohash: [[l1, s1], [l2, s2], [l3, s3]]        for infohash, ds in self.downloads.items():            self.seedcount[infohash] = 0            for x,y in ds.items():                if not y.get('nat',-1):                    ip = y.get('given_ip')                    if not (ip and self.allow_local_override(y['ip'], ip)):                        ip = y['ip']                    self.natcheckOK(infohash,x,ip,y['port'],y['left'])                if not y['left']:                    self.seedcount[infohash] += 1        for infohash in self.downloads:            self.times[infohash] = {}            for peerid in self.downloads[infohash]:                self.times[infohash][peerid] = 0        self.reannounce_interval = config['reannounce_interval']        self.save_dfile_interval = config['save_dfile_interval']        self.show_names = config['show_names']        rawserver.add_task(self.save_dfile, self.save_dfile_interval)        self.prevtime = time()        self.timeout_downloaders_interval = config['timeout_downloaders_interval']        rawserver.add_task(self.expire_downloaders, self.timeout_downloaders_interval)        self.logfile = None        self.log = None        if (config['logfile'] != '') and (config['logfile'] != '-'):            try:                self.logfile = config['logfile']                self.log = open(self.logfile,'a')                sys.stdout = self.log                print "# Log Started: ", isotime()            except:                print "**warning** could not redirect stdout to log file: ", sys.exc_info()[0]        if config['hupmonitor']:            def huphandler(signum, frame, self = self):                try:                    self.log.close ()                    self.log = open(self.logfile,'a')                    sys.stdout = self.log                    print "# Log reopened: ", isotime()                except:                    print "**warning** could not reopen logfile"

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -