Skip to content

Commit 1d4d224

Browse files
Added is_stopped flag to server to prevent new connections and removed REUSE socket option
1 parent 7dad075 commit 1d4d224

File tree

3 files changed

+72
-16
lines changed

3 files changed

+72
-16
lines changed

fineftp-server/src/server_impl.cpp

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ namespace fineftp
2323
FtpServerImpl::FtpServerImpl(const std::string& address, uint16_t port)
2424
: port_ (port)
2525
, address_ (address)
26+
, is_stopped_ (false)
2627
, acceptor_ (io_service_)
2728
{}
2829

@@ -63,18 +64,19 @@ namespace fineftp
6364
return false;
6465
}
6566
}
66-
67-
{
68-
const std::lock_guard<std::mutex> acceptor_lock(acceptor_mutex_);
6967

70-
asio::error_code ec;
71-
acceptor_.set_option(asio::ip::tcp::acceptor::reuse_address(true), ec);
72-
if (ec)
73-
{
74-
std::cerr << "Error setting reuse_address option: " << ec.message() << std::endl;
75-
return false;
76-
}
77-
}
68+
// TODO: Add the code again to use reuse_address option
69+
//{
70+
// const std::lock_guard<std::mutex> acceptor_lock(acceptor_mutex_);
71+
72+
// asio::error_code ec;
73+
// acceptor_.set_option(asio::ip::tcp::acceptor::reuse_address(true), ec);
74+
// if (ec)
75+
// {
76+
// std::cerr << "Error setting reuse_address option: " << ec.message() << std::endl;
77+
// return false;
78+
// }
79+
//}
7880

7981
{
8082
const std::lock_guard<std::mutex> acceptor_lock(acceptor_mutex_);
@@ -119,6 +121,8 @@ namespace fineftp
119121

120122
void FtpServerImpl::stop()
121123
{
124+
is_stopped_ = true;
125+
122126
// Prevent new sessions from being created
123127
{
124128
const std::lock_guard<std::mutex> acceptor_lock(acceptor_mutex_);
@@ -154,6 +158,11 @@ namespace fineftp
154158

155159
void FtpServerImpl::waitForNextFtpSession()
156160
{
161+
if (is_stopped_)
162+
{
163+
return;
164+
}
165+
157166
auto shutdown_callback = [weak_me = std::weak_ptr<FtpServerImpl>(shared_from_this())](FtpSession* session_to_delete)
158167
{
159168
if (auto me = weak_me.lock())
@@ -173,6 +182,16 @@ namespace fineftp
173182
acceptor_.async_accept(new_ftp_session->getSocket()
174183
, [weak_me = std::weak_ptr<FtpServerImpl>(shared_from_this()), new_ftp_session](asio::error_code ec)
175184
{
185+
// Lock the shared pointer to this. May be a nullptr, so we need to check!!!
186+
auto me = weak_me.lock();
187+
188+
// Before even checking the error code, check if the server has been stopped
189+
if (!me || (me->is_stopped_))
190+
{
191+
return;
192+
}
193+
194+
// Check error code
176195
if (ec)
177196
{
178197
if (ec != asio::error::operation_aborted)
@@ -187,8 +206,6 @@ namespace fineftp
187206
#endif
188207
// TODO: review if this is thread safe, if right here the ftp server is shut down and the acceptor is closed. I think, that then the session will still be added to the list of open sessions and kept open.
189208

190-
auto me = weak_me.lock();
191-
192209
if (me)
193210
{
194211
const std::lock_guard<std::mutex> session_list_lock(me->session_list_mutex_);

fineftp-server/src/server_impl.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,10 +54,11 @@ namespace fineftp
5454
void waitForNextFtpSession();
5555

5656
private:
57-
UserDatabase ftp_users_;
57+
UserDatabase ftp_users_;
5858

59-
const uint16_t port_;
60-
const std::string address_;
59+
const uint16_t port_; //! Port used on creation. May be 0. In that case, the OS will choose a port. Thus, this variable should not be used for getting the actual port.
60+
const std::string address_; //! Address used on creation. The acceptor is bound to that address.
61+
std::atomic<bool> is_stopped_; //! Tells whether the server has been stopped. When stopped, it will refuse to accept new connections.
6162

6263
std::vector<std::thread> thread_pool_;
6364
asio::io_service io_service_;

tests/fineftp_test/src/startstop_test.cpp

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,44 @@ TEST(StartStopTests, connection_count)
214214
}
215215
#endif
216216

217+
#if 1
218+
// Restart the server multiple times and check if the same socket can be reused
219+
TEST(StartStopTests, restart_server)
220+
{
221+
constexpr size_t num_restarts = 10;
222+
223+
const DirPreparer dir_preparer(1, 1);
224+
dir_preparer.create_client_files(std::filesystem::path("test.txt"), 16);
225+
226+
227+
std::unique_ptr<fineftp::FtpServer> server;
228+
229+
for (unsigned int i = 0; i < num_restarts; ++i)
230+
{
231+
if (server)
232+
{
233+
server->stop();
234+
server.reset();
235+
}
236+
237+
server = std::make_unique<fineftp::FtpServer>(2121);
238+
server->addUserAnonymous(dir_preparer.server_local_root_dir(0).string(), fineftp::Permission::All);
239+
server->start(4);
240+
241+
// use CURL to upload the file to the server
242+
const std::string curl_command = "curl -S -s -T " + dir_preparer.client_local_root_dir(0, 0).string() + "/test.txt ftp://localhost:2121/test" + std::to_string(i) + ".txt --user anonymous:anonymous";
243+
const int curl_return_code = system_execute(curl_command);
244+
245+
// Check return code
246+
EXPECT_EQ(curl_return_code, 0);
247+
248+
// Check existence of file
249+
EXPECT_TRUE(std::filesystem::exists(dir_preparer.server_local_root_dir(0) / ("test" + std::to_string(i) + ".txt")));
250+
}
251+
}
252+
253+
#endif
254+
217255
#if 1
218256
// Create a large amount of servers, upload files to them from threads and stop the servers while the upload may still be in progress
219257
TEST(StartStopTests, multiple_servers_upload_stop)

0 commit comments

Comments
 (0)