Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ability to redirect all prints #75

Merged
merged 9 commits into from
Jan 15, 2025
9 changes: 7 additions & 2 deletions fineftp-server/include/fineftp/server.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <cstdint>
#include <memory>
#include <string>
#include <iostream>

// IWYU pragma: begin_exports
#include <fineftp/permissions.h>
Expand Down Expand Up @@ -52,8 +53,10 @@ namespace fineftp
*
* @param port: The port to start the FTP server on. Defaults to 21.
* @param host: The host to accept incoming connections from.
* @param output: Normal output prints. Defaults to std::cout.
* @param error: Error output prints. Defaults to std::cerr.
*/
FINEFTP_EXPORT FtpServer(const std::string& address, uint16_t port = 21);
FINEFTP_EXPORT FtpServer(const std::string& address, const uint16_t port = 21, std::ostream& output = std::cout, std::ostream& error = std::cerr);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

port should not be const, as it is passed by value (will give warnings otherwise)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have no issue reverting it, but I never saw an issue with a const for any C or C++ int types when by-value is used (by-ref might be an issue)
(I try to use const on every param method to avoid typos or incorrect assignment)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you give an example of where you might think it will fail?


/**
* @brief Creates an FTP Server instance that will listen on the the given control port.
Expand All @@ -71,8 +74,10 @@ namespace fineftp
* address. Use FtpServer(const std::string&, uint16_t) for that purpose.
*
* @param port: The port to start the FTP server on. Defaults to 21.
* @param output: Normal output prints. Defaults to std::cout.
* @param error: Error output prints. Defaults to std::cerr.
*/
FINEFTP_EXPORT FtpServer(uint16_t port = 21);
FINEFTP_EXPORT FtpServer(const uint16_t port = 21, std::ostream& output = std::cout, std::ostream& error = std::cerr);

// Move
FINEFTP_EXPORT FtpServer(FtpServer&&) noexcept;
Expand Down
6 changes: 3 additions & 3 deletions fineftp-server/src/filesystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@ namespace Filesystem
return can_open_dir;
}

std::map<std::string, FileStatus> dirContent(const std::string& path)
std::map<std::string, FileStatus> dirContent(const std::string& path, std::ostream& error)
{
std::map<std::string, FileStatus> content;
#ifdef WIN32
Expand All @@ -297,7 +297,7 @@ namespace Filesystem
hFind = FindFirstFileW(w_find_file_path.c_str(), &ffd);
if (hFind == INVALID_HANDLE_VALUE)
{
std::cerr << "FindFirstFile Error" << std::endl;
error_ << "FindFirstFile Error" << std::endl;
return content;
}

Expand All @@ -312,7 +312,7 @@ namespace Filesystem
struct dirent *dirp = nullptr;
if(dp == nullptr)
{
std::cerr << "Error opening directory: " << strerror(errno) << std::endl;
error << "Error opening directory: " << strerror(errno) << std::endl;
return content;
}

Expand Down
3 changes: 2 additions & 1 deletion fineftp-server/src/filesystem.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <cstdint>
#include <map>
#include <string>
#include <iostream>

#include <sys/stat.h>

Expand Down Expand Up @@ -68,7 +69,7 @@ namespace fineftp
#endif
};

std::map<std::string, FileStatus> dirContent(const std::string& path);
std::map<std::string, FileStatus> dirContent(const std::string& path, std::ostream& error);

std::string cleanPath(const std::string& path, bool path_is_windows_path, char output_separator);

Expand Down
34 changes: 18 additions & 16 deletions fineftp-server/src/ftp_session.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
namespace fineftp
{

FtpSession::FtpSession(asio::io_service& io_service, const UserDatabase& user_database, const std::function<void()>& completion_handler)
FtpSession::FtpSession(asio::io_service& io_service, const UserDatabase& user_database, const std::function<void()>& completion_handler, std::ostream& output, std::ostream& error)
: completion_handler_ (completion_handler)
, user_database_ (user_database)
, io_service_ (io_service)
Expand All @@ -49,13 +49,15 @@ namespace fineftp
, data_acceptor_ (io_service)
, data_socket_strand_ (io_service)
, timer_ (io_service)
, output_(output)
, error_(error)
{
}

FtpSession::~FtpSession()
{
#ifndef NDEBUG
std::cout << "Ftp Session shutting down" << std::endl;
output_ << "Ftp Session shutting down" << std::endl;
#endif // !NDEBUG

{
Expand Down Expand Up @@ -85,7 +87,7 @@ namespace fineftp
{
asio::error_code ec;
command_socket_.set_option(asio::ip::tcp::no_delay(true), ec);
if (ec) std::cerr << "Unable to set socket option tcp::no_delay: " << ec.message() << std::endl;
if (ec) error_ << "Unable to set socket option tcp::no_delay: " << ec.message() << std::endl;

command_strand_.post([me = shared_from_this()]() { me->readFtpCommand(); });
sendFtpMessage(FtpMessage(FtpReplyCode::SERVICE_READY_FOR_NEW_USER, "Welcome to fineFTP Server"));
Expand Down Expand Up @@ -121,7 +123,7 @@ namespace fineftp
void FtpSession::startSendingMessages()
{
#ifndef NDEBUG
std::cout << "FTP >> " << command_output_queue_.front() << std::endl;
output_ << "FTP >> " << command_output_queue_.front() << std::endl;
#endif

asio::async_write(command_socket_
Expand Down Expand Up @@ -150,7 +152,7 @@ namespace fineftp
}
else
{
std::cerr << "Command write error for message " << me->command_output_queue_.front() << ec.message() << std::endl;
me->error_ << "Command write error for message " << me->command_output_queue_.front() << ec.message() << std::endl;
}
}
));
Expand All @@ -165,12 +167,12 @@ namespace fineftp
{
if (ec != asio::error::eof)
{
std::cerr << "read_until error: " << ec.message() << std::endl;
me->error_ << "read_until error: " << ec.message() << std::endl;
}
#ifndef NDEBUG
else
{
std::cout << "Control connection closed by client." << std::endl;
me->output_ << "Control connection closed by client." << std::endl;
}
#endif // !NDEBUG
// Close the data connection, if it is open
Expand Down Expand Up @@ -198,7 +200,7 @@ namespace fineftp

stream.ignore(2); // Remove the "\r\n"
#ifndef NDEBUG
std::cout << "FTP << " << packet_string << std::endl;
me->output_ << "FTP << " << packet_string << std::endl;
#endif

me->handleFtpCommand(packet_string);
Expand Down Expand Up @@ -412,7 +414,7 @@ namespace fineftp
data_acceptor_.close(ec);
if (ec)
{
std::cerr << "Error closing data acceptor: " << ec.message() << std::endl;
error_ << "Error closing data acceptor: " << ec.message() << std::endl;
}
}

Expand All @@ -423,7 +425,7 @@ namespace fineftp
data_acceptor_.open(endpoint.protocol(), ec);
if (ec)
{
std::cerr << "Error opening data acceptor: " << ec.message() << std::endl;
error_ << "Error opening data acceptor: " << ec.message() << std::endl;
sendFtpMessage(FtpReplyCode::SERVICE_NOT_AVAILABLE, "Failed to enter passive mode.");
return;
}
Expand All @@ -433,7 +435,7 @@ namespace fineftp
data_acceptor_.bind(endpoint, ec);
if (ec)
{
std::cerr << "Error binding data acceptor: " << ec.message() << std::endl;
error_ << "Error binding data acceptor: " << ec.message() << std::endl;
sendFtpMessage(FtpReplyCode::SERVICE_NOT_AVAILABLE, "Failed to enter passive mode.");
return;
}
Expand All @@ -443,7 +445,7 @@ namespace fineftp
data_acceptor_.listen(asio::socket_base::max_connections, ec);
if (ec)
{
std::cerr << "Error listening on data acceptor: " << ec.message() << std::endl;
error_ << "Error listening on data acceptor: " << ec.message() << std::endl;
sendFtpMessage(FtpReplyCode::SERVICE_NOT_AVAILABLE, "Failed to enter passive mode.");
return;
}
Expand Down Expand Up @@ -1060,7 +1062,7 @@ namespace fineftp
if (dir_status.canOpenDir())
{
sendFtpMessage(FtpReplyCode::FILE_STATUS_OK_OPENING_DATA_CONNECTION, "Sending directory listing");
sendDirectoryListing(Filesystem::dirContent(local_path));
sendDirectoryListing(Filesystem::dirContent(local_path, error_));
return;
}
else
Expand Down Expand Up @@ -1108,7 +1110,7 @@ namespace fineftp
if (dir_status.canOpenDir())
{
sendFtpMessage(FtpReplyCode::FILE_STATUS_OK_OPENING_DATA_CONNECTION, "Sending name list");
sendNameList(Filesystem::dirContent(local_path));
sendNameList(Filesystem::dirContent(local_path, error_));
return;
}
else
Expand Down Expand Up @@ -1374,7 +1376,7 @@ namespace fineftp

if (ec)
{
std::cerr << "Data write error: " << ec.message() << std::endl;
me->error_ << "Data write error: " << ec.message() << std::endl;
return;
}

Expand Down Expand Up @@ -1415,7 +1417,7 @@ namespace fineftp
{
if (ec)
{
std::cerr << "Data transfer aborted: " << ec.message() << std::endl;
me->error_ << "Data transfer aborted: " << ec.message() << std::endl;
me->sendFtpMessage(FtpReplyCode::TRANSFER_ABORTED, "Data transfer aborted");
return;
}
Expand Down
5 changes: 4 additions & 1 deletion fineftp-server/src/ftp_session.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ namespace fineftp
// Public API
////////////////////////////////////////////////////////
public:
FtpSession(asio::io_service& io_service, const UserDatabase& user_database, const std::function<void()>& completion_handler);
FtpSession(asio::io_service& io_service, const UserDatabase& user_database, const std::function<void()>& completion_handler, std::ostream& output, std::ostream& error);

// Copy (disabled, as we are inheriting from shared_from_this)
FtpSession(const FtpSession&) = delete;
Expand Down Expand Up @@ -209,5 +209,8 @@ namespace fineftp
std::deque<std::shared_ptr<std::vector<char>>> data_buffer_;

asio::steady_timer timer_;

std::ostream& output_; /* Normal output log */
std::ostream& error_; /* Error output log */
};
}
8 changes: 4 additions & 4 deletions fineftp-server/src/server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@

namespace fineftp
{
FtpServer::FtpServer(const std::string& address, uint16_t port)
: ftp_server_(std::make_unique<FtpServerImpl>(address, port))
FtpServer::FtpServer(const std::string& address, const uint16_t port, std::ostream& output, std::ostream& error)
: ftp_server_(std::make_unique<FtpServerImpl>(address, port, output, error))
{}

FtpServer::FtpServer(uint16_t port)
: FtpServer(std::string("0.0.0.0"), port)
FtpServer::FtpServer(const uint16_t port, std::ostream& output, std::ostream& error)
: FtpServer(std::string("0.0.0.0"), port, output, error)
{}

// Move
Expand Down
27 changes: 15 additions & 12 deletions fineftp-server/src/server_impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,14 @@
namespace fineftp
{

FtpServerImpl::FtpServerImpl(const std::string& address, uint16_t port)
: port_ (port)
FtpServerImpl::FtpServerImpl(const std::string& address, const uint16_t port, std::ostream& output, std::ostream& error)
: ftp_users_(output, error)
, port_ (port)
, address_ (address)
, acceptor_ (io_service_)
, open_connection_count_(0)
, output_(output)
, error_(error)
{}

FtpServerImpl::~FtpServerImpl()
Expand All @@ -40,14 +43,14 @@ namespace fineftp

bool FtpServerImpl::start(size_t thread_count)
{
auto ftp_session = std::make_shared<FtpSession>(io_service_, ftp_users_, [this]() { open_connection_count_--; });
auto ftp_session = std::make_shared<FtpSession>(io_service_, ftp_users_, [this]() { open_connection_count_--; }, output_, error_);

// set up the acceptor to listen on the tcp port
asio::error_code make_address_ec;
const asio::ip::tcp::endpoint endpoint(asio::ip::make_address(address_, make_address_ec), port_);
if (make_address_ec)
{
std::cerr << "Error creating address from string \"" << address_<< "\": " << make_address_ec.message() << std::endl;
error_ << "Error creating address from string \"" << address_<< "\": " << make_address_ec.message() << std::endl;
return false;
}

Expand All @@ -56,7 +59,7 @@ namespace fineftp
acceptor_.open(endpoint.protocol(), ec);
if (ec)
{
std::cerr << "Error opening acceptor: " << ec.message() << std::endl;
error_ << "Error opening acceptor: " << ec.message() << std::endl;
return false;
}
}
Expand All @@ -66,7 +69,7 @@ namespace fineftp
acceptor_.set_option(asio::ip::tcp::acceptor::reuse_address(true), ec);
if (ec)
{
std::cerr << "Error setting reuse_address option: " << ec.message() << std::endl;
error_ << "Error setting reuse_address option: " << ec.message() << std::endl;
return false;
}
}
Expand All @@ -76,7 +79,7 @@ namespace fineftp
acceptor_.bind(endpoint, ec);
if (ec)
{
std::cerr << "Error binding acceptor: " << ec.message() << std::endl;
error_ << "Error binding acceptor: " << ec.message() << std::endl;
return false;
}
}
Expand All @@ -86,13 +89,13 @@ namespace fineftp
acceptor_.listen(asio::socket_base::max_listen_connections, ec);
if (ec)
{
std::cerr << "Error listening on acceptor: " << ec.message() << std::endl;
error_ << "Error listening on acceptor: " << ec.message() << std::endl;
return false;
}
}

#ifndef NDEBUG
std::cout << "FTP Server created." << std::endl << "Listening at address " << acceptor_.local_endpoint().address() << " on port " << acceptor_.local_endpoint().port() << ":" << std::endl;
output_ << "FTP Server created." << std::endl << "Listening at address " << acceptor_.local_endpoint().address() << " on port " << acceptor_.local_endpoint().port() << ":" << std::endl;
#endif // NDEBUG

acceptor_.async_accept(ftp_session->getSocket()
Expand Down Expand Up @@ -126,18 +129,18 @@ namespace fineftp
if (error)
{
#ifndef NDEBUG
std::cerr << "Error handling connection: " << error.message() << std::endl;
error_ << "Error handling connection: " << error.message() << std::endl;
#endif
return;
}

#ifndef NDEBUG
std::cout << "FTP Client connected: " << ftp_session->getSocket().remote_endpoint().address().to_string() << ":" << ftp_session->getSocket().remote_endpoint().port() << std::endl;
output_ << "FTP Client connected: " << ftp_session->getSocket().remote_endpoint().address().to_string() << ":" << ftp_session->getSocket().remote_endpoint().port() << std::endl;
#endif

ftp_session->start();

auto new_session = std::make_shared<FtpSession>(io_service_, ftp_users_, [this]() { open_connection_count_--; });
auto new_session = std::make_shared<FtpSession>(io_service_, ftp_users_, [this]() { open_connection_count_--; }, output_, error_);

acceptor_.async_accept(new_session->getSocket()
, [this, new_session](auto ec)
Expand Down
5 changes: 4 additions & 1 deletion fineftp-server/src/server_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ namespace fineftp
class FtpServerImpl
{
public:
FtpServerImpl(const std::string& address, uint16_t port);
FtpServerImpl(const std::string& address, const uint16_t port, std::ostream& output, std::ostream& error);

// Copy (disabled)
FtpServerImpl(const FtpServerImpl&) = delete;
Expand Down Expand Up @@ -59,5 +59,8 @@ namespace fineftp
asio::ip::tcp::acceptor acceptor_;

std::atomic<int> open_connection_count_;

std::ostream& output_; /* Normal output log */
std::ostream& error_; /* Error output log */
};
}
Loading
Loading