def listen_to_the_team(self): Peer_DBS.listen_to_the_team(self) self.mcast_socket = socket(socket.AF_INET, socket.SOCK_DGRAM) self.mcast_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) self.mcast_socket.bind(('', 1234)) # Listen any interface, # including 224.0.0.1 self.lg.debug("{}: port 1234 bound to 0.0.0.0".format(self.ext_id))
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 instance(self, args): Peer_DBS.peer_port = int(args.peer_port) Peer_DBS.splitter = (args.splitter_address, int(args.splitter_port)) if args.set_of_rules == "DBS": self.peer = Peer_DBS("P", "Peer_DBS", args.loglevel) else: self.peer = Peer_IMS("P", "Peer_IMS", args.loglevel)
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 run_a_peer(self, splitter_id, type, id, first_monitor=False): total_peers = self.number_of_monitors + self.number_of_peers + self.number_of_malicious chunks_before_leave = np.random.weibull(2) * ( total_peers * (self.number_of_rounds - self.current_round)) if type == "monitor": if first_monitor is True: chunks_before_leave = 99999999 if self.set_of_rules == "dbs": peer = Monitor_DBS(id) elif self.set_of_rules == "cis": self.lg.info("simulator: Monitors are TPs in CIS") peer = Monitor_STRPEDS(id) elif self.set_of_rules == "cis-sss": self.lg.info("simulator: Monitors are TPs in CIS") peer = Monitor_SSS(id) elif type == "malicious": if self.set_of_rules == "cis": peer = Peer_Malicious(id) elif self.set_of_rules == "cis-sss": peer = Peer_Malicious_SSS(id) else: self.lg.info( "simulator: Malicious peers are only compatible with CIS") else: if self.set_of_rules == "dbs": peer = Peer_DBS(id) elif self.set_of_rules == "cis": peer = Peer_STRPEDS(id) elif self.set_of_rules == "cis-sss": peer = Peer_SSS(id) self.lg.info("simulator: {}: alive till consuming {} chunks".format( id, chunks_before_leave)) peer.chunks_before_leave = chunks_before_leave peer.set_splitter(splitter_id) # peer.set_id() peer.connect_to_the_splitter() peer.receive_buffer_size() peer.receive_the_number_of_peers() peer.listen_to_the_team() peer.receive_the_list_of_peers() peer.send_ready_for_receiving_chunks() peer.send_peer_type() #Only for simulation purpose # peer.buffer_data() # peer.start() peer.run() ''' while not peer.ready_to_leave_the_team: if type != "malicious" and peer.number_of_chunks_consumed >= chunks_before_leave and peer.player_alive: self.lg.info("simulator:", id, "reached the number of chunks consumed before leave", peer.number_of_chunks_consumed) peer.player_alive = False time.sleep(1) ''' self.lg.info("simulator: {}: left the team".format(id))
def process_message(self, message, sender): if sender in self.bad_peers: return -1 if self.is_current_message_from_splitter() or self.check_message(message, sender): if self.is_control_message(message) and message == 'B': return self.handle_bad_peers_request() else: return Peer_DBS.process_message(self, message, sender) else: self.process_bad_message(message, sender) return -1
def receive_the_next_message(self): message, sender = Peer_DBS.receive_the_next_message(self) self.current_sender = sender return message, sender
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].decode() 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 _p_("Received [send hello to %s %s]" % (peer_id, peer)) _p_("port_diff = %s" % port_diff) _p_("peer_number = %s" % peer_number) # 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].decode() 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 _p_("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.encode() 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]: _p_("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] # No chunk number, as no chunk was received return -1 _print_(Common.NTS_COLOR + "NTS: Received acknowledge from unknown host %s" % (sender, ) + Color.none) elif len(message) == Common.PEER_ID_LENGTH: peer_id = message.decode() _p_("Received [hello (ID %s)] from %s" % (message, sender)) # Send acknowledge self.team_socket.sendto(message, sender) if sender not in self.peer_list: _p_("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 == b'H': _p_("Received [DBS hello] from %s" % str(sender)) # 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: _p_("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) # No chunk number, as no chunk was received return -1
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 _p_("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() self.create_team_socket() try: self.team_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) except Exception as e: _print_(Common.NTS_COLOR + "NTS:" + Color.none, 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.encode() + b'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.encode() + b'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.encode() + b'Y', self.splitter)) _p_("Incorporation successful")
parser.add_argument("-s", "--set-of-rules", help="set of rules") parser.add_argument("-a", "--splitter-address", help="Splitter address") parser.add_argument("-p", "--splitter-port", type=int, help="Splitter port") parser.add_argument("-l", "--chunks-before-leave", type=int, help="Number of chunk before leave the team") args = parser.parse_args() logging.basicConfig( format='%(asctime)s - %(name)s - %(levelname)s - %(message)s') if args.set_of_rules == "dbs": peer = Peer_DBS("P") # elif self.set_of_rules == "ims": # splitter = Splitter_IMS() peer.chunks_before_leave = args.chunks_before_leave peer.set_splitter((args.splitter_address, args.splitter_port)) peer.connect_to_the_splitter() peer.receive_buffer_size() peer.receive_the_number_of_peers() peer.listen_to_the_team() peer.receive_the_list_of_peers() peer.send_ready_for_receiving_chunks() peer.send_peer_type() # Only for simulation purpose peer.run()
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('--enable_chunk_loss', help='Forces a lost of chunks') parser.add_argument( '--max_chunk_debt', help= 'The maximun number of times that other peer can not send a chunk to this peer. Defaut = {}' .format(Peer_DBS.MAX_CHUNK_DEBT)) parser.add_argument( '--player_port', help='Port to communicate with the player. Default = {}'.format( Peer_IMS.PLAYER_PORT)) parser.add_argument( '--port_step', help= 'Source port step forced when behind a sequentially port allocating NAT (conflicts with --chunk_loss_period). Default = {}' .format(Symsp_Peer.PORT_STEP)) parser.add_argument( '--splitter_addr', 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. Notice that in this case, peers that run outside of the host will not be able to communicate with this peer.' ) parser.add_argument('--malicious', action="store_true", help='Enables the malicious activity for peer.') parser.add_argument( '--persistent', action="store_true", help='Forces the peer to send poisoned chunks to other peers.') parser.add_argument( '--on_off_ratio', help= 'Enables on-off attack and sets ratio for on off (from 1 to 100)') parser.add_argument( '--selective', nargs='+', type=str, help='Enables selective attack for given set of peers.') parser.add_argument( '--bad_mouth', nargs='+', type=str, help='Enables Bad Mouth attack for given set of peers.') parser.add_argument( '--trusted', action="store_true", help='Forces the peer to send hashes of chunks to splitter') parser.add_argument( '--checkall', action="store_true", help= 'Forces the peer to send hashes of every chunks to splitter (works only with trusted option)' ) parser.add_argument('--strpeds', action="store_true", help='Enables STrPe-DS') parser.add_argument( '--strpe_log', help='Logging STrPe & STrPe-DS specific data to file.') parser.add_argument('--show_buffer', action="store_true", help='Shows the status of the buffer of chunks.') try: argcomplete.autocomplete(parser) except Exception: pass #args = parser.parse_known_args()[0] args = parser.parse_args() if args.splitter_addr: Peer_IMS.SPLITTER_ADDR = socket.gethostbyname(args.splitter_addr) _print_('Splitter address =', 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_('Listening port (player) =', Peer_IMS.PLAYER_PORT) if args.max_chunk_debt: Peer_DBS.MAX_CHUNK_DEBT = int(args.max_chunk_debt) _print_('Maximun chunk debt =', Peer_DBS.MAX_CHUNK_DEBT) if args.use_localhost: Peer_IMS.USE_LOCALHOST = True _print_('Using localhost address') 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() _print_("Using IP Multicast address =", peer.mcast_addr) if args.show_buffer: Peer_IMS.SHOW_BUFFER = True # A multicast address is always received, even for DBS peers. if peer.mcast_addr == "0.0.0.0": # {{{ IP unicast mode. peer = Peer_DBS(peer) peer.receive_my_endpoint() peer.receive_the_number_of_peers() _print_("Number of peers in the team (excluding me) =", peer.number_of_peers) _print_("Am I a monitor peer? =", peer.am_i_a_monitor()) peer.listen_to_the_team() peer.receive_the_list_of_peers() _print_("List of peers received") peer.receive_magic_flags() _print_("Magic flags =", peer.magic_flags) # After receiving the list of peers, the peer can check # whether is a monitor peer or not (only the first # arriving peers are monitors) if peer.am_i_a_monitor(): from core.monitor_dbs import Monitor_DBS peer = Monitor_DBS(peer) _print_("Monitor DBS") # The peer is a monitor. Now it's time to know the sets of rules that control this team. if (peer.magic_flags & common.LRS): from core.monitor_lrs import Monitor_LRS peer = Monitor_LSR(peer) _print_("Monitor LRS") if (peer.magic_flags & common.NTS): from core.monitor_nts import Monitor_NTS peer = Monitor_NTS(peer) _print_("Monitor NTS") else: peer = Peer_DBS(peer) _print_("Peer DBS") # The peer is a normal peer. Let's know the sets of rules that control this team. if (peer.magic_flags & common.ACS): peer = Peer_ACR(peer) _print_("Peer ACS") if (peer.magic_flags & common.LRS): peer = Peer_LSR(peer) _print_("Peer LRS") if (peer.magic_flags & common.NTS): from peer_nts import Peer_NTS peer = Peeer_NTS(peer) _print_("Peer NTS") if args.enable_chunk_loss: 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: from lossy_peer import Lossy_Peer peer = Lossy_Peer(peer) if args.port_step: Symsp_Peer.PORT_STEP = int(args.port_step) print('PORT_STEP =', Symsp_Peer.PORT_STEP) if int(args.port_step) != 0: peer = Symsp_Peer(peer) if args.strpeds: from core.peer_strpeds import Peer_StrpeDs peer = Peer_StrpeDs(peer) peer.receive_dsa_key() if args.malicious and not args.strpeds: # workaround for malicous strpeds peer from core.malicious_peer import MaliciousPeer peer = MaliciousPeer(peer) if args.persistent: peer.setPersistentAttack(True) if args.on_off_ratio: peer.setOnOffAttack(True, int(args.on_off_ratio)) if args.selective: peer.setSelectiveAttack(True, args.selective) if args.malicious and args.strpeds: from core.peer_strpeds_malicious import Peer_StrpeDsMalicious peer = Peer_StrpeDsMalicious(peer) if args.persistent: peer.setPersistentAttack(True) if args.on_off_ratio: peer.setOnOffAttack(True, int(args.on_off_ratio)) if args.selective: peer.setSelectiveAttack(True, args.selective) if args.bad_mouth: peer.setBadMouthAttack(True, args.bad_mouth) if args.trusted: from core.trusted_peer import TrustedPeer peer = TrustedPeer(peer) if args.checkall: peer.setCheckAll(True) if args.strpe_log != None: peer.LOGGING = True peer.LOG_FILE = open(args.strpe_log, 'w', 0) # }}} else: # {{{ IP multicast mode 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 try: if common.CONSOLE_MODE == False: from gi.repository import GObject try: from adapter import speed_adapter except ImportError as msg: pass GObject.idle_add(speed_adapter.update_widget, str(kbps_recvfrom) + ' kbps', str(kbps_sendto) + ' kbps', str(len(peer.peer_list) + 1)) except Exception as msg: pass 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() try: if common.CONSOLE_MODE == False: GObject.idle_add(speed_adapter.update_widget, str(0) + ' kbps', str(0) + ' kbps', str(0)) except Exception as msg: pass
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].decode() 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 _p_("Received [send hello to %s %s]" % (peer_id, peer)) _p_("port_diff = %s" % port_diff) _p_("peer_number = %s" % peer_number) # 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].decode() 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 _p_("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.encode() 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]: _p_("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] # No chunk number, as no chunk was received return -1 _print_(Common.NTS_COLOR + "NTS: Received acknowledge from unknown host %s" % (sender,) + Color.none) elif len(message) == Common.PEER_ID_LENGTH: peer_id = message.decode() _p_("Received [hello (ID %s)] from %s" % (message, sender)) # Send acknowledge self.team_socket.sendto(message, sender) if sender not in self.peer_list: _p_("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 == b'H': _p_("Received [DBS hello] from %s" % str(sender)) # 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: _p_("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) # No chunk number, as no chunk was received return -1
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 _p_("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() self.create_team_socket() try: self.team_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) except Exception as e: _print_(Common.NTS_COLOR + "NTS:" + Color.none, 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.encode() + b'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.encode() + b'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.encode() + b'Y', self.splitter)) _p_("Incorporation successful")