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

Stop server does not free the accept socket port (on Windows) #70

Open
monsieurgustav opened this issue Aug 30, 2024 · 6 comments
Open

Comments

@monsieurgustav
Copy link

Hi,
I have an unsual use-case where I must stop and restart the FTP server during the app lifetime.
But when I stop it the 1st time, I can observe that the listening port is still busy. (using "netstat -abn -p tcp") The next start works without an error, but no connection is actually accepted.
It happens even if no client connect to the server.
Do you have a clue?
Best regards,
Guillaume

@FlorianReimold
Copy link
Member

Thanks for the report! I will take a look and try to reproduce it. I just don't have the time at the moment, so it will take be a little while. Thanks for the patience!

@FlorianReimold
Copy link
Member

Hi @monsieurgustav, when you write you "stop" the sever, what exactly are you doing? Killing an application? Deleting the C++ object?
Is it possible for you to post some code that triggers the issue?

@monsieurgustav
Copy link
Author

monsieurgustav commented Oct 17, 2024

Sure, here it is:

void restartFtpServer(std::unique_ptr<fineftp::FtpServer>& ftpServer, const QString& folder, uint16_t port, size_t threadCount = 1)
    {
        if (ftpServer)
        {
            ftpServer->stop();
            ftpServer.reset();
        }

        ftpServer = std::make_unique<fineftp::FtpServer>(port);
        ftpServer->addUserAnonymous(folder.toUtf8().toStdString(), fineftp::Permission::ReadOnly);
        ftpServer->start(threadCount);
    }

I call this function when the root folder of the FTP server changes. (I don't think there is another way to do it)

If I remember correctly, one may need to connect (anonymously) to the server before it is destroyed/restarted to trigger the issue. I use WinSCP to connect.

@FlorianReimold
Copy link
Member

I confirmed the issue with wireshark. Indeed, the socket is not closed properly. I think the reason is the following code:

void FtpServerImpl::stop()
{
io_service_.stop();
for (std::thread& thread : thread_pool_)
{
thread.join();
}
thread_pool_.clear();
}

The server stops the io_service, which makes the application to rely on the OS to clean up the sockets. And that may not happen fast enough.

I will check how to fix that bug. For future references: You can also check the existence of that bug in Wireshark, as it will show the improperly terminated connection in red:
image

My test application looks like follows (Windows only, due to hacky system commands):

#include <chrono>
#include <fineftp/server.h>

#include <string>
#include <thread>

void restartFtpServer(std::unique_ptr<fineftp::FtpServer>& ftpServer, const std::string& folder, uint16_t port, size_t threadCount = 1)
{
  if (ftpServer)
  {
    ftpServer->stop();
    ftpServer.reset();
  }

  ftpServer = std::make_unique<fineftp::FtpServer>(port);
  ftpServer->addUserAnonymous(folder, fineftp::Permission::ReadOnly);
  ftpServer->start(threadCount);
}


int main() {
  std::unique_ptr<fineftp::FtpServer> ftpServer;

  restartFtpServer(ftpServer, "C:\\", 2121, 1);

  system("pause");

  restartFtpServer(ftpServer, "D:\\", 2121, 1);

  system("pause");
}

@monsieurgustav
Copy link
Author

Did you try to pause between the stop/start and wait a long time? (30s? 1mn?)
Does the socket/port frees itself at some point?

@FlorianReimold
Copy link
Member

FlorianReimold commented Oct 23, 2024

Actually, I did not experience any issue. In my test, fineftp was able to re-open the port immediately (code above). I didn't check netstat though, as I already confirmed the bug with Wireshark.

What needs to be done is entirely drop the io_service_.stop();. Without the io_service, sockets will not be able to properly shut down. Stopping the FTP Server must do the following instead:

  1. Prevent new sessions from being accepted
  2. Stop all existing FTP sessions
  3. Join all threads without stopping the io_service. This will wait for the io_service to run out of work on its own.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants