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

📄 rttmonitor.py

📁 bittorrent source by python. please enjoy
💻 PY
字号:
# By Greg Hazel and a smigden by Dave Harrisondebug = False#debug = Trueimport osimport Queueimport socketimport itertoolsimport randomfrom pprint import pprintfrom BitTorrent.platform import bttimeimport BitTorrent.stackthreading as threadingfrom BitTorrent.HostIP import get_host_ip, get_host_ipsif os.name == 'nt':    import win32icmp    IP_TTL_EXPIRED_TRANSIT = 11013    IP_SUCCESS = 0def daemon_thread(target, args=()):    t = threading.Thread(target=target, args=args)    t.setDaemon(True)    return tdef in_common(routes):    """routes is a list of lists, each containing a route to a peer."""    r = []    branch = False    for n in itertools.izip(*routes):        # strip dead nodes        f = [i for i in n if i != '*']        # ignore all dead nodes        if len(f) == 0:            continue                if len(set(f)) == 1:            r.append(f[0])        else:            # more than one unique node, the tree has branched            branch = True            break    return (branch, r)class RTTMonitorBase(object):    def __init__(self, new_rtt=None):        self.instantanious_rtt = None        self.min_rtt = None        self.max_rtt = None        def f(rtt):            pass        if new_rtt:            self.new_rtt = new_rtt        else:            self.new_rtt = f    def set_nodes_restart(self, nodes):        pass    def get_min_rtt(self):        return self.min_rtt    def get_max_rtt(self):        return self.max_rtt    def get_current_rtt(self):        return self.instantanious_rttclass RTTMonitorUnix(RTTMonitorBase):    # I assume this will have a unix implementation some day    passclass Options(object):    passdef _set_min(x, y):    if x is None:        return y    if y is None:        return x    return min(x, y)_set_max = maxclass RTTMonitorWin32(RTTMonitorBase):    def __init__(self, new_rtt, interval = 0.5, timeout = 6.0):        self.nodes = []        self.timeout = int(1000 * timeout)        self.interval = interval        self.stop_event = threading.Event()        self.abort_traceroute = threading.Event()        self.finished_event = threading.Event()        # the thread is finished because it hasn't started        self.finished_event.set()        RTTMonitorBase.__init__(self, new_rtt)    def set_nodes_restart(self, nodes):        self.nodes = []        for node in nodes:            self.add_node(node)        t = threading.Thread(target=self.run, args=(list(self.nodes),))        t.setDaemon(True)        t.start()    def add_node(self, node):        self.nodes.append(node)    def get_route(self, q, dst):        try:            dst = socket.gethostbyname(dst)            self.traceroute(dst, self.timeout, lambda n : q.put((dst, n)))        except socket.gaierror:            # if hostbyname lookup fails, it's not a node we can use            # maybe this should be a warning or something, but a downed            # internet connection will cause a lot of these            pass    def run(self, nodes):                q = Queue.Queue()        dst = None        # handy for hard-coding common node        #dst = '68.87.195.50'; nodes = [dst,]; common = nodes        if not dst:             threads = []            for i in nodes:                t = daemon_thread(target=self.get_route, args=(q, i, ))                threads.append(t)                t.start()            waiter_done_event = threading.Event()            def waiter(threads, waiter_done_event):                try:                    for thread in threads:                        thread.join()                except Exception, e:                    print "waiter hiccupped", e                waiter_done_event.set()            waiting_thread = daemon_thread(target=waiter,                                           args=(threads, waiter_done_event, ))            waiting_thread.start()            common = []            routes = {}            while not waiter_done_event.isSet():                try:                    msg = q.get(True, 1.0)                except Queue.Empty:                    pass                else:                    dst = msg[0]                    # nodes appear in the queue in                     # increasing order of TTL.                    new_node = msg[1]                      if dst not in routes:                        l = []                        routes[dst] = l                    else:                        l = routes[dst]                    l.append(new_node)                    branch, common = in_common(routes.values())                    if branch:                        break            self.abort_traceroute.set()            waiter_done_event.wait()            self.abort_traceroute.clear()            local_ips = get_host_ips()            new_common = []            for c in common:                if c not in local_ips:                    new_common.append(c)            common = new_common                        if debug:                pprint(common)            if len(common) == 0:                # this should be inspected, it's not a simple debug message                if debug:                    print "No common node", routes                return            del routes            dst = common[-1]        # kill the old thread        self.stop_event.set()        # wait for it to finish        self.finished_event.wait()        # clear to indicate we're running        self.finished_event.clear()        self.stop_event.clear()                if debug:            print "Farthest common hop [%s]" % dst        # range can change if the node in common changes        self.min_rtt = None        self.max_rtt = None        # Ping a representative peer but set the ttl to the length of the        # common path so that the farthest common hop responds with        # ICMP time exceeded.  (Some routers will send time exceeded         # messages, but they won't respond to ICMP pings directly)          representative = nodes[random.randrange(0, len(nodes))]        if debug:             print "pinging representative %s ttl=%d" % (                representative,len(common))        try:                        while not self.stop_event.isSet():                start = bttime()                rtt = self.ping(representative, 5000, ttl=len(common))                self.instantanious_rtt = rtt                self.min_rtt = _set_min(self.min_rtt, rtt)                self.max_rtt = _set_max(self.max_rtt, rtt)                delta = bttime() - start                self.stop_event.wait(self.interval - delta)                if debug: print "RTTMonitor.py: new_rtt %s" % rtt                self.new_rtt(self.instantanious_rtt)        except Exception, e:            import traceback            traceback.print_exc()            print "ABORTING", e                    self.finished_event.set()    def traceroute(self, dst, timeout, report=None):        """If report is None then this returns the route as a list of IP           addresses.  If report is not None then this calls report as each           node is discovered in the path (e.g., if there are 6 hops in the           path then report gets called 6 times)."""        if debug:            print "Tracing route to [%s]" % dst        i = win32icmp.IcmpCreateFile()        o = Options()        route = None        if report == None:            route = []            def add_node(node):                route.append(node)            report = add_node        for ttl in xrange(64):            o.Ttl = ttl            try:                if ttl == 0:                    addr = get_host_ip()                    status = -1                    rtt = 0                else:                    addr, status, rtt = win32icmp.IcmpSendEcho(i, dst, None, o,                                                               timeout)                if debug:                    print "ttl", ttl, "\t", rtt, "ms\t", addr                report(addr)                if status == IP_SUCCESS:                    if debug:                        print "Traceroute complete in", ttl, "hops"                    break            except Exception, e:                report('*')                if debug:                    print "Hop", ttl, "failed:", unicode(e.args[0])            if self.abort_traceroute.isSet():                break        win32icmp.IcmpCloseHandle(i)        if route:            return route    def ping(self, dst, timeout, ttl = None):        """Returns ICMP echo round-trip time to dst or returns None if a           timeout occurs.  timeout is measured in milliseconds.                      The TTL is useful if the caller wants to ping the router that            is a number of hops in the direction of the dst, e.g., when a            router will not respond to pings directly but will generate            ICMP Time Exceeded messages."""        i = win32icmp.IcmpCreateFile()        rtt = None        try:            o = None            if ttl is not None:                o = Options()                o.Ttl = ttl            addr, status, rtt = win32icmp.IcmpSendEcho(i, dst, None, o, timeout)            if debug:                if status == IP_SUCCESS:                    print "Reply from", addr + ":", "time=" + str(rtt)                elif status == IP_TTL_EXPIRED_TRANSIT:                    print "Ping ttl expired %d: from %s time=%s" %(                          status, str(addr), str(rtt))                else:                    print "Ping failed", status        except Exception, e:            if debug:                print "Ping failed:", unicode(e.args[0])        win32icmp.IcmpCloseHandle(i)        return rttif os.name == 'nt':    RTTMonitor = RTTMonitorWin32else:    RTTMonitor = RTTMonitorUnix

⌨️ 快捷键说明

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