Пример #1
0
    def disconnect_from_the_splitter(self):
        # {{{

        # Close the TCP socket
        Peer_DBS.disconnect_from_the_splitter(self)

        # Use UDP to create a working NAT entry
        self.say_hello(self.splitter)
        self.say_hello(self.splitter)
        self.say_hello(self.splitter)
Пример #2
0
    def disconnect_from_the_splitter(self):
        # {{{

        # Close the TCP socket
        Peer_DBS.disconnect_from_the_splitter(self)

        # Use UDP to create a working NAT entry
        self.say_hello(self.splitter)
        self.say_hello(self.splitter)
        self.say_hello(self.splitter)
Пример #3
0
    def disconnect_from_the_splitter(self):
        # {{{

        self.start_send_hello_thread()

        # Receive the generated ID for this peer from splitter
        self.receive_id()

        # There are currently no other peers in the team
        self.initial_peer_list = []

        # Close the TCP socket
        Peer_DBS.disconnect_from_the_splitter(self)
Пример #4
0
    def process_next_message(self):
        chunk_number = Peer_DBS.process_next_message(self)
        if chunk_number > 0 and self.current_sender != self.splitter:
            if self.counter == 0:
                self.send_chunk_hash(chunk_number)
                self.counter = self.calculate_next_sampled()
            else:
                self.counter -= 1

        return chunk_number
Пример #5
0
    def __init__(self):

        try:
            colorama.init()
        except Exception:
            pass

        _print_("Running in", end=' ')
        if __debug__:
            print("debug mode")
        else:
            print("release mode")

        # {{{ Args handling and object instantiation
        parser = argparse.ArgumentParser(
            description='This is the peer node of a P2PSP team.')

        parser.add_argument(
            '--chunk_loss_period',
            help=
            '0 -> no chunk loss, 1 -> lost all chunks, 2, lost half of the chunks ... Default = {}'
            .format(Lossy_Peer.CHUNK_LOSS_PERIOD))

        parser.add_argument(
            '--max_chunk_loss',
            help=
            'The maximun number of times that other peer can not send a chunk to this peer. Defaut = {}'
            .format(Peer_DBS.MAX_CHUNK_LOSS))

        parser.add_argument(
            '--player_port',
            help='Port to communicate with the player. Default = {}'.format(
                Peer_IMS.PLAYER_PORT))

        parser.add_argument(
            '--splitter_host',
            help='IP address or hostname of the splitter. Default = {}.'.
            format(Peer_IMS.SPLITTER_ADDR))

        parser.add_argument(
            '--splitter_port',
            help='Listening port of the splitter. Default = {}.'.format(
                Peer_IMS.SPLITTER_PORT))

        parser.add_argument(
            '--port',
            help=
            'Port to communicate with the peers. Default {} (the OS will chose it).'
            .format(Peer_IMS.PORT))

        parser.add_argument(
            '--use_localhost',
            action="store_true",
            help=
            'Forces the peer to use localhost instead of the IP of the adapter to connect to the splitter.'
        )

        #args = parser.parse_known_args()[0]
        args = parser.parse_args()

        if args.splitter_host:
            Peer_IMS.SPLITTER_ADDR = socket.gethostbyname(args.splitter_host)
            print('SPLITTER_ADDR =', Peer_IMS.SPLITTER_ADDR)

        if args.splitter_port:
            Peer_IMS.SPLITTER_PORT = int(args.splitter_port)
            print('SPLITTER_PORT =', Peer_IMS.SPLITTER_PORT)

        if args.port:
            Peer_IMS.PORT = int(args.port)
            print('(Peer) PORT =', Peer_IMS.PORT)

        if args.player_port:
            Peer_IMS.PLAYER_PORT = int(args.player_port)
            print('PLAYER_PORT =', Peer_IMS.PLAYER_PORT)

        if args.max_chunk_loss:
            Peer_DBS.MAX_CHUNK_LOSS = int(args.max_chunk_loss)
            print('MAX_CHUNK_LOSS =', Peer_DBS.MAX_CHUNK_LOSS)

        if args.use_localhost:
            Peer_IMS.USE_LOCALHOST = True
            print('Using localhost!')

        peer = Peer_IMS()
        peer.wait_for_the_player()
        peer.connect_to_the_splitter()
        peer.receive_the_mcast_endpoint()
        peer.receive_the_header_size()
        peer.receive_the_chunk_size()
        peer.receive_the_header()
        peer.receive_the_buffer_size()
        #peer.receive_configuration()
        _print_("IP Multicast address =", peer.mcast_addr)

        # A multicast address is always received, even for DBS peers.
        if peer.mcast_addr == "0.0.0.0":
            # {{{ This is an "unicast" peer.

            peer = Peer_DBS(peer)
            peer.receive_my_endpoint()
            peer.receive_the_number_of_peers()
            print("===============> number_of_peers =", peer.number_of_peers)
            print("===============> is_a_monitor =", peer.am_i_a_monitor())
            peer.listen_to_the_team()
            peer.receive_the_list_of_peers()

            if peer.am_i_a_monitor():
                #peer = Monitor_DBS(peer)
                #peer = Monitor_FNS(peer)
                peer = Monitor_LRS(peer)
            else:
                peer = Peer_FNS(peer)
                if args.chunk_loss_period:
                    Lossy_Peer.CHUNK_LOSS_PERIOD = int(args.chunk_loss_period)
                    print('CHUNK_LOSS_PERIOD =', Lossy_Peer.CHUNK_LOSS_PERIOD)
                    if int(args.chunk_loss_period) != 0:
                        peer = Lossy_Peer(peer)

            #peer.receive_my_endpoint()

            # }}}
        else:
            peer.listen_to_the_team()

        # }}}

        # {{{ Run!
        peer.disconnect_from_the_splitter()
        peer.buffer_data()
        peer.start()

        print("+-----------------------------------------------------+")
        print("| Received = Received kbps, including retransmissions |")
        print("|     Sent = Sent kbps                                |")
        print("|       (Expected values are between parenthesis)     |")
        print("------------------------------------------------------+")
        print()
        print(
            "    Time |     Received (Expected) |          Sent (Expected) | Team description"
        )
        print(
            "---------+-------------------------+--------------------------+-----------------..."
        )

        last_chunk_number = peer.played_chunk
        if hasattr(peer, 'sendto_counter'):
            last_sendto_counter = 0
        else:
            peer.sendto_counter = 0
            last_sendto_counter = 0
        if not hasattr(peer, 'peer_list'):
            peer.peer_list = []
        last_recvfrom_counter = peer.recvfrom_counter
        while peer.player_alive:
            time.sleep(1)
            kbps_expected_recv = ((peer.played_chunk - last_chunk_number) *
                                  peer.chunk_size * 8) / 1000
            last_chunk_number = peer.played_chunk
            kbps_recvfrom = ((peer.recvfrom_counter - last_recvfrom_counter) *
                             peer.chunk_size * 8) / 1000
            last_recvfrom_counter = peer.recvfrom_counter
            team_ratio = len(peer.peer_list) / (len(peer.peer_list) + 1.0)
            kbps_expected_sent = int(kbps_expected_recv * team_ratio)
            kbps_sendto = ((peer.sendto_counter - last_sendto_counter) *
                           peer.chunk_size * 8) / 1000
            last_sendto_counter = peer.sendto_counter
            if kbps_recvfrom > 0 and kbps_expected_recv > 0:
                nice = 100.0 / float(
                    (float(kbps_expected_recv) / kbps_recvfrom) *
                    (len(peer.peer_list) + 1))
            else:
                nice = 0.0
            _print_('|', end=Color.none)
            if kbps_expected_recv < kbps_recvfrom:
                sys.stdout.write(Color.red)
            elif kbps_expected_recv > kbps_recvfrom:
                sys.stdout.write(Color.green)
            print(repr(kbps_expected_recv).rjust(12), end=Color.none)
            print(('(' + repr(kbps_recvfrom) + ')').rjust(12), end=' | ')
            #print(("{:.1f}".format(nice)).rjust(6), end=' | ')
            #sys.stdout.write(Color.none)
            if kbps_expected_sent > kbps_sendto:
                sys.stdout.write(Color.red)
            elif kbps_expected_sent < kbps_sendto:
                sys.stdout.write(Color.green)
            print(repr(kbps_sendto).rjust(12), end=Color.none)
            print(('(' + repr(kbps_expected_sent) + ')').rjust(12), end=' | ')
            #sys.stdout.write(Color.none)
            #print(repr(nice).ljust(1)[:6], end=' ')
            print(len(peer.peer_list), end=' ')
            counter = 0
            for p in peer.peer_list:
                if (counter < 5):
                    print(p, end=' ')
                    counter += 1
                else:
                    break
            print()
Пример #6
0
    def process_message(self, message, sender):
        # {{{ Handle NTS messages; pass other messages to base class

        if sender == self.splitter and len(message) == common.PEER_ID_LENGTH + struct.calcsize("4sHHH"):
            # [say hello to (X)] received from splitter
            peer_id = message[: common.PEER_ID_LENGTH]
            IP_addr, source_port_to_splitter, port_diff, peer_number = struct.unpack(
                "4sHHH", message[common.PEER_ID_LENGTH :]
            )
            IP_addr = socket.inet_ntoa(IP_addr)
            source_port_to_splitter = socket.ntohs(source_port_to_splitter)
            port_diff = socket.ntohs(port_diff)
            peer_number = socket.ntohs(peer_number)

            peer = (IP_addr, source_port_to_splitter)  # Endpoint to splitter
            if __debug__:
                print("NTS: Received [send hello to %s %s]" % (peer_id, peer))
            # Here the port prediction happens:
            additional_ports = self.get_probable_source_ports(source_port_to_splitter, port_diff, peer_number)
            self.say_hello(peer, additional_ports)
            # Directly start packet sending
            self.hello_messages_event.set()
        elif sender == self.splitter and len(message) == common.PEER_ID_LENGTH + struct.calcsize("4sHHHH"):
            # [say hello to (X)] received from splitter
            peer_id = message[: common.PEER_ID_LENGTH]
            IP_addr, source_port_to_splitter, port_diff, peer_number, extra_splitter_port = struct.unpack(
                "4sHHHH", message[common.PEER_ID_LENGTH :]
            )  # Ojo, !H ????
            IP_addr = socket.inet_ntoa(IP_addr)
            source_port_to_splitter = socket.ntohs(source_port_to_splitter)
            port_diff = socket.ntohs(port_diff)
            peer_number = socket.ntohs(peer_number)
            extra_splitter_port = socket.ntohs(extra_splitter_port)

            peer = (IP_addr, source_port_to_splitter)  # Endpoint to splitter
            if __debug__:
                print("NTS: Received [send hello to %s %s]" % (peer_id, peer))
            # Here the port prediction happens:
            additional_ports = self.get_probable_source_ports(source_port_to_splitter, port_diff, peer_number)
            self.say_hello(peer, additional_ports)
            # Send to extra splitter port to determine currently allocated
            # source port
            self.say_hello((self.splitter[0], extra_splitter_port))
            # Directly start packet sending
            self.hello_messages_event.set()
        elif (
            message == self.peer_id
            or (sender == self.splitter and len(message) == common.PEER_ID_LENGTH + struct.calcsize("H"))
            or (sender == self.splitter and len(message) == common.PEER_ID_LENGTH + 1 + struct.calcsize("H"))
            or len(message) == common.PEER_ID_LENGTH + 1
        ):  # All sent message sizes
            # Acknowledge received; stop sending the message
            with self.hello_messages_lock:
                for hello_data in self.hello_messages:
                    if (
                        message == hello_data[0]
                        and sender[0] == hello_data[1][0]
                        and sender[1] in self.hello_messages_ports[hello_data]
                    ):
                        if __debug__:
                            print("NTS: Received acknowledge from %s" % (sender,))
                        self.hello_messages.remove(hello_data)
                        del self.hello_messages_times[hello_data]
                        del self.hello_messages_ports[hello_data]
                        return
            print("NTS: Received acknowledge from unknown host %s" % (sender,))
        elif len(message) == common.PEER_ID_LENGTH:
            peer_id = message
            if __debug__:
                print("NTS: Received hello (ID %s) from %s" % (message, sender))
            # Send acknowledge
            self.team_socket.sendto(message, sender)

            if sender not in self.peer_list:
                print("NTS: Appending peer %s %s to list" % (peer_id, sender))
                self.peer_list.append(sender)
                self.debt[sender] = 0
                # Send source port information to splitter
                message += struct.pack("H", socket.htons(sender[1]))
                message_data = (message, self.splitter)
                self.send_message(message_data)

                if peer_id in self.initial_peer_list:
                    self.initial_peer_list.remove(peer_id)
        elif message == "H":
            # Ignore hello messages that are sent by Peer_DBS instances in
            # receive_the_list_of_peers() before a Peer_NTS instance is created
            pass
        elif sender != self.splitter and sender not in self.peer_list:
            if __debug__:
                print("NTS: Ignoring message of length %d from unknown %s" % (len(message), sender))
        elif len(self.initial_peer_list) == 0:
            # Start receiving chunks when fully incorporated
            return Peer_DBS.process_message(self, message, sender)
Пример #7
0
    def try_to_disconnect_from_the_splitter(self):
        # {{{

        self.start_send_hello_thread()

        # Receive the generated ID for this peer from splitter
        self.receive_id()

        # Note: This peer is *not* the monitor peer.

        # Send UDP packets to splitter and monitor peers
        # to create working NAT entries and to determine the
        # source port allocation type of the NAT of this peer
        for peer in self.peer_list[: self.number_of_monitors]:
            self.say_hello(peer)
        self.say_hello(self.splitter)
        # Directly start packet sending
        self.hello_messages_event.set()

        # A list of peer_ids that contains the peers that were in the team when
        # starting incorporation and that are not connected yet
        self.initial_peer_list = []
        # Receive the list of peers, except the monitor peer, with their peer
        # IDs and send hello messages
        self.receive_the_list_of_peers_2()

        # Wait for getting connected to all currently known peers
        incorporation_time = time.time()
        # A timeout < MAX_PEER_ARRIVING_TIME has to be set for self.team_socket
        # The monitor is not in initial_peer_list
        while len(self.initial_peer_list) > 0:
            if time.time() - incorporation_time > common.MAX_PEER_ARRIVING_TIME:
                # Retry incorporation into the team
                print(
                    "NTS: Retrying incorporation with %d peers left: %s"
                    % (len(self.initial_peer_list), self.initial_peer_list)
                )
                incorporation_time = time.time()
                # Cleaning hello messages
                with self.hello_messages_lock:
                    self.hello_messages_times.clear()
                    self.hello_messages_ports.clear()
                    del self.hello_messages[:]
                # Resetting peer lists
                del self.initial_peer_list[:]
                del self.peer_list[self.number_of_monitors :]  # Leave monitors
                # Recreate the socket
                # Similar to Peer_DBS.listen_to_the_team, binds to a random port
                self.team_socket.close()
                if Symsp_Peer.PORT_STEP:
                    self.team_socket = symsp_socket(Symsp_Peer.PORT_STEP, socket.AF_INET, socket.SOCK_DGRAM)
                else:
                    self.team_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
                try:
                    self.team_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
                except Exception as e:
                    print("NTS:", e)
                self.team_socket.bind(("", 0))
                self.team_socket.settimeout(1)
                # Say hello to splitter again, to retry incorporation
                # 'N' for 'not incorporated'
                self.send_message((self.peer_id + "N", self.splitter))
                # Say hello to monitors again, to keep the NAT entry alive
                for peer in self.peer_list[: self.number_of_monitors]:
                    self.send_message((self.peer_id + "N", peer))
                # Receive all peer endpoints and send hello messages
                self.receive_the_list_of_peers_2()

            # Process messages to establish connections to peers
            try:
                message, sender = self.team_socket.recvfrom(struct.calcsize(self.message_format))
                self.process_message(message, sender)
            except socket.timeout:
                pass

        # Close the TCP socket
        Peer_DBS.disconnect_from_the_splitter(self)
        # The peer is now successfully incorporated; inform the splitter
        self.send_message((self.peer_id + "Y", self.splitter))
Пример #8
0
 def receive_the_next_message(self):
     message, sender = Peer_DBS.receive_the_next_message(self)
     self.current_sender = sender
     return message, sender