def test_syn(self, mock_socket): # mock variables syn_packet = packet.create_syn_packet() mock_socket.recvfrom.return_value = (packet.pack_packet(syn_packet), "127.0.0.1") expected_response = packet.pack_packet(packet.create_synack_packet(syn_packet)) r = host.Receiver(mock_socket, 10, "127.0.0.1", 10) r.wait_for_syn() mock_socket.sendto.assert_called_with(expected_response, ("127.0.0.1", 10))
def test_dup_syn(self, mock_socket): syn_packet = packet.create_syn_packet() mock_socket.recvfrom.side_effect = [(packet.pack_packet(syn_packet), "127.0.0.1"), (packet.pack_packet(syn_packet), "127.0.0.1")] expected_response = packet.pack_packet(packet.create_synack_packet(syn_packet)) r = host.Receiver(mock_socket, 10, "127.0.0.1", 10) r.wait_for_syn() r.handle_next_packet() mock_socket.sendto.assert_called_with(expected_response, ("127.0.0.1", 10)) # assert_called_with = most recent call
def test_dup_data(self, mock_socket): data = bytes([128] * 512) latest_data = packet.create_data_packets(data, 0)[0] mock_socket.recvfrom.return_value = (packet.pack_packet(latest_data), "127.0.0.1") latest_ack = packet.create_ack_packet_from_data(latest_data, 0) r = host.Receiver(mock_socket, 10, "127.0.0.1", 10) r.latest_ack = latest_ack r.ack_num = 512 r.handle_next_packet() mock_socket.sendto.assert_called_with(packet.pack_packet(latest_ack), ("127.0.0.1", 10))
def wait_for_syn(self): while(True): pkt = self.wait_for_packet(False) if(pkt.flags == packet.Type.FIN): print("received FIN packet, finishing up") self.is_done = True self.finish_status = DONE return elif(pkt.flags == (packet.Type.EOT | packet.Type.ACK)): print("received EOT/ACK packet while waiting for SYN; remote side didn't receive final ACK, retransmitting") self.sock.sendto(packet.pack_packet(packet.create_ack_packet(0, 0)), (self.emulator, self.port)) elif(pkt.flags == packet.Type.SYN): break print("received SYN packet; responding with SYN/ACK") self.latest_ack = packet.create_synack_packet(pkt) response = packet.pack_packet(self.latest_ack) self.sock.sendto(response, (self.emulator, self.port)) self.ack_num = 1
def test_data_timeout(self, mock_socket): mock_socket.recvfrom.side_effect = socket.timeout("timed out") latest_ack = packet.create_synack_packet(packet.create_syn_packet()) r = host.Receiver(mock_socket, 10, "127.0.0.1", 10) r.latest_ack = latest_ack r.handle_next_packet() mock_socket.sendto.assert_called_with(packet.pack_packet(latest_ack), ("127.0.0.1", 10))
def send_data(self): self.current_offset = self.seq_num - 1 self.bytes_left = self.file_size - self.current_offset self.bytes_to_read = min(self.bytes_left, packet.MAX_DATA_LENGTH * self.window_size) if (self.bytes_to_read == 0): self.send_eot() end = self.current_offset + self.bytes_to_read packets = packet.create_data_packets(self.read_data[self.current_offset:end], self.seq_num) for p in packets: self.sock.sendto(packet.pack_packet(p), (self.emulator, self.port)) print("sent DATA packet with seq {} and data len {} to {} on port {}".format(p.seq_num, p.data_len, self.emulator, self.port))
def test_packing(self): # Input: a data packet containing MAX_LENGTH bytes of data buf = bytes([128] * (packet.MAX_LENGTH)) p = Packet( packet.Type.DATA, 0, 0, buf) packed = packet.pack_packet(p) unpacked = packet.unpack_packet(packed) # Expected output (after packing and unpacking: a packet identical to the packed one self.assertEqual(unpacked.flags, p.flags) self.assertEqual(unpacked.ack_num, p.ack_num) self.assertEqual(unpacked.seq_num, p.seq_num) self.assertEqual(unpacked.data_len, p.data_len) self.assertEqual(unpacked.data, p.data)
def run(self): try: print("waiting for SYN packet...") self.wait_for_syn() if(self.is_done): print("finished running, returning status {}".format("SWITCH" if self.finish_status == SWITCH else "DONE")) return self.finish_status print("entering main receiver loop") while(not self.is_done): self.handle_next_packet() except KeyboardInterrupt: print("\ncaught keyboard interrupt, sending FIN") self.sock.sendto(packet.pack_packet(packet.create_fin_packet()), (self.emulator, self.port)) self.finish_status = DONE print("finished running, returning status {}".format("SWITCH" if self.finish_status == SWITCH else "DONE")) return self.finish_status
def run(self): while(True): if(self.is_recv): self.file = open(self.rcv_prefix + str(self.rcv_count), 'wb') self.rcv_count += 1 receiver = Receiver(self.sock, self.config["port"], self.config["emulator"], self.config["window_size"], self.file) result = receiver.run() if(result == DONE): self.file.close() return else: self.is_recv = False self.file.close() else: if(self.send_idx + 1 > len(self.file_list)): response = packet.pack_packet(packet.create_fin_packet()) self.sock.sendto(response, (self.config["emulator"], self.config["port"])) return else: try: self.file = open(self.file_list[self.send_idx], "rb") read_data = self.file.read() file_size = os.stat(self.file_list[self.send_idx]).st_size self.send_idx += 1 sender = emu.sender.Sender(self.sock, self.config["port"], self.config["emulator"], self.config["window_size"], read_data, file_size) result = sender.run() if(result == SWITCH): self.is_recv = True self.file.close() else: self.file.close() return except Exception as e: print(str(e)) print("error while processing file {}, sending FIN".format(self.file_list[self.send_idx-1])) response = packet.create_fin_packet() self.sock.sendto(response, (self.config["emulator"], self.config["port"])) return
def send_fin(self): self.sock.sendto(packet.pack_packet(packet.create_fin_packet()), (self.emulator, self.port))
def send_eot(self): self.sock.sendto(packet.pack_packet(packet.create_eot_packet()), (self.emulator, self.port)) self.sent_eot = True
def send_ack(self): response = packet.pack_packet(packet.create_ack_packet(0, 0)) self.sock.sendto(response, (self.emulator, self.port))
def send_syn(self): response = packet.pack_packet(packet.create_syn_packet()) self.sock.sendto(response, (self.emulator, self.port)) self.seq_num = 1 self.rcvd_window_bytes = 0 self.latest_rcvd = None
def handle_next_packet(self): if(self.rcvd_window_bytes == (self.window_size * packet.MAX_DATA_LENGTH) or self.ack_now): print("sending ack {}".format(self.ack_num)) response = packet.pack_packet(self.latest_ack) self.sock.sendto(response, (self.emulator, self.port)) self.ack_now = False self.reacked = False self.rcvd_window_bytes = 0 # write buffer to file and create an empty buffer self.file.write(self.buf) self.buf = bytearray() print("waiting for next packet...") rcvd = self.wait_for_packet(True) # wait_for_packet returns None on timeout if(rcvd == None): self.reacked = False if(not self.got_eot): # re-send last ACK print("timed out while waiting for packet; retransmitting ack with ack number {}".format(self.ack_num)) response = packet.pack_packet(self.latest_ack) self.sock.sendto(response, (self.emulator, self.port)) else: # need to resend EOT/ACK print("timed out while waiting for final ACK; retransmitting EOT/ACK") self.sock.sendto(packet.pack_packet(packet.create_eot_ack_packet()), (self.emulator, self.port)) elif(rcvd.flags == packet.Type.SYN): print("received another SYN packet; responding with SYN/ACK") response = packet.pack_packet(packet.create_synack_packet(rcvd)) self.sock.sendto(response, (self.emulator, self.port)) elif(rcvd.flags == packet.Type.FIN): print("received FIN packet, finishing up") self.is_done = True self.finish_status = DONE elif(rcvd.flags == packet.Type.ACK and self.got_eot): print("received ACK for EOT/ACK, switching modes") self.is_done = True self.finish_status = SWITCH elif(rcvd.flags == packet.Type.EOT and not self.got_eot): print("received EOT packet, responding with EOT/ACK") self.sock.sendto(packet.pack_packet(packet.create_eot_ack_packet()), (self.emulator, self.port)) self.got_eot = True elif(rcvd.flags == packet.Type.DATA): # we got a spurious retransmission if(rcvd.seq_num != self.ack_num): if(rcvd.seq_num < self.ack_num): print("spurious retransmission with sequence number {}".format(rcvd.seq_num)) if(not self.reacked): print("retransmitting ACK in response to spurious retransmission") response = packet.pack_packet(self.latest_ack) self.sock.sendto(response, (self.emulator, self.port)) self.reacked_seq_num = rcvd.seq_num self.reacked = True elif(rcvd.seq_num == self.reacked_seq_num): print("retransmitting ACK in response to spurious retransmission") response = packet.pack_packet(self.latest_ack) self.sock.sendto(response, (self.emulator, self.port)) return else: # != and ! < , so it's greater than the ACK number we were expecting, AKA packets were dropped (or re-ordered, but that's unlikely) print("received packet with sequence number {}, packet with sequence number {} was dropped".format(rcvd.seq_num, self.ack_num)) return # the sender will always send max data unless it's almost out of data # in that case, we don't want to wait for the timeout # we should receive an EOT after this (but it shouldn't actually cause problems if not) if(rcvd.data_len < packet.MAX_DATA_LENGTH): print("packet had length {}; acking now".format(str(rcvd.data_len))) self.ack_now = True self.rcvd_window_bytes += rcvd.data_len self.latest_ack = packet.create_ack_packet_from_data(rcvd, self.seq_num) self.ack_num += rcvd.data_len print("received packet with sequence number {}; received {} bytes this window, current ack number is {}".format(rcvd.seq_num, self.rcvd_window_bytes, self.ack_num)) self.buf.extend(rcvd.data)
if(args): if(len(args) > 1): print("syntax: help [command name]") elif(not args[0] in commands): print("Invalid command {}. Type help for a list of commands.".format(args[0])) else: print("{}".format(commands[args[0]])) else: print("Type help [command] to view more detail for a command") for cmd in command_briefs: print(cmd) elif(command == "SYN"): if(args): print("SYN doesn't take any arguments. Sending SYN anyway") sock.sendto(packet.pack_packet(packet.create_syn_packet()), (dest, port)) print("sent SYN packet to {} on port {}".format(dest, port)) elif(command == "SYNACK"): if(args): print("SYNACK doesn't take any arguments. Sending SYN/ACK anyway") sock.sendto(packet.pack_packet(packet.create_synack_packet(packet.create_syn_packet())), (dest, port)) print("sent SYN/ACK packet with to {} on port {}".format(dest, port)) elif(command == "ACK"): if(len(args) != 1): print("usage: ACK [ack_num] (enter 'help ACK' for more)") else: sock.sendto(packet.pack_packet(packet.create_ack_packet(int(args[0]), 0)), (dest, port)) print("sent ACK packet with ack {} to {} on port {}".format(args[0], dest, port))
def test_data(self, mock_socket): data = bytes([128] * packet.MAX_LENGTH * 10) data_packets = packet.create_data_packets(data, 1) # return a different value on each call mock_socket.recvfrom.side_effect = [(packet.pack_packet(data_packets[0]), "127.0.0.1"), (packet.pack_packet(data_packets[1]), "127.0.0.1"), (packet.pack_packet(data_packets[2]), "127.0.0.1"), (packet.pack_packet(data_packets[3]), "127.0.0.1"), (packet.pack_packet(data_packets[4]), "127.0.0.1"), (packet.pack_packet(data_packets[5]), "127.0.0.1"), (packet.pack_packet(data_packets[6]), "127.0.0.1"), (packet.pack_packet(data_packets[7]), "127.0.0.1"), (packet.pack_packet(data_packets[8]), "127.0.0.1"), (packet.pack_packet(data_packets[9]), "127.0.0.1"), (packet.pack_packet(packet.create_fin_packet()), "127.0.0.1")] expected_ack = packet.create_ack_packet_from_data(data_packets[9], 0) r = host.Receiver(mock_socket, 10, "127.0.0.1", 10) r.latest_ack = packet.create_synack_packet(packet.create_syn_packet()) r.ack_num = 1 for i in range(11): r.handle_next_packet() mock_socket.sendto.assert_called_with(packet.pack_packet(expected_ack), ("127.0.0.1", 10)) self.assertEqual(r.ack_num, 14611)