- Added FTP to changelog - Added FTP to documentation - Added documentation in code - Clean up of methods - prevent repeats of the same code
This commit is contained in:
@@ -29,7 +29,8 @@ SessionManager.
|
|||||||
1. Creating a simulation - this notebook explains how to build up a simulation using the Python package. (WIP)
|
1. Creating a simulation - this notebook explains how to build up a simulation using the Python package. (WIP)
|
||||||
- Red Agent Services:
|
- Red Agent Services:
|
||||||
- Data Manipulator Bot - A red agent service which sends a payload to a target machine. (By default this payload is a SQL query that breaks a database)
|
- Data Manipulator Bot - A red agent service which sends a payload to a target machine. (By default this payload is a SQL query that breaks a database)
|
||||||
- DNS Services: DNS Client and DNS Server
|
- DNS Services: `DNSClient` and `DNSServer`
|
||||||
|
- FTP Services: `FTPClient` and `FTPServer`
|
||||||
|
|
||||||
## [2.0.0] - 2023-07-26
|
## [2.0.0] - 2023-07-26
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,62 @@
|
|||||||
|
.. only:: comment
|
||||||
|
|
||||||
|
© Crown-owned copyright 2023, Defence Science and Technology Laboratory UK
|
||||||
|
|
||||||
|
FTP Client Server
|
||||||
|
=================
|
||||||
|
|
||||||
|
FTP Server
|
||||||
|
----------
|
||||||
|
Provides a FTP Client-Server simulation by extending the base Service class.
|
||||||
|
|
||||||
|
Key capabilities
|
||||||
|
^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
- Simulates FTP requests and FTPPacket transfer across a network
|
||||||
|
- Allows the emulation of FTP commands between an FTP client and server:
|
||||||
|
- STOR: stores a file from client to server
|
||||||
|
- RETR: retrieves a file from the FTP server
|
||||||
|
- Leverages the Service base class for install/uninstall, status tracking, etc.
|
||||||
|
|
||||||
|
Usage
|
||||||
|
^^^^^
|
||||||
|
- Install on a Node via the ``SoftwareManager`` to start the FTP server service.
|
||||||
|
- Service runs on FTP (command) port 21 by default. (TODO: look at in depth implementation of FTP PORT command)
|
||||||
|
|
||||||
|
Implementation
|
||||||
|
^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
- FTP request and responses use a ``FTPPacket`` object
|
||||||
|
- Extends Service class for integration with ``SoftwareManager``.
|
||||||
|
|
||||||
|
FTP Client
|
||||||
|
----------
|
||||||
|
|
||||||
|
The ``FTPClient`` provides a client interface for connecting to the ``FTPServer``.
|
||||||
|
|
||||||
|
Key features
|
||||||
|
^^^^^^^^^^^^
|
||||||
|
|
||||||
|
- Connects to the ``FTPServer`` via the ``SoftwareManager``.
|
||||||
|
- Simulates FTP requests and FTPPacket transfer across a network
|
||||||
|
- Allows the emulation of FTP commands between an FTP client and server:
|
||||||
|
- PORT: specifies the port that server should connect to on the client (currently only uses ``Port.FTP``)
|
||||||
|
- STOR: stores a file from client to server
|
||||||
|
- RETR: retrieves a file from the FTP server
|
||||||
|
- QUIT: disconnect from server
|
||||||
|
- Leverages the Service base class for install/uninstall, status tracking, etc.
|
||||||
|
|
||||||
|
Usage
|
||||||
|
^^^^^
|
||||||
|
|
||||||
|
- Install on a Node via the ``SoftwareManager`` to start the FTP client service.
|
||||||
|
- Service runs on FTP (command) port 21 by default. (TODO: look at in depth implementation of FTP PORT command)
|
||||||
|
- Execute sending a file to the FTP server with ``send_file``
|
||||||
|
- Execute retrieving a file from the FTP server with ``request_file``
|
||||||
|
|
||||||
|
Implementation
|
||||||
|
^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
- Leverages ``SoftwareManager`` for sending payloads over the network.
|
||||||
|
- Provides easy interface for Nodes to transfer files between each other.
|
||||||
|
- Extends base Service class.
|
||||||
@@ -18,3 +18,4 @@ Contents
|
|||||||
database_client_server
|
database_client_server
|
||||||
data_manipulation_bot
|
data_manipulation_bot
|
||||||
dns_client_server
|
dns_client_server
|
||||||
|
ftp_client_server
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ class FTPClient(FTPServiceABC):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
connected: bool = False
|
connected: bool = False
|
||||||
"""Keeps track of whether or not the FTP client is connected to an FTP server"""
|
"""Keeps track of whether or not the FTP client is connected to an FTP server."""
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
kwargs["name"] = "FTPClient"
|
kwargs["name"] = "FTPClient"
|
||||||
@@ -29,7 +29,15 @@ class FTPClient(FTPServiceABC):
|
|||||||
self.start()
|
self.start()
|
||||||
|
|
||||||
def _process_ftp_command(self, payload: FTPPacket, session_id: Optional[str] = None, **kwargs) -> FTPPacket:
|
def _process_ftp_command(self, payload: FTPPacket, session_id: Optional[str] = None, **kwargs) -> FTPPacket:
|
||||||
# if server is down, return error
|
"""
|
||||||
|
Process the command in the FTP Packet.
|
||||||
|
|
||||||
|
:param: payload: The FTP Packet to process
|
||||||
|
:type: payload: FTPPacket
|
||||||
|
:param: session_id: session ID linked to the FTP Packet. Optional.
|
||||||
|
:type: session_id: Optional[str]
|
||||||
|
"""
|
||||||
|
# if client service is down, return error
|
||||||
if self.operating_state != ServiceOperatingState.RUNNING:
|
if self.operating_state != ServiceOperatingState.RUNNING:
|
||||||
payload.status_code = FTPStatusCode.ERROR
|
payload.status_code = FTPStatusCode.ERROR
|
||||||
return payload
|
return payload
|
||||||
@@ -38,20 +46,27 @@ class FTPClient(FTPServiceABC):
|
|||||||
return super()._process_ftp_command(payload=payload, session_id=session_id, **kwargs)
|
return super()._process_ftp_command(payload=payload, session_id=session_id, **kwargs)
|
||||||
|
|
||||||
def _connect_to_server(
|
def _connect_to_server(
|
||||||
self, dest_ip_address: Optional[IPv4Address] = None, dest_port: Optional[Port] = Port.FTP
|
self,
|
||||||
|
dest_ip_address: Optional[IPv4Address] = None,
|
||||||
|
dest_port: Optional[Port] = Port.FTP,
|
||||||
|
is_reattempt: Optional[bool] = False,
|
||||||
) -> bool:
|
) -> bool:
|
||||||
"""
|
"""
|
||||||
Connects the client to a given FTP server.
|
Connects the client to a given FTP server.
|
||||||
|
|
||||||
:param: dest_ip_address: IP address of the FTP server the client needs to connect to. Optional.
|
:param: dest_ip_address: IP address of the FTP server the client needs to connect to. Optional.
|
||||||
:type: Optional[IPv4Address]
|
:type: dest_ip_address: Optional[IPv4Address]
|
||||||
:param: dest_port: Port of the FTP server the client needs to connect to. Optional.
|
:param: dest_port: Port of the FTP server the client needs to connect to. Optional.
|
||||||
:type: Optional[Port]
|
:type: dest_port: Optional[Port]
|
||||||
:param: server_password: The password to use when connecting to the FTP server. Optional.
|
:param: is_reattempt: Set to True if attempt to connect to FTP Server has been attempted. Default False.
|
||||||
:type: Optional[str]
|
:type: is_reattempt: Optional[bool]
|
||||||
"""
|
"""
|
||||||
# normally FTP will choose a random port for the transfer, but using the FTP command port will do for now
|
# make sure the service is running before attempting
|
||||||
|
if self.operating_state != ServiceOperatingState.RUNNING:
|
||||||
|
self.sys_log.error(f"FTPClient not running for {self.sys_log.hostname}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
# normally FTP will choose a random port for the transfer, but using the FTP command port will do for now
|
||||||
# create FTP packet
|
# create FTP packet
|
||||||
payload: FTPPacket = FTPPacket(
|
payload: FTPPacket = FTPPacket(
|
||||||
ftp_command=FTPCommand.PORT,
|
ftp_command=FTPCommand.PORT,
|
||||||
@@ -61,11 +76,30 @@ class FTPClient(FTPServiceABC):
|
|||||||
software_manager.send_payload_to_session_manager(
|
software_manager.send_payload_to_session_manager(
|
||||||
payload=payload, dest_ip_address=dest_ip_address, dest_port=dest_port
|
payload=payload, dest_ip_address=dest_ip_address, dest_port=dest_port
|
||||||
)
|
)
|
||||||
return payload.status_code == FTPStatusCode.OK
|
|
||||||
|
if payload.status_code == FTPStatusCode.OK:
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
if is_reattempt:
|
||||||
|
# reattempt failed
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
# try again
|
||||||
|
self._connect_to_server(dest_ip_address=dest_ip_address, dest_port=dest_port, is_reattempt=True)
|
||||||
|
|
||||||
def _disconnect_from_server(
|
def _disconnect_from_server(
|
||||||
self, dest_ip_address: Optional[IPv4Address] = None, dest_port: Optional[Port] = Port.FTP
|
self, dest_ip_address: Optional[IPv4Address] = None, dest_port: Optional[Port] = Port.FTP
|
||||||
) -> bool:
|
) -> bool:
|
||||||
|
"""
|
||||||
|
Connects the client from a given FTP server.
|
||||||
|
|
||||||
|
:param: dest_ip_address: IP address of the FTP server the client needs to disconnect from. Optional.
|
||||||
|
:type: dest_ip_address: Optional[IPv4Address]
|
||||||
|
:param: dest_port: Port of the FTP server the client needs to disconnect from. Optional.
|
||||||
|
:type: dest_port: Optional[Port]
|
||||||
|
:param: is_reattempt: Set to True if attempt to disconnect from FTP Server has been attempted. Default False.
|
||||||
|
:type: is_reattempt: Optional[bool]
|
||||||
|
"""
|
||||||
# send a disconnect request payload to FTP server
|
# send a disconnect request payload to FTP server
|
||||||
payload: FTPPacket = FTPPacket(ftp_command=FTPCommand.QUIT)
|
payload: FTPPacket = FTPPacket(ftp_command=FTPCommand.QUIT)
|
||||||
software_manager: SoftwareManager = self.software_manager
|
software_manager: SoftwareManager = self.software_manager
|
||||||
@@ -85,13 +119,32 @@ class FTPClient(FTPServiceABC):
|
|||||||
dest_folder_name: str,
|
dest_folder_name: str,
|
||||||
dest_file_name: str,
|
dest_file_name: str,
|
||||||
dest_port: Optional[Port] = Port.FTP,
|
dest_port: Optional[Port] = Port.FTP,
|
||||||
is_reattempt: Optional[bool] = False,
|
|
||||||
) -> bool:
|
) -> bool:
|
||||||
"""Send a file to a target IP address."""
|
"""
|
||||||
# if service is not running, return error
|
Send a file to a target IP address.
|
||||||
if self.operating_state != ServiceOperatingState.RUNNING:
|
|
||||||
self.sys_log.error(f"FTPClient not running for {self.sys_log.hostname}")
|
The function checks if the file exists in the FTP Client host.
|
||||||
return False
|
The STOR command is then sent to the FTP Server.
|
||||||
|
|
||||||
|
:param: dest_ip_address: The IP address of the machine that hosts the FTP Server.
|
||||||
|
:type: dest_ip_address: IPv4Address
|
||||||
|
|
||||||
|
:param: src_folder_name: The name of the folder that contains the file to send to the FTP Server.
|
||||||
|
:type: src_folder_name: str
|
||||||
|
|
||||||
|
:param: src_file_name: The name of the file to send to the FTP Server.
|
||||||
|
:type: src_file_name: str
|
||||||
|
|
||||||
|
:param: dest_folder_name: The name of the folder where the file will be stored in the FTP Server.
|
||||||
|
:type: dest_folder_name: str
|
||||||
|
|
||||||
|
:param: dest_file_name: The name of the file to be saved on the FTP Server.
|
||||||
|
:type: dest_file_name: str
|
||||||
|
|
||||||
|
:param: dest_port: The open port of the machine that hosts the FTP Server. Default is Port.FTP.
|
||||||
|
:type: dest_port: Optional[Port]
|
||||||
|
"""
|
||||||
|
# check if the file to transfer exists on the client
|
||||||
file_to_transfer: File = self.file_system.get_file(folder_name=src_folder_name, file_name=src_file_name)
|
file_to_transfer: File = self.file_system.get_file(folder_name=src_folder_name, file_name=src_file_name)
|
||||||
if not file_to_transfer:
|
if not file_to_transfer:
|
||||||
self.sys_log.error(f"Unable to send file that does not exist: {src_folder_name}/{src_file_name}")
|
self.sys_log.error(f"Unable to send file that does not exist: {src_folder_name}/{src_file_name}")
|
||||||
@@ -104,18 +157,7 @@ class FTPClient(FTPServiceABC):
|
|||||||
)
|
)
|
||||||
|
|
||||||
if not self.connected:
|
if not self.connected:
|
||||||
if is_reattempt:
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
return self.send_file(
|
|
||||||
src_folder_name=file_to_transfer.folder.name,
|
|
||||||
src_file_name=file_to_transfer.name,
|
|
||||||
dest_folder_name=dest_folder_name,
|
|
||||||
dest_file_name=dest_file_name,
|
|
||||||
dest_ip_address=dest_ip_address,
|
|
||||||
dest_port=dest_port,
|
|
||||||
is_reattempt=True,
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
# send STOR request
|
# send STOR request
|
||||||
self._send_data(
|
self._send_data(
|
||||||
@@ -137,13 +179,30 @@ class FTPClient(FTPServiceABC):
|
|||||||
dest_folder_name: str,
|
dest_folder_name: str,
|
||||||
dest_file_name: str,
|
dest_file_name: str,
|
||||||
dest_port: Optional[Port] = Port.FTP,
|
dest_port: Optional[Port] = Port.FTP,
|
||||||
is_reattempt: Optional[bool] = False,
|
|
||||||
) -> bool:
|
) -> bool:
|
||||||
"""Request a file from a target IP address."""
|
"""
|
||||||
# if service is not running, return error
|
Request a file from a target IP address.
|
||||||
if self.operating_state != ServiceOperatingState.RUNNING:
|
|
||||||
self.sys_log.error(f"FTPClient not running for {self.sys_log.hostname}")
|
Sends a RETR command to the FTP Server.
|
||||||
return False
|
|
||||||
|
:param: dest_ip_address: The IP address of the machine that hosts the FTP Server.
|
||||||
|
:type: dest_ip_address: IPv4Address
|
||||||
|
|
||||||
|
:param: src_folder_name: The name of the folder that contains the file to send to the FTP Server.
|
||||||
|
:type: src_folder_name: str
|
||||||
|
|
||||||
|
:param: src_file_name: The name of the file to send to the FTP Server.
|
||||||
|
:type: src_file_name: str
|
||||||
|
|
||||||
|
:param: dest_folder_name: The name of the folder where the file will be stored in the FTP Server.
|
||||||
|
:type: dest_folder_name: str
|
||||||
|
|
||||||
|
:param: dest_file_name: The name of the file to be saved on the FTP Server.
|
||||||
|
:type: dest_file_name: str
|
||||||
|
|
||||||
|
:param: dest_port: The open port of the machine that hosts the FTP Server. Default is Port.FTP.
|
||||||
|
:type: dest_port: Optional[Port]
|
||||||
|
"""
|
||||||
# check if FTP is currently connected to IP
|
# check if FTP is currently connected to IP
|
||||||
self.connected = self._connect_to_server(
|
self.connected = self._connect_to_server(
|
||||||
dest_ip_address=dest_ip_address,
|
dest_ip_address=dest_ip_address,
|
||||||
@@ -151,18 +210,7 @@ class FTPClient(FTPServiceABC):
|
|||||||
)
|
)
|
||||||
|
|
||||||
if not self.connected:
|
if not self.connected:
|
||||||
if is_reattempt:
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
return self.request_file(
|
|
||||||
src_folder_name=src_folder_name,
|
|
||||||
src_file_name=src_file_name,
|
|
||||||
dest_folder_name=dest_folder_name,
|
|
||||||
dest_file_name=dest_file_name,
|
|
||||||
dest_ip_address=dest_ip_address,
|
|
||||||
dest_port=dest_port,
|
|
||||||
is_reattempt=True,
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
# send retrieve request
|
# send retrieve request
|
||||||
payload: FTPPacket = FTPPacket(
|
payload: FTPPacket = FTPPacket(
|
||||||
@@ -191,7 +239,15 @@ class FTPClient(FTPServiceABC):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
def receive(self, payload: FTPPacket, session_id: Optional[str] = None, **kwargs) -> bool:
|
def receive(self, payload: FTPPacket, session_id: Optional[str] = None, **kwargs) -> bool:
|
||||||
"""Receives a payload from the SessionManager."""
|
"""
|
||||||
|
Receives a payload from the SessionManager.
|
||||||
|
|
||||||
|
:param: payload: FTPPacket payload.
|
||||||
|
:type: payload: FTPPacket
|
||||||
|
|
||||||
|
:param: session_id: ID of the session. Optional.
|
||||||
|
:type: session_id: Optional[str]
|
||||||
|
"""
|
||||||
if not isinstance(payload, FTPPacket):
|
if not isinstance(payload, FTPPacket):
|
||||||
self.sys_log.error(f"{payload} is not an FTP packet")
|
self.sys_log.error(f"{payload} is not an FTP packet")
|
||||||
return False
|
return False
|
||||||
|
|||||||
@@ -39,23 +39,31 @@ class FTPServer(FTPServiceABC):
|
|||||||
return self.software_manager.session_manager.sessions_by_uuid[session_id]
|
return self.software_manager.session_manager.sessions_by_uuid[session_id]
|
||||||
|
|
||||||
def _process_ftp_command(self, payload: FTPPacket, session_id: Optional[str] = None, **kwargs) -> FTPPacket:
|
def _process_ftp_command(self, payload: FTPPacket, session_id: Optional[str] = None, **kwargs) -> FTPPacket:
|
||||||
# if server is down, return error
|
"""
|
||||||
|
Process the command in the FTP Packet.
|
||||||
|
|
||||||
|
:param: payload: The FTP Packet to process
|
||||||
|
:type: payload: FTPPacket
|
||||||
|
:param: session_id: session ID linked to the FTP Packet. Optional.
|
||||||
|
:type: session_id: Optional[str]
|
||||||
|
"""
|
||||||
|
# if server service is down, return error
|
||||||
if self.operating_state != ServiceOperatingState.RUNNING:
|
if self.operating_state != ServiceOperatingState.RUNNING:
|
||||||
payload.status_code = FTPStatusCode.ERROR
|
payload.status_code = FTPStatusCode.ERROR
|
||||||
return payload
|
return payload
|
||||||
|
|
||||||
|
session_details = self._get_session_details(session_id)
|
||||||
|
|
||||||
# process server specific commands, otherwise call super
|
# process server specific commands, otherwise call super
|
||||||
if payload.ftp_command == FTPCommand.PORT:
|
if payload.ftp_command == FTPCommand.PORT:
|
||||||
# check that the port is valid
|
# check that the port is valid
|
||||||
if isinstance(payload.ftp_command_args, Port) and payload.ftp_command_args.value in range(0, 65535):
|
if isinstance(payload.ftp_command_args, Port) and payload.ftp_command_args.value in range(0, 65535):
|
||||||
# return successful connection
|
# return successful connection
|
||||||
session_details = self._get_session_details(session_id)
|
|
||||||
self.connections[session_id] = session_details.with_ip_address
|
self.connections[session_id] = session_details.with_ip_address
|
||||||
payload.status_code = FTPStatusCode.OK
|
payload.status_code = FTPStatusCode.OK
|
||||||
return payload
|
return payload
|
||||||
|
|
||||||
if payload.ftp_command == FTPCommand.QUIT:
|
if payload.ftp_command == FTPCommand.QUIT:
|
||||||
session_details = self._get_session_details(session_id)
|
|
||||||
self.connections.pop(session_id)
|
self.connections.pop(session_id)
|
||||||
payload.status_code = FTPStatusCode.OK
|
payload.status_code = FTPStatusCode.OK
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,14 @@ class FTPServiceABC(Service, ABC):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
def _process_ftp_command(self, payload: FTPPacket, session_id: Optional[str] = None, **kwargs) -> FTPPacket:
|
def _process_ftp_command(self, payload: FTPPacket, session_id: Optional[str] = None, **kwargs) -> FTPPacket:
|
||||||
|
"""
|
||||||
|
Process the command in the FTP Packet.
|
||||||
|
|
||||||
|
:param: payload: The FTP Packet to process
|
||||||
|
:type: payload: FTPPacket
|
||||||
|
:param: session_id: session ID linked to the FTP Packet. Optional.
|
||||||
|
:type: session_id: Optional[str]
|
||||||
|
"""
|
||||||
# handle STOR request
|
# handle STOR request
|
||||||
if payload.ftp_command == FTPCommand.STOR:
|
if payload.ftp_command == FTPCommand.STOR:
|
||||||
# check that the file is created in the computed hosting the FTP server
|
# check that the file is created in the computed hosting the FTP server
|
||||||
@@ -24,25 +32,14 @@ class FTPServiceABC(Service, ABC):
|
|||||||
payload.status_code = FTPStatusCode.OK
|
payload.status_code = FTPStatusCode.OK
|
||||||
|
|
||||||
if payload.ftp_command == FTPCommand.RETR:
|
if payload.ftp_command == FTPCommand.RETR:
|
||||||
# check that the file exists in the FTP Server
|
if self._retrieve_data(payload=payload, session_id=session_id):
|
||||||
file: File = self.file_system.get_file(
|
|
||||||
folder_name=payload.ftp_command_args["src_folder_name"],
|
|
||||||
file_name=payload.ftp_command_args["src_file_name"],
|
|
||||||
)
|
|
||||||
if file:
|
|
||||||
payload.status_code = FTPStatusCode.OK
|
payload.status_code = FTPStatusCode.OK
|
||||||
self._send_data(
|
|
||||||
file=file,
|
|
||||||
dest_folder_name=payload.ftp_command_args["dest_folder_name"],
|
|
||||||
dest_file_name=payload.ftp_command_args["dest_file_name"],
|
|
||||||
session_id=session_id,
|
|
||||||
)
|
|
||||||
|
|
||||||
return payload
|
return payload
|
||||||
|
|
||||||
def _store_data(self, payload: FTPPacket) -> bool:
|
def _store_data(self, payload: FTPPacket) -> bool:
|
||||||
"""
|
"""
|
||||||
Handle the transfer of data.
|
Stores the data in the FTP Service's host machine.
|
||||||
|
|
||||||
:param: payload: The FTP Packet that contains the file data
|
:param: payload: The FTP Packet that contains the file data
|
||||||
:type: FTPPacket
|
:type: FTPPacket
|
||||||
@@ -75,6 +72,27 @@ class FTPServiceABC(Service, ABC):
|
|||||||
dest_port: Optional[Port] = None,
|
dest_port: Optional[Port] = None,
|
||||||
session_id: Optional[str] = None,
|
session_id: Optional[str] = None,
|
||||||
) -> bool:
|
) -> bool:
|
||||||
|
"""
|
||||||
|
Sends data from the host FTP Service's machine to another FTP Service's host machine.
|
||||||
|
|
||||||
|
:param: file: File to send to the target FTP Service.
|
||||||
|
:type: file: File
|
||||||
|
|
||||||
|
:param: dest_folder_name: The name of the folder where the file will be stored in the FTP Server.
|
||||||
|
:type: dest_folder_name: str
|
||||||
|
|
||||||
|
:param: dest_file_name: The name of the file to be saved on the FTP Server.
|
||||||
|
:type: dest_file_name: str
|
||||||
|
|
||||||
|
:param: dest_ip_address: The IP address of the machine that hosts the FTP Server.
|
||||||
|
:type: dest_ip_address: Optional[IPv4Address]
|
||||||
|
|
||||||
|
:param: dest_port: The open port of the machine that hosts the FTP Server. Default is Port.FTP.
|
||||||
|
:type: dest_port: Optional[Port]
|
||||||
|
|
||||||
|
:param: session_id: session ID linked to the FTP Packet. Optional.
|
||||||
|
:type: session_id: Optional[str]
|
||||||
|
"""
|
||||||
# send STOR request
|
# send STOR request
|
||||||
payload: FTPPacket = FTPPacket(
|
payload: FTPPacket = FTPPacket(
|
||||||
ftp_command=FTPCommand.STOR,
|
ftp_command=FTPCommand.STOR,
|
||||||
@@ -106,6 +124,8 @@ class FTPServiceABC(Service, ABC):
|
|||||||
# find the file
|
# find the file
|
||||||
file_name = payload.ftp_command_args["src_file_name"]
|
file_name = payload.ftp_command_args["src_file_name"]
|
||||||
folder_name = payload.ftp_command_args["src_folder_name"]
|
folder_name = payload.ftp_command_args["src_folder_name"]
|
||||||
|
dest_folder_name = payload.ftp_command_args["dest_folder_name"]
|
||||||
|
dest_file_name = payload.ftp_command_args["dest_file_name"]
|
||||||
retrieved_file: File = self.file_system.get_file(folder_name=folder_name, file_name=file_name)
|
retrieved_file: File = self.file_system.get_file(folder_name=folder_name, file_name=file_name)
|
||||||
|
|
||||||
# if file does not exist, return an error
|
# if file does not exist, return an error
|
||||||
@@ -118,7 +138,10 @@ class FTPServiceABC(Service, ABC):
|
|||||||
else:
|
else:
|
||||||
# send requested data
|
# send requested data
|
||||||
return self._send_data(
|
return self._send_data(
|
||||||
file=retrieved_file, dest_file_name=file_name, dest_folder_name=folder_name, session_id=session_id
|
file=retrieved_file,
|
||||||
|
dest_file_name=dest_file_name,
|
||||||
|
dest_folder_name=dest_folder_name,
|
||||||
|
session_id=session_id,
|
||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.sys_log.error(f"Unable to retrieve file from {self.sys_log.hostname}: {e}")
|
self.sys_log.error(f"Unable to retrieve file from {self.sys_log.hostname}: {e}")
|
||||||
|
|||||||
Reference in New Issue
Block a user