Exemplo n.º 1
0
class PTCClientProtocol(object):
	
	def __init__(self, address, port):
		self.retransmission_queue = RetransmissionQueue(self)
		self.retransmission_attempts = dict()
		self.outgoing_buffer = DataBuffer()
		self.state = CLOSED
		self.control_block = ClientControlBlock(address, port)
		self.socket = Soquete(address, port)
		self.packet_builder = PacketBuilder(self)
	
	def is_connected(self):
		return self.state == ESTABLISHED
		
	def build_packet(self, payload=None, flags=None):
		seq = self.control_block.get_send_seq()
		if payload is not None:
			self.control_block.increment_send_seq()
		packet = self.packet_builder.build(payload=payload, flags=flags, seq=seq)
		return packet
		
	def send_packet(self, packet):
		self.socket.send(packet)
		
	def send_and_queue_packet(self, packet):
		self.send_packet(packet)
		self.retransmission_queue.put(packet)
		
	def send(self, data):
		if not self.is_connected():
			raise Exception('cannot send data: connection not established')
		self.worker.send(data)

	def connect_to(self, address, port):
		self.worker = ClientProtocolWorker.spawn_for(self)
		self.worker.start()
		self.connected_event = threading.Event()
		self.control_block.set_destination_address(address)		# No tendria que ser el protocol block ?
		self.control_block.set_destination_port(port)		# No tendria que ser el protocol block ?
		
		syn_packet = self.build_packet(flags=[SYNFlag])
		self.send_and_queue_packet(syn_packet)
		self.state = SYN_SENT
		
		self.connected_event.wait()
	
	def handle_timeout(self):
		###################
		##   Completar!  ##
		###################
		
		# Tener en cuenta que se debe:
		# (1) Obtener los paquetes en self.retranmission_queue
		# (2) Volver a enviarlos
		# (3) Reencolarlos para otra eventual retransmisión
		# ...y verificar que no se exceda la cantidad máxima de reenvíos!
		# (hacer self.shutdown() si esto ocurre y dejar un mensaje en self.error)
		haypaquetesret = len(self.retransmission_queue.packets()) > 0
		if haypaquetesret:
			print "Retransmit"
			self.retransmission_queue.__iter__()
			primer_paquete = self.retransmission_queue.next().get_seq_number()
			if self.retransmission_attempts.get(primer_paquete,0) >= MAX_RETRANSMISSION_ATTEMPTS:
				self.error = "Error muchas retransmisiones"
				self.shutdown()
			else:
				copia_retransmission_queue = self.retransmission_queue.packets()
				self.retransmission_queue.clear()
				for pack in copia_retransmission_queue:
					self.send_and_queue_packet(pack)
					self.retransmission_attempts[pack.get_seq_number()] = self.retransmission_attempts.get(pack.get_seq_number(),0) + 1	# Le sumo uno a su cantidad de retransmisiones, inicilizandolo en cero si no existe
	
	def handle_pending_data(self):
		more_data_pending = False
		
		if self.control_block.send_allowed():
			try:
				data = self.outgoing_buffer.get(MIN_PACKET_SIZE, MAX_PACKET_SIZE)
			except NotEnoughDataException:
				pass
			else:
				packet = self.build_packet(payload=data)
				self.send_and_queue_packet(packet)
				
			if not self.outgoing_buffer.empty():
				more_data_pending = True
		else:
			more_data_pending = True
		
		if more_data_pending:
			self.worker.signal_pending_data()
	
	def handle_incoming(self, packet):
		###################
		##   Completar!  ##
		###################
		
		# Tener en cuenta que se debe:
		# * Corroborar que el flag de ACK esté seteado
		# * Distinguir el caso donde el estado es SYN_SENT
		#   * No olvidar de hacer self.connected_event.set() al confirmar el ACK y establecer la conexión!!!
		# * Analizar si #ACK es aceptado (hablar con el bloque de control para hacer este checkeo)
		# * Sacar de la cola de retransmisión los paquetes reconocidos por #ACK
		# * Ajustar la ventana deslizante con #ACK
		# * Tener en cuenta también el caso donde el estado es FIN_SENT
		ack_num = packet.get_ack_number()
		if ACKFlag in packet and self.control_block.valid_ack(ack_num):	# si hay ack y es valido
			self.retransmission_queue.acknowledge(packet)	# lo sacamos del retransmission queue
			self.control_block.update_window(ack_num)	# actualizamos la ventana
			for packs_ack in range(self.control_block.get_window_lo(),ack_num+1):	# Eliminamos los paquetes ackeados del diccionario de intentos de retransmision
				del retransmission_attempts[packs_ack]
			
			if self.state == SYN_SENT:	# Si estaba desconectado, conectate
				self.state = ESTABLISHED
				self.connected_event.set()
			elif self.state == FIN_SENT:	# Si te reconoce el fin de la conexion, terminala
				self.state = CLOSED
				self.retransmission_queue.clear()
				self.retransmission_attempts.clear()
				self.close()
			#~ if self.outgoing_buffer and self.retransmission_queue.empty():	#  Si recibimos el ack de lo ultimo imprimimos cuanto tardo
				#~ print clock() - start_time
			
	def handle_close_connection(self):
		if not self.outgoing_buffer.empty():
			self.worker.signal_pending_data()
			self.worker.signal_close_connection()
		elif not self.retransmission_queue.empty():
			self.worker.signal_close_connection()
		else:
			fin_packet = self.build_packet(flags=[FINFlag])
			self.send_and_queue_packet(fin_packet)
			self.state = FIN_SENT
		
	def close(self):
		if self.is_connected():
			self.worker.signal_close_connection()
		
	def shutdown(self):
		self.outgoing_buffer.clear()
		self.retransmission_queue.clear()
		self.retransmission_attempts.clear()
		self.worker.stop()
		# Esto es por si falló el establecimiento de conexión (para destrabar al thread principal)
		self.connected_event.set()
		self.state = CLOSED
Exemplo n.º 2
0
class PTCClientProtocol(object):
    
    def __init__(self, address, port):
        self.retransmission_queue = RetransmissionQueue(self)
        self.retransmission_attempts = Counter()
        self.outgoing_buffer = DataBuffer()
        self.state = CLOSED
        self.control_block = ClientControlBlock(address, port)
        self.socket = Soquete(address, port)
        self.packet_builder = PacketBuilder(self)
    
    def is_connected(self):
        return self.state == ESTABLISHED
        
    def build_packet(self, payload=None, flags=None):
        seq = self.control_block.get_send_seq()
        if payload is not None:
            self.control_block.increment_send_seq()
        packet = self.packet_builder.build(payload=payload, flags=flags, seq=seq)
        return packet
        
    def send_packet(self, packet):
        if DEBUG and RANDOM_LOSS:
            #'perdemos' un 10% de los paquetes
            if random.choice(range(10)) :
                print 'mando el paquete:', packet.get_seq_number()
                self.socket.send(packet)
            else:
                print 'Mala leche con el', packet.get_seq_number()
        else:
            self.socket.send(packet)
        
    def send_and_queue_packet(self, packet):
        self.send_packet(packet)
        self.retransmission_queue.put(packet)
        
    def send(self, data):
        if not self.is_connected():
            raise Exception('cannot send data: connection not established')
        self.worker.send(data)

    def connect_to(self, address, port):
        self.worker = ClientProtocolWorker.spawn_for(self)
        self.worker.start()
        self.connected_event = threading.Event()
        self.control_block.reset_numbers()
        self.control_block.set_destination_address(address)
        self.control_block.set_destination_port(port)
        
        syn_packet = self.build_packet(flags=[SYNFlag])
        self.send_and_queue_packet(syn_packet)
        self.state = SYN_SENT
        
        self.connected_event.wait()
    
    def handle_timeout(self):
        ###################
        ##   Completar!  ##
        ###################
        
        # Tener en cuenta que se debe:
        # (1) Obtener los paquetes en self.retranmission_queue
        # (2) Volver a enviarlos
        # (3) Reencolarlos para otra eventual retransmisión
        # ...y verificar que no se exceda la cantidad máxima de reenvíos!
        # (hacer self.shutdown() si esto ocurre y dejar un mensaje en self.error)
        
        # *** NO SE SI NO HABIA YA OTRA VARIABLE DONDE SE INDICABA LA CANTIDAD DE TRANSMISIONES
        # *** SE CUENTA POR PAQUETE O LA COLA ENTERA?
        # *** HAY QUE RETRANSMITIR TODO LO QUE ESTA EN LA COLA?
        # Cantidad maxima de reenvios: MAX_RETRANSMISSION_ATTEMPTS
        if DEBUG: print 'TIMEOUT'
        oldQueue = self.retransmission_queue
        self.retransmission_queue = RetransmissionQueue(self)       
        for packet in oldQueue:
            if self.retransmission_attempts[packet.get_seq_number()] == MAX_RETRANSMISSION_ATTEMPTS :
                self.error = 'Retransmition Limit Exceeded'
                self.shutdown()
            else:
                self.retransmission_attempts[packet.get_seq_number()] += 1
                self.send_and_queue_packet(packet) 

    def handle_pending_data(self):
        more_data_pending = False
        
        if self.control_block.send_allowed():
            try:
                data = self.outgoing_buffer.get(MIN_PACKET_SIZE, MAX_PACKET_SIZE)
            except NotEnoughDataException:
                pass
            else:
                packet = self.build_packet(payload=data)
                self.send_and_queue_packet(packet)
                
            if not self.outgoing_buffer.empty():
                more_data_pending = True
        else:
            more_data_pending = True
        
        if more_data_pending:
            self.worker.signal_pending_data()
    
    
    def handle_incoming(self, packet):
        ###################
        ##   Completar!  ##
        ###################
        
        # Tener en cuenta que se debe:
        # * Corroborar que el flag de ACK esté seteado
        # * Distinguir el caso donde el estado es SYN_SENT
        #   * No olvidar de hacer self.connected_event.set() al confirmar el ACK y establecer la conexión!!!
        # * Analizar si #ACK es aceptado (hablar con el bloque de control para hacer este checkeo)
        # * Sacar de la cola de retransmisión los paquetes reconocidos por #ACK
        # * Ajustar la ventana deslizante con #ACK
        # * Tener en cuenta también el caso donde el estado es FIN_SENT
        
        # Corroboro que el flag de ACK este seteado
        if not ACKFlag in packet:
            raise Exception('Error (hay que hacer algo mas? Es un error?)')
            self.shutdown()
            return
            
        if DEBUG: print 'me llegó el paquete numero:', packet.get_ack_number()
        # Reviso si el ACK es aceptado
        if self.control_block.ack_accepted(packet): 
            # *** Si no es aceptado no hago nada no?
            for ackedPacket in self.retransmission_queue.acknowledge(packet):
                del(self.retransmission_attempts[ackedPacket.get_seq_number()])
            self.control_block.adjust_window(packet)
        else:
            return
 
        # Si fue aceptado, ejecuto accion en base al estado actual
        # *** ASUMO QUE NO SE LO LLAMA SI EL ESTADO ES CLOSED, ESO ESTARA BIEN?
        if self.state == ESTABLISHED:
            return
        elif self.state == SYN_SENT:
            # El servidor establecio una conexion: 
            # cambio el estado del cliente y sincronizo la conexion
            
            # Corroboro que el numero de ACK recibido sea igual al numero de SEQ enviado
            ackNum = packet.get_ack_number()
            seqNum = self.control_block.get_send_seq()
            
            if not (self.control_block.modular_increment(ackNum) == seqNum):
                #self.error = 'SYN_ACK inválido'
                #self.shutdown()
                if DEBUG: print 'recibí fruta (ack != seq):', ackNum, seqNum
                #no hagamos que se cierre, tal vez le llegó algo viejo o equivocado
                #dejemos que si posta anda mal, lo maten los timeouts.
                return
            
            self.state = ESTABLISHED
            self.connected_event.set()
            if DEBUG: print 'conexión establecida'
            
        elif self.state == FIN_SENT:
            # Recibi respuesta del servidor indicando que puedo cerrar la conexion
            if DEBUG: print 'llego el fin'
            self.state = CLOSED
            # *** Hago algo mas para cerrar la conexion?
            self.shutdown() #(?)
            
        else:
            self.error = 'Estado inexistente'
            self.shutdown()
            
    def handle_close_connection(self):
        if not self.outgoing_buffer.empty():
            self.worker.signal_pending_data()
            self.worker.signal_close_connection()
        elif not self.retransmission_queue.empty():
            self.worker.signal_close_connection()
        else:
            fin_packet = self.build_packet(flags=[FINFlag])
            self.send_and_queue_packet(fin_packet)
            self.state = FIN_SENT
        
    def close(self):
        if self.is_connected():
            self.worker.signal_close_connection()
        
    def shutdown(self):
        self.outgoing_buffer.clear()
        self.retransmission_queue.clear()
        self.retransmission_attempts.clear()
        self.worker.stop()
        # Esto es por si falló el establecimiento de conexión (para destrabar al thread principal)
        self.connected_event.set()
        self.state = CLOSED
Exemplo n.º 3
0
class PTCClientProtocol(object):
    
    def __init__(self, address, port):
        self.retransmission_queue = RetransmissionQueue(self)
        self.retransmission_attempts = dict()
        self.outgoing_buffer = DataBuffer()
        self.state = CLOSED
        self.control_block = ClientControlBlock(address, port)
        self.socket = Soquete(address, port)
        self.packet_builder = PacketBuilder(self)
    
    def is_connected(self):
        return self.state == ESTABLISHED
        
    def build_packet(self, payload=None, flags=None):
        seq = self.control_block.get_send_seq()
        #Comente esto porque quedaba corrida la ventana de recepcion despues del connect
        #if payload is not None:
         #   self.control_block.increment_send_seq()
        self.control_block.increment_send_seq()
        packet = self.packet_builder.build(payload=payload, flags=flags, seq=seq)
        return packet
        
    def send_packet(self, packet):
        self.socket.send(packet)
        
    def send_and_queue_packet(self, packet):
        self.send_packet(packet)
        self.retransmission_queue.put(packet)
        
    def send(self, data):
        if not self.is_connected():
            raise Exception('cannot send data: connection not established')
        self.worker.send(data)

    def sendFile(self, nombre):
        if not self.is_connected():
            raise Exception('cannot send data: connection not established')
        archivo = open(nombre)
        line = archivo.readline() 
        self.worker.send(line)
        archivo.close()

    def connect_to(self, address, port):
        self.worker = ClientProtocolWorker.spawn_for(self)
        self.worker.start()
        self.connected_event = threading.Event()
        self.control_block.set_destination_address(address)
        self.control_block.set_destination_port(port)
        
        syn_packet = self.build_packet(flags=[SYNFlag])
        self.send_and_queue_packet(syn_packet)
        self.state = SYN_SENT
        
        self.connected_event.wait()
    
    def handle_timeout(self):
        ###################
        ##   Completar!  ##
        ###################
        
        # Tener en cuenta que se debe:
        # (1) Obtener los paquetes en self.retranmission_queue
        # (2) Volver a enviarlos
        # (3) Reencolarlos para otra eventual retransmisión
        # ...y verificar que no se exceda la cantidad máxima de reenvíos!
        # (hacer self.shutdown() si esto ocurre y dejar un mensaje en self.error)

        retransmited = RetransmissionQueue(self)
        shutdown = False
        for packet in self.retransmission_queue:
            seqNum = packet.get_seq_number()
            retransmitions = 0
            if(self.retransmission_attempts.has_key(seqNum)):
                retransmitions = self.retransmission_attempts[seqNum]

            if(retransmitions == MAX_RETRANSMISSION_ATTEMPTS):
                shutdown = True
                break
            else:
                self.send_packet(packet)
                retransmited.put(packet)
                self.retransmission_attempts[seqNum] = retransmitions + 1
        
        if(shutdown):
            self.shutdown()
        else:
            self.retransmission_queue = retransmited


    
    def handle_pending_data(self):
        more_data_pending = False
        
        if self.control_block.send_allowed():
            try:
                data = self.outgoing_buffer.get(MIN_PACKET_SIZE, MAX_PACKET_SIZE)
            except NotEnoughDataException:
                pass
            else:
                packet = self.build_packet(payload=data)
                self.send_and_queue_packet(packet)
                
            if not self.outgoing_buffer.empty():
                more_data_pending = True
        else:
            more_data_pending = True
        
        if more_data_pending:
            self.worker.signal_pending_data()
    
    def handle_incoming(self, packet):
        ###################
        ##   Completar!  ##
        ###################
        
        # Tener en cuenta que se debe:
        # * Corroborar que el flag de ACK esté seteado
        # * Distinguir el caso donde el estado es SYN_SENT
        #   * No olvidar de hacer self.connected_event.set() al confirmar el ACK y establecer la conexión!!!
        # * Analizar si #ACK es aceptado (hablar con el bloque de control para hacer este checkeo)
        # * Sacar de la cola de retransmisión los paquetes reconocidos por #ACK
        # * Ajustar la ventana deslizante con #ACK
        # * Tener en cuenta también el caso donde el estado es FIN_SENT
        
         if not ACKFlag in packet:
             print("NO ACK")
             return
         print("ACK "+str(packet.get_ack_number()))
         
         if not self.control_block.ack_valid(packet.get_ack_number()):
             print("NOT VALID ACK "+str(packet.get_ack_number()))
             return

         print("VALID ACK "+str(packet.get_ack_number()))
         self.retransmission_queue.acknowledge(packet)
         
         self.control_block.adjust_window(packet.get_ack_number())
         
         if(self.state == SYN_SENT):
             print("ESTABLISH CONNECTION")
             self.state = ESTABLISHED
             self.connected_event.set()
             return
        
         if(self.state == FIN_SENT):
             print("CLOSE CONNECTION")
             self.state = CLOSED
             self.close()

            
    def handle_close_connection(self):
        if not self.outgoing_buffer.empty():
            self.worker.signal_pending_data()
            self.worker.signal_close_connection()
        elif not self.retransmission_queue.empty():
            self.worker.signal_close_connection()
        else:
            fin_packet = self.build_packet(flags=[FINFlag])
            self.send_and_queue_packet(fin_packet)
            self.state = FIN_SENT
        
    def close(self):
        if self.is_connected():
            self.worker.signal_close_connection()
        
    def shutdown(self):
        self.outgoing_buffer.clear()
        self.retransmission_queue.clear()
        self.retransmission_attempts.clear()
        self.worker.stop()
        # Esto es por si falló el establecimiento de conexión (para destrabar al thread principal)
        self.connected_event.set()
        self.state = CLOSED
Exemplo n.º 4
0
Arquivo: client.py Projeto: Laski/tdc
class PTCClientProtocol(object):
    
    def __init__(self, address, port):
        self.retransmission_queue = RetransmissionQueue(self)
        self.retransmission_attempts = dict()
        self.outgoing_buffer = DataBuffer()
        self.state = CLOSED
        self.control_block = ClientControlBlock(address, port)
        self.socket = Soquete(address, port)
        self.packet_builder = PacketBuilder(self)
    
    def is_connected(self):
        return self.state == ESTABLISHED
        
    def build_packet(self, payload=None, flags=None):
        seq = self.control_block.get_send_seq()
        #if payload is not None:
        self.control_block.increment_send_seq()
        packet = self.packet_builder.build(payload=payload, flags=flags, seq=seq)
        return packet
        
    def send_packet(self, packet):
        if(debug):
            print("Voy a mandar el paquete número: "),
            print(str(packet.get_seq_number()))
        #if random.randint(1, 11) == 1:
            # simulo congestión
        #    return
        self.socket.send(packet)
        
    def send_and_queue_packet(self, packet):
        self.send_packet(packet)
        self.retransmission_queue.put(packet)
        
    def send(self, data):
        if not self.is_connected():
            raise Exception('cannot send data: connection not established')
        self.worker.send(data)
        global t1
        t1 = time.time()

    def connect_to(self, address, port):
        self.worker = ClientProtocolWorker.spawn_for(self)
        self.worker.start()
        self.connected_event = threading.Event()
        self.control_block.set_destination_address(address)
        self.control_block.set_destination_port(port)
        
        syn_packet = self.build_packet(flags=[SYNFlag])
        self.send_and_queue_packet(syn_packet)
        self.state = SYN_SENT
        
        self.connected_event.wait()
    
    def handle_timeout(self):
        global count_rets
        count_rets += 1
        if(debug or True):
            print ("Parece que se perdió un paquete, voy a reenviar.")
        new_queue = RetransmissionQueue(self)
        for packet in self.retransmission_queue:
            if packet not in self.retransmission_attempts:
                self.retransmission_attempts[packet.get_seq_number()] = 0
            self.retransmission_attempts[packet.get_seq_number()] += 1
            if self.retransmission_attempts[packet.get_seq_number()] >= MAX_RETRANSMISSION_ATTEMPTS:
                self.shutdown()
                self.error =  "Intentos de retransmisión superó el máximo"
                break
            else:
                self.send_packet(packet)
            new_queue.put(packet)
        self.retransmission_queue = new_queue
        
    def handle_pending_data(self):
        more_data_pending = False
        
        if self.control_block.send_allowed():
            try:
                data = self.outgoing_buffer.get(MIN_PACKET_SIZE, MAX_PACKET_SIZE)
            except NotEnoughDataException:
                pass
            else:
                packet = self.build_packet(payload=data)
                self.send_and_queue_packet(packet)
                
            if not self.outgoing_buffer.empty():
                more_data_pending = True
        else:
            more_data_pending = True
        
        if more_data_pending:
            self.worker.signal_pending_data()
    
    def handle_incoming(self, packet):
        if self.state == ESTABLISHED and self.control_block.accept_ack(packet):
            self.retransmission_queue.acknowledge(packet)
            self.clear_retransmission_attempts(packet.get_ack_number())
            if(debug):
                print("Recibí el ack número: "),
                print(str(packet.get_ack_number()))
            if self.outgoing_buffer.empty() and self.retransmission_queue.empty():
                print("Recibi el ultimo ack")
                print time.time() - t1
                global f, frets, count_rets

                f.write(str(time.time() - t1))
                f.write("\n")
                f.close()
                frets.write(str(count_rets))
                frets.write("\n")
                frets.close()
        elif self.state == SYN_SENT and self.control_block.accept_control_ack(packet):
            self.state = ESTABLISHED
            self.connected_event.set()
        elif self.state == FIN_SENT and self.control_block.accept_control_ack(packet):
                self.state = CLOSED
                        
        # Tener en cuenta que se debe:
        # * Corroborar que el flag de ACK esté seteado
            # Se encarga el control_block
        # * Distinguir el caso donde el estado es SYN_SENT
            # Dale
        #   * No olvidar de hacer self.connected_event.set() al confirmar el ACK y establecer la conexión!!!
            # A full
        # * Analizar si #ACK es aceptado (hablar con el bloque de control para hacer este checkeo)
            # Sí
        # * Sacar de la cola de retransmisión los paquetes reconocidos por #ACK
            # Lo hace la cola
        # * Ajustar la ventana deslizante con #ACK
            # Lo hace el control_block
        # * Tener en cuenta también el caso donde el estado es FIN_SENT
            # Ok
            
    def clear_retransmission_attempts(self, ack):
        for seq_number in self.retransmission_attempts.keys():
            if seq_number <= ack:
                del self.retransmission_attempts[seq_number]
            
    def handle_close_connection(self):
        if not self.outgoing_buffer.empty():
            self.worker.signal_pending_data()
            self.worker.signal_close_connection()
        elif not self.retransmission_queue.empty():
            self.worker.signal_close_connection()
        else:
            fin_packet = self.build_packet(flags=[FINFlag])
            self.send_and_queue_packet(fin_packet)
            self.state = FIN_SENT
        
    def close(self):
        if self.is_connected():
            self.worker.signal_close_connection()
        
    def shutdown(self):
        self.outgoing_buffer.clear()
        self.retransmission_queue.clear()
        self.retransmission_attempts.clear()
        self.worker.stop()
        # Esto es por si falló el establecimiento de conexión (para destrabar al thread principal)
        self.connected_event.set()
        self.state = CLOSED
Exemplo n.º 5
0
Arquivo: client.py Projeto: Laski/tdc
class PTCClientProtocol(object):
    def __init__(self, address, port):
        self.retransmission_queue = RetransmissionQueue(self)
        self.retransmission_attempts = dict()
        self.outgoing_buffer = DataBuffer()
        self.state = CLOSED
        self.control_block = ClientControlBlock(address, port)
        self.socket = Soquete(address, port)
        self.packet_builder = PacketBuilder(self)

    def is_connected(self):
        return self.state == ESTABLISHED

    def build_packet(self, payload=None, flags=None):
        seq = self.control_block.get_send_seq()
        #if payload is not None:
        self.control_block.increment_send_seq()
        packet = self.packet_builder.build(payload=payload,
                                           flags=flags,
                                           seq=seq)
        return packet

    def send_packet(self, packet):
        if (debug):
            print("Voy a mandar el paquete número: "),
            print(str(packet.get_seq_number()))
        #if random.randint(1, 11) == 1:
        # simulo congestión
        #    return
        self.socket.send(packet)

    def send_and_queue_packet(self, packet):
        self.send_packet(packet)
        self.retransmission_queue.put(packet)

    def send(self, data):
        if not self.is_connected():
            raise Exception('cannot send data: connection not established')
        self.worker.send(data)
        global t1
        t1 = time.time()

    def connect_to(self, address, port):
        self.worker = ClientProtocolWorker.spawn_for(self)
        self.worker.start()
        self.connected_event = threading.Event()
        self.control_block.set_destination_address(address)
        self.control_block.set_destination_port(port)

        syn_packet = self.build_packet(flags=[SYNFlag])
        self.send_and_queue_packet(syn_packet)
        self.state = SYN_SENT

        self.connected_event.wait()

    def handle_timeout(self):
        global count_rets
        count_rets += 1
        if (debug or True):
            print("Parece que se perdió un paquete, voy a reenviar.")
        new_queue = RetransmissionQueue(self)
        for packet in self.retransmission_queue:
            if packet not in self.retransmission_attempts:
                self.retransmission_attempts[packet.get_seq_number()] = 0
            self.retransmission_attempts[packet.get_seq_number()] += 1
            if self.retransmission_attempts[
                    packet.get_seq_number()] >= MAX_RETRANSMISSION_ATTEMPTS:
                self.shutdown()
                self.error = "Intentos de retransmisión superó el máximo"
                break
            else:
                self.send_packet(packet)
            new_queue.put(packet)
        self.retransmission_queue = new_queue

    def handle_pending_data(self):
        more_data_pending = False

        if self.control_block.send_allowed():
            try:
                data = self.outgoing_buffer.get(MIN_PACKET_SIZE,
                                                MAX_PACKET_SIZE)
            except NotEnoughDataException:
                pass
            else:
                packet = self.build_packet(payload=data)
                self.send_and_queue_packet(packet)

            if not self.outgoing_buffer.empty():
                more_data_pending = True
        else:
            more_data_pending = True

        if more_data_pending:
            self.worker.signal_pending_data()

    def handle_incoming(self, packet):
        if self.state == ESTABLISHED and self.control_block.accept_ack(packet):
            self.retransmission_queue.acknowledge(packet)
            self.clear_retransmission_attempts(packet.get_ack_number())
            if (debug):
                print("Recibí el ack número: "),
                print(str(packet.get_ack_number()))
            if self.outgoing_buffer.empty(
            ) and self.retransmission_queue.empty():
                print("Recibi el ultimo ack")
                print time.time() - t1
                global f, frets, count_rets

                f.write(str(time.time() - t1))
                f.write("\n")
                f.close()
                frets.write(str(count_rets))
                frets.write("\n")
                frets.close()
        elif self.state == SYN_SENT and self.control_block.accept_control_ack(
                packet):
            self.state = ESTABLISHED
            self.connected_event.set()
        elif self.state == FIN_SENT and self.control_block.accept_control_ack(
                packet):
            self.state = CLOSED

        # Tener en cuenta que se debe:
        # * Corroborar que el flag de ACK esté seteado
        # Se encarga el control_block
        # * Distinguir el caso donde el estado es SYN_SENT
        # Dale
        #   * No olvidar de hacer self.connected_event.set() al confirmar el ACK y establecer la conexión!!!
        # A full
        # * Analizar si #ACK es aceptado (hablar con el bloque de control para hacer este checkeo)
        # Sí
        # * Sacar de la cola de retransmisión los paquetes reconocidos por #ACK
        # Lo hace la cola
        # * Ajustar la ventana deslizante con #ACK
        # Lo hace el control_block
        # * Tener en cuenta también el caso donde el estado es FIN_SENT
        # Ok

    def clear_retransmission_attempts(self, ack):
        for seq_number in self.retransmission_attempts.keys():
            if seq_number <= ack:
                del self.retransmission_attempts[seq_number]

    def handle_close_connection(self):
        if not self.outgoing_buffer.empty():
            self.worker.signal_pending_data()
            self.worker.signal_close_connection()
        elif not self.retransmission_queue.empty():
            self.worker.signal_close_connection()
        else:
            fin_packet = self.build_packet(flags=[FINFlag])
            self.send_and_queue_packet(fin_packet)
            self.state = FIN_SENT

    def close(self):
        if self.is_connected():
            self.worker.signal_close_connection()

    def shutdown(self):
        self.outgoing_buffer.clear()
        self.retransmission_queue.clear()
        self.retransmission_attempts.clear()
        self.worker.stop()
        # Esto es por si falló el establecimiento de conexión (para destrabar al thread principal)
        self.connected_event.set()
        self.state = CLOSED
Exemplo n.º 6
0
class PTCClientProtocol(object):
    
    def __init__(self, address, port):
        self.retransmission_queue = RetransmissionQueue(self)
        self.retransmission_attempts = dict()
        self.outgoing_buffer = DataBuffer()
        self.state = CLOSED
        self.control_block = ClientControlBlock(address, port)
        self.socket = Soquete(address, port)
        self.packet_builder = PacketBuilder(self)
    
    def is_connected(self):
        return self.state == ESTABLISHED
        
    def build_packet(self, payload=None, flags=None):
        seq = self.control_block.get_send_seq()
        if payload is not None:
            self.control_block.increment_send_seq()
        packet = self.packet_builder.build(payload=payload, flags=flags, seq=seq)
        return packet
        
    def send_packet(self, packet):
        self.socket.send(packet)
        
    def send_and_queue_packet(self, packet):
        self.send_packet(packet)
        self.retransmission_queue.put(packet)

        seq_number = packet.get_seq_number()
        if seq_number in self.retransmission_attempts:
            if self.retransmission_attempts[seq_number] > \
               MAX_RETRANSMISSION_ATTEMPTS + 1:
                self.retransmission_attempts[seq_number] = 0
        else:
            self.retransmission_attempts[seq_number] = 0
        
    def send(self, data):
        if not self.is_connected():
            raise Exception('cannot send data: connection not established')
        self.worker.send(data)

    def connect_to(self, address, port):
        self.worker = ClientProtocolWorker.spawn_for(self)
        self.worker.start()
        self.connected_event = threading.Event()
        self.control_block.set_destination_address(address)
        self.control_block.set_destination_port(port)
        
        syn_packet = self.build_packet(flags=[SYNFlag])
        self.send_and_queue_packet(syn_packet)
        self.state = SYN_SENT
        
        self.connected_event.wait()
    
    def handle_timeout(self):
        ###################
        ##   Completar!  ##
        ###################
        
        # Tener en cuenta que se debe:
        # (1) Obtener los paquetes en self.retranmission_queue
        # (2) Volver a enviarlos
        # (3) Reencolarlos para otra eventual retransmisión
        # ...y verificar que no se exceda la cantidad máxima de reenvíos!
        # (hacer self.shutdown() si esto ocurre y dejar un mensaje en self.error)

        packet_list = []
        for packet in self.retransmission_queue:
            packet_list.append(packet)

        self.retransmission_queue.clear()

        for packet in packet_list:

            if self.retransmission_attempts[packet.get_seq_number()] \
               <= MAX_RETRANSMISSION_ATTEMPTS:
                packet.add_flag(RSTFlag)    # Uso este flag sin utilidad para poder diferenciar retransmiciones
                self.send_and_queue_packet(packet)
                self.retransmission_attempts[packet.get_seq_number()] += 1   
            else:
                self.shutdown()
                self.error = 'Muchas retransmisiones, fuiste!'
                print "Muchas retransmisiones, fuiste!"

    

    def handle_pending_data(self):
        more_data_pending = False
        
        if self.control_block.send_allowed():
            try:
                data = self.outgoing_buffer.get(MIN_PACKET_SIZE, MAX_PACKET_SIZE)
            except NotEnoughDataException:
                pass
            else:
                packet = self.build_packet(payload=data)
                self.send_and_queue_packet(packet)
                
            if not self.outgoing_buffer.empty():
                more_data_pending = True
        else:
            more_data_pending = True
        
        if more_data_pending:
            self.worker.signal_pending_data()
    
    def handle_incoming(self, packet):
        ###################
        ##   Completar!  ##
        ###################
        
        # Tener en cuenta que se debe:
        # * Corroborar que el flag de ACK esté seteado
        # * Distinguir el caso donde el estado es SYN_SENT
        #   * No olvidar de hacer self.connected_event.set() al confirmar el ACK y establecer la conexión!!!
        # * Analizar si #ACK es aceptado (hablar con el bloque de control para hacer este checkeo)
        # * Sacar de la cola de retransmisión los paquetes reconocidos por #ACK
        # * Ajustar la ventana deslizante con #ACK
        # * Tener en cuenta también el caso donde el estado es FIN_SENT
        
        if ACKFlag in packet:
            ack_number = packet.get_ack_number()
            seq_number = packet.get_seq_number()

            if self.state == SYN_SENT:
                if ack_number == self.control_block.send_seq:
                    self.retransmission_queue.acknowledge(packet)
                    self.control_block.increment_send_seq()
                    self.control_block.update_send_window(ack_number)
                    self.state = ESTABLISHED
                    self.connected_event.set()

            elif self.state == FIN_SENT:
                if ack_number ==  self.control_block.send_seq:
                    self.retransmission_queue.acknowledge(packet)
                    self.state = CLOSED

            else:
                if self.control_block.ack_ok(ack_number):
                    self.retransmission_queue.acknowledge(packet)
                    self.control_block.update_send_window(ack_number)
            

    def handle_close_connection(self):
        if not self.outgoing_buffer.empty():
            self.worker.signal_pending_data()
            self.worker.signal_close_connection()
        elif not self.retransmission_queue.empty():
            self.worker.signal_close_connection()
        else:
            fin_packet = self.build_packet(flags=[FINFlag])
            self.send_and_queue_packet(fin_packet)
            self.state = FIN_SENT
        
    def close(self):
        if self.is_connected():
            self.worker.signal_close_connection()
        
    def shutdown(self):
        self.outgoing_buffer.clear()
        self.retransmission_queue.clear()
        self.retransmission_attempts.clear()
        self.worker.stop()
        # Esto es por si falló el establecimiento de conexión (para destrabar al thread principal)
        self.connected_event.set()
        self.state = CLOSED