SatCat5
file_tftp.cc
1 // Copyright 2024 The Aerospace Corporation.
3 // This file is a part of SatCat5, licensed under CERN-OHL-W v2 or later.
5 
6 #include <hal_posix/file_tftp.h>
8 #include <vector>
9 
10 // Additional includes for specific platforms:
11 #if SATCAT5_WIN32
12  static const char* PATH_SEP = "\\";
13 #else
14  static const char* PATH_SEP = "/";
15 #endif
16 
17 // Shortcuts for commonly used names.
20 
21 TftpClientPosix::TftpClientPosix(satcat5::udp::Dispatch* iface)
22  : m_dst(0, true) // Close on finalize
23  , m_src(0, true) // Close on finalize
24  , m_tftp(iface)
25 {
26  // No other initialization required.
27 }
28 
29 TftpClientPosix::~TftpClientPosix()
30 {
31  m_dst.close();
32  m_src.close();
33 }
34 
36  const satcat5::ip::Addr& server,
37  const char* filename_local,
38  const char* filename_remote)
39 {
40  m_dst.open(filename_local);
41  m_tftp.begin_download(&m_dst, server, filename_remote);
42 }
43 
45  const satcat5::ip::Addr& server,
46  const char* filename_local,
47  const char* filename_remote)
48 {
49  m_src.open(filename_local);
50  if (m_src.get_read_ready() > 0)
51  m_tftp.begin_upload(&m_src, server, filename_remote);
52  else
53  log::Log(log::ERROR, "TftpClient: File not found", filename_local);
54 }
55 
58  const char* work_folder)
59  : satcat5::udp::TftpServerCore(iface)
60  , m_work_folder(std::string(work_folder) + PATH_SEP)
61  , m_dst(0, true) // Close on finalize
62  , m_src(0, true) // Close on finalize
63 {
64  // No other initialization required.
65 }
66 
67 TftpServerPosix::~TftpServerPosix()
68 {
69  m_dst.close();
70  m_src.close();
71 }
72 
73 std::string TftpServerPosix::check_path(const char* filename)
74 {
75  // Sanity check: There must be a defined working folder,
76  // and it must not contain the ".." token.
77  if (!filename) return std::string();
78  std::string filename2(filename);
79  if (filename2.find("..") != std::string::npos) return std::string();
80  return m_work_folder + filename2;
81 }
82 
84 {
85  // Check filename is inside the working folder.
86  std::string safe_path = check_path(filename);
87  if (safe_path.empty()) {
88  log::Log(log::INFO, "TftpServer: Rejected read", filename);
89  return 0;
90  } else {
91  m_src.open(safe_path.c_str());
92  if (m_src.get_read_ready() > 0) {
93  log::Log(log::INFO, "TftpServer: Reading", safe_path.c_str())
94  .write(", length").write10(m_src.get_read_ready());
95  return &m_src;
96  } else {
97  log::Log(log::INFO, "TftpServer: File not found", filename);
98  return 0;
99  }
100  }
101 }
102 
103 satcat5::io::Writeable* TftpServerPosix::write(const char* filename)
104 {
105  // Check filename is inside the working folder.
106  std::string safe_path = check_path(filename);
107  if (safe_path.empty()) {
108  log::Log(log::INFO, "TftpServer: Rejected write", filename);
109  return 0;
110  } else {
111  m_dst.open(safe_path.c_str());
112  if (m_dst.get_write_space() > 0) {
113  log::Log(log::INFO, "TftpServer: Writing", safe_path.c_str());
114  return &m_dst;
115  } else {
116  log::Log(log::WARNING, "TftpServer: Unable to open", safe_path.c_str());
117  return 0;
118  }
119  }
120 }
void open(const char *filename, unsigned len=0)
Open the specified file to read the next frame.
Definition: file_io.cc:103
unsigned get_read_ready() const override
How many bytes can be read without blocking?
Definition: file_io.cc:127
unsigned get_write_space() const override
How many bytes can be written without blocking?
Definition: file_io.cc:53
void open(const char *filename)
Open the specified file.
Definition: file_io.cc:33
Abstract API for reading byte-streams and packets.
Definition: io_readable.h:68
Abstract API for writing byte-streams and packets.
Definition: io_writeable.h:24
The Log class creates and formats one log message.
Definition: log.h:195
Log & write10(s32 val)
Print integer as a decimal value with no leading zeros.
Definition: log.cc:261
Log & write(const char *str)
Formatting methods for various data types.
Definition: log.cc:198
Dispatcher sorts incoming UDP messages by port index.
Definition: udp_dispatch.h:20
void begin_upload(satcat5::io::Readable *src, const satcat5::ip::Addr &server, const char *filename)
Upload data from a Readable stream to the server.
Definition: udp_tftp.cc:431
void begin_download(satcat5::io::Writeable *dst, const satcat5::ip::Addr &server, const char *filename)
Download a file from server to a Writeable stream.
Definition: udp_tftp.cc:421
A TFTP client that makes request(s) to a remote server.
Definition: file_tftp.h:18
void begin_upload(const satcat5::ip::Addr &server, const char *filename_local, const char *filename_remote)
Upload data from a Readable stream to the server.
Definition: file_tftp.cc:44
void begin_download(const satcat5::ip::Addr &server, const char *filename_local, const char *filename_remote)
Download a file from server to a Writeable stream.
Definition: file_tftp.cc:35
ServerCore is the base class that handles TFTP network functions.
Definition: udp_tftp.h:150
A TFTP server handles requests from remote clients.
Definition: file_tftp.h:57
std::string check_path(const char *filename)
Check if a user-supplied path is safe to use.
Definition: file_tftp.cc:73
satcat5::io::Readable * read(const char *filename) override
Child class MUST override these methods.
Definition: file_tftp.cc:83
TftpServerPosix(satcat5::udp::Dispatch *iface, const char *work_folder)
Attach this TFTP server to a network interface.
Definition: file_tftp.cc:56
Miscellaneous POSIX wrappers (e.g., heap allocation, log to console...)
IPv4 address is a 32-bit unsigned integer.
Definition: ip_core.h:15