Exemple #1
0
class Splitter(object):

    def __init__(self, packet_size):
        self.packet_size = packet_size
        self.on_new_packet = Event()
        self.on_stream_end = Event()

        self._buffer = bytes()
        self._packets = deque()
        self._current_sequence = 0

    def push_stream(self, data):
        self._buffer = self._buffer + data

        while len(self._buffer) >= self.packet_size:
            packet_data = self._buffer[:self.packet_size]
            self._buffer = self._buffer[self.packet_size:]
            self._create_packet(packet_data)

    def end_stream(self):
        self._create_packet(self._buffer)
        self.on_stream_end.call(self)

    def pop_packet(self):
        return self._packets.popleft()

    def _create_packet(self, packet_data):
        packet = DataPacketMessage.create(self._current_sequence, packet_data)
        self._packets.append(packet)
        self._current_sequence += 1
        self.on_new_packet.call(self)
Exemple #2
0
    def __init__(self, url):
        HTTPClientFactory.__init__(self, url)
        self.deferred = defer.Deferred()
        self.waiting = 1

        self.on_page_part = Event()
        self.on_page_end = Event()
Exemple #3
0
    def __init__(self, packet_size):
        self.packet_size = packet_size
        self.on_new_packet = Event()
        self.on_stream_end = Event()

        self._buffer = bytes()
        self._packets = deque()
        self._current_sequence = 0
Exemple #4
0
    def __init__(self):

        self.on_data_joined = Event()
        self.on_end_join = Event()

        self._buffer = bytes()
        self._current_sequence = 0
        self._packets = {}
        self.sequences = set()
Exemple #5
0
class StreamClient(object):

    def __init__(self):
        self.on_stream_received = Event()
        self.on_stream_end = Event()

    def _data_received(self, data):
        self.on_stream_received.call(data)

    def _connection_lost(self):
        self.on_stream_end.call()
class ConnectionList(object):

    def __init__(self, protocol_class):
        self.on_changed = Event()
        self._connections = {}
        self._protocol_class = protocol_class

    def add(self, connection):
        """Adds a new item to the list of connections."""

        assert isinstance(connection, self._protocol_class)
        assert isinstance(connection.partner_id, str)

        if connection.partner_id in self._connections:
            logging.error('Adding existent connection')
            connection.drop()
            return

        self._connections[connection.partner_id] = connection
        self.on_changed.call(self)

    def remove(self, connection):
        """Removes an item from the list of connections."""

        assert isinstance(connection, self._protocol_class)
        assert isinstance(connection.partner_id, str)

        if connection.partner_id not in self._connections:
            logging.error('Removing nonexistent connection')
            return

        del self._connections[connection.partner_id]
        self.on_changed.call(self)

    def __iter__(self):
        return self._connections.itervalues()

    def __contains__(self, partner_id):
        return partner_id in self._connections

    def __getitem__(self, partner_id):
        return self._connections[partner_id]

    @property
    def ids(self):
        return self._connections.keys()
Exemple #7
0
class Joiner(object):

    def __init__(self):

        self.on_data_joined = Event()
        self.on_end_join = Event()

        self._buffer = bytes()
        self._current_sequence = 0
        self._packets = {}
        self.sequences = set()

    def push_packet(self, packet):
        self._packets[packet.sequence] = packet.data
        self._join_buffer()
        self._update_sequences()

    def end_join(self):
        self.on_end_join.call(self)

    def pop_stream(self):
        buffer = self._buffer
        self._buffer = bytes()
        return buffer

    def _update_sequences(self):
        self.sequences = set(self._packets.keys())

    def _join_buffer(self):
        sequences = takewhile(lambda seq: seq in self._packets,
                              count(self._current_sequence))

        sequences = list(sequences)

        if len(sequences) > 0:
            self._buffer += ''.join(self._packets[seq] for seq in sequences)

            for sequence in sequences:
                del self._packets[sequence]

            self._current_sequence = sequences[-1] + 1

            self.on_data_joined.call(self)
Exemple #8
0
    def __init__(self, tracker_url, peer):
        """
        Initializes the manager.
        """

        self._announce_repeater = TwistedRepeater(self.announce,
                                                  self.DEFAULT_ANNOUNCE)
        self._utility_repeater = TwistedRepeater(self.report_utility,
                                                 self.DEFAULT_ANNOUNCE)

        self.tracker_url = tracker_url
        self.peer = peer
        self.utility_by_peer = {}

        self.peer_list = []
        self.status = TrackerStatus(TrackerStatus.STANDBY, 'Ready to connect')

        self.on_updated = Event()
        self.on_status_changed = Event()
Exemple #9
0
class _HTTPStreamDownloader(HTTPClientFactory):
    protocol = HTTPPageDownloader

    def __init__(self, url):
        HTTPClientFactory.__init__(self, url)
        self.deferred = defer.Deferred()
        self.waiting = 1

        self.on_page_part = Event()
        self.on_page_end = Event()

    def pageStart(self, partialContent):
        self.waiting = 0

    def pagePart(self, data):
        self.on_page_part.call(data)

    def pageEnd(self):
        self.on_page_end.call()
        self.deferred.callback(None)
    def __init__(self, peer_service):
        """
        Creates a new ConnectionManager object.
        """
        self.on_update = Event()

        self._peer_service = peer_service

        self._connection_attempts = set()

        self.incoming_connections = ConnectionList(IncomingProtocol)
        self.incoming_connections.on_changed.add_handler(self._updated)

        self.outgoing_connections = ConnectionList(OutgoingProtocol)
        self.outgoing_connections.on_changed.add_handler(self._updated)
class ConnectionManager(object):
    """
    Maintains a collection of incoming and outgoing connections to a peer.
    """

    def __init__(self, peer_service):
        """
        Creates a new ConnectionManager object.
        """
        self.on_update = Event()

        self._peer_service = peer_service

        self._connection_attempts = set()

        self.incoming_connections = ConnectionList(IncomingProtocol)
        self.incoming_connections.on_changed.add_handler(self._updated)

        self.outgoing_connections = ConnectionList(OutgoingProtocol)
        self.outgoing_connections.on_changed.add_handler(self._updated)

    @property
    def all_connections(self):
        """Returns an iterator of all current connections"""

        return itertools.chain(self.incoming_connections,
                               self.outgoing_connections)

    def connection_allowed(self, peer_id):
        """
        Returns true if a connection with a peer is allowed.

        :param peer_id: The ID of the peer to check.
        """

        if peer_id in self._connection_attempts:
            logging.info('Connection attempt not allowed with ' + peer_id)
            logging.info(str(self._connection_attempts))

        return (peer_id not in self._connections_ids and
                peer_id not in self._connection_attempts)

    def listen(self, port):
        """Starts listening on the given port."""

        factory = self._create_server_factory()
        reactor.listenTCP(port, factory)

    def get_connection(self, partner_id):
        if partner_id in self.incoming_connections:
            return self.incoming_connections[partner_id]

        if partner_id in self.outgoing_connections:
            return self.outgoing_connections[partner_id]

        return None

    def connect_to_peer(self, peer):
        """Establish a new connection with a given peer."""

        logging.debug('Connecting to peer:' + peer.id)
        self._connection_attempts.add(peer.id)
        factory = self._create_client_factory(peer.id)
        reactor.connectTCP(peer.ip, peer.port, factory)

    def connect_to_peers(self, peers):
        """
        Connect to a list of peers
        """

        for peer in peers:
            if peer.id in self._connections_ids:
                continue
            self.connect_to_peer(peer)

    def heartbeat(self):
        """
        Sends heartbeats
        """

        for connection in self.all_connections:
            connection.send_heartbeat()

    def check_heartbeats(self):
        """
        Check connections for last heartbeat
        """

        #FIXME: Put this in a configuration file
        PEER_TIMEOUT  = 30

        for connection in self.all_connections:
            timeout = time.time() - connection.last_heartbeat
            cid = connection.partner_id
            logging.info('Checking peer timeout {0}'.format(cid))
            if timeout > PEER_TIMEOUT:
                logging.info('Peer Connection Timeout {0}'.format(cid))
                connection.drop()


    @property
    def _connections_ids(self):

        return set(self.incoming_connections.ids +
                   self.outgoing_connections.ids)

    def _create_server_factory(self):

        factory = ServerFactory()
        factory.protocol = IncomingProtocol
        factory.add_connection = self.incoming_connections.add
        factory.remove_connection = self.incoming_connections.remove
        self._init_factory(factory)
        return factory

    def _create_client_factory(self, target_id):

        factory = ClientFactory()
        factory.protocol = OutgoingProtocol
        factory.target_id = target_id
        factory.add_connection = self.outgoing_connections.add
        factory.remove_connection = self.outgoing_connections.remove
        self._init_factory(factory)
        return factory

    def _init_factory(self, factory):
        factory.peer_service = self._peer_service
        factory.connection_allowed = self.connection_allowed
        factory.end_connection_attempt = self._end_connection_attempt

    def _updated(self, connection):
        self.on_update.call(self)

    def _end_connection_attempt(self, peer_id):
        if peer_id in self._connection_attempts:
            self._connection_attempts.remove(peer_id)
 def __init__(self, protocol_class):
     self.on_changed = Event()
     self._connections = {}
     self._protocol_class = protocol_class
Exemple #13
0
class TrackerManager(object):
    """
    Manages the connection with the tracker
    """

    DEFAULT_ANNOUNCE = 30

    #TODO: Eliminate tracker_url parameter
    def __init__(self, tracker_url, peer):
        """
        Initializes the manager.
        """

        self._announce_repeater = TwistedRepeater(self.announce,
                                                  self.DEFAULT_ANNOUNCE)
        self._utility_repeater = TwistedRepeater(self.report_utility,
                                                 self.DEFAULT_ANNOUNCE)

        self.tracker_url = tracker_url
        self.peer = peer
        self.utility_by_peer = {}

        self.peer_list = []
        self.status = TrackerStatus(TrackerStatus.STANDBY, 'Ready to connect')

        self.on_updated = Event()
        self.on_status_changed = Event()

    def connect_to_tracker(self):
        self._announce_repeater.start_now()
        self._utility_repeater.start_now()

    def announce(self):
        """Starts connection with the tracker."""

        logging.debug('Announcing to tracker')
        deferred = client.getPage(self._create_announce_url())
        deferred.addCallback(self._on_announce_response)
        deferred.addErrback(self._on_tracker_error)

    def report_utility(self):
        if len(self.utility_by_peer) == 0:
            return
        deferred = client.getPage(self._create_utility_url())
        deferred.addCallback(self._on_utility_response)
        deferred.addErrback(self._on_tracker_error)

    def _create_announce_url(self):
        """Creates a request URL for the tracker with the GET query."""

        query = dict(peer_id = self.peer.id,
                     port = self.peer.port)

        if self.peer.ip is not None:
            query.update(ip = self.peer.ip)

        parts = list(urlparse.urlsplit(self.tracker_url))
        parts[2] += '/announce' # path
        parts[3] = urllib.urlencode(query) # query

        return urlparse.urlunsplit(parts)

    def _create_utility_url(self):
        parts = list(urlparse.urlsplit(self.tracker_url))
        parts[2] += '/utility'
        parts[3] = urllib.urlencode(self.utility_by_peer) # query.

        return urlparse.urlunsplit(parts)

    def _on_tracker_error(self, error):
        logging.error('Unable to contact the tracker: ' + str(error.value))
        self._change_status(TrackerStatus.ERROR,
                            'Unable to contact the tracker')

    def _on_announce_response(self, content):
        try:
            logging.debug('Received tracker announce response')
            response = json.loads(content)

            if 'failure_reason' in response:
                self._on_announce_failure(response['failure_reason'])
                return

            if 'request_interval' in response:
                self._announce_repeater.seconds = response['request_interval']

            if 'peers' in response:
                self._update_peers(response['peers'])

            self._change_status(TrackerStatus.OK, 'OK')

        except Exception as e:
            self._on_announce_failure(str(e))

    def _on_announce_failure(self, error):
        logging.error('Tracker announce failure: ' + error)
        self._change_status(TrackerStatus.ERROR, error)

    def _on_utility_response(self, content):
        logging.debug('Received tracker utility response')
        response = json.loads(content)

        if 'failure_reason' in response:
            self._on_utility_failure(response['failure_reason'])
            return

    def _on_utility_failure(self, error):
        logging.error('Tracker utility failure: ' + error)
        self._change_status(TrackerStatus.ERROR, error)

    def _update_peers(self, peer_list):
        try:
            self.peer_list = []
            for peer_dict in peer_list:
                id = peer_dict['id']
                ip = peer_dict['ip']
                port = peer_dict['port']
                uf = peer_dict['utility_factor']
                self.peer_list.append(Peer(id, ip, port, uf))
            self.on_updated.call(self, self.peer_list)
        except Exception as e:
            raise TrackerManagerError('Unable to convert peer list: ' + str(e))

    def _change_status(self, status, message):
        if self.status.status == status and self.status.message == message:
            return
        self.status = TrackerStatus(status, message)
        self.on_status_changed.call(self, self.status)
Exemple #14
0
 def __init__(self):
     self.on_stream_received = Event()
     self.on_stream_end = Event()