Skip to content

Commit 97c61f4

Browse files
client: fix double-close condition for connections
Currently, to avoid double-close of a connection we check for the `SS_DEAD` status on its stream. However, the `SS_DEAD` status can be set for a multitude of reasons without the connection being closed or even connected. For instance, we set it if a send/recv failed unrecoverably. To fix this, let's rely on the fact that a connection is open iff the file descriptor of its stream is a valid (i.e., not -1). This approach seems to be portable to the Windows platform too. Closes #142
1 parent 277d5d2 commit 97c61f4

File tree

4 files changed

+19
-6
lines changed

4 files changed

+19
-6
lines changed

src/Client/Connection.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ template<class BUFFER, class NetProvider>
125125
ConnectionImpl<BUFFER, NetProvider>::~ConnectionImpl()
126126
{
127127
assert(refs == 0);
128-
if (!strm.has_status(SS_DEAD)) {
128+
if (strm.is_open()) {
129129
connector.close(this);
130130
}
131131
}

src/Client/Connector.hpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -182,14 +182,15 @@ Connector<BUFFER, NetProvider>::close(Connection<BUFFER, NetProvider> &conn)
182182
return close(conn.getImpl());
183183
}
184184

185-
template<class BUFFER, class NetProvider>
185+
template <class BUFFER, class NetProvider>
186186
void
187187
Connector<BUFFER, NetProvider>::close(ConnectionImpl<BUFFER, NetProvider> *conn)
188188
{
189-
assert(!conn->get_strm().has_status(SS_DEAD));
190-
m_NetProvider.close(conn->get_strm());
191-
m_ReadyToSend.erase(conn);
192-
m_ReadyToDecode.erase(conn);
189+
if (conn->get_strm().is_open()) {
190+
m_NetProvider.close(conn->get_strm());
191+
m_ReadyToSend.erase(conn);
192+
m_ReadyToDecode.erase(conn);
193+
}
193194
}
194195

195196
template <class BUFFER, class NetProvider>

src/Client/UnixStream.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,9 @@ class UnixStream : public Stream {
6666
/** Get internal file descriptor of the socket. */
6767
int get_fd() const { return fd; }
6868

69+
/** Check whether the socket is open. */
70+
bool is_open() const { return fd != -1; }
71+
6972
protected:
7073
/** Log helpers. */
7174
template <class... MSG>

test/ClientTest.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,8 @@ trivial(Connector<BUFFER, NetProvider> &client)
182182
TEST_CASE("Connect timeout");
183183
rc = test_connect(client, conn, "8.8.8.8", port);
184184
fail_unless(rc != 0);
185+
TEST_CASE("Close of non-established connection (gh-142)");
186+
client.close(conn);
185187
}
186188

187189
/** Single connection, separate/sequence pings, no errors */
@@ -235,6 +237,9 @@ single_conn_ping(Connector<BUFFER, NetProvider> &client)
235237
fail_unless(response->body.error_stack == std::nullopt);
236238
}
237239
client.close(conn);
240+
241+
TEST_CASE("Double close of connection (gh-142)");
242+
client.close(conn);
238243
}
239244

240245
template <class BUFFER, class NetProvider>
@@ -1082,6 +1087,10 @@ test_sigpipe(void)
10821087
fail_unless(saved_errno == EPIPE);
10831088
#endif
10841089
fail_if(conn.futureIsReady(f));
1090+
1091+
TEST_CASE("Close of connection with error (gh-142)");
1092+
fail_unless(conn.hasError());
1093+
client.close(conn);
10851094
}
10861095

10871096
/** Single connection, wait response from closed connection. */

0 commit comments

Comments
 (0)