Skip to content

Commit eb0fda9

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 5eac82a commit eb0fda9

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
@@ -124,7 +124,7 @@ template<class BUFFER, class NetProvider>
124124
ConnectionImpl<BUFFER, NetProvider>::~ConnectionImpl()
125125
{
126126
assert(refs == 0);
127-
if (!strm.has_status(SS_DEAD)) {
127+
if (strm.is_open()) {
128128
connector.close(this);
129129
}
130130
}

src/Client/Connector.hpp

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

187-
template<class BUFFER, class NetProvider>
187+
template <class BUFFER, class NetProvider>
188188
void
189189
Connector<BUFFER, NetProvider>::close(ConnectionImpl<BUFFER, NetProvider> *conn)
190190
{
191-
assert(!conn->get_strm().has_status(SS_DEAD));
192-
m_NetProvider.close(conn->get_strm());
193-
m_ReadyToSend.erase(conn);
194-
m_ReadyToDecode.erase(conn);
191+
if (conn->get_strm().is_open()) {
192+
m_NetProvider.close(conn->get_strm());
193+
m_ReadyToSend.erase(conn);
194+
m_ReadyToDecode.erase(conn);
195+
}
195196
}
196197

197198
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)