Skip to content

Commit 792d40a

Browse files
Merge branch 'master' of https://github.com/eclipse-ecal/fineftp-server into hotfix/properly_close_sockets
# Conflicts: # fineftp-server/src/ftp_session.cpp # fineftp-server/src/ftp_session.h # fineftp-server/src/server.cpp # fineftp-server/src/server_impl.cpp # fineftp-server/src/server_impl.h
2 parents 1d4d224 + 1f08ffa commit 792d40a

File tree

12 files changed

+127
-51
lines changed

12 files changed

+127
-51
lines changed

fineftp-server/include/fineftp/server.h

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include <cstdint>
55
#include <memory>
66
#include <string>
7+
#include <iostream>
78

89
// IWYU pragma: begin_exports
910
#include <fineftp/permissions.h>
@@ -40,6 +41,25 @@ namespace fineftp
4041
class FtpServer
4142
{
4243
public:
44+
/**
45+
* @brief Creates an FTP Server instance that will listen on the the given control port and accept connections from the given network interface.
46+
*
47+
* Instead of binding the server to a specific address, the server can
48+
* listen on any interface by providing "0.0.0.0" as address.
49+
*
50+
* Instead of using a predefined port, the operating system can choose a
51+
* free port port. Use port=0, if that behaviour is desired. The chosen port
52+
* can be determined by with getPort().
53+
*
54+
* This constructor will accept streams for info and error log output.
55+
*
56+
* @param address: The address to accept incoming connections from. Use "0.0.0.0" to accept connections from any address.
57+
* @param port: The port to start the FTP server on. Use 0 to let the operating system choose a free port. Use 21 for using the default FTP port.
58+
* @param output: Stream for info log output. Defaults to std::cout if constructors without that options are used.
59+
* @param error: Stream for error log output. Defaults to std::cerr if constructors without that options are used.
60+
*/
61+
FINEFTP_EXPORT FtpServer(const std::string& address, uint16_t port, std::ostream& output, std::ostream& error);
62+
4363
/**
4464
* @brief Creates an FTP Server instance that will listen on the the given control port and accept connections from the given network interface.
4565
*
@@ -50,6 +70,9 @@ namespace fineftp
5070
* free port port. Use port=0, if that behaviour is desired. The chosen port
5171
* can be determined by with getPort().
5272
*
73+
* Logs will be printed to std::cout and std::cerr. If you want to use a
74+
* different output stream, use the other constructor.
75+
*
5376
* @param port: The port to start the FTP server on. Defaults to 21.
5477
* @param host: The host to accept incoming connections from.
5578
*/
@@ -64,15 +87,18 @@ namespace fineftp
6487
* Instead of using a predefined port, the operating system can choose a
6588
* free port port. Use port=0, if that behaviour is desired. The chosen port
6689
* can be determined by with getPort().
67-
*
90+
*
6891
* This constructor will create an FTP Server binding to IPv4 0.0.0.0 and
6992
* Thus accepting connections from any IPv4 address.
7093
* For security reasons it might be desirable to bind to a specific IP
7194
* address. Use FtpServer(const std::string&, uint16_t) for that purpose.
72-
*
95+
*
96+
* Logs will be printed to std::cout and std::cerr. If you want to use a
97+
* different output stream, use the other constructor.
98+
*
7399
* @param port: The port to start the FTP server on. Defaults to 21.
74100
*/
75-
FINEFTP_EXPORT FtpServer(uint16_t port = 21);
101+
FINEFTP_EXPORT explicit FtpServer(uint16_t port = 21);
76102

77103
// Move
78104
FINEFTP_EXPORT FtpServer(FtpServer&&) noexcept;
@@ -103,11 +129,11 @@ namespace fineftp
103129
* @param password: The user's password
104130
* @param local_root_path: A path to any resource on the local filesystem that will be accessed by the user
105131
* @param permissions: A bit-mask of what the user will be able to do.
106-
*
132+
*
107133
* @return True if adding the user was successful (i.e. it didn't exit already).
108134
*/
109135
FINEFTP_EXPORT bool addUser(const std::string& username, const std::string& password, const std::string& local_root_path, Permission permissions);
110-
136+
111137
/**
112138
* @brief Adds the "anonymous" / "ftp" user that FTP clients use to access FTP servers without password
113139
*
@@ -137,7 +163,7 @@ namespace fineftp
137163

138164
/**
139165
* @brief Returns the number of currently open connections
140-
*
166+
*
141167
* @return the number of open connections
142168
*/
143169
FINEFTP_EXPORT int getOpenConnectionCount() const;

fineftp-server/src/filesystem.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -283,7 +283,7 @@ namespace Filesystem
283283
return can_open_dir;
284284
}
285285

286-
std::map<std::string, FileStatus> dirContent(const std::string& path)
286+
std::map<std::string, FileStatus> dirContent(const std::string& path, std::ostream& error)
287287
{
288288
std::map<std::string, FileStatus> content;
289289
#ifdef WIN32
@@ -297,7 +297,7 @@ namespace Filesystem
297297
hFind = FindFirstFileW(w_find_file_path.c_str(), &ffd);
298298
if (hFind == INVALID_HANDLE_VALUE)
299299
{
300-
std::cerr << "FindFirstFile Error" << std::endl;
300+
error << "FindFirstFile Error" << std::endl;
301301
return content;
302302
}
303303

@@ -312,7 +312,7 @@ namespace Filesystem
312312
struct dirent *dirp = nullptr;
313313
if(dp == nullptr)
314314
{
315-
std::cerr << "Error opening directory: " << strerror(errno) << std::endl;
315+
error << "Error opening directory: " << strerror(errno) << std::endl;
316316
return content;
317317
}
318318

fineftp-server/src/filesystem.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include <cstdint>
44
#include <map>
55
#include <string>
6+
#include <iostream>
67

78
#include <sys/stat.h>
89

@@ -68,7 +69,7 @@ namespace fineftp
6869
#endif
6970
};
7071

71-
std::map<std::string, FileStatus> dirContent(const std::string& path);
72+
std::map<std::string, FileStatus> dirContent(const std::string& path, std::ostream& error);
7273

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

fineftp-server/src/ftp_session.cpp

Lines changed: 26 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
#include "ftp_session.h"
22

3+
#include <asio.hpp>
4+
35
#include <algorithm>
46
#include <cassert> // assert
57
#include <cctype> // std::iscntrl, toupper
6-
#include <chrono>
8+
#include <chrono> // IWYU pragma: keep (it is used for special preprocessor defines)
79
#include <cstddef>
810
#include <cstdio>
911
#include <fstream>
@@ -28,6 +30,11 @@
2830
#include <sys/stat.h>
2931

3032
#ifdef WIN32
33+
#define WIN32_LEAN_AND_MEAN
34+
#ifndef NOMINMAX
35+
#define NOMINMAX
36+
#endif
37+
#include <windows.h>
3138
#include "win_str_convert.h"
3239
#else
3340
#include <unistd.h>
@@ -37,7 +44,7 @@
3744
namespace fineftp
3845
{
3946

40-
FtpSession::FtpSession(asio::io_service& io_service, const UserDatabase& user_database, const std::function<void(FtpSession*)>& completion_handler)
47+
FtpSession::FtpSession(asio::io_service& io_service, const UserDatabase& user_database, const std::function<void(FtpSession*)>& completion_handler, std::ostream& output, std::ostream& error)
4148
: completion_handler_ (completion_handler)
4249
, user_database_ (user_database)
4350
, io_service_ (io_service)
@@ -49,6 +56,8 @@ namespace fineftp
4956
, data_acceptor_ (io_service)
5057
, data_socket_strand_ (io_service)
5158
, timer_ (io_service)
59+
, output_(output)
60+
, error_(error)
5261
{
5362
}
5463

@@ -62,7 +71,7 @@ namespace fineftp
6271
{
6372
asio::error_code ec;
6473
command_socket_.set_option(asio::ip::tcp::no_delay(true), ec);
65-
if (ec) std::cerr << "Unable to set socket option tcp::no_delay: " << ec.message() << std::endl;
74+
if (ec) error_ << "Unable to set socket option tcp::no_delay: " << ec.message() << std::endl;
6675

6776
command_strand_.post([me = shared_from_this()]() { me->readFtpCommand(); });
6877
sendFtpMessage(FtpMessage(FtpReplyCode::SERVICE_READY_FOR_NEW_USER, "Welcome to fineFTP Server"));
@@ -73,7 +82,7 @@ namespace fineftp
7382
{
7483
#ifndef NDEBUG
7584
// TODO: Have a "is stopped" variable, so that this log message is not printed every time
76-
std::cout << "Ftp Session shutting down" << std::endl;
85+
output_ << "Ftp Session shutting down" << std::endl;
7786
#endif // !NDEBUG
7887

7988
// TODO: protect the two sockets with mutexes, as it is now possible to call stop() from another thread!!!
@@ -142,7 +151,7 @@ namespace fineftp
142151
void FtpSession::startSendingMessages()
143152
{
144153
#ifndef NDEBUG
145-
std::cout << "FTP >> " << command_output_queue_.front() << std::endl;
154+
output_ << "FTP >> " << command_output_queue_.front() << std::endl;
146155
#endif
147156

148157
asio::async_write(command_socket_
@@ -175,7 +184,7 @@ namespace fineftp
175184
auto trimmed_message = me->command_output_queue_.front();
176185
trimmed_message.erase(trimmed_message.find_last_not_of("\r\n") + 1);
177186

178-
std::cerr << "Command write error for message " << trimmed_message << ": " << ec.message() << std::endl;
187+
error_ << "Command write error for message " << trimmed_message << ": " << ec.message() << std::endl;
179188
}
180189
}
181190
));
@@ -190,12 +199,12 @@ namespace fineftp
190199
{
191200
if (ec != asio::error::eof)
192201
{
193-
std::cerr << "read_until error: " << ec.message() << std::endl;
202+
me->error_ << "read_until error: " << ec.message() << std::endl;
194203
}
195204
#ifndef NDEBUG
196205
else
197206
{
198-
std::cout << "Control connection closed by client." << std::endl;
207+
me->output_ << "Control connection closed by client." << std::endl;
199208
}
200209
#endif // !NDEBUG
201210
// Close the data connection, if it is open
@@ -223,7 +232,7 @@ namespace fineftp
223232

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

229238
me->handleFtpCommand(packet_string);
@@ -437,7 +446,7 @@ namespace fineftp
437446
data_acceptor_.close(ec);
438447
if (ec)
439448
{
440-
std::cerr << "Error closing data acceptor: " << ec.message() << std::endl;
449+
error_ << "Error closing data acceptor: " << ec.message() << std::endl;
441450
}
442451
}
443452

@@ -448,7 +457,7 @@ namespace fineftp
448457
data_acceptor_.open(endpoint.protocol(), ec);
449458
if (ec)
450459
{
451-
std::cerr << "Error opening data acceptor: " << ec.message() << std::endl;
460+
error_ << "Error opening data acceptor: " << ec.message() << std::endl;
452461
sendFtpMessage(FtpReplyCode::SERVICE_NOT_AVAILABLE, "Failed to enter passive mode.");
453462
return;
454463
}
@@ -458,7 +467,7 @@ namespace fineftp
458467
data_acceptor_.bind(endpoint, ec);
459468
if (ec)
460469
{
461-
std::cerr << "Error binding data acceptor: " << ec.message() << std::endl;
470+
error_ << "Error binding data acceptor: " << ec.message() << std::endl;
462471
sendFtpMessage(FtpReplyCode::SERVICE_NOT_AVAILABLE, "Failed to enter passive mode.");
463472
return;
464473
}
@@ -468,7 +477,7 @@ namespace fineftp
468477
data_acceptor_.listen(asio::socket_base::max_connections, ec);
469478
if (ec)
470479
{
471-
std::cerr << "Error listening on data acceptor: " << ec.message() << std::endl;
480+
error_ << "Error listening on data acceptor: " << ec.message() << std::endl;
472481
sendFtpMessage(FtpReplyCode::SERVICE_NOT_AVAILABLE, "Failed to enter passive mode.");
473482
return;
474483
}
@@ -1085,7 +1094,7 @@ namespace fineftp
10851094
if (dir_status.canOpenDir())
10861095
{
10871096
sendFtpMessage(FtpReplyCode::FILE_STATUS_OK_OPENING_DATA_CONNECTION, "Sending directory listing");
1088-
sendDirectoryListing(Filesystem::dirContent(local_path));
1097+
sendDirectoryListing(Filesystem::dirContent(local_path, error_));
10891098
return;
10901099
}
10911100
else
@@ -1133,7 +1142,7 @@ namespace fineftp
11331142
if (dir_status.canOpenDir())
11341143
{
11351144
sendFtpMessage(FtpReplyCode::FILE_STATUS_OK_OPENING_DATA_CONNECTION, "Sending name list");
1136-
sendNameList(Filesystem::dirContent(local_path));
1145+
sendNameList(Filesystem::dirContent(local_path, error_));
11371146
return;
11381147
}
11391148
else
@@ -1399,7 +1408,7 @@ namespace fineftp
13991408

14001409
if (ec)
14011410
{
1402-
std::cerr << "Data write error: " << ec.message() << std::endl;
1411+
me->error_ << "Data write error: " << ec.message() << std::endl;
14031412
return;
14041413
}
14051414

@@ -1440,7 +1449,7 @@ namespace fineftp
14401449
{
14411450
if (ec)
14421451
{
1443-
std::cerr << "Data transfer aborted: " << ec.message() << std::endl;
1452+
me->error_ << "Data transfer aborted: " << ec.message() << std::endl;
14441453
me->sendFtpMessage(FtpReplyCode::TRANSFER_ABORTED, "Data transfer aborted");
14451454
return;
14461455
}

fineftp-server/src/ftp_session.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ namespace fineftp
3333
// Public API
3434
////////////////////////////////////////////////////////
3535
public:
36-
FtpSession(asio::io_service& io_service, const UserDatabase& user_database, const std::function<void(FtpSession*)>& completion_handler);
36+
FtpSession(asio::io_service& io_service, const UserDatabase& user_database, const std::function<void(FtpSession*)>& completion_handler, std::ostream& output, std::ostream& error);
3737

3838
// Copy (disabled, as we are inheriting from shared_from_this)
3939
FtpSession(const FtpSession&) = delete;
@@ -210,5 +210,8 @@ namespace fineftp
210210
std::deque<std::shared_ptr<std::vector<char>>> data_buffer_;
211211

212212
asio::steady_timer timer_;
213+
214+
std::ostream& output_; /* Normal output log */
215+
std::ostream& error_; /* Error output log */
213216
};
214217
}

fineftp-server/src/server.cpp

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,27 @@
22

33
#include "server_impl.h"
44

5+
#include <cassert> // assert
6+
#include <cstddef> // size_t
7+
#include <cstdint> // uint16_t
58
#include <memory>
9+
#include <ostream>
610
#include <string>
7-
#include <cstdint> // uint16_t
8-
#include <cstddef> // size_t
9-
#include <cassert> // assert
1011

1112
#include <fineftp/permissions.h>
1213

1314
namespace fineftp
1415
{
15-
FtpServer::FtpServer(const std::string& address, uint16_t port)
16-
: ftp_server_(FtpServerImpl::create(address, port))
16+
FtpServer::FtpServer(const std::string& address, uint16_t port, std::ostream& output, std::ostream& error)
17+
: ftp_server_(FtpServerImpl::create(address, port, output, error))
18+
{}
19+
20+
FtpServer::FtpServer(const std::string& address, const uint16_t port)
21+
: FtpServer(address, port, std::cout, std::cerr)
1722
{}
1823

19-
FtpServer::FtpServer(uint16_t port)
20-
: FtpServer(std::string("0.0.0.0"), port)
24+
FtpServer::FtpServer(const uint16_t port)
25+
: FtpServer(std::string("0.0.0.0"), port, std::cout, std::cerr)
2126
{}
2227

2328
// Move

0 commit comments

Comments
 (0)