def test_opt_ack_decode(raw_opt_ack_packet, option_map): decoded = decode_tftp_datagram(raw_opt_ack_packet) assert isinstance(decoded, OptionsAcknowledgementPacket) for opt in decoded.options: assert isinstance(opt, TFTPOption) assert option_map.get(opt.name) == opt.value assert raw_opt_ack_packet == encode_tftp_datagram(decoded)
def test_server_get_file_no_options(read_handler_factory, listen_port, target_file, file_map): s = TFTPServer(read_handler_factory, disable_factory, "127.0.0.1", listen_port) t = threading.Thread(target=s.serve_forever) t.start() time.sleep(1) client_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) try: client_sock.sendto( ReadRequestPacket(target_file, "octet").encode(), ("127.0.0.1", listen_port)) has_data = True expected_block = 1 reconstructed = bytearray() while has_data: raw, addr = client_sock.recvfrom(600) decoded = decode_tftp_datagram(raw) assert isinstance(decoded, DataPacket) assert decoded.block_number == expected_block reconstructed.extend(decoded.data) if len(decoded.data) < 512: has_data = False client_sock.sendto( AcknowledgementPacket(decoded.block_number).encode(), addr) expected_block += 1 assert reconstructed.decode("utf-8") == file_map[target_file] finally: client_sock.close() s.shutdown() t.join(30)
def test_write_request_with_options(raw_write_request_with_options, request_filename, request_mode, option_map): decoded = decode_tftp_datagram(raw_write_request_with_options) assert isinstance(decoded, WriteRequestPacket) assert decoded.filename == request_filename assert decoded.mode == request_mode for opt in decoded.options: assert isinstance(opt, TFTPOption) assert option_map.get(opt.name) == opt.value assert raw_write_request_with_options == encode_tftp_datagram(decoded)
def step(self): if self.completed: return packet, address = self._sock.recvfrom(66000) assert address == self.remote_addr self._last_seen = time.time() self._retries = 0 try: decoded_packet = decode_tftp_datagram(packet) if self._mode == self.Modes.READ: if isinstance(decoded_packet, AcknowledgementPacket): self._last_packet_received = decoded_packet if self._final_block_sent and decoded_packet.block_number == self._last_block_num: server_logger.debug( "Final Acknowledgement received from {0}.".format( self.remote_addr)) self._done = True elif decoded_packet.block_number >= self._last_packet_received.block_number: server_logger.debug( "Acknowledgement received from {0}.".format( self.remote_addr)) server_logger.debug("Sending next data packet.") self._send_read_data() else: self._send_error(ErrorPacket.ErrorCodes.ILLEGAL_OP, "Received invalid ACK packet.") else: self._send_error(ErrorPacket.ErrorCodes.ILLEGAL_OP, "Did not receive expected ACK packet.") elif self._mode == self.Modes.WRITE: if isinstance(decoded_packet, DataPacket): if decoded_packet.block_number == self._last_block_num + 1: self._handler.write(decoded_packet.data) self._send_write_ack() else: self._send_error(ErrorPacket.ErrorCodes.ILLEGAL_OP, "Did not receive expected DATA packet.") else: assert False except HandlerException as e: self._send_error(e.error_code, e.msg) except BaseException as e: self._send_error(ErrorPacket.ErrorCodes.NOT_DEFINED, str(e))
def test_read_request_decode(raw_read_request, request_filename, request_mode): decoded = decode_tftp_datagram(raw_read_request) assert isinstance(decoded, ReadRequestPacket) assert decoded.filename == request_filename assert decoded.mode == request_mode assert raw_read_request == encode_tftp_datagram(decoded)
def test_error_packet_decode(raw_error_packet, error_code, error_message): decoded = decode_tftp_datagram(raw_error_packet) assert isinstance(decoded, ErrorPacket) assert decoded.error_code == error_code assert decoded.error_message == error_message assert raw_error_packet == encode_tftp_datagram(decoded)
def test_ack_decode(raw_ack_packet, block_number): decoded = decode_tftp_datagram(raw_ack_packet) assert isinstance(decoded, AcknowledgementPacket) assert decoded.block_number == block_number assert raw_ack_packet == encode_tftp_datagram(decoded)
def test_data_decode(raw_data_packet, block_number, data_payload): decoded = decode_tftp_datagram(raw_data_packet) assert isinstance(decoded, DataPacket) assert decoded.block_number == block_number assert decoded.data == data_payload assert raw_data_packet == encode_tftp_datagram(decoded)
def setup(self): server_logger.debug("Setting up session..") self._sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) self._last_seen = time.time() try: self._sock.bind((self.host, self.port)) server_logger.debug("Session for {0} bound to {1}".format( self.remote_addr, self._sock.getsockname())) self._sock.connect(self.remote_addr) self._sock.settimeout(int(1.2 * self._timeout)) decoded_request = decode_tftp_datagram(self.initial_request) if isinstance(decoded_request, ReadRequestPacket): server_logger.debug("Read Request Received from {0}.".format( self.remote_addr)) server_logger.debug("Options: {0}".format( decoded_request.options)) self._mode = self.Modes.READ try: self._handler = self.read_handler_factory( decoded_request.filename, decoded_request.mode, self.remote_addr) assert isinstance(self._handler, AbstractReadHandler) self._handler.open() if decoded_request.options: usable_options = [] for option in decoded_request.options: if option.name.lower( ) == self.KnownOptions.BLKSIZE: requested_block_size = int(option.value) if 8 <= requested_block_size <= 65464: self._block_size = requested_block_size usable_options.append(option) else: self._send_error( ErrorPacket.ErrorCodes.ILLEGAL_OP, "Invalid requested block size: {0}". format(requested_block_size)) elif option.name.lower( ) == self.KnownOptions.TIMEOUT: requested_timeout = int(option.value) if 1 <= requested_timeout <= 255: self._timeout = requested_timeout self._sock.settimeout( int(1.2 * self._timeout)) usable_options.append(option) else: self._send_error( ErrorPacket.ErrorCodes.ILLEGAL_OP, "Invalid timeout: {0}".format( requested_timeout)) elif option.name.lower( ) == self.KnownOptions.TSIZE and self._handler.length is not None: usable_options.append( TFTPOption(self.KnownOptions.TSIZE, str(self._handler.length))) elif option.name.lower( ) == self.KnownOptions.WINDOWSIZE: requested_window_size = int(option.value) if 1 <= requested_window_size <= 65535: self._window_size = requested_window_size usable_options.append(option) else: self._send_error( ErrorPacket.ErrorCodes.ILLEGAL_OP, "Invalid requested window size: {0}". format(requested_window_size)) server_logger.debug( "Sending options acknowledgement to {0}".format( self.remote_addr)) self._sock.send( OptionsAcknowledgementPacket( usable_options).encode()) else: server_logger.debug( "Sending first data block to {0}".format( self.remote_addr)) self._send_read_data() except HandlerException as e: server_logger.warning( "Handler exception setting up for read request for {0} " "(filename: {1}, mode: {2}, options: {3})..." "".format(self.remote_addr, decoded_request.filename, decoded_request.mode, decoded_request.options), exc_info=True) self._send_error(e.error_code, e.msg) except BaseException as e: server_logger.exception( "Unhandled exception setting up for read request for {0} " "(filename: {1}, mode: {2}, options: {3})..." "".format(self.remote_addr, decoded_request.filename, decoded_request.mode, decoded_request.options)) self._send_error(ErrorPacket.ErrorCodes.NOT_DEFINED, str(e)) elif isinstance(decoded_request, WriteRequestPacket): self._mode = self.Modes.WRITE try: self._handler = self.write_handler_factory( decoded_request.filename, decoded_request.mode, self.remote_addr) assert isinstance(self._handler, AbstractWriteHandler) self._handler.open() if decoded_request.options: usable_options = [] for option in decoded_request.options: if option.name.lower( ) == self.KnownOptions.BLKSIZE: requested_block_size = int(option.value) if 8 <= requested_block_size <= 65464: self._block_size = requested_block_size usable_options.append(option) else: self._send_error( ErrorPacket.ErrorCodes.ILLEGAL_OP, "Invalid requested block size: {0}". format(requested_block_size)) elif option.name.lower( ) == self.KnownOptions.TIMEOUT: requested_timeout = int(option.value) if 1 <= requested_timeout <= 255: self._timeout = requested_timeout usable_options.append(option) else: self._send_error( ErrorPacket.ErrorCodes.ILLEGAL_OP, "Invalid timeout: {0}".format( requested_timeout)) server_logger.debug( "Sending options acknowledgement to {0}".format( self.remote_addr)) self._sock.send( OptionsAcknowledgementPacket( usable_options).encode()) else: self._send_write_ack() self._last_seen = time.time() except HandlerException as e: self._send_error(e.error_code, e.msg) except BaseException as e: self._send_error(ErrorPacket.ErrorCodes.NOT_DEFINED, str(e)) else: self._send_error(ErrorPacket.ErrorCodes.ILLEGAL_OP, "Session not started with RRQ or WRQ!") except BaseException: self._sock.close() raise