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_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_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
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
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
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
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
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
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