Blame | Last modification | View Log | Download
# Written by John Hoffman# see LICENSE.txt for license informationfrom cStringIO import StringIO#from RawServer import RawServertry:Trueexcept:True = 1False = 0from BT1.Encrypter import protocol_namedefault_task_id = []class SingleRawServer:def __init__(self, info_hash, multihandler, doneflag, protocol):self.info_hash = info_hashself.doneflag = doneflagself.protocol = protocolself.multihandler = multihandlerself.rawserver = multihandler.rawserverself.finished = Falseself.running = Falseself.handler = Noneself.taskqueue = []def shutdown(self):if not self.finished:self.multihandler.shutdown_torrent(self.info_hash)def _shutdown(self):if not self.finished:self.finished = Trueself.running = Falseself.rawserver.kill_tasks(self.info_hash)if self.handler:self.handler.close_all()def _external_connection_made(self, c, options, already_read):if self.running:c.set_handler(self.handler)self.handler.externally_handshaked_connection_made(c, options, already_read)### RawServer functions ###def add_task(self, func, delay=0, id = default_task_id):if id is default_task_id:id = self.info_hashif not self.finished:self.rawserver.add_task(func, delay, id)# def bind(self, port, bind = '', reuse = False):# pass # not handled heredef start_connection(self, dns, handler = None):if not handler:handler = self.handlerc = self.rawserver.start_connection(dns, handler)return c# def listen_forever(self, handler):# pass # don't call with thisdef start_listening(self, handler):self.handler = handlerself.running = Truereturn self.shutdown # obviously, doesn't listen foreverdef is_finished(self):return self.finisheddef get_exception_flag(self):return self.rawserver.get_exception_flag()class NewSocketHandler: # hand a new socket off where it belongsdef __init__(self, multihandler, connection):self.multihandler = multihandlerself.connection = connectionconnection.set_handler(self)self.closed = Falseself.buffer = StringIO()self.complete = Falseself.next_len, self.next_func = 1, self.read_header_lenself.multihandler.rawserver.add_task(self._auto_close, 15)def _auto_close(self):if not self.complete:self.close()def close(self):if not self.closed:self.connection.close()self.closed = True# header format:# connection.write(chr(len(protocol_name)) + protocol_name +# (chr(0) * 8) + self.encrypter.download_id + self.encrypter.my_id)# copied from Encrypter and modifieddef read_header_len(self, s):l = ord(s)return l, self.read_headerdef read_header(self, s):self.protocol = sreturn 8, self.read_reserveddef read_reserved(self, s):self.options = sreturn 20, self.read_download_iddef read_download_id(self, s):if self.multihandler.singlerawservers.has_key(s):if self.multihandler.singlerawservers[s].protocol == self.protocol:return Truereturn Nonedef read_dead(self, s):return Nonedef data_came_in(self, garbage, s):while True:if self.closed:returni = self.next_len - self.buffer.tell()if i > len(s):self.buffer.write(s)returnself.buffer.write(s[:i])s = s[i:]m = self.buffer.getvalue()self.buffer.reset()self.buffer.truncate()try:x = self.next_func(m)except:self.next_len, self.next_func = 1, self.read_deadraiseif x is None:self.close()returnif x == True: # ready to processself.multihandler.singlerawservers[m]._external_connection_made(self.connection, self.options, s)self.complete = Truereturnself.next_len, self.next_func = xdef connection_flushed(self, ss):passdef connection_lost(self, ss):self.closed = Trueclass MultiHandler:def __init__(self, rawserver, doneflag):self.rawserver = rawserverself.masterdoneflag = doneflagself.singlerawservers = {}self.connections = {}self.taskqueues = {}def newRawServer(self, info_hash, doneflag, protocol=protocol_name):new = SingleRawServer(info_hash, self, doneflag, protocol)self.singlerawservers[info_hash] = newreturn newdef shutdown_torrent(self, info_hash):self.singlerawservers[info_hash]._shutdown()del self.singlerawservers[info_hash]def listen_forever(self):self.rawserver.listen_forever(self)for srs in self.singlerawservers.values():srs.finished = Truesrs.running = Falsesrs.doneflag.set()### RawServer handler functions #### be wary of name collisionsdef external_connection_made(self, ss):NewSocketHandler(self, ss)