# Written by Jie Yang # see LICENSE.txt for license information import sys from threading import Event,currentThread from sha import sha from time import time from struct import pack from traceback import print_exc from BitTornado.__init__ import createPeerID from BitTornado.bencode import bencode, bdecode from BitTornado.BT1.MessageID import * from Swapper.__init__ import GLOBAL from Swapper.utilities import show_permid2 from permid import ChallengeResponse from OverlayEncrypter import OverlayEncoder from OverlayConnecter import OverlayConnecter protocol_name = 'BitTorrent protocol' #TODO: 'BitTorrent+ protocol' overlay_infohash = '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' from __init__ import CurrentVersion, LowestVersion, SupportedVersions DEBUG = False def show(s): text = [] for i in xrange(len(s)): text.append(ord(s[i])) return text def tobinary(i): return (chr(i >> 24) + chr((i >> 16) & 0xFF) + chr((i >> 8) & 0xFF) + chr(i & 0xFF)) def wrap_message(message_id, payload=None): if payload is not None: ben_payload = bencode(payload) message = tobinary(1+len(ben_payload)) + message_id + ben_payload else: message = tobinary(1) + message_id return message class OverlaySwarm: # Code to make this a singleton __single = None infohash = overlay_infohash def __init__(self): if OverlaySwarm.__single: raise RuntimeError, "OverlaySwarm is singleton" OverlaySwarm.__single = self self.myid = createPeerID() self.myid = self.myid[:16] + pack('> sys.stderr,"overlay: Start overlay swarm connection to", dns self.encoder.start_connection(dns, 0) def sendMessage(self, connection, message): if DEBUG: print >> sys.stderr,"overlay: send message", getMessageName(message[0]), "to", connection.get_dns(), show_permid2(connection.permid) connection.send_message(message) def connectionMade(self, connection): """ phase 1: Connecter.Connection is created but permid has not been verified """ if DEBUG: print >> sys.stderr,"overlay: Bare connection",connection.get_myip(),connection.get_myport(),"to",connection.get_ip(),connection.get_port(),"reported by thread",currentThread().getName() #def c(conn = connection): #""" Start permid exchange and challenge/response validation """ if not connection or self.crs.has_key(connection): return # don't start c/r if connection is invalid or permid was exchanged cr = ChallengeResponse(self.myid, self) self.crs[connection] = cr cr.start_cr(connection) #self.rawserver.add_task(c, 0) def permidSocketMade(self, connection): # Connecter.Connection. """ phase 2: notify that the connection has been made """ if self.crs.has_key(connection): self.crs.pop(connection) ## Arno: I don't see the need for letting the rawserver do it. ## gotMessage isn't scheduled on rawserver. #def notify(connection=connection): self.secure_overlay.connectionMade(connection) #self.rawserver.add_task(notify, 0) def connectionLost(self,connection): if DEBUG: print >> sys.stderr,"overlay: connectionLost: connection is",connection.get_ip(),connection.get_port() if connection.permid is None: # No permid, so it was never reported to the SecureOverlay return #def notify(connection=connection): self.secure_overlay.connectionLost(connection) #self.rawserver.add_task(notify, 0) def got_message(self, conn, message): # Connecter.Connection """ Handle message for overlay swarm and return if the message is valid """ if DEBUG: print >> sys.stderr, "overlay: Got",getMessageName(message[0]),"len",len(message), show_permid2(conn.permid) if not conn: return False t = message[0] if t in PermIDMessages: try: if not self.crs.has_key(conn): # incoming permid exchange self.crs[conn] = ChallengeResponse(self.myid, self) if self.crs[conn].got_message(conn, message) == False: if conn and self.crs.has_key(conn): self.crs.pop(conn) conn.close() except: print_exc() else: if conn.permid: # Do not go ahead without permid self.secure_overlay.gotMessage(conn.permid, message) else: print >> sys.stderr, "overlay: Got a message but not found the permid"