def send(self, msg): floor = 0 payload_size = 512 packets = [] # chunk data into packets while floor < len(msg): if floor + payload_size <= len(msg): payload = msg[floor: floor + payload_size] else: payload = msg[floor:] data_packet = RxPPacket( self.port_number, self.destination[1], seq_number=self.seq_number, payload=payload ) packets.append(data_packet) self.seq_number += 1 floor += payload_size kill_packet = RxPPacket( self.port_number, self.destination[1], seq_number=self.seq_number ) kills_sent = 0 # allow to be sent 3 times before dropping client cxn kill_seq_number = kill_packet.seq_number packets.append(kill_packet) # put that shit at the end after we've added all the other packets self.seq_number += 1 self.logger.debug('Placing packets in window to be sent now...') window = SlidingWindow(packets, self.window_size) time_sent = time.time() time_remaining = self.retransmit_timer.timeout self.cxn_status = RxPConnectionStatus.SEND for data_packet in window.window: self.io.send_queue.put((data_packet, self.destination)) while not window.is_empty(): try: ack_packet, address = self.io.recv_queue.get(True, time_remaining) # resend entire send window (all packets that weren't yet ACK'd by the receiver) except Queue.Empty: self.logger.debug( 'Timed out waiting for ack during data transmission; retransmitting unacknowledged packets.') time_sent = time.time() time_remaining = self.retransmit_timer.timeout for data_packet in window.window: if kill_seq_number == data_packet.seq_number: kills_sent += 1 if kills_sent > 3: # if retransmitted 3 times already, kill cxn with client self.logger.debug( 'Kill packet failed to be acknowledged; unable to end connection, closing now.') return if not window.acknowledged_packets.get(data_packet.seq_number): data_packet.frequency += 1 data_packet.update_checksum() self.io.send_queue.put((data_packet, self.destination)) continue # if still getting SYN/ACK, retransmit ACK if self.__verify_syn_ack(ack_packet, address, 1): self.logger.debug('Received SYN/ACK retransmission; retransmitting ACK.') ack_packet = RxPPacket( self.port_number, self.destination[1], ack_number=ack_packet.seq_number + 1, seq_number=2, ack=True ) self.io.send_queue.put((ack_packet, self.destination)) time_remaining = 0 # if a packet in window is acknowledged, slide the window past said received packet elif self.__verify_is_ack(ack_packet, address) and window.index_of_packet(ack_packet) >= 0: self.retransmit_timer.update(ack_packet.frequency, time.time() - time_sent) self.logger.debug( 'ACK received. Updated retransmit timer; timeout is now ' + str(self.retransmit_timer.timeout)) window.acknowledge_packet(ack_packet) if self.__verify_ack(ack_packet, address, window.window[0].seq_number): additions = window.slide() # send newly added packets if they were added if additions > 0: while additions > 0: self.io.send_queue.put((window.window[-additions], self.destination)) self.seq_number += 1 additions -= 1 # otherwise, update time remaining else: time_remaining -= time.time() - time_sent / 4 # decay if time_remaining < time.time(): time_remaining = .5 self.logger.debug('Trash packet receive; time remaining before next timeout: ' + str(time_remaining)) self.cxn_status = RxPConnectionStatus.IDLE
def mf_write(self, data): start = 0 payload_size = 512 packets = [] # chunk data into packets while start < len(data): if start + payload_size <= len(data): payload = data[start : start + payload_size] else: payload = data[start :] data_packet = MFPacket( self.port_number, self.destination[1], sequence_number = self.sequence_number, payload = payload ) packets.append(data_packet) self.sequence_number += 1 start += payload_size terminator_packet = MFPacket( self.port_number, self.destination[1], sequence_number = self.sequence_number ) packets.append(terminator_packet) self.terminator_packet_seq_num = self.sequence_number self.terminator_packet_num_sent = 0 self.sequence_number += 1 # populate window and send all packets window = SlidingWindow(packets, self.window_size) last_sent = time.time() time_remaining = self.retransmit_timer.timeout self.logger.debug('sending data packets in window.') for data_packet in window.window: self.io_loop.send_queue.put((data_packet, self.destination)) #print data_packet.data_offset while not window.is_empty(): try: # wait for incoming packet ack_packet, address = self.io_loop.receive_queue.get(True, time_remaining) except Queue.Empty: # timeout, go back n self.logger.debug('timed out waiting for ack during data transmission. retransmitting window.') last_sent = time.time() time_remaining = self.retransmit_timer.timeout for data_packet in window.window: if self.terminator_packet_seq_num == data_packet.sequence_number: self.terminator_packet_num_sent += 1 if self.terminator_packet_num_sent > 3: self.logger.debug('Unable to end connection, terminating now') return data_packet.frequency += 1 data_packet.recalculate_checksum() self.io_loop.send_queue.put((data_packet, self.destination)) continue # if still getting syn/ack, retransmit ack if self.__verify_syn_ack(ack_packet, address, 1): self.logger.debug('received syn/ack retransmission. retransmitting ack.') ack_packet = MFPacket( self.port_number, self.destination[1], ack_number = ack_packet.sequence_number + 1, sequence_number = 2, ack = True ) self.io_loop.send_queue.put((ack_packet, self.destination)) time_remaining = 0 # if first packet in pipeline is acknowledged, slide the window elif self.__verify_ack(ack_packet, address, window.window[0].sequence_number): self.retransmit_timer.update(ack_packet.frequency, time.time() - last_sent) self.logger.debug('updated retransmit timer. timeout is now ' + str(self.retransmit_timer.timeout)) window.slide() if not window.is_emptying(): self.io_loop.send_queue.put((window.window[-1], self.destination)) self.sequence_number += 1 #print "executing" # otherwise, update time remaining else: time_remaining -= time.time() - last_sent/4 if time_remaining < time.time(): time_remaining = .5 self.logger.debug('bunk packet received. time remaining before timeout: ' + str(time_remaining))