def handshake(self, info_hash, peer_id): self.logger.debug('info_hash was', info_hash) # assert info_hash in self.client.torrents.keys() self.logger.debug('Received handshake resp from peer:', peer_id) # Replace old key in dictionary temp_peer_id = self.peer_id self.peer_id = peer_id self.client.peers[self.peer_id] = self.client.peers[temp_peer_id] del self.client.peers[temp_peer_id] """ try: self.client.torrents[info_hash] except KeyError, e: self.logger.warning( 'Closing conn; client not serving torrent {}.'.format(info_hash)) self.conn.close() """ self.conn.enqueue_msg(WireMessage.construct_msg(2)) # Interested pieces_received = [x[0].received for x in self.client.torrent.pieces] if len(filter(lambda x: x, pieces_received)) > 0: assert len(pieces_received) == self.client.torrent.num_pieces bitfield = Bitfield(pieces_received).byte_array self.conn.enqueue_msg(WireMessage.construct_msg( 5, bitfield)) # Bitfield
def message_handle(cls, buf): message = WireMessage.decode(buf) if cls.debug:print 'Decoded message: ' + str(message) #\n\t if message[0][0] == 'port': cls.s.send(WireMessage.construct_msg(2)) return True if message[0][0] == 'choke': still_choked = True while still_choked: msg = cls.s.recv(5) if struct.unpack('!I', msg[5][0]) == 1: still_choked = False return True if message[0][0] == 'unchoke': print '\'Unchoke\' received. Requesting blocks!\n' cls.s.send(WireMessage.construct_msg(6, 0, 0, 16384)) cls.i = 0 return True if message[0][0] == 'piece': if cls.debug: print 'Block received!!! block size is: ' + str(len(buf)) print 'A piece should be of size: ' + str(cls.length) actual_block = buf[13:] #I am working with a 16384 block size torrent, this won't work otherwise #I would need to set up another check to make sure cls.length was reached cls.i = cls.i + 1 print 'Received ' + str(cls.i) + ' of ' + str(cls.end) + ' pieces' #verify piece_hash = sha1(actual_block).digest() if (piece_hash != cls.pieces.read(20)): print 'Corrupted' else: print 'Verified!' cls.file.write(actual_block) #out now, or at end if cls.i < cls.end - 1: cls.s.send(WireMessage.construct_msg(6, cls.i, 0, 16384)) else: if cls.i == cls.end - 1: cls.s.send(WireMessage.construct_msg(6, cls.i, 0, cls.last)) else: cls.s.close() cls.file.close() print 'Exiting' return False return True if message[0][0] == 'keep_alive': cls.s.send('\x00') return True return True
def recv_msg(self, msg): msg_type, msg_contents = WireMessage.decode(msg) if msg_type == 'handshake': new_conn, addr = self.socket.accept() func = getattr(self.parent, msg_type) assert callable(func) func(new_conn, addr, msg_contents) return True raise Exception('Non-handshake message received.')
def request_blocks(self, pieces, max_requests=1): if self.outstanding_requests > max_requests: return False for piece, peer_id in pieces: blocks = piece.suggest_blocks(max_requests) self.outstanding_requests += len(blocks) for block in blocks: self.logger.debug( '% Requesting pi {}, offset {} and block length {} %'. format(piece.index, block.begin, block.length)) msg = WireMessage.construct_msg(6, piece.index, block.begin, block.length) self.conn.enqueue_msg(msg)
def set_choking(self, am_choking): """Change client's choking status of peer based upon value of am_choking argument. Communicate new choking value to remote peer. """ try: assert am_choking != self.choking # Detect misuse except AssertionError: raise Exception('Error: No change in am_choking') self.am_choking = am_choking msg_id = None if self.am_choking: msg_id = 0 else: msg_id = 1 msg = WireMessage.construct_msg(msg_id) self.conn.enqueue_msg(msg)
def set_interested(self, am_interested): """Change client's interest in peer based upon value of am_interested argument. Communicate new interest to remote peer. """ try: assert am_interested != self.interested # Detect misuse except AssertionError: raise Exception('Error: No change in am_interested') self.am_interested = am_interested msg_id = None if self.am_interested: msg_id = 2 else: msg_id = 3 msg = WireMessage.construct_msg(msg_id) self.conn.enqueue_msg(msg)
def send_cancel(self, index, begin, length): msg = WireMessage.construct_msg(8, index, begin, length) self.conn.enqueue_msg(msg)
def send_have(self, index): """Tell all peers that client has all blocks in piece[index]. """ msg = WireMessage.construct_msg(4, index) self.conn.enqueue_msg(msg) # TODO: all peers
def send_keep_alive(self): msg = WireMessage.construct_msg(-1) self.conn.enqueue_msg(msg)
def request(self, index, begin, length): self.logger.debug('Got request') block_data = self.torrent.get_block(index, begin, length) msg = WireMessage.construct_msg(7, index, begin, block_data) self.conn.enqueue_msg(msg)
""" buf = "" while True: try: msg = self.socket.recv(4096) except Exception, e: self.parent.mark_bad() self.logger.warning('recv() on {}:{}: {}'.format( self.ip, self.port, e)) #self.close() break else: if len(msg) == 0: break buf += msg if len(buf) == 0: return False messages = WireMessage.decode_all(buf) for msg in messages: func = getattr(self.parent, msg[0]) assert callable(func) try: if msg[1]: func(*msg[1]) else: func() except AttributeError, e: # Todo - make sure AttributeError actually relates to func() self.logger.error('Error: Invalid msg type {}'.format(msg[0])) raise Exception(e) def enqueue_msg(self, msg): self._outbound.append(msg)