Skip to content

fix(Net): release FTPClientSession control socket on constructor failure; document readWelcomeMessage #5413 - #5418

Open
matejk wants to merge 2 commits into
mainfrom
5413-ftp-welcome-message
Open

fix(Net): release FTPClientSession control socket on constructor failure; document readWelcomeMessage #5413#5418
matejk wants to merge 2 commits into
mainfrom
5413-ftp-welcome-message

Conversation

@matejk

@matejk matejk commented Jul 25, 2026

Copy link
Copy Markdown
Contributor

Documentation (#5413)

readWelcomeMessage has been undocumented since it was added in #2335 (released in 1.10.0), and its name suggests "read it later" rather than "it was already read". #5413 questions the _serverReady = true assignment in the false branch. That assignment is intentional: without it, the next login() blocks waiting for a welcome reply that was already consumed, and FTPSClientSession stalls before sending AUTH TLS. The behavior is unchanged in every release since 1.10.0.

Documented in FTPClientSession.h and FTPSClientSession.h:

  • what each value of readWelcomeMessage means, and that passing false while the welcome reply is still pending desynchronizes the session, because that reply is then taken as the response to the next command
  • welcomeMessage() is empty when the caller read the reply
  • receiveServerReadyReply() does nothing once the server is marked ready

Control socket leak

Found while writing the tests. _pControlSocket is a raw pointer, so a constructor that throws never releases it: the destructor does not run for a partially constructed object. The socket stays open and the peer never sees a disconnect. This is reachable whenever the server answers with a negative welcome reply, for example 421 Service not available, or the read times out.

Both affected constructors now release the control socket and rethrow. The member type is unchanged, since it is protected and FTPSClientSession dereferences it directly, so switching to a smart pointer would break third-party subclasses.

Tests

The StreamSocket constructor had no coverage at all. Added to FTPClientSessionTest and FTPSClientSessionTest:

  • testWelcomeMessageRead / testWelcomeMessageNotRead cover both values of the flag
  • testConstructorFailureClosesSocket1 / testConstructorFailureClosesSocket2 cover the connection being closed after each constructor throws

The leak tests use a plain ServerSocket instead of DialogServer. DialogServer only leaves its receive loop once the peer disconnects, so a leaked socket would hang the suite rather than fail it; the new tests assert the server side reaches EOF under a receive timeout. Each test was checked against a reverted fix to confirm it fails when the corresponding change is missing.

Closes #5413.

matejk added 2 commits July 25, 2026 17:46
Cover the FTP and FTPS StreamSocket constructors with tests for both values.
…rows

The destructor does not run for a partially constructed object, so the
socket stayed open and the peer never saw a disconnect.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

FTPClientSession(socket, readWelcomeMessage=false) sets _serverReady=true without reading welcome reply

1 participant