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)
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)
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
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()
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)
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))
def receive_the_next_message(self): message, sender = Peer_DBS.receive_the_next_message(self) self.current_sender = sender return message, sender